当前位置: 首页 > news >正文

《Java 加密工具与技术》8: X.509证书和属性证书

X.500 可辨别名称

X.500 可辨别名称(Distinguished Name,简称DN),是用于在X.500目录服务中唯一标识一个条目(Entry)的名称。它由一系列相对可辨别名称(Relative Distinguished Names,简称RDNs)组成,每个RDN由一个或多个属性值对构成,这些属性值对在不同的目录级别上提供了条目的唯一标识。在X.500目录服务中,DN用于确保每个条目都可以被唯一地识别和访问。

例如,一个X.500 DN可能看起来像这样:

CN=John Doe,OU=Users,DC=example,DC=com

在这个例子中:

  • CN=John Doe 是一个RDN,表示通用名称(Common Name)为“John Doe”。

  • OU=Users 是另一个RDN,表示组织单位(Organizational Unit)为“Users”。

  • DC=example 和 DC=com 是额外的RDNs,表示域组件(Domain Component)分别为“example”和“com”。

X.500 DN在多种应用中被使用,包括在公钥基础设施(PKI)中标识证书持有者,以及在轻量级目录访问协议(LDAP)中标识目录条目。

X500Principal 使用示例

X500Principal 类用于表示X.500可辨别名称(Distinguished Name, DN)。它通常用于处理与安全相关的操作,例如在公钥基础设施(PKI)中处理X.509证书的主题或颁发者名称。

import javax.security.auth.x500.X500Principal;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateFactory;
import java.io.FileInputStream;

