Certificats

Published: 24-01-2016

Updated: 07-02-2018

By: Maxime de Roucy

tags: openssl tls

Concepts généraux

Les certificats sont basés sur le principe de la cryptographie asymétrique.

Généralement, lorsqu’on parle de certificat, on parle de certificat x509. Mais il existe d’autre technologie de certificat, e.g. une clé gpg publique peut être considéré comme un certificat. Dans la suite de cette article je ne parle que de certificat x509.

Un certificat est composé d’une clé publique, de données et d’une signature portant sur les deux éléments précédent (un hash des éléments en vérité). À chaque certificat est donc associé une clé privé. Attention, la clé privé n’est pas inclue dans le certificat, c’est un fichier séparé et secret qui est conservé par l’entité ayant émit le « Certificat Signing Request » (CSR) à l’origine du certificat. Seul la clé publique correspondant à cette clé privé est inclue dans le certificat.

Les données contenu dans le certificat inclue les informations généralement indiquées à la création d’un certificat :

Il existe plusieurs type de certificats, pour serveurs web, pour serveur xmpp, des certificats clients pour s’authentifier. Ce qui différenti ces certificat c’est le type de données (attributs) qu’il contient. Le « Subject » est un attribut définissant l’élément validé par le certificat, le « Issuer » définit l’entité ayant délivré (signé) le certificat, il correspond au « Subject » du certificat dont la clé privé à servit à signer le certificat courant. Subject et Issuer sont des chaines caractère appelée « Distinguished Name » (DN) formé d’un ou plusieurs éléments, « Common Name » (CN), « Organisation » (O), « Country » ©, « Locality » (L)… Pour un certificat utilisateur, le CN contiendra souvant une adresse mail, alors que pour un certificat de serveur web le CN contiendra le nom de domaine (vhost) à la charge de celui-ci.

Une PKI est un outil/un système permettant de gérer le cycle de vie des certificats (création, révoquation…). Le tutorial PKI sur readthedocs est très bien fait et je vous encourage à le lire.

EJBCA
est une PKI libre écrite ne Java.
easyrsa
est une PKI libre et très simple fournie avec openvpn.

Les certificat les plus courant servent à authentifier des serveur web. Cela permet à l’utilisateur de vérifier que le site web sur lequel il surf est bien celui qu’il prétend être.

Les navigateur web possède une liste de certificat « racine » considérés comme digne de confiance. Lorsque le navigateur arrive sur une page web en HTTPS il reçoit le certificat du serveur web de la page en question (et potentiellement des certificats intermédiaires, mais j’en parlerais plus tard). Le navigateur vérifie s’il possède dans sa liste de certificat de confiance, un certificat dont l’attribut « Subject » correspond l’attribut « Issuer » du certificat envoyé par le serveur web (en fait il fait une comparaisont du hash de ces éléments). S’il n’en trouve aucune, le site est considéré comme douteux et alerte l’utilisateur.

Si un certificat racine correspondant est trouvé. Le navigateur fait un hash des données du certificat de serveur web et déchiffre la signature du certificat du serveur web grace à la clé publique du certificat de confiance. Si ces deux opérations donnent le même résultat c’est que le certificat du serveur web à bien été signé par la clé privé de l’autorité de certification ayant émit le certificat racine (la clé privé dont la clé publique est contenu dans le certificat racine). Le site web est donc considéré comme « de confiance ».

Une autorité de certification (CA) est une entité qui délivre des certificats. Si une personne veut un certificat, elle créé une clé privé et un CSR et l’envoie à l’autorité de certification. Un CSR et une demande de signature de certificat, il s’agit en gros du certificat non encore signé. L’autorité de certification vérifie que la personne qui demande le certificat est bien celui qu’il prétent être, si ce qu’elle demande est cohérent (e.g. est-ce qu’il possède bien le nom de domaine qu’il souhaite valider) et si les éléments demandé dans le CSR sont en accord avec la politique de l’autorité (e.g. Basic Constraints = CA:FALSE, certaines autorité interdisent certains attributs). Si toutes les conditions sont réunis l’autorité supprime la signature du CSR et ajoute sa signature, le transfomant en certificat. Souvant l’autorité ajoute certains attributs au CSR, comme un liens vers sa « Certificat Révoquation List » (CRL), des attributs de limitations, un liens vers un descriptif de sa politique de gestion de PKI… Une Authorité de certification vend (ou donne parfois) donc de la confiance. Tout est basé sur le fait que l’autorité vérifie méticuleusement l’identité et les droits des demandeurs de certificats avant de leurs accorder. Et c’est après avoir passé des audits de sécurité et pas mal de vérifications que le(s) certificat racine d’une autorité est ajoutée au différente liste de certificats racine de confiance (GNU/Linux distros, Windows, navigateurs…).

Une CRL est un fichier contenant une liste de certificat qui n’ont pas atteint leur date limite de validité et qui ne sont plus considéré comme fiable. Le protocole OCSP qui permet d’obtenir le status (révoké/non révoké) d’un certificat est aujourd’hui préféré au fichier CRL.

Un certificat racine est un certificat autosigné (ou parfois non signé… mais j’ai jamais vue ce cas). C’est à dire que la clé qui à servie à générer la signature contenu dans le certificat est la clé privé correspondant à la clé publique aussi contenu dans le certificat. Un certificat racine de confiance est parfois appelé « trust anchor ».

Comme dit plus haut, le serveur web peut envoyer des certificats intermédiaires en plus de son propre certificat. En effet, comme à chaque certificat correspond une clé privé, on peut créer des chaînes de certificat ; la clé privé associé à chaque certificat servant à signer le(s) certificat fils. La clé privé du certificat racine servant à signé le certificat racine lui-même en plus du/des certificat fils. Le navigateur possède uniquement une liste de certificat racine. Si des certificats intermédiaires se trouve entre celui du serveur web et la racine, le serveur web est obligé de les envoyer pour que le navigateur dispose de la chaine de certificat complète. Cette chaine de certificat est parfois appelé la chaine de confiance.

En théorie donc il est possible de générer des certificat dès que l’on possède un couple clé privé/certificat. En réalité certains attribut contenu dans les certificat en restreigne l’usage. Par exemple, si un certificat possède un attribut « Basic Constraints » contenant « CA:FALSE », les certificats signés via sa clé privé ne seront pas reconnue comme de confiance.

Il existe beaucoup d’autorités de certification, je ne parlerais ici que de quatres d’entre elles.

