se cambian parametros a DianXMLExtensionSigner

facho/cli.py: generate permite firmar directamente

FossilOrigin-Name: 23efe2dc5ae9df524963c927c5b461882f864008efbf25fd8677772ac8431cb1
This commit is contained in:
bit4bit@riseup.net 2020-09-20 01:30:20 +00:00
parent 86a9364c69
commit a917258cee
2 changed files with 40 additions and 17 deletions

View File

@ -228,8 +228,9 @@ def sign_xml(private_key, passphrase, xmlfile, ssl=True):
@click.option('--generate/--validate', default=False) @click.option('--generate/--validate', default=False)
@click.option('--passphrase') @click.option('--passphrase')
@click.option('--ssl/--no-ssl', default=False) @click.option('--ssl/--no-ssl', default=False)
@click.option('--sign/--no-sign', default=False)
@click.argument('scriptname', type=click.Path(exists=True), required=True) @click.argument('scriptname', type=click.Path(exists=True), required=True)
def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=True): def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=True, sign=False):
""" """
imprime xml en pantalla. imprime xml en pantalla.
SCRIPTNAME espera SCRIPTNAME espera
@ -263,6 +264,10 @@ def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=Tr
for extension in extensions: for extension in extensions:
xml.add_extension(extension) xml.add_extension(extension)
if sign:
signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase)
xml.add_extension(signer)
print(xml.tostring(xml_declaration=True)) print(xml.tostring(xml_declaration=True))

View File

@ -2,6 +2,7 @@
# this repository contains the full copyright notices and license terms. # this repository contains the full copyright notices and license terms.
from ..facho import FachoXML, FachoXMLExtension, LXMLBuilder from ..facho import FachoXML, FachoXMLExtension, LXMLBuilder
import uuid
import xmlsig import xmlsig
import xades import xades
from datetime import datetime from datetime import datetime
@ -178,7 +179,7 @@ class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension):
class DianXMLExtensionSigner(FachoXMLExtension): class DianXMLExtensionSigner(FachoXMLExtension):
# RESOLUCION 0001: pagina 516 # RESOLUCION 0001: pagina 516
POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf' POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf'
POLICY_NAME = 'Dian' POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.'
def __init__(self, pkcs12_path, passphrase=None): def __init__(self, pkcs12_path, passphrase=None):
self._pkcs12_path = pkcs12_path self._pkcs12_path = pkcs12_path
@ -192,20 +193,34 @@ class DianXMLExtensionSigner(FachoXMLExtension):
def sign_xml_string(self, document): def sign_xml_string(self, document):
xml = LXMLBuilder.from_string(document) xml = LXMLBuilder.from_string(document)
signature = self.sign_xml_element(xml)
fachoxml = FachoXML(xml,nsmap=NAMESPACES)
#DIAN 1.7.-2020: FAB01
ublextension = fachoxml.fragment('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension', append=True)
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
fachoxml.append_element(extcontent, signature)
return fachoxml.tostring()
def sign_xml_element(self, xml):
signature = xmlsig.template.create( signature = xmlsig.template.create(
xmlsig.constants.TransformInclC14N, xmlsig.constants.TransformInclC14N,
xmlsig.constants.TransformRsaSha256, xmlsig.constants.TransformRsaSha256,
"Signature", "Signature",
) )
id_uuid = str(uuid.uuid4())
ref = xmlsig.template.add_reference( ref = xmlsig.template.add_reference(
signature, xmlsig.constants.TransformSha256, uri="", name="R1" signature, xmlsig.constants.TransformSha256, uri="", name="xmldsig-%s-ref0" % (id_uuid)
) )
xmlsig.template.add_transform(ref, xmlsig.constants.TransformEnveloped) xmlsig.template.add_transform(ref, xmlsig.constants.TransformEnveloped)
id_keyinfo = "%s-KeyInfo" % (id_uuid)
xmlsig.template.add_reference( xmlsig.template.add_reference(
signature, xmlsig.constants.TransformSha256, uri="#KI", name="RKI" signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_keyinfo),
) )
ki = xmlsig.template.ensure_key_info(signature, name="KI") ki = xmlsig.template.ensure_key_info(signature, name=id_keyinfo)
data = xmlsig.template.add_x509_data(ki) data = xmlsig.template.add_x509_data(ki)
xmlsig.template.x509_data_add_certificate(data) xmlsig.template.x509_data_add_certificate(data)
serial = xmlsig.template.x509_data_add_issuer_serial(data) serial = xmlsig.template.x509_data_add_issuer_serial(data)
@ -216,12 +231,20 @@ class DianXMLExtensionSigner(FachoXMLExtension):
xmlsig.template.add_key_value(ki) xmlsig.template.add_key_value(ki)
qualifying = xades.template.create_qualifying_properties(signature) qualifying = xades.template.create_qualifying_properties(signature)
xades.utils.ensure_id(qualifying) xades.utils.ensure_id(qualifying)
xades.utils.ensure_id(qualifying)
# TODO assert with http://www.sic.gov.co/hora-legal-colombiana # TODO assert with http://www.sic.gov.co/hora-legal-colombiana
id_props = "xmldsig-%s-signedprops" % (id_uuid)
props = xades.template.create_signed_properties(qualifying, datetime=datetime.now()) props = xades.template.create_signed_properties(qualifying, datetime=datetime.now())
props.set('Id', id_props)
xades.template.add_claimed_role(props, "supplier") xades.template.add_claimed_role(props, "supplier")
props_ref = xmlsig.template.add_reference(
props, xmlsig.constants.TransformSha256, uri="#%s" % (id_props),
)
props_ref.set('Type', "http://uri.etsi.org/01903#SignedProperties")
xmlsig.template.add_transform(props_ref, xmlsig.constants.TransformEnveloped)
xml.append(signature) xml.append(signature)
policy = xades.policy.GenericPolicyId( policy = xades.policy.GenericPolicyId(
@ -236,20 +259,15 @@ class DianXMLExtensionSigner(FachoXMLExtension):
ctx.verify(signature) ctx.verify(signature)
#xmlsig take parent root #xmlsig take parent root
xml.remove(signature) xml.remove(signature)
return signature
fachoxml = FachoXML(xml,nsmap=NAMESPACES) # return (xpath, xml.Element)
def build(self, fachoxml):
signature = self.sign_xml_element(fachoxml.root)
#DIAN 1.7.-2020: FAB01 #DIAN 1.7.-2020: FAB01
ublextension = fachoxml.fragment('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension', append=True) ublextension = fachoxml.fragment('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension', append=True)
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent') extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
fachoxml.append_element(extcontent, signature) fachoxml.append_element(extcontent, signature)
return fachoxml.tostring()
# return (xpath, xml.Element)
def build(self, fachoxml):
xmlsigned = self.sign_xml_string(fachoxml.tostring())
xml = LXMLBuilder.from_string(xmlsigned)
fachoxml.root = xml
return fachoxml
class DianXMLExtensionAuthorizationProvider(FachoXMLExtension): class DianXMLExtensionAuthorizationProvider(FachoXMLExtension):