public class X500PrincipalExample {
    public static void main(String[] args) {
        try {
            // 加载X.509证书
            FileInputStream fis = new FileInputStream("path/to/your/certificate.crt");
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
            fis.close();

            // 获取证书的主题DN
            X500Principal subjectDN = cert.getSubjectX500Principal();
            System.out.println("Subject DN: " + subjectDN.getName());

            // 获取证书的颁发者DN
            X500Principal issuerDN = cert.getIssuerX500Principal();
            System.out.println("Issuer DN: " + issuerDN.getName());

            // 使用X500Principal的构造函数创建一个新的DN
            X500Principal newDN = new X500Principal("CN=John Doe, OU=Users, O=Example Corp, C=US");
            System.out.println("New DN: " + newDN.getName());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

X500Name (BouncyCastle)使用示例

X500Name 类是用于表示X.500可辨别名称(Distinguished Name, DN)的另一种方式。它通常用于处理与安全相关的操作,例如在公钥基础设施(PKI)中处理X.509证书的主题或颁发者名称。X500Name 类通常与BouncyCastle库一起使用,因为它是BouncyCastle库的一部分,而不是标准JDK的一部分。

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;

import java.security.cert.X509Certificate;
import java.security.cert.CertificateFactory;
import java.io.FileInputStream;

public class X500NameExample {
    public static void main(String[] args) {
        try {
            // 加载X.509证书
            FileInputStream fis = new FileInputStream("path/to/your/certificate.crt");
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
            fis.close();

            // 将X509Certificate转换为X500Name
            JcaX509CertificateHolder certHolder = new JcaX509CertificateHolder(cert);
            X500Name subjectDN = certHolder.getSubject();
            X500Name issuerDN = certHolder.getIssuer();

            // 输出主题DN
            System.out.println("Subject DN: " + subjectDN.toString());

            // 输出颁发者DN
            System.out.println("Issuer DN: " + issuerDN.toString());

            // 获取主题DN中的特定属性(例如通用名称CN)
            String commonName = IETFUtils.valueToString(subjectDN.getRDNs(BCStyle.CN)[0].getFirst().getValue());
            System.out.println("Common Name (CN): " + commonName);

            // 创建一个新的X500Name
            X500Name newDN = new X500Name("CN=John Doe, OU=Users, O=Example Corp, C=US");
            System.out.println("New DN: " + newDN.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

X500NameBuilder 新建X500Name 示例

X500NameBuilder 是BouncyCastle库提供的一个工具类,用于构建 X500Name 对象。X500NameBuilder 提供了一种灵活的方式来创建和自定义X.500可辨别名称(Distinguished Name, DN)。

  • 使用 addRDN 方法添加相对可辨别名称(RDN)。

  • 每个RDN由一个属性类型(如 BCStyle.CN)和一个属性值(如 "John Doe")组成。

  • 常用的属性类型包括:

    • BCStyle.CN:通用名称(Common Name)

    • BCStyle.OU:组织单位(Organizational Unit)

    • BCStyle.O:组织名称(Organization)

    • BCStyle.L:地点(Locality)

    • BCStyle.ST:州/省(State or Province)

    • BCStyle.C:国家代码(Country Code)

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;

public class X500NameBuilderExample {
    public static void main(String[] args) {
        // 创建X500NameBuilder实例
        X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);

        // 添加属性到DN
        builder.addRDN(BCStyle.CN, "John Doe"); // 通用名称 (Common Name)
        builder.addRDN(BCStyle.OU, "Engineering"); // 组织单位 (Organizational Unit)
        builder.addRDN(BCStyle.O, "Example Corp"); // 组织名称 (Organization)
        builder.addRDN(BCStyle.L, "New York"); // 地点 (Locality)
        builder.addRDN(BCStyle.ST, "NY"); // 州/省 (State or Province)
        builder.addRDN(BCStyle.C, "US"); // 国家代码 (Country Code)

        // 构建X500Name对象
        X500Name x500Name = builder.build();

        // 输出X500Name
        System.out.println("X500Name: " + x500Name.toString());
    }
}

X500NameBuilder 修改X500Name 示例

X500Name originalName = new X500Name("CN=Alice, OU=Development, O=Example Corp, C=US");

// 使用X500NameBuilder从现有名称构建
X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
for (var rdn : originalName.getRDNs()) {
    builder.addRDN(rdn.getFirst());
}

// 添加新属性
builder.addRDN(BCStyle.OU, "Engineering");

// 构建新的X500Name
X500Name newName = builder.build();
System.out.println("New X500Name: " + newName.toString());

公钥证书

1. X509v1CertificateBuilder

  • 用途:用于构建X.509版本1(v1)证书。

  • 特点

    • X.509 v1 证书是最简单的证书格式,仅包含基本字段,如主题名称、颁发者名称、有效期和公钥。

    • 不支持扩展:X.509 v1 证书没有扩展字段,因此无法添加自定义扩展(如密钥用途、扩展密钥用途等)。

    • 使用场景:由于功能有限,X.509 v1 证书在现代应用中较少使用,通常用于简单的场景或兼容旧系统。

2. X509v2AttributeCertificateBuilder

  • 用途:用于构建X.509版本2(v2)属性证书。

  • 特点

    • 属性证书(Attribute Certificate)与传统的公钥证书不同,它不包含公钥,而是包含与某个实体(通常是公钥证书的持有者)相关的属性信息。

    • 属性证书通常用于基于角色的访问控制(RBAC)或其他与权限相关的场景。

    • 支持扩展:X.509 v2 属性证书可以包含扩展字段。

3. X509v3CertificateBuilder

  • 用途:用于构建X.509版本3(v3)证书。

  • 特点

    • X.509 v3 证书是最常用的证书格式,支持扩展字段。

    • 支持扩展:X.509 v3 证书可以包含各种扩展字段,如密钥用途(Key Usage)、扩展密钥用途(Extended Key Usage)、主题备用名称(Subject Alternative Name)等。

    • 使用场景:X.509 v3 证书广泛应用于现代PKI(公钥基础设施)中,例如SSL/TLS证书、代码签名证书、客户端身份验证证书等。

创建一个基础的公钥证书

    /**
     * Calculate a date in seconds (suitable for the PKIX profile - RFC 5280)
     *
     * @param hoursInFuture hours ahead of now, may be negative.
     * @return a Date set to now + (hoursInFuture * 60 * 60) seconds
     */
    public static Date calculateDate(int hoursInFuture)
    {
         long secs = System.currentTimeMillis() / 1000;

         return new Date((secs + (hoursInFuture * 60 * 60)) * 1000);
    }
    private static long serialNumberBase = System.currentTimeMillis();

    /**
     * Calculate a serial number using a monotonically increasing value.
     *
     * @return a BigInteger representing the next serial number in the sequence.
     */
    public static synchronized BigInteger calculateSerialNumber()
    {
        return BigInteger.valueOf(serialNumberBase++);
    }

    /**
     * Build a sample self-signed V1 certificate to use as a trust anchor, or
     * root certificate.
     *
     * @param keyPair the key pair to use for signing and providing the
     *                public key.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @return an X509CertificateHolder containing the V1 certificate.
     */
    public static X509CertificateHolder createTrustAnchor(
            KeyPair keyPair, String sigAlg)
            throws OperatorCreationException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo Root Certificate");

        X500Name name = x500NameBld.build();

        X509v1CertificateBuilder certBldr = new JcaX509v1CertificateBuilder(
                                                    name,
                                                    calculateSerialNumber(),
                                                    calculateDate(0),
                                                    calculateDate(24 * 31),
                                                    name,
                                                    keyPair.getPublic());

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                                .setProvider("BC").build(keyPair.getPrivate());

        return certBldr.build(signer);
    }

调用示例

    public static X509KeyCertPair createTrustCert()
            throws GeneralSecurityException, OperatorCreationException
    {
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair trustKp = kpGen.generateKeyPair();

        X509CertificateHolder trustCert =
                                  createTrustAnchor(trustKp, "SHA256withECDSA");
        return new X509KeyCertPair(trustKp, trustCert);
    }

转换X509CertificateHolder为X509Certificate

    /**
     * Simple method to convert an X509CertificateHolder to an X509Certificate
     * using the java.security.cert.CertificateFactory class.
     */
    public static X509Certificate convertX509CertificateHolder(
                                             X509CertificateHolder certHolder)
            throws GeneralSecurityException, IOException
    {
        CertificateFactory cFact = CertificateFactory.getInstance("X.509", "BC");

        return (X509Certificate)cFact.generateCertificate(
                                           new ByteArrayInputStream(
                                                   certHolder.getEncoded()));
    }

创建带有扩展的CA证书

    /**
     * Build a sample V3 intermediate certificate that can be used as a CA
     * certificate.
     *
     * @param signerCert certificate carrying the public key that will later
     *                   be used to verify this certificate's signature.
     * @param signerKey private key used to generate the signature in the
     *                  certificate.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @param certKey public key to be installed in the certificate.
     * @param followingCACerts
     * @return an X509CertificateHolder containing the V3 certificate.
     */
    public static X509CertificateHolder createIntermediateCertificate(
            X509CertificateHolder signerCert, PrivateKey signerKey,
            String sigAlg, PublicKey certKey, int followingCACerts)
            throws CertIOException, GeneralSecurityException,
                   OperatorCreationException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo Intermediate Certificate");

        X500Name subject = x500NameBld.build();

        X509v3CertificateBuilder certBldr = new JcaX509v3CertificateBuilder(
                signerCert.getSubject(),
                calculateSerialNumber(),
                calculateDate(0),
                calculateDate(24 * 31),
                subject,
                certKey);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

        certBldr.addExtension(Extension.authorityKeyIdentifier,
                false, extUtils.createAuthorityKeyIdentifier(signerCert))
                .addExtension(Extension.subjectKeyIdentifier,
                        false, extUtils.createSubjectKeyIdentifier(certKey))
                .addExtension(Extension.basicConstraints,
                        true, new BasicConstraints(followingCACerts))
                .addExtension(Extension.keyUsage,
                        true, new KeyUsage(
                                              KeyUsage.digitalSignature
                                            | KeyUsage.keyCertSign
                                            | KeyUsage.cRLSign));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                .setProvider("BC").build(signerKey);

        return certBldr.build(signer);
    }

调用示例

    public static X509KeyCertPair createInterCert(X509KeyCertPair trustPair)
            throws GeneralSecurityException, OperatorCreationException, CertIOException
    {
        PrivateKey trustAnchorKey = trustPair.getKeyPair().getPrivate();
        X509CertificateHolder trustCert = trustPair.getCert();

        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair caKp = kpGen.generateKeyPair();

        X509CertificateHolder caCert =
                createIntermediateCertificate(trustCert,
                        trustAnchorKey,
                        "SHA256withECDSA", caKp.getPublic(), 0);
        return new X509KeyCertPair(caKp, caCert);
    }

创建终端实体证书

    /**
     * Create a general end-entity certificate for use in verifying digital
     * signatures.
     * 
     * @param signerCert certificate carrying the public key that will later
     *                   be used to verify this certificate's signature.
     * @param signerKey private key used to generate the signature in the
     *                  certificate.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @param certKey public key to be installed in the certificate.
     * @return an X509CertificateHolder containing the V3 certificate.
     */
    public static X509CertificateHolder createEndEntity(
            X509CertificateHolder signerCert, PrivateKey signerKey,
            String sigAlg, PublicKey certKey)
            throws CertIOException, GeneralSecurityException,
                   OperatorCreationException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo End-Entity Certificate");

        X500Name subject = x500NameBld.build();

        X509v3CertificateBuilder   certBldr = new JcaX509v3CertificateBuilder(
                signerCert.getSubject(),
                calculateSerialNumber(),
                calculateDate(0),
                calculateDate(24 * 31),
                subject,
                certKey);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

        certBldr.addExtension(Extension.authorityKeyIdentifier,
                false, extUtils.createAuthorityKeyIdentifier(signerCert))
                .addExtension(Extension.subjectKeyIdentifier,
                        false, extUtils.createSubjectKeyIdentifier(certKey))
                .addExtension(Extension.basicConstraints,
                        true, new BasicConstraints(false))
                .addExtension(Extension.keyUsage,
                        true, new KeyUsage(KeyUsage.digitalSignature));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                                       .setProvider("BC").build(signerKey);

        return certBldr.build(signer);
    }

调用示例

    public static X509KeyCertPair createEECert(X509KeyCertPair caPair)
            throws GeneralSecurityException, OperatorCreationException, CertIOException
    {
        PrivateKey caPrivKey = caPair.getKeyPair().getPrivate();
        X509CertificateHolder caCert = caPair.getCert();

        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair eeKp = kpGen.generateKeyPair();

        X509CertificateHolder eeCert =
                createEndEntity(caCert, caPrivKey, "SHA256withECDSA", eeKp.getPublic());

        return new X509KeyCertPair(eeKp, eeCert);
    }

使用ExtendedKeyUsage

    /**
     * Create a special purpose end entity cert which is associated with a
     * particular key purpose.
     * 
     * @param signerCert certificate carrying the public key that will later
     *                   be used to verify this certificate's signature.
     * @param signerKey private key used to generate the signature in the
     *                  certificate.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @param certKey public key to be installed in the certificate.
     * @param keyPurpose the specific KeyPurposeId to associate with this
     *                   certificate's public key.
     * @return an X509CertificateHolder containing the V3 certificate.
     */
    public static X509CertificateHolder createSpecialPurposeEndEntity(
            X509CertificateHolder signerCert, PrivateKey signerKey,
            String sigAlg, PublicKey certKey, KeyPurposeId keyPurpose)
            throws OperatorCreationException, CertIOException,
                   GeneralSecurityException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo End-Entity Certificate");

        X500Name subject = x500NameBld.build();

        X509v3CertificateBuilder   certBldr = new JcaX509v3CertificateBuilder(
                signerCert.getSubject(),
                calculateSerialNumber(),
                calculateDate(0),
                calculateDate(24 * 31),
                subject,
                certKey);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

        certBldr.addExtension(Extension.authorityKeyIdentifier,
                false, extUtils.createAuthorityKeyIdentifier(signerCert))
                .addExtension(Extension.subjectKeyIdentifier,
                        false, extUtils.createSubjectKeyIdentifier(certKey))
                .addExtension(Extension.basicConstraints,
                        true, new BasicConstraints(false))
                .addExtension(Extension.extendedKeyUsage,
                              true, new ExtendedKeyUsage(keyPurpose));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                                       .setProvider("BC").build(signerKey);

        return certBldr.build(signer);
    }

调用示例

    public static X509KeyCertPair createEESpecCert(X509KeyCertPair caPair)
            throws GeneralSecurityException, OperatorCreationException, CertIOException
    {
        PrivateKey caPrivKey = caPair.getKeyPair().getPrivate();
        X509CertificateHolder caCert = caPair.getCert();

        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair specEEKp = kpGen.generateKeyPair();

        X509CertificateHolder specEECert =
                createSpecialPurposeEndEntity(caCert, caPrivKey,
                                               "SHA256withECDSA",
                                               specEEKp.getPublic(),
                                               KeyPurposeId.id_kp_timeStamping);
        return new X509KeyCertPair(specEEKp, specEECert);
    }

属性证书

    public static X509AttributeCertificateHolder createAttributeCertificate(
            X509CertificateHolder issuerCert, PrivateKey issuerKey, String sigAlg,
            X509CertificateHolder holderCert, String holderRoleUri)
            throws OperatorCreationException
    {
        X509v2AttributeCertificateBuilder acBldr =
                new X509v2AttributeCertificateBuilder(
                      new AttributeCertificateHolder(holderCert),
                      new AttributeCertificateIssuer(issuerCert.getSubject()),
                      calculateSerialNumber(),
                      calculateDate(0),
                      calculateDate(24 * 7));

        GeneralName roleName = new GeneralName(
                         GeneralName.uniformResourceIdentifier, holderRoleUri);

        acBldr.addAttribute(
                 X509AttributeIdentifiers.id_at_role, new RoleSyntax(roleName));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                .setProvider("BC").build(issuerKey);
        
        return acBldr.build(signer);
    }

调用示例

    public static X509AttributeCertificateHolder createAttrCertSample(PrivateKey issuerSigningKey,  X509CertificateHolder issuerCert, X509CertificateHolder holderCert)
            throws OperatorCreationException
    {
        X509AttributeCertificateHolder attrCert =
                createAttributeCertificate(issuerCert,
                        issuerSigningKey,
                        "SHA256withECDSA", holderCert, "id://DAU123456789");
        return attrCert;
    }

附录(完整代码)

package chapter8;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.cert.*;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v1CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

/**
 * Example methods showing generation and verification of X.509 certificates
 */
public class JcaX509Certificate
{
    /**
     * Calculate a date in seconds (suitable for the PKIX profile - RFC 5280)
     *
     * @param hoursInFuture hours ahead of now, may be negative.
     * @return a Date set to now + (hoursInFuture * 60 * 60) seconds
     */
    public static Date calculateDate(int hoursInFuture)
    {
         long secs = System.currentTimeMillis() / 1000;

         return new Date((secs + (hoursInFuture * 60 * 60)) * 1000);
    }
    private static long serialNumberBase = System.currentTimeMillis();

    /**
     * Calculate a serial number using a monotonically increasing value.
     *
     * @return a BigInteger representing the next serial number in the sequence.
     */
    public static synchronized BigInteger calculateSerialNumber()
    {
        return BigInteger.valueOf(serialNumberBase++);
    }

    /**
     * Simple method to convert an X509CertificateHolder to an X509Certificate
     * using the java.security.cert.CertificateFactory class.
     */
    public static X509Certificate convertX509CertificateHolder(
                                             X509CertificateHolder certHolder)
            throws GeneralSecurityException, IOException
    {
        CertificateFactory cFact = CertificateFactory.getInstance("X.509", "BC");

        return (X509Certificate)cFact.generateCertificate(
                                           new ByteArrayInputStream(
                                                   certHolder.getEncoded()));
    }

    /**
     * Convert an X500Name to use the IETF style.
     */
    public static X500Name toIETFName(X500Name name)
    {
        return X500Name.getInstance(RFC4519Style.INSTANCE, name);
    }

    public static X509KeyCertPair createTrustCert()
            throws GeneralSecurityException, OperatorCreationException
    {
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair trustKp = kpGen.generateKeyPair();

        X509CertificateHolder trustCert =
                                  createTrustAnchor(trustKp, "SHA256withECDSA");
        return new X509KeyCertPair(trustKp, trustCert);
    }

    /**
     * Build a sample self-signed V1 certificate to use as a trust anchor, or
     * root certificate.
     *
     * @param keyPair the key pair to use for signing and providing the
     *                public key.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @return an X509CertificateHolder containing the V1 certificate.
     */
    public static X509CertificateHolder createTrustAnchor(
            KeyPair keyPair, String sigAlg)
            throws OperatorCreationException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo Root Certificate");

        X500Name name = x500NameBld.build();

        X509v1CertificateBuilder certBldr = new JcaX509v1CertificateBuilder(
                                                    name,
                                                    calculateSerialNumber(),
                                                    calculateDate(0),
                                                    calculateDate(24 * 31),
                                                    name,
                                                    keyPair.getPublic());

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                                .setProvider("BC").build(keyPair.getPrivate());

        return certBldr.build(signer);
    }

    public static X509KeyCertPair createInterCert(X509KeyCertPair trustPair)
            throws GeneralSecurityException, OperatorCreationException, CertIOException
    {
        PrivateKey trustAnchorKey = trustPair.getKeyPair().getPrivate();
        X509CertificateHolder trustCert = trustPair.getCert();

        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair caKp = kpGen.generateKeyPair();

        X509CertificateHolder caCert =
                createIntermediateCertificate(trustCert,
                        trustAnchorKey,
                        "SHA256withECDSA", caKp.getPublic(), 0);
        return new X509KeyCertPair(caKp, caCert);
    }

    /**
     * Build a sample V3 intermediate certificate that can be used as a CA
     * certificate.
     *
     * @param signerCert certificate carrying the public key that will later
     *                   be used to verify this certificate's signature.
     * @param signerKey private key used to generate the signature in the
     *                  certificate.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @param certKey public key to be installed in the certificate.
     * @param followingCACerts
     * @return an X509CertificateHolder containing the V3 certificate.
     */
    public static X509CertificateHolder createIntermediateCertificate(
            X509CertificateHolder signerCert, PrivateKey signerKey,
            String sigAlg, PublicKey certKey, int followingCACerts)
            throws CertIOException, GeneralSecurityException,
                   OperatorCreationException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo Intermediate Certificate");

        X500Name subject = x500NameBld.build();

        X509v3CertificateBuilder certBldr = new JcaX509v3CertificateBuilder(
                signerCert.getSubject(),
                calculateSerialNumber(),
                calculateDate(0),
                calculateDate(24 * 31),
                subject,
                certKey);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

        certBldr.addExtension(Extension.authorityKeyIdentifier,
                false, extUtils.createAuthorityKeyIdentifier(signerCert))
                .addExtension(Extension.subjectKeyIdentifier,
                        false, extUtils.createSubjectKeyIdentifier(certKey))
                .addExtension(Extension.basicConstraints,
                        true, new BasicConstraints(followingCACerts))
                .addExtension(Extension.keyUsage,
                        true, new KeyUsage(
                                              KeyUsage.digitalSignature
                                            | KeyUsage.keyCertSign
                                            | KeyUsage.cRLSign));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                .setProvider("BC").build(signerKey);

        return certBldr.build(signer);
    }

