# Java HTTPS Server (Secure Sockets)



## JaXnPriVate (6. Jul 2021)

Guten Tag,

derzeit schreibe ich mir ein kleines Socket Framework um verschiedene Sachen umsetzen zu können.

Leider sitze ich jetzt schon seit einigen Tagen an den sogenannten "SecureSocket" bzw. an "SecureSocketServer".


Dabei liegt das Problem, dass anscheinend die Keystore Datei nicht geladen werden kann, ich hatte zuvor das Problem, dass mein Input Stream leer war und der den gleichen Fehler angezeigt habe.

Nun nutze ich einen FileInputStream, welcher mir bei solch einem Falle eine eigene Exception aussendet, jedoch hat sich das Problem nicht gegessen und meine Datei soll immer noch nicht stimmen.

Ich habe schon diverse Sachen von Stack-Overflow ausprobiert und mit dem KeyTool ausprobiert, ob das Format stimmt:


























Nun zu meiner Exception die ich erhalte sowie den Code, den ich nutze:

(Achtung Exception ist sehr lang)
[CODE lang="java" title="Exception"]java.io.IOException: Invalid keystore format
    at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:658)
    at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56)
    at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224)
    at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)
    at java.security.KeyStore.load(KeyStore.java:1445)
    at sun.security.util.AnchorCertificates$1.run(AnchorCertificates.java:61)
    at sun.security.util.AnchorCertificates$1.run(AnchorCertificates.java:52)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.security.util.AnchorCertificates.<clinit>(AnchorCertificates.java:52)
    at sun.security.provider.certpath.AlgorithmChecker.checkFingerprint(AlgorithmChecker.java:214)
    at sun.security.provider.certpath.AlgorithmChecker.<init>(AlgorithmChecker.java:164)
    at sun.security.provider.certpath.AlgorithmChecker.<init>(AlgorithmChecker.java:118)
    at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:157)
    at sun.security.validator.Validator.validate(Validator.java:262)
    at sun.security.validator.Validator.validate(Validator.java:238)
    at sun.security.validator.Validator.validate(Validator.java:207)
    at javax.crypto.JarVerifier.isTrusted(JarVerifier.java:610)
    at javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:530)
    at javax.crypto.JarVerifier.verifyJars(JarVerifier.java:363)
    at javax.crypto.JarVerifier.verify(JarVerifier.java:289)
    at javax.crypto.JceSecurity.verifyProviderJar(JceSecurity.java:164)
    at javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:190)
    at javax.crypto.JceSecurity.canUseProvider(JceSecurity.java:204)
    at javax.crypto.KeyAgreement.getInstance(KeyAgreement.java:179)
    at sun.security.ssl.JsseJce.getKeyAgreement(JsseJce.java:269)
    at sun.security.ssl.JsseJce$EcAvailability.<clinit>(JsseJce.java:418)
    at sun.security.ssl.JsseJce.isEcAvailable(JsseJce.java:194)
    at sun.security.ssl.CipherSuite$KeyExchange.isAvailable(CipherSuite.java:371)
    at sun.security.ssl.CipherSuite.isAvailable(CipherSuite.java:185)
    at sun.security.ssl.SSLContextImpl.getApplicableCipherSuiteList(SSLContextImpl.java:304)
    at sun.security.ssl.SSLContextImpl.access$100(SSLContextImpl.java:42)
    at sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:432)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at java.security.Provider$Service.getImplClass(Provider.java:1634)
    at java.security.Provider$Service.newInstance(Provider.java:1592)
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
    at javax.net.ssl.SSLContext.getInstance(SSLContext.java:156)
    at de.bytestore.mytriox.network.server.ServerSocket.getFactory(ServerSocket.java:510)
    at de.bytestore.mytriox.network.server.ServerSocket.startIO(ServerSocket.java:181)
    at de.bytestore.mytriox.network.server.ServerSocket.start(ServerSocket.java:171)
    at de.bytestore.mytriox.web.WebServer.start(WebServer.java:44)
    at de.bytestore.mytriox.web.WebService.start(WebService.java:54)
    at de.bytestore.mytriox.service.ServiceHandler.start(ServiceHandler.java:63)
    at de.bytestore.mytriox.service.ServiceHandler.start(ServiceHandler.java:48)
    at de.bytestore.mytriox.guardian.GuardianHandler.init(GuardianHandler.java:121)
    at de.bytestore.mytriox.guardian.GuardianHandler.load(GuardianHandler.java:82)
    at de.bytestore.mytriox.Controller.main(Controller.java:11)[/CODE]


