Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 8 Apr 2014 23:16:20 +0000 (UTC)
From:      Xin LI <delphij@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r264285 - in stable: 8/crypto/openssl/crypto/bn 8/crypto/openssl/crypto/ec 8/sys/fs/nfsserver 9/crypto/openssl/crypto/bn 9/crypto/openssl/crypto/ec 9/sys/fs/nfsserver
Message-ID:  <201404082316.s38NGKt1068823@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: delphij
Date: Tue Apr  8 23:16:19 2014
New Revision: 264285
URL: http://svnweb.freebsd.org/changeset/base/264285

Log:
  Fix NFS deadlock vulnerability. [SA-14:05]
  
  Fix ECDSA Cache Side-channel Attack in OpenSSL. [SA-14:06]

Modified:
  stable/8/crypto/openssl/crypto/bn/bn.h
  stable/8/crypto/openssl/crypto/bn/bn_lib.c
  stable/8/crypto/openssl/crypto/ec/ec2_mult.c
  stable/8/sys/fs/nfsserver/nfs_nfsdserv.c

Changes in other areas also in this revision:
Modified:
  stable/9/crypto/openssl/crypto/bn/bn.h
  stable/9/crypto/openssl/crypto/bn/bn_lib.c
  stable/9/crypto/openssl/crypto/ec/ec2_mult.c
  stable/9/sys/fs/nfsserver/nfs_nfsdserv.c