Let’s Encrypt
est une autorité délivrant des certificats gratuit pour les serveurs web. Voir la section Let’s Encrypt.
CAcert
est une autorité communautaire (une association) délivrant des certificats gratuit. Les nouveaux membres peuvent, après validation automatique (ou semi-automatique… je ne sais plus), obtenir un certificat de classe 1 (je décrit plus loin la notion de classe de certificat) valide six mois. Pour obtenir des certificats de classe supérieur et valide plus longtemps, ces membres doivent rencontrer physiquement des autres membres « assurer » qui vérifie leur identité. Chaque rencontre donne droit à un nombre de points relatif au niveau d’accréditation du membre « assurer ». Au bout d’un certain nombre de point le nouveau membre acquière le status de membre validé et peut demander des certificats de classe supérieur. Les membres validé peuvent devenir membre acréditeur en obtenant encore plus de point et en passant un examen. Sur le principe cette autorité est très intéressante mais ses certificats racine ne sont présent que dans très peu de liste. Par exemple, les certificat émis par cette autorité ne sont pas considéré comme de confiance par Firefox et il semble qu’ils ne soit pas prèt d’être inclue. Sous ArchLinux vous pouvez installer les certificats racine de cette autorité via le paquet ca-certificates-cacert.
StartSSL
délivre des certificats gratuit. La révocation de certificat est payante. Selon leur policy (voir section 7.3.2 page 37) elle permet de demander des certificat incluant dans le « Subject Alt Name » (SAN) un SRV-ID (ici appelé « SRV Name ») utilisé notament pour les certificat XMPP. J’ai généré deux certificats en essayant d’inclure un SRV-ID, sans succès. J’ai envoyé un email au support. (up 30/01/2016, pas de réponse depuis une semaine… je relance)
WoSign
Je n’ai jamais testé cette CA. Elle délivre des certificats gratuit. La révocation est aussi gratuite. Selon leur policy (voir section 7.2 pages 56-57) elle ne permet pas de demander de certificat incluant un SRV-ID.

Les classes de certificat ne font pas partie de la norme mais on été inventé par les autorité de certifications. Elles indique uniquement le niveau de validation qui a été effectué lors de la délivrance du certification. On distigue généralement les différente classe de certificat suivant leur Issuer, c’est à dire qu’un certificat parent différent est utilisé par l’autorité pour chaque type de certificat.

max@laptop % openssl x509 -in startcom-craoc.crt -noout -text
…
        Issuer: C=IL, O=StartCom Ltd., OU=StartCom Certification Authority, CN=StartCom Class 1 DV Server CA
…

Il existe deux format d’encodage de certificat (il en existe peut-être d’autre mais je ne les ai jamais rencontré et ne les connais pas)

Le format PKCS #12 généralement utilisé avec l’extension de fichier « .p12 » ou « .pfx » est un conteneur permettant de stoquer plusieurs object comme un certificat et sa clé privé correspondante. En gros on peut le voir comme une archive chiffré (un genre de zip avec mot de passe ultra complex). Il est utile lorsque l’entité qui demande le certificat ne sais pas générer un clé privé ou un CSR. La PKI lui génère le tout et lui envoie le certificat et sa clé privée sous forme d’une fichier au format PKCS #12 protégé par mot de passe.

Pour extraire le certificat et la clé d’un pkcs (sans chiffré la clé : -nodes) :

max@laptop % # certif & clé dans output.pem
max@laptop % openssl pkcs12 -in fichier.pfx -out output.pem -nodes
max@laptop % # uniquement le certif
max@laptop % openssl pkcs12 -in fichier.pfx -out cert.pem -nokeys
max@laptop % # uniquement la clé
max@laptop % openssl pkcs12 -in fichier.pfx -out key.pem -nocerts -nodes

Pour créé une archive pkcs (on ne sais jamais) :

max@laptop % openssl pkcs12 -export -out archive.pfx -inkey key.pem -in cert.pem -certfile CA-chain.pem

Nous avons vu plus haut que chaque certificat contient des données. Parmi ces données deux attributs figure parmis les plus important pour l’utilisateur : Subject et SubjectAltName. En sécurité le « Subject » correspond à la chose qui est validée/sécurisée. Cette élément contient un attribut « Common Name » (CN) qui désigne le nom de l’élément validée, pour un serveur web il s’agit du nom de domaine, pour email il s’agit de l’adresse email…

Le problème et qu’il ne peut y avoir qu’un seul « Subject » dans un certificat et que celui-ci ne peut contenir qu’un seul CN. Il y a longtemps il n’était donc pas possible de valider plusieurs nom de domaine avec un seul certificat. Aujourd’hui il existe l’extension « SubjectAltName » qui permet d’indiquer plusieurs équivalent du CN. Il faut toujours re-indiquer dans le « SubjectAltName » le nom indiqué dans le CN du « Subject ». Si le « SubjectAltName » et présent le CN n’est pas utilisé (dans la plupart des logiciels). « SubjectAltName » est parfois abrégé SAN.

Schéma récapitulatif

Génération d’un certificat

image : schéma récapitulatif sur la génération d'un certificat

Communication TLS entre un client et un serveur (eg. HTTPS)

image : schéma récapitulatif sur la communication entre un client et un serveur TLS

openssl

openssl est l’outil que nous allons le plus manipuler pour géré les certificats. Il s’utilise toujours avec une « commande », e.g. pour les commandes x509 et genrsa : openssl x509 …, openssl genrsa ….

Une des particularité d’openssl est que les page de manuel des commande sont accessible sans préfix « openssl ». Par exemple pour voir les options que l’on peut passer après openssl x509 il faut faire man x509.

principales commandes

Les principales commandes :

x509
permet de manipuler les certificats (généralement les fichier « .crt » mais il existe d’autres extension pour désigner un certificat). Attention, seul le premier certificat est pris en compte. Par exemple si le fichier passé en paramètre de l’option « -in » est un bundle (agrégat de plusieurs certificat), seul le premier sera pris en compte. De la même façon, si on passe cette commande à la suite de s_client les certificats intermédiaires ne seront pas pris en compte.
genrsa
créé une paire de clé rsa (clé privée + clé publique)
rsa
manipule les clé rsa
req
créé et manipule les CSR
s_client
effectue une connection TLS avec un serveur et affiche les informations relatifs au certificats échangé. Lors de la vérification du certificat du serveur s_client prend en comptes les certificats intermédiaires envoyé par le serveur web.
verify

permet de vérifié la chain de confiance d’un certificat. openssl utilise la liste de certificat de confiance présent dans le dossier /etc/ssl/certs (utiliser -CApath ou -CAfile si le certificat racine n’est pas dans /etc/ssl/certs).

% openssl verify -untrusted certificats-intermédiaires.pem certificat.crt

La plupart de ces commandes permettent d’afficher des informations sur les fichiers gérés via les options « -in fichier -noout -text ». « -noout » permet de ne pas afficher le fichier au format PEM (ce qui nous intéresses c’est la description textuelle).

création d’un certificat

Pour nous créer un certificat nous allons d’abort devoir créé un CSR et une clé paire de clés privée/publique.

Pour créé la paire de clé de 4096bits :

max@laptop % openssl genrsa -out craoc.key 4096

Pour créer le CSR nous allons utilisé un fichier de configuration openssl. Beaucoup de tutorial sur le web utilise le fichier de configuration par défault proposé par openssl. Je trouve que ce n’est pas forcément une bonne pratique car ça masque une grande partie de la compléxité du procédé et surtout ça empèche m’empèche de comprendre exactement ce que j’inclue/exclue dans mes CSR.

