SSL - langsamer Handshake

Wie bereits in https://forum.byte-welt.net/java-forum/netzwerkprogrammierung/19769-dateien-verschluesselt-uebers-netzwerk-uebertragen.html angemerkt hab ich Probleme mit einem langsamen Handshake über SSL.
Hab mich da nach meinem Urlaub mit mal n C+±Code ausm Netz kopiert und mit nativem openssl geprüft - hier läuft der Handshake sauber durch.
Laut Google hat das was mit einem reverse-DNS-lookup zu tun - jedoch ist meine DNS-config ok. Auch mögliche Lösungen wie IP/Name cachen oder gar hosts-File lösen das Problem nicht. Lokal funzt alles so dass der Fehler auf meinen Root zurückzuführen ist.

Irgendjemand ne Idee?

Also ich hab mal mit Tshark den Traffic analysiert - und witzigerweise kommt nicht mal ein DNS-request - kann man also, zumindest nach Tshark - als mögliche Ursache ausschließen. Nur liegts dann einfach am Java-Code der so ewig für irgendwelche Berechnung braucht? Und warum nur aufm root und nicht auch in der VM wo das gleiche OS läuft? Kanns ein Problem mit der Hardware sein?
Ich bin überfragt und mir fehlt auch leider die Möglichkeit weiterer Hardware zum testen.
Falls jemand mal meinen Code (natürlich mit anderen Key/Cert) für mich zum Testen laufen lassen will kann er sich ja mal melden.

Mal eine ins Blaue geratene Möglichkeit, die auch total daneben liegen kann.

Kann es sein das Entropie fehlt? Afair wird bei jeder Verbindung via SSL ein neuer Schlüssel erzeugt. Dafür braucht es “Zufall” den es vllt. in der virtuellen Maschine mehr gibt.

Ein einfacher Test könnte sein, ein anderes Programm im Hintergrund laufen zu lassen. Fibonacci Zahlen in Endlosschleife berechnen oder was auch immer und dann schauen ob dies Auswirkungen zeigt.

Grundsätzlich ist es eher genau umgekehrt, in VMs gibt es häufig zu wenig Entropie.

Hm, wenn er allerdings mit der Maus rumfuchtelt, dann kann da doch auch was zusammenkommen?

Kurze Suche ergibt, dass Virtualbox eher weniger Probleme mit Entropie hat als VMWare.

Siehe auch
https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1036980

https://www.virtualbox.org/ticket/11297

VBox kann da unter Umständen was von der CPU mitbenutzen.

Ja, dann kommt auch etwas mehr zusammen, das ist aber häufig trotzdem nicht ausreichend. Und bei einem headless-System hat man in der Regel auch kein Mousedevice :wink:
Kleine Referenz zum Thema Entropie und virtuelle Maschinen:
https://www.virtualbox.org/ticket/11297

The amount of available entropy depends always on the number of devices the system has access and how busy these devices are. A virtual machine usually implements fewer devices and therefore fewer sources of entropy than a bare-metal system. This problem is the same with all virtual machines, not only with VirtualBox and this is not really a VirtualBox bug. On many bare-metal systems you will see the same behavior if the system is idle.

*** Edit ***

Edit: da hast du mit dem Edit ja die gleiche Quelle gepostet, wie ich auch zitiert habe :wink:

Selbe Referenz wie aus meinem Edit :wink:

Ein Jahr jünger.

RNG … - some recent CPUs include them (and recent Linux exposes them)

Viele neuere Intel-CPUs unterstützen AES-NI, welches neben Hardwarebeschleunigung für AES auch die Generierung von echten Zufallszahlen (dort wird physikalisch Rauschen an einem Sensor abgenommen). Das wird dann in neueren Virtualisierungsumgebungen wohl auch von der Clientmaschine verwendet.

Siehe auch hier:
https://software.intel.com/en-us/articles/intel-aes-ni-performance-enhancements-hytrust-datacontrol-case-study#_Toc397546814

Kurz zusammengefaßt:

Virtuelle Maschinen können Entropieprobleme haben, müssen es aber nicht. (Deshalb funktionierts in der VM)

Root-Server kann Probleme haben die nötige Entropie bereitzustellen, wenn er virtualisiert ist und der Client das nicht unterstützt, die nötigen Chips/RNGs fehlen und er zu wenig zu tun hat. (Deshalb scheitert es auf dem Server, bzw. ist langsam)

