xml digital signature in python












0














I'm trying to add a digital signature for an electronic invoice in my country. Signature use XADES-EPS as standard.



I'm using xmlsig and etree to create the signtaure sintax in python 3, like this



def sign_file(cert, password, xml_firma):
min = 1
max = 99999

xmlns_uris = {'ds': 'http://myhost.com/p.xsd'}

random_val = random.randint(min, max)

signature_id = 'Signature-' + str(random_val)
#signed_properties_id = signature_id + '-SignedProperties%05d'
# % random.randint(min, max)

signed_properties_id = 'SignedProperties-' + signature_id
signature_value = 'SignatureValue-' + str(random_val)

qualifying_properties = 'QualifyingProperties-%05d' % random.randint(min, max)

#key_info_id = 'KeyInfo%05d' % random.randint(min, max)
key_info_id = 'KeyInfoId-' + signature_id

reference_id = 'Reference-%05d' % random.randint(min, max)
#object_id = 'Object%05d' % random.randint(min, max)
object_id = 'XadesObjectId-%05d' % random.randint(min, max)

xades = 'http://uri.etsi.org/01903/v1.3.2#'
ds = 'http://www.w3.org/2000/09/xmldsig#'
xades141 = 'http://uri.etsi.org/01903/v1.4.1#'
sig_policy_identifier = 'https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf'
sig_policy_hash_value = 'V8lVVNGDCPen6VELRD1Ja8HARFk='

xml_firmar = base64decode(xml_firma)

root = etree.fromstring(xml_firmar)

certificate = crypto.load_pkcs12(base64.b64decode(cert), password)

# GENERAR NODO PERSONALIZADO PARA FE
sign = etree.Element(
etree.QName(ds, 'Signature'),
nsmap={'ds': ds},
attrib={
xmlsig.constants.ID_ATTR: signature_id,
}
)

#annotate_with_xmlns_prefixes(sign, 'ds')
#add_xmnls_attributes(sign, xmlns_uris)

# GENERO EL NODO ds:SignedInfo
signed_info = etree.SubElement(
sign,
etree.QName(ds, 'SignedInfo')
)

# CREO EL NODO ds:CanonicalizationMethod DENTRO DE signed_info
etree.SubElement(
signed_info,
etree.QName(ds, 'CanonicalizationMethod'),
attrib={
'Algorithm': xmlsig.constants.TransformInclC14N
}
)

# CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
etree.SubElement(
signed_info,
etree.QName(ds, 'SignatureMethod'),
attrib={
'Algorithm': xmlsig.constants.TransformRsaSha256
}
)

# CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
reference = etree.SubElement(
signed_info,
etree.QName(ds, 'Reference'),
attrib={
xmlsig.constants.ID_ATTR: reference_id,
'URI': ''
}
)

# CREO EL NODO ds:Transforms DENTRO DE reference
transforms = etree.SubElement(
reference,
etree.QName(ds, 'Transforms'),
)

# CREO EL NODO ds:Transform DENTRO DE trasnforms
etree.SubElement(
transforms,
etree.QName(ds, 'Transform'),
attrib={
'Algorithm': 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
}
)

# CREO EL NODO ds:DigestMethod DENTRO DE reference
etree.SubElement(
reference,
etree.QName(ds, 'DigestMethod'),
attrib={
'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
}
)

# OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
#digest_value = hashlib.sha256(
# crypto.dump_certificate(
# crypto.FILETYPE_ASN1,
# certificate.get_certificate()
# )
#)

# GENERO EL NODO ds:DigestValue DENTRO DE reference
etree.SubElement(
reference,
etree.QName(ds, 'DigestValue')
)#.text = base64.b64encode(digest_value.digest())

# CREO EL SEGUNDO NODO ds:SignatureMethod DENTRO DE signed_info
sec_reference = etree.SubElement(
signed_info,
etree.QName(ds, 'Reference'),
attrib={
xmlsig.constants.ID_ATTR: 'ReferenceKeyInfo',
'URI': '#' + key_info_id

}
)

# CREO EL NODO ds:DigestMethod DENTRO DE reference
etree.SubElement(
sec_reference,
etree.QName(ds, 'DigestMethod'),
attrib={
'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
}
)

# OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
#digest_value2 = hashlib.sha256(
# crypto.dump_certificate(
# crypto.FILETYPE_ASN1,
# certificate.get_certificate()
# )
#)

# GENERO EL NODO ds:DigestValue DENTRO DE reference
etree.SubElement(
sec_reference,
etree.QName(ds, 'DigestValue')
)#.text = base64.b64encode(digest_value2.digest())

# CREO EL TERCER NODO ds:Reference DENTRO DE signed_info
tr_reference = etree.SubElement(
signed_info,
etree.QName(ds, 'Reference'),
attrib={
'Type': 'http://uri.etsi.org/01903#SignedProperties',
'URI': '#' + signed_properties_id,
}
)

# CREO EL NODO ds:DigestMethod DENTRO DE reference
etree.SubElement(
tr_reference,
etree.QName(ds, 'DigestMethod'),
attrib={
'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
}
)

# OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
#digest_value3 = hashlib.sha256(
# crypto.dump_certificate(
# crypto.FILETYPE_ASN1,
# certificate.get_certificate()
# )
#)

# GENERO EL NODO ds:DigestValue DENTRO DE reference
etree.SubElement(
tr_reference,
etree.QName(ds, 'DigestValue')
)#.text = base64.b64encode(digest_value3.digest())

# GENERO EL NODO ds:SignatureValue
etree.SubElement(
sign,
etree.QName(ds, 'SignatureValue'),
attrib={
xmlsig.constants.ID_ATTR: signature_value
}
)

# GENERO EL NODO ds:KeyInfo
key_info = etree.SubElement(
sign,
etree.QName(ds, 'KeyInfo'),
attrib={
xmlsig.constants.ID_ATTR: key_info_id
}
)


# GENERO EL NODO ds:X509Data
x509 = etree.SubElement(
key_info,
etree.QName(ds, 'X509Data'),
)

# GENERO EL NODO ds:X509Certificate
etree.SubElement(
x509,
etree.QName(ds, 'X509Certificate'),
)

# GENERO EL NODO ds:KeyValue
etree.SubElement(
key_info,
etree.QName(ds, 'KeyValue'),
)



#AQUI EMPIEZO A CREAR EL NODO DE QUALIFYNG PROPERTIES
object_node = etree.SubElement(
sign,
etree.QName(xmlsig.constants.DSigNs, 'Object'),
#nsmap={'etsi': etsi},
attrib={xmlsig.constants.ID_ATTR: object_id}
#nsmap={'xades': xades},
#attrib={xmlsig.constants.ID_ATTR: object_id} NO SE NECESITA EN EL XML DE HACIENDA
)

#CREO EL SUBNODO QUALIFYING PROPERTIES
qualifying_properties = etree.SubElement(
object_node,
etree.QName(xades, 'QualifyingProperties'),
nsmap = {'xades': xades, 'xades141': xades141},
attrib={
xmlsig.constants.ID_ATTR: qualifying_properties,
'Target': '#' + signature_id
})

#CREO EL NODO xades:SignedProperties DENTRO DE QUALIFYING PROPERTIES
signed_properties = etree.SubElement(
qualifying_properties,
etree.QName(xades, 'SignedProperties'),
attrib={
xmlsig.constants.ID_ATTR: signed_properties_id #ESTO HAY QUE CAMBIARLO PARA QUE SEA COMO LO PIDE HACIENDA
}
)

# CREO EL NODO xades:SignedSignatureProperties DENTRO DE SIGNED PROPERTIES
signed_signature_properties = etree.SubElement(
signed_properties,
etree.QName(xades, 'SignedSignatureProperties')
)

#GENERO LA HORA PARA EL NODO xades:SigningTime
#now = datetime.datetime.now().replace(
# microsecond=0, tzinfo=pytz.utc
#)

# GENERO EL NODO xades:SigningTime Y LE PONGO LA HORA
etree.SubElement(
signed_signature_properties,
etree.QName(xades, 'SigningTime')
).text = get_time_hacienda()

#GENERO EL NODO xades:SigningCertificate
signing_certificate = etree.SubElement(
signed_signature_properties,
etree.QName(xades, 'SigningCertificate')
)

#GENERO EL NODO xades:Cert DENTRO DE xades:SigningCertificate
signing_certificate_cert = etree.SubElement(
signing_certificate,
etree.QName(xades, 'Cert')
)

#GENERO EL NODO xades:CertDigest DENTRO DE xades:cert
cert_digest = etree.SubElement(
signing_certificate_cert,
etree.QName(xades, 'CertDigest')
)

#GENERO EL NODO ds:DigestMethod DENTRO DE xades:CertDigest
etree.SubElement(
cert_digest,
etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
attrib={
'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
}
)

# OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
hash_cert = hashlib.sha256(
crypto.dump_certificate(
crypto.FILETYPE_ASN1,
certificate.get_certificate()
)
)

# GENERO EL NODO ds:DigestValue DENTRO DE xades:CertDigest Y LE PONGO EL VALOR DEL DIGESTVALUE ANTERIOR
etree.SubElement(
cert_digest,
etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
).text = base64.b64encode(hash_cert.digest())

# GENERO EL NODO xades:IssuerSerial DENTRO DE xades:Cert
issuer_serial = etree.SubElement(
signing_certificate_cert,
etree.QName(xades, 'IssuerSerial')
)

# GENERO EL NODO ds:X509IssuerName DENTRO DE xades:IssuerSerial
etree.SubElement(
issuer_serial,
etree.QName(xmlsig.constants.DSigNs, 'X509IssuerName')
).text = xmlsig.utils.get_rdns_name(certificate.get_certificate().to_cryptography().issuer.rdns)

# GENERO EL NODO ds:X509SerialNumber DENTRO DE xades:IssuerSerial
etree.SubElement(
issuer_serial,
etree.QName(xmlsig.constants.DSigNs, 'X509SerialNumber')
).text = str(certificate.get_certificate().get_serial_number())

