使用Bouncy Castle在Java中创建自定义X509 v3扩展
我已经成功地使用Bouncy Castle的X509v3CertificateBuilder Java类创建了带有标准V3扩展的X509证书。我现在正在尝试创建带有自定义扩展名的证书 我可以使用addExtension(…)方法创建自定义扩展,但是,证书中的结果值不是我想要的。例如,我希望在自定义OID 1.2.3.4“00 00 00 FF FF FF”下的证书中列出这些精确的八位字节。我尝试过的每件事都用ASN1编码将八位字节字符串包装起来,结果是“04 08 00 00 00 FF FF FF” 基本上,我想用Java创建一个具有自定义扩展名的证书,该扩展名与使用具有以下配置的扩展名文件使用OpenSSL创建证书时的外观相同:使用Bouncy Castle在Java中创建自定义X509 v3扩展,java,openssl,certificate,x509certificate,bouncycastle,Java,Openssl,Certificate,X509certificate,Bouncycastle,我已经成功地使用Bouncy Castle的X509v3CertificateBuilder Java类创建了带有标准V3扩展的X509证书。我现在正在尝试创建带有自定义扩展名的证书 我可以使用addExtension(…)方法创建自定义扩展,但是,证书中的结果值不是我想要的。例如,我希望在自定义OID 1.2.3.4“00 00 00 FF FF FF”下的证书中列出这些精确的八位字节。我尝试过的每件事都用ASN1编码将八位字节字符串包装起来,结果是“04 08 00 00 00 FF FF
1.2.3.4=DER:00:00:00:00:FF:FF:FF:FF
X509v3CertificateBuilder类是否可以以干净的方式实现这一点
下面是创建“不正确”值的代码片段
证书是ASN.1编码的,所以扩展值也应该是ASN.1编码的。04为八位字节字符串类型,08为该八位字节字符串的长度。BouncyCastle对扩展数据的格式一无所知,很可能这就是它不剥离标记和长度的原因,您应该手动解码该数据。在尝试了许多不同的选项后,我认为不可能使用X509v3CertificateBuilder创建具有原始(非ASN.1编码)值的扩展。addExtension()方法期望或更改输入值为ASN.1编码 然而,在查看了X509v3CertificateBuilder在幕后使用的方法的BouncyCastle源代码之后,我找到了一种使用其他类的方法。涉及的代码行更多,但它相当简单,并给出了所需的结果 下面是允许使用原始值进行自定义扩展的代码
// 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);
这些额外的字节(0408)是ASN.1编码的标记类型和标记长度。看起来您的BouncyCastle在需要时(在调用ext.getExtnValue()时)没有剥离它们,或者您使用的BouncyCastle错误。鉴于它是开源的,“源代码是最好的文档”,您可以查看源代码以获得提示。谢谢Eugene!我可以查看源代码并使用其他方法来完成所需的操作。谢谢Nickolay,但是使用此证书的应用程序要求值为原始值,而不是ASN.1编码。我能够在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);