通过 Java 代码生成请求 CSR证书

概述

在 PKI(Public Key Infrastructure,公开密钥基础建设)体系中,证书签名请求(也称为 CSR 或证书请求)是由客户端提交给 CA(Certificate Authority)用于申请数字证书的信息。其中 PKCS#10 规范是 CSR 中最常见的格式。

比如,张三和李四通过互联网进行信息传输,他们两者都希望接受到的信息就是对方发送的原始内容,没有被任何篡改,且不能被抵赖。要实现这个目的,其中一个方法就是使用 PKI。在 PKI 中,他们双方都需要生成密钥对,即公钥和私钥。公钥顾名思义就是公开的密钥,大家都可以得到,而发送的信息则使用他们各自的私钥进行加密,相应的也只有他们各自的公钥才可以解密信息。

那么在实际中,我们是如何分享公钥呢?我们可以通过一个名为 CA(Certification Authority)的第三方机构实现公钥分享,其中还会涉及到 CA 的从属认证机构 RA(Registration Authority,注册管理中心)。CA 将用户的个人身份和公开密钥链接在一起;RA 则确保公开密钥和个人身份链接正确,防止抵赖。归根结底,CA 的作用就是对我们的公钥进行签名,而 CA 作为数字证书的权威机构,CA 的公钥证书一般都已经内置在了各类客户端软件中,所以客户端可以通过验证签发给我们证书的 CA 机构的合法性来判断我们这本证书的合法性。我们将公钥提交到 CA 的这一过程就叫 CSR。

Java生成CSR

  1. 使用标准加密算法获取KeyPairGenerator的实例,此处使用RSA。
  2. 通过提供密钥大小和随机性来源来初始化实例。
  3. 生成CSR中使用的PrivateKey和PublicKey。
  4. 使用PublicKey初始化PKCS10。
  5. 使用标准算法获取签名实例,此处使用MD5WithRSA。
  6. 使用PrivateKey初始化签名对象。
  7. 通过传递通用名称,组织单位,组织,位置,州和国家/地区来创建X500Name对象。
  8. 使用X500Signer,Signature和X500Name对象对PKCS10对象进行编码和签名。
  9. 将PKCS10对象打印到PrintStream。然后就可以使用了。

示例代码

首先,在项目中加入 BouncyCastly 库,以下是 Maven 依赖配置项:

<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcpkix-jdk18on</artifactId>
  <version>1.72</version>
</dependency>

然后,下面是示例代码:

public class CsrUtils {

  private static final Provider BC = new BouncyCastleProvider();

  /**
   * 生成 PKCS#10 证书请求
   */
  public static String generateCsr(boolean isRsaNotEcc) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, OperatorCreationException, IOException {
    // 使用 RSA/ECC 算法,生成密钥对(公钥、私钥)
    KeyPairGenerator generator = KeyPairGenerator.getInstance(isRsaNotEcc ? "RSA" : "EC", BC);
    if (isRsaNotEcc) {
      // RSA
      generator.initialize(2048);
    } else {
      // ECC
      generator.initialize(new ECGenParameterSpec("sm2p256v1"));
    }
    KeyPair keyPair = generator.generateKeyPair();
    PrivateKey privateKey = keyPair.getPrivate();
    PublicKey publicKey = keyPair.getPublic();

    //打印私钥,注意:请务必保存您的私钥
    printOpensslPemFormatKeyFileContent(privateKey, isRsaNotEcc);

    // 按需添加证书主题项,
    X500Principal subject = new X500Principal("C=CN");

    // 使用私钥和 SHA256WithRSA/SM3withSM2 算法创建签名者对象
    ContentSigner signer = new JcaContentSignerBuilder(isRsaNotEcc ? "SHA256WithRSA" : "SM3withSM2")
      .setProvider(BC)
      .build(privateKey);

    // 创建 CSR
    PKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(subject, publicKey);
    PKCS10CertificationRequest csr = builder.build(signer);

    // 打印 OpenSSL PEM 格式文件字符串
    printOpensslPemFormatCsrFileContent(csr);

    // 以 Base64 字符串形式返回 CSR
    return Base64.getEncoder().encodeToString(csr.getEncoded());
  }

  /**
   * 打印 OpenSSL PEM 格式文件字符串的 SSL证书密钥 KEY 文件内容
   * @param privateKey 私钥
   * @param isRsaNotEcc {@code true}:使用 RSA 加密算法;{@code false}:使用 ECC(SM2)加密算法
   */
  private static void printOpensslPemFormatKeyFileContent(PrivateKey privateKey, boolean isRsaNotEcc) throws IOException {
    PemObject pem = new PemObject(isRsaNotEcc ? "PRIVATE KEY" : "EC PRIVATE KEY", privateKey.getEncoded());
    StringWriter str = new StringWriter();
    PemWriter pemWriter = new PemWriter(str);
    pemWriter.writeObject(pem);
    pemWriter.close();
    str.close();

    System.out.println(str.toString());
  }

  /**
   * 打印 OpenSSL PEM 格式文件字符串的 SSL 证书请求 CSR 文件内容
   * @param csr 证书请求对象
   */
  private static void printOpensslPemFormatCsrFileContent(PKCS10CertificationRequest csr) throws IOException {
    PemObject pem = new PemObject("CERTIFICATE REQUEST", csr.getEncoded());
    StringWriter str = new StringWriter();
    PemWriter pemWriter = new PemWriter(str);
    pemWriter.writeObject(pem);
    pemWriter.close();
    str.close();

    System.out.println(str.toString());
  }
}

其他

除此之外,我们还可以使用Java密钥工具Java Keytool的-genkeypair命令来生成私钥和证书请求文件。

keytool -genkeypair -keyalg RSA -keysize 2048 -keystore keystore.jks -storepass password -validity 365 -alias myalias

你可能感兴趣的:(Java基础与框架,java,python,开发语言)