20

I use a mixture of Windows, Linux, and Macs and have noticed big differences in how each OS shows certificate details using the default tools available in each.

The way Windows displays certificate details is very succinct. Specifically, the certificate chain. See screenshot as an example. Windows certificate view And here it is again in Windows, but using the certutil tool. (okay it's inspecting a pfx but you get the point). Windows certutil view However on a Mac, this is how it shows the same cert in Keychain Access. Mac Keychain Access view As you can see, it doesn't have a nice hierarchical view that makes it easy to identify the certificate chain that Windows or certutil shows - at least not to my (possibly) untrained eyes. I also haven't figured out a way to show the certificate chain using openssl either, for example, the following command openssl x509 -in certificate.crt -text does not show a hierarchical chain - only the issuer. So is there a way to view a certificate's chain whether it be text or an image using openssl or native Mac tools?

[Edit]: I often create PFX files with the entire certificate chain (bar the root) for distribution within the company I work for. As part of the process I double check that the certs I've downloaded from the issuing CA are correct and that they're in the right order before passing it to openssl to mint the PFX. So to be clear, I'm questioning how to view the chain of a certificate I am working on locally on my computer.

KFM
  • 321
  • 1
  • 2
  • 6

6 Answers6

21

Use showcerts:

openssl s_client -showcerts -connect www.serverfault.com:443

Output with some information removed for brevity:

depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = *.stackexchange.com
verify return:1
---
Certificate chain
 0 s:/CN=*.stackexchange.com
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
-----BEGIN CERTIFICATE-----
*REMOVED*
-----END CERTIFICATE-----
 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3
-----BEGIN CERTIFICATE-----
*REMOVED*
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=*.stackexchange.com
issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: X25519, 253 bits
Bert
  • 2,863
  • 12
  • 13
  • 4
    Thanks for the answer - that definitely works when retrieving certs from existing websites. I should have clarified that I'm performing this against a CA-issued cert as part of a larger task of building a cert and its chain to be used for various functions. I'll edit my original question to reflect this. – KFM Apr 08 '20 at 01:33
  • This shows the certs _sent_ by the server which _should_ be a full chain except optionally omitting the root, per RFCs 6101 2246 4346 5246. In practice many servers did (and do) this wrong, and (thus) many reliers work around it. E.g. as you show Stack uses a LetsEncrypt cert and follows [their (current) advice](https://letsencrypt.org/2019/04/15/transitioning-to-isrg-root.html) to send the the Identrust/DST intermediate -- but my Firefox (68esr) ignores it and validates using the ISRG intermediate instead. RFC 8446 largely capitulates on this. – dave_thompson_085 Apr 08 '20 at 06:34
  • 3
    When trying to see a cert chain via -showcerts, watch for error message "verify error:num=20:unable to get local issuer certificate" and message "verify error:num=21:unable to verify the first certificate". This seems to mean that openssl doesn't recognize a certificate in the chain. When this happens it doesn't print the complete chain either, making it very difficult to puzzle out what's really going on. Fallback - use a browser that has a larger certificate store than your o/s provides. – chrisinmtown Oct 08 '20 at 01:19
  • Is there really no tool in entire OpenSSL which would simply display all the certificate in the chain with their name hashes? – Jari Turkia Aug 13 '21 at 09:35
  • @chrisinmtown thank you for that info, it explains the weirdness I was seeing between my linux shell and my browser. – refriedjello Mar 14 '22 at 22:59
  • "with their name hashes" is a worthy question of its own. Much punctuation, so clunk: ruby -we '$stdin.read().scan(/(^-----BEGIN CERTIFICATE-----\n(?:[^-].*\n)*----- END CERTIFICATE-----\n)/).each() { |cert| IO.popen(["openssl", "x509", "-subject_hash", "-noout"], "w") { |io| io.puts(cert); io.close(); }; }' – Martin Dorey Mar 14 '23 at 20:55
6

From a certificate bundle, you can use crl2pkcs7 that is not limited to a CRL:

openssl crl2pkcs7 -nocrl -certfile server_bundle.pem | openssl pkcs7 -print_certs -noout

From a live server, we need an additional stage to get the list:

echo | openssl s_client -connect host:port [-servername host] -showcerts | openssl crl2pkcs7 -nocrl | openssl pkcs7 -noout -print_certs

Use the -servername parameter in case your host serves multiple domains to get the right certificate.

Seki
  • 163
  • 1
  • 5
  • 1
    The "live server" syntax doesn't work for me without the addition of -certfile /dev/stdin (openssl 1.1.0l, 1.1.1n). crl2pkcs7 by default treats its input as a crl: -nocrl, no input. – Martin Dorey Mar 14 '23 at 20:42
  • @dave_thompson_085 I do not have the same experience: on a fedora, the given command on /etc/pki/tls/cert.pem shows only the subject and issuer for each cert of the bundle. Maybe related to the version, I am testing with openSSL 3.0 – Seki Aug 18 '23 at 11:54
  • You're right, I didn't think through `-noout` (and it's not version-dependent). It is true this displays info for the certs in the input file whether or not they are a chain as wanted by the Q -- but IF they are supplied by a CA they usually are. A notable exception presently is that LetsEncrypt is still supplying a 'chain' using the expired DST X3 root which is actually invalid and all modern clients actually replace, but LE plans to change this next year so this becomes less of an issue. – dave_thompson_085 Aug 23 '23 at 09:22
4

Just building upon Dave Thompson's answer, this is what you need to verify a certificate bundle/chain consisting of a intermediate and your own leaf:

# split your certificate chain into individual certificates
$ csplit -z -f individual- bundle.pem '/-----BEGIN CERTIFICATE-----/' '{*}'
1977
1850

# verify the chain and show the info in the chain
$ openssl verify -show_chain -untrusted individual-01 individual-00
individual-00: OK
Chain:
depth=0: CN = foobar.example.com (untrusted)
depth=1: C = NO, O = Buypass AS-983163327, CN = Buypass Class 2 CA 2 (untrusted)
depth=2: C = NO, O = Buypass AS-983163327, CN = Buypass Class 2 Root CA
oligofren
  • 641
  • 2
  • 8
  • 23
3

I can't help for other Mac tools including native. OpenSSL is a pure commandline product with no GUI, although of course you could use the library part (libcrypto) and write your own GUI.

From commandline, openssl verify will if possible build (and validate) a chain from the/each leaf cert you give it, plus intermediate(s) from -untrusted (which can be repeated), and possibly more intermediate(s) to a root (or anchor) in -trusted or -CAfile and/or -CApath or the default truststore, which is usually determined by your system or build but can be overridden with envvars. If this fails it gives an error. In 1.1.0 up if it succeeds and you also specify -show_chain, it displays the subject names of each cert -- which may or may not be enough to identify them. If you only have one cert per subject, that's fairly easy. If you have certs for the same subject from different issuers, looking at the next cert's name (except on the last, which is selfsigned unless you also use -partial_chain) is enough. If you have multiple certs for the same subject and issuer it's harder.

I often create PFX files with the entire certificate chain (bar the root) for distribution within the company I work for. As part of the process I double check that the certs I've downloaded from the issuing CA are correct and that they're in the right order before passing it to openssl to mint the PFX.

Except for the 'bar the root' part, you could reverse this workflow. Instead of manually building and checking the chain and then using it, you could use openssl pkcs12 -export -chain and provide the possible chain certs as (or in) -CAfile and/or -CApath. That would build the chain (actually validating it also as a side-effect) and create a PKCS12 containing only the privatekey and leaf plus valid chain if successful, but give an error and create no output if unsuccessful -- i.e. if you don't have a valid chain.

dave_thompson_085
  • 3,262
  • 1
  • 16
  • 16
  • Thanks for your suggestion! I wasn't fussed whether there was a GUI or not. It's the extracting of the information which was more pertinent to me. If `openssl s_client -showcerts` as suggested by @Bert could operate on a certificate on my local computer then that would suffice. As it stands today, it appears it cannot. – KFM Apr 14 '20 at 14:40
0

I know I am late. But I was looking for a solution for the same problem. After googling for 20 mins, figured out.

if the certificate chain is saved as Base64:

openssl pkcs7 -in certificate_chain.p7b -noout -text -print_certs

if the certificate chain is saved as DER:

openssl pkcs7 -inform DER -in certificate_chain.p7b -noout -text -print_certs
Abul
  • 1
0

Connect to server, obtain certificate and output in text format:

echo -n | openssl s_client -connect example.com:443 2> /dev/null | openssl x509 -text

echo -n will prevent openssl hanging.

ivanleoncz
  • 1,643
  • 6
  • 19
  • 32
  • That displays only the end-entity (server, leaf) cert, not any cert chain (nor even bundle) which is what this Q required. (And no, adding `-showcerts` doesn't help here; that includes the received but not validated chain in the output of `s_client`, but `x509` reads only the first cert and discards any others.) – dave_thompson_085 Aug 18 '23 at 05:01