Hi,

I encountered a PDF signed with an AdES signature that failed signature
validation.
The problem turned out to be a failure to parse the signature certificates.

Examining PdfPKCS7, this appears to be a known problem.

In the code, where the problem occurred, I found:

            // the certificates

/*

    This should work, but that's not always the case because of a bug in
BouncyCastle:

*/ 

            X509CertParser cr = new X509CertParser();

            cr.engineInit(new ByteArrayInputStream(contentsKey));

            certs = cr.engineReadAll();

/*    

            The following workaround was provided by Alfonso Massa, but it
doesn't always work either.



            ASN1Set certSet = null;

            ASN1Set crlSet = null;

            while (content.getObjectAt(next) instanceof ASN1TaggedObject) {

                ASN1TaggedObject tagged =
(ASN1TaggedObject)content.getObjectAt(next);



                switch (tagged.getTagNo()) {

                case 0:

                    certSet = ASN1Set.getInstance(tagged, false);

                    break;

                case 1:

                    crlSet = ASN1Set.getInstance(tagged, false);

                    break;

                default:

                    throw new IllegalArgumentException("unknown tag value "
+ tagged.getTagNo());

                }

                ++next;

            }

            certs = new ArrayList<Certificate>(certSet.size());



            CertificateFactory certFact =
CertificateFactory.getInstance("X.509", new BouncyCastleProvider());

            for (Enumeration en = certSet.getObjects();
en.hasMoreElements();) {

                ASN1Primitive obj =
((ASN1Encodable)en.nextElement()).toASN1Primitive();

                if (obj instanceof ASN1Sequence) {

                ByteArrayInputStream stream = new
ByteArrayInputStream(obj.getEncoded());

                X509Certificate x509Certificate =
(X509Certificate)certFact.generateCertificate(stream);

                stream.close();

    certs.add(x509Certificate);

                }

            }

*/




And sure enough, the BouncyCastle X509CertParser function engineReadAll();
fails when initated with the full cms object.

I then tried to invoke the workaround provided by Alfonso Massa (commenting
away the 3 lines that should work).
And that failed too.

So I started digging deeper, and could not understand why the workaround
failed. Because it looked all right.

Then I spotted the preceding lines of code:

            int next = 3;

            while (content.getObjectAt(next) instanceof ASN1TaggedObject)

                ++next;


And of course! 
These lines of codes steps the "next" counter passed the certificates.
Prohibiting the fix from Massa from catching the certs.
Once I removed the while statement here, the fix from Massa worked
perfectly.


I think this is easily missed. IMO the code should at least look like this:


            int next = 3;



            // the certificates

/*

    This should work, but that's not always the case because of a bug in
BouncyCastle:

*/ 

            X509CertParser cr = new X509CertParser();

            cr.engineInit(new ByteArrayInputStream(contentsKey));

            certs = cr.engineReadAll();



            while (content.getObjectAt(next) instanceof ASN1TaggedObject)

                ++next;



/*    

            The following workaround was provided by Alfonso Massa, but it
doesn't always work either.



            ASN1Set certSet = null;

            ASN1Set crlSet = null;

            while (content.getObjectAt(next) instanceof ASN1TaggedObject) {

                ASN1TaggedObject tagged =
(ASN1TaggedObject)content.getObjectAt(next);



                switch (tagged.getTagNo()) {

                case 0:

                    certSet = ASN1Set.getInstance(tagged, false);

                    break;

                case 1:

                    crlSet = ASN1Set.getInstance(tagged, false);

                    break;

                default:

                    throw new IllegalArgumentException("unknown tag value "
+ tagged.getTagNo());

                }

                ++next;

            }

            certs = new ArrayList<Certificate>(certSet.size());



            CertificateFactory certFact =
CertificateFactory.getInstance("X.509", new BouncyCastleProvider());

            for (Enumeration en = certSet.getObjects();
en.hasMoreElements();) {

                ASN1Primitive obj =
((ASN1Encodable)en.nextElement()).toASN1Primitive();

                if (obj instanceof ASN1Sequence) {

                ByteArrayInputStream stream = new
ByteArrayInputStream(obj.getEncoded());

                X509Certificate x509Certificate =
(X509Certificate)certFact.generateCertificate(stream);

                stream.close();

    certs.add(x509Certificate);

                }

            }

*/



This would make it a lot clearer that you need to remove the while loop
updating the counter next if you invoke the fix from Massa, as that counter
increment i duplicated in Massa's code.
I placed the while loop that increments the counter passed all tagged object
after the certificate parsing code, as that to me is the logical order.
First I catch the certs, then I step the counter passed the certs (and other
tagged objects).

I ran Massa's fix on all test signed PDFs I have, and I could not find a
single one where Massa's fix failed to retrieve the certs. Is perhaps the
reason why it is said to "doesn't always work either" because of the same
problem I had?
If so, then I would suggest including Massa's fix by default instead, as it
at least in my tests, is far more likely to succeed, than the
X509CertParser.


Finally, a small nit.

What confused me a bit in the debugging is a confusing variable naming in
this part of PdfPKCS7

The variable "signedData" is actually the CMS/pkcs7 object, and the variable
"content" is actually the SignedData object.
To make it easier to review the code, I renamed "signedData" to "cms", and
"content" to "signedData".


Stefan Santesson

3xA Security AB
Scheelevägen 17, 223 70, Lund
http://AAA-sec.com
ste...@aaa-sec.com
+46-767 861337


















------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
iText-questions mailing list
iText-questions@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/itext-questions

iText(R) is a registered trademark of 1T3XT BVBA.
Many questions posted to this list can (and will) be answered with a reference 
to the iText book: http://www.itextpdf.com/book/
Please check the keywords list before you ask for examples: 
http://itextpdf.com/themes/keywords.php

Reply via email to