0
votes

I am trying through HWCryto - https://github.com/open-eid/hwcrypto.js/wiki/ModernAPI - to add support in a Struts2 application to digital signing. Trying to follow Bruno Lowagie's book first i create an empty signature

    CertificateFactory certFactory;
    try {
        certFactory = CertificateFactory.getInstance("X.509");
        ByteArrayInputStream in = new ByteArrayInputStream(certDecoded);
        cert = (X509Certificate) certFactory.generateCertificate(in);
    } catch (CertificateException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    Calendar cal = Calendar.getInstance();

    int estimatedSize = 8192;

    PdfSignatureAppearance sap = pdfStamper.getSignatureAppearance();

    sap.setVisibleSignature("sig");
    sap.setCertificate(cert);
    sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
    sap.setSignDate(cal);
    ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE,
            PdfName.ADBE_PKCS7_DETACHED);

    try {
        MakeSignature.signExternalContainer(sap, external, 8192);
        pdfStamper.close();
        pdfReader.close();
    } catch (GeneralSecurityException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (DocumentException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

After that i get the pdf output and create a new hash that i will send to smartcard

byte [] alteredPDF=output.toByteArray();


    ExternalDigest externalDigest = new ExternalDigest() {
        @Override
        public MessageDigest getMessageDigest(String hashAlgorithm) throws GeneralSecurityException {
            return DigestAlgorithms.getMessageDigest(hashAlgorithm, "BC");
        }
    };
    PdfSignatureAppearance sapFinal = null;
    try {
        ByteArrayOutputStream outputFinal = new ByteArrayOutputStream();
        pdfReader = new PdfReader(new ByteArrayInputStream(alteredPDF));
        pdfStamper = PdfStamper.createSignature(pdfReader, outputFinal, '\0');
        sapFinal = pdfStamper.getSignatureAppearance();
        sapFinal.setVisibleSignature("sig");
        sapFinal.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
        sapFinal.setCertificate(cert);
        sapFinal.setSignDate(cal);

        PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
        dic.setReason(sap.getReason());
        dic.setLocation(sap.getLocation());
        String certInfo = cert.getSubjectX500Principal().getName();
        dic.setName(certInfo.substring(certInfo.indexOf("CN=") + 3,
                certInfo.indexOf(",OU", certInfo.indexOf("CN=") + 3)));
        dic.setSignatureCreator(sap.getSignatureCreator());
        dic.setContact(sap.getContact());
        dic.setCert(certDecoded);
        dic.setDate(new PdfDate(sap.getSignDate()));
        sapFinal.setCryptoDictionary(dic);

        HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
        exc.put(PdfName.CONTENTS, new Integer(estimatedSize * 2 + 2));
        sapFinal.preClose(exc);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (DocumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }catch(Exception e){
        e.printStackTrace();
    }


    byte[] sh = null;
    byte[] hashVal = null;
    PdfPKCS7 sgn = null;



    try {
        sgn = new PdfPKCS7(null, new Certificate[] { cert }, "SHA256", null, externalDigest, false);

        InputStream data = sapFinal.getRangeStream();
        hashVal = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
        sh = sgn.getAuthenticatedAttributeBytes(hashVal, cal, null, null, CryptoStandard.CMS);
        sh = MessageDigest.getInstance("SHA256", "BC").digest(sh);

    } catch (IOException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchProviderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (GeneralSecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

And finally having the generated sig

        sgn.setExternalDigest(sig, null, "RSA");
        byte[] encodedSign = null;

        try {
            System.out.println(Arrays.toString(Hex.decodeHex(hash.toCharArray())));
            encodedSign = sgn.getEncodedPKCS7(Hex.decodeHex(hash.toCharArray()), cal, null, null, null,
                    CryptoStandard.CMS);
        } catch (DecoderException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        try {
            MakeSignature.signDeferred(pdfReader, "sig", output,
                    new MyExternalSignatureContainer(encodedSign));
        } catch (DocumentException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (GeneralSecurityException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        System.out.println("called sign pdf");

        try {
            FileOutputStream outputStream = new FileOutputStream("d:\\debug.pdf");
            output.writeTo(outputStream);
            output.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

Can anyone please point me to what i am doing wrong?

1
How do those pieces of code interact? In particular, which PdfStamper outputs serve as inputs to which PdfReaders? The flow is not clear.mkl
First of all thank you for your input. There are two pdfStampers . The first serves to create the empty signature and afterwards i create a new one based on the new pdf which contains the empty signature. The first reader takes as argument the bytes of the original pdf and the second one the bytes of the "alteredPDF".Rui Caridade

1 Answers

1
votes

Finally managed to solve my issue. Storing an empty signature into the PDF and recreating the outputstream was being the culprit. Managed to use the same outputstream from beginning to end and it worked. This link - https://github.com/sueastside/BEIDSign/blob/master/beidsign-service/src/main/java/be/redtree/beid/services/SignatureServiceImpl.java -surely helped me. Thank you mkl for your time.