From ae21fd63feba61d45ed18b07b9871cee157bf6d04e444c3765a5131d62173126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= Date: Thu, 5 Mar 2015 21:47:39 +0000 Subject: [PATCH] Accepting request 288636 from home:kstreitova:branches:Apache:Modules - add mod_nss-SNI_support.patch that brings Server Name Indication support that allows to have multiple HTTPS websites with multiple certificates on the same IP address and port. [fate#318331], [bnc#897712] OBS-URL: https://build.opensuse.org/request/show/288636 OBS-URL: https://build.opensuse.org/package/show/Apache:Modules/apache2-mod_nss?expand=0&rev=4 --- apache2-mod_nss.changes | 8 + apache2-mod_nss.spec | 5 +- mod_nss-SNI_support.patch | 397 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 mod_nss-SNI_support.patch diff --git a/apache2-mod_nss.changes b/apache2-mod_nss.changes index 984edf6..7a8645f 100644 --- a/apache2-mod_nss.changes +++ b/apache2-mod_nss.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Tue Mar 3 10:25:27 UTC 2015 - kstreitova@suse.com + +- add mod_nss-SNI_support.patch that brings Server Name Indication + support that allows to have multiple HTTPS websites with multiple + certificates on the same IP address and port. + [fate#318331], [bnc#897712] + ------------------------------------------------------------------- Tue Nov 4 14:13:46 UTC 2014 - kstreitova@suse.com diff --git a/apache2-mod_nss.spec b/apache2-mod_nss.spec index 579bcf9..c37426b 100644 --- a/apache2-mod_nss.spec +++ b/apache2-mod_nss.spec @@ -1,7 +1,7 @@ # # spec file for package apache2-mod_nss # -# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -74,6 +74,8 @@ Patch23: mod_nss-bnc863518-reopen_dev_tty.diff Patch24: mod_nss-compare_subject_CN_and_VS_hostname.patch # PATCH-FIX-UPSTREAM bnc#902068 kstreitova@suse.com -- small fixes for TLS-v1.2 Patch25: mod_nss-add_support_for_enabling_TLS_v1.2.patch +# PATCH-FEATURE-UPSTREAM bnc#897712 fate#318331 kstreitova@suse.com -- add Server Name Indication support +Patch26: mod_nss-SNI_support.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build %define apxs /usr/sbin/apxs2 @@ -115,6 +117,7 @@ security library. %patch23 -p0 -b .mod_nss-bnc863518-reopen_dev_tty.rpmpatch %patch24 -p1 -b .mod_nss-compare_subject_CN_and_VS_hostname.rpmpatch %patch25 -p1 -b .mod_nss-add_support_for_enabling_TLS_v1.2.rpmpatch +%patch26 -p1 -b .mod_nss-SNI_support.rpmpatch # keep this last, otherwise we get fuzzyness from above %if 0%{?suse_version} >= 1300 diff --git a/mod_nss-SNI_support.patch b/mod_nss-SNI_support.patch new file mode 100644 index 0000000..a43c9a4 --- /dev/null +++ b/mod_nss-SNI_support.patch @@ -0,0 +1,397 @@ +From 07405e4dbd1e2df6583bb571a6230da78788c19b Mon Sep 17 00:00:00 2001 +From: standa +Date: Thu, 26 Feb 2015 15:23:50 +0100 +Subject: [PATCH] SNI check with NameVirtualHosts + +--- + docs/mod_nss.html | 10 ++++++ + mod_nss.c | 3 ++ + mod_nss.h | 18 ++++++++++ + nss_engine_config.c | 11 +++++++ + nss_engine_init.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++----- + nss_engine_kernel.c | 51 ++++++++++++++++++++++++++++ + nss_util.c | 19 +++++++++++ + 7 files changed, 199 insertions(+), 8 deletions(-) + +Index: mod_nss-1.0.8/docs/mod_nss.html +=================================================================== +--- mod_nss-1.0.8.orig/docs/mod_nss.html ++++ mod_nss-1.0.8/docs/mod_nss.html +@@ -1079,6 +1079,16 @@ components of the client certificate, th +
+ NSSRequire
+

++NSSSNI
++
++Enables or disables Server Name Identification(SNI) extension check for ++SSL. This option is turn on by default. SNI vhost_id gets from HTTPS header. ++
++
++Example
++
++NSSSNI off
++
+ NSSProxyEngine
+
+ Enables or disables mod_nss HTTPS support for mod_proxy.
+Index: mod_nss-1.0.8/mod_nss.c +=================================================================== +--- mod_nss-1.0.8.orig/mod_nss.c ++++ mod_nss-1.0.8/mod_nss.c +@@ -85,6 +85,9 @@ static const command_rec nss_config_cmds + SSL_CMD_SRV(FIPS, FLAG, + "FIPS 140-1 mode " + "(`on', `off')") ++ SSL_CMD_SRV(SNI, FLAG, ++ "SNI" ++ "(`on', `off')") + SSL_CMD_ALL(CipherSuite, TAKE1, + "Comma-delimited list of permitted SSL Ciphers, + to enable, - to disable " + "(`[+-]XXX,...,[+-]XXX' - see manual)") +Index: mod_nss-1.0.8/mod_nss.h +=================================================================== +--- mod_nss-1.0.8.orig/mod_nss.h ++++ mod_nss-1.0.8/mod_nss.h +@@ -308,6 +308,7 @@ struct SSLSrvConfigRec { + const char *ocsp_name; + BOOL ocsp; + BOOL enabled; ++ BOOL sni; + BOOL proxy_enabled; + const char *vhost_id; + int vhost_id_len; +@@ -343,6 +344,20 @@ typedef struct + PRInt32 version; /* protocol version valid for this cipher */ + } cipher_properties; + ++typedef struct { ++ const char *vhost_id[70]; ++ const char *nick[30]; ++} vhostNick[500]; ++ ++typedef struct { ++ enum { ++ PW_NONE = 0, ++ PW_FROMFILE = 1, ++ PW_PLAINTEXT = 2, ++ PW_EXTERNAL = 3 ++ } source; ++ char *data; ++} secuPWData; + /* Compatibility between Apache 2.0.x and 2.2.x. The numeric version of + * the version first appeared in Apache 2.0.56-dev. I picked 2.0.55 as it + * is the last version without this define. This is used for more than just +@@ -384,6 +399,7 @@ void *nss_config_perdir_merge(apr_pool_t + void *nss_config_server_create(apr_pool_t *p, server_rec *s); + void *nss_config_server_merge(apr_pool_t *p, void *basev, void *addv); + const char *nss_cmd_NSSFIPS(cmd_parms *, void *, int); ++const char *nss_cmd_NSSSNI(cmd_parms *, void *, int); + const char *nss_cmd_NSSEngine(cmd_parms *, void *, int); + const char *nss_cmd_NSSOCSP(cmd_parms *, void *, int); + const char *nss_cmd_NSSOCSPDefaultResponder(cmd_parms *, void *, int); +@@ -471,6 +487,8 @@ apr_file_t *nss_util_ppopen(server_rec + void nss_util_ppclose(server_rec *, apr_pool_t *, apr_file_t *); + char *nss_util_readfilter(server_rec *, apr_pool_t *, const char *, + const char * const *); ++char *getSECItemData(char *data, int len); ++char *getSplitURL(char *url); + /* ssl_io_buffer_fill fills the setaside buffering of the HTTP request + * to allow an SSL renegotiation to take place. */ + int nss_io_buffer_fill(request_rec *r); +Index: mod_nss-1.0.8/nss_engine_config.c +=================================================================== +--- mod_nss-1.0.8.orig/nss_engine_config.c ++++ mod_nss-1.0.8/nss_engine_config.c +@@ -135,6 +135,7 @@ static SSLSrvConfigRec *nss_config_serve + sc->ocsp_name = NULL; + sc->fips = UNSET; + sc->enabled = UNSET; ++ sc->sni = TRUE; + sc->proxy_enabled = UNSET; + sc->vhost_id = NULL; /* set during module init */ + sc->vhost_id_len = 0; /* set during module init */ +@@ -214,6 +215,7 @@ void *nss_config_server_merge(apr_pool_t + cfgMerge(ocsp_name, NULL); + cfgMergeBool(fips); + cfgMergeBool(enabled); ++ cfgMergeBool(sni); + cfgMergeBool(proxy_enabled); + cfgMergeBool(proxy_ssl_check_peer_cn); + +@@ -320,6 +322,15 @@ const char *nss_cmd_NSSFIPS(cmd_parms *c + + return NULL; + } ++ ++const char *nss_cmd_NSSSNI(cmd_parms *cmd, void *dcfg, int flag) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++ ++ sc->sni = flag ? TRUE : FALSE; ++ ++ return NULL; ++} + + const char *nss_cmd_NSSOCSP(cmd_parms *cmd, void *dcfg, int flag) + { +Index: mod_nss-1.0.8/nss_engine_init.c +=================================================================== +--- mod_nss-1.0.8.orig/nss_engine_init.c ++++ mod_nss-1.0.8/nss_engine_init.c +@@ -28,12 +28,17 @@ static SECStatus ownHandshakeCallback(PR + static SECStatus NSSHandshakeCallback(PRFileDesc *socket, void *arg); + static CERTCertificate* FindServerCertFromNickname(const char* name, const CERTCertList* clist); + SECStatus nss_AuthCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer); ++PRInt32 ownSSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr, ++ PRUint32 sniNameArrSize, void *arg); + + /* + * Global variables defined in this file. + */ + char* INTERNAL_TOKEN_NAME = "internal "; + ++vhostNick vhostNickSNI; ++int vhostNickSize = 0; ++ + cipher_properties ciphers_def[ciphernum] = + { + /* SSL2 cipher suites */ +@@ -382,6 +387,11 @@ int nss_init_Module(apr_pool_t *p, apr_p + sc->vhost_id = nss_util_vhostid(p, s); + sc->vhost_id_len = strlen(sc->vhost_id); + ++ if (sc->server->nickname != NULL && sc->vhost_id != NULL) { ++ strcpy(vhostNickSNI[vhostNickSize].vhost_id, sc->vhost_id); ++ strcpy(vhostNickSNI[vhostNickSize].nick, sc->server->nickname); ++ vhostNickSize++; ++ } + /* Fix up stuff that may not have been set */ + if (sc->fips == UNSET) { + sc->fips = FALSE; +@@ -534,7 +544,7 @@ int nss_init_Module(apr_pool_t *p, apr_p + ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, + "Init: Initializing (virtual) servers for SSL"); + +- CERTCertList* clist = PK11_ListCerts(PK11CertListUser, NULL); ++ CERTCertList* clist = PK11_ListCerts(PK11CertListUserUnique, NULL); + + for (s = base_server; s; s = s->next) { + sc = mySrvConfig(s); +@@ -547,7 +557,7 @@ int nss_init_Module(apr_pool_t *p, apr_p + /* + * Read the server certificate and key + */ +- nss_init_ConfigureServer(s, p, ptemp, sc, clist); ++ nss_init_ConfigureServer(s, p, ptemp, sc, clist); + } + + if (clist) { +@@ -1233,13 +1243,21 @@ static void nss_init_certificate(server_ + break; + } + +- secstatus = SSL_ConfigSecureServer(model, *servercert, *serverkey, *KEAtype); ++ secstatus = SSL_ConfigSecureServer(model, *servercert, *serverkey, *KEAtype); + if (secstatus != SECSuccess) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "SSL error configuring server: '%s'", nickname); + nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); + nss_die(); +- } ++ } ++ ++ /* SNI */ ++ if (SSL_SNISocketConfigHook(model, (SSLSNISocketConfig) ownSSLSNISocketConfig, (void*) s) != SECSuccess) { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, ++ "SSL_SNISocketConfigHook failed"); ++ nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); ++ nss_die(); ++ } + } + + +@@ -1308,6 +1326,7 @@ static void nss_init_server_certs(server + nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); + nss_die(); + } ++ + } + + static void nss_init_proxy_ctx(server_rec *s, +@@ -1374,7 +1393,6 @@ void nss_init_Child(apr_pool_t *p, serve + /* If any servers have SSL, we want sslenabled set so we + * can perform further initialization + */ +- + if (sc->enabled == UNSET) { + sc->enabled = FALSE; + } +@@ -1404,11 +1422,12 @@ void nss_init_Child(apr_pool_t *p, serve + nss_init_SSLLibrary(base_server); + + /* Configure all virtual servers */ +- CERTCertList* clist = PK11_ListCerts(PK11CertListUser, NULL); ++ CERTCertList* clist = PK11_ListCerts(PK11CertListUserUnique, NULL); + for (s = base_server; s; s = s->next) { + sc = mySrvConfig(s); +- if (sc->server->servercert == NULL && NSS_IsInitialized()) +- nss_init_ConfigureServer(s, p, mc->ptemp, sc, clist); ++ if (sc->server->servercert == NULL && NSS_IsInitialized()) { ++ nss_init_ConfigureServer(s, p, mc->ptemp, sc, clist); ++ } + } + if (clist) { + CERT_DestroyCertList(clist); +@@ -1741,3 +1760,63 @@ int nss_parse_ciphers(server_rec *s, cha + + return 0; + } ++ ++PRInt32 ownSSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr, ++ PRUint32 sniNameArrSize, void *arg) ++{ ++ server_rec *s = (server_rec *)arg; ++ ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, ++ "start function ownSSLSNISocketConfig for SNI"); ++ ++ secuPWData *pwdata; ++ CERTCertificate * cert = NULL; ++ SECKEYPrivateKey * privKey = NULL; ++ char *nickName = NULL; ++ char *vhost = NULL; ++ int i; ++ ++ PORT_Assert(fd && sniNameArr); ++ if (!fd || !sniNameArr) { ++ return SSL_SNI_SEND_ALERT; ++ } ++ vhost = getSECItemData((char *) sniNameArr->data, sniNameArr->len); ++ ++ for(i = 0; isni parameter gets vhost from HTTPS header ++ */ ++ SSLSrvConfigRec *sc = mySrvConfig(r->server); ++ ++ SECItem *hostInfo = NULL; ++ hostInfo = SSL_GetNegotiatedHostInfo(ssl); ++ if (hostInfo != NULL && sc->sni) { ++ if (ap_is_initial_req(r) && (hostInfo->len != 0)) { ++ char *servername = NULL; ++ char *host, *scope_id; ++ apr_port_t port; ++ apr_status_t rv; ++ ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, ++ "SNI hostInfo hostInfo->data:%s and hostInfo->len:%d" ++ , hostInfo->data, hostInfo->len); ++ ++ servername = getSECItemData((char *) hostInfo->data, hostInfo->len); ++ ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, ++ "SNI hostInfo servername:%s, lenght:%d" ++ , servername, (unsigned)strlen(servername)); ++ ++ if (!r->hostname) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, ++ "Hostname %s provided via SNI, but no hostname" ++ " provided in HTTP request", servername); ++ return HTTP_BAD_REQUEST; ++ } ++ ++ rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); ++ if (rv != APR_SUCCESS || scope_id) { ++ return HTTP_BAD_REQUEST; ++ } ++ ++ if (strcasecmp(host, servername)) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, ++ "Hostname %s provided via SNI and hostname %s provided" ++ " via HTTP are different", servername, host); ++ ++ SECITEM_FreeItem(hostInfo, PR_TRUE); ++ servername = NULL; ++ return HTTP_BAD_REQUEST; ++ } else { ++ SECITEM_FreeItem(hostInfo, PR_TRUE); ++ servername = NULL; ++ } ++ } ++ } ++ /* + * Log information about incoming HTTPS requests + */ + if (r->server->loglevel >= APLOG_INFO && ap_is_initial_req(r)) { +Index: mod_nss-1.0.8/nss_util.c +=================================================================== +--- mod_nss-1.0.8.orig/nss_util.c ++++ mod_nss-1.0.8/nss_util.c +@@ -100,3 +100,22 @@ char *nss_util_readfilter(server_rec *s, + + return buf; + } ++ ++char *getSECItemData(char *data, int len) { ++ ++ data[len]='\0'; ++ ++ return data; ++} ++ ++char *getSplitURL(char *url) { ++ ++ int iter = 0; ++ ++ while(url[iter] != '\0' && url[iter] != ':'){ ++ url[iter++]; ++ } ++ url[iter]='\0'; ++ ++ return url; ++}