0
votes

I get Error "The document has been altered or corrupted since the signature was applied" when signature was applied to pdf using itext.

Digitally signed pdf is generated but the green check mark is not coming. What has to be done to get that green check mark.

Right now it says signature is INVALID.

I used following link for reference http://itextpdf.com/examples/iia.php?id=222

I use following code to apply signature using iText.

    String path = "resources/examplestore";
    String keystore_password = "password";
    String key_password = "password";
    String alias = "signFiles";
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(new FileInputStream(path), keystore_password.toCharArray());
    PrivateKey pk = (PrivateKey) ks.getKey(alias, key_password.toCharArray());
    Certificate[] chain = ks.getCertificateChain(alias);
    String path = "resources/examplestore";
    String keystore_password = "password";
    String key_password = "password";
    String alias = "signFiles";
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(new FileInputStream(path), keystore_password.toCharArray());
    PrivateKey pk = (PrivateKey) ks.getKey(alias, key_password.toCharArray());
    Certificate[] chain = ks.getCertificateChain(alias);

    PdfReader reader = new PdfReader(src);
    FileOutputStream os = new FileOutputStream(dest);
    PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);

    PdfSignatureAppearance appearance = stamper
            .getSignatureAppearance();
    appearance.setReason("I'm approving this.");
    appearance.setLocation("Foobar");
    appearance.setVisibleSignature(new Rectangle(160, 732, 232, 780), 1, "second");

    ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");
    ExternalDigest digest = new BouncyCastleDigest();
    MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);

    I also Verify the code after this.
1
Please provide a sample file signed by your code.mkl
Please find the sample pdf file signed by my code. To download please click hereuser3610915
I'm looking into that file. It does not seem to have been signed with the code you posted, though: PdfStamper.createSignature(reader, os, '\0', null, true); creates a signature in append mode but your sample PDF has only one revision. Furthermore your code creates a signature field "second" while the PDF contains a signature field "first".mkl
Yes the code which was shown above has signature field "second" .. Actual code used to generate the pdf which is attached above is same which is show in this link itextpdf.com/examples/iia.php?id=222 ... If you see the code in the example.. it signs pdf 2 times .. first time it uses PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0'); ... but second time it uses PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true); i.e. in append mode .. is this creates issue?user3610915
Even if i don't sign it second time .. i.e. i only sign with signature field "first" .. the resulting pdf still has same issue.user3610915

1 Answers

1
votes

I am not completely sure in this answer as I hardly ever had to deal with DSA signature, generally I had to deal with RSA or ECDSA signatures.

The HASH value is ok.

The first assumption upon seeing a "The document has been altered or corrupted since the signature was applied" message is that the actual document hash differs from the document hash included in the signature. (Altering the document would result in such a difference.) In case of your document, though, the HASH value in the signature's signed attribute messageDigest is correct.

Thus, the problem is in the signature itself.

A quite obvious peculiarity is the used signature algorithm:

1071 06    7:             OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
            :               (ANSI X9.57 algorithm)
    <05 00>
1080 05    0:             NULL
            :             }

This is peculiar because the signature algorithm needs to include a HASH algorithm to allow for verification, e.g.

The algorithm identifier for DSA with SHA-1 signature values is:

  id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
      us(840) x9-57 (10040) x9cm(4) 3 }

(RFC 3370 section 3.1 DSA)

or

When SHA-224 is used, the OID is:

id-dsa-with-sha224 OBJECT IDENTIFIER  ::=  { joint-iso-ccitt(2)
   country(16) us(840) organization(1) gov(101) csor(3)
   algorithms(4) id-dsa-with-sha2(3) 1 }.

When SHA-256 is used, the OID is:

id-dsa-with-sha256 OBJECT IDENTIFIER  ::=  { joint-iso-ccitt(2)
   country(16) us(840) organization(1) gov(101) csor(3)
   algorithms(4) id-dsa-with-sha2(3) 2 }.

(RFC 5758 section 3.1 DSA Signature Algorithm)

In old SMIME specs using id-dsa instead of id-dsa-with-XXX was interpreted as id-dsa-with-sha1.

Thus, if during verification the algorithm identifier from your signature is accepted at all, it is interpreted to have been used in context with SHA1; your code, though (and I assume your signing code for the signatures first and second coincides in this respect), contains:

ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");

I.e. your code hashes using SHA-256. Thus, your signature won't be positively verified.

The issue

The background issue is that com.itextpdf.text.pdf.security.PdfPKCS7.setExternalDigest(byte[], byte[], String) for DSA signatures only stores the id-dsa OID in digestEncryptionAlgorithmOid and PdfPKCS7.getEncodedPKCS7(byte[], Calendar, TSAClient, byte[], Collection<byte[]>, CryptoStandard) uses digestEncryptionAlgorithmOid as is as signature algorithm OID.

Thus, for all DSA signatures id-dsa is used as signature algorithm even though it actually should not be used at all, and if it is used implies SHA-1.

PS: In case of RSA signatures not including the HASH algorithm in the signature algorithm value is no problem because RSA signatures actually are encoded structures mentioning the HASH algorithm used. DSA, on the other hand, is not about decoding but merely about checking, so there is no implicit HASH algorithm mentioned anywhere.