1. 概述
签署证书签名请求(CSR)是密码学中的常见操作。本教程将介绍如何使用 Bouncy Castle 库完成 CSR 签署。
2. CSR 签署流程
CSR 签署本质是证书颁发机构(CA)验证请求信息后签发证书的过程。 CA 使用其私钥对证书进行签名,生成的证书可用于建立客户端与服务器间的安全连接。
使用 Bouncy Castle 签署 CSR 需要以下核心步骤:
- 生成可信 CA 证书和私钥
- 创建证书签名请求(CSR)
- 使用 CA 证书和私钥签署 CSR
3. 环境准备
首先在项目中添加 Bouncy Castle 依赖(以 Maven 为例):
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.76</version>
</dependency>
然后创建安全提供者注册类:
static {
Security.addProvider(new BouncyCastleProvider());
}
4. 使用 Bouncy Castle 签署 CSR
签署过程包含多个关键步骤,下面逐一解析。
4.1 生成 CA 证书和私钥
CA 作为可信实体负责签发证书。首先生成 CA 密钥对:
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 的核心代码:
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;
}
关键步骤解析:
- ✅ 通过
DefaultSignatureAlgorithmIdentifierFinder
和DefaultDigestAlgorithmIdentifierFinder
确定签名和摘要算法 - ✅ 使用
PrivateKeyFactory
从编码字节创建 CA 私钥 - ✅ 通过
SubjectPublicKeyInfo
指定公钥信息 - ✅ 构建证书生成器,设置颁发者、序列号、有效期、主题和公钥
- ⚠️ 使用签名算法、摘要算法和 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 的全过程:
- 生成 RSA 密钥对
- 创建证书签名请求
- 构建 CA 证书并完成签署
- 通过测试验证签名有效性
实际应用中需注意:
- ⚠️ 生产环境应使用更安全的密钥存储方案
- ✅ 证书有效期应根据实际需求设置
- ❌ 避免在代码中硬编码证书信息