Je me suis inspiré des fichiers de configuration proposé dans la section Simple PKI pour créé les miens. Je vous encourage fortement à parcourir le site pki-tutorial.readthedocs.io. Les fichiers de configuration sont bien commenté.

openssl fourni la commande ca permettant signer des CSR, c’est une CA minimaliste. Elle permet de comprendre à peu près comment fonctionne les autres CA comme « Let’s Encrypt », « startssl » ou « CAcert ». Voici un exemple de configuration openssl d’une autorité de certification simple de signature de CSR (et donc génération de certificat). Les options interressantes sont :

copy_extensions = copy      # Copy extensions from CSR
x509_extensions = email_ext # Default cert extensions

Ces options sont détaillée dans la page man de ca. Elle nous indique que des extensions (attributs) sont utilisées par défaut et qu’ensuite sont ajouté les extensions contenu dans le CSR si celle-ci ne sont pas déjà présente dans les extensions par défaut. On peut supposer que les autres CA fonctionne à peu près de la même manière. C’est à dire qu’il n’est necessaire de renseigné les extensions par défaut. Pour avoir la liste des extensions « par défaut » et « autorisé » il faut aller voir les « policy » des autorité de certification (section 10.3 pour letsencrypt, section 7.3.2 pour startssl).

Pour mon certificat Let’s Encrypt, utilisé sur mon serveur web, j’ai utilisé la configuration suivante (letsencrypt-craoc.conf) :

[ req ]
default_md              = sha256        # MD to use
utf8                    = yes           # Input is UTF-8
string_mask             = utf8only      # Emit UTF-8 strings
prompt                  = no            # Doesn't prompt
distinguished_name      = distinguished_name
req_extensions          = v3_extensions # Desired extensions

[ v3_extensions ]
subjectAltName          = @subject_alternative_name

[ distinguished_name ]
commonName              = craoc.fr

[ subject_alternative_name ]
DNS.1                   = craoc.fr
DNS.2                   = www.craoc.fr
DNS.3                   = davical.craoc.fr
DNS.4                   = dokuwiki.craoc.fr
DNS.5                   = ftp.craoc.fr

Pour générer le CSR :

max@laptop % openssl req -new -config letsencrypt-craoc.conf -out craoc.csr -key craoc.key

Après envoie du CSR et signature par la CA voici le certificat obtenu :

root@server # openssl x509 -in letsencrypt-craoc.crt -noout -text
…
        Subject: CN=craoc.fr
…
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier: 
                4A:6B:61:7B:06:13:88:BF:08:45:D3:7A:8B:A3:C9:EE:D9:96:BE:32
            X509v3 Authority Key Identifier: 
                keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1

            Authority Information Access: 
                OCSP - URI:http://ocsp.int-x1.letsencrypt.org/
                CA Issuers - URI:http://cert.int-x1.letsencrypt.org/

            X509v3 Subject Alternative Name: 
                DNS:davical.craoc.fr, DNS:dokuwiki.craoc.fr, DNS:ftp.craoc.fr, DNS:craoc.fr, DNS:www.craoc.fr
            X509v3 Certificate Policies: 
                Policy: 2.23.140.1.2.1
                Policy: 1.3.6.1.4.1.44947.1.1.1
                  CPS: http://cps.letsencrypt.org
                  User Notice:
                    Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/

Pour mon certificat StartSSL, que je voulais utiliser sur mon serveur XMPP, j’ai utilisé la configuration suivante mais je n’ai pas obtenu le certificat escompté :

oid_section = new_oids

[ new_oids ]

# RFC 6120 section 13.7.1.4. (SRVName dans le RFC 4985, SRV-ID dans le RFC 6120)
# XMPP service providers SHOULD include the SRV-ID identifier type in
# certificate requests
SRVName                 = 1.3.6.1.5.5.7.8.7

# RFC 6120 : XMPPAddress : longer encouraged in certificates issued by certification
# authorities or requested by XMPP service providers
# XMPPAddr = 1.3.6.1.5.5.7.8.5

[ req ]
default_md              = sha256        # MD to use
utf8                    = yes           # Input is UTF-8
string_mask             = utf8only      # Emit UTF-8 strings
prompt                  = no            # Doesn't prompt
req_extensions          = v3_extensions # Desired extensions
distinguished_name      = distinguished_name

[ v3_extensions ]
subjectAltName          = @subject_alternative_name

[ distinguished_name ]
commonName      = craoc.fr

[ subject_alternative_name ]
# See https://tools.ietf.org/html/rfc6120#section-13.7.1.2 for more info.

# _xmpp-client: for client-to-server connections
# _xmpp-server: for server-to-server connections

DNS.0       =                                           craoc.fr
otherName.0 =            SRVName;IA5STRING:_xmpp-client.craoc.fr
otherName.1 =            SRVName;IA5STRING:_xmpp-server.craoc.fr

Après envoie du CSR et signature par la CA voici le certificat obtenu, il ne contient pas les otherName (ce qui n’est pas normal selon moi) :

root@server # openssl x509 -in startssl-craoc.crt -noout -text
…
        Subject: CN=craoc.fr
…
        X509v3 extensions:
            X509v3 Key Usage: 
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication, TLS Web Server Authentication
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                BB:F6:D4:30:BF:18:65:1E:C6:5A:CF:7B:84:5E:44:37:F5:04:88:EE
            X509v3 Authority Key Identifier: 
                keyid:D7:91:4E:01:C4:B0:BF:F8:C8:67:93:44:9C:E7:33:FA:AD:93:0C:AF

            Authority Information Access: 
                OCSP - URI:http://ocsp.startssl.com
                CA Issuers - URI:http://aia.startssl.com/certs/sca.server1.crt

            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:http://crl.startssl.com/sca-server1.crl

            X509v3 Subject Alternative Name: 
                DNS:craoc.fr, DNS:www.craoc.fr
            X509v3 Issuer Alternative Name: 
                URI:http://www.startssl.com/
            X509v3 Certificate Policies: 
                Policy: 2.23.140.1.2.1
                Policy: 1.3.6.1.4.1.23223.1.2.4
                  CPS: http://www.startssl.com/policy

récupérer le certificat d’un serveur

Vous voulez accéder à une page web ou télécharger un élément en https mais le certificat du serveur n’est pas reconnue comme certificat de confiance. Les certificats racine qui on servie à signer le certificat du serveur n’est pas enregistré dans votre système comme certificats de confiances.

Si l’administrateur du serveur à bien fait les choses, lors d’une demande de connexion https celui-ci doit envoyer le certificat d’authentification du serveur mais aussi toutes la chaine de certificat servant à vérifier son authenticité.

Pour optenir des informations sur ce que retourne le serveur lors d’une connection vous pouvez utiliser openssl s_client.

max@laptop % openssl s_client -showcerts -servername example.net -connect example.net:443 < /dev/null 2> /dev/null | less

