3

I am trying to build a chain (or just get it from somewhere) from a certificate using OpenSSL, preferibly using the command line interface.

I have found some example in internet, but I am stuck at the question "Where do I get the CA issuer from the certificate?"

For example check this website openssl command cheatsheet, you will find the command

openssl s_client -showcerts -host example.com -port 443

to get the chain. You can try it using www.google.com instead of example.com. The output should give you the chain. Other websites use the same command, sooner or later...

So, I cannot get the chain directly from the certificate, but I should ask somewhere for the chain.

Now my problem is: where do I get the hostname, where I can send my request for the chain?

I had a look to two certificates.

  1. stackexchange.com
  2. google.com

Using OpenSSL, I can ask the Issuer using the command

openssl x509 -in certFile -noout -issuer

and I get respectively

  1. issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
  2. issuer=C = US, O = Google Trust Services, CN = GTS CA 1O1

Honestly, I do not know what to do with these results....

Then, investigating with the command

openssl x509 -text -in certFile

I have found the AIA extensions:

  1. CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
  2. CA Issuers - URI:http://pki.goog/gsr2/GTS1O1.crt

Ok in the first example, I can finally use the command

openssl s_client -showcerts -host http://cert.int-x3.letsencrypt.org/ -port 443

but with google, I do not know how to download the chain using openssl....I could use wget maybe, but I don't have the same format that I get from stackexchange...

So, finally, my questions:

  • How should do I work with these differences?
  • Is there a better way to get the chain from a certificate, without asking for the CA Issuer?
  • The CA Issuer is an extension, from AIA, and I think it is not mandatory, can I rely on it?
  • How can I get the CA Issuer using OpenSSL, without parsing the output myself? (something like openssl x509 -caIssuer -in certFile)

PS: What I try to achieve at the very end, is to validate a certificate, going through the complete chain, and checking all the OCSP or CRL for each certificate in the chain...If you have working example in C++, or just using OpenSSL CLI, I would be really grateful :)

EDIT:

What I am doing right now is creating the chain by myself.

Using the AIA extensions, I get the CA Issuer URI, download the CA Issuer certificate (convert to PEM if needed), and so on till I do not find a CA Issuer anymore. Then, probably it is a root CA.

After that, I manually collect all the pem and create the chain.

n3mo
  • 663
  • 8
  • 23
  • You can get the local issuer of a certificate using `openssl x509 -in cert.pem -noout -issuer`. eg: `echo '' | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -issuer`. – prateeknischal Oct 29 '19 at 18:32
  • And, yes you are right about `Authority Information Access`, it's a x509 extension and is not mandatory. – prateeknischal Oct 29 '19 at 18:33
  • Hi pikaynu. Thanks for your comment, but the question is: where did you get the "google.com" hostname in your example? not every certificate has a hostname in the subject, and I do not know where the certificate comes from... – n3mo Oct 31 '19 at 11:48
  • Hi n3mo, I am a bit confused on this, You would need atleast one cert of CN to start with. If it's a CN then you can get the cert. If you have the cert, you can get the CN from the subject or the SAN names. To answer, If you can get the whole chain without asking the CA, depends on what the server is presenting, ideally a server should present the whole chain till the Root CA, but if not, you need to parse the last cert and get it's issuer and maybe it's URL too. – prateeknischal Oct 31 '19 at 12:07
  • Hi pikaynu, the problem is, they are not always SSL certificates. In SSL certificates normally the CN is a website, but in my case the CN can be just a name...or an email...for example, in case of an email, I have CN the personal name of the person...or like the example I wrote, the name or a code of the company...at the end, after a discussion with my collegues, we decided to use the AIA extensions (even if not mandatory, they seem to be always present) and construct our own chain using the CA Issuer URI till we reach the root CA (that has no CA Issuer URI) – n3mo Nov 04 '19 at 07:38

3 Answers3

2

Know this is a bit old and it's been resolved but I thought I'd add a little script I write to parse out the CA Issuer from the x509 output:

getcaissuer() {
openssl x509 -noout -text -in $1 | awk '/^[ \t]+CA Issuers[ \t]+-[ \t]+URI:/ { print gensub(/^.*URI:(.*)$/,"\\1","g",$0); }'
}

# usage:  getcaissuer <certificate>
bng44270
  • 339
  • 2
  • 6
  • For people who are new to `awk` (like me): the middle chunk, `awk '/... CA Issuers...URI:/` finds the relevant line, and the last chunk, `{ print gensub(...); }` removes the beginning of that line (the 'CA Issuers - URI:' part, since it isn't part of what we want.) – pianoJames Sep 24 '21 at 17:42
0

It seems a lot of example in internet have in mind the SSL certificate. In SSL certificate, you can just connect to the website and download the complete chain. I think it is in the SSL protocol itself that the server should give you the complete chain.

I was doing it for SMIME certificates, that is why I was confused, because I can not use the same method they use for SSL certificates.

After speaking with my collegues and also comparing what I was doing with some similar programs found in internet, it seems the AIA extension is the correct way to do it. Maybe it is not mandatory in the X509 standard, but it seems widely used (I have never seen a SMIME certificate without the AIA extension).

Then, I create the chain manually, go back using the AIA extension till I find a certificate without such extension.

At this point, that should be a root certificate and I will try to just validate it, using the installed certificates in the machine.

(Of course, do not forget to check the revocation status through CRL or OCSP)

So far, everything is working well :)

n3mo
  • 663
  • 8
  • 23
0

Bonusing off of @bng44270's answer, this script will walk up the chain grabbing certs into the current directory

#!/bin/bash
# get-cert-chain.sh

machine=${1?No address passed}

machine_cert=${machine}.pem

# from https://stackoverflow.com/a/68637388/5401366
getcaissuer() {
    openssl x509 -noout -text -in $1 -ext authorityInfoAccess | awk '/^[ \t]+CA Issuers[ \t]+-[ \t]+URI:/ { print gensub(/^.*URI:(.*)$/,"\\1","g",$0); }'
}

if [ ! -e "${machine_cert}" ];
then
    openssl s_client -connect ${machine}:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM >${machine_cert}
fi;

cur_cert=$machine_cert

while :;
do
    # Get the first matching http line to grab the next cert loc
    nextca=$(getcaissuer ${cur_cert} | grep -m1 http)

    # ran out of stuff to retrieve
    [ -z "${nextca}" ] && break

    echo "Trying to get '${nextca}'"

    nextfile=$(basename ${nextca})

    if [ ! -e ${nextfile} ];
    then
        echo "Getting $nextca"
        curl -sO $nextca
    else
        echo "Found ${nextfile}"
    fi

    # Convert
    cat $nextfile | openssl x509 -inform DER -outform PEM > ${nextfile}.pem

    # down the rabbit hole...
    cur_cert=${nextfile}.pem

done
adrock20
  • 175
  • 1
  • 7