没有JKS的嵌入式Jetty上的TLS

时间:2017-11-18 00:20:20

标签: java ssl jetty x509certificate embedded-jetty

我的目标:我正致力于Jetty Embedded的集成,使其易于使用。 interface允许在不使用Java KeyStore的情况下集成TLS证书的外部源。

这可以在构建分布式Web服务时提供更大的灵活性(在我的情况下为experimental, self-hosted CDN)。

但是,我在构建集成时遇到了问题。存根实现是in this repository

我尝试了什么:我尝试更换key managertrust manager,并为其中的每个功能设置断点。但是,在尝试访问服务器时,永远不会触发这些断点。相反,我遇到了这个错误:

javax.net.ssl.SSLHandshakeException: no cipher suites in common
    at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478)
    at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535)
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:813)
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
    at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:621)
    at org.eclipse.jetty.server.HttpConnection.fillRequestBuffer(HttpConnection.java:322)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:231)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:112)
    at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:261)
    at org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:150)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:112)
    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
    at java.lang.Thread.run(Thread.java:748)

我试过分析"标准" Jetty设置了一个来自密钥库的证书,但没有太多运气。我没有找到Jetty获取我应该覆盖的密码/证书信息的点。

我的问题:如何让Jetty使用my own certificate source而不是Java KeyStore和TrustStore?

1 个答案:

答案 0 :(得分:0)

@EJP指出了我正确的方向,所以这是如何做到的:

以下是需要完成的工作。

首先,为TLS设置Jetty:

HttpConfiguration https = new HttpConfiguration();
https.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new JettySslContextFactory(configuration.getSslProviders());
ServerConnector sslConnector = new ServerConnector(
    server,
    new SslConnectionFactory(sslContextFactory, "http/1.1"),
    new HttpConnectionFactory(https)
);
sslConnector.setPort(httpsPort);

注意类JettySslContextFactory。此类扩展了内置的X509ExtendedKeyManager,需要覆盖protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception方法以提供自定义KeyManager,如下所示:

@Override
protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception {
    return new KeyManager[] {
        new JettyX509ExtendedKeyManager(certificateProviders)
    };
}

除此之外,还在每个连接中运行以下步骤:

  1. SNI匹配器咨询SNI主机名。这似乎是唯一可以使用SNI主机名的地方。
  2. 咨询密钥管理器以获取某个密钥类型(EC或RSA)的别名(一种密钥ID)。这里我们需要从SNI匹配器中获取主机名,否则我们不知道要匹配哪个主机名。
  3. 根据别名(密钥ID),我们可以返回私钥和证书。
  4. 至少这是我从调试此问题中收集的内容。完整代码is online here