Folgenden Code nutze ich, welcher meinen Fehler auslöst:
[CODE lang="java" title="Code"]    /**
     * Get Factory for SecureSocket.
     *
     * @return
     */
    private SSLServerSocketFactory getFactory(FileManager certificateIO) {
        SSLServerSocketFactory factoryIO;
        char[] passphraseIO = "12345678".toCharArray();

        System.out.println(certificateIO.bytes().length);

        if (certificateIO.exits()) {
            //this.socketIO = SSLServerSocketFactory.getDefault().createServerSocket(this.networkIO.getPort(), 10, this.networkIO.getAddress());
            //this.socketIO = this.getContext().getServerSocketFactory().createServerSocket(this.networkIO.getPort(), 10, this.networkIO.getAddress());

            // Initialize Key and Trust Manager.
            TrustManagerFactory trustIO = null;
            KeyManagerFactory managerIO = null;

            try {
                // Load Key Store.
                KeyStore storeIO = KeyStore.getInstance(KeyStore.getDefaultType());
                InputStream streamIO = certificateIO.stream();
                storeIO.load(streamIO, passphraseIO);
                streamIO.close();

                Enumeration<String> aliasIO = storeIO.aliases();

                while (aliasIO.hasMoreElements()) {
                    logIO.append(GuardianLog.Type.INFO, "Found Alias in KeyStore -> " + aliasIO.nextElement() + ".");
                }


                /** FileManager outputIO = new FileManager("F:\\Programmieren\\MyTrioX\\MyTrioX-CONTROLLER\\database\\store.jks");
                 if (!outputIO.exits()) {
                 outputIO.create();
                 }

                 storeIO.store(new FileOutputStream(outputIO.getFile()), passphraseIO);
                 **/


                // Initialize Trust Manger.
                trustIO = TrustManagerFactory.getInstance("SunX509");
                trustIO.init(storeIO);

                // Initialize Key Manger.
                managerIO = KeyManagerFactory.getInstance("SunX509");
                managerIO.init(storeIO, passphraseIO);

            } catch
            (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException
                            exceptionIO) {
                logIO.append(GuardianLog.Type.ERROR, "Can't load Keystore (JKS).", exceptionIO);
            }

            // Initialize SSLContext.
            SSLContext contextIO = null;

            try {
                // Get Context Instance by Protocol (TLS/SSL).
                contextIO = SSLContext.getInstance(this.protocolIO);

                // Initialize SSL Context with Trust and Key Manager.
                contextIO.init(managerIO.getKeyManagers(), trustIO.getTrustManagers()/*null*/, null);
            } catch (KeyManagementException | NoSuchAlgorithmException exceptionIO) {
                logIO.append(GuardianLog.Type.ERROR, "Can't load Keystore (JKS).", exceptionIO);
            }

            // Set Factory to create ServerSocket.
            factoryIO = contextIO.getServerSocketFactory();
            //((SSLServerSocket) this.socketIO).setEnabledCipherSuites(new String[]{"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"});
            //((SSLServerSocket) this.socketIO).setEnabledProtocols(new String[]{"TLSv1.2"});

        } else {
            // Set Fallback Factory to create ServerSocket.
            factoryIO = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
            logIO.append(GuardianLog.Type.ERROR, "Certificate File not exits, fallback to normal HTTP.");
        }

        return factoryIO;
    }[/CODE]

Vielen Dank für eure Hilfe.

Mit freundlichen Grüßen
Jan


----------



## Robert Zenz (6. Jul 2021)

Ich glaube, bin mir aber nicht mehr sicher, dass sich der Default-KeyStore-Type von JKS auf PKCS12 geaendert hat mit einer Version irgendwo zwischen 8 und 11. Also du musst den KeyStore mit dem expliziten Typ "JKS" erstellen, oder deinen KeyStore zu einem PKCS12 wandeln.


----------



## JaXnPriVate (6. Jul 2021)

Meine Fre****, du sagst es Java Version...

Ganz ehrlich ich würde jetzt gerne alles löschen, seit Tagen suche und frage ich nach Fehlerquellen.

Version zu 14 gewechselt zum Testen und es geht einwandfrei... 
Anscheinend geht die 1.8 von Oracle da nicht so, einfach nur ärgerlich...

Für die nächsten User:

*!JAVA VERSION WECHSELN UND TESTEN OB ES GEHT!*


Vielen Dank Robert


----------



## Robert Zenz (6. Jul 2021)

JaXnPriVate hat gesagt.:


> Ganz ehrlich ich würde jetzt gerne alles löschen, seit Tagen suche und frage ich nach Fehlerquellen.


Zwei Hilfestellungen dazu fuer die Zukunft:

