问题
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