尝试使用客户端证书时解决 sslv3 警报握手失败
Posted
技术标签:
【中文标题】尝试使用客户端证书时解决 sslv3 警报握手失败【英文标题】:Solving sslv3 alert handshake failure when trying to use a client certificate 【发布时间】:2016-07-22 02:32:33 【问题描述】:我正在尝试连接到需要授权证书的服务。这个过程是我向服务发送一个 CSR 文件。该服务签署 CSR 并向我发送我用于连接的证书。
我通过以下命令行生成了 CSR:
openssl req -new -nodes -newkey rsa:2048 -keyout cert.key -out cert.csr
我获取了 cert.csr 的内容并发送给了他们。他们生成客户端证书,我得到了一个 PEM 文件。
我现在尝试使用他们在 SSLCERT 中的证书文件进行 curl() 连接,并提供来自 cert.key 的私钥作为 CURLOPT_SSLKEY -(我在步骤 1 中获得)。
失败:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
在这个过程中我做错了什么?
当我尝试使用收到的测试证书(包括来自服务的私钥(自签名证书))时,它可以工作。但是当我使用他们从我的 CSR 生成的证书然后使用我的私钥作为密钥时,它会因握手失败而出错。
所以我知道这与 openssl / curl 不支持 v3/TLS 等其他人在研究解决方案时发现他们的问题无关。
这是我运行的:
curl -i -v --request POST https://service.com/ --cert clientcert.pem --key private_key.pem --cert-type pem --tlsv1.1 --insecure
* Connected to service.com (1xx.xxx.xxx.xx) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Request CERT (13):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS handshake, CERT verify (15):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS alert, Server hello (2):
* error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
* Closing connection 0
运行以下版本:curl 7.35.0 (x86_64-pc-linux-gnu) libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3
【问题讨论】:
No 私钥永远不会被发送到任何地方,更不用说通过 SSL。这就是为什么他们被称为私人。很难理解你到底在问什么。 @EJP 好的,但是我需要发送一个私钥,因为我从他们那里收到的唯一东西是证书(由我制作的 CSR 生成)?我错过了什么吗? @EJP 我必须发送私钥,否则报错“无法设置私钥文件:” 您需要在端点的 SSL 配置中使用您的私钥。你不会在任何地方、任何时间、永远发送它。 SSL 也没有。它只是使用它来签署发送给对等方的证书消息。 @EJP 我的意思是“设置”而不是实际发送,感谢您的指出。当我将 CURL 配置为使用从他们那里获得的测试证书 + 测试私钥时,它可以工作。当我将 CURL 配置为使用从我的 CSR + 我的私钥生成的证书时,它不起作用。那么我是否以错误的方式生成签名的 CSR,因为我想我的错误不匹配? 【参考方案1】:不是一个明确的答案,但太多不适合 cmets:
我假设他们给你的证书要么有错误的颁发者(尽管他们的服务器可以为此使用更具体的警报代码)或错误的主题。我们知道证书与您的私钥匹配——因为curl
和openssl client
都将它们配对,而不会抱怨不匹配;但我们实际上并不知道它与他们想要的 CA 匹配——因为您的 curl 使用 openssl 并且 openssl SSL 客户端不会强制配置的客户端证书与 certreq.CAs 匹配。
在有效的测试 P12 的证书上执行 openssl x509 <clientcert.pem -noout -subject -issuer
和相同的操作。做openssl s_client
(或检查你做的那个)并在Acceptable client certificate CA names
下查看;那里的名称或其中一个名称应匹配(完全正确!)您的证书的颁发者。如果不是,那很可能是您的问题,您需要与他们核实您是否以正确的方式将 CSR 提交到了正确的位置。也许他们在不同的地区、或业务线、或测试与生产、活跃与待定等有不同的制度。
如果您的证书颁发者确实与期望的CA 匹配,请将其主题与工作(test-P12)之一进行比较:它们的格式是否相似?工作组件中是否有任何组件不存在于您的组件中?如果他们允许,请尝试生成并提交一个新的 CSR,其主题名称与 test-P12 完全相同,或者尽可能接近,看看是否会产生一个效果更好的证书。 (您不必生成新的 key 来执行此操作,但如果您选择这样做,请跟踪哪些证书与哪些密钥匹配,这样您就不会混淆它们。)如果没有'不帮助查看带有 openssl x509 <cert -noout -text
的证书扩展,以了解可能与主题授权合理相关的任何差异,例如 KeyUsage、ExtendedKeyUsage、可能是 Policy、可能是 Constraints,甚至可能是非标准的东西。
如果所有其他方法都失败了,请询问服务器操作员他们的日志对问题的看法,或者如果您有权访问,请自行查看日志。
【讨论】:
感谢您的回答。我刚检查过。对于 p12(有效的测试证书)和我正在尝试使用的“实时”客户端证书,颁发者和主题的格式相同。发行人和主题都存在差异,但这只是数据,而不是格式/结构。您的答案剩下的就是尝试 openssl s_client 并查看可接受的客户端证书。如果我现在可以连接并检查,我会尝试。 就是这样!不同的 CA 名称(测试与产品)! @Karem,你是如何解决这个问题的,你的意思是你使用的是具有不同域的 ssl 证书,例如sub.site.com vs bus.site.com?【参考方案2】:什么 SSL 私钥应与客户端证书一起发送?
没有一个:)
客户端证书的一个吸引人的地方是它不会做愚蠢的事情,比如以纯文本形式将秘密(如密码)传输到服务器(HTTP basic_auth
)。密码仍然用于解锁客户端证书的密钥,只是在交换期间不直接用于或对客户端进行身份验证。
相反,客户端会为该会话选择一个临时的随机密钥。然后客户端用他的证书签署临时的、随机的密钥并将其发送到服务器(有些人放弃)。如果坏人拦截了任何东西,它是随机的,因此将来无法使用。它甚至不能用于与服务器的第二次协议运行,因为服务器也会选择一个新的随机值。
失败:错误:14094410:SSL 例程:SSL3_READ_BYTES:sslv3 警报握手失败
使用 TLS 1.0 及以上版本;并使用Server Name Indication。
您没有提供任何代码,所以我不清楚如何告诉您该做什么。相反,这里是用于测试它的 OpenSSL 命令行:
openssl s_client -connect www.example.com:443 -tls1 -servername www.example.com \
-cert mycert.pem -key mykey.pem -CAfile <certificate-authority-for-service>.pem
您也可以使用-CAfile
来避免“验证错误:num=20”。例如,请参阅“verify error:num=20” when connecting to gateway.sandbox.push.apple.com。
【讨论】:
感谢您的解释。我仍然很困惑。为了进行测试,我收到了一个 .p12 文件,我提取该文件以获取证书 + 私钥文件。当在 CURLOPT_SSLCERT + CURLOPT_SSLKEY 的 curl(使用 openssl)中配置时,这非常有效(!)。现在对于从我在服务器上生成的 CSR 生成的真实客户端证书(在他们的末端),我没有从他们那里收到私钥,然后我想好吧,也许我应该使用生成 CSR 时获得的私钥和把它作为 CURLOPT_SSLKEY。没用(这让我想到了这个问题)。 现在你和其他人说根本不应该设置私钥。如果我没有设置私钥(使用 CURLOPT_SSLKEY),我会收到错误“无法设置私钥文件:”(它无法在客户端证书中找到私钥)。这么多令人沮丧的时间,我就是想不通。 我使用的是 TLS 1.2(正如所说的,一切都与测试客户端证书 + 测试私钥一起工作)。我觉得我错过了一些东西/我理解了一些非常错误的东西。 @Karem - 您拥有创建 CSR 时的私钥。它不在客户端证书中,因为它只有公钥。根据您显示的 OpenSSL 命令:-keyout cert.key
。检查文件系统中的cert.key
。
没错!这就是我正在使用的那个。证书密钥!我把它的内容放入 private_key.pem 以在 --key 参数中的 curl 命令(请参阅更新的问题)中运行。但我仍然收到错误握手失败。【参考方案3】:
我在 CentOS 8 系统上的解决方案是通过验证 /etc/crypto-policies/config 读取默认值 DEFAULT 而不是检查系统加密策略比任何其他值。
将此值更改为 DEFAULT 后,运行以下命令:
/usr/bin/update-crypto-policies --set DEFAULT
重新运行 curl 命令,它应该可以工作了。
【讨论】:
【参考方案4】:在我的情况下,错误的原因是我只将证书(例如,cert1.pem
)和私钥(例如,privkey1.pem
)导入到密钥库中,为了解决这个问题,我不得不导入完整的证书链。
我从“Let's Encrypt”证书颁发机构获得了以下文件:
privkey1.pem
fullchain1.pem
chain1.pem
cert1.pem
所以我做了以下事情:
-
将三个证书文件的内容合并成一个名为
all.pem
的文件:
cat cert1.pem chain1.pem fullchain1.pem > all.pem
-
创建包含完整证书链的密钥库:
openssl pkcs12 -export -in all.pem -inkey privkey1.pem -out my_keystore.p12 -name mycertalias -CAfile chain1.pem -caname root
【讨论】:
以上是关于尝试使用客户端证书时解决 sslv3 警报握手失败的主要内容,如果未能解决你的问题,请参考以下文章
如何解决错误 SSL23_GET_SERVER_HELLO:sslv3 警报握手失败
Paypal Sandbox IPN: 14077410:sslroutines:ssl23_get_server_hello:sslv3 警报握手失败
另一个 Paypal Curl / SSL v3 握手错误 - SSL23_GET_SERVER_HELLO:sslv3 警报握手失败
curl:(35)错误:14077410:SSL例程:SSL23_GET_SERVER_HELLO:sslv3警报握手失败