1

I sign a pdf using a certificate. In java I process the pdf and extract the certificate details. I compare the output against the certificate details shown in Adobe for that document. For SerialNumber I was able to make them look the same, but not for public key. Any help appreciated!

I debugged the code, tried to convert using Hex.toHexString, googled in stackoverflow. But no luck

System.out.println("signed? " + pdAcroForm.isSignaturesExist());
if (pdAcroForm.isSignaturesExist()) {
    PDSignatureField signatureField = (PDSignatureField) pdAcroForm.getField("signatureField");
    System.out.println("Name: " + signatureField.getSignature().getName());
    System.out.println("Name: " + signatureField.getSignature().getContactInfo());

    Security.addProvider(new BouncyCastleProvider());
    List<PDSignature> signatureDictionaries = document.getSignatureDictionaries();
    X509Certificate cert;
    Collection<X509Certificate> result = new HashSet<X509Certificate>();
    // Then we validate signatures one at the time.
    for (PDSignature signatureDictionary : signatureDictionaries) {
        // NOTE that this code currently supports only "adbe.pkcs7.detached", the most common signature /SubFilter anyway.
        byte[] signatureContent = signatureDictionary.getContents(new FileInputStream(signedFile));
        byte[] signedContent = signatureDictionary.getSignedContent(new FileInputStream(signedFile));
        // Now we construct a PKCS #7 or CMS.
        CMSProcessable cmsProcessableInputStream = new CMSProcessableByteArray(signedContent);
        try {
            CMSSignedData cmsSignedData = new CMSSignedData(cmsProcessableInputStream, signatureContent);
            Store<?> certStore = cmsSignedData.getCertificates();
            SignerInformationStore signers = cmsSignedData.getSignerInfos();
            Iterator<?> it = signers.getSigners().iterator();
            while (it.hasNext()) {
                SignerInformation signer = (SignerInformation) it.next();
                Collection<?> certCollection = certStore.getMatches(signer.getSID());
                Iterator<?> certIt = certCollection.iterator();
                while (certIt.hasNext()) {
                    X509CertificateHolder certificateHolder = (X509CertificateHolder) certIt.next();
                    System.out.println(certificateHolder.getSubjectPublicKeyInfo());
                    System.out.println(certificateHolder.getSubject());
                    System.out.println(certificateHolder.getIssuer());
                    System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));
                    // SerialNumber isi BigInteger in java and hex value in Windows/Mac/Adobe
                    System.out.println(certificateHolder.getSerialNumber().toString(16));

                    //result.add(new JcaX509CertificateConverter().getCertificate(certificateHolder));

                    /*PublicKey pkey = cert.getPublicKey();
                    System.out.println(pkey.toString());
                    System.out.println(cert.getNotBefore());
                    System.out.println(cert.getNotAfter());
                    System.out.println(cert.getSerialNumber());
                    System.out.println("issuer: " + cert.getIssuerDN());
                    System.out.println("subject:" + cert.getSubjectDN());
                    System.out.println("subject:" + cert.getSubjectDN());
                    System.out.println(cert.getSigAlgName());
                    */
                }
            }
        } catch (CMSException cmse) {
            cmse.printStackTrace();
        }
    }
}

In Adobe the public key is shown like this:

30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8D 00 30 81 89 02 81 81 00 A8 D1 52 E7 2F 58 E8 AE 62 F6 C5 77 2F 78 FA 21 46 51 B5 EF A3 A4 4C E2 EE BD A0 80 46 B6 1D 66 37 01 82 3F 65 5D 3B 0B E7 11 08 05 94 40 CF F2 EF CC BF D9 1A F6 6F 5B 0E 16 5F 85 C1 F3 D7 9D C8 C6 EF 41 09 7C A4 C3 D5 CA 1C F0 80 E6 3F BA D8 69 8F 67 67 70 FC EB 28 48 59 B3 4F F4 6B 38 E7 3B 94 0F 7C EF 2C 02 41 8A 35 A8 72 DE DE 78 DD ED 90 AD 5E 25 A3 71 DD 59 95 1C 57 24 C8 B5 02 03 01 00 01

