httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dirk-Willem van Gulik <di...@webweaving.org>
Subject Re: httpd - side channel attack - timing of digest comparisons
Date Thu, 21 May 2015 18:55:56 GMT
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);
+}

+


Mime
View raw message