File openssl-CVE-2016-0798-101.patch of Package openssl
commit 59a908f1e8380412a81392c468b83bf6071beb2a
Author: Emilia Kasper <emilia@openssl.org>
Date: Wed Feb 24 12:59:59 2016 +0100
CVE-2016-0798: avoid memory leak in SRP
The SRP user database lookup method SRP_VBASE_get_by_user had confusing
memory management semantics; the returned pointer was sometimes newly
allocated, and sometimes owned by the callee. The calling code has no
way of distinguishing these two cases.
Specifically, SRP servers that configure a secret seed to hide valid
login information are vulnerable to a memory leak: an attacker
connecting with an invalid username can cause a memory leak of around
300 bytes per connection.
Servers that do not configure SRP, or configure SRP but do not configure
a seed are not vulnerable.
In Apache, the seed directive is known as SSLSRPUnknownUserSeed.
To mitigate the memory leak, the seed handling in SRP_VBASE_get_by_user
is now disabled even if the user has configured a seed.
Applications are advised to migrate to SRP_VBASE_get1_by_user. However,
note that OpenSSL makes no strong guarantees about the
indistinguishability of valid and invalid logins. In particular,
computations are currently not carried out in constant time.
Reviewed-by: Rich Salz <rsalz@openssl.org>
Index: openssl-1.0.1i/apps/s_server.c
===================================================================
--- openssl-1.0.1i.orig/apps/s_server.c 2016-02-26 09:45:21.967034547 +0100
+++ openssl-1.0.1i/apps/s_server.c 2016-02-26 09:55:55.582705403 +0100
@@ -413,6 +413,8 @@
static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg)
{
srpsrvparm *p = (srpsrvparm *)arg;
+ int ret = SSL3_AL_FATAL;
+
if (p->login == NULL && p->user == NULL )
{
p->login = SSL_get_srp_username(s);
@@ -423,19 +425,23 @@
if (p->user == NULL)
{
BIO_printf(bio_err, "User %s doesn't exist\n", p->login);
- return SSL3_AL_FATAL;
+ goto err;
}
+
if (SSL_set_srp_server_param(s, p->user->N, p->user->g, p->user->s, p->user->v,
p->user->info) < 0)
{
*ad = SSL_AD_INTERNAL_ERROR;
- return SSL3_AL_FATAL;
+ goto err;
}
BIO_printf(bio_err, "SRP parameters set: username = \"%s\" info=\"%s\" \n", p->login,p->user->info);
- /* need to check whether there are memory leaks */
+ ret = SSL_ERROR_NONE;
+
+err:
+ SRP_user_pwd_free(p->user);
p->user = NULL;
p->login = NULL;
- return SSL_ERROR_NONE;
+ return ret;
}
#endif
@@ -2300,7 +2306,8 @@
while (SSL_get_error(con,k) == SSL_ERROR_WANT_X509_LOOKUP)
{
BIO_printf(bio_s_out,"LOOKUP renego during write\n");
- srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login);
+ SRP_user_pwd_free(srp_callback_parm.user);
+ srp_callback_parm.user = SRP_VBASE_get1_by_user(srp_callback_parm.vb, srp_callback_parm.login);
if (srp_callback_parm.user)
BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info);
else
@@ -2359,7 +2366,8 @@
while (SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP)
{
BIO_printf(bio_s_out,"LOOKUP renego during read\n");
- srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login);
+ SRP_user_pwd_free(srp_callback_parm.user);
+ srp_callback_parm.user = SRP_VBASE_get1_by_user(srp_callback_parm.vb, srp_callback_parm.login);
if (srp_callback_parm.user)
BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info);
else
@@ -2448,7 +2456,8 @@
while (i <= 0 && SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP)
{
BIO_printf(bio_s_out,"LOOKUP during accept %s\n",srp_callback_parm.login);
- srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login);
+ SRP_user_pwd_free(srp_callback_parm.user);
+ srp_callback_parm.user = SRP_VBASE_get1_by_user(srp_callback_parm.vb, srp_callback_parm.login);
if (srp_callback_parm.user)
BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info);
else
@@ -2690,7 +2699,8 @@
while (i <= 0 && SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP)
{
BIO_printf(bio_s_out,"LOOKUP during accept %s\n",srp_callback_parm.login);
- srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login);
+ SRP_user_pwd_free(srp_callback_parm.user);
+ srp_callback_parm.user = SRP_VBASE_get1_by_user(srp_callback_parm.vb, srp_callback_parm.login);
if (srp_callback_parm.user)
BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info);
else
Index: openssl-1.0.1i/crypto/srp/srp.h
===================================================================
--- openssl-1.0.1i.orig/crypto/srp/srp.h 2016-02-26 09:45:21.967034547 +0100
+++ openssl-1.0.1i/crypto/srp/srp.h 2016-02-26 09:59:30.355828026 +0100
@@ -83,16 +83,21 @@
typedef struct SRP_user_pwd_st
{
+ /* Owned by us. */
char *id;
BIGNUM *s;
BIGNUM *v;
+ /* Not owned by us. */
const BIGNUM *g;
const BIGNUM *N;
+ /* Owned by us. */
char *info;
} SRP_user_pwd;
DECLARE_STACK_OF(SRP_user_pwd)
+void SRP_user_pwd_free(SRP_user_pwd *user_pwd);
+
typedef struct SRP_VBASE_st
{
STACK_OF(SRP_user_pwd) *users_pwd;
@@ -117,7 +122,12 @@
SRP_VBASE *SRP_VBASE_new(char *seed_key);
int SRP_VBASE_free(SRP_VBASE *vb);
int SRP_VBASE_init(SRP_VBASE *vb, char * verifier_file);
+
+/* This method ignores the configured seed and fails for an unknown user. */
SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username);
+/* NOTE: unlike in SRP_VBASE_get_by_user, caller owns the returned pointer.*/
+SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username);
+
char *SRP_create_verifier(const char *user, const char *pass, char **salt,
char **verifier, const char *N, const char *g);
int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, BIGNUM **verifier, BIGNUM *N, BIGNUM *g);
Index: openssl-1.0.1i/crypto/srp/srp_vfy.c
===================================================================
--- openssl-1.0.1i.orig/crypto/srp/srp_vfy.c 2016-02-26 09:45:14.998989106 +0100
+++ openssl-1.0.1i/crypto/srp/srp_vfy.c 2016-02-26 10:01:19.740387786 +0100
@@ -182,7 +182,7 @@
return olddst;
}
-static void SRP_user_pwd_free(SRP_user_pwd *user_pwd)
+void SRP_user_pwd_free(SRP_user_pwd *user_pwd)
{
if (user_pwd == NULL)
return;
@@ -244,6 +244,24 @@
return (vinfo->s != NULL && vinfo->v != NULL) ;
}
+static SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src)
+{
+ SRP_user_pwd *ret;
+
+ if (src == NULL)
+ return NULL;
+ if ((ret = SRP_user_pwd_new()) == NULL)
+ return NULL;
+
+ SRP_user_pwd_set_gN(ret, src->g, src->N);
+ if (!SRP_user_pwd_set_ids(ret, src->id, src->info)
+ || !SRP_user_pwd_set_sv_BN(ret, BN_dup(src->s), BN_dup(src->v))) {
+ SRP_user_pwd_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
SRP_VBASE *SRP_VBASE_new(char *seed_key)
{
SRP_VBASE *vb = (SRP_VBASE *) OPENSSL_malloc(sizeof(SRP_VBASE));
@@ -474,23 +492,51 @@
}
-
-SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username)
+static SRP_user_pwd *find_user(SRP_VBASE *vb, char *username)
{
int i;
SRP_user_pwd *user;
- unsigned char digv[SHA_DIGEST_LENGTH];
- unsigned char digs[SHA_DIGEST_LENGTH];
- EVP_MD_CTX ctxt;
if (vb == NULL)
return NULL;
+
for(i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++)
{
user = sk_SRP_user_pwd_value(vb->users_pwd, i);
if (strcmp(user->id,username)==0)
return user;
}
+
+ return NULL;
+}
+
+/*
+ * This method ignores the configured seed and fails for an unknown user.
+ * Ownership of the returned pointer is not released to the caller.
+ * In other words, caller must not free the result.
+ */
+SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username)
+{
+ return find_user(vb, username);
+}
+
+/*
+ * Ownership of the returned pointer is released to the caller.
+ * In other words, caller must free the result once done.
+ */
+SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username)
+{
+ SRP_user_pwd *user;
+ unsigned char digv[SHA_DIGEST_LENGTH];
+ unsigned char digs[SHA_DIGEST_LENGTH];
+ EVP_MD_CTX ctxt;
+
+ if (vb == NULL)
+ return NULL;
+
+ if ((user = find_user(vb, username)) != NULL)
+ return srp_user_pwd_dup(user);
+
if ((vb->seed_key == NULL) ||
(vb->default_g == NULL) ||
(vb->default_N == NULL))
Index: openssl-1.0.1i/util/libeay.num
===================================================================
--- openssl-1.0.1i.orig/util/libeay.num 2016-02-26 09:45:21.967034547 +0100
+++ openssl-1.0.1i/util/libeay.num 2016-02-26 09:58:37.423554553 +0100
@@ -1806,6 +1806,8 @@
ASN1_UTCTIME_get 2350 NOEXIST::FUNCTION:
X509_REQ_digest 2362 EXIST::FUNCTION:EVP
X509_CRL_digest 2391 EXIST::FUNCTION:EVP
+SRP_VBASE_get1_by_user 2393 EXIST::FUNCTION:SRP
+SRP_user_pwd_free 2394 EXIST::FUNCTION:SRP
d2i_ASN1_SET_OF_PKCS7 2397 NOEXIST::FUNCTION:
EVP_CIPHER_CTX_set_key_length 2399 EXIST::FUNCTION:
EVP_CIPHER_CTX_ctrl 2400 EXIST::FUNCTION: