如何在Java Sun HttpsServer中使用LetsEncrypt证书?

时间:2016-11-12 22:08:06

标签: java ssl certificate

使用大量谷歌搜索的各种结果我设法创建一个Java类来处理从LetsEncrypt下载证书,非常整洁。 (如果有人有兴趣,可用here

我将此内容作为输出在文件夹中获取:

chain.crt
domain.crt
domain.csr
domain.key
user.key

我一直在使用带有自签名证书的com.sun.net.httpserver.HttpsServer,我按照一些指南来生成,这给了我一个.jks文件,到目前为止使用测试客户端一直很好用。但是现在我需要浏览器接受证书而不会出现验证错误,所以我想在这个HttpsServer中使用从LetsEncrypt下载的证书,但我不知道如何去做。我在谷歌上搜索了一下,但我没有发现任何对我有用的东西,虽然我不得不承认我并不真正理解我在这里做的大部分事情,我甚至不知道哪一个上面的5个文件我应该尝试使用。

我当前的代码使用现有生成的.jks文件设置我的HttpsServer :(也可用here

  public void initHttpsServer(int port, String certificateFilePath, String sslPassword)
  {
    try
    {
      this.server = HttpsServer.create(new InetSocketAddress(port), 0);
      SSLContext sslContext = SSLContext.getInstance("TLS");
      char[] password = sslPassword.toCharArray();
      KeyStore ks = KeyStore.getInstance("JKS");
      FileInputStream fis = new FileInputStream(certificateFilePath);
      ks.load(fis, password);
      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
      kmf.init(ks, password);
      TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
      tmf.init(ks);
      sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
      this.server.setHttpsConfigurator(new HttpsConfigurator(sslContext)
      {
        @Override
        public void configure(HttpsParameters params)
        {
          try
          {
            SSLContext c = SSLContext.getDefault();
            SSLEngine engine = c.createSSLEngine();
            params.setNeedClientAuth(false);
            params.setCipherSuites(engine.getEnabledCipherSuites());
            params.setProtocols(engine.getEnabledProtocols());
            SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
            params.setSSLParameters(defaultSSLParameters);
          }

在寻找解决方案时,我遇到了一些答案,其中包括从cmd运行命令以生成不同类型的文件。我需要所有这些在运行时工作,所以首选方式以编程方式。

另外我有一个相关的问题,当旧的LetsEncrypt证书到期并且我已经下载了新证书时,我是否可以更新正在运行的HttpsServer实例以使用新下载的证书,或者我是否必须重新启动服务器?

非常感谢任何帮助,以确定如何使这项工作。

1 个答案:

答案 0 :(得分:0)

除此之外:调用此JKS文件'certificateFile'具有误导性;一个JKS(或像PKCS12这样的其他密钥库)通常包含几个证书,但通常也包括这个案例,并且通常包括私钥。

通常较难的部分是读取密钥文件,因为您使用的是acme4j,它会为您处理。由于缺乏基础设施而未进行测试,但执行的操作如下:

KeyPair kp = KeyPairUtils.readKeyPair (new FileReader ("domain.key"));
// add error handling and close much like your getOrCreateKeyPair 
CertificateFactory cf = CertificateFactory.getInstance ("X.509");
Certificate cert0 = cf.generateCertificate (new FileInputStream ("domain.crt"));
Certificate cert1 = cf.generateCertificate (new FileInputStream ("chain.crt"));
// add similar error handling and close

KeyStore ks = KeyStore.getInstance ("jks"); // type doesn't really matter since it's in memory only
ks.load (null); 
ks.setKeyEntry ("anyalias", kp.getPrivate(), password, new Certificate[]{cert0,cert1});

// now create a KMF and KeyManager from this KeyStore,
// optionally a TMF and TrustManager, then SSLContext etc as in your existing code

我不知道Sun HttpsServer是否可以在运行时更改KeyManager数据;如果我以后有时间,我会试着看一下。但显然你需要在改变它之前开始它是一个问题: - )