Une autorité de certification ou mini PKI à la maison avec openssl

Pourquoi faire ? Pour délivrer vos propres certificats TLS et clients. Distribuer vos propres certificats pour votre famille, vos proches pour se connecter à vos sites web ou votre réseau. C’est un moyen d’authentification sur et sans mot de passe.

Le présent article vise à proposer le strict minimum pour ces deux usages.

Vous pouvez aussi lire ce tutoriel de Stefan H. Holek. Il propose des implémentations avec des AC intermédiaires ce qui est superflu pour un usage domestique.

Commençons par un peu théorie

Quoique vous pouvez passer ce chapitre et revenir dessus ultérieurement.

Un certificat est une carte d’identité. L’autorité de certification (AC) est l’autorité qui les délivre. Les serveurs web et les navigateurs, à partir de la connaissance de l’AC, savent vérifier un certificat et que celui qui le présente est le détenteur légitime.

De quoi est composé un certificat ?

  • une identité ou un nom,
  • la clé publique,
  • une période de validité
  • la signature du certificat,
  • des usages

L’ identité ou objet sous la forme d’un « distinguished name » (DN) : généralement représenté /C=FR/O=<Société>/OU=<valeur Libre>/L=<Ville>/CN=<nom de personne ou de serveur>. Où C signifie country (pays), O organization (organisation), OU unité organisationnelle (organizational unit), L locality (ville), CN Common Name (nom).

La clé publique est associée à une clé privée. Ces deux clés sont générées en même temps, intimement liées  et obtenues à l’aide d’un algorithme cryptographique asymétrique tel que RSA. Si on chiffre avec une des clés, on doit déchiffrer avec l’autre. Si elles sont suffisamment longue (ex 2048 bits), il n’est pas possible d’obtenir, dans un temps raisonnable, la clé privée à partir de la clé publique. La clé privée doit être jalousement protégée.

La période de validité débute généralement à l’émission du certificat et dure quelques années. Dans notre cas c’est d’assez peu d’importance.

La signature du certificat est le truc qui permet de valider l’origine du certificat. Il est obtenu par le chiffrement du condensat du certificat par la clé privée de l’AC.

Les algorithmes (ex SHA-2)  qui génère les condensats (hash) sont des fonctions à sens unique. Il n’est pas possible dans un temps raisonnable de construire un message à partir d’un condensat. SHA-1 n’est plus sur. Des spécialistes l’ont récemment démontré.

Optionnellement, on peut préciser les usages (authentification, signature, chiffrement,..) dans notre cas simple nous ne les préciserons pas.

Qu’allons nous faire ?

Dans l’ordre nous allons :

  • fabriquer la mairie qui va délivrer les cartes d’identité : générer l’autorité de certification,
  • créer une première demande de carte d’identité : une requête de certification ou CSR,
  • valider la demande et créer la première carte d’identité : signer la requête de certification,
  • ranger la nouvelle carte dans son portefeuille : stocker l’AC et le certificat dans son magasin sur votre machine.

Que vous faut-il ?

Du point de vue minimaliste, il ne vous faut qu’un ordinateur avec une librairie openssl et quelques dizaines de Ko de disponibles sur le disque.

La clé privée de votre future AC est la clé de voûte de l’ensemble. Si un tiers malintentionné s’en empare, l’édifice s’écroule. Partant du principe qu’un ordinateur sur est un ordinateur éteint, vous pouvez dédié une petite VM à votre AC que vous allumez pour l’occasion. Sinon, un compte dédié fera l’affaire.

Dans l’exemple ci-dessous, je vais partir d’une distribution debian. Sur la distribution que j’ai utilisée, le package openssl est déjà installé.

Préparer l’environnement

Création de l’utilisateur ac

Je crée mon utilisateur ac. Sous root :

root@deby:~# adduser ac
Ajout de l'utilisateur « ac » ...
Ajout du nouveau groupe « ac » (1001) ...
Ajout du nouvel utilisateur « ac » (1001) avec le groupe « ac » ...
Entrez le nouveau mot de passe UNIX :
Retapez le nouveau mot de passe UNIX :
passwd : le mot de passe a été mis à jour avec succès
Modification des informations relatives à l'utilisateur ac
Entrez la nouvelle valeur ou « Entrée » pour conserver la valeur proposée
 Nom complet []: Autorite de certification
 N° de bureau []:
 Téléphone professionnel []:
 Téléphone personnel []:
 Autre []:
Cette information est-elle correcte ? [O/n]O

Je me connecte sous ac. Le umask est à 022 par défaut tous les utilisateurs et ceux du groupe ac peuvent lire les fichiers que l’utilisateur ac crée. Pas top du point de sécurité. j’édite (avec vi, emacs ou nano) le fichier .profile. Je dé-commente la ligne umask et change la valeur :

