diff --git a/docs/conf/extra/httpd-ssl.conf.in b/docs/conf/extra/httpd-ssl.conf.in index f8e7281..dab8283 100644 --- a/docs/conf/extra/httpd-ssl.conf.in +++ b/docs/conf/extra/httpd-ssl.conf.in @@ -147,6 +147,12 @@ SSLCertificateKeyFile "@exp_sysconfdir@/server.key" #SSLVerifyClient require #SSLVerifyDepth 10 +# TLS-SRP mutual authentication: +# Enable TLS-SRP and set the path to the OpenSSL SRP verifier +# file (containing login information for SRP user accounts). See +# the mod_ssl FAQ for instructions on creating this file. +#SSLSRPVerifierFile "@exp_sysconfdir@/passwd.srpv" + # Access Control: # With SSLRequire you can do per-directory access control based # on arbitrary complex boolean expressions containing server diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml index b86528d..1d143b6 100644 --- a/docs/manual/mod/mod_ssl.xml +++ b/docs/manual/mod/mod_ssl.xml @@ -97,6 +97,8 @@ compatibility variables.

SSL_SERVER_A_SIG string Algorithm used for the signature of server's certificate SSL_SERVER_A_KEY string Algorithm used for the public key of server's certificate SSL_SERVER_CERT string PEM-encoded server certificate +SSL_SRP_USER string SRP username +SSL_SRP_USERINFO string SRP user info

