📜 ⬆️ ⬇️

We pull the chain of certificates

Yesterday, apparently, there was a https sabbath, and customers began to send certificates in large quantities. Of course, neither root nor intermediate was attached, and a request to send them caused the same perplexity as the oncoming traffic of a blonde on a one-way road.

On the 4th certificate, laziness began to pull them by hand (and I'm lazy by nature), so I sketched the publisher's “scooter” and formed a chain file for feeding nginx.
Surely he is not perfect and tested only on the fifteen certificates, but what they are rich with.

A lot has been said about the x.509 device (including on the habr), so I will not repeat.
')
Below is just a step-by-step instruction for getting the chain interspersed with a little squeeze from theory and nothing more.

All of the following is true for:

Hidden text
$ uname -or FreeBSD 10.3-STABLE $ openssl version OpenSSL 1.0.2h 3 May 2016 $ `echo $SHELL` --version tcsh 6.18.01 (Astron) 2012-02-14 (x86_64-amd-FreeBSD) options wide,nls,dl,al,kan,sm,rh,color,filec $ /usr/local/bin/bash --version GNU bash, version 4.3.25(1)-release (amd64-portbld-freebsd10.0) 


So, suppose we have a site PEM certificate. For example, we take the certificate ya.ru (not only to ping it).

 $ echo | openssl s_client -connect ya.ru:443 | openssl x509 -certopt ca_default -out ya.pem -outform PEM 

In addition to the most coded request, version, signature, etc. It has a number of extensions. One of which is the Authority Information Access and we are interested in:

 $ openssl x509 -in ./ya.pem -noout -text | grep 'Authority Information Access' -A 2 Authority Information Access: OCSP - URI:http://yandex.ocsp-responder.com CA Issuers - URI:http://repository.certum.pl/ycasha2.cer 

The CA Issuers parameter contains the next certificate in the chain. As a rule, this certificate is either in PEM or DER (as in our case) formats.

 $ fetch http://repository.certum.pl/ycasha2.cer 

In fact, the PEM format is no more than a base64 DER representation and you can get PEM from DER by making base64 ./ycasha2.cer ./ycasha2.pem and framing the encoded text "----- BEGIN CERTIFICATE -----", "- --- END CERTIFICATE ----- " . However, it is more logical and easier to do this conversion using openssl :

 $ openssl x509 -inform der -in ./ycasha2.cer -out ./ycasha2.pem 

We go further and look at the following certificate in the chain:

 $ openssl x509 -in ./ycasha2.pem -noout -text | grep 'Authority Information Access' -A 2 Authority Information Access: OCSP - URI:http://subca.ocsp-certum.com CA Issuers - URI:http://repository.certum.pl/ctnca.cer 

 $ fetch http://repository.certum.pl/ctnca.cer 

We transform it too:

 $ openssl x509 -inform der -in ./ctnca.cer -out ./ctnca.pem 

In this certificate (since it is the root) there is no Authority Information Access extension:

 $ openssl x509 -in ./ctnca.pem -noout -text | grep 'X509v3 extensions' -A 6 X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE X509v3 Subject Key Identifier: 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 X509v3 Key Usage: critical Certificate Sign, CRL Sign 

That is, on it and finish pulling the chain. It remains to collect all this in a chain file:

 $ cat ya.pem ycasha2.pem ctnca.pem > chain0.pem 

It seems that now you can put (if there is a Private Key), but I’ll dwell on a couple of nuances.
Installing your certificate on your Yandex check it:

 $ echo | openssl s_client -connect ya.ru:443 | grep Verify Verify return code: 0 (ok) 

Everything is good, but this is only because the default hashes of certificates -Capath, -CAfile of my openssl are found. If we change them, either they are not available on the default paths, or they are simply outdated, or someone has an openssl version with a bug in which the default CApath did not “cling” (if I'm not mistaken from 1.0.1c to 1.0.1e), we get trouble in the form of:

 $ echo | openssl s_client -connect ya.ru:443 -CApath . | grep Verify Verify return code: 20 (unable to get local issuer certificate) 

It is clear that there is no one to sign the root certificate, so our system needs to be allowed to trust it. To do this, you can create a piece of storage. When searching for the required certificate, openssl tries to find it using the certificate hash.

 $ openssl x509 -noout -hash -in ./ctnca.pem 48bec511 

 $ ln -s `pwd`/ctnca.pem `pwd`/48bec511.0 

And now our system trusts ya.ru:

 $ echo | openssl s_client -connect ya.ru:443 -CApath . | grep Verify DONE Verify return code: 0 (ok) 

Of course, it’s lazy to do it with your hands each time, so we automate slightly:

$ cat ./issuers.sh
 #!/usr/local/bin/bash cmd_grep='/usr/bin/grep ' cmd_openssl='/usr/bin/openssl ' cmd_cut='/usr/bin/cut ' cmd_fetch='/usr/bin/fetch ' tmp_der='tmp.der' tmp_cert='tmp.cert' #------------------------------------------------------------------------------ usage () { #printf "function ${FUNCNAME}\n" printf "Error!\nUsage:\t\"$0 certificate.pem\"\n" exit 1 } #------------------------------------------------------------------------------ if [ "X$1" = "X" ] then usage else cp $1 $tmp_cert chain_cert="chain.pem" fi i=0 while : do issuer=`$cmd_openssl x509 -in $tmp_cert -noout -text | $cmd_grep 'CA Issuers' | $cmd_cut -d : -f 2,3` if [ "X$issuer" != "X" ] then echo $i echo $issuer tmp_pem=$1$i.pem $cmd_fetch $issuer --output=$tmp_der is_pem=`$cmd_grep -c CERTIFICATE $tmp_der` printf "IS PEM:\t[$is_pem]\n" #echo "$tmp_der -> $tmp_pem" if [ $is_pem -ne 0 ] then echo "PEM($tmp_der) -> PEM($tmp_pem)" cp -f $tmp_der $tmp_pem else echo "DER($tmp_der) -> PEM($tmp_pem)" echo "$cmd_openssl x509 -inform der -in $tmp_der -out $tmp_pem" $cmd_openssl x509 -inform der -in $tmp_der -out $tmp_pem fi cp $tmp_pem $tmp_cert let "i+=1" #sleep 2 else break fi done if [ $i -gt 0 ] then echo "cat ./$1* > $chain_cert" cat ./$1* > $chain_cert printf "Certificate chain:\n" ls -l $chain_cert #ls | grep -Ev ^ya.pem$ | xargs rm fi 


We carry out:

 $ ./issuers.sh ./ya.pem 0 http://repository.certum.pl/ycasha2.cer tmp.der 100% of 1196 B 16 MBps 00m00s IS PEM: [0] DER(tmp.der) -> PEM(./ya.pem0.pem) /usr/bin/openssl x509 -inform der -in tmp.der -out ./ya.pem0.pem 1 http://repository.certum.pl/ctnca.cer tmp.der 100% of 959 B 13 MBps 00m00s IS PEM: [0] DER(tmp.der) -> PEM(./ya.pem1.pem) /usr/bin/openssl x509 -inform der -in tmp.der -out ./ya.pem1.pem cat ././ya.pem* > chain.pem Certificate chain: -rw-r--r-- 1 root wheel 5842 Jun 30 15:46 chain.pem 

We verify the readings:

 $ md5 chain0.pem ; md5 chain.pem MD5 (chain0.pem) = 6d32b0798d48d14764cd26cc4f730444 MD5 (chain.pem) = 6d32b0798d48d14764cd26cc4f730444 

Something like this ... Of course, the script is not universal, everything hastily in anticipation of a great shukher. Comments / wishes are welcome, but I can hardly answer - we have a denomination with a madhouse here (in Belarus).

Source: https://habr.com/ru/post/304458/


All Articles