umask 077

Je recharge le .profile, puis je teste :

ac@deby:~$ . .profile
ac@deby:~$ umask
0077
ac@deby:~$ touch toto
ac@deby:~$ ls -l toto
-rw------- 1 ac ac 0 mai 5 22:50 toto
ac@deby:~$ rm toto
ac@deby:~$

création du fichier de configuration pour openssl

Il en existe un modèle sous /etc/ssl. J’en faite une copie.

ac@deby:~$ cp /etc/ssl/openssl.cnf monac.cnf

La section CA_default définit notre autorité de certification. Ce que j’y ai changé :

dir             = /home/ac
...
default_days = 1096 # how long to certify for
default_crl_days= 366 # how long before next CRL
default_md = SHA256 # use public key default MD
...
policy          = policy_anything

dir  est le répertoire de base.

default_days est la durée de validité du certificat, je propose 3 ans.

default_crl_days est la durée de validité de la CRL

default_md positionné à SHA256 est l’algorithme de condensat SHA-2 à 256 bits (c’est l’usage).

policy : les contraintes imposées sur les différents champs du certificat. Ici seul le ‘Common name’ est requis et l’adresse e-mail est optionnel.

La CRL est la liste des certificats révoqués identifiés par leurs numéros de série, signée par l’autorité de certification. Dans le cas où une clé privée d’un certificat est compromise, il convient de le déclarer inutilisable. Pour une utilisation domestique, je conseille de ne pas utiliser la révocation, mais plutôt de ne plus attribuer de droit à un certificat douteux. Pour le malheureux ou l’imprudent dont la clé privée est compromise, je conseille de lui en re-générer un autre avec un nom différent.

Dans la section policy_anything je commente les champs non-désiré et elle devient :

[ policy_anything ]
#countryName = optional
#stateOrProvinceName = optional
#localityName = optional
#organizationName = optional
#organizationalUnitName = optional
commonName = supplied
emailAddress = optional

Dans la section req, je commente la ligne des attributs et extensions :

#attributes = req_attributes
#x509_extensions = v3_ca # The extentions to add to the self signed cert

 

J’aligne la section req_distinguided_name , je commente tous les champs non désirés et  elle devient :

[ req_distinguished_name ]
#countryName = Country Name (2 letter code)
#countryName_default = AU
#countryName_min = 2
#countryName_max = 2

#stateOrProvinceName = State or Province Name (full name)
#stateOrProvinceName_default = Some-State

#localityName = Locality Name (eg, city)

#0.organizationName = Organization Name (eg, company)
#0.organizationName_default = Internet Widgits Pty Ltd

# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd

#organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =

commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_max = 64

emailAddress = Email Address
emailAddress_max = 64

J’en ai terminé avec le fichier de configuration, on sauvegarde et on sort. Le résultat est .

Dans la section ac, plusieurs répertoires et fichiers sont référencés. Il faut les créer.

ac@deby:~$ mkdir certs
ac@deby:~$ mkdir crl
ac@deby:~$ touch index.txt
ac@deby:~$ mkdir newcerts
ac@deby:~$ echo 00 > serial
ac@deby:~$ echo 00 > crlnumber
ac@deby:~$ mkdir private

Générer l’autorité de certification

Cela se passe en trois étape. Je commence par générer le secret du tampon magique, je crée mon dossier de demande de validation de mon tampon et je me l’auto-valide. C’est qui le chef ?

Je pense très fort à un mot de passe compliqué (mdp-ca par la suite) qui va protéger la clé privée de mon AC. Ce mot de passe ne doit pas être oublié, il sera demandé à chaque fois que je signerai un certificat. Je demande à générer une bi-clé chiffrée en AES 256, d’une longueur de 2048 bits stockées dans le fichier private/cakey.pem.

ac@deby:~$ openssl genrsa -aes256 -out private/cakey.pem 2048
Generating RSA private key, 2048 bit long modulus
..........+++
............................+++
e is 65537 (0x10001)
Enter pass phrase for private/cakey.pem:
Verifying - Enter pass phrase for private/cakey.pem:

En fait c’est un fichier texte, vous pouvez regarder :

ac@deby:~$ cat private/cakey.pem
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,48169FC778C3D541B1297B4D7E078FB5

/XCoh/N8K+mdrud53f7Rue8YC1YzMSwSDIRNc0konlNh2l5U0W1+I/BVoWjzQAF8
rdqIYVIhlL3QdwvZyAvn4FEX8FhRDXWpOHlyD0WrZQfaj81NyHZ4M3IvNdMNRCpu
...
4Mi9lwn2StNPg82kDLf5cyxv9V5taep59TP4xkmHGaCosEASNfe7iDL4KTQbrMk1
-----END RSA PRIVATE KEY-----