Pour récupérer les certificat racine pour pouvoir ensuite les ajouter aux certificats racine de confiance vous pouvez utiliser la commande suivante :

max@laptop % server=example.net ; openssl s_client -showcerts -servername ${server} -connect ${server}:443 < /dev/null 2> /dev/null | awk '/BEGIN CERTIFICATE/{i++}; /BEGIN CERTIFICATE/,/END CERTIFICATE/{if(i>1){print}}'
max@laptop % server=example.net ; openssl s_client -showcerts -servername ${server} -connect ${server}:443 < /dev/null 2> /dev/null | perl -ne '$i++ if /BEGIN CERTIFICATE/; print if (/BEGIN CERTIFICATE/.../END CERTIFICATE/) && $i > 1'

Cette commande permet d’afficher au format PEM les certificats renvoyés par le serveur, excepté le premier (qui est le certificat du serveur).

showcerts
Permet d’afficher toute la chaine de certificat. Sans cette option seul le certificat du serveur est affiché.
connect
L’IP et le port sur lequel faire la connection TLS.
servername
Le vhost sur lequel récupérer le certificat. Les vhost de « connect » et « servername » peuvent être différent mais il doivent avoir la même IP. Sans cette option on récupère le certificat du vhost par défaut d’nginx/apache. La connection TLS s’effectue avant la connection HTTP. Avant l’apparition du TLS SNI (Server Name Indication) le serveur web ne connaissait le vhost à utiliser qu’une fois la connection TLS établie. Il ne pouvez y avoir qu’une certificat par serveur web et non pas un certificat par vhost.

Certains tutoriels vous conseille d’utiliser openssl x509 pour formater la sortie de openssl s_client. Je vous encourage à NE PAS LE FAIRE car openssl x509 ne considère que le premier certificat qu’il trouve. De la même manière si vous utilisez cette commande sur un bundle de certificat seul le premier sera pris en compte.

Si vous obtenez l’erreur suivante, essayé avec les l’option -CApath ou -CAfile root-ca.crt.

max@laptop % openssl s_client -servername www.craoc.fr -connect www.craoc.fr:443 > /dev/null < /dev/null
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=20:unable to get local issuer certificate
verify return:0
DONE
max@laptop % openssl s_client -CApath '/etc/ssl/certs' -servername www.craoc.fr -connect www.craoc.fr:443 < /dev/null > /dev/null
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X1
verify return:1
depth=0 CN = craoc.fr
verify return:1
DONE
max@laptop % openssl s_client -CAfile /etc/ssl/certs/DST_Root_CA_X3.pem -servername www.craoc.fr -connect www.craoc.fr:443 < /dev/null > /dev/null
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X1
verify return:1
depth=0 CN = craoc.fr
verify return:1
DONE

Signature S/MIME

Pour signer un text en ligne de commande.

max@laptop % cat > test
toto
tata
max@laptop % openssl smime -sign -text -in test -out test.signed -signer craoc.fr.pem.crt -inkey craoc.fr.pem.key -certfile craoc.fr-intermediaire.pem.crt
max@laptop % cat test.signed
MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----A8AB1EED8BAA34A4F61BF39E95FA9966"

This is an S/MIME signed message

------A8AB1EED8BAA34A4F61BF39E95FA9966
Content-Type: text/plain

toto
tata

------A8AB1EED8BAA34A4F61BF39E95FA9966
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"

MIIUTgYJKoZIhvcNAQcCoIIUPzCCFDsCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
DQEHAaCCEWgwggYOMIID9qADAgECAhA2gl5/taSBk3720XNruTymMA0GCSqGSIb3
DQEBDAUAMIGFMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVz
dGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRl
…

------A8AB1EED8BAA34A4F61BF39E95FA9966--

max@laptop % openssl smime -verify -text -in test.signed -signer craoc.fr.pem.crt -purpose any
toto
tata
Verification successful

craoc.fr-intermediaire.pem.crt doit contenir uniquement les certificats intermédiaire.

Source

Déchiffrement matériel

Sources :

Les outils/services qui utilise le TLS utilise généralement les bibliothèques fournie par openssl/libressl. Si openssl est capable d’utiliser l’accélération matériel pour déchiffrer du TLS alors vos outils/services profite de cette accélération.

Pour savoir si votre machine dispose d’un module d’accélération matériel vous pouvez vérifier la présence du flag « aes » sur vos CPU :

max@laptop % grep -m 1 aes /proc/cpuinfo
flags           : … aes …

Vous aussi tester la vitesse des algorithm que vous utilisez.

Test de vitesse

openssl speed permet de tester la vitesse de chiffrement/déchiffrement des différent cypher disponibles :

max@server % openssl speed -h
Error: bad option or value

Available values:
md4      md5      hmac     sha1     sha256   sha512   whirlpoolrmd160
idea-cbc rc2-cbc  bf-cbc   des-cbc  des-ede3
aes-128-cbc aes-192-cbc aes-256-cbc aes-128-ige aes-192-ige aes-256-ige
aes-128-gcm aes-256-gcm
camellia-128-cbc camellia-192-cbc camellia-256-cbc rc4 chacha20-poly1305
rsa512   rsa1024  rsa2048  rsa4096
dsa512   dsa1024  dsa2048
ecdsap160 ecdsap192 ecdsap224 ecdsap256 ecdsap384 ecdsap521
ecdsak163 ecdsak233 ecdsak283 ecdsak409 ecdsak571
ecdsab163 ecdsab233 ecdsab283 ecdsab409 ecdsab571 ecdsa
ecdhp160  ecdhp192  ecdhp224  ecdhp256  ecdhp384  ecdhp521
ecdhk163  ecdhk233  ecdhk283  ecdhk409  ecdhk571
ecdhb163  ecdhb233  ecdhb283  ecdhb409  ecdhb571  ecdh
idea     rc2      des      aes      camellia rsa      blowfish

Available options:
-elapsed        measure time in real time instead of CPU user time.
-evp e          use EVP e.
-decrypt        time decryption instead of encryption (only EVP).
-mr             produce machine readable output.
-multi n        run n benchmarks in parallel.

Par défault, la commande openssl n’utilise pas l’accélération matériel (c’est l’inverse pour les bibliothèque ssl). Pour activer le support de l’accélération matériel il faut utiliser l’option evp. Ici ça ne change rien car mon server ne supporte pas l’AES-NI.

