Is it possible that the lines are ^M-terminated? This is a potential issue when moving files from Windows to UNIX systems. One easy way to check is to use vi
in "show me the binary" mode, with vi -b /etc/apache2/domain.ssl/domain.ssl.crt/domain.com.crt
.
If each line ends with a control-M, like this
-----BEGIN CERTIFICATE-----^M
MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM^M
MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg^M
THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x^M
you've got a file in Windows line-terminated format, and apache doesn't love those.
Your options include moving the file over again, taking more care; or using the dos2unix
command to strip those out; you can also remove them inside vi, if you're careful.
Edit: thanks to @dave_thompson_085, who points out that this answer no longer applies in 2019. That is, Apache/OpenSSL are now tolerant of ^M-terminated lines, so they don't cause problems. That said, other formatting errors, several different examples of which appear in the comments, can still cause problems; check carefully for these if the certificate has been moved across systems.
The answer is yes, you can do it with openssl
, you can easily wrap this up as a "check" script, but I'm not aware of a plugin that already does this.
First, cache the server certificate and intermediate chain:
echo Q | openssl s_client \
-connect www.google.com:443 -servername www.google.com -showcerts > chain.pem
(this chain file contains the site certificate, and the intermediate chain, along with other junk)
You should use -servername www.google.com
as well so that SNI enabled sites return the expected certificate.
If you only wish to output the details of each certificate in the chain file:
gawk 'BEGIN { pipe="openssl x509 -noout -subject -dates -serial "} \
/^-+BEGIN CERT/,/^-+END CERT/ { print | pipe }
/^-+END CERT/ { close(pipe); printf("\n")} ' chain.pem
Add/omit -serial
, -issuer
, -fingerprint
, -purpose
as preferred, to the embedded openssl
command. You can even glue both steps together as one line with (taking care to omit the redirection and chain.pem
occurrences):
echo Q | openssl ... | gawk ...
If you wish to properly validate the chain, including date ranges, then read on.
Next, pull out just the site (first) certificate, I'll use sed
here because I'm lazy ;-)
sed -n '/-BEGIN/,/-END/p;/-END/q' chain.pem > site.pem
Then verify:
openssl verify -verbose -CAfile chain.pem site.pem
This is where the wheels come off: Google (correctly) does not provide the (self-signed) root CA (or "trust anchor") in the chain:
site.pem: /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
error 2 at 2 depth lookup:unable to get issuer certificate
So, pull the root certificate from Geotrust, save it and and set it up a suitable CA directory:
cd /usr/local/nagios/var/CA # example!
wget http://www.geotrust.com/resources/root_certificates/certificates/Equifax_Secure_Certificate_Authority.pem
c_rehash .
And try again:
openssl verify -verbose \
-CAfile chain.pem -CApath /usr/local/nagios/var/CA site.pem
(note the extra -CApath
parameter) and you get:
site.pem: OK
Now the bad news, openssl
doesn't set the return code to indicate success, failure or anything useful. You will need to process the output to make sure that everything is ok, basically anything other than a single line with "OK" indicates a problem. The expired certs you are looking for will show as:
error 10 at 2 depth lookup:certificate has expired
(where the depth may vary).
Notes and caveats:
- the server-provided chain should not contain the root (if it does, the client ought ignore it), work around this by adding
-CApath /some/path
to point to a (pre-hashed) directory of trusted root certs as shown above
- this does not catch mis-ordering of the chain file, nor superfluous certs in the chain file (neither are usually a problem for browsers, but a site validator will usually flag them -- at the very least these needlessly clutter up HTTPS handshakes)
- there's no requirement for the entire chain to be presented by the server, especially for longer chains, in which case adding those to the CApath directory will be required also
- the
chain.pem
created here has extra text junk in it, this doesn't present a problem for openssl
- each non-root certificate will link to its parent by name ("Issuer" field) and ID ("Authority Key Identifier" field) which you can use to find it. The AIA ("Authority Information Access") might also contain URLs to make obtaining them easier, but I find that is not usually the case)
Best Answer
There is no need to pipe stderr to
/dev/null
since it would not be put into the pipe anyway. And once you skip dropping stderr you'll see:Thus, the domain name you've used is simply wrong. Therefore the connection fails and therefore it cannot do a TLS handshake and therefore it cannot provide the certificate and therefore you cannot extract information from the certificate.
It might be that the real web site you've wanted to analyze is
www.abcecommerce.com
and notwww-abcecommerce.com
. Only, this site is only accessible by HTTP and not by HTTPS which means no certificate either.