# GENERO EL NODO xades:SignaturePolicyIdentifier DENTRO DE sign
signature_policy_identifier = etree.SubElement(
signed_signature_properties,
etree.QName(xades, 'SignaturePolicyIdentifier')
)

# GENERO EL NODO xades:SignaturePolicyId DENTRO DE xades:SignaturePolicyIdentifier
signature_policy_id = etree.SubElement(
signature_policy_identifier,
etree.QName(xades, 'SignaturePolicyId')
)

# GENERO EL NODO xades:SigPolicyId DENTRO DE xades:SignaturePolicyId
sig_policy_id = etree.SubElement(
signature_policy_id,
etree.QName(xades, 'SigPolicyId')
)

# GENERO EL NODO xades:Identifier DENTRO DE xades:SigPolicyId
etree.SubElement(
sig_policy_id,
etree.QName(xades, 'Identifier')
).text = sig_policy_identifier

#BORRO ESTE NODO PUES EN FE COSTA RICA NO SE NECESITA
etree.SubElement(
sig_policy_id,
etree.QName(xades, 'Description')
)#.text = "Política de Firma FacturaE v3.1"

# GENERO EL NODO xades:Identifier DENTRO DE signature_policy_id
sig_policy_hash = etree.SubElement(
signature_policy_id,
etree.QName(xades, 'SigPolicyHash')
)

# GENERO EL NODO ds:DigestMethod DENTRO DE xades:Identifier
etree.SubElement(
sig_policy_hash,
etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
attrib={
'Algorithm': 'http://www.w3.org/2000/09/xmldsig#sha1'
})

#GENERO EL DIGEST PARA EL CERTIFICADO LEYENDOLO DE LA URL DE HACIENDA
try:
remote = urllib.request.urlopen(sig_policy_identifier)
hash_value = base64.b64encode(hashlib.sha256(remote.read()).digest())
except urllib.request.HTTPError:
hash_value = sig_policy_hash_value

# GENERO EL NODO ds:DigestValue ds:DigestMethod DENTRO DE sig_policy_hash
etree.SubElement(
sig_policy_hash,
etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
).text = hash_value

#NO REQUERIDO PARA FE COSTA RICA
#signer_role = etree.SubElement(
# signed_signature_properties,
# etree.QName(etsi, 'SignerRole')
#)
#claimed_roles = etree.SubElement(
# signer_role,
# etree.QName(etsi, 'ClaimedRoles')
#)

#etree.SubElement(
# claimed_roles,
# etree.QName(etsi, 'ClaimedRole')
#).text = 'supplier'

signed_data_object_properties = etree.SubElement(
signed_properties,
etree.QName(xades, 'SignedDataObjectProperties')
)

data_object_format = etree.SubElement(
signed_data_object_properties,
etree.QName(xades, 'DataObjectFormat'),
attrib={
'ObjectReference': '#' + reference_id
}
)

#etree.SubElement(
# data_object_format,
# etree.QName(etsi, 'Description')
#).text = 'Factura'

etree.SubElement(
data_object_format,
etree.QName(xades, 'MimeType')
).text = 'text/xml'

ctx = xmlsig.SignatureContext()
key = crypto.load_pkcs12(base64.b64decode(cert), password)
ctx.x509 = key.get_certificate().to_cryptography()
ctx.public_key = ctx.x509.public_key()
ctx.private_key = key.get_privatekey().to_cryptography_key()
root.append(sign)

root.xpath(
'//ds:Signature', namespaces={'ds': xmlsig.constants.DSigNs}
)[0]

ctx.sign(sign)

#xml_bytes = etree.tostring(root, xml_declaration=True)

#return stringToBase64(xml_bytes)


return etree.tostring(
root
)


That code produces a xml signature in the following way



<ds:Signature Id="Signature-17044">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference Id="Reference-74608" URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>+fhrrmGMWpvy8IEowaa2fLh905rLv6xRmKB4zD6Omtg=</ds:DigestValue>
</ds:Reference>
<ds:Reference Id="ReferenceKeyInfo" URI="#KeyInfoId-Signature-17044">
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>zXjLpycv3XvGI47RJR0qIoxtZoApAHwkdjDqRKiGpTU=</ds:DigestValue>
</ds:Reference>
<ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#SignedProperties-Signature-17044">
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>sHX8p3YfyvxNIwL2NC54sZdYfvsfXvfYTCks/8BMQlQ=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue Id="SignatureValue-17044">B9Mb3Ogm1QNkpu1N8o4rF0EP4a/vM9Yjgk7EiYZBQmU/r6+yZ/pVC27XYJubbcoxhlth1pk4y15d95I7RfqdqOwMt8dj6P9FKljPH2jCRU0IlHCul3eudjaBWfbu2+fjpyIFRO53kHhOfumkstMKtSCAPSgHRV0wLb06JcZhVCUXUNy+rJfElxzJjhNq+aHcIjayf2TVs1w/elFOz9Ax2v18xol6BRyHnlrQEUtD57AiVurkkcGs0oUqrDGV7IN3YebBJWge/ttXF+5Bz9NnBHQD4iU5ul3aGhcOwq7FY7qxIbmqBHhmcLi7ZGVCXfiEU58Sn6Sa8yBjOILh5Wgzng==</ds:SignatureValue>
<ds:KeyInfo Id="KeyInfoId-Signature-17044">
<ds:X509Data>
<ds:X509Certificate>MIIFRjCCAy6gAwIBAgIGAWZEbfKCMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNVBAYTAkNSMSkwJwYDVQQKDCBNSU5JU1RFUklPIERFIEhBQ0lFTkRBIC0gU0FOREJPWDEMMAoGA1UECwwD</ds:X509Certificate>
</ds:X509Data>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus>pVc+nKRrS6q2O05DEO7r1smiY/0PDTZpYSirjEzPaxQ2hRvZDGaxX8wEzqiAE7i9icZbqtwaQPECBRhlzjEK4lxbDhESqYI34CKiMMeARquVGn9WJ/EQjQhGm1KgqROvizX3LRcxDgJzd6pbKPxqTUC/gDAy/PEJJuD9WOH0NVYCREZtD3ShkiIt3DphbDK84Whqhvt47ZyFRSIgjxrRkerhOZj3EzFjr4aIADXUXY2LJGTyKHEe8WcvA9k/aaZGZaTRINOwgk4KMSzNXBDweoxXzN0bJukbxXEicLqO7cJHqoaZX0gCDU8KfAN2UAtmhQ/IRgkSD6O2F72kC86ePQ==</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
<ds:Object Id="XadesObjectId-41822">
<xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Id="QualifyingProperties-01611" Target="#Signature-17044">
<xades:SignedProperties Id="SignedProperties-Signature-17044">
<xades:SignedSignatureProperties>
<xades:SigningTime>2018-11-12T15:24:21-06:00</xades:SigningTime>
<xades:SigningCertificate>
<xades:Cert>
<xades:CertDigest>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>gVmykfOS2A4p8ALJ6XVLcdTagMz+hMG4ikjzFipgymI=</ds:DigestValue>
</xades:CertDigest>
<xades:IssuerSerial>
<ds:X509IssuerName>CN=CA PERSONA JURIDICA - SANDBOX,OU=DGT,O=MINISTERIO DE HACIENDA - SANDBOX,C=CR</ds:X509IssuerName>
<ds:X509SerialNumber>1538746348162</ds:X509SerialNumber>
</xades:IssuerSerial>
</xades:Cert>
</xades:SigningCertificate>
<xades:SignaturePolicyIdentifier>
<xades:SignaturePolicyId>
<xades:SigPolicyId>
<xades:Identifier>https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf</xades:Identifier>
<xades:Description/>
</xades:SigPolicyId>
<xades:SigPolicyHash>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>a5aV6NckKzC/0CR4tQeTg2ULnhUNK2uDxsO5VuRInTE=</ds:DigestValue>
</xades:SigPolicyHash>
</xades:SignaturePolicyId>
</xades:SignaturePolicyIdentifier>
</xades:SignedSignatureProperties>
<xades:SignedDataObjectProperties>
<xades:DataObjectFormat ObjectReference="#Reference-74608">
<xades:MimeType>text/xml</xades:MimeType>
</xades:DataObjectFormat>
</xades:SignedDataObjectProperties>
</xades:SignedProperties>
</xades:QualifyingProperties>
</ds:Object>
</ds:Signature>


Xml result has the i need but i get alway invalida signature response. While checking the signature this is the response i get



Checking signature...
xmlsec:



func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=250:obj=sha256:subj=unknown:error=12:invalid data:data and digest do not match
FAIL
SignedInfo References (ok/all): 1/2
Manifests References (ok/all): 0/0



but i have no idea what the problem can be



Any ideas?



NOTE: CERTIFICATE INFORMATION HAS BEEN CUTED