Je crée la requête de certification (le mot passe utilisé est mdp-ca) :

ac@deby:~$ openssl req -new -config monac.cnf -out cacert.csr -key private/cakey.pem
Enter pass phrase for private/cakey.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (e.g. server FQDN or YOUR name) []:A la maison
Email Address []:marc@alamaison.com

Je signe moi-même ma requête. Je crée un certificat x509 à partir de la requête cacert.csr, signée avec la clé private/cakey.pem d’une validité de 30 ans et je le stock dans cacert.pem, avec toujours le même mot de passe :

ac@deby:~$ openssl x509 -req -days 10958 -in cacert.csr -signkey private/cakey.pem -out cacert.pem
Signature ok
subject=/CN=A la maison/emailAddress=marc@alamaison.com
Getting Private key
Enter pass phrase for private/cakey.pem:

Le fichier cacert.csr peut être détruit et c’est fini mon AC est créée.

Je peux relire le certificat :

ac@deby:~$ openssl x509 -noout -in cacert.pem -text

Générer un certificat

Pour générer un certificat, je déroule des étapes identiques : je génère les secrets, je créé mon dossier et la mairie le valide.

Le mot de passe protégeant la bi-clé sera appelé par la suite (mdp-user1)

ac@deby:~$ openssl genrsa -aes256 -out certs/user1.key 2048
Generating RSA private key, 2048 bit long modulus
.......................................................+++
..........+++
e is 65537 (0x10001)
Enter pass phrase for certs/user1.key:
Verifying - Enter pass phrase for certs/user1.key:

Je crée la requête de certification, avec mdp-user1 :

ac@deby:~$ openssl req -new -config monac.cnf -key certs/user1.key -out certs/user1.csr
Enter pass phrase for certs/user1.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (e.g. server FQDN or YOUR name) []:Mon premier utilisateur
Email Address []:u1@alamaison.com

Je signe la requête avec l’AC (mdp-ca)

ac@deby:~$ openssl ca -in certs/user1.csr -out certs/user1.cert -config monac.cnf
Using configuration from monac.cnf
Enter pass phrase for /home/ac/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
 Serial Number: 0 (0x0)
 Validity
 Not Before: May 6 21:43:42 2017 GMT
 Not After : May 6 21:43:42 2020 GMT
 Subject:
 commonName = Mon premier utilisateur
 emailAddress = u1@alamaison.com
 X509v3 extensions:
 X509v3 Basic Constraints:
 CA:FALSE
 Netscape Comment:
 OpenSSL Generated Certificate
 X509v3 Subject Key Identifier:
 23:1C:0D:E9:C8:F5:4C:E3:2E:76:D9:F9:88:43:01:A9:DD:F7:EE:E2
 X509v3 Authority Key Identifier:
 DirName:/CN=A la maison/emailAddress=marc@alamaison.com
 serial:DA:BB:D5:B1:11:4C:F4:75

Certificate is to be certified until May 6 21:43:42 2020 GMT (1096 days)
Sign the certificate? [y/n]:Y


1 out of 1 certificate requests certified, commit? [y/n]Y
Write out database with 1 new entries
Data Base Updated

Et là je note que le fichier serial a été incrémenté et que le fichier index.txt a été mis à jour.

La dernière étape consiste à rassembler les différents éléments nécessaires à un utilisateur en un seul fichier au format PKCS#12, en utilisant mdp-user1. Le nouveau mot de passe créé devra être transmis à l’utilisateur avec le fichier p12.

ac@deby:~$ openssl pkcs12 -export -inkey certs/user1.key -in certs/user1.cert -certfile cacert.pem -out certs/user1.p12
Enter pass phrase for certs/user1.key:
Enter Export Password:
Verifying - Enter Export Password:

Intégration du certificat à votre navigateur

Sur Chromium sous linux, je clique sur les trois petits points en haut à droite, je vais dans settings. Puis, je clique sur « advanced settings », là un bouton « manage certificates… » apparaît. Après avoir cliquer sur ce bouton, une fenêtre s’ouvre, je clique sur « import… », je sélection mon fichier .p12 (user1.p12) , le mot de passe à saisir est celui généré lors de l’export. Je viens d’importer mon certificat et celui de l’autorité de certification.

Copie écran certificat client copie d'écran AC

Sous windows, il suffit de double-cliquer sur le fichier .p12 pour l’importer. Sous iOS, le toucher suffit.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *