3

我已成功使用 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);
4

2 回答 2

4

在尝试了很多不同的选项之后,我认为不可能使用 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);
于 2013-05-10T20:40:52.017 回答
1

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

于 2013-05-07T09:30:13.193 回答