Modified: stable/8/crypto/openssl/crypto/bn/bn.h
==============================================================================
--- stable/8/crypto/openssl/crypto/bn/bn.h	Tue Apr  8 23:16:05 2014	(r264284)
+++ stable/8/crypto/openssl/crypto/bn/bn.h	Tue Apr  8 23:16:19 2014	(r264285)
@@ -511,6 +511,8 @@ BIGNUM *BN_mod_inverse(BIGNUM *ret,
 BIGNUM *BN_mod_sqrt(BIGNUM *ret,
 	const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
 
+void	BN_consttime_swap(BN_ULONG swap, BIGNUM *a, BIGNUM *b, int nwords);
+
 /* Deprecated versions */
 #ifndef OPENSSL_NO_DEPRECATED
 BIGNUM *BN_generate_prime(BIGNUM *ret,int bits,int safe,
@@ -740,11 +742,20 @@ int RAND_pseudo_bytes(unsigned char *buf
 
 #define bn_fix_top(a)		bn_check_top(a)
 
+#define bn_check_size(bn, bits) bn_wcheck_size(bn, ((bits+BN_BITS2-1))/BN_BITS2)
+#define bn_wcheck_size(bn, words) \
+	do { \
+		const BIGNUM *_bnum2 = (bn); \
+		assert(words <= (_bnum2)->dmax && words >= (_bnum2)->top); \
+	} while(0)
+
 #else /* !BN_DEBUG */
 
 #define bn_pollute(a)
 #define bn_check_top(a)
 #define bn_fix_top(a)		bn_correct_top(a)
+#define bn_check_size(bn, bits)
+#define bn_wcheck_size(bn, words)
 
 #endif
 

Modified: stable/8/crypto/openssl/crypto/bn/bn_lib.c
==============================================================================
--- stable/8/crypto/openssl/crypto/bn/bn_lib.c	Tue Apr  8 23:16:05 2014	(r264284)
+++ stable/8/crypto/openssl/crypto/bn/bn_lib.c	Tue Apr  8 23:16:19 2014	(r264285)
@@ -824,3 +824,55 @@ int bn_cmp_part_words(const BN_ULONG *a,
 		}
 	return bn_cmp_words(a,b,cl);
 	}
+
+/* 
+ * Constant-time conditional swap of a and b.  
+ * a and b are swapped if condition is not 0.  The code assumes that at most one bit of condition is set.
+ * nwords is the number of words to swap.  The code assumes that at least nwords are allocated in both a and b,
+ * and that no more than nwords are used by either a or b.
+ * a and b cannot be the same number
+ */
+void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords)
+	{
+	BN_ULONG t;
+	int i;
+
+	bn_wcheck_size(a, nwords);
+	bn_wcheck_size(b, nwords);
+
+	assert(a != b);
+	assert((condition & (condition - 1)) == 0);
+	assert(sizeof(BN_ULONG) >= sizeof(int));
+
+	condition = ((condition - 1) >> (BN_BITS2 - 1)) - 1;
+
+	t = (a->top^b->top) & condition;
+	a->top ^= t;
+	b->top ^= t;
+
+#define BN_CONSTTIME_SWAP(ind) \
+	do { \
+		t = (a->d[ind] ^ b->d[ind]) & condition; \
+		a->d[ind] ^= t; \
+		b->d[ind] ^= t; \
+	} while (0)
+
+
+	switch (nwords) {
+	default:
+		for (i = 10; i < nwords; i++) 
+			BN_CONSTTIME_SWAP(i);
+		/* Fallthrough */
+	case 10: BN_CONSTTIME_SWAP(9); /* Fallthrough */
+	case 9: BN_CONSTTIME_SWAP(8); /* Fallthrough */
+	case 8: BN_CONSTTIME_SWAP(7); /* Fallthrough */
+	case 7: BN_CONSTTIME_SWAP(6); /* Fallthrough */
+	case 6: BN_CONSTTIME_SWAP(5); /* Fallthrough */
+	case 5: BN_CONSTTIME_SWAP(4); /* Fallthrough */
+	case 4: BN_CONSTTIME_SWAP(3); /* Fallthrough */
+	case 3: BN_CONSTTIME_SWAP(2); /* Fallthrough */
+	case 2: BN_CONSTTIME_SWAP(1); /* Fallthrough */
+	case 1: BN_CONSTTIME_SWAP(0);
+	}
+#undef BN_CONSTTIME_SWAP
+}

Modified: stable/8/crypto/openssl/crypto/ec/ec2_mult.c
==============================================================================
--- stable/8/crypto/openssl/crypto/ec/ec2_mult.c	Tue Apr  8 23:16:05 2014	(r264284)
+++ stable/8/crypto/openssl/crypto/ec/ec2_mult.c	Tue Apr  8 23:16:19 2014	(r264285)
@@ -208,9 +208,12 @@ static int gf2m_Mxy(const EC_GROUP *grou
 
 /* Computes scalar*point and stores the result in r.
  * point can not equal r.
- * Uses algorithm 2P of
+ * Uses a modified algorithm 2P of
  *     Lopex, J. and Dahab, R.  "Fast multiplication on elliptic curves over 
  *     GF(2^m) without precomputation".
+ *
+ * To protect against side-channel attack the function uses constant time
+ * swap avoiding conditional branches.
  */
 static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
 	const EC_POINT *point, BN_CTX *ctx)
@@ -244,6 +247,11 @@ static int ec_GF2m_montgomery_point_mult
 	x2 = &r->X;
 	z2 = &r->Y;
 
+	bn_wexpand(x1, group->field.top);
+	bn_wexpand(z1, group->field.top);
+	bn_wexpand(x2, group->field.top);
+	bn_wexpand(z2, group->field.top);
+
 	if (!BN_GF2m_mod_arr(x1, &point->X, group->poly)) goto err; /* x1 = x */
 	if (!BN_one(z1)) goto err; /* z1 = 1 */
 	if (!group->meth->field_sqr(group, z2, x1, ctx)) goto err; /* z2 = x1^2 = x^2 */
@@ -266,16 +274,12 @@ static int ec_GF2m_montgomery_point_mult
 		{
 		for (; j >= 0; j--)
 			{
-			if (scalar->d[i] & mask)
-				{
-				if (!gf2m_Madd(group, &point->X, x1, z1, x2, z2, ctx)) goto err;
-				if (!gf2m_Mdouble(group, x2, z2, ctx)) goto err;
-				}
-			else
-				{
-				if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) goto err;
-				if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err;
-				}
+			BN_consttime_swap(scalar->d[i] & mask, x1, x2, group->field.top);
+			BN_consttime_swap(scalar->d[i] & mask, z1, z2, group->field.top);
+			if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) goto err;
+			if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err;
+			BN_consttime_swap(scalar->d[i] & mask, x1, x2, group->field.top);
+			BN_consttime_swap(scalar->d[i] & mask, z1, z2, group->field.top);
 			mask >>= 1;
 			}
 		j = BN_BITS2 - 1;

Modified: stable/8/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- stable/8/sys/fs/nfsserver/nfs_nfsdserv.c	Tue Apr  8 23:16:05 2014	(r264284)
+++ stable/8/sys/fs/nfsserver/nfs_nfsdserv.c	Tue Apr  8 23:16:19 2014	(r264285)
@@ -1446,10 +1446,23 @@ nfsrvd_rename(struct nfsrv_descript *nd,
 		nfsvno_relpathbuf(&fromnd);
 		goto out;
 	}
+	/*
+	 * Unlock dp in this code section, so it is unlocked before
+	 * tdp gets locked. This avoids a potential LOR if tdp is the
+	 * parent directory of dp.
+	 */
 	if (nd->nd_flag & ND_NFSV4) {
 		tdp = todp;
 		tnes = *toexp;
-		tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
+		if (dp != tdp) {
+			NFSVOPUNLOCK(dp, 0);
+			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
+			    p, 0);	/* Might lock tdp. */
+		} else {
+			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
+			    p, 1);
+			NFSVOPUNLOCK(dp, 0);
+		}
 	} else {
 		tfh.nfsrvfh_len = 0;
 		error = nfsrv_mtofh(nd, &tfh);
@@ -1470,10 +1483,12 @@ nfsrvd_rename(struct nfsrv_descript *nd,
 			tnes = *exp;
 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
 			    p, 1);
+			NFSVOPUNLOCK(dp, 0);
 		} else {
+			NFSVOPUNLOCK(dp, 0);
 			nd->nd_cred->cr_uid = nd->nd_saveduid;
 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
-			    0, p);
+			    0, p);	/* Locks tdp. */
 			if (tdp) {
 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
 				    nd->nd_cred, p, 1);
@@ -1488,7 +1503,7 @@ nfsrvd_rename(struct nfsrv_descript *nd,
 		if (error) {
 			if (tdp)
 				vrele(tdp);
-			vput(dp);
+			vrele(dp);
 			nfsvno_relpathbuf(&fromnd);
 			nfsvno_relpathbuf(&tond);
 			goto out;
@@ -1503,7 +1518,7 @@ nfsrvd_rename(struct nfsrv_descript *nd,
 		}
 		if (tdp)
 			vrele(tdp);
-		vput(dp);
+		vrele(dp);
 		nfsvno_relpathbuf(&fromnd);
 		nfsvno_relpathbuf(&tond);
 		goto out;
@@ -1512,7 +1527,7 @@ nfsrvd_rename(struct nfsrv_descript *nd,
 	/*
 	 * Done parsing, now down to business.
 	 */
-	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
+	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
 	if (nd->nd_repstat) {
 		if (nd->nd_flag & ND_NFSV3) {
 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201404082316.s38NGKt1068823>