From 5081d5137a506f4b5aeaacaf25b8926b5b4ca291 Mon Sep 17 00:00:00 2001 From: Roger Rutishauser Date: Mon, 21 Oct 2024 12:41:43 +0200 Subject: [PATCH] tls --- tls-ssl/README.md | 188 +++++++++++++++++++++++++++++++++++----- tls-ssl/img/ssl_tls.png | Bin 0 -> 19245 bytes 2 files changed, 166 insertions(+), 22 deletions(-) create mode 100755 tls-ssl/img/ssl_tls.png diff --git a/tls-ssl/README.md b/tls-ssl/README.md index 9bbc082..debf1d9 100644 --- a/tls-ssl/README.md +++ b/tls-ssl/README.md @@ -6,18 +6,144 @@ include_toc: true Übersicht: https://www.sslmarket.ch/ssl/formate-von-ssl-zertifikaten-und-ihre -## cacerts / java +## Windows TLS aktivieren -## Neues Zertifikat in cacerts einfügen +Unter Windows muss TLS 1.0, TLS 1.1 und TLS 1.2 aktiviert werden. Dies kann in den Internet Options vom Internet Explorer gemacht werden: + +![](./img/ssl_tls.png) + + +## Zertifikat-Dateien umwandeln, bündeln etc. + +### Chained Certificate erstellen + +Ein Chained Certificate enthält das Server Zertifikat sowie Intermediate-/Root-Zertifikate. + + - Falls nur das Server-Zertifikat vorhanden ist, muss das Root- und Intermediate-Zertifikat separat aus dem Browser herunter geladen werden. Bei der Export-Möglichkeit sollte Base-64 codiert im X.509 Standard (.cer) gewählt werden. Die 3 Teile müssen dann wie im nächsten Punkt beschrieben in einer Datei zusammengefasst werden. + - Falls ein "Bundle" (Root- und Intermediate-Zertifikat) und ein Server-Zertifikat separat geliefert wird, muss dies in eine Datei zusammengefügt werden: + +1. Position: Server-Zertifikat\ +2. Position: Intermediate Zertifikat\ +3. Position: Root-Zertifikat. + +Abspeichern als .chained.crt. + +### PFX erstellen aus Server-Zertifikat und Key + +Um das Zertifikat in das gewünschte Format zu bekommen brauch man zuerst die 2 Basis-Dateien: + + - Zertifikat ("pem", "cer", "crt" oder andere Dateiendung) + - Der Private Key (oft mit ".key" Dateiendung), welcher mit dem CSR erstellt wird und zu diesem Zertifikat gehört. + +Um Intermediate und Root-Zertifikate mit in das PKCS12 aufzunehmen, bedarf es einen einfachen Tricks: + + - Server-Zertifikat in PEM Format (Base64 encoded) abspeichern + - Private Key in PEM Format (Base64 encoded) abspeichern + - Server-Zertifikat in Editor öffnen + - Darunter Intermediate und Root Zertifikate einfügen (in dieser Reihenfolge) + - Wir haben nun ein Full Chained Certificate, das wir als .crt abspeichern.  + +Nun wir die gebündelte Datei (.crt) und der Privatekey (.key) mit openssl zu einer Datei zusammengefasst zu der .pfx (oder je nach gusto .p12) Datei. ``` -keytool -importcert -file cert.pem -alias nwvappdaing001t -keystore cacerts_tryout +openssl pkcs12 -export -in chained.crt -inkey privateekey.key -out output.pfx +``` + +Die erzeugte p12 Datei enthält jetzt den privaten Schlüssel und das Zertifikat. Der Inhalt wird mit einem Passwort geschützt, das beim Absetzen des Befehls abgefragt wird. + +Zu einer bereits bestehenden PKCS12 Datei können die Intermediates mit folgendem Befehl hinzugefügt werden: + +``` +openssl pkcs12 -export -inkey (Ihr Privatekey).key -in (Ihr Zertifikat).crt -out (Zertifikats Name).p12 -chain -CApath /etc/ssl/certs +``` + +### Convert PKS12 (.pfx) to Base64 + +#### Extract the private key from a PFX to a PEM file + +``` +openssl pkcs12 -in filename.pfx -nocerts -out key.pem # enter any temp passphrase +``` + +#### Removing the password from the private key + +``` +openssl rsa -in key.pem -out server.key # <- that is what we need for nginx +``` + +#### Extract the certificate + +``` +openssl pkcs12 -in filename.pfx -clcerts -nokeys -out cert_only.pem +``` + +As DER (binary), not PEM. Using PowerShell: + +``` Powershell +Get-PfxCertificate -FilePath filename.pfx | Export-Certificate -FilePath cert_only.cer -Type CERT +``` + +#### Extract the certificate chain (root and intermediate) + +``` +openssl pkcs12 -in 05-srvingesttst01.pfx -cacerts -nokeys -out cert.pem +``` + +### Convert Base64 to DER (binary) + +Used for cacerts, for example + +``` +openssl x509 -in cert.crt -outform der -out cert.der +# view: +openssl x509 -in cert.der -inform der -text -noout +``` + +### Convert DER (binary) to Base64 + +``` +openssl x509 -in cert.crt -inform der -outform pem -out cert.pem +# view: +openssl x509 -in cert.pem -text -noout +``` + +## IIS (Windows) + + - PFX Datei in IIS importieren + - altes Zertifikat entfernen + - Bindings prüfen und allenfalls anpassen + +## Nginx (Linux) + +Die `.key` und `*.chained.crt` Dateien können wie hier beschrieben für die Konfiguration verwendet werden. + +## Cacerts / Java + +### Truststore + +`javax.net.ssl.trustStore`, der Truststore für CA-Zertifikate. + +Cacerts ist ein Truststore (vertraut den Zertifikaten). Der Default-Speicherort des cacerts ist `jre/lib/security`. Darin befinden sich die Root Zertifikate von den grössten Zertifizierungsstellen (ca. 104) Diesen Root Zertifikaten vertraut Java von Haus aus und alle anderen werden blockiert. Man kann hier weitere hinzufügen oder ein ganze neues cacerts bauen. + +Java lehnt Zertifikate, die nicht im cacerts vorhanden sind aus Sicherheitsgründen ab. Ein Self Signed Certificate oder das Rootertifikat muss deshalb manuell hinterlegt werden. Ab diesem Moment "vertraut" Java diesem Zertifikat. + +### Neues Zertifikat in cacerts einfügen + +``` +keytool -importcert -trustcacerts -file /path/to/cert.pem -alias EinAliasName -keystore /path/to/cacerts -storepass changeit -noprompt +``` + +Ab Java 9 kann das PEM (base64 encoded) Zertifikat verwendet werden.\ +Bei Java < 9 sollte das Zertifikat im x509 DER Format vorliegen. Allenfalls ist eine Konvertierung nötig: + +``` +openssl x509 -outform der -in certificate.pem -out certificate.der ``` ### Zertifikat aus cacerts exportieren ``` -keytool -export -storepass changeit -alias arc2004.bgov.ch -keystore cacerts -file arc2003.bgov.ch.crt +keytool -export -storepass changeit -alias DerAliasName -keystore cacerts -file FQDNname.crt ``` ### Alle Einträge in cacerts auflisten @@ -32,29 +158,47 @@ keytool -list -v -keystore "c:\...\cacerts" > cacerts_output.txt keytool -delete -alias aliasname -keystore ..\cacerts ``` -## Verschiedenes - -### PKS12 (.pfx) in base64 umwandeln - +### Alias eines Keys im Keystore ändern ``` -openssl pkcs12 -in filename.pfx -clcerts -nokeys -out filename.pem +keytool -changealias -alias "your-very-very-long-alias" -destalias "new-alias" -keystore "/path/to/cacerts" ``` -### PFX erstellen aus server-zertifikat und key + +## Tomcat (unter Windows) + +Das Keystore-File von Tomcat beinhaltet das Serverzertifikat, die Chain of Trust (Root-/Intermediate Zertifikate), und den private Key. Tomcat verwendet JKS, PKCS11 or PKCS12 format keystores. Das JKS format ist Java's standard "Java KeyStore" Format. Das PKCS12 Format ist ein Internetstandard, und kann mit OpenSSL oder Microsoft's Key-Manager manipuliert werden.\ +Bei älteren Tomcat-Versionen (<8 ?) muss möglicherweise PFX in JKS umgewandelt werden: ``` -openssl pkcs12 -export -in linux_cert+ca.pem -inkey privateekey.key -out output.pfx +Keytool -importkeystore -srckeystore server.pfx -srcstoretype pkcs12 -destkeystore tomcat.jks -deststoretype jks ``` -Oder mit Keystore Explorer: +Anschliessend in `tomcat/conf/server.xml` im von 443 oder 8443 die Angaben zu `keystoreFile` und `keystorePass` machen. - - Root als base64 exportieren - - Intermediate als base64 exportieren - - Serverzertifikat durch M. Kandlbinder geliefert und in C:\docuteam\ssl-zertifikate-06-2022 abgelegt - - In Keystore Explorer: Neu - - PKCS#12 wählen - - Root und Intermediate importieren - - Schlüsselpaar PKCS#8 erstellen, dabei Key und Serverzertifikat angeben - - default PW geben - - Abspeichern als PFX - - PFX bei Fedora Servern in Tomcat Conf Ordner ablegen +Zudem muss in den Tomcat Monitor Configurations im Tab „Java“ der Pfad zum Java Truststore (cacerts) hinzugefügt werden: + +``` +-Djavax.net.ssl.trustStore=D:\docuteam\apps\jdk\jre\lib\security\cacerts. +``` + +## Ruby (unter Windows) + +Damit Ruby Apps verschlüsselte Verbindungen über Self-Signed Certificates herstellen kann, muss das Root/Intermediate Zertifikat hinterlegt werden. + + - Intermediate und Root Zertifikat separat abspeichern als Base-64. + - Dateiendung auf .pem anpassen, falls dies noch nicht der Fall ist. + - Die 2 Dateien im Ordner `...\Ruby2x-x64\ssl\certs` ablegen. + - Das `c_rehash.rb` Skript im selben Ordner aus CMD heraus ausführen.: `D:\...\Ruby26-x64\ssl\certs>ruby c_rehash.rb` + - Ab Ruby 3.2.2 befinden sich die Zertifikate und `c_rehash.rb` in `D:\...\Ruby32-x64\bin\etc\ssl\certs` + +## Weitere nützliche Befehle + +### Überprüfen, ob Key, CRT und CSR zusammen passen + +Mit folgenden Befehlen kann überprüft werden, ob Key, CRT und CSR zusammen passen (muss 3x die gleiche Checksumme ergeben): + +``` +openssl rsa -noout -modulus -in irgendEinName.key.pem | openssl md5 +openssl x509 -noout -modulus -in irgendEinName.crt.pem | openssl md5 +openssl req -noout -modulus -in irgendEinName.csr | openssl md5 +``` diff --git a/tls-ssl/img/ssl_tls.png b/tls-ssl/img/ssl_tls.png new file mode 100755 index 0000000000000000000000000000000000000000..48972b56cb943f718206ae1e51984c100b424b37 GIT binary patch literal 19245 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 literal 0 HcmV?d00001