In java, using

System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));

SerialNumber is BigInteger in java and hex value in Windows/Mac/Adobe it is shown like this:

03818d0030818902818100a8d152e72f58e8ae62f6c5772f78fa214651b5efa3a44ce2eebda08046b61d663701823f655d3b0be71108059440cff2efccbfd91af66f5b0e165f85c1f3d79dc8c6ef41097ca4c3d5ca1cf080e63fbad8698f676770fceb284859b34ff46b38e73b940f7cef2c02418a35a872dede78dded90ad5e25a371dd59951c5724c8b50203010001

For SerialNumber it works fine. Java code:

System.out.println(certificateHolder.getSerialNumber().toString(16));

Java output:

b27f048515c4f8e4

Adobe output:

00 B2 7F 04 85 15 C4 F8 E4

Many thanks in advance!

mkl
  • 90,588
  • 15
  • 125
  • 265
J S
  • 79
  • 9
  • Adobe (note the first line does not exist in java, the rest matches). Why? 30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8D 00 30 81 89 02 81 81 00 A8 D1 52 E7 2F 58 E8 AE 62 F6 C5 77 2F 78 FA 21 46 51 B5 EF A3 A4 4C E2 EE BD A0 80 46 B6 1D 66 37 01 82 3F 65 5D 3B 0B E7 11 08 05 94 40 CF F2 EF CC BF D9 1A F6 6F 5B 0E 16 5F 85 C1 F3 D7 9D C8 C6 EF 41 09 7C A4 C3 D5 CA 1C F0 80 E6 3F BA D8 69 8F 67 67 70 FC EB 28 48 59 B3 4F F4 6B 38 E7 3B 94 0F 7C EF 2C 02 41 8A 35 A8 72 DE DE 78 DD ED 90 AD 5E 25 A3 71 DD 59 95 1C 57 24 C8 B5 02 03 01 00 01 – J S Jun 09 '19 at 15:30
  • java: 30 81 89 02 81 81 00 A8 D1 52 E7 2F 58 E8 AE 62 F6 C5 77 2F 78 FA 21 46 51 B5 EF A3 A4 4C E2 EE BD A0 80 46 B6 1D 66 37 01 82 3F 65 5D 3B 0B E7 11 08 05 94 40 CF F2 EF CC BF D9 1A F6 6F 5B 0E 16 5F 85 C1 F3 D7 9D C8 C6 EF 41 09 7C A4 C3 D5 CA 1C F0 80 E6 3F BA D8 69 8F 67 67 70 FC EB 28 48 59 B3 4F F4 6B 38 E7 3B 94 0F 7C EF 2C 02 41 8A 35 A8 72 DE DE 78 DD ED 90 AD 5E 25 A3 71 DD 59 95 1C 57 24 C8 B5 02 03 01 00 01 – J S Jun 09 '19 at 15:31
  • I tried now this function in java: System.out.println(DatatypeConverter.printHexBinary(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getBytes())); Please compare the previous 2 comments: The output for java is now like Adobe but Adobe has the following additional values at the beginning. Why is that so and how can I get exact what Adobe shows? 30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8D 00 – J S Jun 09 '19 at 15:35

1 Answers1

1

The Issue

The difference is that Adobe presents the hex dump of the complete SubjectPublicKeyInfo object (the public key including the algorithm information and the key value) while your code only dumps the RSAPublicKey (the key itself).

You can see this clearer by looking at the ASN.1 definitions of the objects in question and an ASN.1 dump of both arrays:

The SubjectPublicKeyInfo

   SubjectPublicKeyInfo  ::=  SEQUENCE  {
        algorithm            AlgorithmIdentifier,
        subjectPublicKey     BIT STRING  }

