From: Stefan Fritsch Date: Fri, 8 Jun 2012 09:38:44 +0000 (+0000) Subject: Add support for TLS-SRP (Secure Remote Password key exchange X-Git-Tag: 2.5.0-alpha~6748 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ccf77a856ab14a85c281ee722a8b697f1f3c4694;p=thirdparty%2Fapache%2Fhttpd.git Add support for TLS-SRP (Secure Remote Password key exchange for TLS, RFC 5054). PR: 51075 Submitted by: Quinn Slack , Christophe Renou, Peter Sylvester git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1347980 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 9a737b6e877..a0dde1a9f02 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) mod_ssl: Add support for TLS-SRP (Secure Remote Password key exchange + for TLS, RFC 5054). PR 51075. [Quinn Slack , + Christophe Renou, Peter Sylvester] + *) htdbm, htpasswd: Don't crash if crypt() fails (e.g. with FIPS enabled). [Paul Wouters , Joe Orton] diff --git a/docs/conf/extra/httpd-ssl.conf.in b/docs/conf/extra/httpd-ssl.conf.in index 1e822a31a18..898a99628c3 100644 --- a/docs/conf/extra/httpd-ssl.conf.in +++ b/docs/conf/extra/httpd-ssl.conf.in @@ -157,6 +157,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/log-message-tags/next-number b/docs/log-message-tags/next-number index 2c9fd9df4db..c6b57b0fe08 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -2308 +2311 diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml index f1e9713c5bb..0b8403a7d1d 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 @@ -670,6 +672,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 @@ -700,6 +703,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 @@ -1180,6 +1184,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 diff --git a/docs/manual/ssl/ssl_faq.xml b/docs/manual/ssl/ssl_faq.xml index a7e36f88334..cf5dd127ef0 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 47b4b195652..6ea367c02db 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 12c6958e3f3..c642be90f7a 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, @@ -272,6 +278,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, @@ -1778,6 +1789,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 3d5dec1ac03..3a747471bed 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 rv; + 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(); + } + + rv = SRP_VBASE_init(mctx->srp_vbase, mctx->srp_vfile); + if (rv != SRP_NO_ERROR) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02310) + "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 @@ -1694,6 +1726,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 bc9e26b92f6..ef21794e184 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -330,6 +330,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. * @@ -1089,6 +1102,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 }; @@ -2073,7 +2090,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 /* @@ -2143,7 +2160,7 @@ 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 */ #ifdef HAVE_TLS_NPN /* @@ -2226,4 +2243,30 @@ int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data_out, *size_out = size; return SSL_TLSEXT_ERR_OK; } -#endif + +#endif /* HAVE_TLS_NPN */ + +#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 febc176efab..8af1c2610a2 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 53747a8a201..e04c933da9c 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -185,6 +185,13 @@ #define HAVE_TLSV1_X #endif +/* SRP support came in OpenSSL 1.0.1 */ +#if (OPENSSL_VERSION_NUMBER < 0x10001000) +#define OPENSSL_NO_SRP +#else +#include +#endif + /* mod_ssl headers */ #include "ssl_util_ssl.h" @@ -647,6 +654,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 */ @@ -773,6 +786,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 */ @@ -850,6 +868,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 *);