202

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?

14 Answers 14

261

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)

14
  • 20
    This is the best answer - I won't even post my over-kill Python solution! Leave out the "-text" to just get subject/issuer info for each certificate.
    – Chris Wolf
    Mar 28, 2016 at 23:03
  • 1
    Isn't this for pkcs7 format, whereas the question is about x509 format bundles? Feb 8, 2018 at 2:16
  • 5
    It only uses pkcs7 as intermediate. Input is concatenated PEM. Feb 8, 2018 at 7:00
  • 4
    For the benefit of posterity, that's "CRL 2", not "CR 12" -- crl2pkcs7 Dec 3, 2019 at 23:01
  • 2
    This answer is outdated. The (now) correct answer is below at serverfault.com/a/1079893/22361
    – Ex Umbris
    Jun 26, 2022 at 0:27
46

Java'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:

  1. All beyond the first certificate in the .crt file are not shown
  2. You may get a different trustchain displayed than you have in the .crt file. This may lead to wrong conclusions.
1
  • 1
    Thanks for clarifying the windows thing. This was really confusing the hell out of me
    – Nick.Mc
    Dec 8, 2017 at 5:17
39
openssl storeutl -noout -text -certs bundle.crt
Paraphrasing from the OpenSSL documentation:

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 URI
0
34

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
3
  • This needs better explanations
    – Sven
    Apr 19, 2018 at 9:09
  • 2
    ...such as how this is different from serverfault.com/a/755815/27515
    – larsks
    Oct 8, 2020 at 10:20
  • 1
    @larsks It's the same except for not having the -text flag. That way it spits out less info (most of which is probably useless to you)
    – JelteF
    Nov 23, 2020 at 14:25
22

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;
6

Since there is no awk based solution:

$ cat ca-bundle | awk '/BEGIN/ { i++; } /BEGIN/, /END/ { print > i ".extracted.crt" }'
$ ls *.extracted.crt | while read cert; 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.

2
  • 2
    The print redirection feature in awk is available in gawk and nawk but not in basic awk. And so, this would work on Linux (gawk is linked as awk), but might not on OS X which has basic awk.
    – sudocracy
    Nov 9, 2015 at 1:34
  • print (and printf) redirection in awk is POSIX, and while I don't have Mac, it works in FreeBSD 10 awk and Solaris 11 both oawk and nawk, as well as GNU awk. But see serverfault.com/a/754668/216633 (and comments) for versions that don't need temp files. Apr 25, 2021 at 11:53
4

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.

4

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]
3

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
1

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.

2
  • 3
    Just for fun: 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 }'.
    – Manav
    May 30, 2016 at 14:11
  • 2
    Simpler: 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) Apr 25, 2021 at 11:48
1

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.

1

@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
1
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.

0

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .