{"id":1352,"date":"2012-11-09T01:36:57","date_gmt":"2012-11-09T00:36:57","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=1352"},"modified":"2012-11-09T02:16:59","modified_gmt":"2012-11-09T01:16:59","slug":"kaputte-krypto-beim-indianer","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=1352","title":{"rendered":"Kaputte Krypto beim Indianer"},"content":{"rendered":"<p>Eigentlich wollte ich einzig mal das SSL-Deployment auf meinem Server etwas aufr\u00e4umen und in diesem Zuge auch den Blog mal vern\u00fcnftig auf SSL ziehen, aber aus der einfachen Aufgabe, 19 Zertifikate auf die passenden Subdomains zu heften wurde dann doch eine etwas umfangreicher Aufgabe. Nicht etwa wegen der Vielzahl an Subdomains (jede Subdomain musste f\u00fcr sowohl IPv4 als auch IPv6 konfiguriert werden), sondern wegen einem kleinen nervigen Bug in der kaputten Krypto. Ursache war dabei aber nicht etwa, dass er nicht verschl\u00fcsselt h\u00e4tte, oder das falsche Zertifikat gezeigt h\u00e4tte &#8211; nunja, damit rechnet man ja noch. Der Fehler war viel subtiler: Beim Aufruf von sub.domain.tld lieferte der Server das richtige Zertifikat, aber antwortete mit der Website f\u00fcr domain.tld. Also: Happy debugging!<!--more--><\/p>\n<p>Nun ist das ja nichts Neues, dass die meiste Krypto kaputt ist, aber von der Subtilit\u00e4t des Fehlers ist der durchaus bemerkenswert &#8211; Nahezu ein Fall &#8222;wie konnte das jemals funktionieren!&#8220; Aber kurz zur verwendeten Konfig zum Mitmei\u00dfeln. Gegeben seien 2 Domains, die auf sowohl IPv4 als auch IPv6 verf\u00fcgbar gemacht werden sollen:<\/p>\n<pre lang=\"apache\" escaped=\"true\">NameVirtualHost 127.0.0.1:443\r\nNameVirtualHost [::1]:443\r\nNameVirtualHost [::2]:443\r\n\r\n&lt;VirtualHost 127.0.0.1:443&gt;\r\n\r\n    ServerAdmin     webmaster@domain.tld\r\n    DocumentRoot    \/var\/www\/virtual\/domain.tld\/htdocs\r\n\r\n    ServerName      domain.tld\r\n    ServerAlias     www.domain.tld domain.tld *.domain.tld\r\n\r\n    GnuTLSEnable on\r\n    GnuTLSCertificateFile \/etc\/ssl\/public\/domain.tld.crt\r\n    GnuTLSKeyFile \/etc\/ssl\/private\/domain.tld.key\r\n    GnuTLSPriorities SECURE:!MD5:!ANON-DH:-VERS-SSL3.0:+COMP-DEFLATE:-AES-128-CBC:-CAMELLIA-128-CBC:-3DES-CBC:-ARCFOUR-40\r\n\r\n    Header add Strict-Transport-Security \"max-age=15768000\"\r\n&lt;\/VirtualHost&gt;\r\n\r\n&lt;VirtualHost 127.0.0.1:443&gt;\r\n\r\n    ServerAdmin     webmaster@domain.tld\r\n    DocumentRoot    \/var\/www\/virtual\/domain.tld\/sub\/htdocs\r\n\r\n    ServerName      sub.domain.tld\r\n    ServerAlias     www.sub.domain.tld sub.domain.tld *.sub.domain.tld\r\n\r\n    GnuTLSEnable on\r\n    GnuTLSCertificateFile \/etc\/ssl\/public\/sub.domain.tld.crt\r\n    GnuTLSKeyFile \/etc\/ssl\/private\/sub.domain.tld.key\r\n    GnuTLSPriorities SECURE:!MD5:!ANON-DH:-VERS-SSL3.0:+COMP-DEFLATE:-AES-128-CBC:-CAMELLIA-128-CBC:-3DES-CBC:-ARCFOUR-40\r\n\r\n    Header add Strict-Transport-Security \"max-age=15768000\"\r\n&lt;\/VirtualHost&gt;\r\n\r\n&lt;VirtualHost [::1]:443&gt;\r\n\r\n    ServerAdmin     webmaster@domain.tld\r\n    DocumentRoot    \/var\/www\/virtual\/domain.tld\/htdocs\r\n\r\n    ServerName      domain.tld\r\n    ServerAlias     www.domain.tld domain.tld *.domain.tld\r\n\r\n    GnuTLSEnable on\r\n    GnuTLSCertificateFile \/etc\/ssl\/public\/domain.tld.crt\r\n    GnuTLSKeyFile \/etc\/ssl\/private\/domain.tld.key\r\n    GnuTLSPriorities SECURE:!MD5:!ANON-DH:-VERS-SSL3.0:+COMP-DEFLATE:-AES-128-CBC:-CAMELLIA-128-CBC:-3DES-CBC:-ARCFOUR-40\r\n\r\n    Header add Strict-Transport-Security \"max-age=15768000\"\r\n&lt;\/VirtualHost&gt;\r\n\r\n&lt;VirtualHost [::2]:443&gt;\r\n\r\n    ServerAdmin     webmaster@domain.tld\r\n    DocumentRoot    \/var\/www\/virtual\/domain.tld\/sub\/htdocs\r\n\r\n    ServerName      sub.domain.tld\r\n    ServerAlias     www.sub.domain.tld sub.domain.tld *.sub.domain.tld\r\n\r\n    GnuTLSEnable on\r\n    GnuTLSCertificateFile \/etc\/ssl\/public\/sub.domain.tld.crt\r\n    GnuTLSKeyFile \/etc\/ssl\/private\/sub.domain.tld.key\r\n    GnuTLSPriorities SECURE:!MD5:!ANON-DH:-VERS-SSL3.0:+COMP-DEFLATE:-AES-128-CBC:-CAMELLIA-128-CBC:-3DES-CBC:-ARCFOUR-40\r\n\r\n    Header add Strict-Transport-Security \"max-age=15768000\"\r\n&lt;\/VirtualHost&gt;<\/pre>\n<p>Soweit ja reines Copy&amp;Paste. Also Config testen und Server neustarten:<\/p>\n<pre lang=\"bash\" escaped=\"true\">apachectl configtest\r\napachectl restart<\/pre>\n<p>Und das ern\u00fcchternde Ergebnis: SSL tut zwar, sogar mit den richtigen Zertifikaten, nur wer auf http:\/\/sub.domain.tld\/ die Daten f\u00fcr sub.domain.tld erwartet liegt etwas falsch: Denn diese erh\u00e4lt man nur wenn man die gleiche Konfig OHNE SSL nutzen w\u00fcrde.<\/p>\n<p>Dass es an dieser Stelle wahrscheinlich zu einem Problem mit den Aliasnamen kam, dachte ich mir zu diesem Zeitpunkt schon fast, da ich aber f\u00fcr IPv6 jeder Subdomain in der Config eine eigene IP vergebe, kommentierte ich den Wildcard erstmal nur f\u00fcr IPv4 aus. Dies \u00e4nderte an dem Ph\u00e4nomen jedoch wenig und so bat ich einen Bekannten um seinen Rat. Er schaute auf die Konfig, schaute noch einmal hin und meinte: irgendwas ist hier broken, die Config stimmt.<\/p>\n<p>Also schaute ich mal eben in den Quelltext von mod_gnutls, was ich f\u00fcr den Krypto-Krams verwende und bisher auch wenig Probleme mit hatte: denn bisher funktionierte SNI hier deutlich besser als mit mod_ssl, was mangels brauchbaren Supports von eben SNI mal eben weggeschmissen wurde &#8211; und nicht nur, weil OpenSSL das beste Beispiel f\u00fcr Doku = Kot ist. Da mod_gnutls direkt als Paket f\u00fcr die verwendete Distribution vorlag, ging es somit im Code weiter:<\/p>\n<pre lang=\"bash\" escaped=\"true\">cd \/usr\/src\r\nsudo apt-src install libapache2-mod-gnutls\r\ncd mod-gnutls-0.5.10\r\n$EDITOR src\/*.c<\/pre>\n<p>Gl\u00fccklicherweise umfasst der Code f\u00fcr mod_gnutls lediglich 5 Dateien, was den \u00dcberblick recht schnell erm\u00f6glichte. Nach etwas Einarbeitung stie\u00df ich auf die Fnktion mgs_find_sni_server, welche in gnutls_hook.c definiert wird. Ein Blick auf deren Implementierung verwies wiederum auf ap_vhost_iterate_given_conn, welche in der Apache Portable Runtime daf\u00fcr zust\u00e4ndig ist, \u00fcber die verf\u00fcgbaren VHosts zu iterieren. Hierf\u00fcr ruft ap_vhost_iterate_given_conn einem vom Aufrufer \u00fcbergebenen Callback auf, der f\u00fcr jeden VHost einmalig aufgerufen wird. Liefert der Callback einen Wert ungleich 0, so bricht ap_vhost_iterate_given_conn ab und gibt den R\u00fcckgabewert des letzten Callback-Aufrufes zur\u00fcck. Soweit ganz einfach &#8211; aber falsch.<\/p>\n<p>Schauen wir mal in den Code &#8211; ich zitiere mal:<\/p>\n<pre lang=\"c\" escaped=\"true\" highlight=\"22,96,120\">\r\n#if USING_2_1_RECENT\r\ntypedef struct {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mgs_handle_t *ctxt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mgs_srvconf_rec *sc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const char *sni_name;\r\n} vhost_cb_rec;\r\n\r\nstatic int vhost_cb(void *baton, conn_rec * conn, server_rec * s)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mgs_srvconf_rec *tsc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vhost_cb_rec *x = baton;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _gnutls_log(debug_log_fp, \"%s: %d\\n\", __func__, __LINE__);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 tsc = (mgs_srvconf_rec *) ap_get_module_config(s-&gt;module_config,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &amp;gnutls_module);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (tsc-&gt;enabled != GNUTLS_ENABLED_TRUE || tsc-&gt;cert_cn == NULL) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return 0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/* The CN can contain a * -- this will match those too. *\/\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (ap_strcasecmp_match(x-&gt;sni_name, tsc-&gt;cert_cn) == 0) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/* found a match *\/\r\n#if MOD_GNUTLS_DEBUG\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 x-&gt;ctxt-&gt;c-&gt;base_server,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"GnuTLS: Virtual Host CB: \"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"'%s' == '%s'\", tsc-&gt;cert_cn, x-&gt;sni_name);\r\n#endif\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/* Because we actually change the server used here, we need to reset\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 * things like ClientVerify.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 *\/\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 x-&gt;sc = tsc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/* Shit. Crap. Dammit. We *really* should rehandshake here, as our\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 * certificate structure *should* change when the server changes. \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 * acccckkkkkk. \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 *\/\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return 1;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } else {\r\n#if MOD_GNUTLS_DEBUG\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 x-&gt;ctxt-&gt;c-&gt;base_server,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"GnuTLS: Virtual Host CB: \"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"'%s' != '%s'\", tsc-&gt;cert_cn, x-&gt;sni_name);\r\n#endif\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return 0;\r\n}\r\n#endif\r\n\r\nmgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int rv;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 unsigned int sni_type;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 size_t data_len = MAX_HOST_LEN;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 char sni_name[MAX_HOST_LEN];\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mgs_handle_t *ctxt;\r\n#if USING_2_1_RECENT\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vhost_cb_rec cbx;\r\n#else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 server_rec *s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mgs_srvconf_rec *tsc;\r\n#endif\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (session == NULL)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return NULL;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _gnutls_log(debug_log_fp, \"%s: %d\\n\", __func__, __LINE__);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ctxt = gnutls_transport_get_ptr(session);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rv = gnutls_server_name_get(ctxt-&gt;session, sni_name,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &amp;data_len, &amp;sni_type, 0);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (rv != 0) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return NULL;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (sni_type != GNUTLS_NAME_DNS) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ctxt-&gt;c-&gt;base_server,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"GnuTLS: Unknown type '%d' for SNI: \"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"'%s'\", sni_type, sni_name);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return NULL;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \/**\r\n\u00a0\u00a0\u00a0\u00a0 * Code in the Core already sets up the c-&gt;base_server as the base\r\n\u00a0\u00a0\u00a0\u00a0 * for this IP\/Port combo.\u00a0 Trust that the core did the 'right' thing.\r\n\u00a0\u00a0\u00a0\u00a0 *\/\r\n#if USING_2_1_RECENT\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cbx.ctxt = ctxt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cbx.sc = NULL;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cbx.sni_name = sni_name;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rv = ap_vhost_iterate_given_conn(ctxt-&gt;c, vhost_cb, &amp;cbx);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (rv == 1) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return cbx.sc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n#else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for (s = ap_server_conf; s; s = s-&gt;next) {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 tsc =\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (mgs_srvconf_rec *)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ap_get_module_config(s-&gt;module_config, &amp;gnutls_module);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (tsc-&gt;enabled != GNUTLS_ENABLED_TRUE) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 continue;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n#if MOD_GNUTLS_DEBUG\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ctxt-&gt;c-&gt;base_server,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"GnuTLS: sni-x509 cn: %s\/%d pk: %s s: 0x%08X s-&gt;n: 0x%08X\u00a0 sc: 0x%08X\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 tsc-&gt;cert_cn, rv,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 gnutls_pk_algorithm_get_name\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (gnutls_x509_privkey_get_pk_algorithm\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (ctxt-&gt;sc-&gt;privkey_x509)), (unsigned int) s,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (unsigned int) s-&gt;next, (unsigned int) tsc);\r\n#endif\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/* The CN can contain a * -- this will match those too. *\/\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (ap_strcasecmp_match(sni_name, tsc-&gt;cert_cn) == 0) {\r\n#if MOD_GNUTLS_DEBUG\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ctxt-&gt;c-&gt;base_server,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"GnuTLS: Virtual Host: \"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"'%s' == '%s'\", tsc-&gt;cert_cn,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sni_name);\r\n#endif\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return tsc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n#endif\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return NULL;\r\n}\r\n<\/pre>\n<p>Bei genauerer Betrachtung liegen hier 2 Fallstricke, die mod_gnutls mit Bravur beide gerissen hat!<\/p>\n<p>Nummer 1 ist das eigentliche ServerName-Fehlverhalten, was sich darin begr\u00fcndet, dass ein beliebiger passender Wildcard ausreicht, damit der Callback behauptet, den richtigen VHost gefunden zu haben.<\/p>\n<p>Nummer 2 ist etwas subtiler, aber eigentlich noch deutlich b\u00f6sartiger: Die Implementierung der Callback-Routine ignoriert die IP-Adresse auf der der VHost aufgespannt ist, was dazu f\u00fchrt, dass ein Alias f\u00fcr www.ipv6-only.tld pl\u00f6tzlich auch auf IPv4 akzeptiert wird, OBWOHL dieser dort nirgends konfiguriert ist.<\/p>\n<p>W\u00e4rend Nummer 1 nur f\u00fcr falschen Content sorgt, was an sich schon \u00e4rgerlich genug ist, sorgt Nummer 2 daf\u00fcr, dass unter Umst\u00e4nden eine nur f\u00fcr das Intranet gedachte Seite pl\u00f6tzlich frei im Internet verf\u00fcgbar wird, wenn man nur deren Domain kennt. AUTSCH!<\/p>\n<p>Der Workaround vorerst ist damit: Keine sich \u00fcberschneidenden ServerAlias-Direktiven, wenn ein unspezifischer Alias eine Subdomain \u00fcberdecken k\u00f6nnte. Damit l\u00e4sst sich Problem 1 bereits recht gut umschiffen, was derzeit auch ausreicht, Problem 2 bleibt aber bestehen.<\/p>\n<p>Beide Fehler habe ich Upstream reported und werd mir die Tage einmal anschauen, inwiefern man diese ohne allzu gro\u00dfe Umbauarbeiten beheben kann. Soweit ich die Situation im Code einsch\u00e4tze, sollte sich hier eine recht einfach L\u00f6sung finden lassen.<\/p>\n<p>Dennoch zeigt dieses Beispiel wieder einmal sch\u00f6n, wie kaputt unsere t\u00e4glich eingesetzte Krypto ist.<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=1352&amp;md5=aabf91ba6c39d730a1e79e66935030a2\" 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>Eigentlich wollte ich einzig mal das SSL-Deployment auf meinem Server etwas aufr\u00e4umen und in diesem Zuge auch den Blog mal vern\u00fcnftig auf SSL ziehen, aber aus der einfachen Aufgabe, 19 Zertifikate auf die passenden Subdomains zu heften wurde dann doch eine etwas umfangreicher Aufgabe. Nicht etwa wegen der Vielzahl an Subdomains (jede Subdomain musste f\u00fcr [&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":[156,14,10,98,162,112,346,50],"class_list":["post-1352","post","type-post","status-publish","format-standard","hentry","category-server","tag-apache","tag-bugs","tag-debian","tag-developement","tag-ipv6","tag-kryptographie","tag-server","tag-ssl"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1352","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=1352"}],"version-history":[{"count":7,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1352\/revisions"}],"predecessor-version":[{"id":1359,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1352\/revisions\/1359"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1352"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1352"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1352"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}