implement a timing_safe_cmp() function to compare memory without leaking
authordjm <djm@openbsd.org>
Tue, 13 Jul 2010 11:52:06 +0000 (11:52 +0000)
committerdjm <djm@openbsd.org>
Tue, 13 Jul 2010 11:52:06 +0000 (11:52 +0000)
timing information by short-circuiting like memcmp() and use it for
some of the more sensitive comparisons (though nothing high-value was
readily attackable anyway); "looks ok" markus@

usr.bin/ssh/auth-rsa.c
usr.bin/ssh/channels.c
usr.bin/ssh/jpake.c
usr.bin/ssh/key.c
usr.bin/ssh/misc.c
usr.bin/ssh/misc.h
usr.bin/ssh/monitor.c
usr.bin/ssh/packet.c
usr.bin/ssh/ssh-rsa.c

index 43022b0..f9e596b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rsa.c,v 1.76 2010/05/11 02:58:04 djm Exp $ */
+/* $OpenBSD: auth-rsa.c,v 1.77 2010/07/13 11:52:06 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -113,7 +113,7 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
        MD5_Final(mdbuf, &md);
 
        /* Verify that the response is the original challenge. */
-       if (memcmp(response, mdbuf, 16) != 0) {
+       if (timing_safe_cmp(response, mdbuf, 16) != 0) {
                /* Wrong answer. */
                return (0);
        }
index 3c2e847..f09c4fd 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.306 2010/06/25 07:20:04 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.307 2010/07/13 11:52:06 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -912,7 +912,7 @@ x11_open_helper(Buffer *b)
        }
        /* Check if authentication data matches our fake data. */
        if (data_len != x11_fake_data_len ||
-           memcmp(ucp + 12 + ((proto_len + 3) & ~3),
+           timing_safe_cmp(ucp + 12 + ((proto_len + 3) & ~3),
                x11_fake_data, x11_fake_data_len) != 0) {
                debug2("X11 auth data does not match fake data.");
                return -1;
index 450b4cb..e5f3b79 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: jpake.c,v 1.2 2009/03/05 07:18:19 djm Exp $ */
+/* $OpenBSD: jpake.c,v 1.3 2010/07/13 11:52:06 djm Exp $ */
 /*
  * Copyright (c) 2008 Damien Miller.  All rights reserved.
  *
@@ -432,7 +432,7 @@ jpake_check_confirm(const BIGNUM *k,
        if (peer_confirm_hash_len != expected_confirm_hash_len)
                error("%s: confirmation length mismatch (my %u them %u)",
                    __func__, expected_confirm_hash_len, peer_confirm_hash_len);
-       else if (memcmp(peer_confirm_hash, expected_confirm_hash,
+       else if (timing_safe_cmp(peer_confirm_hash, expected_confirm_hash,
            expected_confirm_hash_len) == 0)
                success = 1;
        bzero(expected_confirm_hash, expected_confirm_hash_len);
index 20f1fb4..d5f4c58 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.c,v 1.88 2010/05/07 11:30:29 djm Exp $ */
+/* $OpenBSD: key.c,v 1.89 2010/07/13 11:52:06 djm Exp $ */
 /*
  * read_bignum():
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -48,6 +48,7 @@
 #include "uuencode.h"
 #include "buffer.h"
 #include "log.h"
+#include "misc.h"
 #include "ssh2.h"
 
 static struct KeyCert *
@@ -223,7 +224,7 @@ cert_compare(struct KeyCert *a, struct KeyCert *b)
                return 0;
        if (buffer_len(&a->certblob) != buffer_len(&b->certblob))
                return 0;
-       if (memcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob),
+       if (timing_safe_cmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob),
            buffer_len(&a->certblob)) != 0)
                return 0;
        return 1;
index 46a6612..837bee8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.77 2010/07/02 04:32:44 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.78 2010/07/13 11:52:06 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
@@ -830,3 +830,15 @@ ms_to_timeval(struct timeval *tv, int ms)
        tv->tv_usec = (ms % 1000) * 1000;
 }
 
+int
+timing_safe_cmp(const void *_s1, const void *_s2, size_t n)
+{
+       u_char *s1 = (u_char *)_s1;
+       u_char *s2 = (u_char *)_s2;
+       int ret = 0;
+
+       for (; n > 0; n--, s1++, s2++)
+               ret |= *s1 ^ *s2;
+       return ret;
+}
+
index b28e61b..705a994 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.41 2010/01/09 23:04:13 dtucker Exp $ */
+/* $OpenBSD: misc.h,v 1.42 2010/07/13 11:52:06 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -35,6 +35,7 @@ char  *tohex(const void *, size_t);
 void    sanitise_stdfd(void);
 void    ms_subtract_diff(struct timeval *, int *);
 void    ms_to_timeval(struct timeval *, int);
+int     timing_safe_cmp(const void *, const void *, size_t);
 
 struct passwd *pwcopy(struct passwd *);
 const char *ssh_gai_strerror(int);
index 9e57acf..d3b9211 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.106 2010/03/07 11:57:13 dtucker Exp $ */
+/* $OpenBSD: monitor.c,v 1.107 2010/07/13 11:52:06 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -433,7 +433,7 @@ monitor_allowed_key(u_char *blob, u_int bloblen)
 {
        /* make sure key is allowed */
        if (key_blob == NULL || key_bloblen != bloblen ||
-           memcmp(key_blob, blob, key_bloblen))
+           timing_safe_cmp(key_blob, blob, key_bloblen))
                return (0);
        return (1);
 }
