Generazione di un certificato autofirmato con openssl che funziona in Chrome 58


52

A partire da Chrome 58 non accetta più certificati autofirmati che si basano su Common Name: https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category $ 3ACanary% 7Csort: rilevanza% 7Cspell: false

Invece richiede l'utilizzo Subject Alt Name. In precedenza ho seguito questa guida su come generare un certificato autofirmato: https://devcenter.heroku.com/articles/ssl-certificate-self che ha funzionato benissimo perché ho richiesto i file server.crte server.keyper quello che sto facendo. Ora ho bisogno di generare nuovi certificati che includano SANtuttavia tutti i miei tentativi di farlo non hanno funzionato con Chrome 58.

Ecco cosa ho fatto:

Ho seguito i passaggi sull'articolo Heroku sopra menzionato per generare la chiave. Ho quindi scritto un nuovo file di configurazione 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

Quindi ha generato il server.crtcon il seguente comando:

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

Sono su un Mac, quindi ho aperto il server.crtfile con Keychain, l'ho aggiunto ai miei certificati di sistema. L'ho quindi impostato su Always Trust.

Con l'eccezione del file di configurazione per impostare il valore SAN, questi erano passaggi simili che ho usato nelle versioni precedenti di Chrome per generare e fidarmi del certificato autofirmato.

Tuttavia, dopo questo ho ancora il ERR_CERT_COMMON_NAME_INVALIDChrome 58.

Risposte:


62

La mia soluzione:

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

Stato: funziona per me


2
ottimo uso di subshell. Penso che puoi semplificarlo un po ':-config <(cat /System/Library/OpenSSL/openssl.cnf ; printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')
jrwren,

1
Non ricevo più l'errore Nome oggetto alternativo, ma ora viene visualizzato un errore relativo al nome comune e l'impostazione del certificato scaricato su "sempre attendibile" non funziona. qualche idea? @bcardarella
rugbert

2
Con l'aggiornamento a Chrome 59, il certificato mostra un errore come questo: ci sono problemi con la catena di certificati del sito (net :: ERR_CERT_COMMON_NAME_INVALID).
duro

1
Sono passato dev.company.namea localhoste questo ha funzionato per servire il sito di sviluppo locale da localhost. Su macOS ho anche dovuto aggiungere il certificato a Keychain e impostare SSL su "Sempre attendibile".
Daniel M.

1
Questa è di gran lunga la soluzione più semplice e non richiede di andare in giro con sslconf o installare una CA.
bp.

16

In Windows, salva questo script nella cartella SSL come makeCERT.bat. Creerà questi file: esempio.cnf, esempio.crt, esempio.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

13

Ecco una soluzione che funziona per me:

Crea chiave CA e certificato

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

Crea server_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
emailAddress=ikke@server.berlin
CN = server.berlin

Crea il file di configurazione v3.ext

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

[alt_names]
DNS.1 = server.berlin

Crea chiave server

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

Crea certificato server

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

Aggiungi certificato e chiave al file del sito Apache2, sezione HTTPS (porta 443)

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

Copia server_rootCA.pem dal server sul tuo computer.

# scp you@server.berlin:~/server_rootCA.pem .

.. e aggiungilo al browser Chromium

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

Siete tutti fatti!

PS Invece di creare una coppia CA / server funzionale cert (secondo le istruzioni sopra) potresti semplicemente disabilitare le intestazioni HSTS nella configurazione del tuo server HTTP. Ciò impedirà a Chromium di applicare HTTPS e consentirà agli utenti di fare clic su "Avanzate → passare a your.url (non sicuro)" senza dover ottenere e installare il certificato CA (server_rootCA.pem) personalizzato. In altre parole, la disabilitazione di HSTS consentirà al tuo sito di essere visualizzato pubblicamente su HTTP e / o di una connessione HTTPS non sicura (attenzione!).

Per Apache2 aggiungere quanto segue alla sezione HTTP (porta 80) del file del sito

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

Testato su Debian / Apache2.4 + Debian / Chromium 59

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


Seguire il percorso di un'autorità CA principale che in seguito firma i singoli certificati è l'unico modo per ottenere l'autenticazione di Chrome; ha anche il vantaggio che avevo solo bisogno di convincere le persone a installare un singolo certificato. Grazie
geoff il

4
Qualcuno può spiegarmi perché tutti in questo settore sembrano usare basismi come -config <( cat server_rootCA.csr.cnf )invece di solo -config server_rootCA.csr.cnf?
Cesare,

