使用Bouncy Castle在Java中创建自定义X509 v3扩展

我已成功使用Bouncy Castle的X509v3CertificateBuilder Java类创建带有标准V3扩展的X509证书。 我现在正在尝试使用自定义扩展创建证书。

我可以使用addExtension(…)方法创建自定义扩展,但是,证书中的结果值不是我想要的。 例如,我希望在自定义OID 1.2.3.4下的证书中列出这些确切的八位字节:“00 00 00 00 FF FF FF FF”。 我尝试的所有内容都包含ASN1编码的八位字符串,最终为“04 08 00 00 00 00 FF FF FF FF”。

基本上,我想在Java中创建一个带有自定义扩展的证书,该扩展看起来与使用具有此配置的扩展文件使用OpenSSL创建时证书的外观相同:

1.2.3.4=DER:00:00:00:00:FF:FF:FF:FF 

这可以用X509v3CertificateBuilder类以干净的方式完成吗?

下面是一段创建“不正确”值的代码片段。

  // Raw value to place in cert for OID 1.2.3.4. byte[] bytearray = {0, 0, 0, 0, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; ASN1ObjectIdentifier asn1oid = new ASN1ObjectIdentifier("1.2.3.4"); Extension ext = new Extension(asn1oid, false, bytearray); X509v3CertificateBuilder certBldr = new JcaX509v3CertificateBuilder( caCert, serial, startDate, endDate, dn, pubKey) .addExtension( new ASN1ObjectIdentifier("2.5.29.19"), false, new BasicConstraints(false)) .addExtension( new ASN1ObjectIdentifier("2.5.29.15"), true, new X509KeyUsage( X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation | X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)) .addExtension( new ASN1ObjectIdentifier("1.2.3.4"), false, ext.getExtnValue()); // Create and sign the certificate. X509CertificateHolder certHolder = certBldr.build(sigGen); X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC) .getCertificate(certHolder); 

在尝试了很多不同的选项之后,我认为不可能使用X509v3CertificateBuilder来创建具有原始(非ASN.1编码)值的扩展。 addExtension()方法期望或更改输入值为ASN.1编码。

但是,在查看了X509v3CertificateBuilder在幕后使用的方法的Bouncy Castle源代码之后,我找到了一种方法来与其他类一起使用。 涉及的代码行数较多,但它非常简单并且可以提供所需的结果。

以下是允许使用原始值的自定义扩展的代码。

  // Raw value to place in cert for OID 1.2.3.4. byte[] bytearray = {0, 0, 0, 0, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; // Start creating the certificate beginning with the TBS certificate. V3TBSCertificateGenerator tbsGen = new V3TBSCertificateGenerator(); tbsGen.setSerialNumber(new ASN1Integer(serialNum)); tbsGen.setIssuer(issuer); tbsGen.setStartDate(new Time(new Date(startDate))); tbsGen.setEndDate(new Time(new Date(endDate))); tbsGen.setSubject(new X500Name(dn)); tbsGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(certPubKey.getEncoded())); tbsGen.setSignature(sigGen.getAlgorithmIdentifier()); // The Key Usage extension: X509KeyUsage keyuse = new X509KeyUsage( X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation | X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment); Extension keyUsageExt = new Extension( Extension.keyUsage, true, keyuse.getEncoded()); // The Basic Constraints extension: BasicConstraints basic = new BasicConstraints(false); Extension basicExt = new Extension( Extension.basicConstraints, false, basic.getEncoded()); // The Custom extension: ASN1ObjectIdentifier asn1iod = new ASN1ObjectIdentifier("1.2.3.4"); Extension customExt = new Extension( asn1iod, false, bytearray); Extension[] extArray = {keyUsageExt, basicExt, customExt}; tbsGen.setExtensions(new Extensions(extArray)); // Create the TBS certificate. TBSCertificate tbsCert = tbsGen.generateTBSCertificate(); // Sign the certificate. OutputStream ostream = sigGen.getOutputStream(); DEROutputStream derOstream = new DEROutputStream(ostream); derOstream.writeObject(tbsCert); ostream.close(); byte[] tbsSig = sigGen.getSignature(); // Assemble the full X509 certificate. (TBS + Sig Alg + Sig) ASN1EncodableVector asnVector = new ASN1EncodableVector(); asnVector.add(tbsCert); asnVector.add(sigGen.getAlgorithmIdentifier()); asnVector.add(new DERBitString(tbsSig)); X509CertificateHolder certHolder = new X509CertificateHolder( org.bouncycastle.asn1.x509.Certificate.getInstance(new DERSequence(asnVector))); X509Certificate cert = new JcaX509CertificateConverter() .setProvider(BC).getCertificate(certHolder); 

证书是ASN.1编码的,因此扩展值也应该是ASN.1编码的。 04是OCTET STRING类型,08 – 这个八位字节串的长度。 BouncyCastle对扩展数据的格式一无所知,这很可能是因为它没有剥离标签和长度,你应该手动解码这些数据。