XAdES creation with manual signature entry

641 Views Asked by At

I am trying to create a digitally signed XML document using the signature from my ID card.

I have two parts of the program. The first one is getting the certificates and signature of the file from the ID. For that I am using python PKCS11 library with something like this:

with open("input.xml", "rb") as f:
    data = f.read()

lib = lib('path/to/pkcs11/lib.dylib')
token = lib.get_token('name of token')

with token.open(PIN) as session:
    certificate = None

    for obj in session.get_objects({Attribute.CLASS: ObjectClass.CERTIFICATE}):
        certificate = obj
        der_bytes = certificate[Attribute.VALUE]

    with open('certificate.der', "wb") as f:
        f.write(der_bytes)

    # calculate SHA256 of data
    digest = session.digest(data, mechanism=Mechanism.SHA256)

    for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
        private_key = obj

    signature = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)

    with open('signature', "wb") as f:
        f.write(signature)

That generates the certificate.der and signature files and is working properly (at least I think)

For the XML generation part I am using Europe's DSS library in Java like this:

DSSDocument toSignDocument = new FileDocument("input.xml");

// Preparing parameters for the XAdES signature
XAdESSignatureParameters parameters = new XAdESSignatureParameters();

// We choose the level of the signature (-B, -T, -LT, -LTA).     
parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B);

// We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED).
parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED);

// We set the digest algorithm to use with the signature algorithm. You must use the
// same parameter when you invoke the method sign on the token. The default value is SHA256 parameters.setDigestAlgorithm(DigestAlgorithm.SHA256);

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new FileInputStream("certificate.der");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);

// We set the signing certificate
parameters.setSigningCertificate(new CertificateToken(cert));

// Create common certificate verifier
CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();

// Create XAdES service for signature
XAdESService service = new XAdESService(commonCertificateVerifier);

// Get the SignedInfo XML segment that need to be signed.
ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));

// We invoke the service to sign the document with the signature value obtained in
// the previous step.
DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

File signedFile = new File("output.xml");
signedFile.createNewFile();
signedDocument.writeTo(new FileOutputStream(signedFile, false));

That creates XAdES file, but when I try to validate the signature (e.g. using this) it fails saying the signature is not intact.

What am I doing wrong?

1

There are 1 best solutions below

0
On

You do not use dataToSign variable at all for signature value creation.

What you should do is by using the private key corresponding to the created certificate to actually sign the digested dataToSign. I.e., instead of:

File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));

you should do something like this (using your example above):

# calculate SHA256 of data
digest = session.digest(dataToSign, mechanism=Mechanism.SHA256)

for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
    private_key = obj

signatureValue = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)

Please pay attention, that you shall sign not the original document, but the dataToSign, as it contains the reference to the original document (its digest), but also signed parameters, required to ensure compliance to AdES format.

I hope this will help you.

Best regards, Aleksandr.