SSL-Verifizierung mit PHP schlägt fehlt (Fehler 14090086)

Wenn dich PHP mit dieser Fehlermeldung begrüßt, dann liegt es wohl daran, dass beim Abruf einer SSL-Ressource die Identität nicht verifiziert werden konnte. Und das ist auch gut so, denn der Sinn von SSL ist ja das Herstellen einer gesicherten Verbindung. Im Folgenden beschreibe ich zwei Wege, den Fehler zu beheben. Die erste Lösung ist quick’n’dirty und behebt nicht die Ursache und die zweite Lösung kann man als Best Practice betrachten.

 

Verifizierung des SSL Hosts unterdrücken

Im Grunde lässt sich der Fehler ganz einfach umgehen. Denn file_get_contents() kann mit Parametern gefüttert werden, die die Verifizierung der Ressource unterdrücken. Das sieht dann z.B. so aus:

 

Wer auf eine eigene Ressource zurückgreift, z.B. im lokalen Netz oder zu Testzwecken, kann damit leben. Aus Sicherheitsgründen ist die Lösung allerdings nicht zu empfehlen.

Die Zertifikate des SSL Hosts manuell einrichten

Der o.g. Fehler hat eigentlich eine simple Ursache: PHP kennt den Aussteller des Zertifikates nicht und verweigert aus Sicherheitsgründen den Aufbau einer Verbindung. Wir müssen also nur dafür sorgen, dass PHP dem Aussteller vertraut. Das passiert, in dem wir dessen Zertifikat bzw. die komplette Zertifikatskette in eine Datei packen und diese dann an PHP übermitteln.

Im ersten Schritt besorgen wir uns die Zertifikate der Certification Authority. Das funktioniert recht einfach mit dem SSL-Checker von sslshopper.com. In meinem Fall liefert dieser nur zwei Zertifikate zurück. Das eigentliche Server-Zertifikat, das für meine Seite ausgestellt wurde, und das Root-Zertifikat für die Stelle, die mir das Zertifikat ausgestellt hat. Es ist durchaus auch denkbar, dass in dieser Liste noch andere Zertifikate stehen, die so genanten Intermediate-Zertifikate:

SSL Zertifikats-Kette

SSL Zertifikats-Kette

Für unser Problem benötigen wir nun unser eigenes Server-Zertifikat und alle Zertifikate aus der Zertifikats-Kette, im PEM-Format.

Das eigene Server-Zertifikat herunterladen

Wir beginnen also mit dem Zertifikat, mit dem unserer Server ausgestattet ist. In OS X bzw. Linux ist das über die Kommandozeile möglich. Hierzu muss nur der Parameter connect angepasst werden (die eigene URL) und die Ausgabe-Datei am Ende des Kommandos:

Fertig.

Die Zertifikatskette vervollständigen

Als nächstes besorgen wir uns die komplette Zertifikatskette. Auch das ist in den meisten Fällen sehr einfach. Dazu reicht es, nach den Common-Names zu suchen, die der SSL-Checker uns gemeldet hat. Also z.B. thawte DV SSL SHA256 CA und thawte Primary Root CA – G3.

Das führt uns natürlich zu der Seite von Thawte und diesen beiden Ressourcen:

  • https://search.thawte.com/library/VERISIGN/ALL_OTHER/KB_IMAGES/SO26817/Certs/SHA2/thawte_DV_SSL_SHA256_CA.cer
  • https://www.thawte.com/roots/thawte_Primary_Root_CA-G3_SHA256.pem

Diese laden wir uns herunter und speichern sie unter ~/thawteRoot.crt bzw. ~/thawteIntermediate.crt ab. Fertig. Und kurz vor dem Ziel!

Die Zertifikate zusammenführen

Der nächste Schritt ist einfach. Wir packen nun alle Zertifikate in eine Datei. Das machen wir entweder mit einem Text-Editor oder über die Kommandozeile. Die Reihenfolge sollte eigentlich keine Rolle spielen. Ich empfehle aber, das Root-Zertifikat an den Anfang der Datei zu packen, ggf. gefolgt von den Intermediates und schließlich, ganz am Ende, dem eigenen Server-Zertifikat. Auf der Kommandozeile sieht das z.B. so aus:

Das wars.

PHP die Zertifikatskette mitteilen

Als letztes müssen wir unserem PHP-Script noch mitteilen, dass es auch diese Zertifikatskette berücksichtigen soll. Auch das passiert über den Parameter, den ich oben schon angesprochen habe. Doch diesmal erlauben wir PHP, den SSL-Host zu verfizieren:

Geschafft. PHP sollte nun, zur Laufzeit, den SSL-Host überprüfen und dabei auf die Zertifikate zurückgreifen, die die Authentizität einwandfrei bestätigen.

Man kann den Verweis auch an anderer Stelle definieren. Die PHP-Funktion openssl_get_cert_locations(); teilt uns mit, wo PHP nach gültigen Zertifikaten sucht:

Hier fällt z.B. die Datei /Applications/XAMPP/xamppfiles/share/curl/curl-ca-bundle.crt auf. Diese wird in der php.ini mit dem Parameter

gesetzt. Auch in dieser Datei liegen eine Menge von Root- bzw. Intermediate-Zertifikaten. Mitunter macht es mehr Sinn, diese Einstellung in der php.ini zu nutzen, damit auch curl() darauf zurückgreifen kann.