I am creating a CSCA Master list signed data but after successful creation of it, I see two Octet String instead of one in signed message. Please check the source code and output files
CMS using 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));
>>>>> encoded data :
308202b2020100318202ab308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe4
>>>>> ML data :
308006092a864886f70d010702a0803080020103310f300d0609608648016503040201050030800606678108010102a0802480048202b6308202b2020100318202ab308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe4000000000000a0803082044c308203b5a00302010202142710e65ec4b56813da4e0e1e0223b7d485aa64d9300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830325a170d3239313032383032343830325a304f3121301f06035504030c184d61737465724c6973745369676e65724365727454657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230820122300d06092a864886f70d01010105000382010f003082010a0282010100cb4ef691bb600dd6f514569ed79853d56f053257ddcaf11cd7323824499d011d5cc7652e50789977922c76d8c0d937426ce81e74b5b4f52a419481aab713114916859c23a53ac3937ac22a73c1f31b281f74c5c31574ab2f5f270d31667ee3fe9f69d231957dd33a4c97a20c19c0cabcfddc467786c6be42c6fef962c00f44d17e5d50c39443a14d9f44baf89974e5b5620381e4c2096008e7994f4eb1ee70689fce105a22dc1316d4fea5753673c68cc1fc9b6636b088408672bc57ccbc3f2cd74855939c1ab6bf7cb9b7a56f9ace27c92abf431381659ce9d99326f8fd485a24306b7514b5c5903bf417f8a460aec2893f7913c184638641804891836844cb0203010001a38201af308201ab301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730818e06082b06010505070101048181307f302006082b060105050730028614687474703a2f2f6578616d706c652e636f6d2f30302006082b060105050730028614687474703a2f2f6578616d706c652e636f6d2f31303906082b06010505073001862d687474703a2f2f63612d646566696e65642e6f6373702e736572766963652e6c6f6361746f722e75726c2e7377302c0603551d110425302381214d61737465724c6973745369676e657243657274546573744064656d6f2e636f6d30140603551d250101ff040a3008060667810801010330570603551d1f0450304e3025a023a021861f687474703a2f2f7777772e64656d6f2e6f72672f6261722f6261722e63726c3025a023a021861f687474703a2f2f7777772e64656d6f2e6f72672f666f6f2f666f6f2e63726c301d0603551d0e041604148d2713fb3995e04b0dda8a02a1a3d9141ba01914302b0603551d1004243022800f32303139313033313032343830325a810f32303230303133313032343830325a300e0603551d0f0101ff040403020780300d06092a864886f70d01010b050003818100004f1211d31b962c3f7060ca29af5895593aaaecd4a0ec4657fc7e4e54d8f427771c0ff58db6ee5d11fe74074f0838cfbc541fd4a793d10baa4bd0b8b5a4aae8eb6eb330dafcae2f88f9f94981ccc8983565724365ea8dc793bf80b131ffa2f29e9aa4943597fcce72b0ddf2228c942ec4be3a3490935846cdef8664bf0bc5c1308202a730820210a003020102021024c2de802df5eb9a5ffc421546f39635300d06092a864886f70d01010b0500303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b52301e170d3139313033313032343830305a170d3334313032373032353830305a303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5230819f300d06092a864886f70d010101050003818d0030818902818100b23a5a61e46f522c5d0e43325b9485065cabb6db0d88e32bb6ceb0d32ebb740485458e1e4e1cdfe317829e3d785f2de66d0f270120919f46d759a64e944c3579661cf850714af2fd2088f5dc91b1838571802f7d4d7b61219da296a8ae7f55362aa28836cea220635660b0b8c8f3cd596234bbe5ccb04873aa3e301c05f86eb70203010001a381a33081a0300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106302b0603551d1004243022800f32303139313033313032353830305a810f32303234313033313032353830305a301d0603551d0e0416041456d7d0f4db824006e0dc864129ddd6991b36c467301f0603551d2304183016801456d7d0f4db824006e0dc864129ddd6991b36c46730100603551d200409300730050603290101300d06092a864886f70d01010b05000381810027ebd5fe0fd6e8df20e485d07f5b3420cb9719d2bad3dec7db5611cb690087d26f398b4849dd7d99a2abf3a2a71f7b108941a12df1a8a9c42a9c48a0750fded7a5ba38f692780cb6663febfb28d879bb53155113d773b8349e0c658c4ddc5c3d1ec7f8d35d4e72223efaacfdc53698e9157ac4590c708f91346c286d1b7e4fe400003182021a308202160201013057303f3111300f06035504030c084353434154657374310d300b060355040b0c0464656d6f310e300c060355040a0c05647265616d310b3009060355040613024b5202142710e65ec4b56813da4e0e1e0223b7d485aa64d9300d06096086480165030402010500a08195301506092a864886f70d01090331080606678108010102301c06092a864886f70d010905310f170d3139313130313030323033365a302d06092a864886f70d0109343120301e300d06096086480165030402010500a10d06092a864886f70d01010b0500302f06092a864886f70d010904312204202784558fbdeca49e7f905b161924b1b8306df980ed191907f1469ab46b379953300d06092a864886f70d01010b0500048201005d1ffa5ce0cef0304899b192eb873a8d9d656b28ed7fc1a4dfdeea9cc9325a9a228b9a7fb0962358c29d98f6a2b679e40fe5b918f615ecf12624764439c5e5b81665ceaca0c718e6b63bb57b8e8ea0b0579dc0b32923c9add0191b0864ff20b3245175ab7231e10c39d7867d7df1e712b81ba4cc4e0f300ede5c66ec73af6a6a3caf70358844a71c49d7b355d0e584d622c46dbdfc9ecb9a7fdea03a1a3e891f78c57420d2260b317c896312c982885d8f9438eddcef0c9ae19a775f0a7725440a6d4f0ad67daf2c8095e3b6668169e79f2e23b34876c2c8daf622bf0d0ec31cbd9259929dce951050564a7dcf92ad2f30d7945c2500f89653d3cfa2f4f7cc1a000000000000
Wrong Master list (using BC)
Expected Master list (using sun.security.pkcs)
----PKCS#7 using 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));
Correction! While there is a difference in the way PKCS7 and CMS are created, as per comment the difference here is that Bouncy used 'constructed' encoding (with indefinite length, although that is less important here), see wikipedia. A 'constructed' item in ASN.1 has one tag-length prefix for the item and additional tag-length prefix(es) for one or more element(s) that make up the value of the constructed item.
If we look at the actual bytes at offset 49 (in hex), we find
and at 49+6+0x2b6=749 we find
00 00
which is 'end of contents', terminating the constructed item. Thus the outer, constructed OCTET STRING actually consists of the one element which is a primitive OCTET STRING.At a guess, Bouncy uses constructed+indefinite for the content and encapContentInfo, and the outer SignedData containing them, to allow them to be larger than fits in memory -- what in crypto is often called 'online' (a weird term for it) or a bit more sensibly 'streaming'. But it also uses this for the certificates and signerInfos components, which never have this issue -- maybe just for convenience?
The sun classes presumably didn't do this, although you didn't post the data to confirm (or the code used which could be looked at).
This is actually BER for two reasons; DER does not allow either constructed OCTET STRING or indefinite length.
(original but inapplicable answer for reference)
This is a small and easily missed difference between PKCS7 (the RSALabs original) and CMS (its IETFized successor). It was actually introduced in RFC 2630 in 1999, but not clearly documented until RFC 3369 sec 5.2.1 in 2002. Note that
version
(the Integer at beginning of SignedData, which is the outer Context-0 EXPLICIT SEQUENCE) also differs; in the Bouncy-created CMS version it is 3, while in the sun (for which you don't show the source, but is apparently PKCS7) it is 1. PKCS7 only defined version up to 1, so any (structure with) version > 1 must be CMS.