x509 specifies a component of an X.509 DN; one of @@ -662,6 +664,7 @@ specify the preference and order for the ciphers (see Table kDHr Diffie-Hellman key exchange with RSA key kDHd Diffie-Hellman key exchange with DSA key kEDH Ephemeral (temp.key) Diffie-Hellman key exchange (no cert) +kSRP Secure Remote Password (SRP) key exchange Authentication Algorithm: aNULL No authentication aRSA RSA authentication @@ -692,6 +695,7 @@ specify the preference and order for the ciphers (see Table DH all ciphers using Diffie-Hellman key exchange EDH all ciphers using Ephemeral Diffie-Hellman key exchange ADH all ciphers using Anonymous Diffie-Hellman key exchange +SRP all ciphers using Secure Remote Password (SRP) key exchange DSS all ciphers using DSS authentication NULL all ciphers using no encryption @@ -1112,6 +1116,44 @@ SSLVerifyDepth 10 +SSLSRPVerifierFile +Path to SRP verifier file +SSLSRPVerifierFile file-path +server config +virtual host + + +

+This directive enables TLS-SRP and sets the path to the OpenSSL SRP (Secure +Remote Password) verifier file containing TLS-SRP usernames, verifiers, salts, +and group parameters.

+Example +SSLSRPVerifierFile "/path/to/file.srpv" + + + + + +SSLSRPUnknownUserSeed +SRP unknown user seed +SSLSRPUnknownUserSeed secret-string +server config +virtual host + + +

+This directive sets the seed used to fake SRP user parameters for unknown +users, to avoid leaking whether a given user exists. Specify a secret +string. If this directive is not used, then Apache will return the +UNKNOWN_PSK_IDENTITY alert to clients who specify an unknown username. +

+Example +SSLSRPUnknownUserSeed "secret" + +
+
+ + SSLOptions Configure various SSL engine run-time options SSLOptions [+|-]option ... diff --git a/docs/manual/ssl/ssl_faq.xml b/docs/manual/ssl/ssl_faq.xml index a94da97..454d325 100644 --- a/docs/manual/ssl/ssl_faq.xml +++ b/docs/manual/ssl/ssl_faq.xml @@ -702,6 +702,28 @@ HTTPS to an Apache+mod_ssl server with Microsoft Internet Explorer (MSIE)? +
How do I enable TLS-SRP? +

TLS-SRP (Secure Remote Password key exchange for TLS, specified in RFC 5054) + can supplement or replace certificates in authenticating an SSL connection. + To use TLS-SRP, set the + SSLSRPVerifierFile directive to + point to an OpenSSL SRP verifier file. To create the verifier file, use the + openssl tool: + + openssl srp -srpvfile passwd.srpv -add username + + After creating this file, specify it in the SSL server configuration: + + SSLSRPVerifierFile /path/to/passwd.srpv + + To force clients to use non-certificate TLS-SRP cipher suites, use the + following directive: + + SSLCipherSuite "!DSS:!aRSA:SRP" + +

+
+ diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index d908e61..72af46a 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -133,6 +133,15 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_SRV(StrictSNIVHostCheck, FLAG, "Strict SNI virtual host checking") +#ifndef OPENSSL_NO_SRP + SSL_CMD_SRV(SRPVerifierFile, TAKE1, + "SRP verifier file " + "('/path/to/file' - created by srptool)") + SSL_CMD_SRV(SRPUnknownUserSeed, TAKE1, + "SRP seed for unknown users (to avoid leaking a user's existence) " + "('some secret text')") +#endif + /* * Proxy configuration for remote SSL connections */ diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 6042bac..7f2bcb3 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -145,6 +145,12 @@ static void modssl_ctx_init(modssl_ctx_t *mctx) mctx->stapling_responder_timeout = UNSET; mctx->stapling_force_url = NULL; #endif + +#ifndef OPENSSL_NO_SRP + mctx->srp_vfile = NULL; + mctx->srp_unknown_user_seed=NULL; + mctx->srp_vbase = NULL; +#endif } static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, @@ -260,6 +266,11 @@ static void modssl_ctx_cfg_merge(modssl_ctx_t *base, cfgMergeInt(stapling_responder_timeout); cfgMerge(stapling_force_url, NULL); #endif + +#ifndef OPENSSL_NO_SRP + cfgMergeString(srp_vfile); + cfgMergeString(srp_unknown_user_seed); +#endif } static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base, @@ -1663,6 +1674,33 @@ const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *cmd, void *dcfg, #endif /* HAVE_OCSP_STAPLING */ +#ifndef OPENSSL_NO_SRP + +const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + sc->server->srp_vfile = arg; + + return NULL; +} + +const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + sc->server->srp_unknown_user_seed = arg; + return NULL; +} + +#endif /* OPENSSL_NO_SRP */ + void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) { if (!ap_exists_config_define("DUMP_CERTS")) { diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index 67f72ea..229e85e 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -467,6 +467,37 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, modssl_init_stapling(s, p, ptemp, mctx); } #endif + +#ifndef OPENSSL_NO_SRP + /* + * TLS-SRP support + */ + if (mctx->srp_vfile != NULL) { + int rv; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Using SRP verifier file [%s]", mctx->srp_vfile); + + if (!(mctx->srp_vbase = SRP_VBASE_new(mctx->srp_unknown_user_seed))) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, + "Unable to initialize SRP verifier structure " + "[%s seed]", + mctx->srp_unknown_user_seed ? "with" : "without"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + ssl_die(); + } + + rv = SRP_VBASE_init(mctx->srp_vbase, mctx->srp_vfile); + if (rv != SRP_NO_ERROR) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, + "Unable to load SRP verifier file [error %d]", rv); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + ssl_die(); + } + + SSL_CTX_set_srp_username_callback(mctx->ssl_ctx, ssl_callback_SRPServerParams); + SSL_CTX_set_srp_cb_arg(mctx->ssl_ctx, mctx); + } +#endif } #endif @@ -1409,6 +1440,13 @@ static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx) MODSSL_CFG_ITEM_FREE(X509_STORE_free, mctx->crl); MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx); + +#ifndef OPENSSL_NO_SRP + if (mctx->srp_vbase != NULL) { + SRP_VBASE_free(mctx->srp_vbase); + mctx->srp_vbase = NULL; + } +#endif } static void ssl_init_ctx_cleanup_proxy(modssl_ctx_t *mctx) diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index 3bb5846..52fccc1 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -349,6 +349,19 @@ int ssl_hook_Access(request_rec *r) return DECLINED; } +#ifndef OPENSSL_NO_SRP + /* + * Support for per-directory reconfigured SSL connection parameters + * + * We do not force any renegotiation if the user is already authenticated + * via SRP. + * + */ + if (SSL_get_srp_username(ssl)) { + return DECLINED; + } +#endif + /* * Support for per-directory reconfigured SSL connection parameters. * @@ -1103,6 +1116,10 @@ static const char *ssl_hook_Fixup_vars[] = { "SSL_SERVER_A_SIG", "SSL_SESSION_ID", "SSL_SESSION_RESUMED", +#ifndef OPENSSL_NO_SRP + "SSL_SRP_USER", + "SSL_SRP_USERINFO", +#endif NULL }; @@ -2255,4 +2272,30 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s) return 0; } -#endif + +#endif /* OPENSSL_NO_TLSEXT */ + +#ifndef OPENSSL_NO_SRP + +int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) +{ + modssl_ctx_t *mctx = (modssl_ctx_t *)arg; + char *username = SSL_get_srp_username(ssl); + SRP_user_pwd *u; + + if ((u = SRP_VBASE_get_by_user(mctx->srp_vbase, username)) == NULL) { + *ad = SSL_AD_UNKNOWN_PSK_IDENTITY; + return SSL3_AL_FATAL; + } + + if (SSL_set_srp_server_param(ssl, u->N, u->g, u->s, u->v, u->info) < 0) { + *ad = SSL_AD_INTERNAL_ERROR; + return SSL3_AL_FATAL; + } + + /* reset all other options */ + SSL_set_verify(ssl, SSL_VERIFY_NONE, ssl_callback_SSLVerify); + return SSL_ERROR_NONE; +} + +#endif /* OPENSSL_NO_SRP */ diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 99d3832..b0ce881 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -386,7 +386,19 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r, flag = SSL_get_secure_renegotiation_support(ssl); #endif result = apr_pstrdup(p, flag ? "true" : "false"); - } + } +#ifndef OPENSSL_NO_SRP + else if (ssl != NULL && strcEQ(var, "SRP_USER")) { + if ((result = SSL_get_srp_username(ssl)) != NULL) { + result = apr_pstrdup(p, result); + } + } + else if (ssl != NULL && strcEQ(var, "SRP_USERINFO")) { + if ((result = SSL_get_srp_userinfo(ssl)) != NULL) { + result = apr_pstrdup(p, result); + } + } +#endif return result; } diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 5dcc65e..aa8a935 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -523,6 +523,12 @@ typedef struct { const char *stapling_force_url; #endif +#ifndef OPENSSL_NO_SRP + char *srp_vfile; + char *srp_unknown_user_seed; + SRP_VBASE *srp_vbase; +#endif + modssl_auth_ctx_t auth; BOOL ocsp_enabled; /* true if OCSP verification enabled */ @@ -641,6 +647,11 @@ const char *ssl_cmd_SSLOCSPResponseMaxAge(cmd_parms *cmd, void *dcfg, const char const char *ssl_cmd_SSLOCSPResponderTimeout(cmd_parms *cmd, void *dcfg, const char *arg); const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, int flag); +#ifndef OPENSSL_NO_SRP +const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg); +const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg); +#endif + const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag); /** module initialization */ @@ -682,6 +693,9 @@ void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE, int, int); #ifndef OPENSSL_NO_TLSEXT int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *); #endif +#ifndef OPENSSL_NO_SRP +int ssl_callback_SRPServerParams(SSL *, int *, void *); +#endif /** Session Cache Support */ void ssl_scache_init(server_rec *, apr_pool_t *); diff --git a/modules/ssl/ssl_toolkit_compat.h b/modules/ssl/ssl_toolkit_compat.h index a31258a..51a0c88 100644 --- a/modules/ssl/ssl_toolkit_compat.h +++ b/modules/ssl/ssl_toolkit_compat.h @@ -57,6 +57,14 @@ #define OPENSSL_NO_EC #endif +/* SRP support came in OpenSSL 1.0.1 */ +#if (OPENSSL_VERSION_NUMBER < 0x10001000) +#define OPENSSL_NO_SRP +#endif +#ifndef OPENSSL_NO_SRP +#include +#endif + /** Avoid tripping over an engine build installed globally and detected * when the user points at an explicit non-engine flavor of OpenSSL */