dimanche 26 juin 2016

How to verify ECDSA and RSA certificates

I am going to run acme-tiny on a central webserver in order to get the certificates for my two Nginx reverse proxies issued. The newly created certificates are published over https and available to the reverse proxies via download. I want the Nginx servers to check the newly created certificates before replacing the old certificates with the new ones. For this purpose, I wrote the following bash script, which is run on each Nginx server. I would like to know whether I missed something or whether you have ideas for improvement. Or is there a better way to realise this? #!/bin/bash set -e # Commands for deriving the public keys: # openssl ec -in ecdsa.key -pubout > ecdsa_public_key.pem # openssl rsa -in rsa.key -pubout > rsa_public_key.pem curl -O https://example.org/ecdsa.pem curl -O https://example.org/intermediate.pem curl -O https://example.org/rsa.pem # Are the certificates not expired? # Have they (ecdsa.pem, rsa.pem) been recently issued (validity >= 80 days)? openssl x509 -checkend 6912000 -noout -in intermediate.pem openssl x509 -checkend 6912000 -noout -in ecdsa.pem openssl x509 -checkend 6912000 -noout -in rsa.pem # Do the private keys and certificates belong together? openssl x509 -in ecdsa.pem -pubkey | sed -n '/-----BEGIN PUBLIC KEY-----/,/-----END PUBLIC KEY-----/p' | cmp - ecdsa_public_key.pem openssl x509 -in rsa.pem -pubkey | sed -n '/-----BEGIN PUBLIC KEY-----/,/-----END PUBLIC KEY-----/p' | cmp - rsa_public_key.pem # Is the certificate chain valid? openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt intermediate.pem openssl verify -CAfile intermediate.pem ecdsa.pem openssl verify -CAfile intermediate.pem rsa.pem # Are the certificates issued for the correct domain names? (openssl x509 -noout -subject -in ecdsa.pem | awk -F'CN=' '{print $2}' | awk -F'/' '{print $1}'; openssl x509 -noout -text -in ecdsa.pem | grep "^[[:space:]]*DNS:" | xargs | tr ' ' 'n' | grep ^DNS | sed 's/^DNS://' | sed 's/,$//')| sort | uniq | cmp - domains.txt (openssl x509 -noout -subject -in rsa.pem | awk -F'CN=' '{print $2}' | awk -F'/' '{print $1}'; openssl x509 -noout -text -in rsa.pem | grep "^[[:space:]]*DNS:" | xargs | tr ' ' 'n' | grep ^DNS | sed 's/^DNS://' | sed 's/,$//')| sort | uniq | cmp - domains.txt UPDATE 1: As I have stated I want to check every aspect of the certificate not just the validity of the certificate chain. It currently checks: the chains validity, whether private key and certificate match, whether the cert has been recently issued making replacement of the older cert necessary whether the cert has been issued for the desired domain names Therefore, it isn't a duplicate to the linked questions. And, I would like to know whether I have forgotten some check or whether there is space for improvement. Below is an update to the bash script. Beware I have not tested it thoroughly, yet. #!/bin/bash set -e # Execute the script: # ( cd /path_to_workdir && # su - james -c "./check_cert.sh https://www.example.org intermediate.pem ecdsa.pem ecdsa_pubkey.pem /etc/ssl/certs/ca-certificates.crt domains.txt pass.txt" && # su - james -c "./check_cert.sh https://www.example.org intermediate.pem rsa.pem rsa_pubkey.pem /etc/ssl/certs/ca-certificates.crt domains.txt pass.txt" && # cat ecdsa.pem intermediate.pem > /etc/nginx/ssl/ecdsa_bundle.pem ) && # cat rsa.pem intermediate.pem > /etc/nginx/ssl/rsa_bundle.pem ) && # /etc/init.d/nginx reload # Download URL, e.g. https://example.org URL=$1 # Intermediate certificate of certificate chain INTERMEDIATE=$2 # Issued certificate, e.g. ecdsa.pem CERT=$3 # Public key derived from private key via: # openssl ec -in ecdsa.key -pubout > ecdsa_pubkey.pem # openssl rsa -in rsa.key -pubout > rsa_pubkey.pem PUBKEY=$4 # ca-certificates file, e.g. /etc/ssl/certs/ca-certificates.crt CACERTS=$5 # Domains that the cert should cover DOMAINS=$6 # password-file.txt possible content: # machine example.org login james password H3Llo PASS=$7 # Download files if newer than local. if [[ $(curl -s -O --netrc-file "$PASS" -w "%{http_code}" -z "$CERT" "$URL/$CERT") -eq 304 ]]; then echo "No new certificate issued. Nothing to do!" exit 1 fi curl -s -O --netrc-file "$PASS" -z "$INTERMEDIATE" "$URL/$INTERMEDIATE" # Is the certificate chain valid? openssl verify -CAfile "$CACERTS" -untrusted "$INTERMEDIATE" "$CERT" # Do the private keys and certificates belong together? openssl x509 -in "$CERT" -pubkey | sed -n '/-----BEGIN PUBLIC KEY-----/,/-----END PUBLIC KEY-----/p' | cmp - "${PUBKEY}" # Has the Let's Encrypt certificate been recently issued (validity >= 80 days)? openssl x509 -checkend 6912000 -noout -in "$CERT" # Are the certificates issued for the correct domain names? (openssl x509 -noout -subject -in "$CERT" | awk -F'CN=' '{print $2}' | awk -F'/' '{print $1}'; openssl x509 -noout -text -in "$CERT" | grep "^[[:space:]]*DNS:" | xargs | tr ' ' 'n' | grep ^DNS | sed 's/^DNS://' | sed 's/,$//')| sort | uniq | cmp - "$DOMAINS" The code might be run via cronjob: 0 1 * * * /usr/local/bin/update_cert.sh >/dev/null 2>&1 The content of update_cert.sh might be: #!/bin/bash ( cd /path_to_workdir && su - james -c "./check_cert.sh https://www.example.org intermediate.pem ecdsa.pem ecdsa_pubkey.pem /etc/ssl/certs/ca-certificates.crt domains.txt pass.txt" && su - james -c "./check_cert.sh https://www.example.org intermediate.pem rsa.pem rsa_pubkey.pem /etc/ssl/certs/ca-certificates.crt domains.txt pass.txt" && cat ecdsa.pem intermediate.pem > /etc/nginx/ssl/ecdsa_bundle.pem ) && cat rsa.pem intermediate.pem > /etc/nginx/ssl/rsa_bundle.pem ) && /etc/init.d/nginx reload

Aucun commentaire:

Enregistrer un commentaire