openssl s_client -cert:证明客户端证书已发送到服务器

bep*_*ter 39 ssl openssl ssl-certificate

背景

我陷入与服务提供商的指责匹配,其服务提供商具有受SSL服务器和客户端证书保护的API .

  • 我已经生成了CSR,从公共CA(本例中为GoDaddy)获得了证书,并将证书和CA链提供给服务提供商.
  • 他们应该将CA和我的客户端证书加载到他们的网关中.
  • 我正在使用最基本的级别测试 openssl s_client -connect ... -cert ... -key ...
  • 提供商告诉我他们的日志表明我的请求根本不包括客户端SSL证书.
  • 奇怪的是,我的证书的正确CA颁发者确实出现在SSL握手期间提供的"可接受的客户端证书CA名称"列表中.
  • 作为参考,我创建并提供给他们进行测试的自签名证书确实可以正常工作.

样本(失败)请求

[shell ~]$ openssl s_client -connect host:443 -cert cert_and_key.pem -key cert_and_key.pem -state -quiet
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=2 **SNIP**
verify return:1
depth=1 **SNIP**
verify return:1
depth=0 **SNIP**
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server key exchange A
SSL_connect:SSLv3 read server certificate request A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client certificate A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write certificate verify A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL3 alert read:fatal:unknown CA
SSL_connect:failed in SSLv3 read finished A
140011313276744:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:1197:SSL alert number 48
140011313276744:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:
Run Code Online (Sandbox Code Playgroud)

我对SSL3 alert read:fatal:unknown CA错误的解读是服务器无法识别我(实际上)提供的证书的颁发者.但是,提供商"向我保证"CA证书已正确加载,否则我无法说服他们.

因此,抛开其他(广泛的)故障排除步骤,我真正想知道的是:

是否有一些可用的输出openssl s_client最终显示客户端证书不仅仅是服务器请求,但实际上是在SSL握手期间传输到服务器?

我已经试验了-state,-msg,-debug-trace选项,但没有解释输出所需的背景.

EJP的回答表明我提供的示例输出足够证明write client certificate A,但无论-cert选项是否在命令行上使用,都会显示此输出,因此并不表示证书已发送.

bep*_*ter 81

为了验证客户端证书是否正在发送到服务器,您需要分析-state和和-debug标志组合的输出.

首先作为基线,尝试运行

$ openssl s_client -connect host:443 -state -debug
Run Code Online (Sandbox Code Playgroud)

您将获得大量输出,但我们感兴趣的行看起来像这样:

SSL_connect:SSLv3 read server done A
write to 0x211efb0 [0x21ced50] (12 bytes => 12 (0xC))
0000 - 16 03 01 00 07 0b 00 00-03                        .........
000c - <SPACES/NULS>
SSL_connect:SSLv3 write client certificate A
Run Code Online (Sandbox Code Playgroud)

这里发生了什么事:

换句话说:s_client完成读取服务器发送的数据,并将12个字节发送到服务器(我假设是)"无客户端证书"消息.


如果你重复测试,但这次包括-cert和这样的-key标志:

$ openssl s_client -connect host:443 \
   -cert cert_and_key.pem \
   -key cert_and_key.pem  \
   -state -debug
Run Code Online (Sandbox Code Playgroud)

"读取服务器完成"行和"写入客户端证书"行之间的输出将更长,代表客户端证书的二进制形式:

SSL_connect:SSLv3 read server done A
write to 0x7bd970 [0x86d890] (1576 bytes => 1576 (0x628))
0000 - 16 03 01 06 23 0b 00 06-1f 00 06 1c 00 06 19 31   ....#..........1
(*SNIP*)
0620 - 95 ca 5e f4 2f 6c 43 11-                          ..^%/lC.
SSL_connect:SSLv3 write client certificate A
Run Code Online (Sandbox Code Playgroud)

1576 bytes是证书传输的一个很好的指示,但最重要的是,右侧列将显示人类可读的证书部分:您应该能够识别您的CN和发行者字符串证书在那里.

  • 为-state和-debug标志+1 (4认同)
  • 谢谢你教一个人如何钓鱼...... (2认同)

JSA*_*son 7

我知道这是一个老问题,但它似乎还没有答案.我已经复制了这种情况,但我正在编写服务器应用程序,所以我已经能够确定服务器端发生的事情.客户端在服务器请求时发送证书,并且在s_client命令行中引用了真实证书.我的服务器应用程序设置为要求提供客户端证书,如果没有提供,则会失败.这是我发出的命令行:

Yourhostname here -vvvvvvvvvv s_client -connect <hostname>:443 -cert client.pem -key cckey.pem -CAfile rootcert.pem -cipher ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH -tls1 -state

当我省略命令的"-cert client.pem"部分时,服务器端的握手失败,并且s_client命令失败并报告错误.我仍然收到报告"没有发送客户端证书CA名称",但我认为上面已经回答了这个问题.

简短的回答是服务器确定客户端是否将在正常操作条件下发送证书(s_client不正常),并且失败是由于服务器不识别所提供的证书中的CA. 虽然我的项目需要双向身份验证,但我并不熟悉这种情况.

您显然是在发送证书.服务器显然拒绝它.

这里缺少的信息是创建证书的确切方式以及提供者加载证书的方式,但现在可能全部都已完成.

  • 在此问题中跟踪完全相同的路径后,我发现服务器拒绝我的测试证书的原因是由于客户端使用的证书类型不正确。事实证明,我的那个被标记为:`X509v3 Extended Key Usage: TLS Web Server Authentication`。客户端证书应具有“X509v3 扩展密钥用法:TLS Web 客户端身份验证”。所以根本原因是客户端提供的是 Web 服务器证书而不是客户端证书。重新生成正确的客户端类型证书有效! (2认同)
  • 使用 OpenVPN 的 `easyrsa` 工具,创建客户端证书的命令是:`build-client-full`。例如:`./easyrsa --subject-alt-name="DNS.1:*.ec2.internal" build-client-full exampleclient nopass` (2认同)