我想使用我自己的自签名证书在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 -new
和x509 -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/