    public static X509KeyCertPair createEECert(X509KeyCertPair caPair)
            throws GeneralSecurityException, OperatorCreationException, CertIOException
    {
        PrivateKey caPrivKey = caPair.getKeyPair().getPrivate();
        X509CertificateHolder caCert = caPair.getCert();

        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair eeKp = kpGen.generateKeyPair();

        X509CertificateHolder eeCert =
                createEndEntity(caCert, caPrivKey, "SHA256withECDSA", eeKp.getPublic());

        return new X509KeyCertPair(eeKp, eeCert);
    }

    /**
     * Create a general end-entity certificate for use in verifying digital
     * signatures.
     * 
     * @param signerCert certificate carrying the public key that will later
     *                   be used to verify this certificate's signature.
     * @param signerKey private key used to generate the signature in the
     *                  certificate.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @param certKey public key to be installed in the certificate.
     * @return an X509CertificateHolder containing the V3 certificate.
     */
    public static X509CertificateHolder createEndEntity(
            X509CertificateHolder signerCert, PrivateKey signerKey,
            String sigAlg, PublicKey certKey)
            throws CertIOException, GeneralSecurityException,
                   OperatorCreationException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo End-Entity Certificate");

        X500Name subject = x500NameBld.build();

        X509v3CertificateBuilder   certBldr = new JcaX509v3CertificateBuilder(
                signerCert.getSubject(),
                calculateSerialNumber(),
                calculateDate(0),
                calculateDate(24 * 31),
                subject,
                certKey);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