max@server % openssl speed aes-128-gcm
Doing aes-128 gcm for 3s on 16 size blocks: 1194663 aes-128 gcm's in 2.92s
Doing aes-128 gcm for 3s on 64 size blocks: 562348 aes-128 gcm's in 2.92s
Doing aes-128 gcm for 3s on 256 size blocks: 273534 aes-128 gcm's in 2.91s
Doing aes-128 gcm for 3s on 1024 size blocks: 82490 aes-128 gcm's in 2.94s
Doing aes-128 gcm for 3s on 8192 size blocks: 10830 aes-128 gcm's in 2.93s
LibreSSL 2.5.3
built on: date not available
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
compiler: information not available
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
aes-128 gcm       6546.10k    12325.44k    24063.47k    28731.21k    30279.65k
max@server % openssl speed -evp aes-128-gcm
Doing aes-128-gcm for 3s on 16 size blocks: 2539804 aes-128-gcm's in 2.95s
Doing aes-128-gcm for 3s on 64 size blocks: 756601 aes-128-gcm's in 2.96s
Doing aes-128-gcm for 3s on 256 size blocks: 313274 aes-128-gcm's in 2.95s
Doing aes-128-gcm for 3s on 1024 size blocks: 86835 aes-128-gcm's in 2.98s
Doing aes-128-gcm for 3s on 8192 size blocks: 11123 aes-128-gcm's in 3.00s
LibreSSL 2.5.3
built on: date not available
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
compiler: information not available
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
aes-128-gcm      13775.21k    16358.94k    27185.81k    29838.60k    30373.21k

Même tests sur chacha20-poly1305 :

max@server % openssl speed chacha20-poly1305
Doing chacha20 poly1305 for 3s on 16 size blocks: 968670 chacha20 poly1305's in 2.83s
Doing chacha20 poly1305 for 3s on 64 size blocks: 940011 chacha20 poly1305's in 2.93s
Doing chacha20 poly1305 for 3s on 256 size blocks: 434745 chacha20 poly1305's in 3.00s
Doing chacha20 poly1305 for 3s on 1024 size blocks: 136924 chacha20 poly1305's in 3.00s
Doing chacha20 poly1305 for 3s on 8192 size blocks: 18474 chacha20 poly1305's in 2.98s
LibreSSL 2.5.3
built on: date not available
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
compiler: information not available
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
chacha20 poly1305     5476.58k    20532.66k    37098.24k    46736.73k    50784.90k
max@server % openssl speed -evp chacha20-poly1305
chacha20-poly1305 is an unknown cipher or digest

J’utilise donc chacha20-poly1305 sur mon serveur.

Autres

Autres exemples qui m’ont déjà été utiles :

certificat de confiance

Archlinux

Sur une installation ArchLinux les certificats de confiance sont installé par les paquets core/ca-certificates-mozilla et core/ca-certificates-cacert (et le métapaquet ca-certificates qui ne fait rien sinon dépendre des deux précédent paquets).

max@laptop % yaourt -Ql ca-certificates-cacert
…
ca-certificates-cacert /usr/share/ca-certificates/trust-source/anchors/CAcert.org_class3.crt
ca-certificates-cacert /usr/share/ca-certificates/trust-source/anchors/CAcert.org_root.crt
…
max@laptop % yaourt -Ql ca-certificates-mozilla
…
ca-certificates-mozilla /usr/share/ca-certificates/trust-source/mozilla.neutral-trust.crt
ca-certificates-mozilla /usr/share/ca-certificates/trust-source/mozilla.supplement.p11-kit
ca-certificates-mozilla /usr/share/ca-certificates/trust-source/mozilla.trust.crt
…

Les certificat sont installé dans dans /usr/share/ca-certificates/trust-source.

Les certificats racine utilisés par les applications sont stocké dans les dossier /etc/ssl/certs et /etc/ca-certificates/extracted. C’est la commande update-ca-trust extract (lire en particulier le paragraphe Extracted Configuration) qui peuple ces dossiers une fois les « pack » de certificats installé dans /usr/share/ca-certificates.

En fait, sous ArchLinux, update-ca-trust est un script bash appelant la commandes trust de p11-kit (une dépendance du paquet). Je vous encourage à lire ce script car il n’est pas compliqué et il permet de se rendre compte facilement de ce qui ce passe.

La documentation de trust se trouve dans le fichier /usr/share/gtk-doc/html/p11-kit/trust.html.

En fait les « pack » de certificats sont extrait dans /etc/ca-certificates/extracted :

Des certificats sont aussi stocké dans des structures compréhensible par Java.

Tous les lien symbolic contenu dans /etc/ca-certificates/extracted/cadir, et uniquement les liens symbolique (excepté pour le truc Java) sont copié dans le répertoire /etc/ssl/certs.

Gentoo

Sur une installation Gentoo les certificats de confiance sont installés par les paquets app-misc/ca-certificates.

root@server # equery f app-misc/ca-certificates
 * Searching for ca-certificates in app-misc ...
 * Contents of app-misc/ca-certificates-20140927.3.17.2:
…
/etc/ca-certificates.conf
…
/etc/ca-certificates/update.d
…
/etc/env.d/98ca-certificates
…
/etc/ssl/certs/…
…
/usr/sbin/update-ca-certificates
…
/usr/share/ca-certificates/cacert.org/cacert.org_root.crt
…
/usr/share/ca-certificates/mozilla/…
…
/usr/share/ca-certificates/spi-inc.org/spi-cacert-2008.crt
…

Les certificat sont installé dans dans /usr/share/ca-certificates.

Les certificats racine utilisés par les applications sont stocké dans les dossier /etc/ssl/certs. La commande update-ca-certificates (c’est un script bash) peuple ce dossier. Elle prend en compte tous les certificats listés dans le fichier /etc/ca-certificates.conf (mettre un « ! » devant un certificat pour le supprimer), et les certificats placé dans le dossier /usr/local/share/ca-certificates (il faut que les fichier est une extention en .crt).

Le fichier /etc/ssl/certs/ca-certificates.crt est un bundle de tous les certificats traité par update-ca-certificates.

installer ses propre certificats

Archlinux

Il suffit de placer ses certificats racine dans le dossier /etc/ca-certificates/trust-source/anchors et de lancer la commande trust extract-compat (anciennement on utilisé update-ca-trust mais cette méthode est dépréciée).

La commande trust extract-compat va générer les bundle et les liens symboliques. Je ne sais pas quelle est la différence entre update-ca-trust et trust extract-compat.

Gentoo

Il faut placer ses certificats dans le dossier /usr/local/share/ca-certificates (il faut que les fichier est une extention .crt) et lancer la commande update-ca-certificates (ou emerge -1 app-misc/ca-certificates).

Debian

Comme pour Gentoo.

Testé sur Wheezy (7) et Stretch (9).

Alternative

Source : Installing CA Certificates into the OpenSSL framework

Si vous n’êtes pas sous ArchLinux et que la commande trust n’existe pas, utiliser update-ca-trust.

Si le dossier /etc/ca-certificates/trust-source/anchors n’existe pas essayé le dossier /usr/local/share/ca-certificates/. Sous OpenSuse il faut utiliser le dossier /etc/pki/trust/anchors.

Si vraiment vous avez tout essayé mais que vous ne trouvez pas, ou simplement si vous voulez faire un truc de porc à la vas-vite et que vous vous en fouté. Placer le certificat dans le dossier /etc/ssl/certs et générer son lien symbolique via la commande suivante.

max@laptop % i=moncertificat ; ln -s $i `openssl x509 -noout -hash -in $i`.0

certificate with distrust