Sei explizit, immer.
In diesem Fall, wenn du einen JKS-KeyStore hast, erzeuge einen KeyStore mit diesem Typ ohne dass es irgendwelchen Spielraum gibt.
Hinterfrage zuerst deine Logik, und dann die Logik auf der du aufsetzt Stueck fuer Stueck (im Zweifelsfall bis du im Prozessor angekommen bist).
Beides hilft schonmal immens wenn man nach Fehlern sucht. Bei Letzterem, wenn du dir sicher bist dass deine Logik richtig ist, kannst du mit einem Debugger (zum Beispiel den in Eclipse) mal kurz vor dem Fehler anhalten und die Klassen betrachten welche verwendet werden. In meiner Erfahrung braucht man es immer wieder das man entweder mit einem Debugger Werte verifiziert (zum Beispiel dass die Werte auch da sind welche man erwartet), oder beinhart mit einem Decompiler sich die Logik ansieht auf welcher man aufsetzt.


----------



## JaXnPriVate (6. Jul 2021)

Danke für die Tipps


----------



## JaXnPriVate (7. Jul 2021)

Ich würde gerne noch einmal mein Thread aufmischen, weil mich ein neuer Fehler plagt  

Hier scheint es ja Leute zu geben, die Ahnung von dem Themengebiet haben, und zwar läuft jetzt alles ohne wirkliche Fehlermeldungen beim Laden.

Jedoch bekomme ich jedes Mal währen dem Handshake die Meldung, dass kein authentication scheme gefunden wurde.

Meine Frage ist nun, kommt das von meinem Zertifikat oder habe ich etwas in meinem Code falsch gemacht?

Hierzu gibt es natürlich auch einen Stacktrace:
[CODE lang="java" title="Exception"]Stacktrace for ID: 1hrub4vobe0c1
javax.net.ssl.SSLHandshakeException: No available authentication scheme
    at sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:357)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:313)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:304)
    at sun.security.ssl.CertificateMessage$T13CertificateProducer.onProduceCertificate(CertificateMessage.java:970)
    at sun.security.ssl.CertificateMessage$T13CertificateProducer.produce(CertificateMessage.java:959)
    at sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:420)
    at sun.security.ssl.ClientHello$T13ClientHelloConsumer.goServerHello(ClientHello.java:1096)
    at sun.security.ssl.ClientHello$T13ClientHelloConsumer.consume(ClientHello.java:1032)
    at sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:716)
    at sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:683)
    at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:376)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:479)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:457)
    at sun.security.ssl.TransportContext.dispatch(TransportContext.java:200)
    at sun.security.ssl.SSLTransport.decode(SSLTransport.java:154)
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1290)
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1199)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373)
    at de.bytestore.mytriox.network.server.ServerSocket$1.run(ServerSocket.java:204)
    at java.lang.Thread.run(Thread.java:748)
[/CODE]

Ich habe im Internet jetzt nichts Konkretes gefunden, es wurde nur einmal behauptet, dass bei TLSv3 (Kann leider auch nur v3 nutzen) kein SHA-1 genutzt werden kann.

Habe ich ausprobiert, nur bin leider bei dem gleichen Fehler gelandet.


----------



## Robert Zenz (7. Jul 2021)

Das klingt so als waere das Zertifikat nicht fuer TLSv1.3 zulaessig (falscher Algorithmus?) oder Client akzeptiert nur Zertifikate mit einem anderen Algorithmus.


----------



## JaXnPriVate (7. Jul 2021)

Huhu, das kann eventuell sein.

Ich habe es leider noch nicht hinbekommen meine TLS Version zu verändern, obwohl ich TLSv1-2 in den Security-Settings aktiviert habe.

Vom Browser bzw. Client denke ich nicht, dass er die Algorithmen nicht unterstützt, ich denke eher, dass es wirklich an meinem Cert liegt.

Das habe ich nach einem etwas älteren Tutorial erzeugt:








						Tutorial - Java KeyStores (JKS) With Let's Encrypt
					

Add a second RSA 4096 key - (san-cert) We are now going to add a second key to the JKS.  Note: this is not a required step for most installs however to understand JKS functionality fully and the purpose of aliases it’s good to have two keys (and refer to them in the tomcat config)  Command...




					community.letsencrypt.org
				




Vielleicht hat hier ja jemand noch eine Idee, was ich daran ändern kann damit es funktioniert, ich bin leider recht neu auf dem Gebiet von Zertifikaten unterwegs.


----------



## Oneixee5 (7. Jul 2021)

Manche Zertifikat verwenden den DSA-Algorithmus, der seit einiger Zeit zugunsten von RSA veraltet ist und in TLS1.3 überhaupt nicht mehr unterstützt wird. Es müssen stattdessen RSA-Zertifikate erstellt werden. Nicht so alte Versionen des java keytool haben standardmäßig DSA-Zertifikate erstellt ... eine unglückliche Voreinstellung.


