# Frage zum Keystore



## Joob (9. Mai 2021)

Kann man in einer App beim Start

1. eine Schlüssel aus dem Keystore löschen, über den ALIAS
2. einen neuen Schlüssel in den Keystore einfügen, welcher vom Server geladen wurde

und dann die App weiterlaufen lassen und diese verwendet dann den neuen Schlüssel ?


----------



## kneitzel (9. Mai 2021)

Natürlich kannst Du den Keystore verändern. Eine kleine Übersicht bietet z.B. Baeldung unter:








						Java KeyStore API | Baeldung
					

Learn how to interact with java keystores programmatically.




					www.baeldung.com
				




Und wenn die Applikation dann erst Schlüssel lädt, dann lädt sie natürlich den neuen Key.


----------



## Joob (11. Mai 2021)

Erst mal danke, aber wieder einmal bin ich unsicher ob man das überhaupt so macht.

Ich versuche seit ein paar Tagen herauszufinden wie ich aus den privatekey.pem auf meinem Server eine cer-Datei mit dem öffentlichen Schlüssel erzeugen kann und bekomme immer mehr das Gefühl das ich das alles falsch angehe. Insbesondere da ich ja die Letsencrypt Certifikatskette komplet in der cert-Datei haben muss.

Meine grundsätzliche Überlegung war die:

Der CertBot renewed den Key,
das macht er im CronJob.
Ein Renew wird durchgeführt kurz bevor der Schlüssel abgelaufen ist.
Also und hier stehe ich an der ersten Hürde, würde ich gerne immer wieder den öffentlichen Schlüssel auf meinem Server
zum Download ablegen._ 
Dazu muss ich eine cer-Datei erzeugen, das bekomme ich aber nicht hin und bin total unsicher ob dann auch die komplette Kette im Key ist oder ob das gar nicht gebraucht wird. _

Da meine App von dem Kram nichts weiß, soll sie als erstes mal den öffentlichen Schlüssel herunterladen.
Nun käme deine Hilfe mit der ich , dann über den Alias die den alten Key im Keystore löschen und nun die heruntergeladene Datei in dem Keystore der App unter gleichem Alias speichern.
Damit wäre dann alles Startklar.
Dateidownload geschieht über SFTP und für das folgende https ist alles vorbereitet. Das mach ich bei jedem Start der App und habe somit immer den aktuellen Key am Start. Es entsteht kein Sicherheitsproblem da nur der öffentliche Key downgeloaded wird und den kann ich ja auch aus dem Browser herauslesen.

Geht das so, oder ist das Quatsch und man macht das ganz anders.


----------



## kneitzel (11. Mai 2021)

Sorry, aber ich blicke noch nicht wirklich durch, was Du überhaupt versuchst.

Generell erzeugt Dir das certbot Tool alles, was Du brauchst. Falls Du es in einem anderen Format brauchst, dann kann man da einiges umwandeln.

Was ich laufen lasse nach einem renew:
a) ein pem File, das wirklich alles enthält:

```
rm fullcert.pem
cat cert.pem chain.pem fullchain.pem privkey.pem > fullcert.pem
```

b) pkcs12 File (Mittels openssl):

```
rm fullchain.pkcs12
openssl pkcs12 -export -out fullchain.pkcs12 -in fullcert.pem -passout pass:mySecret
```

c) jks für Java Programme z.B. Tomcat:

```
rm keystore.jks
keytool -importkeystore -srckeystore fullchain.pkcs12 -srcstorepass mySecret -destkeystore keystore.jks -deststoretype JKS -deststorepass mySecret
```

mySecret muss das Passwort sein, mit dem Du es schützen willst ...

Aber da musst Du nichts groß herunter laden. Später beim SSL Handshake wird automatisch alles zum Client übertrage. Der Server braucht halt nur die Zertifikate.... Wo soll das Zertifikat denn wie eingesetzt werden?  Also bei meinen Servern tausche ich nur das Zertifikat-File aus und starte den Service neu. Also jks austauschen und neustart des Tomcat.


----------



## Joob (12. Mai 2021)

Ich habe auf dem Server kein Java laufen.

Das findet alles in der APP beim Benutzer statt.

In der App welche beim Benutzer installiert ist, muss ich doch das Zertifikat (Keystore) austauschen wenn dieses abgelaufen ist.
Auf dem Server erstellt also der Zertbot ein neues Zertifikat.
Dieses neue Zertifikat muss doch dann bei den Benutzern ankommen und im Keystore gespeichert werden.