        certBldr.addExtension(Extension.authorityKeyIdentifier,
                false, extUtils.createAuthorityKeyIdentifier(signerCert))
                .addExtension(Extension.subjectKeyIdentifier,
                        false, extUtils.createSubjectKeyIdentifier(certKey))
                .addExtension(Extension.basicConstraints,
                        true, new BasicConstraints(false))
                .addExtension(Extension.keyUsage,
                        true, new KeyUsage(KeyUsage.digitalSignature));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                                       .setProvider("BC").build(signerKey);

        return certBldr.build(signer);
    }

    public static X509KeyCertPair createEESpecCert(X509KeyCertPair caPair)
            throws GeneralSecurityException, OperatorCreationException, CertIOException
    {
        PrivateKey caPrivKey = caPair.getKeyPair().getPrivate();
        X509CertificateHolder caCert = caPair.getCert();

        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
        KeyPair specEEKp = kpGen.generateKeyPair();

        X509CertificateHolder specEECert =
                createSpecialPurposeEndEntity(caCert, caPrivKey,
                                               "SHA256withECDSA",
                                               specEEKp.getPublic(),
                                               KeyPurposeId.id_kp_timeStamping);
        return new X509KeyCertPair(specEEKp, specEECert);
    }

    /**
     * Create a special purpose end entity cert which is associated with a
     * particular key purpose.
     * 
     * @param signerCert certificate carrying the public key that will later
     *                   be used to verify this certificate's signature.
     * @param signerKey private key used to generate the signature in the
     *                  certificate.
     * @param sigAlg the signature algorithm to sign the certificate with.
     * @param certKey public key to be installed in the certificate.
     * @param keyPurpose the specific KeyPurposeId to associate with this
     *                   certificate's public key.
     * @return an X509CertificateHolder containing the V3 certificate.
     */
    public static X509CertificateHolder createSpecialPurposeEndEntity(
            X509CertificateHolder signerCert, PrivateKey signerKey,
            String sigAlg, PublicKey certKey, KeyPurposeId keyPurpose)
            throws OperatorCreationException, CertIOException,
                   GeneralSecurityException
    {
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.C, "AU")
                .addRDN(BCStyle.ST, "Victoria")
                .addRDN(BCStyle.L, "Melbourne")
                .addRDN(BCStyle.O, "The Legion of the Bouncy Castle")
                .addRDN(BCStyle.CN, "Demo End-Entity Certificate");

        X500Name subject = x500NameBld.build();

        X509v3CertificateBuilder   certBldr = new JcaX509v3CertificateBuilder(
                signerCert.getSubject(),
                calculateSerialNumber(),
                calculateDate(0),
                calculateDate(24 * 31),
                subject,
                certKey);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

        certBldr.addExtension(Extension.authorityKeyIdentifier,
                false, extUtils.createAuthorityKeyIdentifier(signerCert))
                .addExtension(Extension.subjectKeyIdentifier,
                        false, extUtils.createSubjectKeyIdentifier(certKey))
                .addExtension(Extension.basicConstraints,
                        true, new BasicConstraints(false))
                .addExtension(Extension.extendedKeyUsage,
                              true, new ExtendedKeyUsage(keyPurpose));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                                       .setProvider("BC").build(signerKey);

        return certBldr.build(signer);
    }
    /**
     * Extract the DER encoded value octets of an extension from a JCA
     * X509Certificate.
     *
     * @param cert the certificate of interest.
     * @param extensionOID the OID associated with the extension of interest.
     * @return the DER encoding inside the extension, null if extension missing.
     */
    public static byte[] extractExtensionValue(
            X509Certificate cert,
            ASN1ObjectIdentifier extensionOID)
    {
        byte[] octString = cert.getExtensionValue(extensionOID.getId());

        if (octString == null)
        {
            return null;
        }

        return ASN1OctetString.getInstance(octString).getOctets();
    }

    public static X509AttributeCertificateHolder createAttrCertSample(PrivateKey issuerSigningKey,  X509CertificateHolder issuerCert, X509CertificateHolder holderCert)
            throws OperatorCreationException
    {
        X509AttributeCertificateHolder attrCert =
                createAttributeCertificate(issuerCert,
                        issuerSigningKey,
                        "SHA256withECDSA", holderCert, "id://DAU123456789");
        return attrCert;
    }

    public static X509AttributeCertificateHolder createAttributeCertificate(
            X509CertificateHolder issuerCert, PrivateKey issuerKey, String sigAlg,
            X509CertificateHolder holderCert, String holderRoleUri)
            throws OperatorCreationException
    {
        X509v2AttributeCertificateBuilder acBldr =
                new X509v2AttributeCertificateBuilder(
                      new AttributeCertificateHolder(holderCert),
                      new AttributeCertificateIssuer(issuerCert.getSubject()),
                      calculateSerialNumber(),
                      calculateDate(0),
                      calculateDate(24 * 7));

        GeneralName roleName = new GeneralName(
                         GeneralName.uniformResourceIdentifier, holderRoleUri);

        acBldr.addAttribute(
                 X509AttributeIdentifiers.id_at_role, new RoleSyntax(roleName));

        ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
                .setProvider("BC").build(issuerKey);
        
        return acBldr.build(signer);
    }
}

