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
*/