Openssl Shows a Different Server Certificate While Browser Shows Correctly

Openssl shows a different server certificate while browser shows correctly

The server is issuing a permanent redirect to ethornetworks.com. To see it, first issue your s_client command:

$ openssl s_client -CAfile AddTrustExternalCARoot.crt -connect apitest.ethormapp.com:443
CONNECTED(00000003)
depth=4 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=3 C = US, ST = UT, L = Salt Lake City, O = The USERTRUST Network, OU = http://www.usertrust.com, CN = UTN - DATACorp SGC
verify return:1
depth=2 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = EssentialSSL CA
verify return:1
depth=0 OU = Domain Control Validated, OU = EssentialSSL Wildcard, CN = *.ethornetworks.com
verify return:1
...

At the very bottom, after you get the verify result, enter a GET / HTTP/1.0 command and press RETURN twice:

    ...
Start Time: 1390985154
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
GET / HTTP/1.0

HTTP/1.1 301 Moved Permanently
Server: nginx/1.4.4
Date: Wed, 29 Jan 2014 08:46:01 GMT
Content-Type: text/html
Content-Length: 184
Connection: close
Location: https://www.ethornetworks.com/

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.4.4</center>
</body>
</html>
closed
$

If you follow the redirect, then you will get the expected result:

$ openssl s_client -CAfile AddTrustExternalCARoot.crt -connect www.ethornetworks.com:443
CONNECTED(00000003)
depth=4 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify error:num=19:self signed certificate in certificate chain
verify return:0
---
Certificate chain
0 s:/OU=Domain Control Validated/OU=EssentialSSL Wildcard/CN=*.ethornetworks.com
i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=EssentialSSL CA
1 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=EssentialSSL CA
i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Certification Authority
...

Finally, you can use the AddTrust External CA Root to ensure the chain verifies as expected. Without it and the -CAfile option, s_client will report 19 (self signed certificate in certificate chain).

opennssl s_client shows wrong cert: browser shows correct

You need to specify the servername option in your openssl command.

From the openssl s_client docs:

-servername name

Set the TLS SNI (Server Name Indication) extension in the ClientHello
message.

So try something like

openssl s_client -connect sub.domainA.com:443 -showcerts -servername sub.domainA.com

Checking server certificate with openssl versus a web request

openssl s_client gets the certificate from the server during the SSL handshake. OPENSSLDIR is only the place where any (optional) configurations for the openssl tool gets stored.

Note that you might get a different certificate with openssl than you have configured on your server because you need to use SNI (Server Name Indication) like the browser do. This feature is used if you have multiple certificates behind the same IP. To use this feature with openssl add the -servername hostname parameter and provide the name you expect. You must also remove the -ssl3 option since this restricts the connection to SSL 3.0 which is not only insecure but also does not support SNI.

Different SHA1 fingerprint in browser and openssl

Short answer is that you're getting different fingerprints because they are actually different certificates :)

Longer answer:

The server at the IP for saucelabs.com is serving the content from apps.saucelabs.com to the openssl s_client utility. You can see this if you print the subject CN of the certificate (note the addition of -subject to the final openssl command).

$ echo "" | openssl s_client -showcerts \
-connect saucelabs.com:443 2>&1 | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p;
/-END CERTIFICATE-/a\\x0' |\
sed -e '$ d' | xargs -0rl -I% sh -c "echo '%' | \
openssl x509 -fingerprint -noout -sha1 -subject"
SHA1 Fingerprint=F7:62:50:60:C2:DC:A9:29:96:B5:99:C2:DB:2A:71:BD:EA:57:0B:F9
subject=CN = app.saucelabs.com
SHA1 Fingerprint=2E:49:16:B0:7F:3D:E9:0C:8D:DE:25:66:FD:9B:9B:40:0D:89:BB:BA
subject=C = US, O = GeoTrust Inc., CN = RapidSSL SHA256 CA - G2
SHA1 Fingerprint=03:9E:ED:B8:0B:E7:A0:3C:69:53:89:3B:20:D2:D9:32:3A:4C:2A:FD
subject=C = US, O = GeoTrust Inc., OU = (c) 2008 GeoTrust Inc. - For authorized use only, CN = GeoTrust Primary Certification Authority - G3

And if you compare that to the info in your browser, you'll note that your browser is getting the certificate for saucelabs.com instead of the one for apps.saucelabs.com which you're getting redirected to.

The server is using SNI to decide which server to send your request to. Apparently, without an sni, the server at saucelabs.com serves the content from apps.saucelab.com. Now, if you want to see the certificates for saucelabs.com then go ahead and send an sni message like your browser does (note the addition of -servername option to the s_client command):

$ echo "" | openssl s_client -servername "saucelabs.com" \
-showcerts \
-connect saucelabs.com:443 2>&1 | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p;
/-END CERTIFICATE-/a\\x0' | sed -e '$ d' | \
xargs -0rl -I% sh -c "echo '%' | \
openssl x509 -fingerprint -noout -sha1 -subject"
SHA1 Fingerprint=80:27:83:5F:A8:81:6B:97:E2:60:FF:B3:A9:7B:69:E1:F2:38:9A:7A
subject=CN = saucelabs.com
SHA1 Fingerprint=2E:49:16:B0:7F:3D:E9:0C:8D:DE:25:66:FD:9B:9B:40:0D:89:BB:BA
subject=C = US, O = GeoTrust Inc., CN = RapidSSL SHA256 CA - G2
SHA1 Fingerprint=03:9E:ED:B8:0B:E7:A0:3C:69:53:89:3B:20:D2:D9:32:3A:4C:2A:FD
subject=C = US, O = GeoTrust Inc., OU = (c) 2008 GeoTrust Inc. - For authorized use only, CN = GeoTrust Primary Certification Authority - G3

And there's the 80...7A hash your browser shows you :)

Why do my browsers say my server's SSL certificate has expired but OpenSSL says it hasn't?

The certificate has two fields - Valid From and Valid To. Check that both parameters are ok, i.e. Valid From is in the past and Valid To is in the future.

When you visit the site with the browser, it shows the lock icon either left to the URL in the address bar or in the status bar. Clicking on the lock icon will show you the certificate that the browser sees. Check that this certificate corresponds to the one you have in server config.

Browser, s_client without SNI and expired certificate

See the 1st comment by @jww. He pointed out that I needed to add -tls1 -servername foo.example.com to my openssl command. His comment:

Try adding -tls1 -servername foo.example.com. I'm guessing you have a front-end server that's providing a default domain for requests without SNI, and the default domain is routed to an internal server with the old certificate. When the browsers connect, they use SNI and get the server for which you have updated the certificate. Or, there could be an intermediate with an expired certificate in the chain that's being served. If you provide real information, its easier for us to help you with problems like this.



Related Topics



Leave a reply



Submit