相关文章:

  • 【计算机网络】考研复试高频知识点总结
  • Android Studio 安装2022版稳定版 2022.3.1 详细操作(带图展示)
  • 机器学习算法——分类任务
  • 【网络安全 | 漏洞挖掘】分享21个基础漏洞案例
  • 两台Win电脑局域网ssh免密登录
  • 【股票数据API接口49】如何获取股票历史交易数据之Python、Java等多种主流语言实例代码演示通过股票数据接口获取数据
  • Spring事务
  • 如何停止Oracle expdp/impdp job
  • unity pico开发二:连接头盔,配置手柄按键事件
  • MySQL快速搭建主从复制
  • springboot gradle 多项目创建
  • 《鸢尾花数学大系:从加减乘除到机器学习》开源资源
  • 【Mybatis】如何简单使用mybatis-plus,以及MybatisGenerator自动生成或者实现SQL语句
  • 【二.提示词工程与实战应用篇】【3.Prompt调优:让AI更懂你的需求】
  • 布置云服务器mysql注意事项:Your password does not satisfy the current policy requirements
  • DeepSeek集成到VScode工具,让编程更高效
  • 神经网络 - 激活函数(Swish函数、GELU函数)
  • 【C语言初阶】操作符_作业详解的一些疑问
  • 浏览器自定义区域截图 js-vue
  • Leetcode 189: 轮转数组
  • 网站开发人员结构/武汉seo软件
  • 域名备案期间 网站访问/做个公司网站多少钱
  • 广西送变电建设公司铁塔厂网站/关键词权重查询
  • 南宁制作网站/seo是指搜索引擎营销
  • seo网站诊断报告/关键词歌词打印
  • 惠州网站建设如何/企业网站seo案例