Adobe's Dump of the SubjectPublicKeyInfo

    <30 81 9F>
  0 159: SEQUENCE {
    <30 0D>
  3  13: . SEQUENCE {
    <06 09>
  5   9: . . OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
       : . . . (PKCS #1)
    <05 00>
 16   0: . . NULL
       : . . }
    <03 81 8D>
 18 141: . BIT STRING, encapsulates {
    <30 81 89>
 22 137: . . SEQUENCE {
    <02 81 81>
 25 129: . . . INTEGER    
       : . . . . 00 A8 D1 52 E7 2F 58 E8    ...R./X.
       : . . . . AE 62 F6 C5 77 2F 78 FA    .b..w/x.
       : . . . . 21 46 51 B5 EF A3 A4 4C    !FQ....L
       : . . . . E2 EE BD A0 80 46 B6 1D    .....F..
       : . . . . 66 37 01 82 3F 65 5D 3B    f7..?e];
       : . . . . 0B E7 11 08 05 94 40 CF    ......@.
       : . . . . F2 EF CC BF D9 1A F6 6F    .......o
       : . . . . 5B 0E 16 5F 85 C1 F3 D7    [.._....
       : . . . . 9D C8 C6 EF 41 09 7C A4    ....A.|.
       : . . . . C3 D5 CA 1C F0 80 E6 3F    .......?
       : . . . . BA D8 69 8F 67 67 70 FC    ..i.ggp.
       : . . . . EB 28 48 59 B3 4F F4 6B    .(HY.O.k
       : . . . . 38 E7 3B 94 0F 7C EF 2C    8.;..|.,
       : . . . . 02 41 8A 35 A8 72 DE DE    .A.5.r..
       : . . . . 78 DD ED 90 AD 5E 25 A3    x....^%.
       : . . . . 71 DD 59 95 1C 57 24 C8    q.Y..W$.
       : . . . . B5                         .
    <02 03>
157   3: . . . INTEGER 65537
       : . . . }
       : . . }
       : . }

The RSAPublicKey

RSAPublicKey ::= SEQUENCE {
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e
}

Your Dump of the RSAPublicKey

    <30 81 89>
  0 137: SEQUENCE {
    <02 81 81>
  3 129: . INTEGER    
       : . . 00 A8 D1 52 E7 2F 58 E8    ...R./X.
       : . . AE 62 F6 C5 77 2F 78 FA    .b..w/x.
       : . . 21 46 51 B5 EF A3 A4 4C    !FQ....L
       : . . E2 EE BD A0 80 46 B6 1D    .....F..
       : . . 66 37 01 82 3F 65 5D 3B    f7..?e];
       : . . 0B E7 11 08 05 94 40 CF    ......@.
       : . . F2 EF CC BF D9 1A F6 6F    .......o
       : . . 5B 0E 16 5F 85 C1 F3 D7    [.._....
       : . . 9D C8 C6 EF 41 09 7C A4    ....A.|.
       : . . C3 D5 CA 1C F0 80 E6 3F    .......?
       : . . BA D8 69 8F 67 67 70 FC    ..i.ggp.
       : . . EB 28 48 59 B3 4F F4 6B    .(HY.O.k
       : . . 38 E7 3B 94 0F 7C EF 2C    8.;..|.,
       : . . 02 41 8A 35 A8 72 DE DE    .A.5.r..
       : . . 78 DD ED 90 AD 5E 25 A3    x....^%.
       : . . 71 DD 59 95 1C 57 24 C8    q.Y..W$.
       : . . B5                         .
    <02 03>
135   3: . INTEGER 65537
       : . }

The solution

The solution is obvious, instead of dumping the public key data only

System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));

dump the whole SubjectPublicKeyInfo object:

System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getEncoded()));
mkl
  • 90,588
  • 15
  • 125
  • 265
  • aaah! Indeed. Very well explained! Thanks a lot! You seem to be a good source of information, would you mind also taking a look at my other question with title „https://stackoverflow.com/questions/56530797/need-advice-on-checking-signature-certificate-of-a-signed-pdf-using-java„? Thank you in advance for your help! – J S Jun 13 '19 at 18:24