]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Add support for TLS-SRP (Secure Remote Password key exchange
authorStefan Fritsch <sf@apache.org>
Fri, 8 Jun 2012 09:38:44 +0000 (09:38 +0000)
committerStefan Fritsch <sf@apache.org>
Fri, 8 Jun 2012 09:38:44 +0000 (09:38 +0000)
for TLS, RFC 5054).

PR: 51075
Submitted by: Quinn Slack <sqs cs stanford edu>, Christophe Renou,
              Peter Sylvester

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1347980 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/conf/extra/httpd-ssl.conf.in
docs/log-message-tags/next-number
docs/manual/mod/mod_ssl.xml
docs/manual/ssl/ssl_faq.xml
modules/ssl/mod_ssl.c
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_engine_vars.c
modules/ssl/ssl_private.h

diff --git a/CHANGES b/CHANGES
index 9a737b6e87793c7ff03b6424293b6198adfd2b5a..a0dde1a9f02c484289794c8ecd465515c02b23ff 100644 (file)
--- 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 <sqs cs stanford edu>,
+     Christophe Renou, Peter Sylvester]
+
   *) htdbm, htpasswd: Don't crash if crypt() fails (e.g. with FIPS enabled). 
      [Paul Wouters <pwouters redhat.com>, Joe Orton]
 
index 1e822a31a189d0bffda939940c412a2f2c1aaabc..898a99628c3336e446f13ed9523cf21a4d780197 100644 (file)
@@ -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
index 2c9fd9df4db07c4927438409cb7c878fb356cfca..c6b57b0fe089457af33f149cd4ba8a4d71645ce7 100644 (file)
@@ -1 +1 @@
-2308
+2311
index f1e9713c5bb656b61b74f5e59be3390c1b8fb67c..0b8403a7d1da7da31febed32925f6d8c0c6f30db 100644 (file)
@@ -96,6 +96,8 @@ compatibility variables.</p>
 <tr><td><code>SSL_SERVER_A_SIG</code></td>              <td>string</td>    <td>Algorithm used for the signature of server's certificate</td></tr>
 <tr><td><code>SSL_SERVER_A_KEY</code></td>              <td>string</td>    <td>Algorithm used for the public key of server's certificate</td></tr>
 <tr><td><code>SSL_SERVER_CERT</code></td>               <td>string</td>    <td>PEM-encoded server certificate</td></tr>
+<tr><td><code>SSL_SRP_USER</code></td>                  <td>string</td>    <td>SRP username</td></tr>
+<tr><td><code>SSL_SRP_USERINFO</code></td>              <td>string</td>    <td>SRP user info</td></tr>
 </table>
 
 <p><em>x509</em> specifies a component of an X.509 DN; one of
@@ -670,6 +672,7 @@ specify the preference and order for the ciphers (see <a href="#table1">Table
 <tr><td><code>kDHr</code></td>   <td>Diffie-Hellman key exchange with RSA key</td></tr>
 <tr><td><code>kDHd</code></td>   <td>Diffie-Hellman key exchange with DSA key</td></tr>
 <tr><td><code>kEDH</code></td>   <td>Ephemeral (temp.key) Diffie-Hellman key exchange (no cert)</td>   </tr>
+<tr><td><code>kSRP</code></td>   <td>Secure Remote Password (SRP) key exchange</td></tr>
 <tr><td colspan="2"><em>Authentication Algorithm:</em></td></tr>
 <tr><td><code>aNULL</code></td>  <td>No authentication</td></tr>
 <tr><td><code>aRSA</code></td>   <td>RSA authentication</td></tr>
@@ -700,6 +703,7 @@ specify the preference and order for the ciphers (see <a href="#table1">Table
 <tr><td><code>DH</code></td>     <td>all ciphers using Diffie-Hellman key exchange</td> </tr>
 <tr><td><code>EDH</code></td>    <td>all ciphers using Ephemeral Diffie-Hellman key exchange</td> </tr>
 <tr><td><code>ADH</code></td>    <td>all ciphers using Anonymous Diffie-Hellman key exchange</td> </tr>
+<tr><td><code>SRP</code></td>    <td>all ciphers using Secure Remote Password (SRP) key exchange</td> </tr>
 <tr><td><code>DSS</code></td>    <td>all ciphers using DSS authentication</td> </tr>
 <tr><td><code>NULL</code></td>   <td>all ciphers using no encryption</td> </tr>
 </table>
@@ -1180,6 +1184,44 @@ SSLVerifyDepth 10
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLSRPVerifierFile</name>
+<description>Path to SRP verifier file</description>
+<syntax>SSLSRPVerifierFile <em>file-path</em></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+
+<usage>
+<p>
+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.</p>
+<example><title>Example</title>
+SSLSRPVerifierFile "/path/to/file.srpv"
+</example>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>SSLSRPUnknownUserSeed</name>
+<description>SRP unknown user seed</description>
+<syntax>SSLSRPUnknownUserSeed <em>secret-string</em></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+
+<usage>
+<p>
+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.
+</p>
+<example><title>Example</title>
+SSLSRPUnknownUserSeed "secret"
+</example>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLOptions</name>
 <description>Configure various SSL engine run-time options</description>
index a7e36f88334f5e1ce7333d34737a3c870a95fcca..cf5dd127ef07fbdaf173a0b4ecaa950234bc9fa0 100644 (file)
@@ -719,6 +719,27 @@ SetEnvIf User-Agent "MSIE [2-5]" \
     or otherwise.</p>
 </section>
 
+<section id="srp"><title>How do I enable TLS-SRP?</title>
+    <p>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
+    <directive module="mod_ssl">SSLSRPVerifierFile</directive> directive to
+    point to an OpenSSL SRP verifier file. To create the verifier file, use the
+    <code>openssl</code> tool:</p>
+    <example>
+    openssl srp -srpvfile passwd.srpv -add username
+    </example>
+    <p>After creating this file, specify it in the SSL server configuration:</p>
+    <example>
+    SSLSRPVerifierFile /path/to/passwd.srpv
+    </example>
+    <p>To force clients to use non-certificate TLS-SRP cipher suites, use the
+    following directive:</p>
+    <example>
+    SSLCipherSuite "!DSS:!aRSA:SRP"
+    </example>
+</section>
+
 </section>
 <!-- /aboutssl -->
 
index 47b4b19565279880532e75594d115263ac226fe4..6ea367c02dbc29aec93c1c9998ba534460146f35 100644 (file)
@@ -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
      */
index 12c6958e3f3e5fb4bec2e2d4e8e20e14e135641c..c642be90f7ab02b718f0e57efbc206f2f63aabdc 100644 (file)
@@ -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;
index 3d5dec1ac03724627f2ab6f7b213b2932e20b171..3a747471bedc7b266e7df6b11834fbe801c06ad7 100644 (file)
@@ -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)
index bc9e26b92f6e9d510a85d3e32cf97533512013e4..ef21794e18417b757f21dbc8ae3f681bb49ca923 100644 (file)
@@ -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 */
index febc176efaba8dae043511228acd813dc956e0bb..8af1c2610a235a34aea3e031e837985f41664ecf 100644 (file)
@@ -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;
 }
index 53747a8a201d00dbcd0844eddf840380a7c9753f..e04c933da9caa05c2729365c1376740481e5b657 100644 (file)
 #define HAVE_TLSV1_X
 #endif
 
+/* SRP support came in OpenSSL 1.0.1 */
+#if (OPENSSL_VERSION_NUMBER < 0x10001000)
+#define OPENSSL_NO_SRP
+#else
+#include <openssl/srp.h>
+#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 *);