0

Hello I'm working on a script to sign XML files with Xades (mandatory). I never worked before in signing XML files so I'm quite lost.

The error seems realted to the sign policy but I'm not sure how it is done. I must add a link to "http://ticketbai.eus/politicafirma", and the policy hash is: "d69VEBc4ED4QbwnDtCA2JESgJiw+rwzfutcaSl5gYvM=" . I also need to take in account that the key must be above 1024 bytes.

Note: I'm working on Python because I'm the most used to it, but I don't have inconvenience to change. The certificate is validated and working correctly apart from the script.

TRACEBACK

    ctx.sign(signature)
  File "C:\Users\acarrera\AppData\Local\Programs\Python\Python39\lib\site-packages\xades\xades_context.py", line 47, in sign
    self.calculate_signed_properties(signed_properties, node, True)
  File "C:\Users\acarrera\AppData\Local\Programs\Python\Python39\lib\site-packages\xades\xades_context.py", line 102, in calculate_signed_properties
    self.calculate_signature_properties(signature_properties, node, sign)
  File "C:\Users\acarrera\AppData\Local\Programs\Python\Python39\lib\site-packages\xades\xades_context.py", line 125, in calculate_signature_properties
    self.policy.calculate_certificates(
  File "C:\Users\acarrera\AppData\Local\Programs\Python\Python39\lib\site-packages\xades\policy.py", line 134, in calculate_certificates
    for key_x509 in keys_x509:
TypeError: 'builtins.Certificate' object is not iterable

PYTHON CODE

import os
import xmlsig
from lxml import etree
from OpenSSL import crypto
from xades import XAdESContext, template, utils
from xades.policy import GenericPolicyId

SIGN_POLICY = f"https://ticketbai.araba.eus/tbai/sinadura/"
CERTIANDER = os.environ.get(
    'CERTIANDER',
    r'SOLDISP_PF2856A9_CERT.pfx')

parsed_file = etree.parse('Factura1.xml').getroot()

signature = xmlsig.template.create(
    xmlsig.constants.TransformInclC14N,
    xmlsig.constants.TransformRsaSha256,
    "Signature",
)
signature_id = utils.get_unique_id()

ref = xmlsig.template.add_reference(
    signature, xmlsig.constants.TransformSha256, uri="", name="REF"
)

xmlsig.template.add_transform(ref, xmlsig.constants.TransformEnveloped)

xmlsig.template.add_reference(
        signature, xmlsig.constants.TransformSha256, uri="#" + signature_id
    )

xmlsig.template.add_reference(
    signature, xmlsig.constants.TransformSha256, uri="#" + signature_id
)

ki = xmlsig.template.ensure_key_info(signature, name="KI")
data = xmlsig.template.add_x509_data(ki)
xmlsig.template.x509_data_add_certificate(data)
serial = xmlsig.template.x509_data_add_issuer_serial(data)
xmlsig.template.x509_issuer_serial_add_issuer_name(serial)
xmlsig.template.x509_issuer_serial_add_serial_number(serial)
xmlsig.template.add_key_value(ki)
qualifying = template.create_qualifying_properties(
    signature, name=utils.get_unique_id(), etsi='xades'
)


props = template.create_signed_properties(qualifying, name=signature_id)


policy = GenericPolicyId(
        SIGN_POLICY,
        xmlsig.constants.TransformSha256,
    )

parsed_file.append(signature)

with open(CERTIANDER, "rb") as key_file:
    pfx = key_file.read()
        
certificate = crypto.load_pkcs12(pfx, b'password') #Personal Password

ctx = XAdESContext(
        policy,
        certificate.get_certificate().to_cryptography(),
    )

ctx.load_pkcs12(certificate)
ctx.sign(signature)

parsed_file[0][0][0].append(signature) 

et = etree.ElementTree(parsed_file)
    
nfs_name = 'Firmado'
et.write(nfs_name, pretty_print=True,
            encoding='utf-8', xml_declaration=True)

2 Answers2

0

I had the same issue and at the end of this question How to sign using Xades-EPES standard with Python? they mention the only difference is that the library can have multiple certificates and you can only have one. I modified the library and eliminated the for where it fails. That worked for me!

  • 3
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 05 '22 at 14:37
0

I'm Having Same Problems But I Read the documentation on git-hub and I managed to sign xml with one function of the library. If you are in Spain I signed the xml and Autofirma detect valid sign, but on the web Valida Firma is not and I don't know why

Import these libraries.

import xmlsig
from lxml import etree
from OpenSSL import crypto
from xades import XAdESContext, template, utils
from xades.policy import GenericPolicyId
class UrllibMock:
    def read(self):
        with open(path.join(BASE_DIR, "data/policy.pdf"), "rb") as f:
            result = f.read()
        return result
def test_create_2(self):

        root = parse_xml("data/free-sample.xml")#Tu xml
        signature = xmlsig.template.create(
            xmlsig.constants.TransformInclC14N,
            xmlsig.constants.TransformRsaSha1,
            "Signature",
        )
        ref = xmlsig.template.add_reference(
            signature, xmlsig.constants.TransformSha1, uri="", name="R1"
        )
        xmlsig.template.add_transform(ref, xmlsig.constants.TransformEnveloped)
        xmlsig.template.add_reference(
            signature, xmlsig.constants.TransformSha1, uri="#KI", name="RKI"
        )
        ki = xmlsig.template.ensure_key_info(signature, name="KI")
        data = xmlsig.template.add_x509_data(ki)
        xmlsig.template.x509_data_add_certificate(data)
        serial = xmlsig.template.x509_data_add_issuer_serial(data)
        xmlsig.template.x509_issuer_serial_add_issuer_name(serial)
        xmlsig.template.x509_issuer_serial_add_serial_number(serial)
        xmlsig.template.add_key_value(ki)
        qualifying = template.create_qualifying_properties(signature)
        utils.ensure_id(qualifying)
        utils.ensure_id(qualifying)
        props = template.create_signed_properties(qualifying, datetime=datetime.now())
        template.add_claimed_role(props, "Supp")
        signed_do = template.ensure_signed_data_object_properties(props)
        template.add_data_object_format(
            signed_do, "#R1", identifier=ObjectIdentifier("Idenfitier0", "Description")
        )
        template.add_commitment_type_indication(
            signed_do,
            ObjectIdentifier("Idenfitier0", "Description"),
            qualifiers_type=["Tipo"],
        )

        template.add_commitment_type_indication(
            signed_do,
            ObjectIdentifier("Idenfitier1", references=["#R1"]),
            references=["#R1"],
        )
        template.add_data_object_format(
            signed_do,
            "#RKI",
            description="Desc",
            mime_type="application/xml",
            encoding="UTF-8",
        )
        root.append(signature)
        ctx = XAdESContext(ImpliedPolicy(xmlsig.constants.TransformSha1))
        with open(path.join(BASE_DIR, "data/CertificadoPrueba.p12#Path to your certificate"), "rb") as key_file:
            ctx.load_pkcs12(pkcs12.load_key_and_certificates(key_file.read(), b"Certificate Password"))
        with patch("xades.policy.urllib.urlopen") as mock:
            mock.return_value = UrllibMock()
            ctx.sign(signature)
            ctx.verify(signature)


        et = etree.ElementTree(root)
    
        nfs_name = 'FirmadoMedias'#Name Of New xml signed
        et.write(nfs_name, pretty_print=True,
                encoding='utf-8', xml_declaration=True)



Javier
  • 1