Lorsque j’essayé d’installer des certificats comme certificats de confiance j’ai obtenu l’erreur suivante :

root@laptop # trust extract-compat
…
p11-kit: certificate with distrust in location for anchors: moncertificat.pem
…

Cette erreur/warning indique que l’entité qui a signé le certificat n’accorde sa confiance à ce certificat que pour certains usages. Le certificat moncertificat.pem au format PEM commance par « BEGIN TRUST CERTIFICAT ».

Par défaut un certificat est signé avec toute la confiance du signataire mais il peut arrivé que cette confiance soit restrainte à certains usage. Par example uniquement la signature de mail et non l’authentification de serveur web. Dans ce cas le certificat est de type « BEGIN TRUST ».

Je vous encourage à lire l’article « OpenSSL: trust and purpose » pour bien comprendre ce qu’est un certificat « BEGIN TRUST » et la différence entre « trust » et « purpose ».

max@laptop % openssl x509 -in in.pem
-----BEGIN CERTIFICATE-----
…

max@laptop % openssl x509 -in in.pem -addtrust serverAuth -addreject clientAuth
-----BEGIN TRUSTED CERTIFICATE-----
…

max@laptop % openssl x509 -in in.pem -addtrust serverAuth -addreject clientAuth -out out.pem
max@laptop % openssl x509 -in in.pem -text > in.txt
max@laptop % openssl x509 -in test.pem -text > out.txt
max@laptop % diff in.txt out.txt
107a108,111
> Trusted Uses:
>   TLS Web Server Authentication
> Rejected Uses:
>   TLS Web Client Authentication

serveur

Lorsque vous utilisez un certificat pour authentifier un serveur il faut que vous fournissiez tous les certificat de la chaine de confiance excepté le(s) certificat racine (celui ou ceux qui sont inclus sur les postes clients).

Avec nginx, dans le fichier qui sera désigné par la directive ssl_certificate vous devrez concaténé votre certificat avec les autres certificats de la chaine. Attention à mettre votre certificat en premier.

max@laptop % cat moncertificat.pem intermediaires.pem > monbundle.pem

Avec apache, la chaine de certificat doit être placée dans un fichier séparé et désigné par la directive SSLCertificateChainFile.

wildcard

Un certificat « wildcard » est un certificat couvrant tous les sous-domaine de premier niveau d’un domaine. Par exemple, si le CN contient « *.craoc.fr » alors www.craoc.fr et ftp.craoc.fr sont validé, mais test.www.craoc.fr ne l’est pas. On ne peut pas créer un certificat avec plusieurs asterisque/wildcard sur un même domaine ; « *test.*.craoc.fr » n’est pas valide. Il est possible d’avoir un ou plusieurs domaine avec wildcard dans le « SubjectAltName ».

Pour résumer, dans le « SubjectAltName » :

Bien sur, les CA peuvent appliquer des restriction. Par exemple, Let’s Encrypt refuse les wildcard.

XMPP

TODO

Les certificat server XMPP n’ont pas besoins de : Client Authentication (1.3.6.1.5.5.7.3.2)

Let’s Encrypt

Let’s Encrypt est une autorité délivrant des certificats gratuit pour les serveurs web. Sa particularité est d’être entièrement automatisée. Elle utilise le protocole ACME pour vérifier la validité des CSR et délivrer les certificats.

Les certificats qu’elle délivre sont valide trois mois et les policy est très restrictive (la liste des extentions X509 inclue dans les certificat est fixe). Il n’est par exemple pas possible d’obtenir un certificat incluant un SRV-ID dans le SubjectAltName comme le recommande vivement la norme XMPP. Il n’est pas non plus possible d’obtenir des certificat « wildcard ».

Voici une description rapide de mon infrastructure de gestion et renouvellement de certificat pour ce CA.

certbot

certbot (anciennement letsencrypt) est le client letsencrypt officiel. Il permet d’obtenir des certificats avec clé ECDSA.

Sources :

Création de l’utilisateur letsencrypt et du dossier /var/log/letsencrypt.

letsencrypt@server % grep letsencrypt /etc/passwd
letsencrypt:x:999:232::/etc/letsencrypt:/sbin/nologin
letsencrypt@server % cd ~letsencrypt
letsencrypt@server % stat /var/log/letsencrypt
  File: ‘/var/log/letsencrypt’
  Size: 372             Blocks: 0          IO Block: 4096   directory
Device: 13h/19d Inode: 2730803     Links: 1
Access: (0755/drwxr-xr-x)  Uid: (  999/letsencrypt)   Gid: (  232/letsencrypt)
…

Pour pouvoir générer un certificat avec une clé ECDSA il faut utiliser le mode « –csr ». J’ai donc créé un fichier de configuration openssl.

letsencrypt@server % cat craoc.conf
[ req ]
default_md              = sha256        # digest (fonction de hashage) utiliser pour générer
                                        # le hash sur lequel s'appliquera le chiffrement
                                        # asymétrique de la clé privé (génération de la signature du csr)
utf8                    = yes           # Input is UTF-8
string_mask             = utf8only      # Emit UTF-8 strings
prompt                  = no            # Doesn't prompt
distinguished_name      = distinguished_name
req_extensions          = v3_extensions # Desired extensions

[ v3_extensions ]
subjectAltName          = @subject_alternative_name

[ distinguished_name ]
commonName              = craoc.fr

[ subject_alternative_name ]
DNS.1                   = craoc.fr
DNS.2                   = www.craoc.fr
DNS.3                   = davical.craoc.fr
DNS.4                   = dokuwiki.craoc.fr
DNS.5                   = ftp.craoc.fr

Il existe beaucoup de « courbe » permettant de paramétrer notre paire de clés privé/publique ECDSA, la liste complète peux être obtenu via openssl ecparam -list_curves.

Génération de la paire :

letsencrypt@server % openssl ecparam -genkey -name prime256v1 -out privkey.pem

Letsencrypt ne permet de n’utiliser que le format DER pour le CSR.

letsencrypt@server % openssl req -new -config craoc.conf -outform der -out csr.der -key privkey.pem

J’utilise la méthode « –webroot » du client officiel. Cela permet de l’utiliser sans droit root mais nécéssite la création d’un répertoire accessible en écriture et en HTTP via « http://mon-domaine/.well-known/acme-challenge/ ».

letsencrypt@server % cat /etc/nginx/default-vhost.conf
server {
        listen 80 default_server;
        server_name _;

        root /var/www/localhost/;

        # pour letsencrypt
        location /.well-known/acme-challenge/ {
                try_files $uri =404;
        }

        # on redirige tout vers https
        location / {
                return 301 https://$host$request_uri;
        }
}
letsencrypt@server % namei /var/www/localhost/.well-known/acme-challenge
f: /var/www/localhost/.well-known/acme-challenge
 d /
 d var
 d www
 d localhost
 d .well-known
 d acme-challenge

