[multiple] move const time cmp funcs to ck.[ch]

http_auth_const_time_memeq_pad() -> ck_memeq_const_time()
http_auth_const_time_memeq() -> ck_memeq_const_time_fixed_len()
This commit is contained in:
Glenn Strauss 2021-05-21 23:50:47 -04:00
parent 0286bdef0c
commit 62ccda8592
9 changed files with 71 additions and 69 deletions

View File

@ -254,3 +254,46 @@ ck_strerror_s (char * const s, const rsize_t maxsize, const errno_t errnum)
#endif
}
int
ck_memeq_const_time (const void *a, const size_t alen, const void *b, const size_t blen)
{
/* constant time memory compare for equality */
/* rounds to next multiple of 64 to avoid potentially leaking exact
* string lengths when subject to high precision timing attacks
*/
/* Note: some libs provide similar funcs but might not obscure length, e.g.
* OpenSSL:
* int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len)
* Note: some OS provide similar funcs but might not obscure length, e.g.
* OpenBSD: int timingsafe_bcmp(const void *b1, const void *b2, size_t len)
* NetBSD: int consttime_memequal(void *b1, void *b2, size_t len)
*/
const volatile unsigned char * const av = (const unsigned char *)a;
const volatile unsigned char * const bv = (const unsigned char *)b;
size_t lim = ((alen >= blen ? alen : blen) + 0x3F) & ~0x3F;
int diff = (alen != blen); /*(never match if string length mismatch)*/
for (size_t i = 0, j = 0; lim; --lim) {
diff |= (av[i] ^ bv[j]);
i += (i < alen);
j += (j < blen);
}
return (0 == diff);
}
int
ck_memeq_const_time_fixed_len (const void *a, const void *b, const size_t len)
{
/* constant time memory compare for equality for fixed len (e.g. digests)
* (padding not necessary for digests, which have fixed, defined lengths) */
/* caller should prefer ck_memeq_const_time() if not operating on digests */
const volatile unsigned char * const av = (const unsigned char *)a;
const volatile unsigned char * const bv = (const unsigned char *)b;
int diff = 0;
for (size_t i = 0; i < len; ++i) {
diff |= (av[i] ^ bv[i]);
}
return (0 == diff);
}

View File

