I have a certificate bundle .crt file.
doing openssl x509 -in bundle.crt -text -noout only shows the root certificate.
how do i see all the other certificates?
http://comments.gmane.org/gmane.comp.encryption.openssl.user/43587 suggests this one-liner:
openssl crl2pkcs7 -nocrl -certfile CHAINED.pem | openssl pkcs7 -print_certs -text -noout It indeed worked for me, but I don't understand the details so can't say if there are any caveats.
updated june 22:
for openssl 1.1.1 and higher: a single-command answer can be found here serverfault.com/a/1079893 (openssl storeutl -noout -text -certs bundle.crt)
To list just the subjects:
openssl storeutl -noout -text -certs \ $(openssl version -d | sed -E 's/OPENSSLDIR: "([^"]*)"/\1/')/cert.pem | \ grep Subject: crl2pkcs7 openssl storeutl -noout -text -certs bundle.crt The openssl storeutl app was added in OpenSSL 1.1.1.
The storeutl command can be used to display the contents fetched from the given URIs.
-noout prevents output of the PEM data-text prints out the objects in text form, like the -text output from openssl x509-certs Only select the certificates from the given URIJava's keytool does the trick:
keytool -printcert -v -file <certs.crt> Annotation: Windows doubleclick does not work. Windows reads only the first certificate in the keystore and automatically extends the trustchain from its built in certificate store.
Results:
.crt file are not shown.crt file. This may lead to wrong conclusions.Oneliner that displays a summary of every certificate in the file.
openssl crl2pkcs7 -nocrl -certfile CHAINED.pem | openssl pkcs7 -print_certs -noout It combines all the certificates into a single intermediate PKCS7 file, and then parses the information in each part of that file.
(The same as Beni's answer, but this gives shorter output, without the -text option).
example:
$ openssl crl2pkcs7 -nocrl -certfile bundled.crt | openssl pkcs7 -print_certs -noout subject=/C=NL/postalCode=5705 CN/L=City/street=Example 20/O=Foobar B.V./OU=ICT/OU=Wildcard SSL/CN=*.example.com issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA subject=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority subject=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority issuer=/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Roo -text flag. That way it spits out less info (most of which is probably useless to you) Following this FAQ led me to this perl script, which very strongly suggests to me that openssl has no native support for handling the nth certificate in a bundle, and that instead we must use some tool to slice-and-dice the input before feeding each certificate to openssl. This perl script, freely adapted from Nick Burch's script linked above, seems to do the job:
#!/usr/bin/perl # script for splitting multi-cert input into individual certs # Artistic Licence # # v0.0.1 Nick Burch <[email protected]> # v0.0.2 Tom Yates <[email protected]> # $filename = shift; unless($filename) { die("You must specify a cert file.\n"); } open INP, "<$filename" or die("Unable to load \"$filename\"\n"); $thisfile = ""; while(<INP>) { $thisfile .= $_; if($_ =~ /^\-+END(\s\w+)?\sCERTIFICATE\-+$/) { print "Found a complete certificate:\n"; print `echo \'$thisfile\' | openssl x509 -noout -text`; $thisfile = ""; } } close INP; Since there is no awk based solution:
awk '/BEGIN/ { i++; } /BEGIN /, /END / { print > ( i ".extracted.crt" ) }' ca-bundle for cert in *.extracted.crt; do openssl x509 -in $cert -text -noout; done The first command split bundle into certs by looking for BEGIN , and END lines. The second command loops through the extracted certs and shows them.
print > i >>> ".extracted.crt" <<<. On my macOS version of awk, it seems the filename expression needs parentheses: { print > ( i ".extracted.crt" ) }. Try this script: https://github.com/jkolezyn/cert_tree
It prints certificates in a pem bundle as a tree, built based on Subject and Issuer fields.
It prints a tree like this:
cert_tree.py -p ~/.certs/ca_list.pem ━ CorpRoot [1] ┣━ ServerCA [2] ┣━ example_cert [3] ┗━ example_2 [8] ━ RootCert [4] ┣━ example_cert3 [5] [EXPIRED on: 2019-06-03 13:26:21] ┣━ other [6] ┣━ other1 [7] [EXPIRED on: 2017-06-16 21:12:18] ┗━ AnotherOne [9] cert_tree.py -pe ~/.certs/mycert.pem ━ RootCert [3] [valid until: 2031-07-08 17:57:15] ┗━ IntermediateCert [2] [valid until: 2023-07-08 18:55:58] ┗━ UserCert [1] [valid until: 2023-09-17 13:33:00] This may not be pretty, or elegant, but it was quick and worked for me using bash on linux, and PEM formatted blocks in a ca-cert bundle file.
while read line do if [ "${line//END}" != "$line" ]; then txt="$txt$line\n" printf -- "$txt" | openssl x509 -subject -issuer -noout txt="" else txt="$txt$line\n" fi done < /path/to/bundle/file You can put it all one line, and adjust the openssl options to suit. I really wish there were a more elegant solution for this, but in this case I think finding the more elegant solution would have taken more time than hacking out the inelegant one.
In bash usually only one (long) line of code is needed :-)
tfile=$( mktemp -u ) && \ csplit -z -q -f "$tfile" bundle.crt '/----BEGIN CERTIFICATE-----/' '{*}' && \ find "${tfile%/*}" -name "${tfile##*/}*" -exec openssl x509 -noout -subject -in "{}" \; -delete awk -v cmd='openssl x509 -noout -text' \ '/BEGIN/{close(cmd)}; {print | cmd}' \ < bundle.pem | less Or to list only subjects and issuers:
awk -v cmd='openssl x509 -noout -subject -issuer' \ '/BEGIN/{close(cmd)}; {print | cmd}' \ < bundle.pem The way it works. print launches cmd and pipes lines to it one by one until it reaches the /BEGIN/ line. At which point it closes the pipe. The following print launches another cmd and starts piping lines to the freshly created pipe.
The credit goes to Stéphane Chazelas.
Here's an awk based solution that doesn't rely on intermediate files.
cat bundle.crt | awk '{ if ($0 == "-----BEGIN CERTIFICATE-----") cert="" else if ($0 == "-----END CERTIFICATE-----") print cert else cert=cert$0 }' | while read CERT; do echo "$CERT" | base64 -d | openssl x509 -inform DER -text -noout done It works by reading PEM blocks from stdin and concatenating each block to single base64 encoded line. Lines are then read, decoded and passed to openssl as DER encoded certificates.
cat bundle.crt | awk -v cmd="openssl x509 -subject -noout" '/-----BEGIN/ { c = $0; next } c { c = c "\n" $0 } /-----END/ { print c|cmd; close(cmd); c = 0 }'. awk <bundle.crt -v cmd="openssl x509 -whatever" '/^-----BEGIN/,/^-----END/ {print|cmd} /^-----END/ {close(cmd)}' and if there isn't extraneous material after the last PEM block (or you don't mind a spurious error message) you can omit the first range as well. (@Manav) I'd like to throw in the idiomatic perl commandline here:
perl -ne "\$n++ if /BEGIN/; print if \$n == 1;" mysite.pem If there's text then a slightly more robust tweak:
perl -ne "\$n++ if /^-----BEGIN CERTIFICATE-----\$/; print if \$n == 3 && /^-----BEGIN CERTIFICATE-----\$/.../^-----END CERTIFICATE-----\$/;" mysite.pem Just change the value of what n should be in the second statement to get the nth certificate.
@user1686 suggested another solution in https://superuser.com/questions/1599666/view-all-certs-in-a-pem-cert-file-full-cert-chain-with-openssl-or-another-comm
it is part of the GnuTLS stack.
certtool -i < multiplecerts.pem Small alteration to MadHatter's post to allow you to copy/paste straight to the CLI. I also included the MD5 hash, which is helpful when making sure the certs are correct. The stdin line returned is the md5 hash of the cert(s).
perl -e 'my $thisfile = ""; foreach (<>) { $thisfile .= $_; if($_ =~ /^\-+END(\s\w+)?\sCERTIFICATE\-+$/) { print "Found a complete certificate:\n"; print `echo "$thisfile" | openssl x509 -noout -text`; print `echo "$thisfile" | openssl x509 -noout -modulus | openssl md5`; $thisfile = ""; } }' < my_id_cert_and_ca_bundle.crt If you want to see a nice short concise output you use this version. Helpful if you are only checking that you have included all your cert, but not really checking usage/etc of the cert(s).
perl -e 'my $thisfile = ""; foreach (<>) { $thisfile .= $_; if($_ =~ /^\-+END(\s\w+)?\sCERTIFICATE\-+$/) { print "Found a complete certificate:\n"; print `echo "$thisfile" | openssl x509 -noout -serial -subject -dates -alias -issuer`; print `echo "$thisfile" | openssl x509 -noout -modulus | openssl md5` . "\n"; $thisfile = ""; } }' < my_id_cert_and_ca_bundle.crt Just in case your openssl version doesn't support all those flags here is some egrep you can use. Same thing as the first one but just pipe to egrep.
perl -e '..... ' < my_id_cert_and_ca_bundle.crt | egrep "Serial|Subject:|Not |Public-Key|^Cert|stdin|ssuer" To check the MD5 hash of the private key you can do the following.
openssl rsa -noout -modulus -in privateKey.key | openssl md5
Reference: SSL Shopper - Certificate Key Matcher