I'm trying to set up stunnel
to provide a TLS wrapper to an HTTP service that doesn't natively support TLS. I have this working well without using TLS client certificates.
When adding the client certificate configuration:
CAfile = /path/to/trusted.crt
verify = 4
I can't seem to connect using openssl s_client
. (Note that I'm cheating a bit -- using my TLS server's certificate as the client cert as well, but the cert says it has an extension for X509v3 Extended Key Usage: TLS Web Client Authentication, TLS Web Server Authentication
, so I figure it should work.)
$ 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)
---
(The connection is closed at this point.)
If I set verify = 0
in the stunnel configuration, the connection is successful and I can make a request. If I set verify = 1
in the stunnel
configuration, the connection is dropped if I provide a client certificate, but accepted if I do not provide one.
So it looks like something is wrong with the certificate itself (for testing, it's the identical certificate being used for the TLS server, so I don't think there is anything wrong with it), or my configuration for how to verify the certificate.
I would like to only verify certificates which actually appear in my trusted.crts
file. These debug lines lead me to believe that I have specified the certificates correctly (this is output from the client):
Acceptable client certificate CA names
/C=[the actual client cert I'd like to use]
/CN=[my-host-name] (for testing)
Since my certificate for testing appears in that list, I expect that it should, well, be acceptable.
I'm not sure what I'm missing.
In /var/log/secure
, stunnel
is logging this:
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
It looks like stunnel
is trying to verify the certificate against a CA, rather than directly-trusting the certificate that is in my trusted.crts
file.
Any suggestions?
UPDATE
If I leave verify = 4
in the stunnel
configuration file but place the client certificate's parent certificate (the one from StartCom) into the trusted.crts
file, I can connect using my test certificate. If I change to using verify = 3
with both the test cert and its signer in the trusted.crts
file, I again cannot connect.
Is there a way to give stunnel
the exact certificate(s) I am willing to accept from clients? The documentation suggests that using verify = 3
or verify = 4
is the way to do that, but I can't seem to make it work in the way I think I should be able to.