Very quick and dirty list of the most obvious places where we compare stuff.
Currently trying to find some time to figure out if these are all vulnerable;
or if it is just the two outer ones.
Dw.
Index: modules/aaa/mod_auth_digest.c
===================================================================
--- modules/aaa/mod_auth_digest.c (revision 1680471)
+++ modules/aaa/mod_auth_digest.c (working copy)
@@ -1394,7 +1394,7 @@
resp->nonce[NONCE_TIME_LEN] = tmp;
resp->nonce_time = nonce_time.time;
- if (strcmp(hash, resp->nonce+NONCE_TIME_LEN)) {
+ if (ap_timingsafe_strcmp(hash, resp->nonce+NONCE_TIME_LEN)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01776)
"invalid nonce %s received - hash is not %s",
resp->nonce, hash);
@@ -1423,7 +1423,7 @@
}
}
else if (conf->nonce_lifetime == 0 && resp->client) {
- if (memcmp(resp->client->last_nonce, resp->nonce, NONCE_LEN)) {
+ if (ap_timingsafe_memcmp(resp->client->last_nonce, resp->nonce,
NONCE_LEN)) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01779)
"user %s: one-time-nonce mismatch - sending "
"new nonce", r->user);
@@ -1749,7 +1749,7 @@
if (resp->message_qop == NULL) {
/* old (rfc-2069) style digest */
- if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) {
+ if (ap_timingsafe_strcmp(resp->digest, old_digest(r, resp,
conf->ha1))) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01792)
"user %s: password mismatch: %s", r->user,
r->uri);
@@ -1784,7 +1784,7 @@
/* we failed to allocate a client struct */
return HTTP_INTERNAL_SERVER_ERROR;
}
- if (strcmp(resp->digest, exp_digest)) {
+ if (ap_timingsafe_strcmp(resp->digest, exp_digest)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01794)
"user %s: password mismatch: %s", r->user,
r->uri);
Index: include/util_md5.h
===================================================================
--- include/util_md5.h (revision 1680471)
+++ include/util_md5.h (working copy)
@@ -64,6 +64,35 @@
*/
AP_DECLARE(char *) ap_md5digest(apr_pool_t *p, apr_file_t *infile);
+/**
+ * Compare two binary buffers (of identical length) in a timing safe
+ * manner. As to avoid leaking information about that what is compared
+ * and thus preventing side channel leaks when for example comparing
+ * a checksum or a password.
+ *.
+ * Both buffers are assumed to have idenitcal length.
+ *
+ * @param buf1 Buffer 1 to compare buffer 2 to.
+ * @param buf2 Buffer 2
+ * @param len The length of the two buffers.
+ * @return 0 when identical, non zero when different.
+ */
+AP_DECLARE(int) ap_timingsafe_memcmp(const void *b1, const void *b2, size_t
len)
+
+/**
+ * Compare \0 terminated strings in a time safe manner.
+ * As to avoid leaking information about that what is compared
+ * and thus preventing side channel leaks when for example comparing
+ * a checksum or a password.
+ *.
+ * Both buffers are assumed to have idenitcal length.
+ *
+ * @param str1 pointer to a \0 terminated string,
+ * @param str2 pointer to a \0 terminated string.
+ * @return 0 when identical or both NULL, non zero when different or one of
the string pointers is NULL.
+ */
+AP_DECLARE(int) ap_timingsafe_strcmp(const char * str1, const char * str2);
+
#ifdef __cplusplus
}
#endif
Index: server/util_md5.c
===================================================================
--- server/util_md5.c (revision 1680471)
+++ server/util_md5.c (working copy)
@@ -164,3 +164,137 @@
return ap_md5contextTo64(p, &context);
}
+/* Oroginal code for ap_timingsafe_memcmp: libressl-portable under below
license.
+ *
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Compare two binary buffers (of identical length) in a timing safe
+ * manner. As to avoid leaking information about that what is compared
+ * and thus preventing side channel leaks when for example comparing
+ * a checksum or a password.
+ *.
+ * Both buffers are assumed to have idenitcal length.
+ *
+ * @param buf1 Buffer 1 to compare buffer 2 to.
+ * @param buf2 Buffer 2
+ * @param len The length of the two buffers.
+ * @return 0 when identical, non zero when different.
+ */
+AP_DECLARE(int) ap_timingsafe_memcmp(const void *b1, const void *b2, size_t
len)
+{
+ const unsigned char *p1 = b1, *p2 = b2;
+ size_t i;
+ int res = 0, done = 0;
+
+ for (i = 0; i < len; i++) {
+ /* lt is -1 if p1[i] < p2[i]; else 0. */
+ int lt = (p1[i] - p2[i]) >> CHAR_BIT;
+
+ /* gt is -1 if p1[i] > p2[i]; else 0. */
+ int gt = (p2[i] - p1[i]) >> CHAR_BIT;
+
+ /* cmp is 1 if p1[i] > p2[i]; -1 if p1[i] < p2[i]; else 0. */
+ int cmp = lt - gt;
+
+ /* set res = cmp if !done. */
+ res |= cmp & ~done;
+
+ /* set done if p1[i] != p2[i]. */
+ done |= lt | gt;
+ }
+
+ return (res);
+}
+