Ein einfacher Test wäre /dev/urandom zu nutzen um das zu prüfen. Sorgt allerdings für schlechte Crypto.

Kann man das so stehen lassen @cmrudolph ?

Ja, das bringt es meiner Meinung nach ziemlich genau auf den Punkt.
Lediglich das Austauschen von /dev/random gegen /dev/urandom ist im Falle einer SSL-Implementierung wohl nicht ganz so einfach. Wenn die Bibliothek nicht explizit ermöglicht, in einen “schlechteren PRNG-Modus” zu verfallen, hat man wohl keinen Einfluss auf die Wahl der Quelle für Zufallszahlen. Bei OpenSSL sollte es jedoch möglich sein, die Quelle auszuwählen.
Zum Testen könnte man aber eine gewisse Menge Zufallszahlen aus /dev/random lesen und die Zeit messen:

$ time dd if=/dev/random of=/dev/null bs=1 count=1k

Auf meinen echt dedizierten Servern dauert das schon ganz schön lange - die haben aber auch keinen physikalischen RNG.

Auf meinem Desktop bin ich für 1k bei 10 - 12 Minuten.

So knappe 100 - 150 byte werden gecacht und gehen dann auch zügig raus. Danach dauert es aber gewaltig. /dev/hwrng ist nicht verfügbar.

https://wiki.openssl.org/index.php/Random_Numbers

dort wird auch auf den Entrophy Gathering Daemon verwiesen.

Hmm, ich kanns zwar gerade nicht prüfen, aber davon ausgehend dass alles andere was mit nativem openSSL läuft auch über längere Beanspruchung (mehrere unabängige Verbindungen ohne cache) keine Probleme zeigt dürfte genug Entropie vorhanden sein.
Auch verschiedene JDK/JRE-Imple (openJDK/oracle) in verschiedenen (headless-)Versionen machen keinen Unterschied - Fehlerbild ist leider dauerhaft reproduzierbar.
Und wenn müsste eigentlich meine VM auf meinem desktop Entropie-Probleme bekommen - schafft aber den ssllabs-server-test bei dem gute 220 Verbindungen ablaufen (hab ich mal ausprobiert).
Weiter ist mir aufgefallen: es ist nicht nur der initiale Handshake der Probleme macht - auch über längere dauer ergibt sich keine Beschleunigung - welche ja aber nach dem Handshake und ausgehandeltem Session-Key bei einem nicht-forward-secrecy cipher dann eintreten sollte.
Nutze ich hingegen selbst die Cipher-Klasse mit gleichem Modus gibts das Problem nicht.

Diese Aussage belustigte mich gerade ein wenig, auch wenn ich zur Lösung deines Problems leider nichts beitragen kann. Aber ist es nicht viel nerviger, wenn ein Fehler nur jedes zweihundertste Mal oder so auftaucht?

Sicher ist es für die Problemlösung besser wenn der Fehler reproduzierbar ist - aber das eigentliche Fehlerbild an sich ergibt halt keinen Sinn. Denn selbst wenn es ein Entropie-Problem sein sollte und es Verzögerungen beim Erzeugen der Zufallsdaten gibt sollte dies ja nur den Handshake selbst betreffen. Das Problem bleibt aber auch nach erfolgreichem Handshake bestehen wo es ja nur noch AES und SHA256 gibt - die an sich ja eigentlich recht schnell berechnet werden können.
Was halt auch merkwürdig ist dass es für den Fehler gleich ist ob OpenJDK oder Oracle und auch egal welche Version (sowohl 7 als auch 8). Und dass es in einer VM halt nicht zum Problem kommt.
Es ist durchaus möglich das es die Hardware ist - aber da ich nur diesen einen root habe - den ich auch nur ungerne hergeben würde - habe ich keine andere Testmöglichkeit.
Ich kann mich höchstens mal mit dem Support von OVH in Verbindung setzen - aber ich denke dass die die Schuld des Fehlers auch erstmal auf Java schieben dürften anstatt gleich mal die Hardware zu tauschen.

[QUOTE=cmrudolph]Zum Testen könnte man aber eine gewisse Menge Zufallszahlen aus /dev/random lesen und die Zeit messen:

$ time dd if=/dev/random of=/dev/null bs=1 count=1k

