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); +} +