我正在尝试设置stunnel
以向本身不支持 TLS 的 HTTP 服务提供 TLS 包装器。我在不使用 TLS 客户端证书的情况下运行良好。
添加客户端证书配置时:
CAfile = /path/to/trusted.crt
verify = 4
我似乎无法使用 进行连接openssl s_client
。(请注意,我有点作弊——也使用我的 TLS 服务器证书作为客户端证书,但证书说它有一个扩展名X509v3 Extended Key Usage: TLS Web Client Authentication, TLS Web Server Authentication
,所以我认为它应该可以工作。)
$ openssl s_client -state -connect [my-host-name]:[port] -cert [my-host-name].crt -key [my-host-name].key-nopass
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=2 C = IL, O = StartCom Ltd., OU = Secure Digital Certificate Signing, CN = StartCom Certification Authority
verify return:1
depth=1 C = IL, O = StartCom Ltd., OU = StartCom Certification Authority, CN = StartCom Class 1 DV Server CA
verify return:1
depth=0 CN = [my-hostname]
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 server session ticket A
140391435724640:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:1293:SSL alert number 48
140391435724640:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:
---
Certificate chain
0 s:/CN=[my-host-name]
i:/C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 1 DV Server CA
1 s:/C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 1 DV Server CA
i:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
2 s:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
i:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=/CN=[my-host-name]
issuer=/C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 1 DV Server CA
---
Acceptable client certificate CA names
/C=[the actual client cert I'd like to use]
/CN=[my-host-name] (for testing)
Server Temp Key: ECDH, prime256v1, 256 bits
---
SSL handshake has read 5620 bytes and written 1937 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 3072 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : ECDHE-RSA-AES256-SHA
Session-ID:
Session-ID-ctx:
Master-Key: [...]
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1465393332
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
(此时连接已关闭。)
如果我verify = 0
在 stunnel 配置中设置,则连接成功,我可以发出请求。如果我在配置verify = 1
中设置stunnel
,则如果我提供客户端证书,则连接将被断开,但如果我不提供,则连接将被接受。
因此看起来证书本身有问题(对于测试来说,它与 TLS 服务器使用的证书相同,所以我认为它没有任何问题),或者我的如何验证证书的配置有问题。
我想仅验证trusted.crts
文件中实际出现的证书。这些调试行让我相信我已正确指定了证书(这是客户端的输出):
Acceptable client certificate CA names
/C=[the actual client cert I'd like to use]
/CN=[my-host-name] (for testing)
由于我的测试证书出现在该列表中,因此我希望它应该是可以接受的。
我不确定我错过了什么。
在 中/var/log/secure
,stunnel
记录以下内容:
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG5[17497:139964729063168]: Service [mysvc] accepted connection from 52.203.5.20:57224
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG4[17497:139964729063168]: CERT: Verification error: unable to get local issuer certificate
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG4[17497:139964729063168]: Certificate check failed: depth=0, /CN=[my-host-name]
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG3[17497:139964729063168]: SSL_accept: 140890B2: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG5[17497:139964729063168]: Connection reset: 0 byte(s) sent to SSL, 0 byte(s) sent to socket
它看起来像是stunnel
试图根据 CA 验证证书,而不是直接信任我的trusted.crts
文件中的证书。
有什么建议么?
更新
如果我保留verify = 4
配置stunnel
文件,但将客户端证书的父证书(来自 StartCom 的证书)放入文件中trusted.crts
,我可以使用我的测试证书进行连接。如果我更改为verify = 3
同时使用文件中的测试证书及其签名者trusted.crts
,我再次无法连接。
有没有办法提供stunnel
我愿意从客户端接受的确切证书?文档建议使用verify = 3
或verify = 4
可以做到这一点,但我似乎无法让它以我认为应该能够的方式工作。
答案1
由于我刚开始使用 stunnel,因此尚未测试此答案,但根据文档,我猜测:
a) 您应该放弃该verify
选项,因为它不完整或者不像选项那样清晰,verifyChain
而且verifyPeer
已经过时了:
verify = LEVEL
verify the peer certificate
This option is obsolete and should be replaced with the verifyChain
and verifyPeer options.
b)verifyChain
应使用 中给出的CAfile
或 中的文件中的来检查您的证书链CApath
。对于具有中间证书的链,所有中间证书都应针对 CA 根有效,该根必须包含在 CA 集合(文件或路径)中。
c)verifyPeer
检查证书本身是否应该包含在CAfile
或中CApath
。
请注意,实际上,如果不参考扩展,根 CA 证书只是一个自签名证书,其中 CA 标志设置为是。当然,此类 CA 证书不包含在通常随浏览器或操作系统分发的受信任 CA 集中。在 Linux 中,OpenSSL 存储其受信任证书颁发机构的 CApath ( /etc/ssl/certs
) 应该可以对照标准受信任证书集进行检查。当然,您也可以在那里添加自己的 CA。
术语/C
和/CN
是证书主题的一部分,其中/C
是国家/地区,/CN
是通用名称。请参阅输出
openssl x509 -noout -subject </etc/ssl/certs/Deutsche_Telekom_Root_CA_2.pem
subject=C = DE, O = Deutsche Telekom AG, OU = T-TeleSec Trust Center, CN = Deutsche Telekom Root CA 2
作为示例。再次说明:这些根证书仅在您使用时才有用verifyChain=yes
。如果选项是verifyPeer=yes
证书本身被选中,如果您将两者都设置为是,则将测试根证书和对等证书,可能还会测试所有中间证书(未选中)。
来自 stunnel(8):
cert = CERT_FILE
certificate chain file name
The parameter specifies the file containing certificates used by
stunnel to authenticate itself against the remote client or server.
The file should contain the whole certificate chain starting from
the actual server/client certificate, and ending with the self-
signed root CA certificate. The file must be either in PEM or P12
format.
我猜想根 CA 证书实际上不需要包含在链中。大多数配置都没有这个,但了解整个链应该被视为一种美德,所以为什么不把它添加到文件中呢!
现在我们可以检查证书是否有效,但我们仍然不知道如何检查证书是否真正属于对等方。对等方可能窃取了有效证书并试图现在使用它。
在 Stunnel 中我们现在有:
checkEmail
,检查DN
主题或主题备用名称 (rfc822Name (参见 RFC280)) 扩展 (X509v3) 中的 (可分辨名称或目录名称) 字段。
checkHost
,检查证书的 DNS 名称。对于客户端证书检查,这可能很难使用或无法使用。
checkIP
,检查证书的IP地址。
手册上写着"Certificates are accepted if no subject checks where specified"
。我其实不太明白这一点,因为我认为checkIP
、checkHost
和checkEmail
字段是"subject checks"
,很难指定checkEmail
主题检查,而"no subject checks are specified"
。
我猜他们的意思是“没有其他科目检查”。当然,如果没有指定任何科目检查,证书只要有效就应该是有效的。
请注意,将检查证书中的主机和 IP,并且不会提及在建立连接时是否将其与对端的主机名或 IP 进行比较,就像与 HTTPS 服务器通信时一样,其中 CN 必须与备选中的主机名或 DNS 名称或备选中的 IP 匹配。
所有这些附带案例都未经测试,他们可能跳过了一些文档。
verifyPeer
如果您使用包含verifyPeer
具有主题和替代方案等的整个对等证书,则主题检查也是多余的。
我看不到证书使用字段在某处被检查。如果是的话,文档中缺少这一点!
当我检查完所有附带情况后,我将发布更新。