253

I want to download the ssl certificate from, say https://www.google.com, using wget or any other commands. Any unix command line? wget or openssl?

RainDoctor
  • 4,162
  • 3
  • 22
  • 25

6 Answers6

351

In order to download the certificate, you need to use the client built into openssl like so:

echo -n | openssl s_client -connect $HOST:$PORTNUMBER -servername $SERVERNAME \
    | openssl x509 > /tmp/$SERVERNAME.cert

That will save the certificate to /tmp/$SERVERNAME.cert.

The -servername is used to select the correct certificate when multiple are presented, in the case of SNI.

You can use -showcerts if you want to download all the certificates in the chain. But if you just want to download the server certificate, there is no need to specify -showcerts. The x509 at the end will strip out the intermediate certs, you will need to use sed -n '/-----BEGIN/,/-----END/p' instead of the x509 at the end.

echo -n gives a response to the server, so that the connection is released

openssl x509 removes information about the certificate chain and connection details. This is the preferred format to import the certificate into other keystores.

Sean Reifschneider
  • 10,370
  • 3
  • 24
  • 28
  • 17
    appreciate that you not only gave a good answer, but also a precise explanation. – marco.m Jan 24 '14 at 17:13
  • Does `-showcerts` show the server/leaf cert too? I thought it only displayed intermediates when that switch was included. – Mike B Apr 30 '14 at 05:56
  • As the answer said, `s_client` always shows the server cert (if there is one, i.e. the server responds to hello and doesn't choose an anonymous suite). `-showcerts` shows *all* the certs received, server cert first then intermediates and/or root. – dave_thompson_085 May 28 '14 at 08:58
  • 1
    what a great answer. – bitoiu Aug 15 '14 at 15:24
  • 5
    this doesn't work in the presences of a proxy, though. – Frederick Nord Apr 16 '15 at 09:00
  • 5
    This also doesn't work with servers that use SNI (multiple certificates/domains on a single IP-adress). To avoid problems, specify openssl's servername parameter: openssl s_client -connect HOST:PORTNUMBER -servername CN – Rens Verhage Dec 09 '16 at 12:30
  • 2
    A shorter alternative to the `sed` command is `openssl x509`. Without any additional arguments, reads a PEM-formatted cert from stdin and prints it back to stdout in PEM format, ignoring anything that's not between the `-BEGIN CERTIFICATE-` and `-END CERTIFICATE-` lines. – Thomas Oct 03 '17 at 09:04
  • 1
    @Thomas True but that only returns 1 certificate. If you need multiple certificates, as in the chain, you need sed. For example: `openssl s_client -connect $server:$port -servername $server -showcerts 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > chain.pem` – mellow-yellow Jan 19 '18 at 20:41
  • 3
    openssl 1.1.0 and greater does support proxies now with the `-proxy` option (e.g. `-proxy 127.0.0.1:3000`). – Nick Spacek Dec 06 '18 at 12:14
  • @NickSpacek Is there also a way to make it work with a proxy that requires authentication? – sschuberth Apr 07 '20 at 09:08
  • Getting `s_client: must not provide both -connect option and target parameter` error when executing this. – Павле Jul 15 '20 at 16:35
78

I found the answer. Openssl provides it.

openssl s_client -connect ${REMHOST}:${REMPORT}

RainDoctor
  • 4,162
  • 3
  • 22
  • 25
  • 2
    also `openssl x509 -text < – mpapis Aug 01 '12 at 05:21
  • 2
    `sudo rm -f cert.pem && sudo echo -n | openssl s_client -connect localhost:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./cert.pem` courtesy of http://serverfault.com/questions/139728/how-to-download-ssl-certificate-from-a-website – pulkitsinghal Feb 19 '13 at 02:50
  • 2
    [this](http://superuser.com/a/641396/96477) accomplishes the same and skips the `sed` hack. – phs Dec 10 '13 at 07:13
  • This just checks one certificate, what if the service is part of a load balanced group of servers, of which each have a different certificate, possibly signed by a different root CA? Or in other words, a mitm attack might let this request go trough to the real site, and then direct other requests to his servers. Are there any ways to check this? And to get a list of all certificates an domain really has? – Jens Timmerman Apr 28 '14 at 10:37
  • @JensTimmerman _"Or in other words, a mitm attack might let this request go trough to the real site, and then direct other requests to his servers."_ That is not possible unless the man-in-the-middle has a valid certificate for the target server (or the client is silly does not check the server certificate). Evidently, if the server sometimes offers a different certificate you can only hope to probably eventually get them all by repeating connection attempts. – David Tonhofer Aug 04 '15 at 16:08
  • @pulkitsinghal why using -f for rm on a file? never do this dangerous action – djdomi Jul 27 '21 at 10:58
31

The GNUTLS client tool, gnutls-cli, can also make this easy:

gnutls-cli --print-cert www.example.com \
        < /dev/null \
        > www.example.com.certs

The program is designed to provide an interactive client to the site, so you need to give it empty input (in this example, from /dev/null) to end the interactive session.

bignose
  • 942
  • 10
  • 20
17
true | openssl s_client -connect google.com:443 2>/dev/null | openssl x509

this mode of openssl expects stdin, so we provide it via true |, this connects to the server specified in the -connect parameter. 2>/dev/null silences errors (optional), we can pass the whole output into the x509 parser, specifying /dev/stdin to use the shell pipe as the input file. And that will output just the -----BEGIN CERTIFICATE----- to -----END CERTIFICATE----- portion of the s_client output. You can redirect that to a file by adding > google.com.pem to the end of the command.


As best I can tell, this does not verify the certificate chain, it only can tell you what ssl identity the end server provides.

Der_Meister
  • 113
  • 6
ThorSummoner
  • 321
  • 4
  • 13
  • 3
    (1) this doesn't really improve the answers from 6 years ago (2) `x509` reads stdin by default so `-in /dev/stdin` is redundant (3) `s_client` verifies the server cert correctly chains to a local trust anchor (root) and is unexpired, but you've suppressed the information that would show this (4) it does NOT check for revocation (5) it checks the _name_ in the server cert only in 1.0.2 and then not by default (but you can easily check that yourself by looking at the cert afterward) – dave_thompson_085 Aug 11 '16 at 21:43
  • @dave_thompson_085, the question is how to download certificate, but not show chain information. I like the openssl x509 much better than sed in another answer. – Der_Meister Feb 22 '18 at 11:49
  • this works neatly, tks – Dee Apr 29 '20 at 02:33
  • works but it gives me the old cert, use gnutls-cli better – Dee Apr 29 '20 at 03:28
  • 1
    @datdinhquoc are there multiple certificates being served? I speculate that one tool is returning the first x509 certificate, and another the last. `gnutls-cli` in my experience shows all certificates served, i expect openssl would do the same. When handling multiple certificates it can be tricky, if you have python, I have an example x509-loader here that could be useful: https://stackoverflow.com/a/39313870/1695680 – ThorSummoner Apr 29 '20 at 08:27
11

based on @bignose answer, here is a self-contained version that fits well in e.g. a chef recipe:

sudo apt-get install gnutls-bin 
gnutls-cli --print-cert myserver.com </dev/null| sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > myserver.crt
sudo cp myserver.crt /usr/local/share/ca-certificates/myserver.crt
sudo update-ca-certificates
oDDsKooL
  • 471
  • 1
  • 4
  • 13
2

Alternative syntax using Ex and process substitution:

ex +'/BEGIN CERTIFICATE/,/END CERTIFICATE/p' <(echo | openssl s_client -showcerts -connect example.com:443) -scq > file.crt
kenorb
  • 5,943
  • 1
  • 44
  • 53