Quitter le forum et retourner au site

OpenSSL & Infrastructure de Gestion de Clés - mode bazar

Vous avez un didactiel ou une astuce particulière concernant un logiciel, partagez votre expérience dans cette partie.
Avatar de l’utilisateur
le Manchot Masqué
Administrateur du site
Messages : 725
Inscription : lun. 26 mai 2008, 21:05
Distribution : Debian, Ubuntu
Niveau : Moitié plein !
Localisation : Guebwiller

OpenSSL & Infrastructure de Gestion de Clés - mode bazar

Message par le Manchot Masqué »

Attention : ce petit billet s'adresse à un public déjà avancé, qui veut configurer une Infrastructure de Gestion de clé en ligne de commande.

# Intro
Une IGC définit d'abord une Autorité de Certification (CA), laquelle joue le rôle d'organisme certificateur, qui va signer les requêtes qu'on lui présente avec sa clé privée, et émettre un certificat par requête, qu'on peut ensuite utiliser avec des serveurs web en mode https, ou d'autres logiciels à sécuriser...
Un certificat contient généralement les données du propriétaire (à qui appartient le certificat, avec sa localisation géographique partielle), la clé publique du propriétaire, et la signature de ces éléments par la clé privée de l'autorité. Quand vous allez sur le web vous connecter en https sur un site, votre navigateur ramène le certificat du site web, calcule l'empreinte des données du propriétaire + clé publique. Votre navigateur possède également une base de clés publiques d'organismes certificateurs, connus et réputés fiables, base régulièrement remise à jour. Il utilise alors la clé publique de l'organisme qui a émit le certificat, pour décoder la signature du certificat et la comparer avec l'empreinte calculée. S'ils correspondent, le cadenas est fermé et le site est réputé le bon. Comprenez qu'en faisant votre propre IGC, vous jouez finalement le rôle d'un organisme certificateur...

# Pour les paresseux
En mode graphique, xca est bien entendu plus rapide - MAIS il arrive qu'il corrompe son fichier de base de données, donc il faut à chaque modif bien revérifier sa sauvegarde... Malgré ces petits bugs de jeunesse, reconnaissons à cet outil qu'il permet un gain très appréciable de temps en production...

# Pour les courageux !
Mais revenons maintenant à notre ligne de commande.
On se place dans le cadre d'une machine nommée debiantpl qui génère donc nos certificats. On voudra notamment générer un certificat pour un serveur web apache2 installé sur la machine même, afin de pouvoir travailler via l'URL https://debiantpl.
On commence donc par faire un dossier /opt/igc1, on se place dans ce dossier, et on indique à openssl d'utiliser ce dossier comme référence pour ne pas toucher à la config par défaut dans /etc/openssl. Cela se fait en exportant simplement la variable d'environnement OPENSSL_CONF :

Code : Tout sélectionner

mkdir /opt/igc1
cd /opt/igc1
export OPENSSL_CONF=/opt/igc1
avant toute autre action.
Puis on prépare notre IGC :

Code : Tout sélectionner

touch index.txt
echo '01' > serial
mkdir certs private
chmod 700 private
On créé ensuite le fichier de configuration openssl.cnf :

Code : Tout sélectionner

#############################################################################
# Cette section définit l'autorité de certification par défaut et les
# paramètres de base de notre Infrastructure de Gestion de Clés

[ ca ]
default_ca = ca_main

[ ca_main ]
dir		= /opt/igc1
certificate	= $dir/cacert.pem
database	= $dir/index.txt
new_certs_dir	= $dir/certs
private_key	= $dir/private/cakey.pem
serial		= $dir/serial

default_crl_days	= 7 # délai de révocation
default_days		= 365 # durée de validité
default_md		= sha256 # algorithme utilisé pour les empreintes

policy		= ca_policy # attributs à fournir pour signer les requêtes
x509_extensions	= ca_x509_extensions # extensions à rajouter aux certificats par défaut

[ ca_policy ]
commonName		= supplied # obligatoire
stateOrProvinceName	= match # doit être identique au CA
countryName		= match # doit être identique au CA
emailAddress		= supplied # obligatoire
organizationName	= supplied # obligatoire
organizationalUnitName	= optional # optionnel

[ ca_x509_extensions ]
basicConstraints = critical, CA:false

#############################################################################
# Cette section explique comment générer les requêtes de certification (CSR)

[ req ]
default_bits	= 2048
default_keyfile	= /opt/igc1/private/cakey.pem # clé privée du CA
default_md	= sha256
distinguished_name	= req_dn # informations utilisées pour créer le DN
x509_extensions		= v3_ca  # extensions à rajouter aux certificats auto-signés
req_extensions		= v3_req # extensions à rajouter aux requêtes de certification

[ req_dn ]
commonName		= Nom
countryName		= Pays
countryName_default	= FR
stateOrProvinceName	= Province
stateOrProvinceName_default = Alsace
emailAddress		= Courriel
organizationName	= Organisation

[ v3_ca ]
basicConstraints	= CA:true

