{"id":83,"date":"2009-01-30T22:20:17","date_gmt":"2009-01-30T22:20:17","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=83"},"modified":"2009-01-31T18:12:01","modified_gmt":"2009-01-31T18:12:01","slug":"php-als-ssl-client","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=83","title":{"rendered":"PHP als SSL-Client"},"content":{"rendered":"<p>Es ist ja nicht so, als ob PHP nichts kann, ganz im Gegenteil: PHP kann alles, nur nicht das, was man brauch &#8211; naja, oder zumindest nicht ausreichend einfach. Da w\u00e4re z.B. die Geschichte mit der sicheren Kommunikation \u00fcber SSL\/TLS. PHP selber muss, wenn es auf einem Server l\u00e4uft, SSL nicht weiter beherrschen wie das Auslesen der Umgebungsvariablen, die vom Apache gesetzt werden. M\u00f6chte man nun aber von einem fremden Server via PHP ein paar Daten sicher abfragen oder \u00fcbertragen bekommen, darf man eine Kr\u00fccke nach der anderen benutzen.<!--more--><\/p>\n<p>Da w\u00e4re zuerst einmal <a title=\"PHP: fsockopen\" href=\"http:\/\/php.net\/fsockopen\"><strong><code>fsockopen<\/code><\/strong><\/a>, was an sich sehr nett ist, und was bei einigen Communities daf\u00fcr sorgt, dass man aus dem IRC-Channel gekickt wird, weil einer der Ops grad schlechte Laune hat. Aber gut. das hat jeder Op mal. <code>fsockopen<\/code> erlaubt es bei PHP Client-Sockets sowohl f\u00fcr <code>udp<\/code>, <code>tcp<\/code> als auch weitere Protokollwrapper zu \u00f6ffnen: Darunter auch SSL und TLS. Das ist an sich schon einmal recht praktisch, jedoch steht nirgends beschrieben, inwiefern mit diesen Funktionen eine \u00dcberpr\u00fcfung des vom Server verschickten Zertifikates m\u00f6glich ist, bzw. ob man ein eigenes Client-Zertifikat mitgeben kann. Wahrscheinlich \u00fcber einen undokumentierten Experimental-Hack im Context-System &#8211; oder im Klartext: Nein. Das kommt also f\u00fcr meinen Anwendungsfall nicht in Frage.<\/p>\n<p>Gehen wir zum n\u00e4chsten Kandidaten: <a title=\"PHP: cURL Library\" href=\"http:\/\/php.net\/curl\"><strong>cURL<\/strong><\/a>. cURL ist so das Leichtgewicht in Sachen HTTP-Sprechen f\u00fcr Anf\u00e4nger. Man kann damit alles M\u00f6gliche machen, nur nicht vern\u00fcnftig arbeiten. Nach dem man mit <a title=\"PHP: curl_init\" href=\"http:\/\/php.net\/curl_init\"><code>curl_init<\/code><\/a> sich eine Resource geholt hat, kann man diese zwar konfigurieren und mit Hilfe der Funktion <a title=\"PHP: curl_setopt\" href=\"http:\/\/php.net\/curl_setopt\"><code>curl_setopt<\/code><\/a> eine Reihe verschiedener Einstellungen setzen: Darunter die SSL-Version, ob das Client- oder Server-Zertifikat gepr\u00fcft werden sollte, die Zertifizierungskette, zu verwendende Cipher und noch ein wenig mehr. Wenn meine Gegenstelle aber nicht SSL, sondern TLS spricht, dann versagt auch cURL kl\u00e4glich.<\/p>\n<p>Bliebe noch die <strong><a title=\"PHP: Socket und Stream-API\" href=\"http:\/\/php.net\/stream\">Socket-API<\/a><\/strong>. Diese ist zwar nicht allzu intuitiv und das Interface ist genauso vermurkst wie cURL, daf\u00fcr kann man hier aber wenigstens ansatzweise das tun, was ich m\u00f6chte: Arbeiten.<\/p>\n<p>Obwohl nicht ganz: Bevor das n\u00e4mlich geht, muss man daf\u00fcr sorgen, dass die <a title=\"PHP: OpenSSL Extension\" href=\"http:\/\/php.net\/openssl\"><strong>OpenSSL-Extension<\/strong><\/a> geladen und konfiguriert ist. Unter Windows ist dies am Einfachsten mit dem Download der PECL-Binaries der Extensions und einem Eintrag <\/p>\n<pre lang=\"ini\">extension=php_openssl.dll<\/pre>\n<p> in seiner <code>php.ini<\/code> getan, aber viel gr\u00f6\u00dfer ist der Aufwand meist auch nicht &#8211; vorausgesetzt PHP <a title=\"PHP: OpenSSL-Installation\" href=\"http:\/\/de2.php.net\/manual\/en\/openssl.installation.php#86578\">findet die richtigen Binaries<\/a> f\u00fcr OpenSSL an sich. Unter Linux ist der Support meist bereits durch die Distribution mit in PHP eingebaut, ansonsten muss man sich PHP selber bauen, da es f\u00fcr die OpenSSL-Erweiterung AFAIK kein eigenes Paket gibt (f\u00fcr Debian habe ich zumindest keines gesehen).<\/p>\n<p>OK, also wir haben die Socket-API, wir haben OpenSSL, aber wie quetscht man nun aus dem Socket das Zertifikat raus? Sucht man da bei Google, bekommt man unter anderem jemanden, der versucht hat, mit PHP <a title=\"Hello. Is there anybody in there?\" href=\"http:\/\/www.cdatazone.org\/index.php?\/archives\/20-Hello.-Is-There-Anybody-in-There.html\">SSL-Client-Zertifikat-Authentifizierung zu realisieren<\/a>. Gut, nehmen wir seinen Ansatz und bauen das etwas um:<\/p>\n<pre lang=\"php\">\r\n$site_cert = NULL;\r\n\r\n$context = stream_context_create();\r\n$result = stream_context_set_option($context, 'ssl', 'verify_host', true);\r\n$result = stream_context_set_option($context, 'ssl', 'allow_self_signed', true);\r\n$result = stream_context_set_option($context, 'ssl', 'capture_peer_cert', true);\r\n\r\nif ($fp = stream_socket_client(\"ssl:\/\/svn.benny-baumann.de:443\/\", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context)) {\r\n    if ($options = stream_context_get_options($context)) {\r\n        var_dump($options);\r\n        if (isset($options['ssl']) && isset($options['ssl']['peer_certificate'])) {\r\n            $site_cert = $options['ssl']['peer_certificate'];\r\n        }\r\n    }\r\n    fclose($fp);\r\n}\r\n\r\nif ($site_cert) {\r\n    openssl_x509_export($site_cert, $str_cert);\r\n    $pubkey = openssl_pkey_get_public($str_cert);\r\n    $keyinfo = openssl_pkey_get_details($pubkey);\r\n    var_dump($keyinfo);\r\n}\r\n<\/pre>\n<p>Soweit so gut: SSL funktioniert. Wenn man aber jegliche Vorkommen von SSL durch TLS austauscht, so rennt man in <a title=\"PHP: Server certificate not captured using TLS\" href=\"http:\/\/bugs.php.net\/47236\">einen weiteren Bug von PHP<\/a>.<\/p>\n<p>ARGH!<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=83&amp;md5=762b478906b855fff185342e4890ad00\" title=\"Flattr\" target=\"_blank\"><img src=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" srcset=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" alt=\"Flattr this!\"\/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Es ist ja nicht so, als ob PHP nichts kann, ganz im Gegenteil: PHP kann alles, nur nicht das, was man brauch &#8211; naja, oder zumindest nicht ausreichend einfach. Da w\u00e4re z.B. die Geschichte mit der sicheren Kommunikation \u00fcber SSL\/TLS. PHP selber muss, wenn es auf einem Server l\u00e4uft, SSL nicht weiter beherrschen wie das [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[4],"tags":[62,58,61,21,59,50,57,60],"class_list":["post-83","post","type-post","status-publish","format-standard","hentry","category-server","tag-bug","tag-curl","tag-openssl","tag-php","tag-sockets","tag-ssl","tag-tls","tag-zertifikate"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/83","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=83"}],"version-history":[{"count":10,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/83\/revisions"}],"predecessor-version":[{"id":93,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/83\/revisions\/93"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=83"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=83"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=83"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}