Generieren eines selbstsignierten Zertifikats mit openssl, das in Chrome 58 funktioniert

52

Ab Chrome 58 werden keine selbstsignierten Zertifikate mehr akzeptiert, für die Folgendes erforderlich ist Common Name: https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category $ 3ACanary% 7Csort: relevance% 7Cspell: false

Stattdessen muss verwendet werden Subject Alt Name. Ich habe zuvor diesen Leitfaden zur Erstellung eines selbstsignierten Zertifikats befolgt: https://devcenter.heroku.com/articles/ssl-certificate-self. Das hat sehr gut funktioniert, da ich die Dateien server.crtund server.keyfür das, was ich tue, benötigte. Ich muss jetzt neue Zertifikate generieren, die SANalle meine Versuche enthalten, dies zu tun, die mit Chrome 58 nicht funktioniert haben.

Folgendes habe ich getan:

Ich habe die Schritte in dem oben erwähnten Heroku-Artikel befolgt, um den Schlüssel zu generieren. Ich habe dann eine neue OpenSSL-Konfigurationsdatei geschrieben:

[ 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

Dann generierte das server.crtmit folgendem Befehl:

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

Ich bin auf einem Mac und habe die server.crtDatei mit dem Schlüsselbund geöffnet und zu meinen Systemzertifikaten hinzugefügt. Ich habe es dann auf eingestellt Always Trust.

Mit Ausnahme der Konfigurationsdatei zum Festlegen des SAN-Werts waren dies ähnliche Schritte, die ich in früheren Chrome-Versionen ausgeführt habe, um das selbstsignierte Zertifikat zu generieren und ihm zu vertrauen.

Danach bekomme ich allerdings noch die ERR_CERT_COMMON_NAME_INVALIDin Chrome 58.

Cardarella
quelle

Antworten:

62

Meine Lösung:

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

Status: Funktioniert bei mir

Cardarella
quelle
2
große Verwendung von Unterschale. Ich denke, Sie können es ein wenig vereinfachen:-config <(cat /System/Library/OpenSSL/openssl.cnf ; printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')
Jrwren
1
Ich erhalte nicht mehr den Fehler "Betreff alt", aber jetzt erhalte ich einen Fehler bezüglich des allgemeinen Namens, und das Festlegen des heruntergeladenen Zertifikats auf "Immer vertrauen" funktioniert nicht. Irgendwelche Gedanken? @bcardarella
rugbert
2
Bei der Aktualisierung auf Chrome 59 wird im Zertifikat der folgende Fehler angezeigt: Es gibt Probleme mit der Zertifikatskette der Site (net :: ERR_CERT_COMMON_NAME_INVALID).
theHarsh
1
Ich wechselte dev.company.namezu localhostund dies funktionierte, um die lokale Entwicklungsseite von localhost zu bedienen. Unter macOS musste ich auch das Zertifikat zu Keychain hinzufügen und SSL auf "Always Trust" setzen.
Daniel M.
1
Das ist bei weitem die einfachste Lösung und erfordert kein Verschrauben mit sslconf oder Installieren einer Zertifizierungsstelle.
bp.
16

Speichern Sie dieses Skript unter Windows in Ihrem SSL-Ordner als makeCERT.bat. Es werden die folgenden Dateien erstellt: example.cnf, example.crt, example.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
STWilson
quelle
13

Hier ist eine Lösung, die für mich funktioniert:

CA-Schlüssel und Zertifikat erstellen

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

Erstellen Sie 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
[email protected]
CN = server.berlin

Erstellen Sie die Konfigurationsdatei v3.ext

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

[alt_names]
DNS.1 = server.berlin

Serverschlüssel erstellen

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

Erstellen Sie ein Server-Zertifikat

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

Fügen Sie cert und key zur Apache2-Site-Datei, Abschnitt HTTPS (Port 443), hinzu

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

Kopieren Sie server_rootCA.pem vom Server auf Ihren Computer.

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

.. und zum Chromium-Browser hinzufügen

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

SIE SIND ALLE FERTIG!

PS Anstatt ein funktionsfähiges CA- und Server-Zertifizierungspaar zu erstellen (gemäß den obigen Anweisungen), können Sie einfach HSTS-Header in Ihrer HTTP-Serverkonfiguration deaktivieren. Dadurch wird verhindert, dass Chromium HTTPS erzwingt, und Benutzer können auf "Erweitert → Weiter mit Ihrer URL (unsicher)" klicken, ohne das benutzerdefinierte CA-Zertifikat (server_rootCA.pem) anfordern und installieren zu müssen. Mit anderen Worten: Wenn Sie HSTS deaktivieren müssen, kann Ihre Site über HTTP und / oder eine unsichere HTTPS-Verbindung öffentlich angezeigt werden (Vorsicht!).

Fügen Sie für Apache2 der Site-Datei den folgenden Abschnitt hinzu: HTTP (Port 80)

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

Getestet auf Debian / Apache2.4 + Debian / Chromium 59

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

binary.koala
quelle
Der Weg einer Stammzertifizierungsstelle, die später die einzelnen Zertifikate signiert, ist der einzige Weg, mit dem ich Chrome zur vollständigen Authentifizierung bringen kann. hat auch den vorteil, dass ich nur leute dazu bringen musste, ein einziges cert zu installieren. Thanks
Geoff
4
Kann mir bitte jemand erklären, warum jeder in diesem Bereich Bashismen wie -config <( cat server_rootCA.csr.cnf )anstatt nur verwendet -config server_rootCA.csr.cnf?
Caesar
Können Sie bitte Ihre Antwort in Bezug auf die Apache-Header aktualisieren, die das Problem umgehen können? Können Sie darauf hinweisen, wohin diese in einer virtuellen Hostdefinition gehen sollten? Ich habe mehrere Alternativen ausprobiert und kann immer noch nicht über https auf die Websites zugreifen. Vielen Dank
Nikos M.
12

Es gibt mehrere gute Antworten, die Beispiele dafür geben, wie dies funktioniert, aber keine, die erklären, wo bei Ihrem Versuch etwas schief gelaufen ist. OpenSSL kann manchmal ziemlich unintuitiv sein, es lohnt sich also, durchzugehen.

Nebenbei bemerkt, ignoriert OpenSSL standardmäßig alle Distinguished Name-Werte, die Sie in der Konfiguration angeben. Wenn Sie sie verwenden möchten, müssen Sie prompt = no zu Ihrer Konfiguration hinzufügen . Darüber hinaus, wie der Befehl ein Zertifikat geschrieben erzeugt nur Anforderung kein Zertifikat selbst, so dass der -daysBefehl nichts tut.

Wenn Sie Ihre Zertifikatsanforderung mit dem von Ihnen angegebenen Befehl generieren und das Ergebnis überprüfen, wird der Betreff-Alternativname angezeigt:

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

Wenn Sie dann das Zertifikat mit dem Befehl in heroku link generieren und das Ergebnis überprüfen, fehlt der Betreff-Alternativname:

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

Der Grund dafür ist, dass OpenSSL standardmäßig keine Erweiterungen von der Anforderung in das Zertifikat kopiert. Normalerweise wird das Zertifikat von einer Zertifizierungsstelle auf der Grundlage einer Kundenanforderung erstellt / signiert, und einige Erweiterungen können dem Zertifikat mehr Leistung verleihen, als die Zertifizierungsstelle beabsichtigt hat, wenn sie den in der Anforderung definierten Erweiterungen blind vertrauen.

Es gibt Möglichkeiten, OpenSSL anzuweisen, die Erweiterungen zu kopieren, aber es ist meiner Meinung nach mehr Arbeit, als nur die Erweiterungen in einer Konfigurationsdatei anzugeben, wenn Sie das Zertifikat generieren.

Wenn Sie versuchen sollten, Ihre vorhandene Konfigurationsdatei zu verwenden, funktioniert dies nicht, da der oberste Abschnitt markiert ist und [req]diese Einstellungen nur für den Befehl req und nicht für den Befehl x509 gelten. Es ist nicht erforderlich, über eine Abschnittsmarkierung der obersten Ebene zu verfügen. Sie können also einfach die erste Zeile entfernen, und dann funktioniert dies sowohl für das Generieren von Anforderungen als auch für das Erstellen von Zertifikaten.

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

Alternativ können Sie das -x509Argument für den reqBefehl verwenden, um ein selbstsigniertes Zertifikat in einem einzigen Befehl zu generieren, anstatt zuerst eine Anforderung und dann ein Zertifikat zu erstellen. In diesem Fall muss die [req]Abschnittszeile nicht entfernt werden, da dieser Abschnitt vom Befehl req gelesen und verwendet wird.

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

Um es noch einmal zusammenzufassen, hier ist die geänderte Konfigurationsdatei, die in den obigen Befehlen verwendet wird:

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
quelle
2
Dies ist die einzige Erklärung, die mir geholfen hat, zu verstehen, warum das Zertifikat ohne SAN ausgegeben wurde (in meinem Fall musste x509_extensions in die Konfigurationsdatei aufgenommen werden)
Daniel Beardsmore,
2

Meine Lösung besteht darin, das Wesentliche openssl.cnfso zu belassen, wie es ist, und am Ende einen neuen Abschnitt hinzuzufügen, [ cert_www.example.com ]in dem beispielsweise www.example.com die Website ist, für die ich ein Zertifikat erstellen subjectAltNamemöchte noch etwas). Natürlich kann der Abschnitt beliebig benannt werden.

Danach kann ich den openssl reqBefehl wie zuvor ausführen , indem ich nur -extensions cert_www.example.comden Inhalt hinzufüge -subj, der abgerufen werden soll, und füge hinzu, dass alle DN-Informationen direkt hinzugefügt werden.

Vergessen Sie nicht, den Inhalt des Zertifikats nach seiner Erstellung und vor seiner Verwendung mit zu überprüfen openssl x509 -text

Patrick Mevzek
quelle
1

Bash-Skript mit eingebauter Konfiguration

Als Shell-Skript, das plattformübergreifend mit bash funktionieren soll. Nimmt HOSTNAMEenv set für die Shell an oder liefert einen Hostnamen Ihrer Wahl, zself_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"

Das obige fügt mehr oder weniger das Nötigste ein, was die Konfigurationsdatei info openssl benötigt.

Hinweis: Wird DNS:localhostals SAN mitgeliefert , um das Testen über localhost zu vereinfachen. Entfernen Sie dieses zusätzliche Bit aus dem Skript, wenn Sie es nicht möchten.

Kredit

Die Antwort von bcardarella ist großartig (kann wegen unzureichender Wiederholung nicht kommentieren / up-vote). Die Antwort verwendet jedoch einen vorhandenen plattformspezifischen Speicherort für die Konfigurationsdatei von openssl ... daher:

Funktioniert bei mir

Offensichtlich müsste man einfach die openssl-Konfigurationsdatei für die von Ihnen angegebene Plattform finden und den richtigen Speicherort angeben.

Prüfung

Importieren Sie zum Testen test.cert.pemin die Chrome-Berechtigungen in chrome://settings/certificatesund:

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

Und nach dem Testen

kill $openssl_pid
JPvRiel
quelle