Auf dem Server hatte ich mir openssl angeschaut, denn damit wollte ich einen PublicKey erstellen und zum download bereitstellen.
Genauso wie ich die cer Datei aus dem Browser erstellen kann und dann auf dem Lokalen Rechner in den Keystore einlese, wollte ich die cer Datei vom Server herunterladen und dann im Keystore des Users aktualisieren.


----------



## kneitzel (12. Mai 2021)

Was brauchst Du denn auf der Client Seite wofür? Den Public Key musst Du nicht erstellen, denn den hast Du doch schon erstellt bekommen. Ebenso wie alle anderen notwendigen Zertifikate wie das intermediate.

Generell kannst Du aber den Ansatz, den ich oben gezeigt habe, fast 1:1 übernehmen. Den private key kann man ja weg lassen. Und der Java Keystore kann ja dann den Clients gegeben werden.

Aber ich verstehe dennoch nicht, was die Clients mit dem Zertifikat machen sollen. Denn die sollen ja jetzt nur den public key (mit dem intermediate und ggf. dem root Zertifikat so dem noch nicht vertraut wurde) kriegen?

Dann muss ja der private Key auch irgendwo Verwendung finden, oder? Also für eine https Verbindung oder so.
Wenn das dein Szenario wäre, dann brauchen die Clients da nur den Trust auf das root Zertifikat von letsencrypt. Denn der Server sollte dann public key und intermediate Key automatisch im Handshake zur Verfügung stellen.

Oder nutzt Du das irgendwie anders? Also kein Handshake sondern Du nutzt den private Key um etwas zu verschlüsseln / signieren oder so und das soll der Client dann entschlüsseln können?

Vielleicht kannst Du den genauen Usecase ja einmal vorstellen.


----------



## kneitzel (12. Mai 2021)

Ach so - nur um dann evtl. auf offene Fragen einzugehen (Ich gehe den Thread gerade noch einmal von oben durch um mal zu sehen, ob ich es besser verstehen kann) und dabei werfe ich Dir jetzt einfach paar Bruchstücke zu, die Dir ggf. weiterhelfen auch ohne dass ich verstanden habe, was Du da im Detail baust:



Joob hat gesagt.:


> Dazu muss ich eine cer-Datei erzeugen, das bekomme ich aber nicht hin


Certbot erstellt ja pem Dateien. Die kann man umwandeln in eine CER Datei mittels openssl. So eine Umwandlung wäre z.B.:

```
openssl x509 -inform PEM -in cert.pem -outform DER -out certificate.cer
```



Joob hat gesagt.:


> über den Alias die den alten Key im Keystore löschen


Das ginge zum einen über das keytool:

```
keytool -delete -noprompt -alias ${cert.alias}  -keystore ${keystore.file} -storepass ${keystore.pass}
```
Oder auch in Java mit der KeyStore Klasse. Die verlinkte API Dokumentation zeigt da vieles direkt auf. Keystore öffnen (getInstance mit Datei und Passwort) und dann löschen per deleteEntry.


Joob hat gesagt.:


> die heruntergeladene Datei in dem Keystore der App unter gleichem Alias speichern


Das ginge dann per keytool:

```
keytool -import -alias ${alias} -file ${file.cer} -keystore ${keystore.jks}
```

Oder eben auch per Java Code. Da würde ich aber generell ein JKS Format nutzen. Also Keystore öffnen (Siehe Klasse oben), Zertifikat laden und dann per setCertificateEntry (für einzelnes Zertifikat) oder setKeyEntry (für z.B. ganze Chains) einfügen.

Das wären dann noch ein paar weitere Schritte, die Dir evtl. irgendwie weiter helfen könnten...


----------



## Joob (12. Mai 2021)

Das ist total nett von Dir das du dich so um mein Problem kümmerst.

Vielleicht sehe ich das zu kompliziert.
Ich schreib mal wie ich das bisher verstanden habe.

Der CertBot erneuert das Zertifikat kurz bevor dieses abgelaufen ist und speichert das Zertifikat auf dem Server.
Die App muss nun den *neuen PublicKey* kennen um sich beim Handshake auf dem Server zu identifizieren.
Dazu muss der neue PublicKey in KeyStore der App vorhanden sein.
Der PrivateKey darf unter keinen Umständen vom Server denn er ist geheim.

Auf dem Server würde ich dann mit

```
openssl x509 -inform PEM -in cert.pem -outform DER -out certificate.cer
```
den neuen PublicKey auf dem Server im Verzeichnis var/www/html.... zur Verfügung stellen.
Das würde ich im Rahmen des CronJobs vom CertBot immer machen.

Damit liegt auf meinem Server immer der korrekte publicKey in der cer-Datei, auch nach dem Durchgeführten Renew.
Kein Sicherheitsrisiko denn diese kann ich mir auch im Browser generieren.

