You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@pdfbox.apache.org by Paresh Chouhan <pa...@gmail.com> on 2017/05/24 10:03:09 UTC

PDF Signing, generated PDF Document certification is invalid, using HSM

I have a service which signs the data and provides me with the signed hash,
it correctly generates PKCS#7 DigestInfo as stated here
https://tools.ietf.org/html/rfc2315#section-9.4

find the code at the end of this email,
the problem is the generated PDF is shown as invalid

public class DetachedPkcs7 implements SignatureInterface {
    public static void main(String[] args) {
        Security.addProvider(new
org.bouncycastle.jce.provider.BouncyCastleProvider());
        try {
            //load pdf document
            PDDocument document = PDDocument.load(new File("test.pdf"));
            int accessPermissions = getMDPPermission(document);
            if (accessPermissions == 1)
            {
                throw new IllegalStateException("No changes to the
document are permitted due to DocMDP transform parameters
dictionary");
            }
            //prepare signature
            PDSignature signature = new PDSignature();
            signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
            signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
            signature.setName("Ankit Agarwal");
            signature.setLocation("Bhopal, IN");
            signature.setReason("Testing");
            // TODO extract the above details from the signing
certificate? Reason as a parameter?

            // the signing date, needed for valid signature
            signature.setSignDate(Calendar.getInstance());

//            // Optional: certify
            if (accessPermissions == 0)
            {
                setMDPPermission(document, signature, 3);
            }

            FileOutputStream fos = new FileOutputStream(new
File("signed_file.pdf"));

            DetachedPkcs7 detachedPkcs7 = new DetachedPkcs7();
            //populate signature options for visible signature. if any.
            SignatureOptions signatureOptions = null;
            document.addSignature(signature);
            ExternalSigningSupport externalSigning =
document.saveIncrementalForExternalSigning(fos);
            InputStream dataToSign = externalSigning.getContent();
            byte[] cmsSignature = detachedPkcs7.sign(dataToSign);
            externalSigning.setSignature(cmsSignature);
        }
        catch(FileNotFoundException fex) {
            fex.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class CMSTypedDataInputStream implements CMSTypedData {
        InputStream in;

        public CMSTypedDataInputStream(InputStream is) {
            in = is;
        }

        @Override
        public ASN1ObjectIdentifier getContentType() {
            return PKCSObjectIdentifiers.data;
        }

        @Override
        public Object getContent() {
            return in;
        }

        @Override
        public void write(OutputStream out) throws IOException,
                CMSException {
            byte[] buffer = new byte[8 * 1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
        }
    }

    static class CMSProcessableInputStream implements CMSProcessable,
CMSTypedData {
        private InputStream input;
        private boolean used = false;
        private final ASN1ObjectIdentifier contentType;

        public CMSProcessableInputStream(
                InputStream input)
        {
            this(new
ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), input);
        }

        public CMSProcessableInputStream(ASN1ObjectIdentifier
contentType, InputStream input) {
            this.input = input;
            this.contentType = contentType;
        }

        public InputStream getInputStream()
        {
//            checkSingleUsage();

            return input;
        }

        public void write(OutputStream zOut)
                throws IOException, CMSException
        {
//            checkSingleUsage();

            Streams.pipeAll(input, zOut);
            input.close();
        }

        public Object getContent()
        {
            return getInputStream();
        }

//        private synchronized void checkSingleUsage()
//        {
//            if (used)
//            {
//                throw new
IllegalStateException("CMSProcessableInputStream can only be used
once");
//            }
//
//            used = true;
//        }

        @Override
        public ASN1ObjectIdentifier getContentType() {
            return contentType;
        }
    }

    public byte[] sign(InputStream content) throws IOException {
        try {
            //prepare message digest
            MessageDigest mdOriginal = MessageDigest.getInstance("SHA-256");
            byte[] dataToDigest = IOUtils.toByteArray(content);
            byte[] digestOriginal = mdOriginal.digest(dataToDigest);
            System.out.println("SHA256Original : " +
Hex.encodeHexString(digestOriginal));
            //the certificate of the signer.
            String certPem = "-----BEGIN CERTIFICATE-----\n" +
                    "USER CERT HERE, THIS IS ALSO TAKEN FROM USB TOKEN
(HSM)\n" +
                    "-----END CERTIFICATE-----";
            ByteArrayInputStream inStream = new
ByteArrayInputStream(certPem.getBytes());

            BufferedInputStream bis = new BufferedInputStream(inStream);
            System.out.println(bis.available());
            CertificateFactory cf = null;

            cf = CertificateFactory.getInstance("X.509");
            List<Certificate> certList = new ArrayList<Certificate>();
            //generate certificate from input stream
            Certificate certificate = cf.generateCertificate(bis);

            certList.add(certificate);

            Store certs = new JcaCertStore(certList);
            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

            Scanner s = new Scanner(System.in);

           //wait for the user to enter base64 encoded signed value.
            final String signedHash = s.nextLine();
            System.out.println("Signing. . . ");
            s.close();
            ContentSigner nonSigner = new ContentSigner() {

                @Override
                public byte[] getSignature() {
                    return Base64.decodeBase64(signedHash);
                }

                @Override
                public OutputStream getOutputStream() {
                    return new ByteArrayOutputStream();
                }

                @Override
                public AlgorithmIdentifier getAlgorithmIdentifier() {
                    return new
DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
                }
            };
            org.bouncycastle.asn1.x509.Certificate cert =
org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
            JcaSignerInfoGeneratorBuilder sigb = new
JcaSignerInfoGeneratorBuilder(new
JcaDigestCalculatorProviderBuilder().build());
            sigb.setDirectSignature(true);
            gen.addCertificates(certs);
            gen.addSignerInfoGenerator(sigb.build(nonSigner, new
X509CertificateHolder(cert)));

            CMSTypedDataInputStream msg = new
CMSTypedDataInputStream(new ByteArrayInputStream(dataToDigest)); //
this is never used.
            CMSSignedData signedData = gen.generate(msg, false);
            byte[] pkcs7 = signedData.getEncoded();

            //this is the signature.
            content.close();
            return pkcs7;
        } catch (CertificateException e) {
            content.close();
            e.printStackTrace();
        } catch (CMSException e) {
            content.close();
            e.printStackTrace();
        } catch (OperatorCreationException e) {
            content.close();
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            content.close();
            e.printStackTrace();
        }
        content.close();
        return null;
    }

    static public int getMDPPermission(PDDocument doc)
    {
        COSBase base =
doc.getDocumentCatalog().getCOSObject().getDictionaryObject(COSName.PERMS);
        if (base instanceof COSDictionary)
        {
            COSDictionary permsDict = (COSDictionary) base;
            base = permsDict.getDictionaryObject(COSName.DOCMDP);
            if (base instanceof COSDictionary)
            {
                COSDictionary signatureDict = (COSDictionary) base;
                base = signatureDict.getDictionaryObject("Reference");
                if (base instanceof COSArray)
                {
                    COSArray refArray = (COSArray) base;
                    for (int i = 0; i < refArray.size(); ++i)
                    {
                        base = refArray.getObject(i);
                        if (base instanceof COSDictionary)
                        {
                            COSDictionary sigRefDict = (COSDictionary) base;
                            if
(COSName.DOCMDP.equals(sigRefDict.getDictionaryObject("TransformMethod")))
                            {
                                base =
sigRefDict.getDictionaryObject("TransformParams");
                                if (base instanceof COSDictionary)
                                {
                                    COSDictionary transformDict =
(COSDictionary) base;
                                    int accessPermissions =
transformDict.getInt(COSName.P, 2);
                                    if (accessPermissions < 1 ||
accessPermissions > 3)
                                    {
                                        accessPermissions = 2;
                                    }
                                    return accessPermissions;
                                }
                            }
                        }
                    }
                }
            }
        }
        return 0;
    }

    static public void setMDPPermission(PDDocument doc, PDSignature
signature, int accessPermissions)
    {
        COSDictionary sigDict = signature.getCOSObject();

        // DocMDP specific stuff
        COSDictionary transformParameters = new COSDictionary();
        transformParameters.setItem(COSName.TYPE,
COSName.getPDFName("TransformParams"));
        transformParameters.setInt(COSName.P, accessPermissions);
        transformParameters.setName(COSName.V, "1.2");
        transformParameters.setNeedToBeUpdated(true);

        COSDictionary referenceDict = new COSDictionary();
        referenceDict.setItem(COSName.TYPE, COSName.getPDFName("SigRef"));
        referenceDict.setItem("TransformMethod", COSName.getPDFName("DocMDP"));
        referenceDict.setItem("DigestMethod", COSName.getPDFName("SHA1"));
        referenceDict.setItem("TransformParams", transformParameters);
        referenceDict.setNeedToBeUpdated(true);

        COSArray referenceArray = new COSArray();
        referenceArray.add(referenceDict);
        sigDict.setItem("Reference", referenceArray);
        referenceArray.setNeedToBeUpdated(true);

        // Catalog
        COSDictionary catalogDict = doc.getDocumentCatalog().getCOSObject();
        COSDictionary permsDict = new COSDictionary();
        catalogDict.setItem(COSName.PERMS, permsDict);
        permsDict.setItem(COSName.DOCMDP, signature);
        catalogDict.setNeedToBeUpdated(true);
        permsDict.setNeedToBeUpdated(true);
    }

}

-- 
Regards
Paresh Chouhan
https://github.com/pareshchouhan

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Paresh Chouhan <pa...@gmail.com>.
sorry for double post, indentation wasn't preserved so here's a pastebin :
https://pastebin.com/b3qZH6xW

On Wed, May 24, 2017 at 3:42 PM Paresh Chouhan <pa...@gmail.com>
wrote:

> I have a service which signs the data and provides me with the signed
> hash, it correctly generates PKCS#7 DigestInfo as stated here
> https://tools.ietf.org/html/rfc2315#section-9.4
>
> find the code at the end of this email,
> the problem is the generated PDF is shown as invalid
>
> public class DetachedPkcs7 implements SignatureInterface {
>     public static void main(String[] args) {
>         Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
>         try {
>             //load pdf document
>             PDDocument document = PDDocument.load(new File("test.pdf"));
>             int accessPermissions = getMDPPermission(document);
>             if (accessPermissions == 1)
>             {
>                 throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
>             }
>             //prepare signature
>             PDSignature signature = new PDSignature();
>             signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
>             signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
>             signature.setName("Ankit Agarwal");
>             signature.setLocation("Bhopal, IN");
>             signature.setReason("Testing");
>             // TODO extract the above details from the signing certificate? Reason as a parameter?
>
>             // the signing date, needed for valid signature
>             signature.setSignDate(Calendar.getInstance());
>
> //            // Optional: certify
>             if (accessPermissions == 0)
>             {
>                 setMDPPermission(document, signature, 3);
>             }
>
>             FileOutputStream fos = new FileOutputStream(new File("signed_file.pdf"));
>
>             DetachedPkcs7 detachedPkcs7 = new DetachedPkcs7();
>             //populate signature options for visible signature. if any.
>             SignatureOptions signatureOptions = null;
>             document.addSignature(signature);
>             ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(fos);
>             InputStream dataToSign = externalSigning.getContent();
>             byte[] cmsSignature = detachedPkcs7.sign(dataToSign);
>             externalSigning.setSignature(cmsSignature);
>         }
>         catch(FileNotFoundException fex) {
>             fex.printStackTrace();
>         } catch (IOException e) {
>             e.printStackTrace();
>         }
>     }
>
>     class CMSTypedDataInputStream implements CMSTypedData {
>         InputStream in;
>
>         public CMSTypedDataInputStream(InputStream is) {
>             in = is;
>         }
>
>         @Override
>         public ASN1ObjectIdentifier getContentType() {
>             return PKCSObjectIdentifiers.data;
>         }
>
>         @Override
>         public Object getContent() {
>             return in;
>         }
>
>         @Override
>         public void write(OutputStream out) throws IOException,
>                 CMSException {
>             byte[] buffer = new byte[8 * 1024];
>             int read;
>             while ((read = in.read(buffer)) != -1) {
>                 out.write(buffer, 0, read);
>             }
>             in.close();
>         }
>     }
>
>     static class CMSProcessableInputStream implements CMSProcessable, CMSTypedData {
>         private InputStream input;
>         private boolean used = false;
>         private final ASN1ObjectIdentifier contentType;
>
>         public CMSProcessableInputStream(
>                 InputStream input)
>         {
>             this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), input);
>         }
>
>         public CMSProcessableInputStream(ASN1ObjectIdentifier contentType, InputStream input) {
>             this.input = input;
>             this.contentType = contentType;
>         }
>
>         public InputStream getInputStream()
>         {
> //            checkSingleUsage();
>
>             return input;
>         }
>
>         public void write(OutputStream zOut)
>                 throws IOException, CMSException
>         {
> //            checkSingleUsage();
>
>             Streams.pipeAll(input, zOut);
>             input.close();
>         }
>
>         public Object getContent()
>         {
>             return getInputStream();
>         }
>
> //        private synchronized void checkSingleUsage()
> //        {
> //            if (used)
> //            {
> //                throw new IllegalStateException("CMSProcessableInputStream can only be used once");
> //            }
> //
> //            used = true;
> //        }
>
>         @Override
>         public ASN1ObjectIdentifier getContentType() {
>             return contentType;
>         }
>     }
>
>     public byte[] sign(InputStream content) throws IOException {
>         try {
>             //prepare message digest
>             MessageDigest mdOriginal = MessageDigest.getInstance("SHA-256");
>             byte[] dataToDigest = IOUtils.toByteArray(content);
>             byte[] digestOriginal = mdOriginal.digest(dataToDigest);
>             System.out.println("SHA256Original : " + Hex.encodeHexString(digestOriginal));
>             //the certificate of the signer.
>             String certPem = "-----BEGIN CERTIFICATE-----\n" +
>                     "USER CERT HERE, THIS IS ALSO TAKEN FROM USB TOKEN (HSM)\n" +
>                     "-----END CERTIFICATE-----";
>             ByteArrayInputStream inStream = new ByteArrayInputStream(certPem.getBytes());
>
>             BufferedInputStream bis = new BufferedInputStream(inStream);
>             System.out.println(bis.available());
>             CertificateFactory cf = null;
>
>             cf = CertificateFactory.getInstance("X.509");
>             List<Certificate> certList = new ArrayList<Certificate>();
>             //generate certificate from input stream
>             Certificate certificate = cf.generateCertificate(bis);
>
>             certList.add(certificate);
>
>             Store certs = new JcaCertStore(certList);
>             CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
>
>             Scanner s = new Scanner(System.in);
>
>            //wait for the user to enter base64 encoded signed value.
>             final String signedHash = s.nextLine();
>             System.out.println("Signing. . . ");
>             s.close();
>             ContentSigner nonSigner = new ContentSigner() {
>
>                 @Override
>                 public byte[] getSignature() {
>                     return Base64.decodeBase64(signedHash);
>                 }
>
>                 @Override
>                 public OutputStream getOutputStream() {
>                     return new ByteArrayOutputStream();
>                 }
>
>                 @Override
>                 public AlgorithmIdentifier getAlgorithmIdentifier() {
>                     return new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
>                 }
>             };
>             org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
>             JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build());
>             sigb.setDirectSignature(true);
>             gen.addCertificates(certs);
>             gen.addSignerInfoGenerator(sigb.build(nonSigner, new X509CertificateHolder(cert)));
>
>             CMSTypedDataInputStream msg = new CMSTypedDataInputStream(new ByteArrayInputStream(dataToDigest)); // this is never used.
>             CMSSignedData signedData = gen.generate(msg, false);
>             byte[] pkcs7 = signedData.getEncoded();
>
>             //this is the signature.
>             content.close();
>             return pkcs7;
>         } catch (CertificateException e) {
>             content.close();
>             e.printStackTrace();
>         } catch (CMSException e) {
>             content.close();
>             e.printStackTrace();
>         } catch (OperatorCreationException e) {
>             content.close();
>             e.printStackTrace();
>         } catch (NoSuchAlgorithmException e) {
>             content.close();
>             e.printStackTrace();
>         }
>         content.close();
>         return null;
>     }
>
>     static public int getMDPPermission(PDDocument doc)
>     {
>         COSBase base = doc.getDocumentCatalog().getCOSObject().getDictionaryObject(COSName.PERMS);
>         if (base instanceof COSDictionary)
>         {
>             COSDictionary permsDict = (COSDictionary) base;
>             base = permsDict.getDictionaryObject(COSName.DOCMDP);
>             if (base instanceof COSDictionary)
>             {
>                 COSDictionary signatureDict = (COSDictionary) base;
>                 base = signatureDict.getDictionaryObject("Reference");
>                 if (base instanceof COSArray)
>                 {
>                     COSArray refArray = (COSArray) base;
>                     for (int i = 0; i < refArray.size(); ++i)
>                     {
>                         base = refArray.getObject(i);
>                         if (base instanceof COSDictionary)
>                         {
>                             COSDictionary sigRefDict = (COSDictionary) base;
>                             if (COSName.DOCMDP.equals(sigRefDict.getDictionaryObject("TransformMethod")))
>                             {
>                                 base = sigRefDict.getDictionaryObject("TransformParams");
>                                 if (base instanceof COSDictionary)
>                                 {
>                                     COSDictionary transformDict = (COSDictionary) base;
>                                     int accessPermissions = transformDict.getInt(COSName.P, 2);
>                                     if (accessPermissions < 1 || accessPermissions > 3)
>                                     {
>                                         accessPermissions = 2;
>                                     }
>                                     return accessPermissions;
>                                 }
>                             }
>                         }
>                     }
>                 }
>             }
>         }
>         return 0;
>     }
>
>     static public void setMDPPermission(PDDocument doc, PDSignature signature, int accessPermissions)
>     {
>         COSDictionary sigDict = signature.getCOSObject();
>
>         // DocMDP specific stuff
>         COSDictionary transformParameters = new COSDictionary();
>         transformParameters.setItem(COSName.TYPE, COSName.getPDFName("TransformParams"));
>         transformParameters.setInt(COSName.P, accessPermissions);
>         transformParameters.setName(COSName.V, "1.2");
>         transformParameters.setNeedToBeUpdated(true);
>
>         COSDictionary referenceDict = new COSDictionary();
>         referenceDict.setItem(COSName.TYPE, COSName.getPDFName("SigRef"));
>         referenceDict.setItem("TransformMethod", COSName.getPDFName("DocMDP"));
>         referenceDict.setItem("DigestMethod", COSName.getPDFName("SHA1"));
>         referenceDict.setItem("TransformParams", transformParameters);
>         referenceDict.setNeedToBeUpdated(true);
>
>         COSArray referenceArray = new COSArray();
>         referenceArray.add(referenceDict);
>         sigDict.setItem("Reference", referenceArray);
>         referenceArray.setNeedToBeUpdated(true);
>
>         // Catalog
>         COSDictionary catalogDict = doc.getDocumentCatalog().getCOSObject();
>         COSDictionary permsDict = new COSDictionary();
>         catalogDict.setItem(COSName.PERMS, permsDict);
>         permsDict.setItem(COSName.DOCMDP, signature);
>         catalogDict.setNeedToBeUpdated(true);
>         permsDict.setNeedToBeUpdated(true);
>     }
>
> }
>
> --
> Regards
> Paresh Chouhan
> https://github.com/pareshchouhan
>
-- 
Regards
Paresh Chouhan
https://github.com/pareshchouhan

PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Paresh Chouhan <pa...@gmail.com>.
I have a service which signs the data and provides me with the signed hash,
it correctly generates PKCS#7 DigestInfo as stated here
https://tools.ietf.org/html/rfc2315#section-9.4

find the code at the end of this email,
the problem is the generated PDF is shown as invalid

public class DetachedPkcs7 implements SignatureInterface {
    public static void main(String[] args) {
        Security.addProvider(new
org.bouncycastle.jce.provider.BouncyCastleProvider());
        try {
            //load pdf document
            PDDocument document = PDDocument.load(new File("test.pdf"));
            int accessPermissions = getMDPPermission(document);
            if (accessPermissions == 1)
            {
                throw new IllegalStateException("No changes to the
document are permitted due to DocMDP transform parameters
dictionary");
            }
            //prepare signature
            PDSignature signature = new PDSignature();
            signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
            signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
            signature.setName("Ankit Agarwal");
            signature.setLocation("Bhopal, IN");
            signature.setReason("Testing");
            // TODO extract the above details from the signing
certificate? Reason as a parameter?

            // the signing date, needed for valid signature
            signature.setSignDate(Calendar.getInstance());

//            // Optional: certify
            if (accessPermissions == 0)
            {
                setMDPPermission(document, signature, 3);
            }

            FileOutputStream fos = new FileOutputStream(new
File("signed_file.pdf"));

            DetachedPkcs7 detachedPkcs7 = new DetachedPkcs7();
            //populate signature options for visible signature. if any.
            SignatureOptions signatureOptions = null;
            document.addSignature(signature);
            ExternalSigningSupport externalSigning =
document.saveIncrementalForExternalSigning(fos);
            InputStream dataToSign = externalSigning.getContent();
            byte[] cmsSignature = detachedPkcs7.sign(dataToSign);
            externalSigning.setSignature(cmsSignature);
        }
        catch(FileNotFoundException fex) {
            fex.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class CMSTypedDataInputStream implements CMSTypedData {
        InputStream in;

        public CMSTypedDataInputStream(InputStream is) {
            in = is;
        }

        @Override
        public ASN1ObjectIdentifier getContentType() {
            return PKCSObjectIdentifiers.data;
        }

        @Override
        public Object getContent() {
            return in;
        }

        @Override
        public void write(OutputStream out) throws IOException,
                CMSException {
            byte[] buffer = new byte[8 * 1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
        }
    }

    static class CMSProcessableInputStream implements CMSProcessable,
CMSTypedData {
        private InputStream input;
        private boolean used = false;
        private final ASN1ObjectIdentifier contentType;

        public CMSProcessableInputStream(
                InputStream input)
        {
            this(new
ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), input);
        }

        public CMSProcessableInputStream(ASN1ObjectIdentifier
contentType, InputStream input) {
            this.input = input;
            this.contentType = contentType;
        }

        public InputStream getInputStream()
        {
//            checkSingleUsage();

            return input;
        }

        public void write(OutputStream zOut)
                throws IOException, CMSException
        {
//            checkSingleUsage();

            Streams.pipeAll(input, zOut);
            input.close();
        }

        public Object getContent()
        {
            return getInputStream();
        }

//        private synchronized void checkSingleUsage()
//        {
//            if (used)
//            {
//                throw new
IllegalStateException("CMSProcessableInputStream can only be used
once");
//            }
//
//            used = true;
//        }

        @Override
        public ASN1ObjectIdentifier getContentType() {
            return contentType;
        }
    }

    public byte[] sign(InputStream content) throws IOException {
        try {
            //prepare message digest
            MessageDigest mdOriginal = MessageDigest.getInstance("SHA-256");
            byte[] dataToDigest = IOUtils.toByteArray(content);
            byte[] digestOriginal = mdOriginal.digest(dataToDigest);
            System.out.println("SHA256Original : " +
Hex.encodeHexString(digestOriginal));
            //the certificate of the signer.
            String certPem = "-----BEGIN CERTIFICATE-----\n" +
                    "USER CERT HERE, THIS IS ALSO TAKEN FROM USB TOKEN
(HSM)\n" +
                    "-----END CERTIFICATE-----";
            ByteArrayInputStream inStream = new
ByteArrayInputStream(certPem.getBytes());

            BufferedInputStream bis = new BufferedInputStream(inStream);
            System.out.println(bis.available());
            CertificateFactory cf = null;

            cf = CertificateFactory.getInstance("X.509");
            List<Certificate> certList = new ArrayList<Certificate>();
            //generate certificate from input stream
            Certificate certificate = cf.generateCertificate(bis);

            certList.add(certificate);

            Store certs = new JcaCertStore(certList);
            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

            Scanner s = new Scanner(System.in);

           //wait for the user to enter base64 encoded signed value.
            final String signedHash = s.nextLine();
            System.out.println("Signing. . . ");
            s.close();
            ContentSigner nonSigner = new ContentSigner() {

                @Override
                public byte[] getSignature() {
                    return Base64.decodeBase64(signedHash);
                }

                @Override
                public OutputStream getOutputStream() {
                    return new ByteArrayOutputStream();
                }

                @Override
                public AlgorithmIdentifier getAlgorithmIdentifier() {
                    return new
DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
                }
            };
            org.bouncycastle.asn1.x509.Certificate cert =
org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
            JcaSignerInfoGeneratorBuilder sigb = new
JcaSignerInfoGeneratorBuilder(new
JcaDigestCalculatorProviderBuilder().build());
            sigb.setDirectSignature(true);
            gen.addCertificates(certs);
            gen.addSignerInfoGenerator(sigb.build(nonSigner, new
X509CertificateHolder(cert)));

            CMSTypedDataInputStream msg = new
CMSTypedDataInputStream(new ByteArrayInputStream(dataToDigest)); //
this is never used.
            CMSSignedData signedData = gen.generate(msg, false);
            byte[] pkcs7 = signedData.getEncoded();

            //this is the signature.
            content.close();
            return pkcs7;
        } catch (CertificateException e) {
            content.close();
            e.printStackTrace();
        } catch (CMSException e) {
            content.close();
            e.printStackTrace();
        } catch (OperatorCreationException e) {
            content.close();
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            content.close();
            e.printStackTrace();
        }
        content.close();
        return null;
    }

    static public int getMDPPermission(PDDocument doc)
    {
        COSBase base =
doc.getDocumentCatalog().getCOSObject().getDictionaryObject(COSName.PERMS);
        if (base instanceof COSDictionary)
        {
            COSDictionary permsDict = (COSDictionary) base;
            base = permsDict.getDictionaryObject(COSName.DOCMDP);
            if (base instanceof COSDictionary)
            {
                COSDictionary signatureDict = (COSDictionary) base;
                base = signatureDict.getDictionaryObject("Reference");
                if (base instanceof COSArray)
                {
                    COSArray refArray = (COSArray) base;
                    for (int i = 0; i < refArray.size(); ++i)
                    {
                        base = refArray.getObject(i);
                        if (base instanceof COSDictionary)
                        {
                            COSDictionary sigRefDict = (COSDictionary) base;
                            if
(COSName.DOCMDP.equals(sigRefDict.getDictionaryObject("TransformMethod")))
                            {
                                base =
sigRefDict.getDictionaryObject("TransformParams");
                                if (base instanceof COSDictionary)
                                {
                                    COSDictionary transformDict =
(COSDictionary) base;
                                    int accessPermissions =
transformDict.getInt(COSName.P, 2);
                                    if (accessPermissions < 1 ||
accessPermissions > 3)
                                    {
                                        accessPermissions = 2;
                                    }
                                    return accessPermissions;
                                }
                            }
                        }
                    }
                }
            }
        }
        return 0;
    }

    static public void setMDPPermission(PDDocument doc, PDSignature
signature, int accessPermissions)
    {
        COSDictionary sigDict = signature.getCOSObject();

        // DocMDP specific stuff
        COSDictionary transformParameters = new COSDictionary();
        transformParameters.setItem(COSName.TYPE,
COSName.getPDFName("TransformParams"));
        transformParameters.setInt(COSName.P, accessPermissions);
        transformParameters.setName(COSName.V, "1.2");
        transformParameters.setNeedToBeUpdated(true);

        COSDictionary referenceDict = new COSDictionary();
        referenceDict.setItem(COSName.TYPE, COSName.getPDFName("SigRef"));
        referenceDict.setItem("TransformMethod", COSName.getPDFName("DocMDP"));
        referenceDict.setItem("DigestMethod", COSName.getPDFName("SHA1"));
        referenceDict.setItem("TransformParams", transformParameters);
        referenceDict.setNeedToBeUpdated(true);

        COSArray referenceArray = new COSArray();
        referenceArray.add(referenceDict);
        sigDict.setItem("Reference", referenceArray);
        referenceArray.setNeedToBeUpdated(true);

        // Catalog
        COSDictionary catalogDict = doc.getDocumentCatalog().getCOSObject();
        COSDictionary permsDict = new COSDictionary();
        catalogDict.setItem(COSName.PERMS, permsDict);
        permsDict.setItem(COSName.DOCMDP, signature);
        catalogDict.setNeedToBeUpdated(true);
        permsDict.setNeedToBeUpdated(true);
    }

}

-- 
Regards
Paresh Chouhan
https://github.com/pareshchouhan

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Paresh Chouhan <pa...@gmail.com>.
Thanks Tilman, I have posted the question on Stackoverflow,
for anyone arriving at a dead end hopefully you can find the solution here
:
https://stackoverflow.com/questions/44196316/pdf-signing-generated-pdf-document-certification-is-invalid-using-external-si

On Thu, May 25, 2017 at 9:05 PM Tilman Hausherr <TH...@t-online.de>
wrote:

> ok... sorry I can't help further. Maybe it's best to ask on
> stackoverflow. Use a label for bouncycastle and include all, i.e. code,
> links to PDF files and the image.
>
>
> Tilman
>
>
>
>
>
> Am 25.05.2017 um 12:42 schrieb Paresh Chouhan:
> > oh I cannot attach the image, see my work flow is something like this
> > http://i64.tinypic.com/29v02u.png
> > so I am doing the signing on the client and reattaching the signed
> > hash that I receive from client.
> >
> > On Thu, May 25, 2017 at 4:09 PM Paresh Chouhan
> > <pareshchouhan2013@gmail.com <ma...@gmail.com>>
> wrote:
> >
> >     On Thu, May 25, 2017 at 3:13 PM Tilman Hausherr
> >     <THausherr@t-online.de <ma...@t-online.de>> wrote:
> >
> >         Am 25.05.2017 um 08:22 schrieb Paresh Chouhan:
> >         > Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
> >         > Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh
> >
> >         Thanks... I wanted to see the files first because I'm lazy and
> >         had hoped
> >         it's some obvious problem in the PDF itself, but it isn't. So
> >         I looked
> >         at your code... the signing is quite different than in our
> >         example, why
> >         is this so? The "CreateSignatureBase" class has the code to
> >         produce the
> >         signature.
> >
> >         That you mention a HSM isn't really relevant... At work, I'm
> >         signing
> >         with a PKI card and all I had to change was getting the keystore.
> >
> >         Tilman
> >
> >
>  ---------------------------------------------------------------------
> >         To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
> >         <ma...@pdfbox.apache.org>
> >         For additional commands, e-mail: users-help@pdfbox.apache.org
> >         <ma...@pdfbox.apache.org>
> >
> >         workflow.png
> >
> >     --
> >     Regards
> >     Paresh Chouhan
> >     https://github.com/pareshchouhan
> >
> > --
> > Regards
> > Paresh Chouhan
> > https://github.com/pareshchouhan
>
>
> --
Regards
Paresh Chouhan
https://github.com/pareshchouhan

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Tilman Hausherr <TH...@t-online.de>.
ok... sorry I can't help further. Maybe it's best to ask on 
stackoverflow. Use a label for bouncycastle and include all, i.e. code, 
links to PDF files and the image.


Tilman





Am 25.05.2017 um 12:42 schrieb Paresh Chouhan:
> oh I cannot attach the image, see my work flow is something like this 
> http://i64.tinypic.com/29v02u.png
> so I am doing the signing on the client and reattaching the signed 
> hash that I receive from client.
>
> On Thu, May 25, 2017 at 4:09 PM Paresh Chouhan 
> <pareshchouhan2013@gmail.com <ma...@gmail.com>> wrote:
>
>     On Thu, May 25, 2017 at 3:13 PM Tilman Hausherr
>     <THausherr@t-online.de <ma...@t-online.de>> wrote:
>
>         Am 25.05.2017 um 08:22 schrieb Paresh Chouhan:
>         > Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
>         > Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh
>
>         Thanks... I wanted to see the files first because I'm lazy and
>         had hoped
>         it's some obvious problem in the PDF itself, but it isn't. So
>         I looked
>         at your code... the signing is quite different than in our
>         example, why
>         is this so? The "CreateSignatureBase" class has the code to
>         produce the
>         signature.
>
>         That you mention a HSM isn't really relevant... At work, I'm
>         signing
>         with a PKI card and all I had to change was getting the keystore.
>
>         Tilman
>
>         ---------------------------------------------------------------------
>         To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
>         <ma...@pdfbox.apache.org>
>         For additional commands, e-mail: users-help@pdfbox.apache.org
>         <ma...@pdfbox.apache.org>
>
>         workflow.png
>
>     -- 
>     Regards
>     Paresh Chouhan
>     https://github.com/pareshchouhan
>
> -- 
> Regards
> Paresh Chouhan
> https://github.com/pareshchouhan



Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Paresh Chouhan <pa...@gmail.com>.
Hi  Diego,
Only thing is I am not discarding changes so my steps are more like
   - Grab original PDF
   - add signature dictionary and get the hash
   - send the hash to client
   - Wait for data on Standard Input.
   - Wait for Client to send the signed hash back, This data is then feeded
to the paused program, that is, the data is sent to standard input of the
program
   - add the CMS. :)

On Thu, May 25, 2017 at 7:07 PM Diego Azevedo <da...@esec.com.br> wrote:

> Hey, Paresh
>
> I had the same problem with a similar workflow, and glancing at your code I
> think you did the same as I did before:
>
>
>    - Grab original PDF
>    - add signature dictionary and get the hash
>    - discart changes
>    - send the hash to client
>    - mount CMS package with information returned from client
>    - grab original PDF
>    - add signature dictionary AND the CMS
>
> This won't work. Adding the same dictionary, with the same information, in
> two different moments will create two different PDFs, with different
> hashes.
> The cause is the trailer dictionary. It has an ID entry that will always
> change.
>
> If that's really the cause (I only glanced at your code), you have two
> workarrounds:
>
>    - Change PDFbox to create the same ID in different moments (It uses the
>    document itself and I think it also uses "currentTimeInMilis" somewhere)
>    - save your PDF with a garbage signature and update it latter with the
>    CMS
>
>
>
>
> On Thu, May 25, 2017 at 7:42 AM, Paresh Chouhan <
> pareshchouhan2013@gmail.com
> > wrote:
>
> > oh I cannot attach the image, see my work flow is something like this
> > http://i64.tinypic.com/29v02u.png
> > so I am doing the signing on the client and reattaching the signed hash
> > that I receive from client.
> >
> > On Thu, May 25, 2017 at 4:09 PM Paresh Chouhan <
> > pareshchouhan2013@gmail.com> wrote:
> >
> >> On Thu, May 25, 2017 at 3:13 PM Tilman Hausherr <TH...@t-online.de>
> >> wrote:
> >>
> >>> Am 25.05.2017 um 08:22 schrieb Paresh Chouhan:
> >>> > Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
> >>> > Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh
> >>>
> >>> Thanks... I wanted to see the files first because I'm lazy and had
> hoped
> >>> it's some obvious problem in the PDF itself, but it isn't. So I looked
> >>> at your code... the signing is quite different than in our example, why
> >>> is this so? The "CreateSignatureBase" class has the code to produce the
> >>> signature.
> >>>
> >>> That you mention a HSM isn't really relevant... At work, I'm signing
> >>> with a PKI card and all I had to change was getting the keystore.
> >>>
> >>> Tilman
> >>>
> >>> ---------------------------------------------------------------------
> >>> To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
> >>> For additional commands, e-mail: users-help@pdfbox.apache.org
> >>>
> >> [image: workflow.png]
> >>>
> >> --
> >> Regards
> >> Paresh Chouhan
> >> https://github.com/pareshchouhan
> >>
> > --
> > Regards
> > Paresh Chouhan
> > https://github.com/pareshchouhan
> >
>
>
>
> --
> []'s
>
> Diego Azevedo
>
-- 
Regards
Paresh Chouhan
https://github.com/pareshchouhan

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Diego Azevedo <da...@esec.com.br>.
Hey, Paresh

I had the same problem with a similar workflow, and glancing at your code I
think you did the same as I did before:


   - Grab original PDF
   - add signature dictionary and get the hash
   - discart changes
   - send the hash to client
   - mount CMS package with information returned from client
   - grab original PDF
   - add signature dictionary AND the CMS

This won't work. Adding the same dictionary, with the same information, in
two different moments will create two different PDFs, with different hashes.
The cause is the trailer dictionary. It has an ID entry that will always
change.

If that's really the cause (I only glanced at your code), you have two
workarrounds:

   - Change PDFbox to create the same ID in different moments (It uses the
   document itself and I think it also uses "currentTimeInMilis" somewhere)
   - save your PDF with a garbage signature and update it latter with the
   CMS




On Thu, May 25, 2017 at 7:42 AM, Paresh Chouhan <pareshchouhan2013@gmail.com
> wrote:

> oh I cannot attach the image, see my work flow is something like this
> http://i64.tinypic.com/29v02u.png
> so I am doing the signing on the client and reattaching the signed hash
> that I receive from client.
>
> On Thu, May 25, 2017 at 4:09 PM Paresh Chouhan <
> pareshchouhan2013@gmail.com> wrote:
>
>> On Thu, May 25, 2017 at 3:13 PM Tilman Hausherr <TH...@t-online.de>
>> wrote:
>>
>>> Am 25.05.2017 um 08:22 schrieb Paresh Chouhan:
>>> > Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
>>> > Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh
>>>
>>> Thanks... I wanted to see the files first because I'm lazy and had hoped
>>> it's some obvious problem in the PDF itself, but it isn't. So I looked
>>> at your code... the signing is quite different than in our example, why
>>> is this so? The "CreateSignatureBase" class has the code to produce the
>>> signature.
>>>
>>> That you mention a HSM isn't really relevant... At work, I'm signing
>>> with a PKI card and all I had to change was getting the keystore.
>>>
>>> Tilman
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
>>> For additional commands, e-mail: users-help@pdfbox.apache.org
>>>
>> [image: workflow.png]
>>>
>> --
>> Regards
>> Paresh Chouhan
>> https://github.com/pareshchouhan
>>
> --
> Regards
> Paresh Chouhan
> https://github.com/pareshchouhan
>



-- 
[]'s

Diego Azevedo

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Paresh Chouhan <pa...@gmail.com>.
oh I cannot attach the image, see my work flow is something like this
http://i64.tinypic.com/29v02u.png
so I am doing the signing on the client and reattaching the signed hash
that I receive from client.

On Thu, May 25, 2017 at 4:09 PM Paresh Chouhan <pa...@gmail.com>
wrote:

> On Thu, May 25, 2017 at 3:13 PM Tilman Hausherr <TH...@t-online.de>
> wrote:
>
>> Am 25.05.2017 um 08:22 schrieb Paresh Chouhan:
>> > Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
>> > Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh
>>
>> Thanks... I wanted to see the files first because I'm lazy and had hoped
>> it's some obvious problem in the PDF itself, but it isn't. So I looked
>> at your code... the signing is quite different than in our example, why
>> is this so? The "CreateSignatureBase" class has the code to produce the
>> signature.
>>
>> That you mention a HSM isn't really relevant... At work, I'm signing
>> with a PKI card and all I had to change was getting the keystore.
>>
>> Tilman
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
>> For additional commands, e-mail: users-help@pdfbox.apache.org
>>
> [image: workflow.png]
>>
> --
> Regards
> Paresh Chouhan
> https://github.com/pareshchouhan
>
-- 
Regards
Paresh Chouhan
https://github.com/pareshchouhan

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Paresh Chouhan <pa...@gmail.com>.
On Thu, May 25, 2017 at 3:13 PM Tilman Hausherr <TH...@t-online.de>
wrote:

> Am 25.05.2017 um 08:22 schrieb Paresh Chouhan:
> > Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
> > Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh
>
> Thanks... I wanted to see the files first because I'm lazy and had hoped
> it's some obvious problem in the PDF itself, but it isn't. So I looked
> at your code... the signing is quite different than in our example, why
> is this so? The "CreateSignatureBase" class has the code to produce the
> signature.
>
> That you mention a HSM isn't really relevant... At work, I'm signing
> with a PKI card and all I had to change was getting the keystore.
>
> Tilman
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
> For additional commands, e-mail: users-help@pdfbox.apache.org
> [image: workflow.png]
>
-- 
Regards
Paresh Chouhan
https://github.com/pareshchouhan

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Tilman Hausherr <TH...@t-online.de>.
Am 25.05.2017 um 08:22 schrieb Paresh Chouhan:
> Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
> Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh

Thanks... I wanted to see the files first because I'm lazy and had hoped 
it's some obvious problem in the PDF itself, but it isn't. So I looked 
at your code... the signing is quite different than in our example, why 
is this so? The "CreateSignatureBase" class has the code to produce the 
signature.

That you mention a HSM isn't really relevant... At work, I'm signing 
with a PKI card and all I had to change was getting the keystore.

Tilman

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
For additional commands, e-mail: users-help@pdfbox.apache.org


Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Paresh Chouhan <pa...@gmail.com>.
Original PDF : https://www.mediafire.com/?bg9z4c9450v01io
Signed PDF : https://www.mediafire.com/?fqvnf9mg50pfzjh
^Tilman :)


On Thu, May 25, 2017 at 12:28 AM Tilman Hausherr <TH...@t-online.de>
wrote:

> Hi,
> Please upload your signed PDF file to a public location.
> Tilman
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
> For additional commands, e-mail: users-help@pdfbox.apache.org
>
> --
Regards
Paresh Chouhan
https://github.com/pareshchouhan

Re: PDF Signing, generated PDF Document certification is invalid, using HSM

Posted by Tilman Hausherr <TH...@t-online.de>.
Hi,
Please upload your signed PDF file to a public location.
Tilman


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
For additional commands, e-mail: users-help@pdfbox.apache.org