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



我想在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,我配置:Bind *:443 SSL CRT/path/server。Pem ca-file/path/ca. PemCRT验证需要CRT -ignore-err all

我用类似的方式创建客户端证书:

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客户端)代码可以访问相同的内容。

我在1/2上度过了2天。我很确定以前做过这个的人可以在5米内回答这个问题。至少我希望如此。:)

谢谢!

1。创建客户端证书

错误: openssl x509 -req -signkey创建一个自签名的证书,根据定义,这意味着证书(主题密钥)中的密钥是对证书进行私钥签名的同一密钥的公开一半。cert(不是req)案例的文档清楚地表明,它用签名密钥替换了证书中先前的密钥。-req文档不太清楚,但它做了同样的事情;它在证书中放入来自CSR的主体名(也作为颁发者)和来自-signkey的密钥。您使用了包含客户端名称的CSR,但使用了包含CA密钥的-signkey,从而产生了不可用的嵌合体。

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

aside:对于自签名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选项解密SSL/TLS使用akRSA服务器密钥(也有其他选项)只接受pkcs# 1而不是pkcs# 8。

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

2 a。也许只是转换成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

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

2 b。可能会进一步转换为JKS。如果Jersey不能直接使用pkcs# 12, Java可以将其转换为JKS, 任何正常Java代码都可以使用,如:

keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore client.jks 

UPDATE 2018:在写完这个答案后,Java对PKCS12的支持增加了,这使得转换为JKS的必要性降低了。2017年秋季发布的8u60及以上版本仍然默认为密钥库类型JKS,但作为一个特殊功能(?)类型JKS实际上可以读取(尽管不能写入)PKCS12;参见JRE/lib/security/java.security文件的发布说明和keystore.type.compat项。2017年发布的Java9使默认的密钥库类型PKCS12(如预期的那样)读写PKCS12,尽管显式JKS不再读取PKCS12。但是,如果出于某种原因需要使用Java9进行转换,则现在需要指定-deststoretype jks,而不再需要指定-srcstoretype pkcs12

最新更新