Notes pour la mise en place d’une autorité de certification avec OpenSSL

Note: Ce tuto est très vieux et risque de ne pas fonctionner correctement à l’heure où vous lisez ces lignes.

La majeure partie de l’article ci-dessous provient originellement du blog de Serianox, et est repartagé après quelques modifications et ajouts sous Licence Creative Commons Attribution – Pas d’Utilisation Commerciale – Partage à l’Identique 2.0 France
Licence Creative Commons

Par Serianox le lundi 10 mai 2010, 14:21 – (Lien permanent de la version originelle de Serianox)
Modifié par Zertrin, le dimanche 15 avril 2012.

Petite mise à plat des notes que j’avais prises lorsque je m’étais amusé avec OpenSSL, ou comment mettre en place une petite autorité de certification auto-signée.

Ceci n’est pas un guide, mais plutôt un petit walkthrough pour les personnes qui connaissent déjà bien les principes.

Procédure en partant de zéro : création d’une autorité de certification auto-signée et émission d’un certificat serveur signé par cette autorité :

Tout d’abord, mettons en forme nos répertoires

#~ mkdir -p /etc/ssl/local; cd /etc/ssl/local

Puis créons différents sous-répertoires, à savoir:

  • certs : pour les certificats serveur
  • conf : pour les fichiers de configuration
  • keys : pour les clefs serveur
  • newcerts : pour les certificats nouvellement crées
  • private : pour le certificat racine et sa clef
  • public : pour la clef publique
  • requests : pour les requêtes
#~ mkdir {certs,conf,keys,newcerts,private,public,requests}

Puis il nous reste à générer deux fichiers dans cette racine pour pouvoir commencer

#~ touch index.txt
#~ echo "00" > serial

Nous allons ensuite générer nos fichiers de configuration.

Le premier, conf/ca.cnf est celui utilisé lors de la génération de notre autorité de certification auto-signée

[req]
default_days = 3650
default_keyfile = private/ca.key.new
encrypt_key = yes
default_bits = 4096
distinguished_name = rdn
prompt = no
req_extensions = req_exts
x509_extensions = x509_exts

[rdn]
countryName = <>
stateOrProvinceName = <>
localityName = <>
organizationName = <>
organizationalUnitName = <>
emailAddress = <>
commonName = <>

[req_exts]

[x509_exts]
#nsComment =
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
issuerAltName = issuer:copy
basicConstraints = critical,CA:TRUE,pathlen:0
keyUsage = keyCertSign, cRLSign
subjectAltName = email:copy

Le second, conf/openssl.cnf représente les contraintes qui doivent être validées par toute requêtes avant d’être signées par l’autorité.

[ca]
default_ca      = CA_default

[CA_default]
dir = .
certs = $dir/certs
new_certs_dir = $dir/newcerts
database = $dir/index.txt
certificate = $dir/private/ca.crt
serial = $dir/serial
private_key = $dir/private/ca.key
default_days = 365
default_md = sha1
preserve = no
policy = policy_match
x509_extensions = x509_exts
copy_extensions = copy

[policy_match]
countryName = match
organizationName = optional
commonName = supplied
emailAddress = optional

[x509_exts]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
issuerAltName = issuer:copy
basicConstraints = critical,CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment

Le dernier, conf/server.cnf, est notre certificat de test qui sera signé par notre autorité. Il faut ensuite l’adapter à chaque usage.

[req]
default_days = 365
default_keyfile = keys/server.key.new
encrypt_key = yes
default_bits = 2048
distinguished_name = rdn
prompt = no
req_extensions = req_exts
x509_extensions = req_exts

[rdn]
countryName = <>
stateOrProvinceName = <>
localityName = <>
organizationName = <>
organizationalUnitName = <>
emailAddress = <>
commonName = <>

[req_exts]
subjectAltName = @alt_names

[alt_names]
email.1 = copy
DNS.1 = <>
DNS.2 = <>

Maintenant, commençons nos opérations.

Nous générons notre autorité de la façons suivante.

#~ openssl req -new -x509 -days 3650 -config conf/ca.cnf -out newcerts/ca.crt

Nous générons ensuite une requête pour notre serveur.

#~ openssl req -new -config conf/server.cnf -out requests/server.csr

Puis nous la vérifions.

#~ openssl req -in requests/server.csr -noout -text

Si tout semble en ordre, nous la signons

#~ openssl ca -config conf/openssl.cnf -days 365 -in requests/server.csr -out newcerts/server.crt

Une fois signé, on peut déplacer le nouveau certificat et renommer sa clef privée pour mettre en prod

#~ mv newcerts/server.crt certs/server.crt
#~ mv keys/server.key.new keys/server.key

