package com.qianwen.license.keystore; import java.io.FileWriter; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.Objects; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemWriter; import cn.hutool.core.io.FileUtil; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; public class CertificateUtils { /** * 生成密钥对及证书 * @param certificateInfo 证书信息 * @param caPrivateKey 根证书私钥,用于给证书签名 * @return * @throws Throwable */ public static KeyAndCertificate generateCertificate(CertificateInfo certificateInfo, PrivateKey caPrivateKey) throws Throwable { // 生成证书所需密钥对,RSA 算法,密钥长度 2048 字节 // KeyPair keyPair_old = KeyUtil.generateKeyPair(certificateInfo.getKeyAlgorithm(), 2048); //下面3行自己的 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(certificateInfo.getKeyAlgorithm()); //keyGen.initialize(2048); keyGen.initialize(1024); KeyPair keyPair = keyGen.genKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); //证书颁发者信息 X500Name issuer = certificateInfo.getIssuer(); //证书主题信息 X500Name subject = certificateInfo.getSubject(); SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); X509v3CertificateBuilder x509v3CertificateBuilder = new X509v3CertificateBuilder( issuer, certificateInfo.getSerial(), certificateInfo.getNotBefore(), certificateInfo.getNotAfter(), subject, subjectPublicKeyInfo ); JcaContentSignerBuilder jcaContentSignerBuilder = new JcaContentSignerBuilder(certificateInfo.getSignAlgorithm()); //如果没有根证书私钥,自己给自己签名,在生成根证书时会有这种情况 if(Objects.isNull(caPrivateKey)) { caPrivateKey = privateKey; } //签名者 ContentSigner contentSigner = jcaContentSignerBuilder.build(caPrivateKey); //生成证书 X509CertificateHolder x509CertificateHolder = x509v3CertificateBuilder.build(contentSigner); //X509CertificateHolder 转 X509Certificate JcaX509CertificateConverter jcaX509CertificateConverter = new JcaX509CertificateConverter(); //转换成 X509Certificate 证书对象 X509Certificate x509Certificate = jcaX509CertificateConverter.getCertificate(x509CertificateHolder); return new KeyAndCertificate(privateKey, publicKey, x509Certificate); } /** * 保存私钥到磁盘 * @param privateKey * @param filePath * @throws Throwable */ public static void save(PrivateKey privateKey, String filePath) throws Throwable { save(privateKey.getEncoded(), X509CertificateConstants.PRIVATE_KEY_TYPE, filePath); } /** * 保存公钥到磁盘 * @param publicKey * @param filePath * @throws Throwable */ public static void save(PublicKey publicKey, String filePath) throws Throwable { save(publicKey.getEncoded(), X509CertificateConstants.PUBLIC_KEY_TYPE, filePath); } /** * 保存证书到磁盘 * @param certificate * @param filePath * @throws Throwable */ public static void save(Certificate certificate, String filePath) throws Throwable { save(certificate.getEncoded(), X509CertificateConstants.CERTIFICATE_TYPE, filePath); } /** * 以 PEM 格式保存密钥、证书到磁盘 * @param encodedBytes * @param type * @param filePath * @throws Throwable */ public static void save(byte[] encodedBytes, String type, String filePath) throws Throwable { FileUtil.mkParentDirs(filePath); PemObject pemObject = new PemObject(type, encodedBytes); try(FileWriter fileWriter = new FileWriter(filePath); PemWriter pemWriter = new PemWriter(fileWriter)) { pemWriter.writeObject(pemObject); } } }