Génération d’un certificat avec certbot. Lors des tests il est recommendé d’utiliser l’option --staging qui permet de faire ses requêtes sur un serveur dédié, sans limitation. Le client garde 10 fichiers (ligne logging.handlers.RotatingFileHandler(…, backupCount=10)) de logs dans /var/log/letsencrypt, il n’est pas nécessaire d’utiliser logrotate.

letsencrypt@server % certbot certonly --webroot --webroot-path /var/www/localhost --non-interactive --email 'maxime.deroucy@gmail.com' --agree-tos --work-dir /var/log/letsencrypt --csr csr.der

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/0001_chain.pem. Your cert will expire on
   2016-07-23. To obtain a new version of the certificate in the
   future, simply run Let's Encrypt again.

letsencrypt@server % ls
0000_cert.pem  0000_chain.pem  0001_chain.pem  accounts/  craoc.conf  csr.der  logs/  privkey.pem
letsencrypt@server % mv 0001_chain.pem chain.pem
letsencrypt@server % rm 0000_chain.pem 0000_cert.pem
letsencrypt@server % openssl x509 -in chain.pem -noout -text
…
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3
…
        Subject: CN=craoc.fr
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
…
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
…
            X509v3 Subject Alternative Name: 
                DNS:craoc.fr, DNS:davical.craoc.fr, DNS:dokuwiki.craoc.fr, DNS:ftp.craoc.fr, DNS:www.craoc.fr
…

Configuration de nginx.

root@server # grep ssl_ /etc/nginx/pelican.conf
        ssl_certificate     /etc/letsencrypt/chain.pem;
        ssl_certificate_key /etc/letsencrypt/privkey.pem;
root@server # cat /etc/nginx/nginx.conf
…
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers EECDH+AESGCM:EECDH+AES;
        ssl_prefer_server_ciphers on;
        ssl_ecdh_curve X25519:secp521r1:secp384r1:prime256v1;
…

Avec le mode « –csr » il n’est pour l’instant (24/04/2016) pas possible d’utiliser la commande « certbot renew » (et donc --renew-hook). Je suis obligé de relancer exactement la même commande pour obtenir un nouveau certificat. Et celle-ci m’en génère un nouveau même si l’ancien est encore bon (plus de 30 jours avant expiration). J’ai donc utilisé un script bash pour tester et renouveler périodiquement mon certificat.

root@server # systemctl cat letsencrypt.timer
# /etc/systemd/system/letsencrypt.timer
[Unit]
Description=renew letsencrypt certificats

[Timer]
OnCalendar=weekly
Persistent=true
#RandomizedDelaySec=5h

[Install]
WantedBy=timers.target
root@server # systemctl cat letsencrypt.service
# /etc/systemd/system/letsencrypt.service
[Unit]
Description=renew letsencrypt certificats
Requisite=nginx.service
OnFailure=cron-failure@%p.service

[Service]
Type=oneshot
User=letsencrypt
WorkingDirectory=/etc/letsencrypt/
ExecStart=/usr/bin/chronic /etc/letsencrypt/renew.sh
root@server # cat /etc/letsencrypt/renew.sh
#!/bin/bash

set -e -o pipefail -u -x

cd /etc/letsencrypt

enddate_full_format=`openssl x509 -in chain.pem -noout -enddate | cut -d= -f2`
enddate_short_format=`date --date="$enddate_full_format" '+%s'`
date_in_thirty_days=`date --date='now + 30 days' '+%s'`

if test $enddate_short_format -gt $date_in_thirty_days
then
        exit 0
fi

certbot certonly --webroot --webroot-path /var/www/localhost --non-interactive --email 'maxime.deroucy@gmail.com' --agree-tos --work-dir /var/log/letsencrypt --csr csr.der

rm 0000_cert.pem 0000_chain.pem
mv 0001_chain.pem chain.pem

sudo nginx -s reload

renew

Une petite note concernant l’option « renew » de certbot (même si je ne l’utilise pas pour l’instant). La commande certbot -h all nous indique que « renew » renouvelle les certificat proche de leur date d’expiration… c’est cool mais « proche » ça correspond à combient de temps ?

En fait « proche » peu se configurer via la directive renew_before_expiry, qui est par défaut fixé à 30 jours.

simp_le

J’utilisait précédemment le client simp_le pour obtenir et renouveller mes certificats.

root@server # pwd
/etc/ssl/letsencrypt
root@server # ls -l
total 12K
-rw-r--r-- 1 letsencrypt letsencrypt 3,1K  2 mars  00:32 account_key.json
-rw-r--r-- 1 letsencrypt letsencrypt 3,9K  2 mars  00:32 fullchain.pem
-rw------- 1 letsencrypt letsencrypt 3,2K  2 mars  00:32 key.pem
drwxr-xr-x 1 root        root         234  2 mars  23:34 old/
root@server # cat /etc/systemd/system/letsencrypt.service
[Unit]
Description=renew letsencrypt certificats
Requisite=nginx.service
OnFailure=cron-failure@%p.service

[Service]
Type=oneshot
User=letsencrypt
WorkingDirectory=/etc/ssl/letsencrypt/

# exit status:
#   0 if certificate data was created or updated
#   1 if renewal not necessary
#   2 in case of errors.
#
# OK if 0 or 1
SuccessExitStatus=1

ExecStart=/bin/sh -c '\
        /usr/bin/simp_le \
                --default_root /var/www/acme-challenge \
                --vhost craoc.fr \
                --vhost www.craoc.fr \
                --vhost davical.craoc.fr \
                --vhost dokuwiki.craoc.fr \
                --vhost ftp.craoc.fr \
                -f account_key.json \
                -f key.pem \
                -f fullchain.pem \
                --reuse_key \
                --email maxime.deroucy@gmail.com \
        && \
        /usr/bin/sudo nginx -s reload'
ExecStart=/usr/bin/find /var/www/acme-challenge -type f -delete

root@server # cat /etc/systemd/system/letsencrypt.timer
[Unit]
Description=renew letsencrypt certificats

[Timer]
OnCalendar=*-*-01 04:00
Persistent=true

[Install]
WantedBy=timers.target
root@server # cat /etc/nginx/pelican.conf
# pour letsencrypt
server {
        listen 80;
        server_name www.craoc.fr;

        access_log /var/log/nginx/www.craoc.fr.access_log main;
        error_log /var/log/nginx/www.craoc.fr.error_log info;

        root /var/www/git/www.craoc.fr;

        location /.well-known/acme-challenge/ {
                root /var/www/acme-challenge/;
                try_files $uri =404;
        }

        location / {
                return 301 https://$host$request_uri;
        }
}