Procédure pour mettre à jour un certificat existant :

Pour me faciliter les choses, j’ai préparé un petit script bash qui me permet de faire les choses dans l’ordre (à adapter bien évidemment selon votre configuration) : Voir en Annexe

Pour commencer, on édite le fichier de configuration propre à l’émission du certificat (le cas échéant, par exemple ajout de sous-domaines DNS…) :

#~ cd /etc/ssl/local/
#~ vim conf/server.cnf

On crée ensuite une nouvelle requête à partir du fichier de conf :

#~ openssl req -new -config conf/server.cnf -out requests/server.csr

On vérifie avant toute chose que la demande correspond bien à ce qu’on veut :

#~ openssl req -in requests/server.csr -noout -text

Si tout est bon, on commence par révoquer le certificat émis précedemment :

#~ openssl ca -config conf/openssl.cnf -revoke certs/server.crt

On signe ensuite la demande émise précédemment :

#~ openssl ca -config conf/openssl.cnf -days 365 -in requests/server.csr -out newcerts/server.crt

On déplace ensuite le nouveau certificat et sa clef dans les dossiers idoines :

#~ mv keys/server.key keys/server.key.bak
#~ mv keys/server.key.new keys/server.key
#~ mv certs/server.crt certs/server.crt.bak
#~ mv newcerts/server.crt certs/server.crt

Si nécessaire, on retire le mot de passe de la clef privée serveur :

#~ openssl rsa -in keys/server.key -out keys/server.key.insecure

Quelques manipulations supplémentaires

  • Suppression d’un mot de passe sur une clef
#~ openssl rsa -in keys/server.key -out keys/server.key.insecure
  • Ajout d’un mot de passe pour une clef
#~ openssl rsa -in keys/server.key.insecure -des3 -out keys/server.key
  • Conversion d’un PEM en DER
#~ openssl x509 -in certs/server.crt -inform pem -out certs/server.der -outform der
  • Conversion d’un DER en PEM
#~ openssl x509 -in certs/server.der -inform der -out certs/server.pem -outform pem
  • Génération d’un certificat serveur avec la clef privée incluse dedans
#~ cat certs/server.crt keys/server.key > server.pem

Enfin, quelques opérations de signature.

  • Exporter la partie publique d’une clef
#~ openssl rsa -in keys/server.key -pubout -out pub.key
  • Chiffrer avec la clef publique
#~ openssl rsautl -encrypt -in file -inkey pub.key -out file.sec
  • Déchiffrer avec la clef privée
#~ openssl rsautl -decrypt -in file.sec -inkey keys/server.key -out file
  • Hacher un gros fichier
#~ openssl dgst sha512 -out file.dst file
  • Signer un fichier
#~ openssl rsautl -sign -in file -inkey keys/server.key -out file.sgn
  • Verifier un hash
#~ openssl rsautl -verify -in file.sgn -pubin -inkey pub.key -out file

Et voila, c’est tout. En conclusion de cette longue énumération, je rappelle à toutes les personnes qui lisent ce genre de ligne que mettre en place une autorité de certification ne consiste pas seulement en générer les fichiers nécessaires ; avoir une politique de sécurité consiste déjà à protéger convenablement ses clefs privées.

Annexe

Voici le script bash que j’utilise pour mettre à jour mon certificat quand cela est nécessaire (renouvellement, ajout de sous-domaines…) :

#!/bin/bash

cont(){
  read -p "Continue? [yY to continue] " -n 1
  if [[ ! $REPLY =~ ^[Yy]$ ]]
  then
    exit 1
  fi
  echo
}

cd /etc/ssl/local/

echo "####### EDITING conf/server.cnf #######"
vim conf/server.cnf

echo "####### CREATING request/server.csr #######"
cont
openssl req -new -config conf/server.cnf -out requests/server.csr

echo "####### REVIEW of request/server.csr #######"
cont
openssl req -in requests/server.csr -noout -text

echo "####### REVOKING certs/server.crt #######"
echo "!!!!!!! IMPORTANT : if you continue, the current certificate WILL be revoked !!!!!!!"
cont
openssl ca -config conf/openssl.cnf -revoke certs/server.crt 

echo "####### SIGNING of conf/server.csr #######"
cont
openssl ca -config conf/openssl.cnf -days 365 -in requests/server.csr -out newcerts/server.crt

echo "####### MOVING new key #######"
cont
mv keys/server.key keys/server.key.bak
mv keys/server.key.new keys/server.key

echo "####### MOVING new cert #######"
cont
mv certs/server.crt certs/server.crt.bak
mv newcerts/server.crt certs/server.crt

echo "####### REMOVING password of keyfile #######"
cont
openssl rsa -in keys/server.key -out keys/server.key.insecure