Security of OpenSSL ECDSA signatures

Damien Miller djm at mindrot.org
Tue May 24 16:29:14 EST 2011


On Mon, 23 May 2011, Dan Kaminsky wrote:

> The Brumley and Tuveri attack is against a scalar multiplication
> algorithm that is specific to GF(2m) fields (see section 3.2 of the
> paper). An attack on prime fields would be a new one altogether.
> 
> -d
> 
> 
> I asked one of the timing attack guys if they were able to run their
> nanosecond scale attacks against a device having a network interface
> enforced jitter several orders of magnitude higher than what they were
> looking for.  Command looked something like:
> 
> tc qdisc change dev eth0 root netem delay 2ms 1ms
> 
> No reply.
> 
> I know in theory this shouldn't help, but if OpenSSH's ECDSA implementation
> is in fact variable time, why not add a random usleep at 10-100x the worst
> case scenario for at least average hardware?

random delays will not help because you can sample to eliminate them. I
think you would want something like the following, that rounds signing
operations up to the next power of two milliseconds.

Index: key.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/key.c,v
retrieving revision 1.97
diff -u -p -r1.97 key.c
--- key.c	17 May 2011 07:13:31 -0000	1.97
+++ key.c	24 May 2011 06:28:21 -0000
@@ -36,11 +36,13 @@
 
 #include <sys/param.h>
 #include <sys/types.h>
+#include <sys/time.h>
 
 #include <openssl/evp.h>
 
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "xmalloc.h"
 #include "key.h"
@@ -1588,28 +1590,68 @@ key_to_blob(const Key *key, u_char **blo
 	return len;
 }
 
+/*
+ * Round up to nearest power of two. Bit-twiddle algorithm from
+ * http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ */
+static u_int64_t
+ceil2_u64(u_int64_t n)
+{
+	n--;
+	n |= n >> 1;
+	n |= n >> 2;
+	n |= n >> 4;
+	n |= n >> 8;
+	n |= n >> 16;
+	n |= n >> 32;
+	n++;
+	return n;
+}
+
 int
 key_sign(
     const Key *key,
     u_char **sigp, u_int *lenp,
     const u_char *data, u_int datalen)
 {
+	int result = -1;
+	struct timeval start, finish, diff;
+	u_int64_t duration, desired;
+
+	gettimeofday(&start, NULL);
 	switch (key->type) {
 	case KEY_DSA_CERT_V00:
 	case KEY_DSA_CERT:
 	case KEY_DSA:
-		return ssh_dss_sign(key, sigp, lenp, data, datalen);
+		result = ssh_dss_sign(key, sigp, lenp, data, datalen);
+		break;
 	case KEY_ECDSA_CERT:
 	case KEY_ECDSA:
-		return ssh_ecdsa_sign(key, sigp, lenp, data, datalen);
+		result = ssh_ecdsa_sign(key, sigp, lenp, data, datalen);
+		break;
 	case KEY_RSA_CERT_V00:
 	case KEY_RSA_CERT:
 	case KEY_RSA:
-		return ssh_rsa_sign(key, sigp, lenp, data, datalen);
+		result = ssh_rsa_sign(key, sigp, lenp, data, datalen);
+		break;
 	default:
 		error("key_sign: invalid key type %d", key->type);
-		return -1;
+		result = -1;
+		break;
 	}
+
+	/*
+	 * Round up perceived duration of signing operation to the nearest
+	 * power of two milliseconds by sleeping the difference.
+	 */
+	gettimeofday(&finish, NULL);
+	timersub(&finish, &start, &diff);
+	duration = diff.tv_sec * 1000000 + diff.tv_usec;
+	duration = (duration + 999) / 1000;	/* round up to milliseconds */
+	desired = ceil2_u64(duration);		/* round up to 2^n */
+	if (desired > duration)
+		usleep((desired - duration) * 1000);
+	return result;
 }
 
 /*


More information about the openssh-unix-dev mailing list