简介
首先简单介绍下什么是数字证书,所谓数字证书,就是互联网通讯中的“身份证”。通常的数字证书是由权威机构CA证书授权中心发行的,能提供在Internet上进行身份验证。数字证书的认证原理基于非对称加密算法。生成证书前首先需要生成一对非对称密钥,将颁发者身份信息、使用者身份信息、公钥、颁发者私钥对基本证书域的签名值以及一些算法标识符oid按照RFC2459所规定的形式组合成符合文档定义的ASN1结构,就完成证书的制作了。但实际的证书生成,标准的流程都是先生成证书请求,这个证书请求中包含自身的身份信息,证书所需公钥,私钥对证书请求信息域的签名值,扩展项信息和一些算法标识oid,证书请求的数据格式定义在RFC2986中,生成证书时通过解析证书请求来获取使用者身份信息和使用者公钥。BouncyCastle是一种用于 Java 平台的开放源码的轻量级密码包,它支持大量的密码算法,同时抽象包装了各种ASN1数据类型以及ASN1结构相关的解析和组装。使用BC包可以很方便的组装生成证书。我使用的JDK版本1.8,BC版本为1.59,BC对于SM2算法的集成于版本1.57,组装国密证书部分的代码需要至少BC1.57的支持,之前版本的sm2签名写法与1.59的略有差异。完整代码在我的Github,希望可以帮助到你。
一. 生成自签发根证书
为了方便,自签发根证书就不走证书请求了,直接使用传入的使用者身份信息(Subject)和生成的密钥对(Keypair)来制作证书。
public static Certificate selfSignedCertGen(X500Name subject, KeyPair keyPair, Date notBefore, Date notAfter) throws Exception{
SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
BcX509ExtensionUtils extUtils = new BcX509ExtensionUtils();
ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
extensionsGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(true)); //ca cert
extensionsGenerator.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign));
extensionsGenerator.addExtension(Extension.subjectKeyIdentifier,false,extUtils.createSubjectKeyIdentifier(subjectPublicKeyInfo));
extensionsGenerator.addExtension(Extension.authorityKeyIdentifier,false,extUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo));
V3TBSCertificateGenerator tbsGen = new V3TBSCertificateGenerator();
tbsGen.setSerialNumber(new ASN1Integer(UUID.randomUUID().getMostSignificantBits()&Long.MAX_VALUE));
tbsGen.setIssuer(subject); //自签证书颁发者等于使用者
tbsGen.setStartDate(new Time(notBefore, Locale.CHINA));
tbsGen.setEndDate(new Time(notAfter,Locale.CHINA));
tbsGen.setSubject(subject);
tbsGen.setSubjectPublicKeyInfo(subjectPublicKeyInfo);
tbsGen.setExtensions(extensionsGenerator.generate());
tbsGen.setSignature(getSignAlgo(subjectPublicKeyInfo.getAlgorithm())); //签名算法标识等于密钥算法标识
TBSCertificate tbs = tbsGen.generateTBSCertificate();
byte[] signature = null;
if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("ECDSA")) {
if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(GMObjectIdentifiers.sm2p256v1)) {
signature = Signers.SM2Sign(tbsCertificate.getEncoded(),issuerPrivateKey);
} else if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(SECObjectIdentifiers.secp256k1)) { //项目中ecdsa签名使用的曲线为secp256k1
signature = Signers.ECDSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
} else
throw new IllegalArgumentException("不支持的曲线");
} else if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("RSA")) {
signature = Signers.RSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
} else
throw new IllegalArgumentException("不支持的密钥算法");
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCertificate);
v.add(getSignAlgo(issuerSubjectPublicKeyInfo.getAlgorithm())); //根据公钥算法标识返回对应签名算法标识
v.add(new DERBitString(signature));
return Certificate.getInstance(new DERSequence(v));
}
二. 生成证书请求
传入使用者身份信息(Subject),使用者公钥,组装证书请求信息对象(CertificateRequestInfo),并使用传入的使用者私钥进行签名,最终生成P10格式的证书请求。
public static PKCS10CertificationRequest generateCSR(X500Name subject, PublicKey publicKey, PrivateKey privateKey) {
try {
SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
CertificationRequestInfo info = new CertificationRequestInfo(subject,subjectPublicKeyInfo,new DERSet());
byte[] signature;
AlgorithmIdentifier signAlgo = getSignAlgo(subjectPublicKeyInfo.getAlgorithm());
if(signAlgo.getAlgorithm().equals(GMObjectIdentifiers.sm2sign_with_sm3)) {
signature = Signers.SM2Sign(info.getEncoded(ASN1Encoding.DER),privateKey);
} else if(signAlgo.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA256)) {
signature = Signers.ECDSASign(info.getEncoded(ASN1Encoding.DER),privateKey);
} else if(signAlgo.getAlgorithm().equals(PKCSObjectIdentifiers.sha256WithRSAEncryption)) {
signature = Signers.RSASign(info.getEncoded(ASN1Encoding.DER),privateKey);
} else
throw new IllegalArgumentException("密钥算法不支持");
return new PKCS10CertificationRequest(new CertificationRequest(info,signAlgo,new DERBitString(signature)));
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("密钥结构错误");
}
}
三. 签发终端实体证书
终端实体证书有别于CA证书,它无法向下签发任何证书,V3的终端实体证书中使用扩展字段(BasicConstraints=false)来区分该证书是不是CA证书。制作终端实体证书需要颁发者证书(必须是CA证书),颁发者证书的私钥。
public static Certificate certGen(PKCS10CertificationRequest csr, PrivateKey issuerPrivateKey, byte[] issuerCert, Date notBefore, Date notAfter) throws Exception {
X509CertificateHolder issuer = new X509CertificateHolder(issuerCert);
if(!verifyCSR(csr))
throw new IllegalArgumentException("证书请求验证失败");
X500Name subject = csr.getSubject();
BcX509ExtensionUtils extUtils = new BcX509ExtensionUtils();
ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
extensionsGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(false)); //entity cert
extensionsGenerator.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature));
extensionsGenerator.addExtension(Extension.authorityKeyIdentifier,false,extUtils.createAuthorityKeyIdentifier(issuer)); //授权密钥标识
extensionsGenerator.addExtension(Extension.subjectKeyIdentifier,false,extUtils.createSubjectKeyIdentifier(csr.getSubjectPublicKeyInfo())); //使用者密钥标识
V3TBSCertificateGenerator tbsGen = new V3TBSCertificateGenerator();
tbsGen.setSerialNumber(new ASN1Integer(UUID.randomUUID().getMostSignificantBits()&Long.MAX_VALUE));
tbsGen.setIssuer(issuer.getSubject());
tbsGen.setStartDate(new Time(notBefore, Locale.CHINA));
tbsGen.setEndDate(new Time(notAfter,Locale.CHINA));
tbsGen.setSubject(subject);
tbsGen.setSubjectPublicKeyInfo(csr.getSubjectPublicKeyInfo());
tbsGen.setExtensions(extensionsGenerator.generate());
tbsGen.setSignature(issuer.getSubjectPublicKeyInfo().getAlgorithm()); //签名算法标识等于颁发者证书的密钥算法标识
TBSCertificate tbs = tbsGen.generateTBSCertificate();
byte[] signature = null;
if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("ECDSA")) {
if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(GMObjectIdentifiers.sm2p256v1)) {
signature = Signers.SM2Sign(tbsCertificate.getEncoded(),issuerPrivateKey);
} else if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(SECObjectIdentifiers.secp256k1)) {
signature = Signers.ECDSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
} else
throw new IllegalArgumentException("不支持的曲线");
} else if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("RSA")) {
signature = Signers.RSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
} else
throw new IllegalArgumentException("不支持的密钥算法");
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCertificate);
v.add(getSignAlgo(issuerSubjectPublicKeyInfo.getAlgorithm()));
v.add(new DERBitString(signature));
return Certificate.getInstance(new DERSequence(v));
}