Auf meinen echt dedizierten Servern dauert das schon ganz schön lange - die haben aber auch keinen physikalischen RNG.[/QUOTE]
Tja, scheint bei meinem genau so zu sein.
Ich bin aber anders drauf gekommen: SecureRandom.getInstanceStrong() nutzt auf meinem Root den Modus “NativePRNGBlocking”. Gebe ich selbst jedoch “NativePRNG” oder gar “SHA1PRNG” vor ist die Bremse plötzlich gelöst. Warum sowas trotzdem noch Auswirkungen auch nach abgeschlossenem Schlüsselaustausch hat obwohl SecureRandom im AES-Cipher selbst keine Rolle mehr spielt bleibt mir unklar. Wird wohl an der Impl der SSL-Klassen liegen.
Was deinen Code angeht: ich habs nach 15min mit ctrl+c abgebrochen, und scheinbar gibts wohl generell Probleme mit lesen von /dev/random.

Ist bei meinem Server dasselbe. /dev/random oder auch die anderen Randoms schreiben mit ein paar Kilobyte bis Megabyte pro Sekunde out.

Pseudozufallszahlen brauchen halt ihre Berechnungen. [emoji14] (Wenn’s halt nicht direkt in Hardware gegossen ist.)

[QUOTE=Sen-Mithrarin]…
Was deinen Code angeht: ich habs nach 15min mit ctrl+c abgebrochen, und scheinbar gibts wohl generell Probleme mit lesen von /dev/random.[/QUOTE]

Naja, macht auch Sinn, dass das lange dauern kann, da /dev/random afaik (durch kürzliches Nachlesen, da auf unseren Servern die Entropie zu gering war etc.) blockiert falls keine Zufallszahlen vorhanden sind. Wenn also nichts da ist, wartest und naja… wer weiß wie lange das dann dauert

Interessant war dann nur die Ausgabe nach dem ich mit ctrl+c abgebrochen hatte: es wurde angeblich das ganz kB kopiert - nur scheint wohl der Prozess hängen geblieben zu sein.

Wie kann ich, ohne physikalischen Zugriff auf die Hardware, für mehr / bessere Entropie sorgwn?

Indem man für mehr IO sorgt. Also Lese- / Schreibzugriffe auf die Festplatte durchführen.
Ich bezweifle aber, dass es sich dabei um ein Entropieproblem handelt. Du schriebst, dass die Performanceprobleme auch vorherrschen, wenn die Verbindung bereits besteht. AES benötigt keine Zufallszahlen - unabhängig von der Implementierung. Daher kann es nicht die Ursache sein.

Ist ja eben das was mich so wundert. Nutze ich NativePRGN läuft alles ohne Probleme (ich nehme an weil dann aus /dev/urandom gelesen wird). Wenn ich jedoch mit getInstanceStrong() eine NativePRGNBlocking Instanz nehme (die dann blocking aus /dev/random lesen dürfte) ist es halt nicht nur der initiale Handshake der halt an sich so ewig braucht (wenn überhaupt dürfte ja nur das Erzeugen der Zufallszahlen längere Zeit beanspruchen) sondern halt auch nach dem die Session voll etabliert wurde und dann halt nur noch mit einem statischen symetrischem Session-Key und einer Hash-Funktion gearbeitet wird auf die SecureRandom ja gar kein Einfluss mehr haben sollte. Oder arbeitet SSL bzw dessen Java-Impl so anders das überall irgendwie SecureRandom mit ins Spiel kommt - z.B. dass für jede HMAC auch noch ein Salt erzeugt wird (der ja dann auch irgendwie übertragen werden muss)?
Schon interessant dass es halt so einen Unterschied macht nur davon abhängig ob ich ein SecureRandom nehme was blockierend aus /dev/random liest oder nicht-blockierend aus /dev/urandom - was ja nach dem Handshake nicht mehr von Belang sein sollte.
Ich werd mal gucken ob es weitere Stolpersteine gibt (z.B. JSSE/JCE vs BouncyCastle) - aber zumindest erstmal eine “Lösung” mit der man soweit arbeiten kann dass die Antwort auf die im gelinkten Thread gestellte Frage nun doch ganz beruhigt “Java hat bereits fertige SSL-Klassen” gegeben werden kann.

Und was die Sicherheit angeht: man liest zwar viel dass /dev/urandom von der Entropie-Qualität her schlechter sein soll - und daher gerade für sehr lange Schlüssel gemieden werden sollte - aber ich bin kein Crypto-Experte um das nachprüfen zu können und verlass mich da einfach mal drauf dass der true-rng-seed den sich urandom ja auch nur selbst von random holt ausreichend sein dürfte.