2

我正在创建一个 CSCA 主列表签名数据,但在成功创建它之后,我在签名消息中看到两个八位字节字符串而不是一个。请检查源代码和输出文件

使用 BC 的 CMS

// 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 使用太阳----

    // 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));         
4

1 回答 1

1

更正!虽然创建 PKCS7 和 CMS 的方式有所不同,但根据评论,这里的区别在于 Bouncy 使用了“构造”编码(无限长度,尽管在这里不太重要),请参阅wikipedia。ASN.1 中的“构造”项具有该项的一个标记长度前缀和一个或多个构成构造项值的元素的附加标记长度前缀。

$ 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“内容结束”,终止构造的项目。因此,外部构造的 OCTET STRING 实际上由一个元素组成,该元素是原始 OCTET STRING。

猜测一下,Bouncy 对内容和 encapContentInfo 以及包含它们的外部 SignedData 使用构造+不确定,以允许它们大于内存中的容量——在加密中通常被称为“在线”(对它来说是一个奇怪的术语)或者更明智的“流媒体”。但它也将它用于证书和 signerInfos 组件,它们从来没有这个问题——也许只是为了方便?

sun 类可能没有这样做,尽管您没有发布数据来确认(或者可以查看使用的代码)。

这实际上是 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,而在阳光下(您没有显示源代码,但显然是 PKCS7)它是 1。PKCS7 只定义了高达 1 的版本,所以任何(结构与)版本> 1 必须是 CMS。

于 2019-11-01T10:18:48.380 回答