Auf Seiten der App:
bevor die App https verwendet, muss der aktuell auf dem Server liegende Key im KeyStore der Anwendung gespeichert werden.
_(Eigentlich nur nach einem Renew, aber das ist ja unnötig komplex)_
Dazu lädt die App den auf dem Server liegenden PublicKey bei jedem Start
und entfernt im eigenen Keystore den alten PublicKey per ALIAS und lädt den gerade geladenen PublicKey in den Keystore.

```
keytool -delete -noprompt -alias ${cert.alias}  -keystore ${keystore.file} -storepass ${keystore.pass}
keytool -import -alias ${alias} -file ${file.cer} -keystore ${keystore.jks}
```

- Mache ich das zu kompliziert oder habe ich das alles falsch verstanden ?
- Wenn ich aus der pem Datei privatekey.pem die cer-Datei erstelle ist das dann ein für den Handshake brauchbares Zertifikat oder muss ich da noch etwas hinsichtlich der Zertifikatskette bedenken ?


----------



## Joob (12. Mai 2021)

Eventuell gibt es hinsichtlich der Konstruktion noch etwas wichtiges zu sagen. 
Der Benutzer installiert sich die App auf seinem PC per Installationsprogramm.
Auf dem Server werden nur Daten abgelegt, einerseits als Dateien andererseits in einer DB auf welche per PHP zugegriffen wird.


----------



## kneitzel (12. Mai 2021)

Joob hat gesagt.:


> Die App muss nun den *neuen PublicKey* kennen um sich beim Handshake auf dem Server zu identifizieren.


Das ist schon der Punkt, wo ich nicht mitkomme. Das Zertifikat ist ein Zertifikat von Letsencrypt, wenn ich Dich richtig verstanden habe. Das ist erst einmal kein Client Zertifikat, mit dem ein Client sich autorisiert. (Technisch zwar denkbar, aber wenn Du da bei der Verifizierung was falsch machst, akzeptierst Du plötzlich alle Zertifikate, die von Letsencrypt ausgestellt wurden und so ...)

Vorgehen wäre daher, das Du eine eigene CA führst, die dann Zertifikate ausgibt und diese dann auch widerrufen kann und so. Und denen kannst Du dann mit gutem Gewissen vertrauen.

Wenn es nicht um ein Client Zertifikat geht. mit der der Client sich authentifizieren soll sondern nur um https, dann musst Du gar nichts machen!

Du hast also PHP genannt. Das läuft dann unter einem Apache Webserver oder so. Dem kannst Du die Zertifikate direkt so geben. Clients brauchen gar nichts. Dann kann Deine Applikation aber auch ein Webbrowser auf deinen Server zugreifen. Im Rahmen des Handshakes bekommen die Clients dann das Zertifikat. Dieses prüfen sie dann auf diverse Kriterien:
a) Ist es für die aufgerufene Adresse gültig? (Also z.B. www.joob.de oder was auch immer Du hast)
b) Wird dem Aussteller vertraut (Dazu wird ggf. ein Intermediate Zertifikat mit geprüft)
c) Ist es schon/noch gültig.

Daher: Keinerlei manueller Aufwand. So ist es ja auch gedacht.


----------



## Joob (12. Mai 2021)

Das heißt also wenn ich einmal das Certifikat von letsencrpyt im Keystore gespeichert habe, ist es nicht
von Bedeutung das der CertBot das Zertifikat erneuert hat, sondern alles läuft einfach weiter ohne das ich etwas tun muss.

Im Rahmen des Handshakes werden die Keys getauscht und dann die Kommunikation verschlüsselt zwischen Server und Client gesendet.

Das wäre ja  super.


----------



## Joob (12. Mai 2021)

Stimmt das ?


----------



## kneitzel (12. Mai 2021)

So Du nur SSL Verschlüsselte Verbindungen von Clients zum Server haben willst, dann stimmt das und es wird sogar noch besser:

Java hat in einer cacerts Datei die root Zertifikate, denen vertraut wird. Die notwendigen Root-Zertifikate sollten da schon enthalten sein.

