|
|
dc8c34 |
From ea31415690291ab5be6c70a20738e5b1291b92dd Mon Sep 17 00:00:00 2001
|
|
|
dc8c34 |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
dc8c34 |
Date: Mon, 26 Feb 2018 18:09:32 -0500
|
|
|
dc8c34 |
Subject: [PATCH] Bug 1525628 - CVE-2017-15135: Authentication bypass due to
|
|
|
dc8c34 |
lack of size check in slapi_ct_memcmp function in ch_malloc.c
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Description: Backport this fix top 1.2.11(RHEL 6.9)
|
|
|
dc8c34 |
---
|
|
|
dc8c34 |
ldap/servers/plugins/pwdstorage/clear_pwd.c | 4 +-
|
|
|
dc8c34 |
ldap/servers/plugins/pwdstorage/crypt_pwd.c | 2 +-
|
|
|
dc8c34 |
ldap/servers/plugins/pwdstorage/md5_pwd.c | 2 +-
|
|
|
dc8c34 |
ldap/servers/plugins/pwdstorage/sha_pwd.c | 16 ++++++--
|
|
|
dc8c34 |
ldap/servers/plugins/pwdstorage/smd5_pwd.c | 60 +++++++++++++++--------------
|
|
|
dc8c34 |
ldap/servers/slapd/ch_malloc.c | 34 ++++++++++++++--
|
|
|
dc8c34 |
ldap/servers/slapd/slapi-plugin.h | 2 +-
|
|
|
dc8c34 |
7 files changed, 79 insertions(+), 41 deletions(-)
|
|
|
dc8c34 |
|
|
|
dc8c34 |
diff --git a/ldap/servers/plugins/pwdstorage/clear_pwd.c b/ldap/servers/plugins/pwdstorage/clear_pwd.c
|
|
|
dc8c34 |
index 5a889d4aa..55809a252 100644
|
|
|
dc8c34 |
--- a/ldap/servers/plugins/pwdstorage/clear_pwd.c
|
|
|
dc8c34 |
+++ b/ldap/servers/plugins/pwdstorage/clear_pwd.c
|
|
|
dc8c34 |
@@ -68,7 +68,7 @@ clear_pw_cmp( const char *userpwd, const char *dbpwd )
|
|
|
dc8c34 |
* However, even if the first part of userpw matches dbpwd, but len !=, we
|
|
|
dc8c34 |
* have already failed anyawy. This prevents substring matching.
|
|
|
dc8c34 |
*/
|
|
|
dc8c34 |
- if (slapi_ct_memcmp(userpwd, dbpwd, len_dbp) != 0) {
|
|
|
dc8c34 |
+ if (slapi_ct_memcmp(userpwd, dbpwd, len_dbp, len_dbp) != 0) {
|
|
|
dc8c34 |
result = 1;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
} else {
|
|
|
dc8c34 |
@@ -80,7 +80,7 @@ clear_pw_cmp( const char *userpwd, const char *dbpwd )
|
|
|
dc8c34 |
* dbpwd to itself. We have already got result == 1 if we are here, so we are
|
|
|
dc8c34 |
* just trying to take up time!
|
|
|
dc8c34 |
*/
|
|
|
dc8c34 |
- if (slapi_ct_memcmp(dbpwd, dbpwd, len_dbp)) {
|
|
|
dc8c34 |
+ if (slapi_ct_memcmp(dbpwd, dbpwd, len_dbp, len_dbp)) {
|
|
|
dc8c34 |
/* Do nothing, we have the if to fix a coverity check. */
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
diff --git a/ldap/servers/plugins/pwdstorage/crypt_pwd.c b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
|
|
|
dc8c34 |
index 37557deb1..eb498e603 100644
|
|
|
dc8c34 |
--- a/ldap/servers/plugins/pwdstorage/crypt_pwd.c
|
|
|
dc8c34 |
+++ b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
|
|
|
dc8c34 |
@@ -87,7 +87,7 @@ crypt_pw_cmp( const char *userpwd, const char *dbpwd )
|
|
|
dc8c34 |
/* we use salt (first 2 chars) of encoded password in call to crypt() */
|
|
|
dc8c34 |
cp = crypt( userpwd, dbpwd );
|
|
|
dc8c34 |
if (cp) {
|
|
|
dc8c34 |
- rc= slapi_ct_memcmp( dbpwd, cp, strlen(dbpwd));
|
|
|
dc8c34 |
+ rc= slapi_ct_memcmp( dbpwd, cp, strlen(dbpwd), strlen(cp));
|
|
|
dc8c34 |
} else {
|
|
|
dc8c34 |
rc = -1;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
diff --git a/ldap/servers/plugins/pwdstorage/md5_pwd.c b/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
|
|
dc8c34 |
index d00ef945b..8e352edd3 100644
|
|
|
dc8c34 |
--- a/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
|
|
dc8c34 |
+++ b/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
|
|
dc8c34 |
@@ -86,7 +86,7 @@ md5_pw_cmp( const char *userpwd, const char *dbpwd )
|
|
|
dc8c34 |
bver = NSSBase64_EncodeItem(NULL, (char *)b2a_out, sizeof b2a_out, &binary_item);
|
|
|
dc8c34 |
/* bver points to b2a_out upon success */
|
|
|
dc8c34 |
if (bver) {
|
|
|
dc8c34 |
- rc = slapi_ct_memcmp(bver,dbpwd, strlen(dbpwd));
|
|
|
dc8c34 |
+ rc = slapi_ct_memcmp(bver,dbpwd, strlen(dbpwd), strlen(bver));
|
|
|
dc8c34 |
} else {
|
|
|
dc8c34 |
slapi_log_error(SLAPI_LOG_PLUGIN, MD5_SUBSYSTEM_NAME,
|
|
|
dc8c34 |
"Could not base64 encode hashed value for password compare");
|
|
|
dc8c34 |
diff --git a/ldap/servers/plugins/pwdstorage/sha_pwd.c b/ldap/servers/plugins/pwdstorage/sha_pwd.c
|
|
|
dc8c34 |
index 1b787524b..994e20480 100644
|
|
|
dc8c34 |
--- a/ldap/servers/plugins/pwdstorage/sha_pwd.c
|
|
|
dc8c34 |
+++ b/ldap/servers/plugins/pwdstorage/sha_pwd.c
|
|
|
dc8c34 |
@@ -78,7 +78,7 @@ sha_pw_cmp (const char *userpwd, const char *dbpwd, unsigned int shaLen )
|
|
|
dc8c34 |
char userhash[MAX_SHA_HASH_SIZE];
|
|
|
dc8c34 |
char quick_dbhash[MAX_SHA_HASH_SIZE + SHA_SALT_LENGTH + 3];
|
|
|
dc8c34 |
char *dbhash = quick_dbhash;
|
|
|
dc8c34 |
- struct berval salt;
|
|
|
dc8c34 |
+ struct berval salt = {0};
|
|
|
dc8c34 |
int hash_len; /* must be a signed valued -- see below */
|
|
|
dc8c34 |
unsigned int secOID;
|
|
|
dc8c34 |
char *schemeName;
|
|
|
dc8c34 |
@@ -150,9 +150,19 @@ sha_pw_cmp (const char *userpwd, const char *dbpwd, unsigned int shaLen )
|
|
|
dc8c34 |
|
|
|
dc8c34 |
/* the proof is in the comparison... */
|
|
|
dc8c34 |
if ( hash_len >= shaLen ) {
|
|
|
dc8c34 |
- result = slapi_ct_memcmp( userhash, dbhash, shaLen );
|
|
|
dc8c34 |
+ /*
|
|
|
dc8c34 |
+ * This say "if the hash has a salt IE >, OR if they are equal, check the hash component ONLY.
|
|
|
dc8c34 |
+ * This is why we repeat shaLen twice, even though it seems odd. If you have a dbhast of ssha
|
|
|
dc8c34 |
+ * it's len is 28, and the userpw is 20, but 0 - 20 is the sha, and 21-28 is the salt, which
|
|
|
dc8c34 |
+ * has already been processed into userhash.
|
|
|
dc8c34 |
+ * The case where dbpwd is truncated is handled above in "invalid base64" arm.
|
|
|
dc8c34 |
+ */
|
|
|
dc8c34 |
+ result = slapi_ct_memcmp(userhash, dbhash, shaLen, shaLen);
|
|
|
dc8c34 |
} else {
|
|
|
dc8c34 |
- result = slapi_ct_memcmp( userhash, dbhash + OLD_SALT_LENGTH, hash_len - OLD_SALT_LENGTH );
|
|
|
dc8c34 |
+ /* This case is for if the salt is at the START, which only applies to DS40B1 case.
|
|
|
dc8c34 |
+ * May never be a valid check...
|
|
|
dc8c34 |
+ */
|
|
|
dc8c34 |
+ result = slapi_ct_memcmp(userhash, dbhash + OLD_SALT_LENGTH, shaLen, hash_len - OLD_SALT_LENGTH);
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
loser:
|
|
|
dc8c34 |
diff --git a/ldap/servers/plugins/pwdstorage/smd5_pwd.c b/ldap/servers/plugins/pwdstorage/smd5_pwd.c
|
|
|
dc8c34 |
index ecf9760a4..5afff6022 100644
|
|
|
dc8c34 |
--- a/ldap/servers/plugins/pwdstorage/smd5_pwd.c
|
|
|
dc8c34 |
+++ b/ldap/servers/plugins/pwdstorage/smd5_pwd.c
|
|
|
dc8c34 |
@@ -81,35 +81,37 @@ smd5_pw_cmp( const char *userpwd, const char *dbpwd )
|
|
|
dc8c34 |
/*
|
|
|
dc8c34 |
* Decode hash stored in database.
|
|
|
dc8c34 |
*/
|
|
|
dc8c34 |
- hash_len = pwdstorage_base64_decode_len(dbpwd, 0);
|
|
|
dc8c34 |
- if ( hash_len >= sizeof(quick_dbhash) ) { /* get more space: */
|
|
|
dc8c34 |
- dbhash = (char*) slapi_ch_calloc( hash_len + 1, sizeof(char) );
|
|
|
dc8c34 |
- if ( dbhash == NULL ) goto loser;
|
|
|
dc8c34 |
- } else {
|
|
|
dc8c34 |
- memset( quick_dbhash, 0, sizeof(quick_dbhash) );
|
|
|
dc8c34 |
- }
|
|
|
dc8c34 |
-
|
|
|
dc8c34 |
- hashresult = PL_Base64Decode( dbpwd, 0, dbhash );
|
|
|
dc8c34 |
- if (NULL == hashresult) {
|
|
|
dc8c34 |
- slapi_log_error( SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
|
|
|
dc8c34 |
- "smd5_pw_cmp: userPassword \"%s\" is the wrong length "
|
|
|
dc8c34 |
- "or is not properly encoded BASE64\n", dbpwd );
|
|
|
dc8c34 |
- goto loser;
|
|
|
dc8c34 |
- }
|
|
|
dc8c34 |
-
|
|
|
dc8c34 |
- salt.bv_val = (void*)(dbhash + MD5_LENGTH); /* salt starts after hash value */
|
|
|
dc8c34 |
- salt.bv_len = hash_len - MD5_LENGTH; /* remaining bytes must be salt */
|
|
|
dc8c34 |
-
|
|
|
dc8c34 |
- /* create the hash */
|
|
|
dc8c34 |
- memset( userhash, 0, sizeof(userhash) );
|
|
|
dc8c34 |
- PK11_DigestBegin(ctx);
|
|
|
dc8c34 |
- PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
|
|
|
dc8c34 |
- PK11_DigestOp(ctx, (unsigned char*)(salt.bv_val), salt.bv_len);
|
|
|
dc8c34 |
- PK11_DigestFinal(ctx, userhash, &outLen, sizeof userhash);
|
|
|
dc8c34 |
- PK11_DestroyContext(ctx, 1);
|
|
|
dc8c34 |
-
|
|
|
dc8c34 |
- /* Compare everything up to the salt. */
|
|
|
dc8c34 |
- rc = slapi_ct_memcmp( userhash, dbhash, MD5_LENGTH );
|
|
|
dc8c34 |
+ hash_len = pwdstorage_base64_decode_len(dbpwd, 0);
|
|
|
dc8c34 |
+ if (hash_len >= sizeof(quick_dbhash)) { /* get more space: */
|
|
|
dc8c34 |
+ dbhash = (char *)slapi_ch_calloc(hash_len + 1, sizeof(char));
|
|
|
dc8c34 |
+ if (dbhash == NULL)
|
|
|
dc8c34 |
+ goto loser;
|
|
|
dc8c34 |
+ } else {
|
|
|
dc8c34 |
+ memset(quick_dbhash, 0, sizeof(quick_dbhash));
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ hashresult = PL_Base64Decode(dbpwd, 0, dbhash);
|
|
|
dc8c34 |
+ if (NULL == hashresult) {
|
|
|
dc8c34 |
+ slapi_log_error(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
|
|
|
dc8c34 |
+ "smd5_pw_cmp: userPassword \"%s\" is the wrong length "
|
|
|
dc8c34 |
+ "or is not properly encoded BASE64\n",
|
|
|
dc8c34 |
+ dbpwd);
|
|
|
dc8c34 |
+ goto loser;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ salt.bv_val = (void *)(dbhash + MD5_LENGTH); /* salt starts after hash value */
|
|
|
dc8c34 |
+ salt.bv_len = hash_len - MD5_LENGTH; /* remaining bytes must be salt */
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ /* create the hash */
|
|
|
dc8c34 |
+ memset(userhash, 0, sizeof(userhash));
|
|
|
dc8c34 |
+ PK11_DigestBegin(ctx);
|
|
|
dc8c34 |
+ PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
|
|
|
dc8c34 |
+ PK11_DigestOp(ctx, (unsigned char *)(salt.bv_val), salt.bv_len);
|
|
|
dc8c34 |
+ PK11_DigestFinal(ctx, userhash, &outLen, sizeof userhash);
|
|
|
dc8c34 |
+ PK11_DestroyContext(ctx, 1);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ /* Compare everything up to the salt. */
|
|
|
dc8c34 |
+ rc = slapi_ct_memcmp(userhash, dbhash, MD5_LENGTH, MD5_LENGTH);
|
|
|
dc8c34 |
|
|
|
dc8c34 |
loser:
|
|
|
dc8c34 |
if ( dbhash && dbhash != quick_dbhash ) slapi_ch_free_string( (char **)&dbhash );
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/ch_malloc.c b/ldap/servers/slapd/ch_malloc.c
|
|
|
dc8c34 |
index 38bca5c18..1da053e3f 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/ch_malloc.c
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/ch_malloc.c
|
|
|
dc8c34 |
@@ -740,7 +740,7 @@ memory_record_dump( caddr_t data, caddr_t arg )
|
|
|
dc8c34 |
/* Constant time memcmp. Does not shortcircuit on failure! */
|
|
|
dc8c34 |
/* This relies on p1 and p2 both being size at least n! */
|
|
|
dc8c34 |
int
|
|
|
dc8c34 |
-slapi_ct_memcmp( const void *p1, const void *p2, size_t n)
|
|
|
dc8c34 |
+slapi_ct_memcmp( const void *p1, const void *p2, size_t n1, size_t n2)
|
|
|
dc8c34 |
{
|
|
|
dc8c34 |
int result = 0;
|
|
|
dc8c34 |
const unsigned char *_p1 = (const unsigned char *)p1;
|
|
|
dc8c34 |
@@ -751,9 +751,35 @@ slapi_ct_memcmp( const void *p1, const void *p2, size_t n)
|
|
|
dc8c34 |
return 2;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
- for (i = 0; i < n; i++) {
|
|
|
dc8c34 |
- if (_p1[i] ^ _p2[i]) {
|
|
|
dc8c34 |
- result = 1;
|
|
|
dc8c34 |
+ if (n1 == n2) {
|
|
|
dc8c34 |
+ for (i = 0; i < n1; i++) {
|
|
|
dc8c34 |
+ if (_p1[i] ^ _p2[i]) {
|
|
|
dc8c34 |
+ result = 1;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+ } else {
|
|
|
dc8c34 |
+ const unsigned char *_pa;
|
|
|
dc8c34 |
+ const unsigned char *_pb;
|
|
|
dc8c34 |
+ size_t nl;
|
|
|
dc8c34 |
+ if (n2 > n1) {
|
|
|
dc8c34 |
+ _pa = _p2;
|
|
|
dc8c34 |
+ _pb = _p2;
|
|
|
dc8c34 |
+ nl = n2;
|
|
|
dc8c34 |
+ } else {
|
|
|
dc8c34 |
+ _pa = _p1;
|
|
|
dc8c34 |
+ _pb = _p1;
|
|
|
dc8c34 |
+ nl = n1;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+ /* We already fail as n1 != n2 */
|
|
|
dc8c34 |
+ result = 3;
|
|
|
dc8c34 |
+ for (i = 0; i < nl; i++) {
|
|
|
dc8c34 |
+ if (_pa[i] ^ _pb[i]) {
|
|
|
dc8c34 |
+ /*
|
|
|
dc8c34 |
+ * If we don't mutate result here, dead code elimination
|
|
|
dc8c34 |
+ * we remove for loop.
|
|
|
dc8c34 |
+ */
|
|
|
dc8c34 |
+ result = 4;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
return result;
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
|
|
|
dc8c34 |
index 7f361731b..ac040c716 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/slapi-plugin.h
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/slapi-plugin.h
|
|
|
dc8c34 |
@@ -5531,7 +5531,7 @@ char * slapi_ch_smprintf(const char *fmt, ...)
|
|
|
dc8c34 |
* \param n length in bytes of the content of p1 AND p2.
|
|
|
dc8c34 |
* \return 0 on match. 1 on non-match. 2 on presence of NULL pointer in p1 or p2.
|
|
|
dc8c34 |
*/
|
|
|
dc8c34 |
-int slapi_ct_memcmp( const void *p1, const void *p2, size_t n);
|
|
|
dc8c34 |
+int slapi_ct_memcmp( const void *p1, const void *p2, size_t n1, size_t n2);
|
|
|
dc8c34 |
|
|
|
dc8c34 |
/*
|
|
|
dc8c34 |
* syntax plugin routines
|
|
|
dc8c34 |
--
|
|
|
dc8c34 |
2.13.6
|
|
|
dc8c34 |
|