Java 在Jetty中设置运行时的ssl密钥库

Java 在Jetty中设置运行时的ssl密钥库,java,ssl,certificate,jetty,ssl-certificate,Java,Ssl,Certificate,Jetty,Ssl Certificate,是否可以在运行时更改密钥库?目前,我正在先设置SSL,然后再设置服务器。start() 我想做的是在运行时创建一个证书并使用它。基本上,我正在创建一个类似Fiddler的工具,它可以动态创建证书。我不是java安全包方面的专家,但据我所知,没有直接的方法从公共API创建密钥对 但是,如果您允许您的代码从sun的受限软件包进行导入,我是有可能的,例如: import sun.security.x509.*; 下面是您要查找的代码的概要: PrivateKey privkey = pair.get

是否可以在运行时更改密钥库?目前,我正在先设置SSL,然后再设置服务器。start()


我想做的是在运行时创建一个证书并使用它。基本上,我正在创建一个类似Fiddler的工具,它可以动态创建证书。

我不是java安全包方面的专家,但据我所知,没有直接的方法从公共API创建密钥对

但是,如果您允许您的代码从sun的受限软件包进行导入,我是有可能的,例如:

import sun.security.x509.*;
下面是您要查找的代码的概要:

PrivateKey privkey = pair.getPrivate();
X509CertInfo info = new X509CertInfo();
Date from = new Date();
//Validity for next one year
Date to = new Date(from.getTime() + (365) * 86400000l);

CertificateValidity interval = new CertificateValidity(from, to);

BigInteger sn = new BigInteger(64, new SecureRandom());
X500Name owner = new X500Name(dn);

info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

// Sign the cert
X509CertImpl cert = new X509CertImpl(info);
cert.sign(privkey, algorithm);

//cert object is ready to use

希望这有助于创建您自己的
密钥库
实现

您可以创建一个覆盖
密钥库的类,并将其作为Jetty的信任库。然后,您可以自由返回所需的任何
证书


可能您必须使用第三方库动态创建证书,因为Java无法创建证书(使用官方API)。您可以使用BouncyCastle进行此操作。

这里似乎有两个问题:在上动态生成证书(“我想做的是在运行时创建一个证书并使用它”),以及在不重新启动的情况下进行设置(“是否可以在运行时更改密钥库?”)

  • 要动态生成证书,可以使用

    • 首先,生成一个自签名CA(使用CA基本约束集),例如(有关详细信息,请查看
      -ext
      选项)。这将是您的定制CA

    • 从该密钥库导出证书(仅CA证书,而不是其私钥),并将其导入到要使用的客户端

    • 在应用程序中,使用该私钥与
      X509V3CertificateGenerator
      进行签名,并确保使用的颁发者DN与上面生成的CA证书的主题DN匹配

    • 然后,您需要使用与您的客户机要联系的主机名相匹配的主题DN(或主题替代名称)配置生成的证书。如果您打算作为某种透明代理自动执行此操作,那么这可能是一个棘手的问题。(据我所知,当前版本的Java无法读取来自SNI扩展的名称,至少不能提前读取或不进行更多手动处理。) 更简单的方法当然是将此主机名作为工具中的可配置选项

  • 要在不重新启动服务器的情况下进行设置,您可以实现自己的
    X509KeyManager
    ,它保留在您正在使用的
    SSLContext
    中,但保留一个引用和自定义访问器,以便稍后重新配置证书。它当然不一定是“干净”的东西,我也没有试过,但原则上它应该是有效的。(您当然应该确保正确处理并发方面。)

    这可能使您不必关闭侦听套接字,重新配置
    SSLContext
    并重新启动套接字。考虑到您可能需要与应用程序进行交互(以重新配置主机名),这可能有些过分


在Jetty邮件列表中发布此问题后,我得到的答复是,这不太可行

自Jetty 9.4.0以来,此问题已得到修复,请参阅。现在,您可以覆盖密钥/信任库等,并调用
SslContextFactory.reload


但是请注意,TLS会话恢复有一个警告:。根据评论,这不应该是普通浏览器的问题,但谁知道IE、移动、非浏览器客户端等呢。

为什么?谁会相信它?你想清楚了吗?当然有办法创建密钥对。看-1…我如何告诉Jetty在运行时使用特定的密钥库/密钥?@gauravphoenix您不必更改密钥库。只需更改密钥库即可。Jetty会在每次需要密钥时询问您的密钥库,然后您可以自由返回任何您想要的密钥。Jetty不是这样工作的-一旦加载密钥库,Jetty就不会重新加载对其所做的更改
PrivateKey privkey = pair.getPrivate();
X509CertInfo info = new X509CertInfo();
Date from = new Date();
//Validity for next one year
Date to = new Date(from.getTime() + (365) * 86400000l);

CertificateValidity interval = new CertificateValidity(from, to);

BigInteger sn = new BigInteger(64, new SecureRandom());
X500Name owner = new X500Name(dn);

info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

// Sign the cert
X509CertImpl cert = new X509CertImpl(info);
cert.sign(privkey, algorithm);

//cert object is ready to use