From bbde2f3f569b0b483b2ba8ce0cf5b43092f210ff Mon Sep 17 00:00:00 2001 From: rcritten <> Date: Thu, 29 Sep 2005 19:35:44 +0000 Subject: 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. --- docs/mod_nss.html | 174 +++++++++++++++++++++++++++++++++++++++++----------- mod_nss.c | 129 ++++++++++++++++++++++++++++---------- mod_nss.h | 14 ++++- nss_engine_config.c | 71 +++++++++++++++++++-- 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 @@ + + - - mod_nss @@ -32,25 +32,18 @@ Environment Variables
Database Management
Why is SSLv2 disabled?
-
+Frequently Asked Questions

Introduction

The mod_ssl package was created in April 1998 by Ralf S. Engelschall and was originally derived from the Apache-SSL package developed by Ben Laurie. It stays under a -BSD-style -license which is equivalent to the license used by The Apache Group 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. -
-
-mod_nss is based directly on the mod_ssl package from Apache + href="mailto:ben@algroup.co.uk">Ben Laurie. It is licensed under +the Apache 2.0 +license.
+
+
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 NSS calls instead.
@@ -93,6 +86,20 @@ installation. The assumption is that this has the layout of: PATH/lib, PATH/include, etc.
+ + --with-nss-inc=PATH
+ + The file system path to the NSS +include directory (e.g. /usr/local/include/nss3)
+ + + + --with-nss-lib=PATH
+ + The file system path to the NSS +lib directory (e.g. /usr/local/lib)
+ + --with-nspr=[PATH]
@@ -100,6 +107,20 @@ PATH/include, etc.
installation. The assumption is that this has the layout of: PATH/lib, PATH/include, etc. + + --with-nspr-inc=PATH
+ + The file system path to the NSPR +include directory (e.g. /usr/local/include/nspr4)
+ + + + --with-nspr-lib=PATH
+ + The file system path to the NSPR +lib directory (e.g. /usr/local/lib)
+ + --with-apxs=[PATH]
@@ -117,7 +138,7 @@ tells us where the APR include files and libraries are located

 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.

 It is strongly recommended that the mozilla.org version be used.
@@ -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:

FIPS is disabled by default.
@@ -404,7 +425,8 @@ Example
A space-separated list of the SSL ciphers used, with the prefix + to enable or - to disable.

-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 SSLv2 is not allowed in mod_nss.

Available ciphers are:
@@ -622,7 +644,7 @@ be enclosed in double quotes.
NSSNickname Server-Cert
NSSNickname "This contains a space"

-NSSEnforceValidCerts
+NSSEnforceValidCerts

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.

NSSEnforceValidCerts on

-NSSVerifyClient
+NSSVerifyClient

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.

Available options are:
- The mod_ssl option option_no_ca is not supported.
@@ -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.

-NSSRequire
+Example
+
+NSSRequire
+

+NSSProxyEngine
+
+Enables or disables mod_nss HTTPS support for mod_proxy.
+
+Example
+
+NSSProxyEngine on
+
+NSSProxyProtocol
+
+Specifies the SSL protocols that may be used in proxy connections. The +syntax is identical to NSSProtocol.
+
+Example
+
+NSSProxyProtocol SSLv3
+

+NSSProxyCipherSuite
+
+Specifies the SSL ciphers available for proxy connections. They syntax +is identical to NSSCipherSuite.
+
+Example
+
+NSSProxyCipherSuite ++rsa_3des_sha,-rsa_null_md5,-rsa_null_sha,+rsa_rc4_128_md5
+
+NSSProxyNickname
+
+The nickname of the client certificate to send if the remote server +requests client authentication.
+
+Example
+
+NSSProxyNickname beta

Environment Variables

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:
% certutil -V -n Server-Cert -u V -d .
certutil: certificate is valid

Why is SSLv2 disabled?

-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. -
+SSL 3/TLS. SSL2 also doesn't support useful features like client +authentication. +
+

Frequently Asked Questions

+Q. Does mod_nss support mod_proxy?
+
+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 36468. +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.
+
+You also have to change the SSL functions that mod_proxy looks to use. +You'll need to apply this patch:
+
+1038,1039c1038,1039
+< APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
+< APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
+---
+> APR_DECLARE_OPTIONAL_FN(int, nss_proxy_enable, (conn_rec *));
+> APR_DECLARE_OPTIONAL_FN(int, nss_engine_disable, (conn_rec *));
+1041,1042c1041,1042
+< static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = +NULL;
+< static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable += NULL;
+---
+> static APR_OPTIONAL_FN_TYPE(nss_proxy_enable) *proxy_ssl_enable = +NULL;
+> static APR_OPTIONAL_FN_TYPE(nss_engine_disable) *proxy_ssl_disable += NULL;
+1069,1070c1069,1070
+<     proxy_ssl_enable = +APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
+<     proxy_ssl_disable = +APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
+---
+>     proxy_ssl_enable = +APR_RETRIEVE_OPTIONAL_FN(nss_proxy_enable);
+>     proxy_ssl_disable = +APR_RETRIEVE_OPTIONAL_FN(nss_engine_disable);
+

diff --git a/mod_nss.c b/mod_nss.c index e546680..2dd2f3c 100644 --- a/mod_nss.c +++ b/mod_nss.c @@ -15,6 +15,7 @@ #include "mod_nss.h" #include +#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); } diff --git a/mod_nss.h b/mod_nss.h index eb452cb..a2a4bef 100644 --- a/mod_nss.h +++ b/mod_nss.h @@ -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 +#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); -- cgit