我的任务是使用HTTPS保护(以前的HTTP)Web服务.从现在离开的同事我继承了在我们现有服务器的TCP和HTTP层之间插入SSLEngine对象的代码.据我所知,这段代码可以正常工作.我从SSLContext.createSSLEngine()获取SSLEngine,但是如何生成一个合适的SSLContext会让我感到困惑.
SSLEngine本身在javadoc中有一个很好的概念性介绍,但遗憾的是我不需要与自己接口.另一方面,SSLContext.init()是非常稀疏的文档,只是说我必须传递“身份验证密钥的来源”和“对等身份验证信任决策的来源”,我不知道那是什么.这些参数类型的文档(通常是我下一次尝试理解它)是通用的,没有说什么,SSLContext的类文档也是无用的简短.
我获得了一堆ascii-armored .crt,.pem和.key文件,这些文件一起使Apache能够在Java服务器最终将直接处理的域中提供HTTPS.我想我需要以某种方式将它们加载到SSLContext或SSLEngine中,但我不确定SSLContext.init()是否是正确的位置(尽管它似乎没有其他许多地方) .
Which documentation should I start by reading to get a working understanding of how to do this?
我的谷歌试图生成大量未经证实的半无证的示例代码,质量和安全性未知,以及一些高级演练,如“如何编写自己的密钥提供程序”,但没有对JRE最基本用法的整体概念介绍类.
特别是因为这与安全性有关,所以我没有使用复制粘贴示例代码,我只是漫无目的地敲打它,直到它看起来像我想做的更多或更少.我需要对各个部分实际上应该如何组合在一起的高级概念性理解.
(如果文档的详细程度足以让我弄清楚如何在实践中进行SSL客户端授权,那么奖励点 – 但这并不是立即紧急的).
默认值(如果将null传递给SSLContext.init(…))默认值是合理的,但您可能想要了解这些默认值是什么(请参阅Customization部分).
密钥库没有默认值(只有信任库,如果你想要客户端证书身份验证,你几乎肯定想要自定义它).
通常,您可以按如下方式初始化SSLContext:
KeyStore ks = KeyStore.getInstance(...); // Load the keystore
ks.load(...); // Load as required from the inputstream of your choice,for example.
KeyStore ts = KeyStore.getInstance(...); // Load the truststore
ts.load(...);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks,
也许您可能对this answer感兴趣,因为密钥库和信任库之间存在差异.简而言之,两者都是存储意义上的“密钥库”,但密钥库是存储证书(链)和关联私钥的位置(即服务器上的服务器证书和私钥以及客户端证书和私钥.客户端)和信任库是您在远程方提供其证书时存储您愿意信任的CA证书或远程证书(没有私钥,因为它们不是您的证书)的地方.
关于如何处理密钥/证书文件,最简单的当然是使用PCKS12类型的密钥库,您可以按照this answer中的描述进行构建.
编辑:(以下评论)
So is it correctly understood that I can get away with a null
TrustManager if I’m a server and not yet doing SSL client
authentication?
是.
But that if I were to do cliemt authentication I need to provide a
TrustManager that contains the public keys of every client that should
be able to connect?
通常不是.您将为颁发这些客户端证书的CA提供CA证书.如果您没有此基础结构(或者如果您正在构建它并且还没有任何客户端证书),您应该考虑创建自己的PKI,或者从着名的CA购买客户端证书.
您还可以构建一个接受自签名证书(独立于任何CA)的TrustManager,并使用预定义列表中的指纹对其进行验证,但这会带来许多问题(特别是服务器如何请求正确的证书) ),你最终可能会复制PKI的部分内容.除非你更了解你正在做什么,否则这不是我推荐的.
That’s a bit of a downer; I had hoped I could have waited until I got
the request URL before I needed to retrieve a fingerprint for the
authorized client and only then compare to the fingerprint the actual
client authenticated with.
在这里,你谈论的是一个完全不同的方面.如果要在获取证书之前首先获取请求的URL,则需要使用重新协商. HTTP层必须与SSLEngine通信,要求它触发新的握手(现在设置为要求客户端证书).
SSLEngine通常不是Java中SSL / TLS的简单途径,但异步重新协商可能变得非常棘手.实际上,它的语义在应用层并不十分清楚.您可以在收到HTTP请求后很好地触发重新协商,但是同时发送响应(因为您可能有异步请求/响应,可能是流水线的).从技术上讲,新握手会影响两个管道.
总的来说,重新协商与否,这完全独立于检查您如何信任客户端证书.如果您真的希望继续使用您的应用程序层(而不是SSL / TLS层)进行证书验证,那么您必须编写一个信任任何内容的X509TrustManager(绕过SSL / TLS层的验证)并让您的应用程序从SSLSession(对等证书)获得证书并在那里进行验证.总的来说,这与接受自签名证书并手动验证它们非常相似.它可以完成,但你要走出PKI模型,你需要一些自定义代码才能这样做(而不是仅使用API,因为默认情况下它会被使用).
如果你对这一切都不熟悉,我会避免这种做法.尝试建立测试CA并首先了解它的工作原理.关于使用CA或进行手动指纹验证的整个问题最终是一个管理问题:它是由您如何在相关各方之间分发证书来定义的.
Also,what is
doing here? This is supposed to run
on an unattended server in a hosting facility somewhere; we cannot
wait for someone to come around to type in a password during startup
(say,after a power outage).
您需要设置密码.如果需要,大多数服务器都会从配置文件中读取它(或者更糟糕的是,您可以对其进行硬编码).