----------



## JaXnPriVate (7. Jul 2021)

Hmm, aber wie sehe ich denn ob das wirklich ein RSA Format ist. 
Denn KeyTool GUI, zeigt mir das ganze als RSA an, aber wie bei meinem letzten Problem, möchte ich mich nicht wirklich darauf verlassen. 


Ich werde einfach mal meine vorherigen Befehle mit -keyalg RSA ausführen, vielleicht besteht danach ja Funktion.


----------



## JaXnPriVate (7. Jul 2021)

Also ich habe jetzt alles mit RSA generiert und schwups war der Fehler weg, dafür sendet er jetzt nicht mehr das Cert bzw. im Browser wird es nicht angezeigt und ein neuer Fehler erscheint  😆 


```
Stacktrace for ID: 1hv5jbh2ule0i
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
    at sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1470)
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1298)
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1199)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373)
    at de.bytestore.mytriox.network.server.ServerSocket$1.run(ServerSocket.java:202)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:480)
    at sun.security.ssl.SSLSocketInputRecord.readHeader(SSLSocketInputRecord.java:469)
    at sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:159)
    at sun.security.ssl.SSLTransport.decode(SSLTransport.java:110)
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1290)
    ... 5 more


Stacktrace for ID: 1ies920a04njp
javax.net.ssl.SSLHandshakeException: Empty client certificate chain
    at sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:357)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:313)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:304)
    at sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1191)
    at sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1178)
    at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:376)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:479)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:457)
    at sun.security.ssl.TransportContext.dispatch(TransportContext.java:200)
    at sun.security.ssl.SSLTransport.decode(SSLTransport.java:154)
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1290)
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1199)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373)
    at de.bytestore.mytriox.network.server.ServerSocket$1.run(ServerSocket.java:202)
    at java.lang.Thread.run(Thread.java:748)
```

Über den OpenSSL Client erhalte ich beim Testen zwar das Cert aber folgende Nachricht:


> Verification error: unable to get local issuer certificate



Wenn das so weiter geht, muss ich das ganze erst einmal pausieren und mich ein bisle über SSL/TLS informieren.
Über JKS bzw. Secure Sockets gibt es leider wenig, weil die meisten irgendwelche Libs nutzen...


----------



## Oneixee5 (7. Jul 2021)

Das ist eine übliches Problem mit selbst erstellen Zertifikaten. So einfach werden die nicht akzeptiert. Du musst deinen Anwendungen beibringen selbst erstellte Zertifikate zu akzeptieren. Und JA, man sollte sich erst über so ein Thema umfassend informieren, bevor man mit der Umsetzung beginnt. Es geht dabei ja um Datenschutz und -sicherheit, nicht nur um deine sondern auch die deiner Kunden.


----------



## kneitzel (7. Jul 2021)

Da dürfte jetzt das Intermediate Zertifikat fehlen. Dein Zertifikat wurde mit einem anderen Zertifikat unterschrieben und das muss der Server auch mitgeben.


----------



## JaXnPriVate (7. Jul 2021)

kneitzel hat gesagt.:


> Da dürfte jetzt das Intermediate Zertifikat fehlen. Dein Zertifikat wurde mit einem anderen Zertifikat unterschrieben und das muss der Server auch mitgeben.


Für mich sieht es so aus, als wäre alles dabei... Aber ich werde mir das noch mal genauer ansehen.


----------



## kneitzel (7. Jul 2021)

Hmm, sieht erst mal gut aus ... Du nutzt letsencrypt und hast R3 und das root Zertifikat drin wie es scheint ...

Das X1 muss nach meinem Verständnis als Root Zertifikat vertraut werden. Dazu evtl. einmal nachsehen im cacerts, was da so drin ist. Also sowas wie:

keytool -keystore "$JAVA_HOME/lib/security/cacerts" -storepass changeit -list | grep x1

Die / müssen bei Dir natürlich \ sein und bei Windows Installation ist i.d.R. noch ein JRE Verzeichnis mit dabei:
keytool -keystore "$JAVA_HOME\jre\lib\security\cacerts" -storepass changeit -list

Und dann halt nach dem X1 Zertifikat suchen (isrg root x1).

Edit: In meinem java 8 JDK ist das z.B. nicht drin, im Java 16 ist es drin (beides AdoptOpenJDK)


----------



## JaXnPriVate (7. Jul 2021)

Uuuuuuund 



Vollah, danke für eure Hilfe Jungs, ohne euch hätte ich das nicht geschafft.

Ich habe das ganze jetzt direkt über PKCS#12 generiert und in JKS konvertiert und nun geht alles 

Zudem hatte ich auch das R3 statt dem X1 genutzt


----------

