0
votes

I can sign document using itextpdf library with external signature.

But the problem is that the end user doesn't want to send his document because it may contain any sensitive data. So, I asked the end user to give document hash for signing the hash with external service and send the signed hash back.

But, here comes the problem, when they tried to sign the document with the given signed hash using itextpdf (PdfSignatureAppearance) the PDF document is getting signed. But when verifying the signature it showing that the signature is invalid.

I've seen the same kinda question here Sign PDF using an external service and iText .

So, the problem happens because the hash gets invalidated each time when we open the document using PdfSignatureAppearance (itextpdf library).

Can anyone please tell me whether it is possible to sign the PDF document with previously generated hash and signed hash (which I got from external service) using itextpdf library so that the hash should not get invalidated?

1
I would guess that if you hash the PDF on its bytes using something like SHA512 directly, the hash should stay the same all the time unless the PDF content gets changed.StoneBird
It's not sufficient to sign the document bytes. Certain attributes need to be signed too. Your end customer shouldn't create the hash without using iText. Another addition to @StoneBird's comment would be that you can't just hash the complete document. You have to leave a "hole" in the PDF where the signature will be put. It should be obvious that every byte in the PDF should be signed except the signature itself.Bruno Lowagie
@Harish cf. stack overflow documentation for some backgrounds on PDF signatures.mkl

1 Answers

0
votes
class MyExternalSignatureContainer implements ExternalSignatureContainer {
    protected byte[] sig;
    protected Certificate[] chain;
    protected PrivateKey pk;
    public MyExternalSignatureContainer(byte[] sig,Certificate[] chain,PrivateKey pk) {
        this.sig = sig;
        this.chain=chain;
        this.pk=pk;
    }
    public byte[] sign(InputStream is)throws GeneralSecurityException  {

        return sig;

    }
    public void modifySigningDictionary(PdfDictionary signDic) {
    }
}

 public byte[] emptySignature_hash(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(dest);
        PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
        appearance.setCertificate(chain[0]);
        ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
        MakeSignature.signExternalContainer(appearance, external, 8192);



        InputStream inp = appearance.getRangeStream();  

        BouncyCastleDigest digest = new BouncyCastleDigest();


         byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
         return hash;


    }


public byte[] signed_hash(byte[] hash, PrivateKey pk, Certificate[] chain)throws GeneralSecurityException{
        PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "SunPKCS11-eToken");

        //return extSignature;
       BouncyCastleDigest digest = new BouncyCastleDigest();
        Calendar cal = Calendar.getInstance();
        String hashAlgorithm = signature.getHashAlgorithm();
        System.out.println(hashAlgorithm);
        PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);

        byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
        byte[] extSignature = signature.sign(sh);

        System.out.println(signature.getEncryptionAlgorithm());

       // Calendar cal = Calendar.getInstance();
        sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
    return sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);

        }
    public void createSignature(String src, String dest, String fieldname,byte[] hash, PrivateKey pk, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {

    PdfReader reader = new PdfReader(src);
    FileOutputStream os = new FileOutputStream(dest);
    ExternalSignatureContainer external = new MyExternalSignatureContainer(hash,chain,pk);
    MakeSignature.signDeferred(reader, fieldname, os, external);
}


public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
 byte[] hh = app.emptySignature_hash(SRC, TEMP, "sig1", chain);
 byte[] hh_sign = (app.signed_hash(hh,  pk,  chain));

 app.createSignature(TEMP, DEST1, "sig1",hh_sign, pk, chain);

    }