/ Linux

[Chrome 58+] Corriger l'erreur missing_subjectAltName avec OpenSSL

Depuis la version 58, Chrome/Chromium bloque les certificats SSL qui n'utilisent pas l'extension subjectAlternativeName pour l'identification des noms de domaines associés. Historiquement, j'ai toujours utilisé le champ Common Name (CN=) lors de la génération d'un certificat autosigné sans savoir que c'était déprécié depuis 17 ans...

Si vous utilisez un certificat SSL non SAN, vous devriez avoir cette erreur avec la dernière version stable de chrome :

screen1

Pour résoudre ce problème, il suffit d'utiliser l'extension subjectAlternativeName du standard X509v3 en utilisant l'argument -extfile lors de la génération du CSR.

# Fichier : subjectAltName.ext
# Source : http://wiki.cacert.org/FAQ/subjectAltName

basicConstraints=CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alternate_names

[alternate_names]
DNS.1 = *.meshup.net
DNS.2 = www.domain.tld
DNS.3 = admin.domain.tld
DNS.x = ... etc

Il existe d'autre méthodes comme faire passer les noms DNS par une variable d'environnement subjectAltName=$ENV::ALTNAME en la déclarant comme ça : ALTNAME=DNS:example.com,DNS:other.example.net

Ou encore de passer directement par la ligne de commande :

# Source : https://security.stackexchange.com/a/91556

openssl req -newkey rsa:4096 -x509 -nodes -new -sha256 -days 3650 \
    -keyout domain.key \
    -out domain.crt \
    -subj "CN=*.domain.tld" \
    -reqexts SAN \
    -extensions SAN \
    -config <(cat /usr/lib/ssl/openssl.cnf \
            <(printf '[SAN]\nsubjectAltName=DNS:*.domain.tld'))
    

Attention le fichier de conf d'openssl n'est pas systématiquement sous /usr/lib/ssl/openssl.cnf, ça dépend de la distribution : find / -name "openssl.cnf".

Pour ma part, j'ai choisi de modifier légèrement mon script de génération en ajoutant -extfile subjectAltName.ext lors de la création du CSR :

#!/bin/bash

openssl genrsa -out domain.ca.key 4096
openssl req -x509 -new -nodes -days 3658 -sha256 \
  -key domain.ca.key \
  -out domain.ca.crt \
  -subj "/C=FR/ST=France/L=Paris/O=domain.tld/OU=Certificate Authority/CN=Root CA/emailAddress=admin@domain.tld"

openssl genrsa -out webservices.domain.key 4096
openssl req -new -sha256 \
  -key webservices.domain.key \
  -out webservices.domain.csr \
  -subj "/C=FR/ST=France/L=Paris/O=domain.tld/OU=Web services/CN=*.domain.tld/emailAddress=admin@domain.tld"

openssl genrsa -out client.key 4096
openssl req -new -sha256 \
  -key client.key \
  -out client.csr \
  -subj "/C=FR/ST=France/L=Paris/O=domain.tld/OU=Client certificate/CN=*.domain.tld/emailAddress=admin@domain.tld"

openssl x509 -req -days 3658 -sha256 \
  -in webservices.domain.csr \
  -CA domain.ca.crt \
  -CAkey domain.ca.key \
  -CAcreateserial \
  -out webservices.domain.crt \
  -extfile subjectAltName.ext

openssl x509 -req -days 3658 -sha256 \
  -in client.csr \
  -CA domain.ca.crt \
  -CAkey domain.ca.key \
  -CAcreateserial \
  -out client.crt \
  -extfile subjectAltName.ext

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

Ce script me permet de générer rapidement un certificat racine, un certificat pour chacun de mes services (web, mail...etc) et un certificat client pour protéger certains sous-domaines avec PKCS#12.

Il reste plus qu'à importer domain.ca.crt et client.p12 dans le navigateur et tout refonctionne comme avant :

screen2

Petite astuce avec Chromium (je sais pas si ça fonctionne avec chrome). Pour choisir automatiquement le bon certificat lors de la connexion à un sous-domaine protégé par PKCS#12, il est possible de déclarer une policy sous /etc/chromium/policies/managed/CustomCertificates.json qui sera suivie par le navigateur :

{
  "AutoSelectCertificateForUrls": [
      "{\"pattern\":\"https://rss.domain.tld\",\"filter\":{\"ISSUER\":{\"CN\":\"Root CA\"}}}",
      "{\"pattern\":\"https://www.domain.tld\",\"filter\":{\"ISSUER\":{\"CN\":\"Root CA\"}}}"
    ]
}

Source : https://www.chromium.org/administrators/policy-list-3#AutoSelectCertificateForUrls

Si certains se posent la question :

"Mais pourquoi tu t'embêtes avec des certificats autosignés alors qu'il y a Let's Encrypt maintenant ?"

Pour 3 raisons essentiellement :

  1. Parce que j'ai envie de garder privé certains de mes sous-domaines. Avec let's encrypt c'est très facile de trouver l'ensemble des sous-domaines via le champ subjectAltName justement.
  2. Parce qu'il y a qu'un ensemble restreint de personnes qui utilisent ces URLs
  3. Parce que ça me permet de ne pas changer mon certificat client tous les 4 matins, je le communique une fois et il change plus pendant 10 ans (sauf quand il devient obsolète, d'où cet article :D)

Pour le point numéro 1, c'est pas suffisant de faire ça. Il faut aussi ne pas déclarer les sous-domaines dans la zone DNS du domaine, ne mentionner le sous-domaine dans aucun moteur de recherche...etc sinon c'est toujours possible de les trouver via un outil comme Sublist3r par exemple.

[Chrome 58+] Corriger l'erreur missing_subjectAltName avec OpenSSL
Share this