From: Rainer Jung Date: Tue, 11 Dec 2012 09:55:03 +0000 (+0000) Subject: Add support for TLS-SRP (Secure Remote Password key exchange X-Git-Tag: 2.4.4~341 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ad61aab1d7bfafeabb699ebfded32403c47066c0;p=apache Add support for TLS-SRP (Secure Remote Password key exchange for TLS, RFC 5054). Including some improvements as suggested by Kaspar PR: 51075 Submitted by: Quinn Slack , Christophe Renou, Peter Sylvester Backported by: sf Reviewed by: sf, minfrin, rjung Backports of r1347980 and r1348653 form trunk. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1420057 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index a12c2654ca..39e017eb6c 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,10 @@ Changes with Apache 2.4.4 + *) mod_ssl: Add support for TLS-SRP (Secure Remote Password key exchange + for TLS, RFC 5054). PR 51075. [Quinn Slack , + Christophe Renou, Peter Sylvester] + *) mod_rewrite: Stop mergeing RewriteBase down to subdirectories unless new option 'RewriteOptions MergeBase' is configured. PR 53963. [Eric Covener] diff --git a/STATUS b/STATUS index c4b72aca1f..5a32007b62 100644 --- a/STATUS +++ b/STATUS @@ -91,16 +91,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_ssl: Add support for TLS-SRP (Secure Remote Password key exchange - for TLS, RFC 5054). - trunk patch: http://svn.apache.org/viewvc?view=revision&revision=1347980 and - http://svn.apache.org/viewvc?view=revision&revision=1348653 - 2.4.x patch: http://people.apache.org/~sf/ssl-TLS-SRP-2_4-v2.patch - +1: sf, minfrin, rjung - rjung: Please add docs compatibility note for 2.4.4. - There is another docs block missing from the backport about - how to create the verifier file using the openssl commandline tool. - * mod_proxy: Make balancers server-specific, as they should have been. Inheritance causes too many behind-the-scene interactions to be reliable in a dynamic environ. diff --git a/docs/conf/extra/httpd-ssl.conf.in b/docs/conf/extra/httpd-ssl.conf.in index 673d1aa816..d65889cfc0 100644 --- a/docs/conf/extra/httpd-ssl.conf.in +++ b/docs/conf/extra/httpd-ssl.conf.in @@ -157,6 +157,14 @@ 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). +# Requires OpenSSL 1.0.1 or newer. See the mod_ssl FAQ for +# detailed instructions on creating this file. Example: +# "openssl srp -srpvfile @exp_sysconfdir@/passwd.srpv -add username" +#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 00a09596b2..7c231fc6d5 100644 --- a/docs/manual/mod/mod_ssl.xml +++ b/docs/manual/mod/mod_ssl.xml @@ -96,6 +96,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 @@ -671,6 +673,7 @@ openssl version. Newer openssl versions may include additional ciphers.

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 @@ -706,6 +709,7 @@ openssl version. Newer openssl versions may include additional ciphers.

ECDH Elliptic Curve Diffie-Hellman key exchange ADH all ciphers using Anonymous Diffie-Hellman key exchange AECDH all ciphers using Anonymous Elliptic Curve Diffie-Hellman key exchange +SRP all ciphers using Secure Remote Password (SRP) key exchange DSS all ciphers using DSS authentication ECDSA all ciphers using ECDSA authentication aNULL all ciphers using no authentication @@ -1179,6 +1183,57 @@ SSLVerifyDepth 10 + +SSLSRPVerifierFile +Path to SRP verifier file +SSLSRPVerifierFile file-path +server config +virtual host +Available in httpd 2.4.4 and later, if using OpenSSL 1.0.1 or +later + + +

+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" + +

+The verifier file can be created with the openssl command line +utility:

+Creating the SRP verifier file +openssl srp -srpvfile passwd.srpv -userinfo "some info" -add username + +

The value given with the optional -userinfo parameter is +avalable in the SSL_SRP_USERINFO request environment variable.

+ +
+
+ + +SSLSRPUnknownUserSeed +SRP unknown user seed +SSLSRPUnknownUserSeed secret-string +server config +virtual host +Available in httpd 2.4.4 and later, if using OpenSSL 1.0.1 or +later + + +

+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 diff --git a/docs/manual/ssl/ssl_faq.xml b/docs/manual/ssl/ssl_faq.xml index d1d0c105e4..22aa7b32f0 100644 --- a/docs/manual/ssl/ssl_faq.xml +++ b/docs/manual/ssl/ssl_faq.xml @@ -719,6 +719,27 @@ SetEnvIf User-Agent "MSIE [2-5]" \ or otherwise.

+
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 0872da8a82..12d473bafb 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -148,6 +148,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 15993f16cc..658ef6b379 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -149,6 +149,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, @@ -274,6 +280,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, @@ -1782,6 +1793,32 @@ 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; + /* SRP_VBASE_init takes char*, not const char* */ + sc->server->srp_vfile = apr_pstrdup(cmd->pool, arg); + return NULL; +} + +const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + /* SRP_VBASE_new takes char*, not const char* */ + sc->server->srp_unknown_user_seed = apr_pstrdup(cmd->pool, arg); + return NULL; +} + +#endif /* OPENSSL_NO_SRP */ + void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) { apr_file_t *out = NULL; diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index aa24652f22..be891d6277 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -526,6 +526,38 @@ 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 err; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02308) + "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, APLOGNO(02309) + "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(s); + } + + err = SRP_VBASE_init(mctx->srp_vbase, mctx->srp_vfile); + if (err != SRP_NO_ERROR) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02310) + "Unable to load SRP verifier file [error %d]", err); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + ssl_die(s); + } + + SSL_CTX_set_srp_username_callback(mctx->ssl_ctx, + ssl_callback_SRPServerParams); + SSL_CTX_set_srp_cb_arg(mctx->ssl_ctx, mctx); + } +#endif } #endif @@ -1687,6 +1719,13 @@ void ssl_init_Child(apr_pool_t *p, server_rec *s) static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx) { 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 e514a74bdf..a088df166f 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -329,6 +329,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. * @@ -1088,6 +1101,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 }; @@ -2072,7 +2089,7 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s) return 0; } -#endif +#endif /* OPENSSL_NO_TLSEXT */ #ifdef HAVE_TLS_SESSION_TICKETS /* @@ -2142,4 +2159,30 @@ int ssl_callback_SessionTicket(SSL *ssl, /* OpenSSL is not expected to call us with modes other than 1 or 0 */ return -1; } -#endif +#endif /* HAVE_TLS_SESSION_TICKETS */ + +#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 (username == NULL + || (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 223ac9a406..536e6b1f73 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -395,6 +395,18 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r, #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 f2fb7d5240..a9269680bc 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -185,6 +185,15 @@ #define OPENSSL_NO_COMP #endif +/* SRP support came in OpenSSL 1.0.1 */ +#ifndef OPENSSL_NO_SRP +#ifdef SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB +#include +#else +#define OPENSSL_NO_SRP +#endif +#endif + /* mod_ssl headers */ #include "ssl_util_ssl.h" @@ -647,6 +656,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 */ @@ -775,6 +790,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 */ @@ -851,6 +871,9 @@ void modssl_init_stapling(server_rec *, apr_pool_t *, apr_pool_t *, mods void ssl_stapling_ex_init(void); int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x); #endif +#ifndef OPENSSL_NO_SRP +int ssl_callback_SRPServerParams(SSL *, int *, void *); +#endif /** I/O */ void ssl_io_filter_init(conn_rec *, request_rec *r, SSL *);