文章目录
Before Start
X.509数字证书请参考:
中文版的简要介绍可以参考这篇文章 Agzs . X509证书–ANS1结构
如果还未能生成SM2密钥对请先阅读
Build with Maven
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.60</version>
</dependency>
QuickStart
/**
* BouncyCastle算法提供者
*/
private static final Provider BC = new BouncyCastleProvider();
生成自签名公私钥对
keyPairGenerator
的构造请参考 JAVA SM2 密钥生成 签名验签
// 产生密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
证书签名算法算法提供者
在制作证书时需要使用到签名算法签名证书中部分数据区域,国密类型的数字证书使用的签名算法是SM3withSM2
,这里使用私钥创建算法提供容器。
ContentSigner sigGen = new JcaContentSignerBuilder("SM3withSM2")
.setProvider(BC)
.build(keyPair.getPrivate());
设置证书信息
设置证书的基本数据:使用者信息、颁发者信息、证书序号、证书生效日期、证书失效日期,以及证书扩展属性。
标识信息构造(DN)
上面提到的使用者信息、颁发者信息,使用Distinct Name的方式来描述。
关于DN中的各个字段的含义请参考 IBM Previous Next
Distinguished Names
实际上简单来讲就是,用来确定“实体” 身份/信息 的一系列列键值对组成的字符串。
这里的键是一个ASN1ObjectIdentifier
,实际上Bouncycastle已经为我们把需要的大多键都已经列好了,我们只要使用这个类org.bouncycastle.asn1.x500.style.BCStyle
的静态变量就可以。
private static X500NameBuilder createStdBuilder() {
X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
// 国家代码
builder.addRDN(BCStyle.C, "CN");
// 组织
builder.addRDN(BCStyle.O, "HZNU");
// 省份
builder.addRDN(BCStyle.ST, "Zhejiang");
// 地区
builder.addRDN(BCStyle.L, "Hangzhou");
return builder;
}
然后我们就可以使用X500NameBuilder
的build()
方法构造对应的DN了。
BCStyle 源码请参考,也可以使用与该文件中处于同级目录的RFC4519Style
获取扩展密钥用途构造(可选)
如果需要设置证书的扩展密钥用途,可以使用DERSequence
来构造一个拓展密钥用途的序列。
public static DERSequence extendedKeyUsage() {
// 构造容器对象
ASN1EncodableVector vector = new ASN1EncodableVector();
// 客户端身份认证
vector.add(KeyPurposeId.id_kp_clientAuth);
// 安全电子邮件
vector.add(KeyPurposeId.id_kp_emailProtection);
return new DERSequence(vector);
}
扩展密钥用途的各个OID Bouncycastle 已经为我们提供,请参考KeyPurposeId
证书信息构造
接下来可以使用X509v3CertificateBuilder
来设置证书的基本参数,下面列举基本一些证书参数和扩展参数的设置方式。
// 构造X.509 第3版的证书构建者
X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
// 颁发者信息
createStdBuilder().build()
// 证书序列号
, BigInteger.valueOf(1)
// 证书生效日期
, new Date(System.currentTimeMillis() - 50 * 1000)
// 证书失效日期
, new Date(System.currentTimeMillis() + 50 * 1000)
// 使用者信息(PS:由于是自签证书,所以颁发者和使用者DN都相同)
, createStdBuilder().build()
// 证书公钥
, keyPair.getPublic())
/*
设置证书扩展
证书扩展属性,请根据需求设定,参数请参考 《RFC 5280》
*/
// 设置密钥用法
.addExtension(Extension.keyUsage, false
, new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation))
// 设置扩展密钥用法:客户端身份认证、安全电子邮件
.addExtension(Extension.extendedKeyUsage, false, extendedKeyUsage())
// 基础约束,标识是否是CA证书,这里false标识为实体证书
.addExtension(Extension.basicConstraints, false, new BasicConstraints(false))
// Netscape Cert Type SSL客户端身份认证
.addExtension(MiscObjectIdentifiers.netscapeCertType, false, new NetscapeCertType(NetscapeCertType.sslClient));
更多 Netscape Cert Type 类型请参考:NetscapeCertType
X.509格式证书对象生成
通过使用证书构造好的信息,接下就能够生成x509格式的证书对象
// 将证书构造参数装换为X.509证书对象
X509Certificate certificate = new JcaX509CertificateConverter()
.setProvider(BC)
.getCertificate(certGen.build(sigGen));
保存证书
如果需要永久的保存刚才生成的这份证书,那么我们需要对这个证书进行序列化,常见的证书序列化是将ASN.1编码的证书对象,进行BASE64编码,这样证书更加便于网络传输。
public static void makeCertFile(X509Certificate x509Certificate, Path savePath) throws CertificateEncodingException, IOException {
if (Files.exists(savePath)) {
// 删除已存在文件
Files.deleteIfExists(savePath);
}
// 创建文件
Files.createFile(savePath);
// 获取ASN.1编码的证书字节码
byte[] asn1BinCert = x509Certificate.getEncoded();
// 编码为BASE64 便于传输
byte[] base64EncodedCert = Base64.encode(asn1BinCert);
// 写入文件
Files.write(savePath, base64EncodedCert);
}
给与文件名称,调用保存(常见的DER编码的证书后缀名为.cer
)。
// 保存为证书文件
makeCertFile(certificate, Paths.get("test-cert.cer"));
ASN.1 结构解析工具
通过该工具,输入证书的BASE64编码的字符串,我们能够快速分析证书的结构,以及各种字段。
致谢
在编写代码时参考了下面的例子:
- Java Code Examples . X509v3CertificateBuilder.https://www.programcreek.com/java-api-examples/?api=org.bouncycastle.cert.X509v3CertificateBuilder
- github . bouncycastle . https://github.com/bcgit/bc-java/blob/master/pkix/src/test/jdk1.1/org/bouncycastle/cert/test/CertTest.java
参考列表:
- RFC5280 . Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile . https://tools.ietf.org/html/rfc5280)
- Agzs . X509证书–ANS1结构 . https://blog.csdn.net/code_segment/article/details/77163652
- IBM . Previous Next
Distinguished Names . https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.sec.doc/q009860_.htm