puoi aggiornare la tua risposta relativa alle intestazioni di apache che possono aggirare il problema (non mi dispiace che questo sia solo per i siti locali per lo sviluppo e vorrei fare un esempio generico senza dover generare nuovi certificati ogni volta). Puoi indicare dove all'interno di una definizione di host virtuale dovrebbero andare. Ho provato diverse alternative e ancora non riesco ad accedere ai siti tramite https. Grazie
Nikos M. il

12

Ci sono molte grandi risposte che forniscono esempi di come farlo funzionare, ma nessuna che spiega dove le cose sono andate male nel tuo tentativo. OpenSSL può essere piuttosto non intuitivo alcune volte, quindi vale la pena passarci attraverso.

Innanzitutto, per impostazione predefinita, OpenSSL ignora qualsiasi valore di nome distinto fornito nella configurazione. Se vuoi usarli devi aggiungere prompt = no alla tua configurazione. Inoltre, il comando come scritto genera solo una richiesta di certificato e non un certificato stesso, quindi il -dayscomando non fa nulla.

Se si genera la richiesta di certificato utilizzando questo comando fornito e si controlla il risultato, è presente il Nome alternativo oggetto:

$ 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
         ...

Ma se si genera il certificato utilizzando il comando nel collegamento heroku e si controlla il risultato, manca il nome alternativo dell'oggetto:

$ 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
         ...

Il motivo è che per impostazione predefinita OpenSSL non copia le estensioni dalla richiesta al certificato. Normalmente, il certificato viene creato / firmato da un'autorità di certificazione sulla base di una richiesta di un cliente e alcune estensioni potrebbero concedere al certificato più potenza di quella che la CA intendeva se si fidassero ciecamente delle estensioni definite nella richiesta.

Ci sono modi per dire a OpenSSL di copiare le estensioni, ma IMHO è più lavoro che fornire le estensioni in un file di configurazione quando si genera il certificato.

Se si dovesse tentare di utilizzare il file di configurazione esistente, non funzionerà perché la sezione di livello superiore è contrassegnata, [req]pertanto tali impostazioni si applicano solo al comando req e non al comando x509. Non è necessario avere un marcatore di sezione di livello superiore, quindi puoi semplicemente rimuovere quella prima riga e quindi funzionerà bene sia per generare richieste che per certificati.

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

In alternativa, è possibile utilizzare l' -x509argomento per il reqcomando per generare un certificato autofirmato in un singolo comando, anziché creare prima una richiesta e quindi un certificato. In questo caso non è necessario rimuovere la [req]linea di sezione, poiché quella sezione viene letta e utilizzata dal comando req.

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

Per ricapitolare, ecco il file di configurazione modificato utilizzato nei comandi sopra:

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

2
Questa è l'unica spiegazione che mi ha aiutato a capire perché il certificato è stato rilasciato senza una SAN (nel mio caso, avevo bisogno di includere x509_extensions nel file di configurazione)
Daniel Beardsmore il

2

La mia soluzione è quella di mantenere il principale openssl.cnfcosì com'è e alla fine aggiungere una nuova sezione come [ cert_www.example.com ]dove www.example.com è il sito Web per il quale voglio creare un certificato e, in esso, inserire il subjectAltNamenecessario (e qualunque altra cosa). Naturalmente la sezione potrebbe essere nominata come preferisci.

Dopodiché, posso eseguire il openssl reqcomando come prima, aggiungendo solo -extensions cert_www.example.comper il suo contenuto da raccogliere e aggiungo -subjper aggiungere direttamente tutte le informazioni DN.

Non dimenticare di verificare il contenuto del certificato dopo la sua creazione e prima dell'uso, con openssl x509 -text


1

Script di Bash con configurazione integrata

Come uno script di shell che dovrebbe funzionare su piattaforme diverse con bash. Presuppone che HOSTNAMEenv sia impostato per la shell o fornisca un nome host di propria scelta, ad esself_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"

Quanto sopra inietta più o meno le informazioni minime sul file di configurazione minimo necessario per opensl.

Nota, incluso extra DNS:localhostcome SAN per consentire più facilmente il test tramite localhost. Rimuovi quel bit in più dallo script se non lo desideri.

Credito

La risposta di bcardarella è ottima (non posso commentare / aumentare il voto a causa di un rappresentante insufficiente). Tuttavia, la risposta utilizza un percorso di file di configurazione openssl esistente specifico per la piattaforma ... quindi:

Per me va bene

Ovviamente, bisognerebbe semplicemente trovare il file di configurazione di openssl per la propria piattaforma e sostituire la posizione corretta.

Test

Per un modo di test, importare test.cert.pemnelle autorità di Chrome in chrome://settings/certificatese:

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

E dopo i test

kill $openssl_pid
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.