summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/http_auth.c23
-rw-r--r--src/http_auth.h3
-rw-r--r--src/mod_auth.c2
-rw-r--r--src/mod_authn_file.c2
-rw-r--r--src/mod_authn_mysql.c2
5 files changed, 29 insertions, 3 deletions
diff --git a/src/http_auth.c b/src/http_auth.c
index 24c2319a..bedb5fe0 100644
--- a/src/http_auth.c
+++ b/src/http_auth.c
@@ -51,6 +51,29 @@ 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
diff --git a/src/http_auth.h b/src/http_auth.h
index 64a32da7..5f6e00d4 100644
--- a/src/http_auth.h
+++ b/src/http_auth.h
@@ -71,6 +71,9 @@ const http_auth_backend_t * http_auth_backend_get (const buffer *name);
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(connection *con, const char *username, size_t ulen, const char *auth_type, size_t alen);
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 34e5e91a..2a7bcea8 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -1128,7 +1128,7 @@ static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d,
mod_auth_digest_mutate(&ai,m,uri,nonce,cnonce,nc,qop);
- if (0 != memcmp(rdigest, ai.digest, ai.dlen)) {
+ if (!http_auth_const_time_memeq(rdigest, ai.digest, ai.dlen)) {
/* digest not ok */
log_error_write(srv, __FILE__, __LINE__, "sssB",
"digest: auth failed for ", username, ": wrong password, IP:", con->dst_addr_buf);
diff --git a/src/mod_authn_file.c b/src/mod_authn_file.c
index 6f76794a..fa21892b 100644
--- a/src/mod_authn_file.c
+++ b/src/mod_authn_file.c
@@ -356,7 +356,7 @@ static handler_t mod_authn_file_htdigest_basic(server *srv, connection *con, voi
mod_authn_file_digest(&ai, pw, strlen(pw));
- return (0 == memcmp(htdigest, ai.digest, ai.dlen)
+ return (http_auth_const_time_memeq(htdigest, ai.digest, ai.dlen)
&& http_auth_match_rules(require, username->ptr, NULL, NULL))
? HANDLER_GO_ON
: HANDLER_ERROR;
diff --git a/src/mod_authn_mysql.c b/src/mod_authn_mysql.c
index c1f881f5..d8842bfa 100644
--- a/src/mod_authn_mysql.c
+++ b/src/mod_authn_mysql.c
@@ -380,7 +380,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)))
- ? memcmp(HA1, md5pw, sizeof(md5pw))
+ ? http_auth_const_time_memeq(HA1, md5pw, sizeof(md5pw)) ? 0 : 1
: -1;
}