server {
        listen 443 ssl http2 default_server;
        server_name www.craoc.fr;

        ssl_certificate     /etc/ssl/letsencrypt/fullchain.pem;
        ssl_certificate_key /etc/ssl/letsencrypt/key.pem;

	…

Tests

Let’s Encrypt limite la fréquence des requêtes (enregistrement, authentification, demande de certificat) qu’il est possible de passer à l’API. Lorsque j’ai monter ma plate-forme de renouvellement de certificat j’ai fait plusieurs tests avant d’avoir une configuration fonctionnelle et qui me plaise.

Let’s Encrypt fourni une API dédiée au test qui n’est pas limitée.

letsencrypt@server # simp_le --server 'https://acme-staging.api.letsencrypt.org/directory' --default_root /var/www/acme-challenge --vhost craoc.fr … --vhost ftp.craoc.fr -f account_key.json -f key.pem -f fullchain.pem --reuse_key --email maxime.deroucy@gmail.com
2016-03-03 21:02:13,950:INFO:simp_le:1202: Generating new account key
2016-03-03 21:02:21,430:INFO:requests.packages.urllib3.connectionpool:756: Starting new HTTPS connection (1): acme-staging.api.letsencrypt.org
…
2016-03-03 21:02:28,562:INFO:simp_le:1294: davical.craoc.fr was successfully self-verified
…
2016-03-03 21:02:29,071:INFO:simp_le:1294: ftp.craoc.fr was successfully self-verified
2016-03-03 21:02:29,590:INFO:simp_le:1294: craoc.fr was successfully self-verified
…
2016-03-03 21:02:30,086:INFO:simp_le:1294: dokuwiki.craoc.fr was successfully self-verified
…
2016-03-03 21:02:30,591:INFO:simp_le:1294: www.craoc.fr was successfully self-verified
…
2016-03-03 21:02:31,092:INFO:simp_le:1302: Generating new certificate private key
…
2016-03-03 21:02:41,545:INFO:simp_le:385: Saving account_key.json
2016-03-03 21:02:41,546:INFO:simp_le:385: Saving key.pem
2016-03-03 21:02:41,548:INFO:simp_le:385: Saving fullchain.pem
letsencrypt@server # ls -l
total 12K
-rw-r--r-- 1 letsencrypt letsencrypt 3,1K  3 mars  22:02 account_key.json
-rw-r--r-- 1 letsencrypt letsencrypt 3,3K  3 mars  22:02 fullchain.pem
-rw-r--r-- 1 letsencrypt letsencrypt 3,2K  3 mars  22:02 key.pem
letsencrypt@server # openssl x509 -in fullchain.pem -noout -text
        …
        Issuer: CN=happy hacker fake CA
        …
        Subject: serialNumber=fa956f497abe51b9182da212a01e31a1e761
        …
            X509v3 Subject Alternative Name:
                DNS:craoc.fr, DNS:davical.craoc.fr, DNS:dokuwiki.craoc.fr, DNS:ftp.craoc.fr, DNS:www.craoc.fr
        …

acme-tiny

Avant d’utiliser simp_le j’utilisait acme-tiny pour « dialoguer » avec la CA. J’ai arrété d’utiliser ce script car je me suis apperçut que le développeur principal du projet voulait conserver le nombre de ligne de code de son script sous la barre de 200 ; potentiellement au prix de sa lisibilité. Peut-être cela a-t-il changé aujourd’hui. Aussi, le client simp_le est mentionné dans le README du client officiel. Et son développeur principal est aussi le développeur principal du client officiel (le 02/03/2016).

Je donne ici la configuration que j’utilisai avec acme-tiny.

root@server # pwd
/etc/ssl/letsencrypt
root@server # ls -l
total 36K
-r-------- 1 letsencrypt letsencrypt 3,2K 10 janv. 14:57 account.key
drwxr-xr-x 1 letsencrypt letsencrypt  116 10 janv. 15:58 acme-tiny/
-rw-r--r-- 1 letsencrypt letsencrypt 3,9K 10 janv. 16:32 craoc.chained.crt
-r-------- 1 root        root         506 24 janv. 18:04 craoc.conf
-rw-r--r-- 1 letsencrypt letsencrypt 2,2K 10 janv. 16:25 craoc.crt
-rw-r--r-- 1 letsencrypt letsencrypt 1,8K 14 janv. 23:49 craoc.csr
-r-------- 1 letsencrypt letsencrypt 3,2K 10 janv. 15:25 craoc.key
-rw-r--r-- 1 letsencrypt letsencrypt 1,7K 10 janv. 16:26 intermediate.pem
-rwxr-xr-x 1 letsencrypt letsencrypt  233 10 janv. 16:39 renew_cert.sh*
root@server # cat renew_cert.sh
#!/bin/sh
set -e

cd /etc/ssl/letsencrypt
python acme-tiny/acme_tiny.py --account-key account.key --csr craoc.csr --acme-dir /var/www/acme-challenge > craoc.crt
cat craoc.crt intermediate.pem > craoc.chained.crt
sudo nginx -s reload
root@server # ls /etc/systemd/system/letsencrypt.*
/etc/systemd/system/letsencrypt.service  /etc/systemd/system/letsencrypt.timer
root@server # cat /etc/systemd/system/letsencrypt.service
[Unit]
Description=renew letsencrypt certificats
Requisite=nginx.service
OnFailure=cron-failure@%p.service

[Service]
Type=oneshot
ExecStart=/etc/ssl/letsencrypt/renew_cert.sh
WorkingDirectory=/etc/ssl/letsencrypt/
User=letsencrypt
root@server # cat /etc/systemd/system/letsencrypt.timer
[Unit]
Description=renew letsencrypt certificats

[Timer]
OnCalendar=*-01/3-01 04:00
Persistent=true

[Install]
WantedBy=timers.target

DNS CAA

Source :

Les enregistrement DNS CAA permettent de spécifier au client TLS, via le DNS, quels CA sont autorisé à emmetre des certificats pour votre domaine :

CAA 0 issue "letsencrypt.org"
CAA 0 iodef "mailto:admin@craoc.fr"

Chez OVH il n’est pas possible de renseigné ce type d’enregistrement DNS (forum OVH).

Non répudiation

Qu’est ce que la non répudiation :

The non-repudiation value in the keyUsage attribute relates to the whole certificate, not any purpose in particular. The presence of the non-repudiation flag indicates that the private key has sufficient protections in place that the entity named in the certificate cannot later repudiate—deny—actions they take with the certificate. The presence of the flag doesn’t prevent repudiation, rather it indicates that repudiation isn’t likely to survive reasonable scrutiny.

So in this specific case, the CA is giving the user the option of a certificate that does or does not include the non-repudiation element. If you want to assert to those verifying the signature that you can’t easily deny it was you who signed it (the USB token is the key enabler here), use the non-repudiation certificate. Otherwise, use the certificate marked for digital signatures. (Depending on the other attributes in the certificate, you may or may not be able to sign documents with either or both certificates.)

Extended Validation Certificates

Les Extended Validation (EV) certificates sont, comme les classes de certificat, une notion inventé par les CA. Il s’agit en fait de la classe ultime de certificat. Pour obtenir un certificat EV il faut subir un processus de vérification standardisée par le CA/B Forum. Il ont la particularité être indiqué par les navigateur web par un encart vert dans la barre d’URL.

image : barre verte déclanchée par un certificat EV dans Firefox

liens

Quelques liens intéressant :