share|improve this question



























    0














    I'm trying to add a digital signature for an electronic invoice in my country. Signature use XADES-EPS as standard.



    I'm using xmlsig and etree to create the signtaure sintax in python 3, like this



    def sign_file(cert, password, xml_firma):
    min = 1
    max = 99999

    xmlns_uris = {'ds': 'http://myhost.com/p.xsd'}

    random_val = random.randint(min, max)

    signature_id = 'Signature-' + str(random_val)
    #signed_properties_id = signature_id + '-SignedProperties%05d'
    # % random.randint(min, max)

    signed_properties_id = 'SignedProperties-' + signature_id
    signature_value = 'SignatureValue-' + str(random_val)

    qualifying_properties = 'QualifyingProperties-%05d' % random.randint(min, max)

    #key_info_id = 'KeyInfo%05d' % random.randint(min, max)
    key_info_id = 'KeyInfoId-' + signature_id

    reference_id = 'Reference-%05d' % random.randint(min, max)
    #object_id = 'Object%05d' % random.randint(min, max)
    object_id = 'XadesObjectId-%05d' % random.randint(min, max)

    xades = 'http://uri.etsi.org/01903/v1.3.2#'
    ds = 'http://www.w3.org/2000/09/xmldsig#'
    xades141 = 'http://uri.etsi.org/01903/v1.4.1#'
    sig_policy_identifier = 'https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf'
    sig_policy_hash_value = 'V8lVVNGDCPen6VELRD1Ja8HARFk='

    xml_firmar = base64decode(xml_firma)

    root = etree.fromstring(xml_firmar)

    certificate = crypto.load_pkcs12(base64.b64decode(cert), password)

    # GENERAR NODO PERSONALIZADO PARA FE
    sign = etree.Element(
    etree.QName(ds, 'Signature'),
    nsmap={'ds': ds},
    attrib={
    xmlsig.constants.ID_ATTR: signature_id,
    }
    )

    #annotate_with_xmlns_prefixes(sign, 'ds')
    #add_xmnls_attributes(sign, xmlns_uris)

    # GENERO EL NODO ds:SignedInfo
    signed_info = etree.SubElement(
    sign,
    etree.QName(ds, 'SignedInfo')
    )

    # CREO EL NODO ds:CanonicalizationMethod DENTRO DE signed_info
    etree.SubElement(
    signed_info,
    etree.QName(ds, 'CanonicalizationMethod'),
    attrib={
    'Algorithm': xmlsig.constants.TransformInclC14N
    }
    )

    # CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
    etree.SubElement(
    signed_info,
    etree.QName(ds, 'SignatureMethod'),
    attrib={
    'Algorithm': xmlsig.constants.TransformRsaSha256
    }
    )

    # CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
    reference = etree.SubElement(
    signed_info,
    etree.QName(ds, 'Reference'),
    attrib={
    xmlsig.constants.ID_ATTR: reference_id,
    'URI': ''
    }
    )

    # CREO EL NODO ds:Transforms DENTRO DE reference
    transforms = etree.SubElement(
    reference,
    etree.QName(ds, 'Transforms'),
    )

    # CREO EL NODO ds:Transform DENTRO DE trasnforms
    etree.SubElement(
    transforms,
    etree.QName(ds, 'Transform'),
    attrib={
    'Algorithm': 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
    }
    )

    # CREO EL NODO ds:DigestMethod DENTRO DE reference
    etree.SubElement(
    reference,
    etree.QName(ds, 'DigestMethod'),
    attrib={
    'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
    }
    )

    # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
    #digest_value = hashlib.sha256(
    # crypto.dump_certificate(
    # crypto.FILETYPE_ASN1,
    # certificate.get_certificate()
    # )
    #)

    # GENERO EL NODO ds:DigestValue DENTRO DE reference
    etree.SubElement(
    reference,
    etree.QName(ds, 'DigestValue')
    )#.text = base64.b64encode(digest_value.digest())

    # CREO EL SEGUNDO NODO ds:SignatureMethod DENTRO DE signed_info
    sec_reference = etree.SubElement(
    signed_info,
    etree.QName(ds, 'Reference'),
    attrib={
    xmlsig.constants.ID_ATTR: 'ReferenceKeyInfo',
    'URI': '#' + key_info_id

    }
    )

    # CREO EL NODO ds:DigestMethod DENTRO DE reference
    etree.SubElement(
    sec_reference,
    etree.QName(ds, 'DigestMethod'),
    attrib={
    'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
    }
    )

    # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
    #digest_value2 = hashlib.sha256(
    # crypto.dump_certificate(
    # crypto.FILETYPE_ASN1,
    # certificate.get_certificate()
    # )
    #)

    # GENERO EL NODO ds:DigestValue DENTRO DE reference
    etree.SubElement(
    sec_reference,
    etree.QName(ds, 'DigestValue')
    )#.text = base64.b64encode(digest_value2.digest())

    # CREO EL TERCER NODO ds:Reference DENTRO DE signed_info
    tr_reference = etree.SubElement(
    signed_info,
    etree.QName(ds, 'Reference'),
    attrib={
    'Type': 'http://uri.etsi.org/01903#SignedProperties',
    'URI': '#' + signed_properties_id,
    }
    )

    # CREO EL NODO ds:DigestMethod DENTRO DE reference
    etree.SubElement(
    tr_reference,
    etree.QName(ds, 'DigestMethod'),
    attrib={
    'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
    }
    )

    # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
    #digest_value3 = hashlib.sha256(
    # crypto.dump_certificate(
    # crypto.FILETYPE_ASN1,
    # certificate.get_certificate()
    # )
    #)

    # GENERO EL NODO ds:DigestValue DENTRO DE reference
    etree.SubElement(
    tr_reference,
    etree.QName(ds, 'DigestValue')
    )#.text = base64.b64encode(digest_value3.digest())

    # GENERO EL NODO ds:SignatureValue
    etree.SubElement(
    sign,
    etree.QName(ds, 'SignatureValue'),
    attrib={
    xmlsig.constants.ID_ATTR: signature_value
    }
    )

    # GENERO EL NODO ds:KeyInfo
    key_info = etree.SubElement(
    sign,
    etree.QName(ds, 'KeyInfo'),
    attrib={
    xmlsig.constants.ID_ATTR: key_info_id
    }
    )


    # GENERO EL NODO ds:X509Data
    x509 = etree.SubElement(
    key_info,
    etree.QName(ds, 'X509Data'),
    )

    # GENERO EL NODO ds:X509Certificate
    etree.SubElement(
    x509,
    etree.QName(ds, 'X509Certificate'),
    )

    # GENERO EL NODO ds:KeyValue
    etree.SubElement(
    key_info,
    etree.QName(ds, 'KeyValue'),
    )



    #AQUI EMPIEZO A CREAR EL NODO DE QUALIFYNG PROPERTIES
    object_node = etree.SubElement(
    sign,
    etree.QName(xmlsig.constants.DSigNs, 'Object'),
    #nsmap={'etsi': etsi},
    attrib={xmlsig.constants.ID_ATTR: object_id}
    #nsmap={'xades': xades},
    #attrib={xmlsig.constants.ID_ATTR: object_id} NO SE NECESITA EN EL XML DE HACIENDA
    )

    #CREO EL SUBNODO QUALIFYING PROPERTIES
    qualifying_properties = etree.SubElement(
    object_node,
    etree.QName(xades, 'QualifyingProperties'),
    nsmap = {'xades': xades, 'xades141': xades141},
    attrib={
    xmlsig.constants.ID_ATTR: qualifying_properties,
    'Target': '#' + signature_id
    })

    #CREO EL NODO xades:SignedProperties DENTRO DE QUALIFYING PROPERTIES
    signed_properties = etree.SubElement(
    qualifying_properties,
    etree.QName(xades, 'SignedProperties'),
    attrib={
    xmlsig.constants.ID_ATTR: signed_properties_id #ESTO HAY QUE CAMBIARLO PARA QUE SEA COMO LO PIDE HACIENDA
    }
    )

    # CREO EL NODO xades:SignedSignatureProperties DENTRO DE SIGNED PROPERTIES
    signed_signature_properties = etree.SubElement(
    signed_properties,
    etree.QName(xades, 'SignedSignatureProperties')
    )

    #GENERO LA HORA PARA EL NODO xades:SigningTime
    #now = datetime.datetime.now().replace(
    # microsecond=0, tzinfo=pytz.utc
    #)

    # GENERO EL NODO xades:SigningTime Y LE PONGO LA HORA
    etree.SubElement(
    signed_signature_properties,
    etree.QName(xades, 'SigningTime')
    ).text = get_time_hacienda()

    #GENERO EL NODO xades:SigningCertificate
    signing_certificate = etree.SubElement(
    signed_signature_properties,
    etree.QName(xades, 'SigningCertificate')
    )

    #GENERO EL NODO xades:Cert DENTRO DE xades:SigningCertificate
    signing_certificate_cert = etree.SubElement(
    signing_certificate,
    etree.QName(xades, 'Cert')
    )

    #GENERO EL NODO xades:CertDigest DENTRO DE xades:cert
    cert_digest = etree.SubElement(
    signing_certificate_cert,
    etree.QName(xades, 'CertDigest')
    )

    #GENERO EL NODO ds:DigestMethod DENTRO DE xades:CertDigest
    etree.SubElement(
    cert_digest,
    etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
    attrib={
    'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
    }
    )

    # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
    hash_cert = hashlib.sha256(
    crypto.dump_certificate(
    crypto.FILETYPE_ASN1,
    certificate.get_certificate()
    )
    )

    # GENERO EL NODO ds:DigestValue DENTRO DE xades:CertDigest Y LE PONGO EL VALOR DEL DIGESTVALUE ANTERIOR
    etree.SubElement(
    cert_digest,
    etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
    ).text = base64.b64encode(hash_cert.digest())

    # GENERO EL NODO xades:IssuerSerial DENTRO DE xades:Cert
    issuer_serial = etree.SubElement(
    signing_certificate_cert,
    etree.QName(xades, 'IssuerSerial')
    )

    # GENERO EL NODO ds:X509IssuerName DENTRO DE xades:IssuerSerial
    etree.SubElement(
    issuer_serial,
    etree.QName(xmlsig.constants.DSigNs, 'X509IssuerName')
    ).text = xmlsig.utils.get_rdns_name(certificate.get_certificate().to_cryptography().issuer.rdns)

    # GENERO EL NODO ds:X509SerialNumber DENTRO DE xades:IssuerSerial
    etree.SubElement(
    issuer_serial,
    etree.QName(xmlsig.constants.DSigNs, 'X509SerialNumber')
    ).text = str(certificate.get_certificate().get_serial_number())

    # GENERO EL NODO xades:SignaturePolicyIdentifier DENTRO DE sign
    signature_policy_identifier = etree.SubElement(
    signed_signature_properties,
    etree.QName(xades, 'SignaturePolicyIdentifier')
    )

    # GENERO EL NODO xades:SignaturePolicyId DENTRO DE xades:SignaturePolicyIdentifier
    signature_policy_id = etree.SubElement(
    signature_policy_identifier,
    etree.QName(xades, 'SignaturePolicyId')
    )

    # GENERO EL NODO xades:SigPolicyId DENTRO DE xades:SignaturePolicyId
    sig_policy_id = etree.SubElement(
    signature_policy_id,
    etree.QName(xades, 'SigPolicyId')
    )

    # GENERO EL NODO xades:Identifier DENTRO DE xades:SigPolicyId
    etree.SubElement(
    sig_policy_id,
    etree.QName(xades, 'Identifier')
    ).text = sig_policy_identifier

    #BORRO ESTE NODO PUES EN FE COSTA RICA NO SE NECESITA
    etree.SubElement(
    sig_policy_id,
    etree.QName(xades, 'Description')
    )#.text = "Política de Firma FacturaE v3.1"

    # GENERO EL NODO xades:Identifier DENTRO DE signature_policy_id
    sig_policy_hash = etree.SubElement(
    signature_policy_id,
    etree.QName(xades, 'SigPolicyHash')
    )

    # GENERO EL NODO ds:DigestMethod DENTRO DE xades:Identifier
    etree.SubElement(
    sig_policy_hash,
    etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
    attrib={
    'Algorithm': 'http://www.w3.org/2000/09/xmldsig#sha1'
    })

    #GENERO EL DIGEST PARA EL CERTIFICADO LEYENDOLO DE LA URL DE HACIENDA
    try:
    remote = urllib.request.urlopen(sig_policy_identifier)
    hash_value = base64.b64encode(hashlib.sha256(remote.read()).digest())
    except urllib.request.HTTPError:
    hash_value = sig_policy_hash_value

    # GENERO EL NODO ds:DigestValue ds:DigestMethod DENTRO DE sig_policy_hash
    etree.SubElement(
    sig_policy_hash,
    etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
    ).text = hash_value

    #NO REQUERIDO PARA FE COSTA RICA
    #signer_role = etree.SubElement(
    # signed_signature_properties,
    # etree.QName(etsi, 'SignerRole')
    #)
    #claimed_roles = etree.SubElement(
    # signer_role,
    # etree.QName(etsi, 'ClaimedRoles')
    #)

    #etree.SubElement(
    # claimed_roles,
    # etree.QName(etsi, 'ClaimedRole')
    #).text = 'supplier'

    signed_data_object_properties = etree.SubElement(
    signed_properties,
    etree.QName(xades, 'SignedDataObjectProperties')
    )

    data_object_format = etree.SubElement(
    signed_data_object_properties,
    etree.QName(xades, 'DataObjectFormat'),
    attrib={
    'ObjectReference': '#' + reference_id
    }
    )

    #etree.SubElement(
    # data_object_format,
    # etree.QName(etsi, 'Description')
    #).text = 'Factura'

    etree.SubElement(
    data_object_format,
    etree.QName(xades, 'MimeType')
    ).text = 'text/xml'

    ctx = xmlsig.SignatureContext()
    key = crypto.load_pkcs12(base64.b64decode(cert), password)
    ctx.x509 = key.get_certificate().to_cryptography()
    ctx.public_key = ctx.x509.public_key()
    ctx.private_key = key.get_privatekey().to_cryptography_key()
    root.append(sign)

    root.xpath(
    '//ds:Signature', namespaces={'ds': xmlsig.constants.DSigNs}
    )[0]

    ctx.sign(sign)

    #xml_bytes = etree.tostring(root, xml_declaration=True)

    #return stringToBase64(xml_bytes)


    return etree.tostring(
    root
    )


    That code produces a xml signature in the following way



    <ds:Signature Id="Signature-17044">
    <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
    <ds:Reference Id="Reference-74608" URI="">
    <ds:Transforms>
    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
    </ds:Transforms>
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    <ds:DigestValue>+fhrrmGMWpvy8IEowaa2fLh905rLv6xRmKB4zD6Omtg=</ds:DigestValue>
    </ds:Reference>
    <ds:Reference Id="ReferenceKeyInfo" URI="#KeyInfoId-Signature-17044">
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    <ds:DigestValue>zXjLpycv3XvGI47RJR0qIoxtZoApAHwkdjDqRKiGpTU=</ds:DigestValue>
    </ds:Reference>
    <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#SignedProperties-Signature-17044">
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    <ds:DigestValue>sHX8p3YfyvxNIwL2NC54sZdYfvsfXvfYTCks/8BMQlQ=</ds:DigestValue>
    </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue Id="SignatureValue-17044">B9Mb3Ogm1QNkpu1N8o4rF0EP4a/vM9Yjgk7EiYZBQmU/r6+yZ/pVC27XYJubbcoxhlth1pk4y15d95I7RfqdqOwMt8dj6P9FKljPH2jCRU0IlHCul3eudjaBWfbu2+fjpyIFRO53kHhOfumkstMKtSCAPSgHRV0wLb06JcZhVCUXUNy+rJfElxzJjhNq+aHcIjayf2TVs1w/elFOz9Ax2v18xol6BRyHnlrQEUtD57AiVurkkcGs0oUqrDGV7IN3YebBJWge/ttXF+5Bz9NnBHQD4iU5ul3aGhcOwq7FY7qxIbmqBHhmcLi7ZGVCXfiEU58Sn6Sa8yBjOILh5Wgzng==</ds:SignatureValue>
    <ds:KeyInfo Id="KeyInfoId-Signature-17044">
    <ds:X509Data>
    <ds:X509Certificate>MIIFRjCCAy6gAwIBAgIGAWZEbfKCMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNVBAYTAkNSMSkwJwYDVQQKDCBNSU5JU1RFUklPIERFIEhBQ0lFTkRBIC0gU0FOREJPWDEMMAoGA1UECwwD</ds:X509Certificate>
    </ds:X509Data>
    <ds:KeyValue>
    <ds:RSAKeyValue>
    <ds:Modulus>pVc+nKRrS6q2O05DEO7r1smiY/0PDTZpYSirjEzPaxQ2hRvZDGaxX8wEzqiAE7i9icZbqtwaQPECBRhlzjEK4lxbDhESqYI34CKiMMeARquVGn9WJ/EQjQhGm1KgqROvizX3LRcxDgJzd6pbKPxqTUC/gDAy/PEJJuD9WOH0NVYCREZtD3ShkiIt3DphbDK84Whqhvt47ZyFRSIgjxrRkerhOZj3EzFjr4aIADXUXY2LJGTyKHEe8WcvA9k/aaZGZaTRINOwgk4KMSzNXBDweoxXzN0bJukbxXEicLqO7cJHqoaZX0gCDU8KfAN2UAtmhQ/IRgkSD6O2F72kC86ePQ==</ds:Modulus>
    <ds:Exponent>AQAB</ds:Exponent>
    </ds:RSAKeyValue>
    </ds:KeyValue>
    </ds:KeyInfo>
    <ds:Object Id="XadesObjectId-41822">
    <xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Id="QualifyingProperties-01611" Target="#Signature-17044">
    <xades:SignedProperties Id="SignedProperties-Signature-17044">
    <xades:SignedSignatureProperties>
    <xades:SigningTime>2018-11-12T15:24:21-06:00</xades:SigningTime>
    <xades:SigningCertificate>
    <xades:Cert>
    <xades:CertDigest>
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    <ds:DigestValue>gVmykfOS2A4p8ALJ6XVLcdTagMz+hMG4ikjzFipgymI=</ds:DigestValue>
    </xades:CertDigest>
    <xades:IssuerSerial>
    <ds:X509IssuerName>CN=CA PERSONA JURIDICA - SANDBOX,OU=DGT,O=MINISTERIO DE HACIENDA - SANDBOX,C=CR</ds:X509IssuerName>
    <ds:X509SerialNumber>1538746348162</ds:X509SerialNumber>
    </xades:IssuerSerial>
    </xades:Cert>
    </xades:SigningCertificate>
    <xades:SignaturePolicyIdentifier>
    <xades:SignaturePolicyId>
    <xades:SigPolicyId>
    <xades:Identifier>https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf</xades:Identifier>
    <xades:Description/>
    </xades:SigPolicyId>
    <xades:SigPolicyHash>
    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <ds:DigestValue>a5aV6NckKzC/0CR4tQeTg2ULnhUNK2uDxsO5VuRInTE=</ds:DigestValue>
    </xades:SigPolicyHash>
    </xades:SignaturePolicyId>
    </xades:SignaturePolicyIdentifier>
    </xades:SignedSignatureProperties>
    <xades:SignedDataObjectProperties>
    <xades:DataObjectFormat ObjectReference="#Reference-74608">
    <xades:MimeType>text/xml</xades:MimeType>
    </xades:DataObjectFormat>
    </xades:SignedDataObjectProperties>
    </xades:SignedProperties>
    </xades:QualifyingProperties>
    </ds:Object>
    </ds:Signature>


    Xml result has the i need but i get alway invalida signature response. While checking the signature this is the response i get



    Checking signature...
    xmlsec:



    func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=250:obj=sha256:subj=unknown:error=12:invalid data:data and digest do not match
    FAIL
    SignedInfo References (ok/all): 1/2
    Manifests References (ok/all): 0/0



    but i have no idea what the problem can be



    Any ideas?



    NOTE: CERTIFICATE INFORMATION HAS BEEN CUTED










    share|improve this question

























      0












      0








      0







      I'm trying to add a digital signature for an electronic invoice in my country. Signature use XADES-EPS as standard.



      I'm using xmlsig and etree to create the signtaure sintax in python 3, like this



      def sign_file(cert, password, xml_firma):
      min = 1
      max = 99999

      xmlns_uris = {'ds': 'http://myhost.com/p.xsd'}

      random_val = random.randint(min, max)

      signature_id = 'Signature-' + str(random_val)
      #signed_properties_id = signature_id + '-SignedProperties%05d'
      # % random.randint(min, max)

      signed_properties_id = 'SignedProperties-' + signature_id
      signature_value = 'SignatureValue-' + str(random_val)

      qualifying_properties = 'QualifyingProperties-%05d' % random.randint(min, max)

      #key_info_id = 'KeyInfo%05d' % random.randint(min, max)
      key_info_id = 'KeyInfoId-' + signature_id

      reference_id = 'Reference-%05d' % random.randint(min, max)
      #object_id = 'Object%05d' % random.randint(min, max)
      object_id = 'XadesObjectId-%05d' % random.randint(min, max)

      xades = 'http://uri.etsi.org/01903/v1.3.2#'
      ds = 'http://www.w3.org/2000/09/xmldsig#'
      xades141 = 'http://uri.etsi.org/01903/v1.4.1#'
      sig_policy_identifier = 'https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf'
      sig_policy_hash_value = 'V8lVVNGDCPen6VELRD1Ja8HARFk='

      xml_firmar = base64decode(xml_firma)

      root = etree.fromstring(xml_firmar)

      certificate = crypto.load_pkcs12(base64.b64decode(cert), password)

      # GENERAR NODO PERSONALIZADO PARA FE
      sign = etree.Element(
      etree.QName(ds, 'Signature'),
      nsmap={'ds': ds},
      attrib={
      xmlsig.constants.ID_ATTR: signature_id,
      }
      )

      #annotate_with_xmlns_prefixes(sign, 'ds')
      #add_xmnls_attributes(sign, xmlns_uris)

      # GENERO EL NODO ds:SignedInfo
      signed_info = etree.SubElement(
      sign,
      etree.QName(ds, 'SignedInfo')
      )

      # CREO EL NODO ds:CanonicalizationMethod DENTRO DE signed_info
      etree.SubElement(
      signed_info,
      etree.QName(ds, 'CanonicalizationMethod'),
      attrib={
      'Algorithm': xmlsig.constants.TransformInclC14N
      }
      )

      # CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
      etree.SubElement(
      signed_info,
      etree.QName(ds, 'SignatureMethod'),
      attrib={
      'Algorithm': xmlsig.constants.TransformRsaSha256
      }
      )

      # CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
      reference = etree.SubElement(
      signed_info,
      etree.QName(ds, 'Reference'),
      attrib={
      xmlsig.constants.ID_ATTR: reference_id,
      'URI': ''
      }
      )

      # CREO EL NODO ds:Transforms DENTRO DE reference
      transforms = etree.SubElement(
      reference,
      etree.QName(ds, 'Transforms'),
      )

      # CREO EL NODO ds:Transform DENTRO DE trasnforms
      etree.SubElement(
      transforms,
      etree.QName(ds, 'Transform'),
      attrib={
      'Algorithm': 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
      }
      )

      # CREO EL NODO ds:DigestMethod DENTRO DE reference
      etree.SubElement(
      reference,
      etree.QName(ds, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      #digest_value = hashlib.sha256(
      # crypto.dump_certificate(
      # crypto.FILETYPE_ASN1,
      # certificate.get_certificate()
      # )
      #)

      # GENERO EL NODO ds:DigestValue DENTRO DE reference
      etree.SubElement(
      reference,
      etree.QName(ds, 'DigestValue')
      )#.text = base64.b64encode(digest_value.digest())

      # CREO EL SEGUNDO NODO ds:SignatureMethod DENTRO DE signed_info
      sec_reference = etree.SubElement(
      signed_info,
      etree.QName(ds, 'Reference'),
      attrib={
      xmlsig.constants.ID_ATTR: 'ReferenceKeyInfo',
      'URI': '#' + key_info_id

      }
      )

      # CREO EL NODO ds:DigestMethod DENTRO DE reference
      etree.SubElement(
      sec_reference,
      etree.QName(ds, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      #digest_value2 = hashlib.sha256(
      # crypto.dump_certificate(
      # crypto.FILETYPE_ASN1,
      # certificate.get_certificate()
      # )
      #)

      # GENERO EL NODO ds:DigestValue DENTRO DE reference
      etree.SubElement(
      sec_reference,
      etree.QName(ds, 'DigestValue')
      )#.text = base64.b64encode(digest_value2.digest())

      # CREO EL TERCER NODO ds:Reference DENTRO DE signed_info
      tr_reference = etree.SubElement(
      signed_info,
      etree.QName(ds, 'Reference'),
      attrib={
      'Type': 'http://uri.etsi.org/01903#SignedProperties',
      'URI': '#' + signed_properties_id,
      }
      )

      # CREO EL NODO ds:DigestMethod DENTRO DE reference
      etree.SubElement(
      tr_reference,
      etree.QName(ds, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      #digest_value3 = hashlib.sha256(
      # crypto.dump_certificate(
      # crypto.FILETYPE_ASN1,
      # certificate.get_certificate()
      # )
      #)

      # GENERO EL NODO ds:DigestValue DENTRO DE reference
      etree.SubElement(
      tr_reference,
      etree.QName(ds, 'DigestValue')
      )#.text = base64.b64encode(digest_value3.digest())

      # GENERO EL NODO ds:SignatureValue
      etree.SubElement(
      sign,
      etree.QName(ds, 'SignatureValue'),
      attrib={
      xmlsig.constants.ID_ATTR: signature_value
      }
      )

      # GENERO EL NODO ds:KeyInfo
      key_info = etree.SubElement(
      sign,
      etree.QName(ds, 'KeyInfo'),
      attrib={
      xmlsig.constants.ID_ATTR: key_info_id
      }
      )


      # GENERO EL NODO ds:X509Data
      x509 = etree.SubElement(
      key_info,
      etree.QName(ds, 'X509Data'),
      )

      # GENERO EL NODO ds:X509Certificate
      etree.SubElement(
      x509,
      etree.QName(ds, 'X509Certificate'),
      )

      # GENERO EL NODO ds:KeyValue
      etree.SubElement(
      key_info,
      etree.QName(ds, 'KeyValue'),
      )



      #AQUI EMPIEZO A CREAR EL NODO DE QUALIFYNG PROPERTIES
      object_node = etree.SubElement(
      sign,
      etree.QName(xmlsig.constants.DSigNs, 'Object'),
      #nsmap={'etsi': etsi},
      attrib={xmlsig.constants.ID_ATTR: object_id}
      #nsmap={'xades': xades},
      #attrib={xmlsig.constants.ID_ATTR: object_id} NO SE NECESITA EN EL XML DE HACIENDA
      )

      #CREO EL SUBNODO QUALIFYING PROPERTIES
      qualifying_properties = etree.SubElement(
      object_node,
      etree.QName(xades, 'QualifyingProperties'),
      nsmap = {'xades': xades, 'xades141': xades141},
      attrib={
      xmlsig.constants.ID_ATTR: qualifying_properties,
      'Target': '#' + signature_id
      })

      #CREO EL NODO xades:SignedProperties DENTRO DE QUALIFYING PROPERTIES
      signed_properties = etree.SubElement(
      qualifying_properties,
      etree.QName(xades, 'SignedProperties'),
      attrib={
      xmlsig.constants.ID_ATTR: signed_properties_id #ESTO HAY QUE CAMBIARLO PARA QUE SEA COMO LO PIDE HACIENDA
      }
      )

      # CREO EL NODO xades:SignedSignatureProperties DENTRO DE SIGNED PROPERTIES
      signed_signature_properties = etree.SubElement(
      signed_properties,
      etree.QName(xades, 'SignedSignatureProperties')
      )

      #GENERO LA HORA PARA EL NODO xades:SigningTime
      #now = datetime.datetime.now().replace(
      # microsecond=0, tzinfo=pytz.utc
      #)

      # GENERO EL NODO xades:SigningTime Y LE PONGO LA HORA
      etree.SubElement(
      signed_signature_properties,
      etree.QName(xades, 'SigningTime')
      ).text = get_time_hacienda()

      #GENERO EL NODO xades:SigningCertificate
      signing_certificate = etree.SubElement(
      signed_signature_properties,
      etree.QName(xades, 'SigningCertificate')
      )

      #GENERO EL NODO xades:Cert DENTRO DE xades:SigningCertificate
      signing_certificate_cert = etree.SubElement(
      signing_certificate,
      etree.QName(xades, 'Cert')
      )

      #GENERO EL NODO xades:CertDigest DENTRO DE xades:cert
      cert_digest = etree.SubElement(
      signing_certificate_cert,
      etree.QName(xades, 'CertDigest')
      )

      #GENERO EL NODO ds:DigestMethod DENTRO DE xades:CertDigest
      etree.SubElement(
      cert_digest,
      etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      hash_cert = hashlib.sha256(
      crypto.dump_certificate(
      crypto.FILETYPE_ASN1,
      certificate.get_certificate()
      )
      )

      # GENERO EL NODO ds:DigestValue DENTRO DE xades:CertDigest Y LE PONGO EL VALOR DEL DIGESTVALUE ANTERIOR
      etree.SubElement(
      cert_digest,
      etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
      ).text = base64.b64encode(hash_cert.digest())

      # GENERO EL NODO xades:IssuerSerial DENTRO DE xades:Cert
      issuer_serial = etree.SubElement(
      signing_certificate_cert,
      etree.QName(xades, 'IssuerSerial')
      )

      # GENERO EL NODO ds:X509IssuerName DENTRO DE xades:IssuerSerial
      etree.SubElement(
      issuer_serial,
      etree.QName(xmlsig.constants.DSigNs, 'X509IssuerName')
      ).text = xmlsig.utils.get_rdns_name(certificate.get_certificate().to_cryptography().issuer.rdns)

      # GENERO EL NODO ds:X509SerialNumber DENTRO DE xades:IssuerSerial
      etree.SubElement(
      issuer_serial,
      etree.QName(xmlsig.constants.DSigNs, 'X509SerialNumber')
      ).text = str(certificate.get_certificate().get_serial_number())

      # GENERO EL NODO xades:SignaturePolicyIdentifier DENTRO DE sign
      signature_policy_identifier = etree.SubElement(
      signed_signature_properties,
      etree.QName(xades, 'SignaturePolicyIdentifier')
      )

      # GENERO EL NODO xades:SignaturePolicyId DENTRO DE xades:SignaturePolicyIdentifier
      signature_policy_id = etree.SubElement(
      signature_policy_identifier,
      etree.QName(xades, 'SignaturePolicyId')
      )

      # GENERO EL NODO xades:SigPolicyId DENTRO DE xades:SignaturePolicyId
      sig_policy_id = etree.SubElement(
      signature_policy_id,
      etree.QName(xades, 'SigPolicyId')
      )

      # GENERO EL NODO xades:Identifier DENTRO DE xades:SigPolicyId
      etree.SubElement(
      sig_policy_id,
      etree.QName(xades, 'Identifier')
      ).text = sig_policy_identifier

      #BORRO ESTE NODO PUES EN FE COSTA RICA NO SE NECESITA
      etree.SubElement(
      sig_policy_id,
      etree.QName(xades, 'Description')
      )#.text = "Política de Firma FacturaE v3.1"

      # GENERO EL NODO xades:Identifier DENTRO DE signature_policy_id
      sig_policy_hash = etree.SubElement(
      signature_policy_id,
      etree.QName(xades, 'SigPolicyHash')
      )

      # GENERO EL NODO ds:DigestMethod DENTRO DE xades:Identifier
      etree.SubElement(
      sig_policy_hash,
      etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2000/09/xmldsig#sha1'
      })

      #GENERO EL DIGEST PARA EL CERTIFICADO LEYENDOLO DE LA URL DE HACIENDA
      try:
      remote = urllib.request.urlopen(sig_policy_identifier)
      hash_value = base64.b64encode(hashlib.sha256(remote.read()).digest())
      except urllib.request.HTTPError:
      hash_value = sig_policy_hash_value

      # GENERO EL NODO ds:DigestValue ds:DigestMethod DENTRO DE sig_policy_hash
      etree.SubElement(
      sig_policy_hash,
      etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
      ).text = hash_value

      #NO REQUERIDO PARA FE COSTA RICA
      #signer_role = etree.SubElement(
      # signed_signature_properties,
      # etree.QName(etsi, 'SignerRole')
      #)
      #claimed_roles = etree.SubElement(
      # signer_role,
      # etree.QName(etsi, 'ClaimedRoles')
      #)

      #etree.SubElement(
      # claimed_roles,
      # etree.QName(etsi, 'ClaimedRole')
      #).text = 'supplier'

      signed_data_object_properties = etree.SubElement(
      signed_properties,
      etree.QName(xades, 'SignedDataObjectProperties')
      )

      data_object_format = etree.SubElement(
      signed_data_object_properties,
      etree.QName(xades, 'DataObjectFormat'),
      attrib={
      'ObjectReference': '#' + reference_id
      }
      )

      #etree.SubElement(
      # data_object_format,
      # etree.QName(etsi, 'Description')
      #).text = 'Factura'

      etree.SubElement(
      data_object_format,
      etree.QName(xades, 'MimeType')
      ).text = 'text/xml'

      ctx = xmlsig.SignatureContext()
      key = crypto.load_pkcs12(base64.b64decode(cert), password)
      ctx.x509 = key.get_certificate().to_cryptography()
      ctx.public_key = ctx.x509.public_key()
      ctx.private_key = key.get_privatekey().to_cryptography_key()
      root.append(sign)

      root.xpath(
      '//ds:Signature', namespaces={'ds': xmlsig.constants.DSigNs}
      )[0]

      ctx.sign(sign)

      #xml_bytes = etree.tostring(root, xml_declaration=True)

      #return stringToBase64(xml_bytes)


      return etree.tostring(
      root
      )


      That code produces a xml signature in the following way



      <ds:Signature Id="Signature-17044">
      <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference Id="Reference-74608" URI="">
      <ds:Transforms>
      <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
      </ds:Transforms>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>+fhrrmGMWpvy8IEowaa2fLh905rLv6xRmKB4zD6Omtg=</ds:DigestValue>
      </ds:Reference>
      <ds:Reference Id="ReferenceKeyInfo" URI="#KeyInfoId-Signature-17044">
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>zXjLpycv3XvGI47RJR0qIoxtZoApAHwkdjDqRKiGpTU=</ds:DigestValue>
      </ds:Reference>
      <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#SignedProperties-Signature-17044">
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>sHX8p3YfyvxNIwL2NC54sZdYfvsfXvfYTCks/8BMQlQ=</ds:DigestValue>
      </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue Id="SignatureValue-17044">B9Mb3Ogm1QNkpu1N8o4rF0EP4a/vM9Yjgk7EiYZBQmU/r6+yZ/pVC27XYJubbcoxhlth1pk4y15d95I7RfqdqOwMt8dj6P9FKljPH2jCRU0IlHCul3eudjaBWfbu2+fjpyIFRO53kHhOfumkstMKtSCAPSgHRV0wLb06JcZhVCUXUNy+rJfElxzJjhNq+aHcIjayf2TVs1w/elFOz9Ax2v18xol6BRyHnlrQEUtD57AiVurkkcGs0oUqrDGV7IN3YebBJWge/ttXF+5Bz9NnBHQD4iU5ul3aGhcOwq7FY7qxIbmqBHhmcLi7ZGVCXfiEU58Sn6Sa8yBjOILh5Wgzng==</ds:SignatureValue>
      <ds:KeyInfo Id="KeyInfoId-Signature-17044">
      <ds:X509Data>
      <ds:X509Certificate>MIIFRjCCAy6gAwIBAgIGAWZEbfKCMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNVBAYTAkNSMSkwJwYDVQQKDCBNSU5JU1RFUklPIERFIEhBQ0lFTkRBIC0gU0FOREJPWDEMMAoGA1UECwwD</ds:X509Certificate>
      </ds:X509Data>
      <ds:KeyValue>
      <ds:RSAKeyValue>
      <ds:Modulus>pVc+nKRrS6q2O05DEO7r1smiY/0PDTZpYSirjEzPaxQ2hRvZDGaxX8wEzqiAE7i9icZbqtwaQPECBRhlzjEK4lxbDhESqYI34CKiMMeARquVGn9WJ/EQjQhGm1KgqROvizX3LRcxDgJzd6pbKPxqTUC/gDAy/PEJJuD9WOH0NVYCREZtD3ShkiIt3DphbDK84Whqhvt47ZyFRSIgjxrRkerhOZj3EzFjr4aIADXUXY2LJGTyKHEe8WcvA9k/aaZGZaTRINOwgk4KMSzNXBDweoxXzN0bJukbxXEicLqO7cJHqoaZX0gCDU8KfAN2UAtmhQ/IRgkSD6O2F72kC86ePQ==</ds:Modulus>
      <ds:Exponent>AQAB</ds:Exponent>
      </ds:RSAKeyValue>
      </ds:KeyValue>
      </ds:KeyInfo>
      <ds:Object Id="XadesObjectId-41822">
      <xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Id="QualifyingProperties-01611" Target="#Signature-17044">
      <xades:SignedProperties Id="SignedProperties-Signature-17044">
      <xades:SignedSignatureProperties>
      <xades:SigningTime>2018-11-12T15:24:21-06:00</xades:SigningTime>
      <xades:SigningCertificate>
      <xades:Cert>
      <xades:CertDigest>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>gVmykfOS2A4p8ALJ6XVLcdTagMz+hMG4ikjzFipgymI=</ds:DigestValue>
      </xades:CertDigest>
      <xades:IssuerSerial>
      <ds:X509IssuerName>CN=CA PERSONA JURIDICA - SANDBOX,OU=DGT,O=MINISTERIO DE HACIENDA - SANDBOX,C=CR</ds:X509IssuerName>
      <ds:X509SerialNumber>1538746348162</ds:X509SerialNumber>
      </xades:IssuerSerial>
      </xades:Cert>
      </xades:SigningCertificate>
      <xades:SignaturePolicyIdentifier>
      <xades:SignaturePolicyId>
      <xades:SigPolicyId>
      <xades:Identifier>https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf</xades:Identifier>
      <xades:Description/>
      </xades:SigPolicyId>
      <xades:SigPolicyHash>
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
      <ds:DigestValue>a5aV6NckKzC/0CR4tQeTg2ULnhUNK2uDxsO5VuRInTE=</ds:DigestValue>
      </xades:SigPolicyHash>
      </xades:SignaturePolicyId>
      </xades:SignaturePolicyIdentifier>
      </xades:SignedSignatureProperties>
      <xades:SignedDataObjectProperties>
      <xades:DataObjectFormat ObjectReference="#Reference-74608">
      <xades:MimeType>text/xml</xades:MimeType>
      </xades:DataObjectFormat>
      </xades:SignedDataObjectProperties>
      </xades:SignedProperties>
      </xades:QualifyingProperties>
      </ds:Object>
      </ds:Signature>


      Xml result has the i need but i get alway invalida signature response. While checking the signature this is the response i get



      Checking signature...
      xmlsec:



      func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=250:obj=sha256:subj=unknown:error=12:invalid data:data and digest do not match
      FAIL
      SignedInfo References (ok/all): 1/2
      Manifests References (ok/all): 0/0



      but i have no idea what the problem can be



      Any ideas?



      NOTE: CERTIFICATE INFORMATION HAS BEEN CUTED










      share|improve this question













      I'm trying to add a digital signature for an electronic invoice in my country. Signature use XADES-EPS as standard.



      I'm using xmlsig and etree to create the signtaure sintax in python 3, like this



      def sign_file(cert, password, xml_firma):
      min = 1
      max = 99999

      xmlns_uris = {'ds': 'http://myhost.com/p.xsd'}

      random_val = random.randint(min, max)

      signature_id = 'Signature-' + str(random_val)
      #signed_properties_id = signature_id + '-SignedProperties%05d'
      # % random.randint(min, max)

      signed_properties_id = 'SignedProperties-' + signature_id
      signature_value = 'SignatureValue-' + str(random_val)

      qualifying_properties = 'QualifyingProperties-%05d' % random.randint(min, max)

      #key_info_id = 'KeyInfo%05d' % random.randint(min, max)
      key_info_id = 'KeyInfoId-' + signature_id

      reference_id = 'Reference-%05d' % random.randint(min, max)
      #object_id = 'Object%05d' % random.randint(min, max)
      object_id = 'XadesObjectId-%05d' % random.randint(min, max)

      xades = 'http://uri.etsi.org/01903/v1.3.2#'
      ds = 'http://www.w3.org/2000/09/xmldsig#'
      xades141 = 'http://uri.etsi.org/01903/v1.4.1#'
      sig_policy_identifier = 'https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf'
      sig_policy_hash_value = 'V8lVVNGDCPen6VELRD1Ja8HARFk='

      xml_firmar = base64decode(xml_firma)

      root = etree.fromstring(xml_firmar)

      certificate = crypto.load_pkcs12(base64.b64decode(cert), password)

      # GENERAR NODO PERSONALIZADO PARA FE
      sign = etree.Element(
      etree.QName(ds, 'Signature'),
      nsmap={'ds': ds},
      attrib={
      xmlsig.constants.ID_ATTR: signature_id,
      }
      )

      #annotate_with_xmlns_prefixes(sign, 'ds')
      #add_xmnls_attributes(sign, xmlns_uris)

      # GENERO EL NODO ds:SignedInfo
      signed_info = etree.SubElement(
      sign,
      etree.QName(ds, 'SignedInfo')
      )

      # CREO EL NODO ds:CanonicalizationMethod DENTRO DE signed_info
      etree.SubElement(
      signed_info,
      etree.QName(ds, 'CanonicalizationMethod'),
      attrib={
      'Algorithm': xmlsig.constants.TransformInclC14N
      }
      )

      # CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
      etree.SubElement(
      signed_info,
      etree.QName(ds, 'SignatureMethod'),
      attrib={
      'Algorithm': xmlsig.constants.TransformRsaSha256
      }
      )

      # CREO EL NODO ds:SignatureMethod DENTRO DE signed_info
      reference = etree.SubElement(
      signed_info,
      etree.QName(ds, 'Reference'),
      attrib={
      xmlsig.constants.ID_ATTR: reference_id,
      'URI': ''
      }
      )

      # CREO EL NODO ds:Transforms DENTRO DE reference
      transforms = etree.SubElement(
      reference,
      etree.QName(ds, 'Transforms'),
      )

      # CREO EL NODO ds:Transform DENTRO DE trasnforms
      etree.SubElement(
      transforms,
      etree.QName(ds, 'Transform'),
      attrib={
      'Algorithm': 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
      }
      )

      # CREO EL NODO ds:DigestMethod DENTRO DE reference
      etree.SubElement(
      reference,
      etree.QName(ds, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      #digest_value = hashlib.sha256(
      # crypto.dump_certificate(
      # crypto.FILETYPE_ASN1,
      # certificate.get_certificate()
      # )
      #)

      # GENERO EL NODO ds:DigestValue DENTRO DE reference
      etree.SubElement(
      reference,
      etree.QName(ds, 'DigestValue')
      )#.text = base64.b64encode(digest_value.digest())

      # CREO EL SEGUNDO NODO ds:SignatureMethod DENTRO DE signed_info
      sec_reference = etree.SubElement(
      signed_info,
      etree.QName(ds, 'Reference'),
      attrib={
      xmlsig.constants.ID_ATTR: 'ReferenceKeyInfo',
      'URI': '#' + key_info_id

      }
      )

      # CREO EL NODO ds:DigestMethod DENTRO DE reference
      etree.SubElement(
      sec_reference,
      etree.QName(ds, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      #digest_value2 = hashlib.sha256(
      # crypto.dump_certificate(
      # crypto.FILETYPE_ASN1,
      # certificate.get_certificate()
      # )
      #)

      # GENERO EL NODO ds:DigestValue DENTRO DE reference
      etree.SubElement(
      sec_reference,
      etree.QName(ds, 'DigestValue')
      )#.text = base64.b64encode(digest_value2.digest())

      # CREO EL TERCER NODO ds:Reference DENTRO DE signed_info
      tr_reference = etree.SubElement(
      signed_info,
      etree.QName(ds, 'Reference'),
      attrib={
      'Type': 'http://uri.etsi.org/01903#SignedProperties',
      'URI': '#' + signed_properties_id,
      }
      )

      # CREO EL NODO ds:DigestMethod DENTRO DE reference
      etree.SubElement(
      tr_reference,
      etree.QName(ds, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      #digest_value3 = hashlib.sha256(
      # crypto.dump_certificate(
      # crypto.FILETYPE_ASN1,
      # certificate.get_certificate()
      # )
      #)

      # GENERO EL NODO ds:DigestValue DENTRO DE reference
      etree.SubElement(
      tr_reference,
      etree.QName(ds, 'DigestValue')
      )#.text = base64.b64encode(digest_value3.digest())

      # GENERO EL NODO ds:SignatureValue
      etree.SubElement(
      sign,
      etree.QName(ds, 'SignatureValue'),
      attrib={
      xmlsig.constants.ID_ATTR: signature_value
      }
      )

      # GENERO EL NODO ds:KeyInfo
      key_info = etree.SubElement(
      sign,
      etree.QName(ds, 'KeyInfo'),
      attrib={
      xmlsig.constants.ID_ATTR: key_info_id
      }
      )


      # GENERO EL NODO ds:X509Data
      x509 = etree.SubElement(
      key_info,
      etree.QName(ds, 'X509Data'),
      )

      # GENERO EL NODO ds:X509Certificate
      etree.SubElement(
      x509,
      etree.QName(ds, 'X509Certificate'),
      )

      # GENERO EL NODO ds:KeyValue
      etree.SubElement(
      key_info,
      etree.QName(ds, 'KeyValue'),
      )



      #AQUI EMPIEZO A CREAR EL NODO DE QUALIFYNG PROPERTIES
      object_node = etree.SubElement(
      sign,
      etree.QName(xmlsig.constants.DSigNs, 'Object'),
      #nsmap={'etsi': etsi},
      attrib={xmlsig.constants.ID_ATTR: object_id}
      #nsmap={'xades': xades},
      #attrib={xmlsig.constants.ID_ATTR: object_id} NO SE NECESITA EN EL XML DE HACIENDA
      )

      #CREO EL SUBNODO QUALIFYING PROPERTIES
      qualifying_properties = etree.SubElement(
      object_node,
      etree.QName(xades, 'QualifyingProperties'),
      nsmap = {'xades': xades, 'xades141': xades141},
      attrib={
      xmlsig.constants.ID_ATTR: qualifying_properties,
      'Target': '#' + signature_id
      })

      #CREO EL NODO xades:SignedProperties DENTRO DE QUALIFYING PROPERTIES
      signed_properties = etree.SubElement(
      qualifying_properties,
      etree.QName(xades, 'SignedProperties'),
      attrib={
      xmlsig.constants.ID_ATTR: signed_properties_id #ESTO HAY QUE CAMBIARLO PARA QUE SEA COMO LO PIDE HACIENDA
      }
      )

      # CREO EL NODO xades:SignedSignatureProperties DENTRO DE SIGNED PROPERTIES
      signed_signature_properties = etree.SubElement(
      signed_properties,
      etree.QName(xades, 'SignedSignatureProperties')
      )

      #GENERO LA HORA PARA EL NODO xades:SigningTime
      #now = datetime.datetime.now().replace(
      # microsecond=0, tzinfo=pytz.utc
      #)

      # GENERO EL NODO xades:SigningTime Y LE PONGO LA HORA
      etree.SubElement(
      signed_signature_properties,
      etree.QName(xades, 'SigningTime')
      ).text = get_time_hacienda()

      #GENERO EL NODO xades:SigningCertificate
      signing_certificate = etree.SubElement(
      signed_signature_properties,
      etree.QName(xades, 'SigningCertificate')
      )

      #GENERO EL NODO xades:Cert DENTRO DE xades:SigningCertificate
      signing_certificate_cert = etree.SubElement(
      signing_certificate,
      etree.QName(xades, 'Cert')
      )

      #GENERO EL NODO xades:CertDigest DENTRO DE xades:cert
      cert_digest = etree.SubElement(
      signing_certificate_cert,
      etree.QName(xades, 'CertDigest')
      )

      #GENERO EL NODO ds:DigestMethod DENTRO DE xades:CertDigest
      etree.SubElement(
      cert_digest,
      etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2001/04/xmlenc#sha256'
      }
      )

      # OBTENGO EL DIGEST VALUE DEL CERTIFICADO PARA EL NODO DIGESTVALUE
      hash_cert = hashlib.sha256(
      crypto.dump_certificate(
      crypto.FILETYPE_ASN1,
      certificate.get_certificate()
      )
      )

      # GENERO EL NODO ds:DigestValue DENTRO DE xades:CertDigest Y LE PONGO EL VALOR DEL DIGESTVALUE ANTERIOR
      etree.SubElement(
      cert_digest,
      etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
      ).text = base64.b64encode(hash_cert.digest())

      # GENERO EL NODO xades:IssuerSerial DENTRO DE xades:Cert
      issuer_serial = etree.SubElement(
      signing_certificate_cert,
      etree.QName(xades, 'IssuerSerial')
      )

      # GENERO EL NODO ds:X509IssuerName DENTRO DE xades:IssuerSerial
      etree.SubElement(
      issuer_serial,
      etree.QName(xmlsig.constants.DSigNs, 'X509IssuerName')
      ).text = xmlsig.utils.get_rdns_name(certificate.get_certificate().to_cryptography().issuer.rdns)

      # GENERO EL NODO ds:X509SerialNumber DENTRO DE xades:IssuerSerial
      etree.SubElement(
      issuer_serial,
      etree.QName(xmlsig.constants.DSigNs, 'X509SerialNumber')
      ).text = str(certificate.get_certificate().get_serial_number())

      # GENERO EL NODO xades:SignaturePolicyIdentifier DENTRO DE sign
      signature_policy_identifier = etree.SubElement(
      signed_signature_properties,
      etree.QName(xades, 'SignaturePolicyIdentifier')
      )

      # GENERO EL NODO xades:SignaturePolicyId DENTRO DE xades:SignaturePolicyIdentifier
      signature_policy_id = etree.SubElement(
      signature_policy_identifier,
      etree.QName(xades, 'SignaturePolicyId')
      )

      # GENERO EL NODO xades:SigPolicyId DENTRO DE xades:SignaturePolicyId
      sig_policy_id = etree.SubElement(
      signature_policy_id,
      etree.QName(xades, 'SigPolicyId')
      )

      # GENERO EL NODO xades:Identifier DENTRO DE xades:SigPolicyId
      etree.SubElement(
      sig_policy_id,
      etree.QName(xades, 'Identifier')
      ).text = sig_policy_identifier

      #BORRO ESTE NODO PUES EN FE COSTA RICA NO SE NECESITA
      etree.SubElement(
      sig_policy_id,
      etree.QName(xades, 'Description')
      )#.text = "Política de Firma FacturaE v3.1"

      # GENERO EL NODO xades:Identifier DENTRO DE signature_policy_id
      sig_policy_hash = etree.SubElement(
      signature_policy_id,
      etree.QName(xades, 'SigPolicyHash')
      )

      # GENERO EL NODO ds:DigestMethod DENTRO DE xades:Identifier
      etree.SubElement(
      sig_policy_hash,
      etree.QName(xmlsig.constants.DSigNs, 'DigestMethod'),
      attrib={
      'Algorithm': 'http://www.w3.org/2000/09/xmldsig#sha1'
      })

      #GENERO EL DIGEST PARA EL CERTIFICADO LEYENDOLO DE LA URL DE HACIENDA
      try:
      remote = urllib.request.urlopen(sig_policy_identifier)
      hash_value = base64.b64encode(hashlib.sha256(remote.read()).digest())
      except urllib.request.HTTPError:
      hash_value = sig_policy_hash_value

      # GENERO EL NODO ds:DigestValue ds:DigestMethod DENTRO DE sig_policy_hash
      etree.SubElement(
      sig_policy_hash,
      etree.QName(xmlsig.constants.DSigNs, 'DigestValue')
      ).text = hash_value

      #NO REQUERIDO PARA FE COSTA RICA
      #signer_role = etree.SubElement(
      # signed_signature_properties,
      # etree.QName(etsi, 'SignerRole')
      #)
      #claimed_roles = etree.SubElement(
      # signer_role,
      # etree.QName(etsi, 'ClaimedRoles')
      #)

      #etree.SubElement(
      # claimed_roles,
      # etree.QName(etsi, 'ClaimedRole')
      #).text = 'supplier'

      signed_data_object_properties = etree.SubElement(
      signed_properties,
      etree.QName(xades, 'SignedDataObjectProperties')
      )

      data_object_format = etree.SubElement(
      signed_data_object_properties,
      etree.QName(xades, 'DataObjectFormat'),
      attrib={
      'ObjectReference': '#' + reference_id
      }
      )

      #etree.SubElement(
      # data_object_format,
      # etree.QName(etsi, 'Description')
      #).text = 'Factura'

      etree.SubElement(
      data_object_format,
      etree.QName(xades, 'MimeType')
      ).text = 'text/xml'

      ctx = xmlsig.SignatureContext()
      key = crypto.load_pkcs12(base64.b64decode(cert), password)
      ctx.x509 = key.get_certificate().to_cryptography()
      ctx.public_key = ctx.x509.public_key()
      ctx.private_key = key.get_privatekey().to_cryptography_key()
      root.append(sign)

      root.xpath(
      '//ds:Signature', namespaces={'ds': xmlsig.constants.DSigNs}
      )[0]

      ctx.sign(sign)

      #xml_bytes = etree.tostring(root, xml_declaration=True)

      #return stringToBase64(xml_bytes)


      return etree.tostring(
      root
      )


      That code produces a xml signature in the following way



      <ds:Signature Id="Signature-17044">
      <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference Id="Reference-74608" URI="">
      <ds:Transforms>
      <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
      </ds:Transforms>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>+fhrrmGMWpvy8IEowaa2fLh905rLv6xRmKB4zD6Omtg=</ds:DigestValue>
      </ds:Reference>
      <ds:Reference Id="ReferenceKeyInfo" URI="#KeyInfoId-Signature-17044">
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>zXjLpycv3XvGI47RJR0qIoxtZoApAHwkdjDqRKiGpTU=</ds:DigestValue>
      </ds:Reference>
      <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#SignedProperties-Signature-17044">
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>sHX8p3YfyvxNIwL2NC54sZdYfvsfXvfYTCks/8BMQlQ=</ds:DigestValue>
      </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue Id="SignatureValue-17044">B9Mb3Ogm1QNkpu1N8o4rF0EP4a/vM9Yjgk7EiYZBQmU/r6+yZ/pVC27XYJubbcoxhlth1pk4y15d95I7RfqdqOwMt8dj6P9FKljPH2jCRU0IlHCul3eudjaBWfbu2+fjpyIFRO53kHhOfumkstMKtSCAPSgHRV0wLb06JcZhVCUXUNy+rJfElxzJjhNq+aHcIjayf2TVs1w/elFOz9Ax2v18xol6BRyHnlrQEUtD57AiVurkkcGs0oUqrDGV7IN3YebBJWge/ttXF+5Bz9NnBHQD4iU5ul3aGhcOwq7FY7qxIbmqBHhmcLi7ZGVCXfiEU58Sn6Sa8yBjOILh5Wgzng==</ds:SignatureValue>
      <ds:KeyInfo Id="KeyInfoId-Signature-17044">
      <ds:X509Data>
      <ds:X509Certificate>MIIFRjCCAy6gAwIBAgIGAWZEbfKCMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNVBAYTAkNSMSkwJwYDVQQKDCBNSU5JU1RFUklPIERFIEhBQ0lFTkRBIC0gU0FOREJPWDEMMAoGA1UECwwD</ds:X509Certificate>
      </ds:X509Data>
      <ds:KeyValue>
      <ds:RSAKeyValue>
      <ds:Modulus>pVc+nKRrS6q2O05DEO7r1smiY/0PDTZpYSirjEzPaxQ2hRvZDGaxX8wEzqiAE7i9icZbqtwaQPECBRhlzjEK4lxbDhESqYI34CKiMMeARquVGn9WJ/EQjQhGm1KgqROvizX3LRcxDgJzd6pbKPxqTUC/gDAy/PEJJuD9WOH0NVYCREZtD3ShkiIt3DphbDK84Whqhvt47ZyFRSIgjxrRkerhOZj3EzFjr4aIADXUXY2LJGTyKHEe8WcvA9k/aaZGZaTRINOwgk4KMSzNXBDweoxXzN0bJukbxXEicLqO7cJHqoaZX0gCDU8KfAN2UAtmhQ/IRgkSD6O2F72kC86ePQ==</ds:Modulus>
      <ds:Exponent>AQAB</ds:Exponent>
      </ds:RSAKeyValue>
      </ds:KeyValue>
      </ds:KeyInfo>
      <ds:Object Id="XadesObjectId-41822">
      <xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Id="QualifyingProperties-01611" Target="#Signature-17044">
      <xades:SignedProperties Id="SignedProperties-Signature-17044">
      <xades:SignedSignatureProperties>
      <xades:SigningTime>2018-11-12T15:24:21-06:00</xades:SigningTime>
      <xades:SigningCertificate>
      <xades:Cert>
      <xades:CertDigest>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>gVmykfOS2A4p8ALJ6XVLcdTagMz+hMG4ikjzFipgymI=</ds:DigestValue>
      </xades:CertDigest>
      <xades:IssuerSerial>
      <ds:X509IssuerName>CN=CA PERSONA JURIDICA - SANDBOX,OU=DGT,O=MINISTERIO DE HACIENDA - SANDBOX,C=CR</ds:X509IssuerName>
      <ds:X509SerialNumber>1538746348162</ds:X509SerialNumber>
      </xades:IssuerSerial>
      </xades:Cert>
      </xades:SigningCertificate>
      <xades:SignaturePolicyIdentifier>
      <xades:SignaturePolicyId>
      <xades:SigPolicyId>
      <xades:Identifier>https://www.hacienda.go.cr/ATV/ComprobanteElectronico/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf</xades:Identifier>
      <xades:Description/>
      </xades:SigPolicyId>
      <xades:SigPolicyHash>
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
      <ds:DigestValue>a5aV6NckKzC/0CR4tQeTg2ULnhUNK2uDxsO5VuRInTE=</ds:DigestValue>
      </xades:SigPolicyHash>
      </xades:SignaturePolicyId>
      </xades:SignaturePolicyIdentifier>
      </xades:SignedSignatureProperties>
      <xades:SignedDataObjectProperties>
      <xades:DataObjectFormat ObjectReference="#Reference-74608">
      <xades:MimeType>text/xml</xades:MimeType>
      </xades:DataObjectFormat>
      </xades:SignedDataObjectProperties>
      </xades:SignedProperties>
      </xades:QualifyingProperties>
      </ds:Object>
      </ds:Signature>


      Xml result has the i need but i get alway invalida signature response. While checking the signature this is the response i get



      Checking signature...
      xmlsec:



      func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=250:obj=sha256:subj=unknown:error=12:invalid data:data and digest do not match
      FAIL
      SignedInfo References (ok/all): 1/2
      Manifests References (ok/all): 0/0



      but i have no idea what the problem can be



      Any ideas?



      NOTE: CERTIFICATE INFORMATION HAS BEEN CUTED







      python xml signature






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 12 '18 at 21:30









      Jason

      2516




      2516





























          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270392%2fxml-digital-signature-in-python%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270392%2fxml-digital-signature-in-python%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python