Générer un certificat auto-signé avec openssl fonctionnant sous Chrome 58

52

À partir de Chrome 58, il n'accepte plus les certificats auto-signés qui s'appuient sur Common Name: https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category $ 3ACanary% 7Canalyse: pertinence% 7spell: false

Au lieu de cela, il faut utiliser Subject Alt Name. Je suivais auparavant ce guide sur la façon de générer un certificat auto-signé: https://devcenter.heroku.com/articles/ssl-certificate-self, qui fonctionnait très bien car j'avais besoin des fichiers server.crtet server.keypour ce que je faisais. Je dois maintenant générer de nouveaux certs qui incluent, SANcependant, toutes mes tentatives pour le faire n’ont pas fonctionné avec Chrome 58.

Voici ce que j'ai fait:

J'ai suivi les étapes de l'article de Heroku mentionné ci-dessus pour générer la clé. J'ai alors écrit un nouveau fichier de configuration OpenSSL:

[ req ]
default_bits        = 2048
distinguished_name  = req_distinguished_name
req_extensions      = san
extensions          = san
[ req_distinguished_name ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com

Puis généré le server.crtavec la commande suivante:

openssl req \
-new \
-key server.key \
-out server.csr \
-config config.cnf \
-sha256 \
-days 3650

Je suis sur un Mac, alors j'ai ouvert le server.crtfichier avec Keychain, je l'ai ajouté à mes certificats système. Je l'ai ensuite réglé sur Always Trust.

À l'exception du fichier de configuration permettant de définir la valeur SAN, ces étapes étaient les mêmes que celles utilisées dans les versions précédentes de Chrome pour générer et faire confiance au certificat auto-signé.

Cependant, je reçois toujours le ERR_CERT_COMMON_NAME_INVALIDdans Chrome 58 après cela .

bcardarella
la source

Réponses:

62

Ma solution:

openssl req \
    -newkey rsa:2048 \
    -x509 \
    -nodes \
    -keyout server.key \
    -new \
    -out server.crt \
    -subj /CN=dev.mycompany.com \
    -reqexts SAN \
    -extensions SAN \
    -config <(cat /System/Library/OpenSSL/openssl.cnf \
        <(printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')) \
    -sha256 \
    -days 3650

Statut: Fonctionne pour moi

bcardarella
la source
2
grande utilisation de sous-shell. Je pense que vous pouvez simplifier un peu:-config <(cat /System/Library/OpenSSL/openssl.cnf ; printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')
jrwren
1
Je ne reçois plus l'erreur Nom du sujet alt, mais maintenant, je reçois une erreur concernant le nom commun et la définition du certificat téléchargé sur "toujours confiance" ne fonctionne pas. Des pensées? @bcardarella
rugbert
2
Avec la mise à jour de Chrome 59, le certificat indique une erreur comme celle-ci: Il existe des problèmes avec la chaîne de certificats du site (net :: ERR_CERT_COMMON_NAME_INVALID).
theHarsh
1
J'ai changé dev.company.namepour localhostet cela a fonctionné pour servir le site de développement local de localhost. Sur macOS, je devais également ajouter le certificat à Keychain et définir SSL sur "Toujours faire confiance".
Daniel M.
1
C'est de loin la solution la plus simple et ne nécessite pas de visser avec sslconf ou d'installer une autorité de certification.
p.
16

Sous Windows, enregistrez ce script dans votre dossier SSL sous le nom makeCERT.bat. Il créera les fichiers suivants: exemple.cnf, exemple.crt, exemple.key

@echo off

REM IN YOUR SSL FOLDER, SAVE THIS FILE AS: makeCERT.bat
REM AT COMMAND LINE IN YOUR SSL FOLDER, RUN: makecert
REM IT WILL CREATE THESE FILES: example.cnf, example.crt, example.key
REM IMPORT THE .crt FILE INTO CHROME Trusted Root Certification Authorities
REM REMEMBER TO RESTART APACHE OR NGINX AFTER YOU CONFIGURE FOR THESE FILES

REM PLEASE UPDATE THE FOLLOWING VARIABLES FOR YOUR NEEDS.
SET HOSTNAME=example
SET DOT=com
SET COUNTRY=US
SET STATE=KS
SET CITY=Olathe
SET ORGANIZATION=IT
SET ORGANIZATION_UNIT=IT Department
SET EMAIL=webmaster@%HOSTNAME%.%DOT%

(
echo [req]
echo default_bits = 2048
echo prompt = no
echo default_md = sha256
echo x509_extensions = v3_req
echo distinguished_name = dn
echo:
echo [dn]
echo C = %COUNTRY%
echo ST = %STATE%
echo L = %CITY%
echo O = %ORGANIZATION%
echo OU = %ORGANIZATION_UNIT%
echo emailAddress = %EMAIL%
echo CN = %HOSTNAME%.%DOT%
echo:
echo [v3_req]
echo subjectAltName = @alt_names
echo:
echo [alt_names]
echo DNS.1 = *.%HOSTNAME%.%DOT%
echo DNS.2 = %HOSTNAME%.%DOT%
)>%HOSTNAME%.cnf

openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout %HOSTNAME%.key -days 3560 -out %HOSTNAME%.crt -config %HOSTNAME%.cnf
ST Wilson
la source
13

Voici une solution qui fonctionne pour moi:

Créer une clé de certification et un certificat

# openssl genrsa -out server_rootCA.key 2048
# openssl req -x509 -new -nodes -key server_rootCA.key -sha256 -days 3650 -out server_rootCA.pem

Créer serveur_rootCA.csr.cnf

# server_rootCA.csr.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=DE
ST=Berlin
L=NeuKoelln
O=Weisestrasse
OU=local_RootCA
[email protected]
CN = server.berlin

Créer un fichier de configuration v3.ext

# v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = server.berlin

Créer une clé de serveur

# openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config <( cat server_rootCA.csr.cnf )

Créer un certificat de serveur

# openssl x509 -req -in server.csr -CA server_rootCA.pem -CAkey server_rootCA.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile v3.ext

Ajouter un certificat et une clé dans la section HTTPS (port 443) du fichier de site Apache2

SSLCertificateFile    /etc/apache2/ssl/server.crt
SSLCertificateKeyFile    /etc/apache2/ssl/server.key

Copiez server_rootCA.pem du serveur sur votre ordinateur.

# scp [email protected]:~/server_rootCA.pem .

.. et l'ajouter au navigateur Chromium

Chromium -> Setting -> (Advanced) Manage Certificates -> Import -> 'server_rootCA.pem'

VOUS ÊTES TOUT FAIT!

PS Au lieu de créer une paire de certificats d’autorité de certification de serveur et de serveur (selon les instructions ci-dessus), vous pouvez simplement désactiver les en-têtes HSTS dans la configuration de votre serveur HTTP. Cela empêchera Chromium d'appliquer HTTPS et permettra aux utilisateurs de cliquer sur «Avancé → passer à votre fichier .url (non sécurisé)» sans avoir à obtenir et installer votre certificat CA personnalisé (racine_serveur). En d'autres termes, le fait de désactiver HSTS permettra à votre site d'être affiché publiquement via HTTP et / ou une connexion HTTPS non sécurisée (méfiez-vous!).

Pour Apache2, ajoutez ce qui suit au fichier de site, section HTTP (port 80)

Header unset Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=0;includeSubDomains"

Testé sur Debian / Apache2.4 + Debian / Chromium 59

https://ram.k0a1a.net/self-signed_https_cert_after_chrome_58

binary.koala
la source
Le chemin emprunté par une autorité de certification racine qui signe plus tard les certificats individuels est le seul moyen d'obtenir l'authentification complète de chrome. a aussi l’avantage que je n’avais besoin que d’amener les gens à installer un seul certificat. Merci
geoff
4
Quelqu'un peut - il s'il vous plaît me expliquer pourquoi tout le monde dans ce domaine semble utiliser comme bashismes au -config <( cat server_rootCA.csr.cnf )lieu de simplement -config server_rootCA.csr.cnf?
César
Pouvez-vous s'il vous plaît mettre à jour votre réponse concernant les en-têtes Apache qui peuvent contourner le problème (cela ne me dérange pas que ce soit pour les sites locaux à des fins de développement uniquement et je voudrais créer une solution générique sans avoir à générer de nouveaux certificats à chaque fois). Pouvez-vous indiquer à quel endroit dans une définition d'hôte virtuel elles devraient aller? J'ai essayé plusieurs alternatives et je ne peux toujours pas accéder aux sites via https. Merci
Nikos M.
12

Il y a plusieurs bonnes réponses qui donnent des exemples sur la façon de faire fonctionner cela, mais aucune qui n'explique où les choses se sont mal passées lors de votre tentative. OpenSSL peut être assez non intuitif à certains moments, il vaut donc la peine de s'y intéresser.

Tout d’abord, OpenSSL ignore, par défaut, les valeurs de nom distinctif fournies dans la configuration. Si vous voulez les utiliser, vous devez ajouter prompt = no à votre configuration. De plus, la commande telle qu’elle est écrite ne génère qu’une demande de certificat, pas un certificat lui-même; elle -daysne fait donc rien.

Si vous générez votre demande de certificat à l'aide de la commande que vous avez donnée et inspectez le résultat, le nom d'objet alternatif est présent:

$ openssl req -new -key server.key -out server.csr -config config.cnf -sha256
$ openssl req -text -noout -in server.csr
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:dev.mycompany.com
    Signature Algorithm: sha256WithRSAEncryption
         ...

Mais ensuite, si vous générez le certificat à l'aide de la commande heroku link et examinez le résultat, le nom alt du sujet est manquant:

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
$ openssl x509 -text -noout -in server.crt
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            89:fd:75:26:43:08:04:61
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Validity
            Not Before: Jan 21 04:27:21 2018 GMT
            Not After : Jan 21 04:27:21 2019 GMT
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         ...

La raison en est que par défaut, OpenSSL ne copie pas les extensions de la demande vers le certificat. Normalement, le certificat serait créé / signé par une autorité de certification à la demande d'un client, et certaines extensions pourraient accorder au certificat plus de puissance que l'intention de l'autorité de certification si elles devaient faire confiance aux extensions définies dans la demande.

Il existe des moyens de demander à OpenSSL de copier les extensions, mais à mon humble avis, cela représente plus de travail que de simplement fournir les extensions dans un fichier de configuration lorsque vous générez le certificat.

Si vous essayez d'utiliser votre fichier de configuration existant, cela ne fonctionnera pas car la section de niveau supérieur est marquée de [req]sorte que ces paramètres s'appliquent uniquement à la commande req et non à la commande x509. Il n'est pas nécessaire d'avoir un marqueur de section de niveau supérieur, vous pouvez donc simplement supprimer cette première ligne, et cela fonctionnera correctement pour la génération de requêtes ou le certificat.

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt -extfile config.cnf

Vous pouvez également utiliser l' -x509argument de la reqcommande pour générer un certificat auto-signé en une seule commande, plutôt que de créer d'abord une demande, puis un certificat. Dans ce cas, il n'est pas nécessaire de supprimer la [req]ligne de section car cette section est lue et utilisée par la commande req.

$ openssl req -x509 -sha256 -days 365 -key server.key -out server.crt -config config.cnf

Pour récapituler, voici le fichier de configuration modifié utilisé dans les commandes ci-dessus:

default_bits        = 2048
distinguished_name  = dn
x509_extensions     = san
req_extensions      = san
extensions          = san
prompt              = no
[ dn ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com
Pavon
la source
2
C'est la seule explication qui m'a permis de comprendre pourquoi le certificat est sorti sans SAN (dans mon cas, je devais inclure x509_extensions dans le fichier de configuration)
Daniel Beardsmore
2

Ma solution est de garder le principal openssl.cnfcomme il est et juste à la fin pour ajouter une nouvelle section comme [ cert_www.example.com ]où www.example.com est le site pour lequel je veux créer un certificat, et en elle, a mis le subjectAltNameje aurais besoin (et rien d'autre). Bien sûr, la section peut être nommée comme vous le souhaitez.

Après cela, je peux exécuter la openssl reqcommande comme avant, en ajoutant simplement -extensions cert_www.example.compour que son contenu soit repris et -subjen ajoutant directement toutes les informations de DN.

N'oubliez pas de vérifier le contenu du certificat après sa création et avant son utilisation, avec openssl x509 -text

Patrick Mevzek
la source
1

Script Bash avec config cuit dedans

En tant que script shell qui devrait fonctionner sur toutes les plateformes avec bash. Suppose que l’ HOSTNAMEenvironnement défini pour le shell ou fournisse un nom d’hôte de votre choix, par exemple:self_signed_cert.sh test

set -e

if [ -z "$1" ]; then
  hostname="$HOSTNAME"
else
  hostname="$1"
fi

local_openssl_config="
[ req ]
prompt = no
distinguished_name = req_distinguished_name
x509_extensions = san_self_signed
[ req_distinguished_name ]
CN=$hostname
[ san_self_signed ]
subjectAltName = DNS:$hostname, DNS:localhost
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign, cRLSign
extendedKeyUsage = serverAuth, clientAuth, timeStamping
"

openssl req \
  -newkey rsa:2048 -nodes \
  -keyout "$hostname.key.pem" \
  -x509 -sha256 -days 3650 \
  -config <(echo "$local_openssl_config") \
  -out "$hostname.cert.pem"
openssl x509 -noout -text -in "$hostname.cert.pem"

Ce qui précède injecte plus ou moins le minimum de configuration dont le fichier d’information a besoin.

Note, inclus en DNS:localhosttant que SAN pour permettre le test via localhost plus facilement. Supprimez ce bit supplémentaire du script si vous ne le souhaitez pas.

Crédit

La réponse de bcardarella est excellente ( je ne peux pas commenter / voter en raison d'un représentant insuffisant). Cependant, la réponse utilise un emplacement de fichier de configuration openssl existant qui est spécifique à la plate-forme ... par conséquent:

Travaille pour moi

De toute évidence, il vous suffira simplement de trouver le fichier de configuration openssl pour votre propre plate-forme et de remplacer l'emplacement correct.

Tester

Pour tester, importez test.cert.pemdans les autorités de chrome dans chrome://settings/certificateset:

openssl s_server -key test.key.pem -cert test.cert.pem -accept 20443 -www &
openssl_pid=$!
google-chrome https://localhost:20443

Et après avoir testé

kill $openssl_pid
JPvRiel
la source