【问题标题】:Creating Custom X509 v3 Extensions in Java with Bouncy Castle使用 Bouncy Castle 在 Java 中创建自定义 X509 v3 扩展
【发布时间】:2013-05-07 06:10:42
【问题描述】:

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

【问题讨论】:

  • 那些额外的字节字节(04 08)是ASN.1编码的标签类型和标签长度。看起来您的 BouncyCastle 没有在需要时剥离它们(在调用 ext.getExtnValue() 时),或者您使用错误的 BouncyCastle。鉴于它是开源的并且“源代码是最好的文档”,您可以查看源代码以获取提示。
  • 谢谢尤金!我能够查看源代码并使用其他方法来完成所需的工作。

标签: java openssl certificate x509certificate bouncycastle


【解决方案1】:

在尝试了很多不同的选项后,我认为不可能使用 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);

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 感谢 Nickolay,但使用此证书的应用程序要求该值是原始值而不是 ASN.1 编码。我能够在 Bouncy Castle 中找到其他方法来创建原始值。
    猜你喜欢
    • 2015-07-03
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    相关资源
    最近更新 更多