@ -42,6 +42,16 @@ static inline errno_t ck_memzero(void *s, rsize_t n) {
errno_t ck_strerror_s (char *s, rsize_t maxsize, errno_t errnum);
/*(ck_memeq_const_time() is not from C11 Annex K)
* constant time memory compare for equality
* rounds to next multiple of 64 to avoid potentially leaking exact
* string lengths when subject to high precision timing attacks */
int ck_memeq_const_time (const void *a, size_t alen, const void *b, size_t blen);
/*(ck_memeq_const_time_fixed_len() is not from C11 Annex K)
* constant time memory compare for equality for fixed len (e.g. digests)
* (padding not necessary for digests, which have fixed, defined lengths) */
int ck_memeq_const_time_fixed_len (const void *a, const void *b, size_t len);
__END_DECLS

View File

@ -58,57 +58,6 @@ void http_auth_backend_set (const http_auth_backend_t *backend)
}
int http_auth_const_time_memeq (const void *a, const void *b, const size_t len)
{
/* constant time memory compare, unless compiler figures it out
* (similar to mod_secdownload.c:const_time_memeq()) */
/* caller should prefer http_auth_const_time_memeq_pad()
* if not operating on digests, which have defined lengths */
/* Note: some libs provide similar funcs, e.g.
* OpenSSL:
* int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len)
* Note: some OS provide similar funcs, e.g.
* OpenBSD: int timingsafe_bcmp(const void *b1, const void *b2, size_t len)
* NetBSD: int consttime_memequal(void *b1, void *b2, size_t len)
*/
const volatile unsigned char * const av = (const unsigned char *)a;
const volatile unsigned char * const bv = (const unsigned char *)b;
int diff = 0;
for (size_t i = 0; i < len; ++i) {
diff |= (av[i] ^ bv[i]);
}
return (0 == diff);
}
int http_auth_const_time_memeq_pad (const void *a, const size_t alen, const void *b, const size_t blen)
{
/* constant time memory compare, unless compiler figures it out
* (similar to mod_secdownload.c:const_time_memeq()) */
/* round to next multiple of 64 to avoid potentially leaking exact
* password length when subject to high precision timing attacks)
* (not necessary when comparing digests, which have defined lengths)
*/
/* Note: some libs provide similar funcs but might not obscure length, e.g.
* OpenSSL:
* int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len)
* Note: some OS provide similar funcs but might not obscure length, e.g.
* OpenBSD: int timingsafe_bcmp(const void *b1, const void *b2, size_t len)
* NetBSD: int consttime_memequal(void *b1, void *b2, size_t len)
*/
const volatile unsigned char * const av = (const unsigned char *)a;
const volatile unsigned char * const bv = (const unsigned char *)b;
size_t lim = ((alen >= blen ? alen : blen) + 0x3F) & ~0x3F;
int diff = (alen != blen); /*(never match if string length mismatch)*/
for (size_t i = 0, j = 0; lim; --lim) {
diff |= (av[i] ^ bv[j]);
i += (i < alen);
j += (j < blen);
}
return (0 == diff);
}
void http_auth_dumbdata_reset (void)
{
memset(http_auth_schemes, 0, sizeof(http_auth_schemes));

View File

@ -88,12 +88,6 @@ const http_auth_backend_t * http_auth_backend_get (const buffer *name);
__attribute_cold__
void http_auth_backend_set (const http_auth_backend_t *backend);
__attribute_pure__
int http_auth_const_time_memeq (const void *a, const void *b, size_t len);
__attribute_pure__
int http_auth_const_time_memeq_pad (const void *a, size_t alen, const void *b, size_t blen);
void http_auth_setenv(request_st *r, const char *username, size_t ulen, const char *auth_type, size_t alen);
int http_auth_digest_hex2bin (const char *hexstr, size_t len, unsigned char *bin, size_t binlen);

View File

@ -6,6 +6,7 @@
#include "sys-crypto-md.h" /* USE_LIB_CRYPTO */
#include "base.h"
#include "ck.h"
#include "plugin.h"
#include "plugin_config.h"
#include "http_auth.h"
@ -795,8 +796,7 @@ static handler_t mod_auth_check_basic(request_st * const r, void *p_d, const str
ae = http_auth_cache_query(sptree, ndx);
if (ae && ae->require == require
&& buffer_is_equal_string(username, ae->username, ae->ulen))
rc = http_auth_const_time_memeq_pad(ae->pwdigest, ae->dlen,
pw, pwlen)
rc = ck_memeq_const_time(ae->pwdigest, ae->dlen, pw, pwlen)
? HANDLER_GO_ON
: HANDLER_ERROR;
else /*(not found or hash collision)*/
@ -1473,7 +1473,7 @@ static handler_t mod_auth_check_digest(request_st * const r, void *p_d, const st
mod_auth_digest_mutate(&ai,m,uri,nonce,cnonce,nc,qop);
if (!http_auth_const_time_memeq(rdigest, ai.digest, ai.dlen)) {
if (!ck_memeq_const_time_fixed_len(rdigest, ai.digest, ai.dlen)) {
/*safe_memclear(ai.digest, ai.dlen);*//* skip clear since mutated */
/* digest not ok */
log_error(r->conf.errh, __FILE__, __LINE__,

View File

@ -41,6 +41,7 @@
#include "sys-crypto-md.h"
#include "safe_memclear.h"
#include "base.h"
#include "ck.h"
#include "http_auth.h"
#include "fdevent.h"
#include "log.h"
@ -403,7 +404,7 @@ mod_authn_dbi_password_cmp (const char *userpw, unsigned long userpwlen, http_au
/*(compare 16-byte MD5 binary instead of converting to hex strings
* in order to then have to do case-insensitive hex str comparison)*/
return (0 == http_auth_digest_hex2bin(userpw, 32, md5pw, sizeof(md5pw)))
? http_auth_const_time_memeq(HA1, md5pw, sizeof(md5pw)) ? 0 : 1
? ck_memeq_const_time_fixed_len(HA1, md5pw, sizeof(md5pw)) ? 0 : 1
: -1;
}
#ifdef USE_LIB_CRYPTO
@ -423,7 +424,7 @@ mod_authn_dbi_password_cmp (const char *userpw, unsigned long userpwlen, http_au
/*(compare 32-byte binary digest instead of converting to hex strings
* in order to then have to do case-insensitive hex str comparison)*/
return (0 == http_auth_digest_hex2bin(userpw, 64, shapw, sizeof(shapw)))
? http_auth_const_time_memeq(HA1, shapw, sizeof(shapw)) ? 0 : 1
? ck_memeq_const_time_fixed_len(HA1, shapw, sizeof(shapw)) ? 0 : 1
: -1;
}
#endif

View File

@ -21,6 +21,7 @@
#include "safe_memclear.h"
#include "base.h"
#include "ck.h"
#include "plugin.h"
#include "fdevent.h"
#include "http_auth.h"
@ -302,7 +303,7 @@ static handler_t mod_authn_file_htdigest_basic(request_st * const r, void *p_d,
mod_authn_file_digest(&ai, pw, strlen(pw));
int rc = (http_auth_const_time_memeq(htdigest, ai.digest, ai.dlen)
int rc = (ck_memeq_const_time_fixed_len(htdigest, ai.digest, ai.dlen)
&& http_auth_match_rules(require, username->ptr, NULL, NULL));
safe_memclear(htdigest, ai.dlen);
@ -394,7 +395,9 @@ static handler_t mod_authn_file_plain_basic(request_st * const r, void *p_d, con
mod_authn_file_patch_config(r, p);
rc = mod_authn_file_htpasswd_get(p->conf.auth_plain_userfile, CONST_BUF_LEN(username), password_buf, r->conf.errh);
if (0 == rc) {
rc = http_auth_const_time_memeq_pad(CONST_BUF_LEN(password_buf), pw, strlen(pw)) ? 0 : -1;
rc = ck_memeq_const_time(CONST_BUF_LEN(password_buf), pw, strlen(pw))
? 0
: -1;
}
safe_memclear(password_buf->ptr, password_buf->size);
buffer_free(password_buf);

View File

@ -30,6 +30,7 @@
#include <mysql.h>
#include "base.h"
#include "ck.h"
#include "http_auth.h"
#include "log.h"
#include "plugin.h"
@ -317,7 +318,7 @@ static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpw
/*(compare 16-byte MD5 binary instead of converting to hex strings
* in order to then have to do case-insensitive hex str comparison)*/
return (0 == http_auth_digest_hex2bin(userpw, 32, md5pw, sizeof(md5pw)))
? http_auth_const_time_memeq(HA1, md5pw, sizeof(md5pw)) ? 0 : 1
? ck_memeq_const_time_fixed_len(HA1, md5pw, sizeof(md5pw)) ? 0 : 1
: -1;
}

View File

@ -4,6 +4,7 @@
#include "log.h"
#include "buffer.h"
#include "base64.h"
#include "ck.h"
#include "http_auth.h"
#include "plugin.h"
@ -159,8 +160,8 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
li_MD5_Update(&Md5Ctx, ts_str, 8);
li_MD5_Final(HA1, &Md5Ctx);
return http_auth_const_time_memeq((char *)HA1,
(char *)md5bin, sizeof(md5bin));
return ck_memeq_const_time_fixed_len((char *)HA1,
(char *)md5bin,sizeof(md5bin));
}
#ifdef USE_LIB_CRYPTO
case SECDL_HMAC_SHA1:
@ -179,7 +180,7 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
li_to_base64_no_padding(base64_digest, 28, digest, 20, BASE64_URL);
return (27 == maclen)
&& http_auth_const_time_memeq(mac, base64_digest, 27);
&& ck_memeq_const_time_fixed_len(mac, base64_digest, 27);
}
break;
case SECDL_HMAC_SHA256:
@ -198,7 +199,7 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
li_to_base64_no_padding(base64_digest, 44, digest, 32, BASE64_URL);
return (43 == maclen)
&& http_auth_const_time_memeq(mac, base64_digest, 43);
&& ck_memeq_const_time_fixed_len(mac, base64_digest, 43);
}
break;
#endif