diff options
author | rcritten <> | 2005-09-29 19:35:44 +0000 |
---|---|---|
committer | rcritten <> | 2005-09-29 19:35:44 +0000 |
commit | bbde2f3f569b0b483b2ba8ce0cf5b43092f210ff (patch) | |
tree | f2a936af8ab186a747824c0ff73b6ecd36b6b268 | |
parent | cd6deedffa07c991fc6119ef055d2f634db5eca9 (diff) | |
download | mod_nss-bbde2f3f569b0b483b2ba8ce0cf5b43092f210ff.tar.gz mod_nss-bbde2f3f569b0b483b2ba8ce0cf5b43092f210ff.tar.xz mod_nss-bbde2f3f569b0b483b2ba8ce0cf5b43092f210ff.zip |
Add proxy support to mod_nss. Most of the changes are related to
adding new configuration directives. For the others we need to
initialize an NSS socket differently whether we will be acting as a
client or a server.
-rw-r--r-- | docs/mod_nss.html | 174 | ||||
-rw-r--r-- | mod_nss.c | 129 | ||||
-rw-r--r-- | mod_nss.h | 14 | ||||
-rw-r--r-- | nss_engine_config.c | 71 | ||||
-rw-r--r-- | nss_engine_init.c | 107 |
5 files changed, 385 insertions, 110 deletions
diff --git a/docs/mod_nss.html b/docs/mod_nss.html index 8d38d47..7d6f5f1 100644 --- a/docs/mod_nss.html +++ b/docs/mod_nss.html @@ -1,4 +1,6 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> <!-- Copyright 2001-2005 The Apache Software Foundation @@ -13,8 +15,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and --> -<html> -<head> <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"> <title>mod_nss</title> @@ -32,25 +32,18 @@ <a href="#Environment">Environment Variables</a><br> <a href="#Database_Management">Database Management</a><br> <a href="#SSLv2">Why is SSLv2 disabled?</a><br> -<br> +<a href="#FAQ">Frequently Asked Questions</a><br> <h1><a name="Introduction"></a>Introduction</h1> The <a href="http://www.modssl.org/">mod_ssl</a> package was created in April 1998 by <a href="mailto:rse@engelschall.com">Ralf S. Engelschall</a> and was originally derived from the <a href="http://www.apache-ssl.org/">Apache-SSL</a> package developed by <a - href="mailto:ben@algroup.co.uk">Ben Laurie</a>. It stays under a -BSD-style -license which is equivalent to the license used by <a - href="http://www.apache.org/">The Apache Group</a> for the Apache -webserver -itself. This means, in short, that you are free to use it both for -commercial -and non-commercial purposes as long as you retain the authors' -copyright -notices and give the proper credit. -<br> -<br> -mod_nss is based directly on the mod_ssl package from Apache + href="mailto:ben@algroup.co.uk">Ben Laurie</a>. It is licensed under +the <a href="http://www.apache.org/licenses/" class="external" + title="http://www.apache.org/licenses/" rel="nofollow">Apache 2.0 +license</a><span class="urlexpansion">.<br> +<br> +</span>mod_nss is based directly on the mod_ssl package from Apache 2.0.54. It is a conversion from using OpenSSL calls to using <a href="http://www.mozilla.org/projects/security/pki/nss/">NSS</a> calls instead.<br> @@ -94,6 +87,20 @@ PATH/include, etc.<br> </td> </tr> <tr> + <td style="vertical-align: top;">--with-nss-inc=PATH<br> + </td> + <td style="vertical-align: top;">The file system path to the NSS +include directory (e.g. /usr/local/include/nss3)<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--with-nss-lib=PATH<br> + </td> + <td style="vertical-align: top;">The file system path to the NSS +lib directory (e.g. /usr/local/lib)<br> + </td> + </tr> + <tr> <td style="vertical-align: top;">--with-nspr=[PATH]<br> </td> <td style="vertical-align: top;">The file system path of the NSPR @@ -101,6 +108,20 @@ installation. The assumption is that this has the layout of: PATH/lib, PATH/include, etc.</td> </tr> <tr> + <td style="vertical-align: top;">--with-nspr-inc=PATH<br> + </td> + <td style="vertical-align: top;">The file system path to the NSPR +include directory (e.g. /usr/local/include/nspr4)<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--with-nspr-lib=PATH<br> + </td> + <td style="vertical-align: top;">The file system path to the NSPR +lib directory (e.g. /usr/local/lib)<br> + </td> + </tr> + <tr> <td style="vertical-align: top;">--with-apxs=[PATH]<br> </td> <td style="vertical-align: top;">The location of the apxs binary @@ -117,7 +138,7 @@ tells us where the APR include files and libraries are located<br> </table> <br> If --with-nss or --with-nspr are not passed configure will look -for the mozilla-[nss|nspr]-devel packages and use the libraries with +for the [nss|nspr]-devel packages and use the libraries with that if found.<br> <br> It is strongly recommended that the mozilla.org version be used.<br> @@ -371,12 +392,12 @@ limited to those that are FIPS-certified. Any non-FIPS that are included in the NSSCipherSuite entry are automatically disabled. The allowable ciphers are:<br> <ul> -<li>rsa_3des_sha</li> -<li>rsa_des_sha</li> -<li>fips_3des_sha</li> -<li>fips_des_sha</li> -<li>rsa_des_56_sha</li> -<li>fortezza</li> + <li>rsa_3des_sha</li> + <li>rsa_des_sha</li> + <li>fips_3des_sha</li> + <li>fips_des_sha</li> + <li>rsa_des_56_sha</li> + <li>fortezza</li> </ul> <span style="font-weight: bold;"><br> </span>FIPS is disabled by default.<br> @@ -404,7 +425,8 @@ Example</span><br style="font-weight: bold;"> A space-separated list of the SSL ciphers used, with the prefix <code>+</code> to enable or <code>-</code> to disable.<br> <br> -All ciphers are disabled by default. The SSLv2 ciphers cannot be enabled because +All ciphers are disabled by default. The SSLv2 ciphers cannot be +enabled because <a href="#SSLv2">SSLv2</a> is not allowed in mod_nss.<br> <br> Available ciphers are:<br> @@ -622,7 +644,7 @@ be enclosed in double quotes.<br> <code>NSSNickname Server-Cert</code><br> <code>NSSNickname "This contains a space"</code><br> <br> -NSSEnforceValidCerts<br> +<big><big>NSSEnforceValidCerts</big></big><br> <br> By default mod_nss will not start up if the server certificate is not valid. This means that if the certificate has @@ -636,7 +658,7 @@ not recommended.<br> <br> <code>NSSEnforceValidCerts on</code><br> <br> -NSSVerifyClient<br> +<big><big>NSSVerifyClient</big></big><br> <br> Determines whether Client Certificate Authentication will be requested or required. This may be set in a @@ -646,18 +668,17 @@ per-directry context an SSL renogitation is required and a certificate requested from the client.<br> <br> Available options are:<br> - <ul> <li><code>none</code>: no client certificate is required or requested<br> - </li> - <li>code>optional</code>: a client + </li> + <li>code>optional: a client certificate is requested but if one is not available, the connection may continue.<br> - </li> + </li> <li><code>require</code>: a valid client certificate is required for the connection to continue.<br> - </li> + </li> </ul> The mod_ssl option <code>option_no_ca</code> is not supported.<br> @@ -732,7 +753,45 @@ Provides a regular expression-based access-control mechanism. Access may be restricted (or allowed) based on any number of variables such as components of the client certificate, the remote IP address, etc.<br> <br> -<code>NSSRequire</code><br> +<span style="font-weight: bold;">Example</span><br> +<br> +<code>NSSRequire<br> +</code><br> +<big><big>NSSProxyEngine</big></big><br> +<br> +Enables or disables mod_nss HTTPS support for mod_proxy.<br> +<br> +<span style="font-weight: bold;">Example</span><br> +<br> +<code>NSSProxyEngine on</code><br> +<br> +<big><big>NSSProxyProtocol</big></big><br> +<br> +Specifies the SSL protocols that may be used in proxy connections. The +syntax is identical to NSSProtocol.<br> +<br> +<span style="font-weight: bold;">Example</span><br> +<br> +<code>NSSProxyProtocol SSLv3<br> +</code><br> +<big><big>NSSProxyCipherSuite</big></big><br> +<br> +Specifies the SSL ciphers available for proxy connections. They syntax +is identical to NSSCipherSuite.<br> +<br> +<span style="font-weight: bold;">Example</span><br> +<br> +<code>NSSProxyCipherSuite ++rsa_3des_sha,-rsa_null_md5,-rsa_null_sha,+rsa_rc4_128_md5</code><br> +<br> +<big><big>NSSProxyNickname</big></big><br> +<br> +The nickname of the client certificate to send if the remote server +requests client authentication.<br> +<br> +<span style="font-weight: bold;">Example</span><br> +<br> +<code>NSSProxyNickname beta</code><br> <h1><a name="Environment"></a>Environment Variables</h1> Quite a few environment variables (for CGI and SSI) may be set depending on the NSSOptions configuration. It can be expensive to set @@ -1121,10 +1180,53 @@ have NSS validate it:<br> <code>% certutil -V -n Server-Cert -u V -d .<br> certutil: certificate is valid</code><br> <h1><a name="SSLv2"></a>Why is SSLv2 disabled?</h1> -All major browsers (Firefox, Internet Explorer, Mozilla, Netscape, Opera, and -Safari) support SSL 3 and TLS so there is no need for a web server to support +All major browsers (Firefox, Internet Explorer, Mozilla, Netscape, +Opera, and +Safari) support SSL 3 and TLS so there is no need for a web server to +support SSL 2. There are some known attacks against SSL 2 that are handled by -SSL 3/TLS. SSL2 also doesn't support useful features like client authentication. -<br> +SSL 3/TLS. SSL2 also doesn't support useful features like client +authentication. +<br> +<h1><a name="FAQ"></a>Frequently Asked Questions</h1> +Q. Does mod_nss support mod_proxy?<br> +<br> +A. In order to use the mod_nss proxy support you will need to build +your own mod_proxy by applying a patch found in bug <a + href="http://issues.apache.org/bugzilla/show_bug.cgi?id=36468">36468</a>. +The patch is needed so we can compare the hostname contained in the +remote certificate with the hostname you meant to visit. This prevents +man-in-the-middle attacks.<br> +<br> +You also have to change the SSL functions that mod_proxy looks to use. +You'll need to apply this patch:<br> +<br> +<code>1038,1039c1038,1039<br> +< APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));<br> +< APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));<br> +---<br> +> APR_DECLARE_OPTIONAL_FN(int, nss_proxy_enable, (conn_rec *));<br> +> APR_DECLARE_OPTIONAL_FN(int, nss_engine_disable, (conn_rec *));<br> +1041,1042c1041,1042<br> +< static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = +NULL;<br> +< static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable += NULL;<br> +---<br> +> static APR_OPTIONAL_FN_TYPE(nss_proxy_enable) *proxy_ssl_enable = +NULL;<br> +> static APR_OPTIONAL_FN_TYPE(nss_engine_disable) *proxy_ssl_disable += NULL;<br> +1069,1070c1069,1070<br> +< proxy_ssl_enable = +APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);<br> +< proxy_ssl_disable = +APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);<br> +---<br> +> proxy_ssl_enable = +APR_RETRIEVE_OPTIONAL_FN(nss_proxy_enable);<br> +> proxy_ssl_disable = +APR_RETRIEVE_OPTIONAL_FN(nss_engine_disable);<br> +</code><br> </body> </html> @@ -15,6 +15,7 @@ #include "mod_nss.h" #include <assert.h> +#include "sslerr.h" /* * the table of configuration directives we provide @@ -101,7 +102,6 @@ static const command_rec nss_config_cmds[] = { SSL_CMD_DIR(Require, AUTHCFG, RAW_ARGS, "Require a boolean expression to evaluate to true for granting access" "(arbitrary complex boolean expression - see manual)") -#ifdef PROXY /* * Proxy configuration for remote SSL connections */ @@ -114,31 +114,11 @@ static const command_rec nss_config_cmds[] = { SSL_CMD_SRV(ProxyCipherSuite, TAKE1, "SSL Proxy: colon-delimited list of permitted SSL ciphers " "(`XXX:...:XXX' - see manual)") - SSL_CMD_SRV(ProxyVerify, TAKE1, - "SSL Proxy: whether to verify the remote certificate " - "(`on' or `off')") - SSL_CMD_SRV(ProxyVerifyDepth, TAKE1, - "SSL Proxy: maximum certificate verification depth " - "(`N' - number of intermediate certificates)") - SSL_CMD_SRV(ProxyCACertificateFile, TAKE1, - "SSL Proxy: file containing server certificates " - "(`/path/to/file' - PEM encoded certificates)") - SSL_CMD_SRV(ProxyCACertificatePath, TAKE1, - "SSL Proxy: directory containing server certificates " - "(`/path/to/dir' - contains PEM encoded certificates)") - SSL_CMD_SRV(ProxyCARevocationPath, TAKE1, - "SSL Proxy: CA Certificate Revocation List (CRL) path " - "(`/path/to/dir' - contains PEM encoded files)") - SSL_CMD_SRV(ProxyCARevocationFile, TAKE1, - "SSL Proxy: CA Certificate Revocation List (CRL) file " - "(`/path/to/file' - PEM encoded)") - SSL_CMD_SRV(ProxyMachineCertificateFile, TAKE1, - "SSL Proxy: file containing client certificates " - "(`/path/to/file' - PEM encoded certificates)") - SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1, - "SSL Proxy: directory containing client certificates " - "(`/path/to/dir' - contains PEM encoded certificates)") + SSL_CMD_SRV(ProxyNickname, TAKE1, + "SSL Proxy: client certificate Nickname to be for proxy connections " + "(`nickname')") +#ifdef IGNORE /* Deprecated directives. */ AP_INIT_RAW_ARGS("NSSLog", ap_set_deprecated, NULL, OR_ALL, "SSLLog directive is no longer supported - use ErrorLog."), @@ -183,7 +163,6 @@ static SSLConnRec *nss_init_connection_ctx(conn_rec *c) return sslconn; } -#ifdef PROXY int nss_proxy_enable(conn_rec *c) { SSLSrvConfigRec *sc = mySrvConfig(c->base_server); @@ -193,7 +172,7 @@ int nss_proxy_enable(conn_rec *c) if (!sc->proxy_enabled) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, "SSL Proxy requested for %s but not enabled " - "[Hint: SSLProxyEngine]", sc->vhost_id); + "[Hint: NSSProxyEngine]", sc->vhost_id); return 0; } @@ -203,7 +182,6 @@ int nss_proxy_enable(conn_rec *c) return 1; } -#endif int nss_engine_disable(conn_rec *c) { @@ -222,6 +200,76 @@ int nss_engine_disable(conn_rec *c) return 1; } +/* Callback for an incoming certificate that is not valid */ + +SECStatus NSSBadCertHandler(void *arg, PRFileDesc * socket) +{ + conn_rec *c = (conn_rec *)arg; + PRErrorCode err = PR_GetError(); + SECStatus rv = SECFailure; + CERTCertificate *peerCert = SSL_PeerCertificate(socket); + + switch (err) { + case SSL_ERROR_BAD_CERT_DOMAIN: + if (c->remote_host != NULL) { + rv = CERT_VerifyCertName(peerCert, c->remote_host); + if (rv != SECSuccess) { + char *remote = CERT_GetCommonName(&peerCert->subject); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + "SSL Proxy: Possible man-in-the-middle attack. The remove server is %s, we expected %s", remote, c->remote_host, rv); + PORT_Free(remote); + } + } else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + "SSL Proxy: I don't have the name of the host we're supposed to connect to so I can't verify that we are connecting to who we think we should be. Giving up. Hint: See Apache bug 36468."); + } + break; + default: + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + "Bad remote server certificate.", err); + nss_log_nss_error(APLOG_MARK, APLOG_ERR, NULL); + break; + } + return rv; +} + +/* Callback to pull the client certificate upon server request */ + +static SECStatus NSSGetClientAuthData(void *arg, PRFileDesc *socket, + CERTDistNames *caNames, + CERTCertificate **pRetCert,/*return */ + SECKEYPrivateKey **pRetKey) +{ + CERTCertificate * cert; + SECKEYPrivateKey * privKey; + void * proto_win = NULL; + SECStatus rv = SECFailure; + char * localNickName = (char *)arg; + + proto_win = SSL_RevealPinArg(socket); + + if (localNickName) { + cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), + localNickName, certUsageSSLClient, + PR_FALSE, proto_win); + if (cert) { + privKey = PK11_FindKeyByAnyCert(cert, proto_win); + if (privKey) { + rv = SECSuccess; + } else { + CERT_DestroyCertificate(cert); + } + } + + if (rv == SECSuccess) { + *pRetCert = cert; + *pRetKey = privKey; + } + } + + return rv; +} + static int nss_hook_pre_connection(conn_rec *c, void *csd) { SSLSrvConfigRec *sc = mySrvConfig(c->base_server); @@ -285,7 +333,28 @@ static int nss_hook_pre_connection(conn_rec *c, void *csd) nss_io_filter_init(c, ssl); - SSL_ResetHandshake(ssl, PR_TRUE); + SSL_ResetHandshake(ssl, mctx->as_server); + + /* If we are doing a client connection, set our own bad certificate + * handler and register the nickname we want to use in case client + * authentication is requested. + */ + if (!mctx->as_server) { + if (SSL_BadCertHook(ssl, (SSLBadCertHandler) NSSBadCertHandler, c) != SECSuccess) + { + /* errors are reported in the certificate handler */ + return DECLINED; + } + if (mctx->nickname) { + if (SSL_GetClientAuthDataHook(ssl, NSSGetClientAuthData, + (void*)mctx->nickname) != SECSuccess) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, + "Unable to register client authentication callback"); + return DECLINED; + } + } + } return APR_SUCCESS; } @@ -335,9 +404,7 @@ static void nss_register_hooks(apr_pool_t *p) nss_var_register(); -#ifdef PROXY APR_REGISTER_OPTIONAL_FN(nss_proxy_enable); -#endif APR_REGISTER_OPTIONAL_FN(nss_engine_disable); } @@ -238,6 +238,8 @@ typedef struct { char *cipherSuite; + int as_server; + int ssl2; int ssl3; int tls; @@ -278,9 +280,7 @@ typedef struct { int nOptionsAdd; int nOptionsDel; const char *szCipherSuite; - nss_verify_t nVerifyClient; - const char *szCACertificatePath; - const char *szCACertificateFile; + nss_verify_t nVerifyClient; const char *szUserName; } SSLDirConfigRec; @@ -333,6 +333,11 @@ const char *nss_cmd_NSSOptions(cmd_parms *, void *, const char *); const char *nss_cmd_NSSRequireSSL(cmd_parms *cmd, void *dcfg); const char *nss_cmd_NSSRequire(cmd_parms *, void *, const char *); +const char *nss_cmd_NSSProxyEngine(cmd_parms *cmd, void *dcfg, int flag); +const char *nss_cmd_NSSProxyProtocol(cmd_parms *, void *, const char *); +const char *nss_cmd_NSSProxyCipherSuite(cmd_parms *, void *, const char *); +const char *nss_cmd_NSSProxyNickname(cmd_parms *cmd, void *dcfg, const char *arg); + /* module initialization */ int nss_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); void nss_init_Child(apr_pool_t *, server_rec *); @@ -363,8 +368,11 @@ APR_DECLARE_OPTIONAL_FN(char *, nss_var_lookup, APR_DECLARE_OPTIONAL_FN(int, nss_is_https, (conn_rec *)); /* Proxy Support */ +int nss_proxy_enable(conn_rec *c); int nss_engine_disable(conn_rec *c); +APR_DECLARE_OPTIONAL_FN(int, nss_proxy_enable, (conn_rec *)); + APR_DECLARE_OPTIONAL_FN(int, nss_engine_disable, (conn_rec *)); /* I/O */ diff --git a/nss_engine_config.c b/nss_engine_config.c index 9eb0cea..a13cdab 100644 --- a/nss_engine_config.c +++ b/nss_engine_config.c @@ -69,6 +69,8 @@ static void modnss_ctx_init(modnss_ctx_t *mctx) { mctx->sc = NULL; /* set during module init */ + mctx->as_server = PR_TRUE; + mctx->ssl2 = PR_FALSE; mctx->ssl3 = PR_FALSE; mctx->tls = PR_FALSE; @@ -87,6 +89,18 @@ static void modnss_ctx_init(modnss_ctx_t *mctx) } +static void modnss_ctx_init_proxy(SSLSrvConfigRec *sc, + apr_pool_t *p) +{ + modnss_ctx_t *mctx; + + mctx = sc->proxy = apr_palloc(p, sizeof(*sc->proxy)); + + modnss_ctx_init(mctx); + + mctx->as_server = PR_FALSE; +} + static void modnss_ctx_init_server(SSLSrvConfigRec *sc, apr_pool_t *p) { @@ -95,6 +109,8 @@ static void modnss_ctx_init_server(SSLSrvConfigRec *sc, mctx = sc->server = apr_palloc(p, sizeof(*sc->server)); modnss_ctx_init(mctx); + + mctx->as_server = PR_TRUE; } static SSLSrvConfigRec *nss_config_server_new(apr_pool_t *p) @@ -111,9 +127,7 @@ static SSLSrvConfigRec *nss_config_server_new(apr_pool_t *p) sc->proxy = NULL; sc->server = NULL; -#ifdef PROXY modnss_ctx_init_proxy(sc, p); -#endif modnss_ctx_init_server(sc, p); @@ -149,6 +163,13 @@ static void modnss_ctx_cfg_merge(modnss_ctx_t *base, cfgMerge(enforce, PR_TRUE); } +static void modnss_ctx_cfg_merge_proxy(modnss_ctx_t *base, + modnss_ctx_t *add, + modnss_ctx_t *mrg) +{ + modnss_ctx_cfg_merge(base, add, mrg); +} + static void modnss_ctx_cfg_merge_server(modnss_ctx_t *base, modnss_ctx_t *add, modnss_ctx_t *mrg) @@ -170,9 +191,7 @@ void *nss_config_server_merge(apr_pool_t *p, void *basev, void *addv) { cfgMergeBool(enabled); cfgMergeBool(proxy_enabled); -#ifdef PROXY modnss_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy); -#endif modnss_ctx_cfg_merge_server(base->server, add->server, mrg->server); @@ -270,7 +289,7 @@ const char *nss_cmd_NSSEngine(cmd_parms *cmd, void *dcfg, int flag) const char *nss_cmd_NSSFIPS(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - + sc->fips = flag ? TRUE : FALSE; return NULL; @@ -281,7 +300,7 @@ const char *nss_cmd_NSSOCSP(cmd_parms *cmd, void *dcfg, int flag) SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->ocsp = flag ? TRUE : FALSE; - + return NULL; } @@ -395,6 +414,46 @@ const char *nss_cmd_NSSNickname(cmd_parms *cmd, return NULL; } +const char *nss_cmd_NSSProxyEngine(cmd_parms *cmd, void *dcfg, int flag) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->proxy_enabled = flag ? TRUE : FALSE; + + return NULL; +} + +const char *nss_cmd_NSSProxyProtocol(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->proxy->auth.protocols = arg; +} + +const char *nss_cmd_NSSProxyCipherSuite(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->proxy->auth.cipher_suite = arg; + + return NULL; +} + +const char *nss_cmd_NSSProxyNickname(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->proxy->nickname = arg; + + return NULL; +} + const char *nss_cmd_NSSEnforceValidCerts(cmd_parms *cmd, void *dcfg, int flag) diff --git a/nss_engine_init.c b/nss_engine_init.c index 78fb56c..7eda971 100644 --- a/nss_engine_init.c +++ b/nss_engine_init.c @@ -16,7 +16,9 @@ #include "mod_nss.h" #include "apr_thread_proc.h" #include "ap_mpm.h" -#include <secmod.h> +#include "secmod.h" +#include "sslerr.h" +#include "pk11func.h" static SECStatus ownBadCertHandler(void *arg, PRFileDesc * socket); static SECStatus ownHandshakeCallback(PRFileDesc * socket, void *arg); @@ -111,6 +113,7 @@ static void nss_init_SSLLibrary(server_rec *s, int sslenabled, int fipsenabled, SSLModConfigRec *mc = myModConfig(s); SSLSrvConfigRec *sc; int forked = 0; + char cwd[PATH_MAX]; sc = mySrvConfig(s); @@ -172,8 +175,14 @@ static void nss_init_SSLLibrary(server_rec *s, int sslenabled, int fipsenabled, /* Set the PKCS #11 strings for the internal token. */ PK11_ConfigurePKCS11(NULL,NULL,NULL, INTERNAL_TOKEN_NAME, NULL, NULL,NULL,NULL,8,1); + /* We need to be in the same directory as libnssckbi.so to load the + * root certificates properly. + */ + getcwd(cwd, PATH_MAX); + chdir(mc->pCertificateDatabase); /* Initialize NSS and open the certificate database read-only. */ rv = NSS_Initialize(mc->pCertificateDatabase, mc->pDBPrefix, mc->pDBPrefix, "secmod.db", NSS_INIT_READONLY); + chdir(cwd); /* Assuming everything is ok so far, check the cert database password(s). */ if (sslenabled && (rv != SECSuccess)) { @@ -287,11 +296,9 @@ int nss_init_Module(apr_pool_t *p, apr_pool_t *plog, sc->server->sc = sc; } -#ifdef PROXY if (sc->proxy) { sc->proxy->sc = sc; } -#endif /* * Create the server host:port string because we need it a lot @@ -366,8 +373,8 @@ int nss_init_Module(apr_pool_t *p, apr_pool_t *plog, /* - * Announce mod_ssl and SSL library in HTTP Server field - * as ``mod_ssl/X.X.X OpenSSL/X.X.X'' + * Announce mod_nss and SSL library in HTTP Server field + * as ``mod_nss/X.X.X NSS/X.X.X'' */ nss_add_version_components(p, base_server); @@ -391,20 +398,28 @@ static void nss_init_ctx_socket(server_rec *s, nss_die(); } - if (SSL_OptionSet(mctx->model, SSL_HANDSHAKE_AS_SERVER, PR_TRUE) + if (SSL_OptionSet(mctx->model, SSL_HANDSHAKE_AS_SERVER, mctx->as_server) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Unable to set SSL server handshake mode."); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } - if (SSL_OptionSet(mctx->model, SSL_HANDSHAKE_AS_CLIENT, PR_FALSE) + if (SSL_OptionSet(mctx->model, SSL_HANDSHAKE_AS_CLIENT, !mctx->as_server) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Unable to disable handshake as client"); + "Unable to set handshake as client"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } + if (!mctx->as_server) { + if ((SSL_OptionSet(mctx->model, SSL_NO_CACHE, PR_TRUE)) != SECSuccess) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Unable to disable SSL client caching"); + nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); + nss_die(); + } + } } static void nss_init_ctx_protocol(server_rec *s, @@ -622,7 +637,8 @@ static void nss_init_ctx_cipher_suite(server_rec *s, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "FIPS mode enabled, permitted SSL ciphers are: [%s]", fipsciphers); - } + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Configuring permitted SSL ciphers [%s]", suite); @@ -666,7 +682,7 @@ static void nss_init_ctx_cipher_suite(server_rec *s, ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Cipher %s is enabled but this is not a FIPS cipher, disabling.", ciphers_def[i].name); cipher_state[i] = PR_FALSE; - } + } } } @@ -728,18 +744,20 @@ static void nss_init_server_certs(server_rec *s, * Get own certificate and private key. */ - if (mctx->nickname == NULL) { + if (mctx->nickname == NULL && mctx->as_server) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "No certificate nickname provided."); nss_die(); } - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "Using nickname %s.", mctx->nickname); + + if (mctx->nickname != NULL) + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Using nickname %s.", mctx->nickname); mctx->servercert = FindServerCertFromNickname(mctx->nickname); /* Verify the certificate chain. */ - if (mctx->servercert != NULL) { + if (mctx->servercert != NULL && mctx->as_server) { SECCertificateUsage usage = certificateUsageSSLServer; if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), mctx->servercert, PR_TRUE, usage, NULL, NULL) != SECSuccess) { @@ -754,14 +772,14 @@ static void nss_init_server_certs(server_rec *s, } } - if (NULL == mctx->servercert) + if (NULL == mctx->servercert && mctx->as_server) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Certificate not found: '%s'", mctx->nickname); nss_die(); } - if (strchr(mctx->nickname, ':')) + if (mctx->nickname && strchr(mctx->nickname, ':')) { char* token = strdup(mctx->nickname); char* colon = strchr(token, ':'); @@ -786,17 +804,20 @@ static void nss_init_server_certs(server_rec *s, slot = PK11_GetInternalKeySlot(); } - mctx->serverkey = PK11_FindPrivateKeyFromCert(slot, mctx->servercert, NULL); - PK11_FreeSlot(slot); + if (mctx->servercert) { + mctx->serverkey = PK11_FindPrivateKeyFromCert(slot, mctx->servercert, NULL); + PK11_FreeSlot(slot); + } - if (mctx->serverkey == NULL) { + if (mctx->as_server && mctx->serverkey == NULL) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Key not found for: '%s'", mctx->nickname); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } - mctx->serverKEAType = NSS_FindCertKEAType(mctx->servercert); + if (mctx->as_server) { + mctx->serverKEAType = NSS_FindCertKEAType(mctx->servercert); /* * Check for certs that are expired or not yet valid and WARN about it @@ -824,6 +845,7 @@ static void nss_init_server_certs(server_rec *s, "Unhandled Certificate time type %d for: '%s'", certtimestatus, mctx->nickname); break; } + } secstatus = (SECStatus)SSL_SetPKCS11PinArg(mctx->model, NULL); if (secstatus != SECSuccess) { @@ -832,15 +854,15 @@ static void nss_init_server_certs(server_rec *s, nss_die(); } -#if 1 - secstatus = SSL_ConfigSecureServer(mctx->model, mctx->servercert, mctx->serverkey, mctx->serverKEAType); - if (secstatus != SECSuccess) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "SSL error configuring server: '%s'", mctx->nickname); - nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); - nss_die(); + if (mctx->as_server) { + secstatus = SSL_ConfigSecureServer(mctx->model, mctx->servercert, mctx->serverkey, mctx->serverKEAType); + if (secstatus != SECSuccess) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "SSL error configuring server: '%s'", mctx->nickname); + nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); + nss_die(); + } } -#endif secstatus = (SECStatus)SSL_HandshakeCallback(mctx->model, (SSLHandshakeCallback)NSSHandshakeCallback, NULL); if (secstatus != SECSuccess) @@ -852,6 +874,16 @@ static void nss_init_server_certs(server_rec *s, } } +static void nss_init_proxy_ctx(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + SSLSrvConfigRec *sc) +{ + nss_init_ctx(s, p, ptemp, sc->proxy); + + nss_init_server_certs(s, p, ptemp, sc->proxy); +} + static void nss_init_server_ctx(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, @@ -876,11 +908,11 @@ void nss_init_ConfigureServer(server_rec *s, nss_init_server_ctx(s, p, ptemp, sc); } -#ifdef PROXY if (sc->proxy_enabled) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Enabling proxy."); nss_init_proxy_ctx(s, p, ptemp, sc); } -#endif } void nss_init_Child(apr_pool_t *p, server_rec *s) @@ -936,10 +968,14 @@ SECStatus ownBadCertHandler(void *arg, PRFileDesc * socket) { PRErrorCode err = PR_GetError(); - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, - "Bad certificate: %d", err); - - return SECFailure; + switch (err) { + default: + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + "Bad remote server certificate.", err); + nss_log_nss_error(APLOG_MARK, APLOG_ERR, NULL); + return SECFailure; + break; + } } /* @@ -1028,6 +1064,9 @@ FindServerCertFromNickname(const char* name) PRUint32 bestCertMatchedUsage = 0; PRBool bestCertIsValid = PR_FALSE; + if (name == NULL) + return NULL; + clist = PK11_ListCerts(PK11CertListUser, NULL); for (cln = CERT_LIST_HEAD(clist); !CERT_LIST_END(cln,clist); |