警报“SSL3_READ_BYTES:sslv3 警报错误证书”是否表明 SSL 失败

kri*_*433 24 ssl openssl ssl-certificate ssl-certificate-errors

运行以下命令时 openssl s_client -host example.xyz -port 9093

我收到以下错误:

139810559764296:error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate:s3_pkt.c:1259:SSL alert number 42
39810559764296:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:
Run Code Online (Sandbox Code Playgroud)

但最后我收到"Verify return code: 0 (ok)"消息。

我的问题是上述警报表示什么,以及 SSL 是否真的成功。

SSL handshake has read 6648 bytes and written 354 bytes
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol  : TLSv1.2
Cipher    : AES128-SHA
Session-ID: xx
Session-ID-ctx:
Master-Key: xx
Key-Arg   : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1475096098
Timeout   : 300 (sec)
**Verify return code: 0 (ok)**
Run Code Online (Sandbox Code Playgroud)

dav*_*085 37

“握手失败”表示握手失败,并且没有 SSL/TLS 连接。您应该看到openssl退出到 shell(或 CMD 等)并且不等待输入数据发送到服务器。“验证返回码 0”表示在服务器的证书中没有发现任何问题,要么是根本没有检查,要么是因为它被检查并且是好的(就 OpenSSL 的检查而言,它并没有涵盖所有内容);在这种情况下,通过了解协议,我们可以推断出后一种情况适用。

收到警报bad certificate(代码 42)意味着服务器要求您使用证书进行身份验证,而您没有这样做,这导致了握手失败。在该行之前的几行,SSL handshake has read ... and written ...您应该看到一行Acceptable client certificate CA names通常后跟几行标识 CA,可能后跟一行开头Client Certificate Types,可能还有一些关于Requested Signature Algorithms取决于您的 OpenSSL 版本和协商协议。

在“可接受”列表中查找CA 颁发的证书,或者如果它是空的,则查找有关服务器的文档,说明它信任哪些 CA,或联系服务器运营商或所有者并询问他们,以及匹配的私钥,两者以 PEM 格式,-cert $file -key $file; 如果您在一个文件中同时拥有这两个文件,就像 PEM 一样,只需使用-cert $file. 如果你有不同的格式,要么指定它,要么在这里搜索超级用户和 security.SX;已经有很多关于转换各种证书和私钥格式的问答。如果您的证书需要验证“链”或“中间”证书(甚至不止一个),这通常是来自公共 CA(而不是内部 CA)的证书的情况,具体取决于服务器的配置方式,s_client需要一个技巧:要么将链证书添加到您的系统信任库,要么创建一个本地/临时信任库,其中包含您需要验证服务器的 CA 证书以及您需要发送的链证书。

如果您没有这样的证书,您要么需要获得一个证书,这是一个需要更多细节来回答的不同问题,或者您需要找到一种无需使用证书身份验证即可连接到服务器的方法;再次检查文档和/或询问运营商/所有者。

编辑:从评论看来,您可能拥有 Java 中的客户端密钥和证书链以及服务器锚点?在检查时,我没有看到一个很好的现有答案完全涵盖了这种情况,所以即使这可能不会很好地搜索:

# Assume Java keystore is type JKS (the default but not only possibility)
# named key.jks and the privatekey entry is named mykey (ditto)
# and the verify certs are in trust.jks in entries named trust1 trust2 etc.

# convert Java key entry to PKCS12 then PKCS12 to PEM files
keytool -importkeystore -srckeystore key.jks -destkeystore key.p12 -deststoretype pkcs12 -srcalias mykey 
openssl pkcs12 -in key.p12 -nocerts -out key.pem
openssl pkcs12 -in key.p12 -nokeys -clcerts -out cert.pem
openssl pkcs12 -in key.p12 -nokeys -cacerts -out chain.pem
# extract verify certs to individual PEM files
# (or if you 'uploaded' PEM files and still have them just use those)
keytool -keystore trust.jks -export -alias trust1 -rfc -file trust1.pem
keytool -keystore trust.jks -export -alias trust2 -rfc -file trust2.pem
... more if needed ...
# combine for s_client 
cat chain.pem trust*.pem >combined.pem
openssl s_client -connect host:port -key key.pem -cert cert.pem -CAfile combined.pem
Run Code Online (Sandbox Code Playgroud)