JAVA8 通过根证书及私钥生成子证书。

最近需要添加EMQX的双向认证。通过服务器生成根证书的子证书及私钥发送给设备。

 话不多说。直接上DEMO


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
import lombok.SneakyThrows;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import sun.misc.BASE64Decoder;

/**
 * @author TanJ
 * @date 2021/11/16 17:20
 */
public class X509 {

//私钥
 private static final String PRIVATE_KEY_S = "-----BEGIN RSA PRIVATE KEY-----\n";
 private static final String PRIVATE_KEY_E = "\n-----END RSA PRIVATE KEY-----";
 //证书
 private static final String CERTIFICATE_S = "-----BEGIN CERTIFICATE-----\n";
 private static final String CERTIFICATE_E = "\n-----END CERTIFICATE-----";



  static{
    try{
      Security.addProvider(new BouncyCastleProvider());
    }catch(Exception e){
      e.printStackTrace();
    }
  }


  /**
   * 加载私钥
   * @param privateKey
   * @return
   * @throws Exception
   */
  public static PrivateKey getPrivateKey(String privateKey) throws Exception {
    // 解码由base64编码的私钥
    BASE64Decoder base64Decoder= new BASE64Decoder();
    byte[] keyBytes = base64Decoder.decodeBuffer(privateKey);

    PKCS8EncodedKeySpec keySpec= new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory= KeyFactory.getInstance("RSA");
    return keyFactory.generatePrivate(keySpec);
  }

  @SneakyThrows
  public static void main(String[] args) {
    //加载根证书
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    X509Certificate rootCert = (X509Certificate) cf
        .generateCertificate(new FileInputStream("XXXX/ca.pem"));

    //提取根证书私钥  注意参数需要去除证书中的前缀及后缀!!
    PrivateKey rootPrivateKey = getPrivateKey(
        "MIIEvQIBADANBgkqhkiG9w0s...");

    // 生成client私钥
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    keyPairGen.initialize(2048);

    KeyPair keyPair =  keyPairGen.genKeyPair();

    PrivateKey privateKey = keyPair.getPrivate();

    //填充subject信息
    X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE);
    nameBuilder.addRDN(BCStyle.C, "testClient");

    BigInteger serial = new BigInteger(Long.toString(System.currentTimeMillis()));
    org.bouncycastle.asn1.x500.X500Name subjectName  = nameBuilder.build();

// 发行者名称
    final X500Name issuerName;
    if (rootCert == null) {
      // 如果没有根证书,则默认用当前证书
      issuerName = subjectName;
    } else {
      //设置下发证书为根证书信息
      issuerName = new X509CertificateHolder(rootCert.getEncoded()).getSubject();
    }
    //证书过期时间
    Date notBefore = new Date(System.currentTimeMillis());
    Date notAfter = DateUtil.offsetMonth(notBefore,12);
    JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuerName, serial, notBefore, notAfter, subjectName, keyPair.getPublic());

//-----------
    // 添加信息
//    final JcaX509ExtensionUtils u = new JcaX509ExtensionUtils();
//    if (rootCert != null) {
//      // Authority key identifier 2.5.29.35
//      certBuilder.addExtension(Extension.authorityKeyIdentifier, false, //u.createAuthorityKeyIdentifier(rootCert));
//    }
// Subject key identifier 2.5.29.14
//    certBuilder.addExtension(Extension.subjectKeyIdentifier, false,
//        u.createSubjectKeyIdentifier(keyPair.getPublic()));
// Key usage 2.5.29.15
//    if (rootCert == null) {
//      certBuilder.addExtension(Extension.keyUsage, true,
//          new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | //KeyUsage.dataEncipherment
//              | KeyUsage.keyAgreement | KeyUsage.nonRepudiation | KeyUsage.cRLSign
//              | KeyUsage.keyCertSign));
//    }
// Basic Constraints 2.5.29.19
//    certBuilder.addExtension(Extension.basicConstraints, false, new //BasicConstraints(rootCert == null));
// Extended key usage 2.5.29.37
//    certBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(
//        new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth, //KeyPurposeId.id_kp_serverAuth }));
// CRL distribution points 2.5.29.31
//    String SERVER_BASE_REST_PKI_URL = "123";
//    String CRL_URL = "456";
//    DistributionPointName distributionPoint = new DistributionPointName(new //GeneralNames(new GeneralName(
//        GeneralName.uniformResourceIdentifier, SERVER_BASE_REST_PKI_URL + issuerName + //CRL_URL)));
//    DistributionPoint[] distPoints = new DistributionPoint[1];
//    distPoints[0] = new DistributionPoint(distributionPoint, null, null);
//    certBuilder.addExtension(Extension.cRLDistributionPoints, false, new //CRLDistPoint(distPoints));
    //----


    //设置使用根证书私钥进行签名。算法使用根证书相同算法
    ContentSigner signer = new JcaContentSignerBuilder(  rootCert.getSigAlgName()).build(rootPrivateKey);
    X509CertificateHolder certHolder = certBuilder.build(signer);
    X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certHolder);
    //拼接证书格式
    String privateKeyStr =
        PRIVATE_KEY_S + new String(Base64.getEncoder().encode(privateKey.getEncoded()))
            + PRIVATE_KEY_E;

    String certificateStr =
        CERTIFICATE_S + new String(  Base64.getEncoder().encode((certificate.getEncoded())))
            + CERTIFICATE_E;

    //以下自行发挥
    //TODO
    IoUtil.write(new FileOutputStream(".../client.key"), true,
        privateKeyStr.getBytes(StandardCharsets.UTF_8));

    IoUtil.write(new FileOutputStream(".../client.pem"), true,
        certificateStr.getBytes(StandardCharsets.UTF_8));


  }
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值