diff options
| author | Rob Crittenden <rcritten@redhat.com> | 2015-09-24 17:13:20 -0400 |
|---|---|---|
| committer | Rob Crittenden <rcritten@redhat.com> | 2015-10-02 16:51:56 -0400 |
| commit | 00fe09480dfd28674661830d8a045e0f560bbe51 (patch) | |
| tree | f13ebc99b09ee029ddbc75bba74aa60cb3e9dc66 | |
| parent | ea7584f67ef0e522254c3806cc0356e89594c711 (diff) | |
| download | mod_nss-00fe09480dfd28674661830d8a045e0f560bbe51.tar.gz mod_nss-00fe09480dfd28674661830d8a045e0f560bbe51.tar.xz mod_nss-00fe09480dfd28674661830d8a045e0f560bbe51.zip | |
Add support for Server Name Indication (SNI)
Uses a hash table to pair up server names and nicknames and
a lookup is done during the handshake to determine which
nickname to be used, and therefore which VirtualHost.
Based heavily on patch from Stanislav Tokos <stokos@suse.de>
| -rw-r--r-- | docs/mod_nss.html | 28 | ||||
| -rw-r--r-- | mod_nss.c | 5 | ||||
| -rw-r--r-- | mod_nss.h | 11 | ||||
| -rw-r--r-- | nss_engine_config.c | 22 | ||||
| -rw-r--r-- | nss_engine_init.c | 193 | ||||
| -rw-r--r-- | nss_engine_kernel.c | 79 | ||||
| -rw-r--r-- | nss_engine_vars.c | 7 | ||||
| -rw-r--r-- | nss_util.c | 51 |
8 files changed, 383 insertions, 13 deletions
diff --git a/docs/mod_nss.html b/docs/mod_nss.html index 19d8fef..f073978 100644 --- a/docs/mod_nss.html +++ b/docs/mod_nss.html @@ -184,7 +184,9 @@ following line to httpd.conf (location relative to httpd.conf):<br> </code><br> This has Apache load the mod_nss configuration file, <code>nss.conf</code>. It is here that you will setup your VirtualServer entries to and -configure your SSL servers.<br> +configure your SSL servers. If you have a certificate with Subject +Alternative Names then you can configure separate VirtualServer entries +for eacon one.<br> <h1><a name="Generation"></a>Certificate Generation</h1> A ksh script, <code>gencert</code>, is included to automatically @@ -1057,6 +1059,30 @@ If set to 0 then no buffering is done. <code>NSSRenegBufferSize 262144<br> </code><br> <br> +<big><big>NSSSNI</big></big><br> +<br> +Enables or disables Server Name Identification (SNI) extension check for +TLS. This option is enabled by default. To disable SNI, set this to off +in the default name-based VirtualHost. +<br> +<br> +<span style="font-weight: bold;">Example</span><br> +<br> +<code>NSSSNI off</code><br> +<br> +<big><big>NSSStrictSNIVHostCheck</big></big><br> +<br> +Configures whether a non-SNI client is allowed to access a name-based +VirtualHost. If set to on in the default name-based VirtualHost +then clients that are SNI unaware cannot access any virtual host. If set +to on in any other VirtualHost then SNI unaware clients cannot access +this particular virtual host. +<br> +<br> +<span style="font-weight: bold;">Example</span><br> +<br> +<code>NSSStrictSNIVHostCheck off</code><br> +<br> <big><big>NSSProxyEngine</big></big><br> <br> Enables or disables mod_nss HTTPS support for mod_proxy.<br> @@ -85,6 +85,11 @@ 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_SRV(StrictSNIVHostCheck, FLAG, + "Strict SNI virtual host checking") SSL_CMD_ALL(CipherSuite, TAKE1, "Comma-delimited list of permitted SSL Ciphers, + to enable, - to disable " "(`[+-]XXX,...,[+-]XXX' - see manual)") @@ -311,6 +311,8 @@ struct SSLSrvConfigRec { const char *ocsp_name; BOOL ocsp; BOOL enabled; + BOOL sni; + BOOL strict_sni_vhost_check; BOOL proxy_enabled; const char *vhost_id; int vhost_id_len; @@ -341,6 +343,10 @@ typedef struct { * for cipher definitions see nss_engine_cipher.h */ +/* pool and hash to store ServerName and NSSNickname pairs for SNI */ +apr_pool_t *mp; +apr_hash_t *ht; + /* 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 @@ -373,6 +379,8 @@ void *nss_config_perdir_merge(apr_pool_t *p, void *basev, void *addv); 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_NSSStrictSNIVHostCheck(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); @@ -463,6 +471,9 @@ apr_file_t *nss_util_ppopen(server_rec *, apr_pool_t *, const char *, 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 *searchHashVhostbyNick(char *vhost_id); +char *searchHashVhostbyNick_match(char *vhost_id); +void addHashVhostNick(char *vhost_id, char *nickname); /* 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, apr_size_t maxlen); diff --git a/nss_engine_config.c b/nss_engine_config.c index 8d4421a..2c9aa5a 100644 --- a/nss_engine_config.c +++ b/nss_engine_config.c @@ -134,6 +134,8 @@ static SSLSrvConfigRec *nss_config_server_new(apr_pool_t *p) sc->ocsp_name = NULL; sc->fips = UNSET; sc->enabled = UNSET; + sc->sni = TRUE; + sc->strict_sni_vhost_check = TRUE; sc->proxy_enabled = UNSET; sc->vhost_id = NULL; /* set during module init */ sc->vhost_id_len = 0; /* set during module init */ @@ -214,6 +216,8 @@ void *nss_config_server_merge(apr_pool_t *p, void *basev, void *addv) { cfgMerge(ocsp_name, NULL); cfgMergeBool(fips); cfgMergeBool(enabled); + cfgMergeBool(sni); + cfgMergeBool(strict_sni_vhost_check); cfgMergeBool(proxy_enabled); cfgMergeBool(proxy_ssl_check_peer_cn); cfgMergeBool(session_tickets); @@ -343,6 +347,24 @@ const char *nss_cmd_NSSFIPS(cmd_parms *cmd, void *dcfg, int flag) 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_NSSStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->strict_sni_vhost_check = flag ? TRUE : FALSE; + + return NULL; +} + const char *nss_cmd_NSSOCSP(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); diff --git a/nss_engine_init.c b/nss_engine_init.c index 4d82f53..df84a9f 100644 --- a/nss_engine_init.c +++ b/nss_engine_init.c @@ -29,6 +29,7 @@ static SECStatus ownHandshakeCallback(PRFileDesc * socket, void *arg); 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 nssSSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr, PRUint32 sniNameArrSize, void *arg); /* * Global variables defined in this file. @@ -89,6 +90,7 @@ static void nss_init_SSLLibrary(server_rec *base_server) int fipsenabled = FALSE; int ocspenabled = FALSE; int ocspdefault = FALSE; + int snienabled = FALSE; char *dbdir = NULL; const char * ocspurl = NULL; const char * ocspname = NULL; @@ -118,6 +120,10 @@ static void nss_init_SSLLibrary(server_rec *base_server) return; } } + + if (sc->sni == TRUE) { + snienabled = TRUE; + } } /* We need to be in the same directory as libnssckbi.so to load the @@ -243,6 +249,14 @@ static void nss_init_SSLLibrary(server_rec *base_server) } } + if (snienabled) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, + "SNI is enabled"); + } else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, + "SNI is disabled"); + } + /* * Seed the Pseudo Random Number Generator (PRNG) * only need ptemp here; nothing inside allocated from the pool @@ -262,6 +276,8 @@ int nss_init_Module(apr_pool_t *p, apr_pool_t *plog, int fipsenabled = FALSE; int threaded = 0; struct semid_ds status; + char *split_vhost_id = NULL; + char *last1; mc->nInitCount++; @@ -325,6 +341,14 @@ int nss_init_Module(apr_pool_t *p, apr_pool_t *plog, sc->vhost_id = nss_util_vhostid(p, s); sc->vhost_id_len = strlen(sc->vhost_id); + if (sc->sni && sc->server->nickname != NULL && sc->vhost_id != NULL) { + split_vhost_id = apr_strtok(sc->vhost_id, ":", &last1); + ap_str_tolower(split_vhost_id); + addHashVhostNick(split_vhost_id, (char *)sc->server->nickname); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "SNI: %s -> %s", split_vhost_id, (char *)sc->server->nickname); + } + /* Fix up stuff that may not have been set */ if (sc->fips == UNSET) { sc->fips = FALSE; @@ -477,7 +501,7 @@ int nss_init_Module(apr_pool_t *p, apr_pool_t *plog, 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); @@ -1033,12 +1057,20 @@ static void nss_init_certificate(server_rec *s, const char *nickname, SSLKEAType *KEAtype, PRFileDesc *model, int enforce, + int sni, const CERTCertList* clist) { + SSLModConfigRec *mc = myModConfig(s); SECCertTimeValidity certtimestatus; SECStatus secstatus; PK11SlotInfo* slot = NULL; + CERTCertNicknames *certNickDNS = NULL; + char **nnptr = NULL; + int nn = 0; + apr_array_header_t *names = NULL; + apr_array_header_t *wild_names = NULL; + int i, j; if (nickname == NULL) { return; @@ -1105,17 +1137,55 @@ static void nss_init_certificate(server_rec *s, const char *nickname, *KEAtype = NSS_FindCertKEAType(*servercert); + /* add ServerAlias entries to hash */ + names = s->names; + if (names) { + char **name = (char **)names->elts; + for (i = 0; i < names->nelts; ++i) { + ap_str_tolower(name[i]); + addHashVhostNick(name[i], (char *)nickname); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "SNI ServerAlias: %s -> %s", name[i], nickname); + } + } + + /* add ServerAlias entries with wildcards */ + wild_names = s->wild_names; + if (wild_names) { + char **wild_name = (char **)wild_names->elts; + for (j = 0; j < wild_names->nelts; ++j) { + ap_str_tolower(wild_name[j]); + addHashVhostNick(wild_name[j], (char *)nickname); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "SNI wildcard: %s -> %s", wild_name[i], nickname); + } + } + + /* get valid DNS names from certificate to hash */ + certNickDNS = CERT_GetValidDNSPatternsFromCert(*servercert); + + if (certNickDNS) { + nnptr = certNickDNS->nicknames; + nn = certNickDNS->numnicknames; + + while ( nn > 0 ) { + ap_str_tolower(*nnptr); + addHashVhostNick(*nnptr, (char *)nickname); + nnptr++; + nn--; + } + } + /* Subject/hostname check */ secstatus = CERT_VerifyCertName(*servercert, s->server_hostname); if (secstatus != SECSuccess) { char *cert_dns = CERT_GetCommonName(&(*servercert)->subject); ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Misconfiguration of certificate's CN and virtual name." - " The certificate CN has %s. We expected %s as virtual" - " name.", cert_dns, s->server_hostname); + "Misconfiguration of certificate's CN and virtual name." + " The certificate CN has %s. We expected %s as virtual" + " name.", cert_dns, s->server_hostname); PORT_Free(cert_dns); } - /* * Check for certs that are expired or not yet valid and WARN about it. * No need to refuse working - the client gets a warning. @@ -1140,13 +1210,23 @@ static void nss_init_certificate(server_rec *s, const char *nickname, 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(); } + + if (PR_TRUE == sni) { + if (SSL_SNISocketConfigHook(model, (SSLSNISocketConfig) nssSSLSNISocketConfig, (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(); + } + } } @@ -1192,11 +1272,13 @@ static void nss_init_server_certs(server_rec *s, nss_init_certificate(s, mctx->nickname, &mctx->servercert, &mctx->serverkey, &mctx->serverKEAType, - mctx->model, mctx->enforce, clist); + mctx->model, mctx->enforce, mctx->sc->sni, + clist); #ifdef NSS_ENABLE_ECC nss_init_certificate(s, mctx->eccnickname, &mctx->eccservercert, &mctx->eccserverkey, &mctx->eccserverKEAType, - mctx->model, mctx->enforce, clist); + mctx->model, mctx->enforce, mctx->sc->sni, + clist); #endif } @@ -1215,6 +1297,7 @@ static void nss_init_server_certs(server_rec *s, nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } + } static void nss_init_proxy_ctx(server_rec *s, @@ -1281,7 +1364,6 @@ void nss_init_Child(apr_pool_t *p, server_rec *base_server) /* If any servers have SSL, we want sslenabled set so we * can perform further initialization */ - if (sc->enabled == UNSET) { sc->enabled = FALSE; } @@ -1311,11 +1393,12 @@ void nss_init_Child(apr_pool_t *p, server_rec *base_server) 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()) + if (sc->server->servercert == NULL && NSS_IsInitialized()) { nss_init_ConfigureServer(s, p, mc->ptemp, sc, clist); + } } if (clist) { CERT_DestroyCertList(clist); @@ -1346,6 +1429,11 @@ apr_status_t nss_init_ModuleKill(void *data) if (mc->nInitCount == 1) nss_init_ChildKill(base_server); + if (mp) { + apr_pool_destroy(mp); + mp = NULL; + } + /* NSS_Shutdown() gets called in nss_init_ChildKill */ return APR_SUCCESS; } @@ -1398,6 +1486,11 @@ apr_status_t nss_init_ChildKill(void *data) } } + if (mp) { + apr_pool_destroy(mp); + mp = NULL; + } + if (shutdown) { /* Clear any client-side session cache data */ SSL_ClearSessionCache(); @@ -1597,3 +1690,81 @@ SECStatus NSSHandshakeCallback(PRFileDesc *socket, void *arg) { return SECSuccess; } + +/* + * Callback made during SSL request to see if SNI was requested and + * pair it with a configured nickname. + */ +PRInt32 nssSSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr, + PRUint32 sniNameArrSize, void *arg) +{ + server_rec *s = (server_rec *)arg; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "nssSSLSNISocketConfig"); + + void *pinArg; + CERTCertificate *cert = NULL; + SECKEYPrivateKey *privKey = NULL; + char *nickName = NULL; + char *vhost = NULL; + apr_pool_t *str_p; + + PORT_Assert(fd && sniNameArr); + if (!fd || !sniNameArr) { + return SSL_SNI_SEND_ALERT; + } + + apr_pool_create(&str_p, NULL); + vhost = apr_pstrndup(str_p, (char *) sniNameArr->data, sniNameArr->len); + + /* rfc6125 - Checking of Traditional Domain Names */ + ap_str_tolower(vhost); + + nickName = searchHashVhostbyNick(vhost); + if (nickName == NULL) { + /* search for wildcard_names in serverAlises */ + nickName = searchHashVhostbyNick_match(vhost); + if (nickName == NULL) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "SNI: Search for %s failed. Unrecognized name.", vhost); + goto loser; + } + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,"SNI: Found nickname %s for vhost: %s", nickName, vhost); + + pinArg = SSL_RevealPinArg(fd); + + /* if pinArg is NULL, then we would not get the key and + * return an error status. */ + cert = PK11_FindCertFromNickname(nickName, &pinArg); + if (cert == NULL) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Failed to find certificate for nickname: %s", nickName); + goto loser; + } + privKey = PK11_FindKeyByAnyCert(cert, &pinArg); + if (privKey == NULL) { + goto loser; + } + + SSLKEAType certKEA = NSS_FindCertKEAType(cert); + + if (SSL_ConfigSecureServer(fd, cert, privKey, certKEA) != SECSuccess) { + goto loser; /* Send alert */ + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "SNI: Successfully paired vhost %s with nickname: %s", vhost, nickName); + + return 0; + +loser: + if (privKey) + SECKEY_DestroyPrivateKey(privKey); + if (cert) + CERT_DestroyCertificate(cert); + apr_pool_destroy(str_p); + + return SSL_SNI_SEND_ALERT; +} diff --git a/nss_engine_kernel.c b/nss_engine_kernel.c index 721eedb..9ce1411 100644 --- a/nss_engine_kernel.c +++ b/nss_engine_kernel.c @@ -25,6 +25,8 @@ int nss_hook_ReadReq(request_rec *r) { SSLConnRec *sslconn = myConnConfig(r->connection); PRFileDesc *ssl = sslconn ? sslconn->ssl : NULL; + SECItem *hostInfo = NULL; + SSLSrvConfigRec *sc = mySrvConfig(r->server); if (!sslconn) { return DECLINED; @@ -72,6 +74,74 @@ int nss_hook_ReadReq(request_rec *r) } /* + * SNI is on by default. You can switch SNI off by setting + * NSSSNI off. + */ + + if (sc->sni) { + hostInfo = SSL_GetNegotiatedHostInfo(ssl); + if (hostInfo != NULL) { + if (ap_is_initial_req(r) && (hostInfo->len != 0)) { + char *servername = NULL; + char *host, *scope_id; + apr_port_t port; + apr_status_t rv; + apr_pool_t *s_p; + + hostInfo->data[hostInfo->len] = '\0'; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "SNI request for %s", (char *)hostInfo->data); + + apr_pool_create(&s_p, NULL); + servername = apr_pstrndup(s_p, (char *) hostInfo->data, hostInfo->len); + + 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); + apr_pool_destroy(s_p); + return HTTP_BAD_REQUEST; + } + + rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); + if (rv != APR_SUCCESS || scope_id) { + apr_pool_destroy(s_p); + 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); + + apr_pool_destroy(s_p); + return HTTP_BAD_REQUEST; + } + apr_pool_destroy(s_p); + } + } else if (((sc->strict_sni_vhost_check) + || (mySrvConfig(r->server))->strict_sni_vhost_check) + && r->connection->vhost_lookup_data) { + /* + * We are using a name based configuration here, but no hostname + * was provided via SNI. Don't allow that if are requested to do + * strict checking. Check whether this strict checking was set + * up either in the server config we used for handshaking or in + * our current server. This should avoid insecure configuration + * by accident. + */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "No hostname was provided via SNI for a name based" + " virtual host"); + apr_table_setn(r->notes, "error-notes", + "Reason: The client software did not provide a " + "hostname using Server Name Indication (SNI), " + "which is required to access this server.<br />\n"); + return HTTP_FORBIDDEN; + } + } + + /* * Log information about incoming HTTPS requests */ if (r->server->log.level >= APLOG_INFO && ap_is_initial_req(r)) { @@ -815,6 +885,8 @@ int nss_hook_Fixup(request_rec *r) int i; CERTCertificate *cert; CERTCertificateList *chain = NULL; + SECItem *hostInfo = NULL; + const char *servername; /* * Check to see if SSL is on @@ -840,6 +912,13 @@ int nss_hook_Fixup(request_rec *r) /* the always present HTTPS (=HTTP over SSL) flag! */ apr_table_setn(env, "HTTPS", "on"); + /* add content of SNI TLS extension (if supplied with ClientHello) */ + hostInfo = SSL_GetNegotiatedHostInfo(ssl); + if (hostInfo) { + servername = apr_pstrndup(r->pool, (char *) hostInfo->data, hostInfo->len); + apr_table_set(env, "SSL_TLS_SNI", servername); + } + /* standard SSL environment variables */ if (dc->nOptions & SSL_OPT_STDENVVARS) { for (i = 0; nss_hook_Fixup_vars[i]; i++) { diff --git a/nss_engine_vars.c b/nss_engine_vars.c index 517a691..7a0d08b 100644 --- a/nss_engine_vars.c +++ b/nss_engine_vars.c @@ -345,6 +345,13 @@ static char *nss_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var) CERT_DestroyCertificate(xs); } } + else if (ssl != NULL && strcEQ(var, "TLS_SNI")) { + SECItem *hostInfo = SSL_GetNegotiatedHostInfo(ssl); + if (hostInfo) { + result = apr_pstrndup(p, (char *) hostInfo->data, hostInfo->len); + PORT_Free(hostInfo); + } + } return result; } @@ -13,7 +13,6 @@ * limitations under the License. */ - #include "mod_nss.h" #include "ap_mpm.h" #include "apr_thread_mutex.h" @@ -100,3 +99,53 @@ char *nss_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd, return buf; } + +static void initializeHashVhostNick() { + if (NULL != ht) + return; + apr_pool_create(&mp, NULL); + ht = apr_hash_make(mp); +} + +char *searchHashVhostbyNick(char *vhost_id) { + char *searchVal = NULL; + + if (NULL == ht) + return NULL; + + searchVal = apr_hash_get(ht, vhost_id, APR_HASH_KEY_STRING); + + return searchVal; +} + +char *searchHashVhostbyNick_match(char *vhost_id) +{ + char *searchValReg = NULL; + apr_hash_index_t *hi; + + if (NULL == ht) + return NULL; + + for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) { + const char *k = NULL; + const char *v = NULL; + + apr_hash_this(hi, (const void**)&k, NULL, (void**)&v); + if (!ap_strcasecmp_match(vhost_id, k)) { + searchValReg = apr_hash_get(ht, k, APR_HASH_KEY_STRING); + return searchValReg; + } + } + return NULL; +} + +void addHashVhostNick(char *vhost_id, char *nickname) { + if (ht == NULL) { + initializeHashVhostNick(); + } + + if (searchHashVhostbyNick(vhost_id) == NULL) { + apr_hash_set(ht, apr_pstrdup(mp, vhost_id), APR_HASH_KEY_STRING, + apr_pstrdup(mp, nickname)); + } +} |
