open-eid / digidoc4j

DigiDoc for Java. Javadoc:
http://open-eid.github.io/digidoc4j
GNU Lesser General Public License v2.1
72 stars 39 forks source link

Cryptographic signature verification has failed - issue during signature finalize #135

Open Ashkehn opened 2 months ago

Ashkehn commented 2 months ago

Hi all,

I am developing a simple digital signing application and closely followed the documentation. However, when I attempt to finalize the signature using the finalize method from the DataToSign class, I encounter the following error: eu.europa.esig.dss.model.DSSException: Cryptographic signature verification has failed / Signature verification failed against the best candidate. image image

I am using a self signed x509 certificate generated on my windows machine.

Thanks in advance.

rsarendus commented 2 months ago

Hello,

Cryptographic signature verification failure indicates that the signature you provided fails to validate against the public key of your certificate. This could have many reasons, including:


At the following line of your code:

signatureDTO.setBase64Signature(digestDTO.getHash());

What does digestDTO::getHash return? What does signatureDTO::setBase64Signature do?

At the following line of your code:

byte[] signatureBytes = DatatypeConverter.parseBase64Binary(signatureDTO.getBase64Signature());

How is the signature, returned by signatureDTO::getBase64Signature, obtained?

Is the signature creation implemented in Java or is the signing done remotely using some other means?


The exact way to sign the input data depends on the tool that you are using.

For example, in case of using java.security.Signature for signing in Java, you must also pay attention to the signature algorithm. Signature algorithms like "SHA256withRSA"* (in case of signing with an RSA key) and "SHA256withECDSA"* (in case of signing with an EC key), expect that you provide the raw, un-hashed data-to-sign:

Signature signature = Signature.getInstance("SHA256withRSA"); // or "SHA256withECDSA"
signature.init(yourPrivateKey); // Initialize the signature with your private key
signature.update(dataToSign.getDataToSign()); // Provide the raw, un-hashed input
return signature.sign();

But if you calculate the digest of the data-to-sign yourself, then you must use signature algorithms like "NONEwithRSA" (in case of signing with an RSA key) and "NONEwithECDSA" (in case of signing with an EC key).

Signature signature = Signature.getInstance("NONEwithECDSA");
signature.init(yourPrivateKey); // Initialize the signature with your private key
signature.update(digest); // Provide the digest that you have calculated
return signature.sign();

NB: "SHA256withRSA"* signature algorithm corresponds to RSASSA-PKCS1-v1_5 signature scheme. This means that when using RSA key for signing and you calculate the digest yourself, then you must also prepend the digest with appropriate padding:

Signature signature = Signature.getInstance("NONEwithRSA");
signature.init(yourPrivateKey); // Initialize the signature with your private key
signature.update(dataToSign.getDigestAlgorithm().digestInfoPrefix()); // Prepend the digest with padding
signature.update(digest); // Append the digest that you have calculated
return signature.sign();

* The digest algorithm in the above examples has been chosen based on your example code. When using a different digest algorithm, adapt the examples accordingly.

Ashkehn commented 2 months ago

Hello,

I managed to resolve the issue, but now I am encountering another problem with the (Signature ID: id-e68830f0f475537cb207ac01bb696c3b) - OCSP request failed. Kindly refer to the GitHub Wiki for more information: https://github.com/open-eid/digidoc4j/wiki/Questions-&-Answers#if-ocsp-request-has-failed.

I have checked the GitHub link but haven't found the solution.

I use a self-signed certificate, and the configuration mode is set to TEST. Tried to set

 Configuration::setOCSPAccessCertificateFileName("mypath");
  Configuration::setOCSPAccessCertificatePassword("");
  or 
  Configuration::setSignOCSPRequests(false);

Thank you

naare commented 2 months ago

If you need to test the signing I suggest you use keystore that is already made for testing purposes in DD4J project (you can see references and pins): https://github.com/open-eid/digidoc4j/blob/a7a1e77186d67d551072a40412f1d76bfc5b1799/digidoc4j/src/test/java/org/digidoc4j/AbstractTest.java#L111

These keystores work out of the box with DD4J in TEST mode and can be used for testing purposes.

Using your own certificate for LT profile signature means that the issued certificate profile must match all the requirements, it must be trusted (present in TSL or trusted programmatically together with all needed qualifiers) and must have valid OCSP response. Fullfilling all these conditions with self issued certificates requires specific knowledge and is not easily achieved.