Pdf signing using USB device

23 views Asked by At

I am trying to sign a pdf with DSC usb Token using itext 7 version. I searched a lot and tried different combination of codes from the internet, but result being same "Document has been altered" I know there is some problem in the hash mismatch. I don't have the certificate to use pdfpkcs7. I am trying with epass2003auto, usb token.

I am trying to sign the pdf with usb dsc token.

  1. I have a client, which takes base64 of hash, and then returns signed hash. Code below:
private static byte[] sign(String content, PrivateKey privateKey, Certificate[] chain, String provider) throws Exception {
        byte[] hash = Base64.decodeBase64(content);
        String digestAlgorithm = "SHA-256";
        AlgorithmId[] digestAlgorithmIds = new AlgorithmId[]{AlgorithmId.get(digestAlgorithm)};
        Signature s = Signature.getInstance("SHA256WithRSA", provider);
        s.initSign(privateKey);
        s.update(hash);
        byte[] signature = s.sign();
        ContentInfo contentInfo = new ContentInfo(ContentInfo.DATA_OID, (DerValue)null);
        int index = 0;
        int length = chain == null ? 0 : chain.length;
        X509Certificate[] certificates = new X509Certificate[length];

        X509Certificate x509;
        for(x509 = null; index < length; ++index) {
            X509Certificate tempCertificate = (X509Certificate)chain[index];
            certificates[index] = tempCertificate;
            boolean[] keyUsage = tempCertificate.getKeyUsage();
            if (keyUsage != null && keyUsage[0]) {
                x509 = tempCertificate;
            }
        }
        Validate.notNull(x509, "Selected encryption certificate cannot be used for digital signing.");
        BigInteger serial = x509.getSerialNumber();
        String issuerName = x509.getIssuerDN().getName();
        AlgorithmId dAlgId = AlgorithmId.get(digestAlgorithm);
        SignerInfo si = new SignerInfo(new X500Name(issuerName), serial, dAlgId, new AlgorithmId(AlgorithmId.RSAEncryption_oid), signature);
        SignerInfo[] signerInfos = new SignerInfo[]{si};
        PKCS7 pkcs7 = new PKCS7(digestAlgorithmIds, contentInfo, certificates, signerInfos);


        ByteArrayOutputStream bytes = new DerOutputStream();
        pkcs7.encodeSignedData(bytes);
        byte[] output = bytes.toByteArray();
        return output;
    }
  1. Code to create empty signature block.
public Result preparesign(Http.Request request)
{
    String src = config.getString("app.temporaryDirectory") + "dummy.pdf";
    String dest = config.getString("app.temporaryDirectory") + "dsc_ready_to_sign.pdf";
   byte[] hashToSign = createBlankSignature(src, dest, "Sig");
// send to client.

}
private byte[] createBlankSignature(String src, String temp, String fieldName) throws IOException, GeneralSecurityException {
        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(temp);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(temp), new StampingProperties().useAppendMode());
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setLayer2FontSize(6)
                .setPageRect(new Rectangle(36, 650, SIGNATURE_WIDTH, SIGNATURE_HEIGHT))
                .setPageNumber(1)
                .setSignatureCreator("BS");
        signer.setFieldName(fieldName);
        MyExternalBlankSignatureContainer external = new MyExternalBlankSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
        signer.signExternalContainer(external, 16000);
        return external.getHash4Sign();

    }

 public class MyExternalBlankSignatureContainer implements IExternalSignatureContainer {

        /* Signature dictionary. Filter and SubFilter.  */
        private PdfDictionary sigDic;
        @Getter
        private byte[] hash4Sign = null;


    public MyExternalBlankSignatureContainer(PdfName filter, PdfName subFilter) {
            sigDic = new PdfDictionary();
            sigDic.put(PdfName.Filter, filter);
            sigDic.put(PdfName.SubFilter, subFilter);
        }

       @Override
        public byte[] sign(InputStream data) throws GeneralSecurityException {
            try {
                String hashAlgorithm = DigestAlgorithms.SHA256;//"SHA-256";
                BouncyCastleDigest digest = new BouncyCastleDigest();
                MessageDigest md = digest.getMessageDigest(hashAlgorithm);

                byte[]   hash = DigestAlgorithms.digest(data, md);
                hash4Sign = hash;

                return new byte[0];
            } catch (IOException | GeneralSecurityException de) {
                de.printStackTrace();
                throw new GeneralSecurityException(de);
            }
        }

        @Override
        public void modifySigningDictionary(PdfDictionary signDic) {
            signDic.putAll(sigDic);
        }
    }
  1. Send the signed hash to client. put the signed hash to pdf.
public Result signDoc(Http.Request request)
    {
        String src = config.getString("app.temporaryDirectory") + "dsc_ready_to_sign.pdf";
        String dest = config.getString("app.temporaryDirectory") + "dsc_signed.pdf";
       try
        {
            Form<DSCSignResponse> dscSignResponseForm = formFactory.form(DSCSignResponse.class).bindFromRequest(request);
            if(dscSignResponseForm.hasErrors())
            {
                return badRequest(dscSignResponseForm.errorsAsJson());
            }
            for(DSCSignResponse.Document document : dscSignResponseForm.get().getDocuments()) {
                PdfReader reader = new PdfReader(src);
                try(FileOutputStream os = new FileOutputStream(dest)) {
                    PdfSigner signer = new PdfSigner(reader, os, new StampingProperties().useAppendMode());
                    byte[] signatureBytes = Base64.getDecoder().decode(document.getEncodeBase64Sign());
                    
                    IExternalSignatureContainer external = new MyExternalSignatureContainer(signatureBytes, PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
                    PdfSigner.signDeferred(signer.getDocument(), "Sig", os, external);

                }
            }

        }
        catch (Exception ex)
        {
            System.out.println(ex.getMessage());
        }


    }
     public class MyExternalSignatureContainer implements IExternalSignatureContainer {

       /* Signature dictionary. Filter and SubFilter.  */
       private PdfDictionary sigDic;
       private byte[] signedHash =null;
       private Certificate[] chain = null;

       public MyExternalSignatureContainer(byte[] _signedHash, PdfName filter, PdfName subFilter) {
           sigDic = new PdfDictionary();
           sigDic.put(PdfName.Filter, filter);
           sigDic.put(PdfName.SubFilter, subFilter);
           signedHash = _signedHash;
       }

       @Override
       public byte[] sign(InputStream data) throws GeneralSecurityException {
           try {
               return signedHash;
           } catch (Exception de) {
               de.printStackTrace();
               throw new GeneralSecurityException(de);
           }
       }

       @Override
       public void modifySigningDictionary(PdfDictionary signDic) {
           signDic.putAll(sigDic);
       }
   }

I am getting Document has been altered error.

Can anyone let me know the issue here. Appreciate your help.

0

There are 0 answers