Bouncycastle 签名数据消息中的附加八位字节字符串
Additional Octet String in Bouncycastle signed data message
我正在创建国家签名认证机构主列表签名数据,但在成功创建之后,我在签名消息中看到了两个八位字节字符串,而不是一个。请检查源代码和输出文件
CMS 使用 BC
// load master list signer key
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(FileTools.readFiletoBuffer("CSCAFiles/MLS.key"));
ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
PrivateKey MLSkey = KeyFactory.getInstance(algOid).generatePrivate(spec);
// load master list signing cert
X509Certificate MLSCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/MLSCert.der"),
X509Certificate.class);
// create master list
X509CertificateHolder x509CertificateHolder = new X509CertificateHolder(MLSCert.getEncoded());
String pubkeyAlgorithm = MLSCert.getPublicKey().getAlgorithm();
String certAlgorithm = "";
if (pubkeyAlgorithm.equals("RSA")) {
certAlgorithm = "SHA256WITHRSA";
} else if (pubkeyAlgorithm.equals("ECDSA")) {
certAlgorithm = "SHA256WITHECDSA";
} else if (pubkeyAlgorithm.equals("DSA")) {
certAlgorithm = "SHA256WITHDSA";
} else {
certAlgorithm = "SHA256WITHRSA";
}
// csca cert
X509Certificate cscaCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der"),
X509Certificate.class);
// create master list content
JcaX509CertificateHolder[] hollist = CertTools
.convertToX509CertificateHolder(new X509Certificate[] { cscaCert });
org.bouncycastle.asn1.x509.Certificate certList[] = new org.bouncycastle.asn1.x509.Certificate[1];
certList[0] = hollist[0].toASN1Structure();
//certList[1] = hollist[0].toASN1Structure();
CscaMasterList ml = new CscaMasterList(certList);
System.out.println(">>>>> encoded data : " + new java.math.BigInteger(1, ml.getEncoded()).toString(16));
CMSTypedData message = new CMSProcessableByteArray(ICAOObjectIdentifiers.id_icao_cscaMasterList,
ml.toASN1Primitive().getEncoded());
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(certAlgorithm);
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
AsymmetricKeyParameter privateKeyParameter = PrivateKeyFactory.createKey(MLSkey.getEncoded());
BcContentSignerBuilder signBuilder = null;
if (pubkeyAlgorithm.equals("RSA")) {
signBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
} else if (pubkeyAlgorithm.equals("EC")) {
signBuilder = new BcECContentSignerBuilder(sigAlgId, digAlgId);
} else if (pubkeyAlgorithm.equals("DSA")) {
signBuilder = new BcDSAContentSignerBuilder(sigAlgId, digAlgId);
} else {
signBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
}
ContentSigner signer = signBuilder.build(privateKeyParameter);
SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new SignerInfoGeneratorBuilder(
new BcDigestCalculatorProvider());
SignerInfoGenerator infoGenerator = signerInfoGeneratorBuilder.build(signer, x509CertificateHolder);
CMSSignedDataGenerator dataGenerator = new CMSSignedDataGenerator();
dataGenerator.addSignerInfoGenerator(infoGenerator);
dataGenerator.addCertificate(x509CertificateHolder);
dataGenerator.addCertificate(new X509CertificateHolder(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der")));
CMSSignedData signedData = dataGenerator.generate(message, true);
System.out.println(">>>>> ML data : " + new java.math.BigInteger(1, signedData.getEncoded()).toString(16));
>>>>>>编码数据:
308202b2020100318202ab308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe4
>>>>> 机器学习数据:
308006092a864886f70d010702a0803080020103310f300d0609608648016503040201050030800606678108010102a0802480048202b6308202b2020100318202ab308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe4000000000000a0803082044c308203b5a00302010202142710e65ec4b56813da4e0e1e0223b7d485aa64d9300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830325a170d3239313032383032343830325a304f3121301f06035504030c184d61737465724c6973745369676e65724365727454657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230820122300d06092a864886f70d01010105000382010f003082010a0282010100cb4ef691bb600dd6f514569ed79853d56f053257ddcaf11cd7323824499d011d5cc7652e50789977922c76d8c0d937426ce81e74b5b4f52a419481aab713114916859c23a53ac3937ac22a73c1f31b281f74c5c31574ab2f5f270d31667ee3fe9f69d231957dd33a4c97a20c19c0cabcfddc467786c6be42c6fef962c00f44d17e5d50c39443a14d9f44baf89974e5b5620381e4c2096008e7994f4eb1ee70689fce105a22dc1316d4fea5753673c68cc1fc9b6636b088408672bc57ccbc3f2cd74855939c1ab6bf7cb9b7a56f9ace27c92abf431381659ce9d99326f8fd485a24306b7514b5c5903bf417f8a460aec2893f7913c184638641804891836844cb0203010001a38201af308201ab301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730818e06082b06010505070101048181307f302006082b060105050730028614687474703a2f2f6578616d706c652e636f6d2f30302006082b060105050730028614687474703a2f2f6578616d706c652e636f6d2f31303906082b06010505073001862d687474703a2f2f63612d646566696e65642e6f6373702e736572766963652e6c6f6361746f722e75726c2e7377302c0603551d110425302381214d61737465724c6973745369676e657243657274546573744064656d6f2e636f6d30140603551d250101ff040a3008060667810801010330570603551d1f0450304e3025a023a021861f687474703a2f2f7777772e64656d6f2e6f72672f6261722f6261722e63726c3025a023a021861f687474703a2f2f7777772e64656d6f2e6f72672f666f6f2f666f6f2e63726c301d0603551d0e041604148d2713fb3995e04b0dda8a02a1a3d9141ba01914302b0603551d1004243022800f32303139313033313032343830325a810f32303230303133313032343830325a300e0603551d0f0101ff040403020780300d06092a864886f70d01010b050003818100004f1211d31b962c3f7060ca29af5895593aaaecd4a0ec4657fc7e4e54d8f427771c0ff58db6ee5d11fe74074f0838cfbc541fd4a793d10baa4bd0b8b5a4aae8eb6eb330dafcae2f88f9f94981ccc8983565724365ea8dc793bf80b131ffa2f29e9aa4943597fcce72b0ddf2228c942ec4be3a3490935846cdef8664bf0bc5c1308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe400003182021a308202160201013057303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5202142710e65ec4b56813da4e0e1e0223b7d485aa64d9300d06096086480165030402010500a08195301506092a864886f70d01090331080606678108010102301c06092a864886f70d010905310f170d3139313130313030323033365a302d06092a864886f70d0109343120301e300d06096086480165030402010500a10d06092a864886f70d01010b0500302f06092a864886f70d010904312204202784558fbdeca49e7f905b161924b1b8306df980ed191907f1469ab46b379953300d06092a864886f70d01010b0500048201005d1ffa5ce0cef0304899b192eb873a8d9d656b28ed7fc1a4dfdeea9cc9325a9a228b9a7fb0962358c29d98f6a2b679e40fe5b918f615ecf12624764439c5e5b81665ceaca0c718e6b63bb57b8e8ea0b0579dc0b32923c9add0191b0864ff20b3245175ab7231e10c39d7867d7df1e712b81ba4cc4e0f300ede5c66ec73af6a6a3caf70358844a71c49d7b355d0e584d622c46dbdfc9ecb9a7fdea03a1a3e891f78c57420d2260b317c896312c982885d8f9438eddcef0c9ae19a775f0a7725440a6d4f0ad67daf2c8095e3b6668169e79f2e23b34876c2c8daf622bf0d0ec31cbd9259929dce951050564a7dcf92ad2f30d7945c2500f89653d3cfa2f4f7cc1a000000000000
错误的主列表(使用 BC)
预期主列表(使用sun.security.pkcs)
----PKCS#7 使用 sun----
// load master list signer key
/* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(FileTools.readFiletoBuffer("CSCAFiles/MLS.key"));
/*
* Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm OID
* and use that to construct a KeyFactory.
*/
ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
PrivateKey MLSkey = KeyFactory.getInstance(algOid).generatePrivate(spec);
X509Certificate MLSCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/MLSCert.der"),
X509Certificate.class);
// create the output stream
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
bOut.write(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der"));
bOut.write(FileTools.readFiletoBuffer("CSCAFiles/DSCert.der"));
bOut.write(FileTools.readFiletoBuffer("CSCAFiles/DLSCert.der"));
bOut.close();
// create ml
// set up the generator
////////////////////////
X509CertificateHolder x509CertificateHolder = new X509CertificateHolder(MLSCert.getEncoded());
String pubkeyAlgorithm = MLSCert.getPublicKey().getAlgorithm();
String certAlgorithm = "";
if (pubkeyAlgorithm.equals("RSA")) {
certAlgorithm = "SHA256WITHRSA";
} else if (pubkeyAlgorithm.equals("ECDSA")) {
certAlgorithm = "SHA256WITHECDSA";
} else if (pubkeyAlgorithm.equals("DSA")) {
certAlgorithm = "SHA256WITHDSA";
} else {
certAlgorithm = "SHA256WITHRSA";
}
// csca cert
X509Certificate cscaCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der"),
X509Certificate.class);
// create master list content
JcaX509CertificateHolder[] hollist = CertTools
.convertToX509CertificateHolder(new X509Certificate[] { cscaCert });
org.bouncycastle.asn1.x509.Certificate certList[] = new org.bouncycastle.asn1.x509.Certificate[2];
certList[0] = hollist[0].toASN1Structure();
certList[1] = hollist[0].toASN1Structure();
CscaMasterList ml = new CscaMasterList(certList);
///////////////////////
// Data to sign
byte[] dataToSign = ml.getEncoded();
// compute signature:
Signature signature = Signature.getInstance(certAlgorithm);
signature.initSign(MLSkey);
signature.update(dataToSign);
byte[] signedData = signature.sign();
// load X500Name
sun.security.x509.X500Name xName = new sun.security.x509.X500Name(cscaCert.getSubjectDN().getName());
// load serial number
BigInteger serial = hollist[0].getSerialNumber();
// laod digest algorithm
AlgorithmId digestAlgorithmId = new AlgorithmId(AlgorithmId.SHA_oid);
// load signing algorithm
AlgorithmId signAlgorithmId = new AlgorithmId(AlgorithmId.RSAEncryption_oid);
// Create SignerInfo:
SignerInfo sInfo = new SignerInfo(xName, serial, digestAlgorithmId, signAlgorithmId, signedData);
// Create ContentInfo:
ContentInfo cInfo = new ContentInfo(new ObjectIdentifier("2.23.136.1.1.2"),
new DerValue(DerValue.tag_OctetString, dataToSign));
// Create PKCS7 Signed data
PKCS7 p7 = new PKCS7(new AlgorithmId[] { digestAlgorithmId }, cInfo,
new java.security.cert.X509Certificate[] { cscaCert }, new SignerInfo[] { sInfo });
// Write PKCS7 to bYteArray
ByteArrayOutputStream bOut1 = new DerOutputStream();
p7.encodeSignedData(bOut1);
System.out.println(">>>>> ML data : " + new java.math.BigInteger(1, bOut1.toByteArray()).toString(16));
更正! 虽然 PKCS7 和 CMS 的创建方式有所不同,但根据评论,此处 的区别在于 Bouncy使用了 'constructed' 编码(不定长度 ,虽然这在这里不太重要),参见 wikipedia。 ASN.1 中的一项 'constructed' 项目有一个标签长度前缀,并且 附加 标签长度前缀用于构成一个或多个元素构建项目的价值。
$ openssl asn1parse <58653210.cms -inform der -i
0:d=0 hl=2 l=inf cons: SEQUENCE
2:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
13:d=1 hl=2 l=inf cons: cont [ 0 ]
15:d=2 hl=2 l=inf cons: SEQUENCE
17:d=3 hl=2 l= 1 prim: INTEGER :03
20:d=3 hl=2 l= 15 cons: SET
22:d=4 hl=2 l= 13 cons: SEQUENCE
24:d=5 hl=2 l= 9 prim: OBJECT :sha256
35:d=5 hl=2 l= 0 prim: NULL
37:d=3 hl=2 l=inf cons: SEQUENCE
39:d=4 hl=2 l= 6 prim: OBJECT :2.23.136.1.1.2
47:d=4 hl=2 l=inf cons: cont [ 0 ]
49:d=5 hl=2 l=inf cons: OCTET STRING
51:d=6 hl=4 l= 694 prim: OCTET STRING [HEX DUMP]:308202B202010031
[snip rest of (correct) body]
749:d=6 hl=2 l= 0 prim: EOC
751:d=5 hl=2 l= 0 prim: EOC
753:d=4 hl=2 l= 0 prim: EOC
755:d=3 hl=2 l=inf cons: cont [ 0 ]
757:d=4 hl=4 l=1100 cons: SEQUENCE
[snip certificate]
1861:d=4 hl=4 l= 679 cons: SEQUENCE
[snip certificate]
2544:d=4 hl=2 l= 0 prim: EOC
2546:d=3 hl=4 l= 538 cons: SET
2550:d=4 hl=4 l= 534 cons: SEQUENCE
[snip SignerInfo]
3088:d=3 hl=2 l= 0 prim: EOC
3090:d=2 hl=2 l= 0 prim: EOC
3092:d=1 hl=2 l= 0 prim: EOC
如果我们查看偏移量 49(十六进制)处的实际字节,我们会发现
24 80 -- tag for OCTET STRING _constructed_, length indefinite
-- a constructed item contains (consists of) one or more following elements
04 82 02 B6 -- tag for OCTET STRING _primitive_, length 02B6
-- this is the only element within the constructed item
并且在 49+6+0x2b6=749 我们发现 00 00
即 'end of contents',终止构造的项目。因此,外部构造的 OCTET STRING 实际上由一个元素组成,该元素是原始 OCTET STRING。
据推测,Bouncy 对内容和 encapContentInfo 以及包含它们的外部 SignedData 使用了 constructed+indefinite,以允许它们大于内存中的容量——在加密中通常称为 'online' (一个奇怪的术语)或更明智的 'streaming'。但它也将此用于证书和 signerInfos 组件,它们从来没有这个问题——也许只是为了方便?
太阳类估计没有这样做,虽然你没有post数据证实(或者使用的代码可以看一下)。
这实际上是 BER,原因有二; DER不允许或者构造OCTET STRING 或者不定长度。
(原创但不适用的答案供参考)
这是 PKCS7(RSALabs 的原始版本)和 CMS(其 IETF 化后继版本)之间的一个小差异,很容易被忽略。它实际上是在 1999 年的 RFC 2630 中引入的,但直到 2002 年的 RFC 3369 sec 5.2.1 才明确记录。请注意 version
(SignedData 开头的 Integer,即外部 Context-0 EXPLICIT SEQUENCE)也不同;在 Bouncy 创建的 CMS 版本中它是 3,而在 sun 中(你没有显示源代码,但显然是 PKCS7)它是 1。PKCS7 只定义版本最多 1,所以任何(结构)版本> 1 必须是 CMS。
我正在创建国家签名认证机构主列表签名数据,但在成功创建之后,我在签名消息中看到了两个八位字节字符串,而不是一个。请检查源代码和输出文件
CMS 使用 BC
// load master list signer key
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(FileTools.readFiletoBuffer("CSCAFiles/MLS.key"));
ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
PrivateKey MLSkey = KeyFactory.getInstance(algOid).generatePrivate(spec);
// load master list signing cert
X509Certificate MLSCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/MLSCert.der"),
X509Certificate.class);
// create master list
X509CertificateHolder x509CertificateHolder = new X509CertificateHolder(MLSCert.getEncoded());
String pubkeyAlgorithm = MLSCert.getPublicKey().getAlgorithm();
String certAlgorithm = "";
if (pubkeyAlgorithm.equals("RSA")) {
certAlgorithm = "SHA256WITHRSA";
} else if (pubkeyAlgorithm.equals("ECDSA")) {
certAlgorithm = "SHA256WITHECDSA";
} else if (pubkeyAlgorithm.equals("DSA")) {
certAlgorithm = "SHA256WITHDSA";
} else {
certAlgorithm = "SHA256WITHRSA";
}
// csca cert
X509Certificate cscaCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der"),
X509Certificate.class);
// create master list content
JcaX509CertificateHolder[] hollist = CertTools
.convertToX509CertificateHolder(new X509Certificate[] { cscaCert });
org.bouncycastle.asn1.x509.Certificate certList[] = new org.bouncycastle.asn1.x509.Certificate[1];
certList[0] = hollist[0].toASN1Structure();
//certList[1] = hollist[0].toASN1Structure();
CscaMasterList ml = new CscaMasterList(certList);
System.out.println(">>>>> encoded data : " + new java.math.BigInteger(1, ml.getEncoded()).toString(16));
CMSTypedData message = new CMSProcessableByteArray(ICAOObjectIdentifiers.id_icao_cscaMasterList,
ml.toASN1Primitive().getEncoded());
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(certAlgorithm);
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
AsymmetricKeyParameter privateKeyParameter = PrivateKeyFactory.createKey(MLSkey.getEncoded());
BcContentSignerBuilder signBuilder = null;
if (pubkeyAlgorithm.equals("RSA")) {
signBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
} else if (pubkeyAlgorithm.equals("EC")) {
signBuilder = new BcECContentSignerBuilder(sigAlgId, digAlgId);
} else if (pubkeyAlgorithm.equals("DSA")) {
signBuilder = new BcDSAContentSignerBuilder(sigAlgId, digAlgId);
} else {
signBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
}
ContentSigner signer = signBuilder.build(privateKeyParameter);
SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new SignerInfoGeneratorBuilder(
new BcDigestCalculatorProvider());
SignerInfoGenerator infoGenerator = signerInfoGeneratorBuilder.build(signer, x509CertificateHolder);
CMSSignedDataGenerator dataGenerator = new CMSSignedDataGenerator();
dataGenerator.addSignerInfoGenerator(infoGenerator);
dataGenerator.addCertificate(x509CertificateHolder);
dataGenerator.addCertificate(new X509CertificateHolder(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der")));
CMSSignedData signedData = dataGenerator.generate(message, true);
System.out.println(">>>>> ML data : " + new java.math.BigInteger(1, signedData.getEncoded()).toString(16));
>>>>>>编码数据:
308202b2020100318202ab308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe4
>>>>> 机器学习数据:
308006092a864886f70d010702a0803080020103310f300d0609608648016503040201050030800606678108010102a0802480048202b6308202b2020100318202ab308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe4000000000000a0803082044c308203b5a00302010202142710e65ec4b56813da4e0e1e0223b7d485aa64d9300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830325a170d3239313032383032343830325a304f3121301f06035504030c184d61737465724c6973745369676e65724365727454657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230820122300d06092a864886f70d01010105000382010f003082010a0282010100cb4ef691bb600dd6f514569ed79853d56f053257ddcaf11cd7323824499d011d5cc7652e50789977922c76d8c0d937426ce81e74b5b4f52a419481aab713114916859c23a53ac3937ac22a73c1f31b281f74c5c31574ab2f5f270d31667ee3fe9f69d231957dd33a4c97a20c19c0cabcfddc467786c6be42c6fef962c00f44d17e5d50c39443a14d9f44baf89974e5b5620381e4c2096008e7994f4eb1ee70689fce105a22dc1316d4fea5753673c68cc1fc9b6636b088408672bc57ccbc3f2cd74855939c1ab6bf7cb9b7a56f9ace27c92abf431381659ce9d99326f8fd485a24306b7514b5c5903bf417f8a460aec2893f7913c184638641804891836844cb0203010001a38201af308201ab301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730818e06082b06010505070101048181307f302006082b060105050730028614687474703a2f2f6578616d706c652e636f6d2f30302006082b060105050730028614687474703a2f2f6578616d706c652e636f6d2f31303906082b06010505073001862d687474703a2f2f63612d646566696e65642e6f6373702e736572766963652e6c6f6361746f722e75726c2e7377302c0603551d110425302381214d61737465724c6973745369676e657243657274546573744064656d6f2e636f6d30140603551d250101ff040a3008060667810801010330570603551d1f0450304e3025a023a021861f687474703a2f2f7777772e64656d6f2e6f72672f6261722f6261722e63726c3025a023a021861f687474703a2f2f7777772e64656d6f2e6f72672f666f6f2f666f6f2e63726c301d0603551d0e041604148d2713fb3995e04b0dda8a02a1a3d9141ba01914302b0603551d1004243022800f32303139313033313032343830325a810f32303230303133313032343830325a300e0603551d0f0101ff040403020780300d06092a864886f70d01010b050003818100004f1211d31b962c3f7060ca29af5895593aaaecd4a0ec4657fc7e4e54d8f427771c0ff58db6ee5d11fe74074f0838cfbc541fd4a793d10baa4bd0b8b5a4aae8eb6eb330dafcae2f88f9f94981ccc8983565724365ea8dc793bf80b131ffa2f29e9aa4943597fcce72b0ddf2228c942ec4be3a3490935846cdef8664bf0bc5c1308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe400003182021a308202160201013057303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5202142710e65ec4b56813da4e0e1e0223b7d485aa64d9300d06096086480165030402010500a08195301506092a864886f70d01090331080606678108010102301c06092a864886f70d010905310f170d3139313130313030323033365a302d06092a864886f70d0109343120301e300d06096086480165030402010500a10d06092a864886f70d01010b0500302f06092a864886f70d010904312204202784558fbdeca49e7f905b161924b1b8306df980ed191907f1469ab46b379953300d06092a864886f70d01010b0500048201005d1ffa5ce0cef0304899b192eb873a8d9d656b28ed7fc1a4dfdeea9cc9325a9a228b9a7fb0962358c29d98f6a2b679e40fe5b918f615ecf12624764439c5e5b81665ceaca0c718e6b63bb57b8e8ea0b0579dc0b32923c9add0191b0864ff20b3245175ab7231e10c39d7867d7df1e712b81ba4cc4e0f300ede5c66ec73af6a6a3caf70358844a71c49d7b355d0e584d622c46dbdfc9ecb9a7fdea03a1a3e891f78c57420d2260b317c896312c982885d8f9438eddcef0c9ae19a775f0a7725440a6d4f0ad67daf2c8095e3b6668169e79f2e23b34876c2c8daf622bf0d0ec31cbd9259929dce951050564a7dcf92ad2f30d7945c2500f89653d3cfa2f4f7cc1a000000000000
错误的主列表(使用 BC)
预期主列表(使用sun.security.pkcs)
----PKCS#7 使用 sun----
// load master list signer key
/* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(FileTools.readFiletoBuffer("CSCAFiles/MLS.key"));
/*
* Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm OID
* and use that to construct a KeyFactory.
*/
ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
PrivateKey MLSkey = KeyFactory.getInstance(algOid).generatePrivate(spec);
X509Certificate MLSCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/MLSCert.der"),
X509Certificate.class);
// create the output stream
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
bOut.write(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der"));
bOut.write(FileTools.readFiletoBuffer("CSCAFiles/DSCert.der"));
bOut.write(FileTools.readFiletoBuffer("CSCAFiles/DLSCert.der"));
bOut.close();
// create ml
// set up the generator
////////////////////////
X509CertificateHolder x509CertificateHolder = new X509CertificateHolder(MLSCert.getEncoded());
String pubkeyAlgorithm = MLSCert.getPublicKey().getAlgorithm();
String certAlgorithm = "";
if (pubkeyAlgorithm.equals("RSA")) {
certAlgorithm = "SHA256WITHRSA";
} else if (pubkeyAlgorithm.equals("ECDSA")) {
certAlgorithm = "SHA256WITHECDSA";
} else if (pubkeyAlgorithm.equals("DSA")) {
certAlgorithm = "SHA256WITHDSA";
} else {
certAlgorithm = "SHA256WITHRSA";
}
// csca cert
X509Certificate cscaCert = CertTools.getCertfromByteArray(FileTools.readFiletoBuffer("CSCAFiles/CSCACert.der"),
X509Certificate.class);
// create master list content
JcaX509CertificateHolder[] hollist = CertTools
.convertToX509CertificateHolder(new X509Certificate[] { cscaCert });
org.bouncycastle.asn1.x509.Certificate certList[] = new org.bouncycastle.asn1.x509.Certificate[2];
certList[0] = hollist[0].toASN1Structure();
certList[1] = hollist[0].toASN1Structure();
CscaMasterList ml = new CscaMasterList(certList);
///////////////////////
// Data to sign
byte[] dataToSign = ml.getEncoded();
// compute signature:
Signature signature = Signature.getInstance(certAlgorithm);
signature.initSign(MLSkey);
signature.update(dataToSign);
byte[] signedData = signature.sign();
// load X500Name
sun.security.x509.X500Name xName = new sun.security.x509.X500Name(cscaCert.getSubjectDN().getName());
// load serial number
BigInteger serial = hollist[0].getSerialNumber();
// laod digest algorithm
AlgorithmId digestAlgorithmId = new AlgorithmId(AlgorithmId.SHA_oid);
// load signing algorithm
AlgorithmId signAlgorithmId = new AlgorithmId(AlgorithmId.RSAEncryption_oid);
// Create SignerInfo:
SignerInfo sInfo = new SignerInfo(xName, serial, digestAlgorithmId, signAlgorithmId, signedData);
// Create ContentInfo:
ContentInfo cInfo = new ContentInfo(new ObjectIdentifier("2.23.136.1.1.2"),
new DerValue(DerValue.tag_OctetString, dataToSign));
// Create PKCS7 Signed data
PKCS7 p7 = new PKCS7(new AlgorithmId[] { digestAlgorithmId }, cInfo,
new java.security.cert.X509Certificate[] { cscaCert }, new SignerInfo[] { sInfo });
// Write PKCS7 to bYteArray
ByteArrayOutputStream bOut1 = new DerOutputStream();
p7.encodeSignedData(bOut1);
System.out.println(">>>>> ML data : " + new java.math.BigInteger(1, bOut1.toByteArray()).toString(16));
更正! 虽然 PKCS7 和 CMS 的创建方式有所不同,但根据评论,此处 的区别在于 Bouncy使用了 'constructed' 编码(不定长度 ,虽然这在这里不太重要),参见 wikipedia。 ASN.1 中的一项 'constructed' 项目有一个标签长度前缀,并且 附加 标签长度前缀用于构成一个或多个元素构建项目的价值。
$ openssl asn1parse <58653210.cms -inform der -i
0:d=0 hl=2 l=inf cons: SEQUENCE
2:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
13:d=1 hl=2 l=inf cons: cont [ 0 ]
15:d=2 hl=2 l=inf cons: SEQUENCE
17:d=3 hl=2 l= 1 prim: INTEGER :03
20:d=3 hl=2 l= 15 cons: SET
22:d=4 hl=2 l= 13 cons: SEQUENCE
24:d=5 hl=2 l= 9 prim: OBJECT :sha256
35:d=5 hl=2 l= 0 prim: NULL
37:d=3 hl=2 l=inf cons: SEQUENCE
39:d=4 hl=2 l= 6 prim: OBJECT :2.23.136.1.1.2
47:d=4 hl=2 l=inf cons: cont [ 0 ]
49:d=5 hl=2 l=inf cons: OCTET STRING
51:d=6 hl=4 l= 694 prim: OCTET STRING [HEX DUMP]:308202B202010031
[snip rest of (correct) body]
749:d=6 hl=2 l= 0 prim: EOC
751:d=5 hl=2 l= 0 prim: EOC
753:d=4 hl=2 l= 0 prim: EOC
755:d=3 hl=2 l=inf cons: cont [ 0 ]
757:d=4 hl=4 l=1100 cons: SEQUENCE
[snip certificate]
1861:d=4 hl=4 l= 679 cons: SEQUENCE
[snip certificate]
2544:d=4 hl=2 l= 0 prim: EOC
2546:d=3 hl=4 l= 538 cons: SET
2550:d=4 hl=4 l= 534 cons: SEQUENCE
[snip SignerInfo]
3088:d=3 hl=2 l= 0 prim: EOC
3090:d=2 hl=2 l= 0 prim: EOC
3092:d=1 hl=2 l= 0 prim: EOC
如果我们查看偏移量 49(十六进制)处的实际字节,我们会发现
24 80 -- tag for OCTET STRING _constructed_, length indefinite
-- a constructed item contains (consists of) one or more following elements
04 82 02 B6 -- tag for OCTET STRING _primitive_, length 02B6
-- this is the only element within the constructed item
并且在 49+6+0x2b6=749 我们发现 00 00
即 'end of contents',终止构造的项目。因此,外部构造的 OCTET STRING 实际上由一个元素组成,该元素是原始 OCTET STRING。
据推测,Bouncy 对内容和 encapContentInfo 以及包含它们的外部 SignedData 使用了 constructed+indefinite,以允许它们大于内存中的容量——在加密中通常称为 'online' (一个奇怪的术语)或更明智的 'streaming'。但它也将此用于证书和 signerInfos 组件,它们从来没有这个问题——也许只是为了方便?
太阳类估计没有这样做,虽然你没有post数据证实(或者使用的代码可以看一下)。
这实际上是 BER,原因有二; DER不允许或者构造OCTET STRING 或者不定长度。
(原创但不适用的答案供参考)
这是 PKCS7(RSALabs 的原始版本)和 CMS(其 IETF 化后继版本)之间的一个小差异,很容易被忽略。它实际上是在 1999 年的 RFC 2630 中引入的,但直到 2002 年的 RFC 3369 sec 5.2.1 才明确记录。请注意 version
(SignedData 开头的 Integer,即外部 Context-0 EXPLICIT SEQUENCE)也不同;在 Bouncy 创建的 CMS 版本中它是 3,而在 sun 中(你没有显示源代码,但显然是 PKCS7)它是 1。PKCS7 只定义版本最多 1,所以任何(结构)版本> 1 必须是 CMS。