使用 Bouncy Castle 签署 CSR

1、概览

签署(也叫做签发)证书签名请求(CSR)是密码学中的一项常见操作。本文将带你了解如何使用 Bouncy Castle 签署 CSR。

2、签署 CSR

签署 CSR 是证书颁发机构(CA)验证 CSR 中的信息并颁发证书的过程。CA 使用其私钥签署证书。签名后的证书可在客户端和服务器之间建立安全连接。

要使用 Bouncy Castle 签署 CSR,需要执行几个基本步骤:

  1. 生成可信实体 CA 证书和私钥。
  2. 生成证书签名请求(CSR)。
  3. 使用 CA 证书和私钥签署 CSR。

3、设置

首先,需要在 pom.xml 中添加 Bouncy Castle 依赖:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk18on</artifactId>
    <version>1.76</version>
</dependency>

接下来,需要创建一个 SecurityProvider 类来注册 Bouncy Castle Provider:

static {
    Security.addProvider(new BouncyCastleProvider());
}

4、使用 Bouncy Castle 签署 CSR

使用 Bouncy Castle 签署 CSR 需要几个步骤。

4.1、生成可信实体 CA 证书和私钥

CA 是向客户签发证书的可信实体。我们必须生成 CA 证书和私钥来签署 CSR。

先生成一个密钥对:

public static KeyPair generateRSAKeyPair() {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048);
    return keyPairGenerator.generateKeyPair();
}

4.2、生成证书签署请求

根据密钥对创建证书签名请求(CSR):

public static PKCS10CertificationRequest generateCSR(KeyPair pair) {
    PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
      new X500Principal("CN=Requested Test Certificate"), pair.getPublic());
    JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
    ContentSigner signer = csBuilder.build(pair.getPrivate());
    return p10Builder.build(signer);
}

4.3、签署证书签名请求(CSR)

接下来,创建一个证书生成器,使用 CA 证书和私钥签署 CSR。

签署 CSR:

public X509Certificate sign(PKCS10CertificationRequest inputCSR, PrivateKey caPrivate, KeyPair pair) {
    AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
    AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);

    AsymmetricKeyParameter foo = PrivateKeyFactory.createKey(caPrivate.getEncoded());
    SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded());

    X509v3CertificateBuilder myCertificateGenerator = new X509v3CertificateBuilder(
      new X500Name("CN=issuer"), 
      new BigInteger("1"), 
      new Date(System.currentTimeMillis()), 
      new Date(System.currentTimeMillis() + 30L * 365 * 24 * 60 * 60 * 1000), 
      inputCSR.getSubject(), 
      keyInfo);

    ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(foo);

    X509CertificateHolder holder = myCertificateGenerator.build(sigGen);
    Certificate eeX509CertificateStructure = holder.toASN1Structure();

    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");

    InputStream is1 = new ByteArrayInputStream(eeX509CertificateStructure.getEncoded());
    X509Certificate theCert = (X509Certificate) cf.generateCertificate(is1);
    is1.close();
    return theCert;
}

该方法首先要确定用于签署证书的签名和摘要算法。我们使用 DefaultSignatureAlgorithmIdentifierFinderDefaultDigestAlgorithmIdentifierFinder 类查找这些算法。

AsymmetricKeyParameter 用于从编码后的字节数组中创建 CA 的私钥。

我们使用 PrivateKeyFactory 类从编码后的字节数组中创建私钥。SubjectPublicKeyInfo 用于指定公钥信息。

接下来,创建证书生成器。它为证书设置签发人(issuer)、序列号(serial number)、有效期(validity period)、主题(subject)和公钥(public key)。

然后,使用签名和摘要算法以及 CA 的私钥创建 ContentSigner,用于签署证书。

最后,该方法会生成证书,并将其转换为 X509Certificate 后返回。

5、测试

编写一个测试来验证签名过程:

@Test
public void givenCSR_whenSignWithBC_thenSuccess() {
    SignCSRBouncyCastle signCSRBouncyCastle = new SignCSRBouncyCastle();
    KeyPair pair = SignCSRBouncyCastle.generateRSAKeyPair();
    PKCS10CertificationRequest csr = SignCSRBouncyCastle.generateCSR(pair);
    KeyPair caPair = SignCSRBouncyCastle.generateRSAKeyPair();
    X509Certificate signedCert = signCSRBouncyCastle.signCSR(csr, caPair.getPrivate(), pair);

    assertThat(signedCert).isNotNull();
    assertThat(signedCert.getSubjectDN().getName()).isEqualTo("CN=Requested Test Certificate");
    assertDoesNotThrow(() -> signedCert.verify(caPair.getPublic()));
}

如上,我们生成一对密钥并创建 CSR。然后,生成 CA 密钥对,并使用 CA 私钥签署 CSR。最后,使用 CA 公钥验证已签署的证书。

6、总结

本文介绍了如何使用 Bouncy Castle 库签署 CSR。

我们首先生成了密钥对,创建了 CSR,然后生成了 CA 密钥对,并使用 CA 证书签署了 CSR。最后还编写了一个测试来验证签名过程。


Ref:https://www.baeldung.com/java-bouncy-castle-sign-csr