shithub: riscv

Download patch

ref: 3bb0b9f4ea46431189b2cae2a6c2887f786d822a
parent: 844bbecadb3a4263a183ce03021849ac41cbd20f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Aug 26 01:59:42 EDT 2015

libsec: add q parameter to dh_new() for subgroup support, sanitize dh parameters

--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -447,15 +447,16 @@
 {
 	mpint	*g;	/* base g */
 	mpint	*p;	/* large prime */
+	mpint	*q;	/* subgroup prime */
 	mpint	*x;	/* random secret */
-	mpint	*y;	/* public key y = g ^ x % p */
+	mpint	*y;	/* public key y = g**x % p */
 };
 
-/* generate new public key: y = g ^ x % p */
-mpint* dh_new(DHstate *dh, mpint *p, mpint *g);
+/* generate new public key: y = g**x % p */
+mpint* dh_new(DHstate *dh, mpint *p, mpint *q, mpint *g);
 
-/* calculate shared key: k = pub ^ x % p */
-mpint* dh_finish(DHstate *dh, mpint *pub);
+/* calculate shared key: k = y**x % p */
+mpint* dh_finish(DHstate *dh, mpint *y);
 
 /* password-based key derivation function 2 (RFC 2898) */
 void pbkdf2_hmac_sha1(uchar *p, ulong plen, uchar *s, ulong slen, ulong rounds, uchar *d, ulong dlen);
--- a/sys/src/libsec/port/dh.c
+++ b/sys/src/libsec/port/dh.c
@@ -3,38 +3,72 @@
 #include <libsec.h>
 
 mpint*
-dh_new(DHstate *dh, mpint *p, mpint *g)
+dh_new(DHstate *dh, mpint *p, mpint *q, mpint *g)
 {
+	mpint *pm1;
+	int n;
+
 	memset(dh, 0, sizeof(*dh));
-	dh->g = mpcopy(g);
+	if(mpcmp(g, mpone) <= 0)
+		return nil;
+
+	n = mpsignif(p);
+	pm1 = mpnew(n);
+	mpsub(p, mpone, pm1);
 	dh->p = mpcopy(p);
-	if(dh->g != nil && dh->p != nil){
-		dh->x = mprand(mpsignif(dh->p), genrandom, nil);
-		dh->y = mpnew(0);
-		if(dh->x != nil && dh->y != nil){
-			mpexp(dh->g, dh->x, dh->p, dh->y);
-			return dh->y;
-		}
+	dh->g = mpcopy(g);
+	dh->q = mpcopy(q != nil ? q : pm1);
+	dh->x = mpnew(mpsignif(dh->q));
+	dh->y = mpnew(n);
+	for(;;){
+		mpnrand(dh->q, genrandom, dh->x);
+		mpexp(dh->g, dh->x, dh->p, dh->y);
+		if(mpcmp(dh->y, mpone) > 0 && mpcmp(dh->y, pm1) < 0)
+			break;
 	}
-	dh_finish(dh, nil);
-	return nil;
+	mpfree(pm1);
+
+	return dh->y;
 }
 
 mpint*
-dh_finish(DHstate *dh, mpint *pub)
+dh_finish(DHstate *dh, mpint *y)
 {
-	mpint *k;
+	mpint *k = nil;
 
-	k = nil;
-	if(pub != nil && dh->x != nil && dh->p != nil){
-		if((k = mpnew(0)) != nil)
-			mpexp(pub, dh->x, dh->p, k);
+	if(y == nil || dh->x == nil || dh->p == nil || dh->q == nil)
+		goto Out;
+
+	/* y > 1 */
+	if(mpcmp(y, mpone) <= 0)
+		goto Out;
+
+	k = mpnew(mpsignif(dh->p));
+
+	/* y < p-1 */
+	mpsub(dh->p, mpone, k);
+	if(mpcmp(y, k) >= 0){
+Bad:
+		mpfree(k);
+		k = nil;
+		goto Out;
 	}
-	mpfree(dh->g);
+
+	/* y**q % p == 1 if q < p-1 */
+	if(mpcmp(dh->q, k) < 0){
+		mpexp(y, dh->q, dh->p, k);
+		if(mpcmp(k, mpone) != 0)
+			goto Bad;
+	}
+
+	mpexp(y, dh->x, dh->p, k);
+
+Out:
 	mpfree(dh->p);
+	mpfree(dh->q);
+	mpfree(dh->g);
 	mpfree(dh->x);
 	mpfree(dh->y);
 	memset(dh, 0, sizeof(*dh));
 	return k;
 }
-
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -797,7 +797,7 @@
 	Y = bytestomp(Ys);
 	K = nil;
 
-	if(P == nil || G == nil || Y == nil || dh_new(&dh, P, G) == nil)
+	if(P == nil || G == nil || Y == nil || dh_new(&dh, P, nil, G) == nil)
 		goto Out;
 	epm = mptobytes(dh.y);
 	K = dh_finish(&dh, Y);