通过 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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
最简单的方法,直接用java里的keytool工具生成一个keystore文件,然后直接用这个文件启用https就可以了。 方法如下: 命令行执行%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA 执行过程中会询问你一些信息,比如国家代码,省市等,其中需要填写两个密码,一次在开头,一次在最后,请保持两个密码相同。比如,我将密码都设成s3cret。 如果不同,启动会报错,大概是下面这样的 java.io.IOException: Cannot recover key 执行完成后会生成一个.keystore文件,将它复制到tomcat的bin目录下(并不一定,放哪里都可以) 打开conf目录下的server.xml文件,找到以下这一段 它被注释掉了,将注释去掉,并将这一段改成以下 maxThreads="150" scheme="https" secure="true" keystoreFile="bin/.keystore" keystorePass=" s3cret" clientAuth="false" sslProtocol="TLS" /> 之后启动tomcat就可以了,通过https方式访问8443端口,就能看到效果。如果用http访问之前的端口,那么还是普通的未加密连接。 到这里问题来了,我的目的是启用https,但现在http还能访问,那么就可以绕开https。https也就起不了什么作用了。因此要强制访问https。 打开你的web应用的web.xml文件,在最后加上这样一段 Protected Context /* CONFIDENTIAL 重启tomcat,现在你放问原来的地址,假设是http://localhost:8080/mywebapp/,可以看到,连接被重定向到了https的连接 https://localhost:8443/mywebapp/。这样,我们的目的达到了。 但似乎还有点小问题,keystorePass="s3cret",这个密码直接被明码方式卸载server.xml里。总觉得有还是有点不爽。 那么还有一种稍微复杂点的方式,我们使用openssl。 首先,需要下载openssl,为了方便,可以下载一个绿色版, 加压后除了openssl.exe以外,还有一个bat文件,这个可以帮助我们快速创建证书申请文件。 运行autocsr.bat,按照提示输入信息,之后按任意键确认。你会得到两个文件,一个server.key,这是私钥文件,还有一个名为certreq.csr证书请求文件。 如果你要向证书颁发机构申请正式的安全证书,那么就把这个certreq.csr文件发给他们就行了。他们会给你发来两个cer文件,一个是服务器证书,一个是根证书 如果你只是要使用https,那么证书自己签署就可以了。 在命令行下进入刚才解压的目录,找到openssl.exe所在的目录,执行以下命令 openssl x509 -req -in certreq.csr -out cert.cer -signkey server.key -days 3650 现在你将得到一个名为cert.cer的证书文件。 修改server.xml将 maxThreads="150" scheme="https" secure="true" keystoreFile="bin/.keystore" keystorePass=" s3cret" clientAuth="false" sslProtocol="TLS" /> 修改为以下内容(假设cert.cer和server.key文件都放在tomcat的conf目录下) maxThreads="150" scheme="https" secure="true" SSLCertificateFile="conf/cert.cer" SSLCertificateKeyFile="conf/server.key" sslProtocol="TLS" /> PS.如果真的向证书颁发机构申请到了正式的安全证书,那么配置还有点不同,如下 maxThreads="150" scheme="https" secure="true" SSLCertificateFile="conf/server.cer" SSLCertificateKeyFile="conf/server.key" SSLCertificateChainFile="conf/intermediate.cer" sslProtocol="TLS" /> 因为证书颁发机构会给两个整数,一个是签署后的服务器证书,还有一个中级CA证书,所以要多一行配置。 可能证书颁发机构只会给你服务器证书也就是server.cer, 中级的CA证书即 intermediate.cer 需要到 证书颁发机构提供的网站中去下载,具体的操作会为证书颁发机构给发的邮箱中会有相关的提示 好了,到这里都配置完了,重启tomcat,就可以看到效果。不过,看到的通常会是一个exception,大概是说APR not available 如果遇到这个异常,说明你的tomcat没有安装apr支持 apr安装详见:http://www.blogjava.net/yongboy/archive/2009/08/31/293343.html 之后启动tomcat,问题应该解决了,看起来效果和第一种方式没什么不同。
生成CA证书及其子证书可以使用Java的Keytool工具和Bouncy Castle库结合使用。以下是一个简单的示例: 1. 首先,创建一个密钥库并生成一个RSA密钥对作为CA证书: ``` KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); // 生成2048位RSA密钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); X500Name issuerName = new X500Name("CN=MyCA"); BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis()); X509v3CertificateBuilder caBuilder = new JcaX509v3CertificateBuilder( issuerName, serialNumber, new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000), // 开始时间为昨天 new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000), // 结束时间为一年后 issuerName, keyPair.getPublic() ); ContentSigner caContentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate()); X509Certificate caCertificate = new JcaX509CertificateConverter().getCertificate(caBuilder.build(caContentSigner)); ``` 这将使用Java的KeyPairGenerator类生成一个2048位的RSA密钥对,并使用Bouncy Castle库中的JcaX509v3CertificateBuilder类构建一个X.509证书,作为CA证书。请注意,此示例中的证书有效期为一年,您可以根据需要进行更改。 2. 然后,使用以下代码导出CA证书: ``` KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(null, null); keyStore.setCertificateEntry("myca", caCertificate); FileOutputStream fos = new FileOutputStream("mykeystore.jks"); keyStore.store(fos, "mykeystorepassword".toCharArray()); fos.close(); ``` 这将使用Java的KeyStore类将CA证书保存到一个名为mykeystore.jks的密钥库中,并设置一个密码来保护密钥库。 3. 接下来,使用以下代码创建一个证书签名请求CSR): ``` PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder( new X500Name("CN=MyCert"), keyPair.getPublic() ); ContentSigner csrContentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate()); PKCS10CertificationRequest csr = csrBuilder.build(csrContentSigner); ``` 这将使用Bouncy Castle库中的JcaPKCS10CertificationRequestBuilder类创建一个证书签名请求。 4. 然后,将CSR发送给CA机构,以便他们签署您的证书。在收到签署的证书后,将其保存为mycert.crt文件。 5. 最后,使用以下代码将证书导入到受信任的证书列表中: ``` CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); InputStream certInputStream = new FileInputStream("mycert.crt"); X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(certInputStream); certInputStream.close(); keyStore.setCertificateEntry("mycert", cert); FileOutputStream fos = new FileOutputStream("mykeystore.jks"); keyStore.store(fos, "mykeystorepassword".toCharArray()); fos.close(); ``` 这将使用Java的CertificateFactory类将证书加载到内存中,并使用KeyStore类将证书保存到密钥库中。 请注意,以上示例中的代码可能需要根据您的具体情况进行调整。此外,生成真实的CA证书和其子证书需要更复杂的流程和步骤,您需要深入了解相关知识才能完成。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiangzhihong8

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值