[ v3_req ]
basicConstraints        = CA:false

# Cf profils OpenSSL : https://superuser.com/questions/738612/openssl-ca-keyusage-extension
[ v3_webserver ]
subjectKeyIdentifier    = hash
#authorityKeyIdentifier  = keyid:always, issuer:always
basicConstraints        = critical, CA:false
keyUsage                = critical, nonRepudiation, digitalSignature, keyEncipherment, keyAgreement 
extendedKeyUsage        = critical, serverAuth
subjectAltName          = @alt_vpn_server

[ alt_vpn_server ]
DNS.1       = debiantpl
Notre IGC est prête.
On génère la clé privée de l'autorité de certification et son certificat auto-signé:

Code : Tout sélectionner

openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM
On génère la clé privée et la requête de certification qu'il faudra envoyer à l'autorité pour signature

Code : Tout sélectionner

openssl req -newkey rsa:2048 -keyout apache2.key.pem -keyform PEM -out apache2.req.pem -outform PEM -reqexts v3_webserver -verbose
openssl req -text -noout -verify -in apache2.req.pem
Remarquez l'option v3_webserver qui permet d'utiliser la section préconfigurée dans le fichier openssl.cnf.
On présente notre requête à l'autorité (CA) qui va la signer et générer notre certificat

Code : Tout sélectionner

openssl ca -in apache2.req.pem
Si tout s'est bien passé, on peut configurer notre hôte SSL pour apache2 dans /etc/apache2/sites-available/site-ssl.conf :

Code : Tout sélectionner

<VirtualHost *:443>
	ServerName debiantpl
	DocumentRoot /var/www/html
	SSLEngine on
	SSLCACertificateFile /opt/igc1/cacert.pem 
	SSLCertificateFile /opt/igc1/certs/01.pem
	SSLCertificateKeyFile /opt/igc1/apache2.key.pem 
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Puis on fait notre moulinette apache2 "classique" :

Code : Tout sélectionner

a2dissite 000-default
a2dissite default-ssl
a2enmod ssl
apachectl configtest
a2ensite site-ssl
systemctl restart apache2
Il faut encore rajouter le cacert.pem dans la liste des organismes certificateurs de Firefox (Paramètres > Vie privée et sécurité > Afficher les Certificats).
Si tout va bien, on peut enfin se connecter en https://debiantpl, sans avertissement, avec un cadenas fermé...

# Le coup de gueule
Avec openssl, on touche à un logiciel maître qui est au cœur de la sécurité informatique actuelle. Et là, force est de constater des surprises assez grotesques entre le logiciel réel et sa documentation...
Normalement par exemple, les extensions de requête de certification ne sont pas sensées, d'après la doc, être copiés dans le certificat final. Pourtant elles le sont dans la version Debian 12 ici utilisée ! Et pire encore, quand vous rajouter l'option -copy_extensions copyall, le phénomène est inversé : les extensions de la requête ne sont plus copiées dans le certificat final !
Là déjà, on se pose de vraies questions sur les mainteneurs de l'outil. Mais ce n'est pas la seule bizarrerie.
Le fait d'indiquer l'option DNS:debiantpl dans openssl.cnf est en fait une hérésie : Normalement, vous êtes sensés mettre dans le fichier de configuration les éléments "statiques", et pouvoir donner en argument de ligne de commande les éléments dynamiques. Et d'après le site officiel, il faut utiliser -addext pour pouvoir fournie les DNS alternatifs (alternate names ici). Et là, c'est le drame : dès que vous utilisez cette option (-addext "subjectAltName = DNS:debiantpl"), en enlevant préalablement les lignes concernées dans openssl.cnf, vous avez droit à une sympathique erreur

Code : Tout sélectionner

  Error adding extensions defined via -addext
4017FFFDE77F0000:error:0580008C:x509 certificate routines:X509at_add1_attr:duplicate attribute:../crypto/x509/x509_att.c:86:
Impossible de savoir de quel élément dupliqué on parle ici. Le mode "verbeux" d'openssl, servant de débugage, est en fait inexploitable ! Sur un petit outil lambda, on se dirait que les développeurs n'ont peut-être pas encore eu le temps de s'y mettre, soit. Mais sur un outil aussi stratégique et omniprésent, c'est impardonnable ! Là de toute évidence, il y a un problème de qualité. Ou alors la NSA est encore passée foutre le bordel... Si j'étais un gouvernement averti, j'irai quand même payer quelques ingénieurs pour étudier le code source - juste au cas où...
En attendant, on ne peut qu'espérer que les devs openssl vont un peu plus tester leur outil, mettre la doc à jour, et surtout rajouter les options qui manquent en mode ligne de commande.

# PS
Si vous n'avez pas encore mal à la tête en ayant lu tout ça, c'est que vous êtes gravement et irrémédiablement contaminé(e) par le virus GNU/Linux. Il n'existe à ce jour aucun remède connu pour vous soigner. Un bon café, ou un thé, devrait néanmoins vous libérer les neurones du cauchemar de la CLI. Bon rétablissement à vous !
Répondre