Set/Get 在 Java 中导入 DER/PEM 时的 X509 CertificatePolicies 扩展

Set/Get X509 CertificatePolicies Extension when importing DER/PEM in Java

我在 Java 中获取和设置证书策略扩展时遇到问题。我正在使用充气城堡 1.57。

我正在像这样向证书生成器添加扩展:

boolean isCritical = Extensions.certificatePolicies;
String cpValue = Extensions.certificatePoliciesValue;
cerGen.addExtension(Extension.certificatePolicies, isCritical, cpValue.getBytes());

并获得如下扩展:

byte[] policyBytes = certificate.getExtensionValue(Extension.certificatePolicies.toString());
if (policyBytes != null) {
    Object policyObj = new ASN1InputStream(policyBytes).readObject();
    policyBytes = ((DEROctetString) policyObj).getOctets();
    String policyField = new String(policyBytes); // this is cpValue when set
}

这在我导出证书之前工作正常,但是当我将它导出为 DER 或 PEM 类型时,当我尝试导入它时出现错误:

java.io.IOException: Invalid encoding for CertificatePoliciesExtension.

这是我的导入源代码:

 CertificateFactory fact = CertificateFactory.getInstance("X.509");
 FileInputStream is = new FileInputStream(file.getAbsolutePath());
 X509Certificate cer = (X509Certificate) fact.generateCertificate(is);

当我尝试生成证书时,最后一行出现异常。

发生错误是因为您将扩展创建为单个 String

您获取扩展的代码有效,因为您也将其作为单个 String 阅读(您阅读的方式与创建它的方式完全相同,这就是它有效的原因)。

但是 Certificate Policies 扩展有一个很好的预定义格式,CertificateFactory 尝试根据这种格式解析证书。

RFC 5280 中您可以找到扩展名的格式:

certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation

PolicyInformation ::= SEQUENCE {
    policyIdentifier   CertPolicyId,
    policyQualifiers   SEQUENCE SIZE (1..MAX) OF
                            PolicyQualifierInfo OPTIONAL }

CertPolicyId ::= OBJECT IDENTIFIER

PolicyQualifierInfo ::= SEQUENCE {
    policyQualifierId  PolicyQualifierId,
    qualifier          ANY DEFINED BY policyQualifierId }

-- policyQualifierIds for Internet policy qualifiers

id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }

PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
... and lots of other types definitions

请注意,扩展名不是 String。它是一个PolicyInformation的序列,这是一个标识符和限定符等的序列。

我创建了一个只有一个值的示例扩展,作为示例:

import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.PolicyQualifierId;
import org.bouncycastle.asn1.x509.PolicyQualifierInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;

X509v3CertificateBuilder certGen = //create builder

boolean isCritical = true; // depends on your application (setting any value for tests)
PolicyQualifierInfo pqInfo = new PolicyQualifierInfo("aaa.bbb"); // the value you want
PolicyInformation policyInfo = new PolicyInformation(PolicyQualifierId.id_qt_cps, new DERSequence(pqInfo));
CertificatePolicies policies = new CertificatePolicies(policyInfo);
certGen.addExtension(Extension.certificatePolicies, isCritical, policies);

要阅读此扩展,您可以执行以下操作:

import org.bouncycastle.x509.extension.X509ExtensionUtil;

X509Certificate certificate = // a java.security.cert.X509Certificate
byte[] policyBytes = certificate.getExtensionValue(Extension.certificatePolicies.toString());
if (policyBytes != null) {
    CertificatePolicies policies = CertificatePolicies.getInstance(X509ExtensionUtil.fromExtensionValue(policyBytes));
    PolicyInformation[] policyInformation = policies.getPolicyInformation();
    for (PolicyInformation pInfo : policyInformation) {
        ASN1Sequence policyQualifiers = (ASN1Sequence) pInfo.getPolicyQualifiers().getObjectAt(0);
        System.out.println(policyQualifiers.getObjectAt(1)); // aaa.bbb
    }
}

以这种方式创建证书,fact.generateCertificate 将创建证书而不会出错。