java - HAProxy SSL终止+客户端证书验证+ curl/Java客户端

标签 java ssl curl haproxy keytool

我想使用我自己的自签名证书在HAProxy上进行SSL终止,并使用我创建的客户端证书来验证客户端访问。

我通过以下方式创建服务器(也是CA)证书:

openssl genrsa -out ca.key 1024
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt

和:
cat ca.crt ca.key > haproxy.pem

在HAProxy,我配置:
绑定*:443 ssl crt /path/server.pem ca文件/path/ca.crt验证所需的crt-ignore-err全部

我以类似的方式创建客户端证书:
openssl req -new -key client.key -out client.csr
openssl x509 -req -days 365 -in client.csr -signkey ca.key -out client.crt
cat client.crt client.key > client.pem

我的逻辑是:我先创建一个客户端密钥,一个证书签名请求,然后使用CA(也是服务器证书,因此有一个服务器可以识别的简单链)对其进行签名。

为了进行测试,我首先尝试使用服务器证书作为客户端证书:
curl https://my.service:443/ping -E ./haproxy.pem -k
pong

好的,它有效。现在,我尝试使用客户端证书作为客户端证书:
curl https://my.service:443/ping -E ./client.pem -k
curl: (58) unable to set private key file: './client.pem' type PEM

我的问题:
1)我想创建此服务器将支持的客户端证书,并使用curl对其进行测试。
2)我想使用keytool将此证书和CA导入到新的Java密钥库/信任库中,以便Java(Jersey客户端)代码可以访问相同的内容。

我花了2天的1/2时间。
我敢肯定,以前做过此事的人可以在5m内回答。还是这样,我希望。 :)

谢谢!

最佳答案

1.创建客户端证书

错误: openssl x509 -req -signkey创建了一个自签名证书,根据定义,这意味着证书中的密钥(主题密钥)是同一密钥的公共部分,其私有部分对证书进行了签名。证书(非要求)案例的文档很清楚,它用签名密钥替换了证书中先前的密钥。 -req文档不太清晰,但是它做的是相同的事情。它将来自CSR的主题名称(也作为颁发者)和来自-signkey的密钥放入证书中。您使用了包含客户端名称的CSR,但是使用了包含CA密钥的-signkey,从而生成了无法使用的嵌合体。

右:使用x509签署“子”(非自签名)证书,使用-CA以及文档https://www.openssl.org/docs/apps/x509.html#SIGNING-OPTIONS中描述的-CAkey(或在安装了openssl doc的任何Unix上使用man [where] x509)。如果给定CA(由其DN定义)存在一个子证书,或者曾经有多个子证书,请使用序列号文件方案自动方便地分配序列号,或者使用-set_serial手动分配唯一的序列号(顺序是唯一的最简单方法,但是如果您更喜欢另一种方法,也可以)。

除了:用于自签名CA(和服务器?!)证书的,您不需要单独的req -newx509 -req -signkey步骤,您可以在一个req -new -x509中进行操作。有关req的信息,请参见文档/手册。实际上,您不需要单独的genrsa步骤,req -newkey [-nodes] -x509也可以做到这一点。注意事项:在OpenSSL 1.0.0+中,它将生成通用PKCS#8格式的密钥文件,而不是genrsa(和rsa)使用的“旧式” PKCS#1格式;所有OpenSSL函数都可以接受,但其他一些可能不接受。特别是最后一次,我检查了一下(前一阵子)的Wireshark选项,使用akRSA的服务器密钥来解密SSL / TLS(还有其他选项),仅接受PKCS#1而不接受PKCS#8。

2.在Java(Jersey)中使用。 请注意,任何进行客户端身份验证的SSL / TLS客户端(包括Java)都需要证书和私钥,并且在大多数情况下,证书使用您还需要的“链”或“中间”证书。有些人(咳嗽)微软(咳嗽)鼓励您误解并忽略这一重要区别,但是,如果您仅尝试使用证书,则根本无法使用。另一方面,信任库条目仅需要证书,几乎总是只需要根(CA)证书,通常只需要证书。对于PKC,您由同一个人操作CA,服务器和客户端的情况有些不同。

2a。也许只是转换为pkcs12。 Java不直接支持密钥的openssl格式,但是Java和openssl都支持PKCS#12(Microsoft,Mozilla,Apple以及其他可能也支持)。由于您在client.pem中结合了客户端密钥和(叶子)证书,因此

openssl pkcs12 -export <client.pem -CA ca.crt [-name whatever] >client.p12
# if you use separate key,cert files see the doc about -in and -inkey

如果可以配置密钥库“类型”(如pkcs12),则Java crypto(JCE和JSSE)可以将此PKCS#12用作密钥库。默认的SSLSocketFactory支持此功能,我使用过的其他应用程序也支持此功能,但是我不使用Jersey,也不知道它在这里做什么。通常不支持PKCS#12携带“单独的”证书(不包含私钥),但是在您的情况下,客户端的CA证书也是服务器的证书,因此它也将与您的信任库一起工作;否则,您需要将服务器CA或服务器自签名证书(仅证书而非私钥)导入JKS信任库(这可能是JRE / lib / security / [jsse] cacerts中的默认信任库)。

2b。也许可以进一步转换为JKS。 如果Jersey无法直接使用PKCS#12,则Java可以将其转换为任何理智的Java代码都可以使用的JKS,例如:
keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore client.jks 

更新2018:在编写此答案后,增加了Java对PKCS12的支持,从而减少了转换为JKS的频率。 8u60于2017年秋季发布,并且仍默认使用密钥库类型JKS,但作为一种特殊功能(?),JKS类型实际上可以读取(尽管不能写入)PKCS12;请参阅keystore.type.compat文件中的the release notes和项目JRE/lib/security/java.security。 Java9 2017年发布了默认的密钥库类型PKCS12(按预期方式),它可以读写PKCS12(尽管如此),尽管显式JKS不再读取PKCS12。但是,如果由于某种原因确实需要使用Java9进行转换,则现在需要指定-deststoretype jks,而不再需要指定-srcstoretype pkcs12

关于java - HAProxy SSL终止+客户端证书验证+ curl/Java客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30444321/

相关文章:

SSL 证书未在 Google Cloud Console GKE 中更新

bash - 如何从 Gitlab 下载私有(private)存储库而不暴露 url 中的访问 token ?

linux - 从 URL 执行 bash 脚本

java - 运行低于 Lollipop 的设备上的 CameraManager

.htaccess - 如何在 Heroku Cedar 堆栈上使用 .htaccess 重定向到 HTTPS

用于统计单词的Java函数

android - 带 Flutter 的传送带 - 在本地运行 .net Web 应用程序时出现握手错误

php - 如何在curl调用中访问Uber API OAuth 2.0不记名 token

java - 在 Hibernate/JPA 中使用批量插入

java - Xmlgregoriancalendar 不允许在 ddMMyyyy 中前导零