vendredi 24 juin 2016

How to verify ECDSA and RSA certificates [duplicate]

This question already has an answer here:

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