@@ -829,14 +829,14 @@ monitor_valid_userblob(u_char *data, u_int datalen)
                len = buffer_len(&b);
                if ((session_id2 == NULL) ||
                    (len < session_id2_len) ||
-                   (memcmp(p, session_id2, session_id2_len) != 0))
+                   (timing_safe_cmp(p, session_id2, session_id2_len) != 0))
                        fail++;
                buffer_consume(&b, session_id2_len);
        } else {
                p = buffer_get_string(&b, &len);
                if ((session_id2 == NULL) ||
                    (len != session_id2_len) ||
-                   (memcmp(p, session_id2, session_id2_len) != 0))
+                   (timing_safe_cmp(p, session_id2, session_id2_len) != 0))
                        fail++;
                xfree(p);
        }
@@ -884,7 +884,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
        p = buffer_get_string(&b, &len);
        if ((session_id2 == NULL) ||
            (len != session_id2_len) ||
-           (memcmp(p, session_id2, session_id2_len) != 0))
+           (timing_safe_cmp(p, session_id2, session_id2_len) != 0))
                fail++;
        xfree(p);
 
@@ -1361,9 +1361,9 @@ mm_get_kex(Buffer *m)
 
        kex = xcalloc(1, sizeof(*kex));
        kex->session_id = buffer_get_string(m, &kex->session_id_len);
-       if ((session_id2 == NULL) ||
-           (kex->session_id_len != session_id2_len) ||
-           (memcmp(kex->session_id, session_id2, session_id2_len) != 0))
+       if (session_id2 == NULL ||
+           kex->session_id_len != session_id2_len ||
+           timing_safe_cmp(kex->session_id, session_id2, session_id2_len) != 0)
                fatal("mm_get_get: internal error: bad session id");
        kex->we_need = buffer_get_int(m);
        kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
index 0da9b51..522d2f4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.166 2009/06/27 09:29:06 andreas Exp $ */
+/* $OpenBSD: packet.c,v 1.167 2010/07/13 11:52:06 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1297,7 +1297,7 @@ packet_read_poll2(u_int32_t *seqnr_p)
                macbuf = mac_compute(mac, active_state->p_read.seqnr,
                    buffer_ptr(&active_state->incoming_packet),
                    buffer_len(&active_state->incoming_packet));
-               if (memcmp(macbuf, buffer_ptr(&active_state->input),
+               if (timing_safe_cmp(macbuf, buffer_ptr(&active_state->input),
                    mac->mac_len) != 0) {
                        logit("Corrupted MAC on input.");
                        if (need > PACKET_MAX_SIZE)
index e98533c..dbb31d8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.41 2010/04/16 01:47:26 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.42 2010/07/13 11:52:06 djm Exp $ */
 /*
  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
  *
@@ -27,6 +27,7 @@
 #include "buffer.h"
 #include "key.h"
 #include "compat.h"
+#include "misc.h"
 #include "ssh.h"
 
 static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
@@ -246,11 +247,11 @@ openssh_RSA_verify(int type, u_char *hash, u_int hashlen,
                error("bad decrypted len: %d != %d + %d", len, hlen, oidlen);
                goto done;
        }
-       if (memcmp(decrypted, oid, oidlen) != 0) {
+       if (timing_safe_cmp(decrypted, oid, oidlen) != 0) {
                error("oid mismatch");
                goto done;
        }
-       if (memcmp(decrypted + oidlen, hash, hlen) != 0) {
+       if (timing_safe_cmp(decrypted + oidlen, hash, hlen) != 0) {
                error("hash mismatch");
                goto done;
        }