can't get public key display in java to match those in Adobe

孤人 提交于 2019-12-24 11:29:37

问题


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!


回答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()));


来源:https://stackoverflow.com/questions/56515629/cant-get-public-key-display-in-java-to-match-those-in-adobe

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!