Ich habe eben mal ein 8er Adopt OpenJDK geprüft (und Du kannst Deine Installationen auch prüfen):
- Im Installationsverzeichnis in jre/lib/securty wechseln
- "keytool -list -keystore cacerts" aufrufen (ggf. in eine Datei umleiten.
- Schauen, ob da Zertifikate von der Internet Security Research Group vorhanden sind (ISRG X1 und ISRG X2)

Wenn das der Fall ist, dann wird Letsencrypt bereits vertraut.


----------



## Joob (12. Mai 2021)

Ach wie gut das ich gefragt habe und Du geduligt mein Missverständis aufgedeckt hast. Ist ja gar nicht kompliziert.

Das mit der list habe ich gemacht und auch mein letencrypt Zertifikat dem Keystore hinzugefügt.
Das ist ein wildcard Zertifikat, da müsste ich dann die host Names variieren können.

Ans laufen hatte ich das schon bekommen, aber ich hatte immer im Kopf das ich eine Konstruktion bauen müsste um es nach dem Renew auch noch verwenden zu können.

Das war mir eine riesen Hilfe. Schönen Dank.


----------



## kneitzel (12. Mai 2021)

Joob hat gesagt.:


> auch mein letencrypt Zertifikat dem Keystore


Ich hoffe du meinst damit nicht das cacerts ... das wäre nur für root Zertifikate. So Du nicht unter die CAs gegangen bist, würde da Dein Zertifikat nicht rein gehören 

Aber ich freue mich, wenn ich Dir etwas weiter helfen konnte.


----------



## Joob (12. Mai 2021)

hier habe ich mein Zertifikat gespeichert und auch gefunden

keytool -list -keystore "C:\Program Files\Java\jdk-14.0.2\lib\security\cacerts" -storepass "changeit"


```
vitrain.online, 08.05.2021, trustedCertEntry,
Certificate fingerprint (SHA-256): xxxxxxxxxxxxxxxxxxxxxxxxxxx
xrampglobalca [jdk], 01.11.2004, trustedCertEntry,
Certificate fingerprint (SHA-256): xxxxxxxxxxxxxxxxxxxxxxxx
```

Ist das dann OK, ich meine wegen deiner Erwähnung des root Zertifikats.


----------



## kneitzel (12. Mai 2021)

Ja, da gehört es nicht rein. Das ist eine Liste von Zertifikaten von Certificate Authorities. Daher auch der Name cacerts. 

Du musst Dein Zertifikat nur dem Server bekannt geben, damit dieser Verbindungen damit absichert. Für die Clients musst du nichts machen.


----------



## Joob (12. Mai 2021)

Aber meine App lief erst nachdem ich die cert Datei aus dem Browser generiert hatte und dann die cert Datei mit :


```
keytool -import -alias vitrain.online -keystore "C:\Program Files\Java\jdk-14.0.2\lib\security\cacerts" -file "C:\Users\Jupp\Desktop\vitrain.cer" -storepass "changeit"
REM keytool -delete -noprompt -alias vitrain.online -keystore "C:\Program Files\Java\jdk-14.0.2\lib\security\cacerts" -storepass "changeit"

keytool -list -keystore "C:\Program Files\Java\jdk-14.0.2\lib\security\cacerts" -storepass "changeit"
pause
```

eingetragen habe, das oben ist meine Batch.


----------



## Joob (12. Mai 2021)

Auf dem Server habe ich alles im webbrowser eingestellt. apache  / sites-available / default-ssl.conf 000-default.conf


----------



## kneitzel (12. Mai 2021)

Hast du mal eine Seite im Browser geprüft? Zeigen die Browser die Seite richtig an oder kommt da ggf. auch eine Warnung?

Das ist ein guter Test um erst einmal zu sehen, ob der Webserver richtig konfiguriert wurde.

Typischer Fehler kann z.B. ein fehlendes Intermediate Zertifikat sein. Das würden aber die meisten Browser dann anzeigen weil dann der Trust auch im Browser nicht sicher gestellt sein kann.

Wenn du magst kann ich Dich da etwas durch führen. Der erste Test mit dem Webbrowser ist dann halt die Prüfung, wo wir schauen müssen: auf dem Server oder auf dem Client. Danach schauen wir dann gerne weiter.


----------



## Joob (12. Mai 2021)

Im Browser habe ich die Domain eingegeben. 
Dann kam die Default Seite von apache.
Auf dem Server habe ich ein redirect auf https .
Das klappt auch alles.
Dann habe ich im Browser das Zertifikat in einer Datei gespeichert.

Die Datei habe ich dann im KeyStore gespeichert, mit dem Batch welches ich Dir gezeigt habe.
Aber das wäre cool wenn du mir helfen könntest das zu verstehen und ein gutes Konzept aufzubauen.

Wann würde es Dir denn passen.


----------



## kneitzel (12. Mai 2021)

Heute kann ich da nichts mehr schauen, aber du kannst mir in einem Gespräch einmal die Domain sagen, dann schaue ich mir das einmal kurz an.

Wenn da alles ok ist, dann sehe ich, welches Root Zertifikat benötigt wird und können das prüfen (und ggf. hinzu fügen)


----------

