Blame SOURCES/gnutls-3.6.14-fips-dh-check.patch

3f2b2e
From bea53f1b46a64d6dcf5bbe4794740c4d4459f9bf Mon Sep 17 00:00:00 2001
3f2b2e
From: Daiki Ueno <ueno@gnu.org>
3f2b2e
Date: Fri, 10 Jul 2020 09:35:49 +0200
3f2b2e
Subject: [PATCH 1/5] dh: check validity of Z before export
3f2b2e
3f2b2e
SP800-56A rev3 section 5.7.1.1 step 2 mandates that the validity of the
3f2b2e
calculated shared secret is verified before the data is returned to the
3f2b2e
caller.  This patch adds the validation check.
3f2b2e
3f2b2e
Suggested by Stephan Mueller.
3f2b2e
3f2b2e
Signed-off-by: Daiki Ueno <ueno@gnu.org>
3f2b2e
---
3f2b2e
 lib/nettle/pk.c | 26 +++++++++++++++++---------
3f2b2e
 1 file changed, 17 insertions(+), 9 deletions(-)
3f2b2e
3f2b2e
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
3f2b2e
index 57a8560ed..08c7d4860 100644
3f2b2e
--- a/lib/nettle/pk.c
3f2b2e
+++ b/lib/nettle/pk.c
3f2b2e
@@ -288,7 +288,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
3f2b2e
 	switch (algo) {
3f2b2e
 	case GNUTLS_PK_DH: {
3f2b2e
 		bigint_t f, x, q, prime;
3f2b2e
-		bigint_t k = NULL, ff = NULL, r = NULL;
3f2b2e
+		bigint_t k = NULL, primesub1 = NULL, r = NULL;
3f2b2e
 		unsigned int bits;
3f2b2e
 
3f2b2e
 		if (nonce != NULL)
3f2b2e
@@ -299,21 +299,20 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
3f2b2e
 		q = priv->params[DH_Q];
3f2b2e
 		prime = priv->params[DH_P];
3f2b2e
 
3f2b2e
-		ret = _gnutls_mpi_init_multi(&k, &ff, &r, NULL);
3f2b2e
+		ret = _gnutls_mpi_init_multi(&k, &primesub1, &r, NULL);
3f2b2e
 		if (ret < 0)
3f2b2e
 			return gnutls_assert_val(ret);
3f2b2e
 
3f2b2e
-		ret = _gnutls_mpi_add_ui(ff, f, 1);
3f2b2e
+		ret = _gnutls_mpi_sub_ui(primesub1, prime, 1);
3f2b2e
 		if (ret < 0) {
3f2b2e
 			gnutls_assert();
3f2b2e
 			goto dh_cleanup;
3f2b2e
 		}
3f2b2e
 
3f2b2e
-		/* check if f==0,1, or f >= p-1.
3f2b2e
-		 * or (ff=f+1) equivalently ff==1,2, ff >= p */
3f2b2e
-		if ((_gnutls_mpi_cmp_ui(ff, 2) == 0)
3f2b2e
-		    || (_gnutls_mpi_cmp_ui(ff, 1) == 0)
3f2b2e
-		    || (_gnutls_mpi_cmp(ff, prime) >= 0)) {
3f2b2e
+		/* check if f==0,1, or f >= p-1 */
3f2b2e
+		if ((_gnutls_mpi_cmp_ui(f, 1) == 0)
3f2b2e
+		    || (_gnutls_mpi_cmp_ui(f, 0) == 0)
3f2b2e
+		    || (_gnutls_mpi_cmp(f, primesub1) >= 0)) {
3f2b2e
 			gnutls_assert();
3f2b2e
 			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
3f2b2e
 			goto dh_cleanup;
3f2b2e
@@ -354,6 +353,15 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
3f2b2e
 			goto dh_cleanup;
3f2b2e
 		}
3f2b2e
 
3f2b2e
+		/* check if k==0,1, or k = p-1 */
3f2b2e
+		if ((_gnutls_mpi_cmp_ui(k, 1) == 0)
3f2b2e
+		    || (_gnutls_mpi_cmp_ui(k, 0) == 0)
3f2b2e
+		    || (_gnutls_mpi_cmp(k, primesub1) == 0)) {
3f2b2e
+			gnutls_assert();
3f2b2e
+			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
3f2b2e
+			goto dh_cleanup;
3f2b2e
+		}
3f2b2e
+
3f2b2e
 		if (flags & PK_DERIVE_TLS13) {
3f2b2e
 			ret =
3f2b2e
 			    _gnutls_mpi_dprint_size(k, out,
3f2b2e
@@ -370,7 +378,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
3f2b2e
 		ret = 0;
3f2b2e
 dh_cleanup:
3f2b2e
 		_gnutls_mpi_release(&r);
3f2b2e
-		_gnutls_mpi_release(&ff);
3f2b2e
+		_gnutls_mpi_release(&primesub1);
3f2b2e
 		zrelease_temp_mpi_key(&k);
3f2b2e
 		if (ret < 0)
3f2b2e
 			goto cleanup;
3f2b2e
-- 
3f2b2e
2.26.2
3f2b2e
3f2b2e
3f2b2e
From 13202600d3e42258d8758b05ff45a3e3d0f07e4e Mon Sep 17 00:00:00 2001
3f2b2e
From: Daiki Ueno <ueno@gnu.org>
3f2b2e
Date: Fri, 10 Jul 2020 09:42:30 +0200
3f2b2e
Subject: [PATCH 2/5] ecdh: check validity of P before export
3f2b2e
3f2b2e
SP800-56A rev3 section 5.7.1.2 step 2 mandates that the validity of
3f2b2e
the calculated shared secret is verified before the data is returned
3f2b2e
to the caller.  This patch adds the validation check.
3f2b2e
3f2b2e
Suggested by Stephan Mueller.
3f2b2e
3f2b2e
Signed-off-by: Daiki Ueno <ueno@gnu.org>
3f2b2e
---
3f2b2e
 lib/nettle/pk.c | 27 +++++++++++++++++++++------
3f2b2e
 1 file changed, 21 insertions(+), 6 deletions(-)
3f2b2e
3f2b2e
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
3f2b2e
index 08c7d4860..7f0fa8e03 100644
3f2b2e
--- a/lib/nettle/pk.c
3f2b2e
+++ b/lib/nettle/pk.c
3f2b2e
@@ -229,25 +229,38 @@ _gost_params_to_pubkey(const gnutls_pk_params_st * pk_params,
3f2b2e
 }
3f2b2e
 #endif
3f2b2e
 
3f2b2e
-static void
3f2b2e
+static int
3f2b2e
 ecc_shared_secret(struct ecc_scalar *private_key,
3f2b2e
 		  struct ecc_point *public_key, void *out, unsigned size)
3f2b2e
 {
3f2b2e
 	struct ecc_point r;
3f2b2e
-	mpz_t x;
3f2b2e
+	mpz_t x, y;
3f2b2e
+	int ret = 0;
3f2b2e
 
3f2b2e
 	mpz_init(x);
3f2b2e
+	mpz_init(y);
3f2b2e
 	ecc_point_init(&r, public_key->ecc);
3f2b2e
 
3f2b2e
 	ecc_point_mul(&r, private_key, public_key);
3f2b2e
 
3f2b2e
-	ecc_point_get(&r, x, NULL);
3f2b2e
+	ecc_point_get(&r, x, y);
3f2b2e
+
3f2b2e
+	/* Check if the point is not an identity element.  Note that this cannot
3f2b2e
+	 * happen in nettle implementation, because it cannot represent an
3f2b2e
+	 * infinity point. */
3f2b2e
+	if (mpz_cmp_ui(x, 0) == 0 && mpz_cmp_ui(y, 0) == 0) {
3f2b2e
+		ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
3f2b2e
+		goto cleanup;
3f2b2e
+	}
3f2b2e
+
3f2b2e
 	nettle_mpz_get_str_256(size, out, x);
3f2b2e
 
3f2b2e
+ cleanup:
3f2b2e
 	mpz_clear(x);
3f2b2e
+	mpz_clear(y);
3f2b2e
 	ecc_point_clear(&r);
3f2b2e
 
3f2b2e
-	return;
3f2b2e
+	return ret;
3f2b2e
 }
3f2b2e
 
3f2b2e
 #define MAX_DH_BITS DEFAULT_MAX_VERIFY_BITS
3f2b2e
@@ -423,8 +436,10 @@ dh_cleanup:
3f2b2e
 				goto ecc_cleanup;
3f2b2e
 			}
3f2b2e
 
3f2b2e
-			ecc_shared_secret(&ecc_priv, &ecc_pub, out->data,
3f2b2e
-					  out->size);
3f2b2e
+			ret = ecc_shared_secret(&ecc_priv, &ecc_pub, out->data,
3f2b2e
+						out->size);
3f2b2e
+			if (ret < 0)
3f2b2e
+				gnutls_free(out->data);
3f2b2e
 
3f2b2e
 		      ecc_cleanup:
3f2b2e
 			ecc_point_clear(&ecc_pub);
3f2b2e
-- 
3f2b2e
2.26.2
3f2b2e
3f2b2e
3f2b2e
From 245fb622e82bfa7b80d2cec7cafdbc65014ca3cb Mon Sep 17 00:00:00 2001
3f2b2e
From: Daiki Ueno <ueno@gnu.org>
3f2b2e
Date: Fri, 17 Jul 2020 17:45:17 +0200
3f2b2e
Subject: [PATCH 3/5] dh-primes: make the FIPS approved check return Q value
3f2b2e
3f2b2e
This is necessary for full public key validation in
3f2b2e
SP800-56A (revision 3), section 5.6.2.3.1.
3f2b2e
3f2b2e
Signed-off-by: Daiki Ueno <ueno@gnu.org>
3f2b2e
---
3f2b2e
 lib/auth/dh_common.c |  2 +-
3f2b2e
 lib/dh-primes.c      | 38 +++++++++++++++++++++++---------------
3f2b2e
 lib/dh.h             | 10 ++++++----
3f2b2e
 3 files changed, 30 insertions(+), 20 deletions(-)
3f2b2e
3f2b2e
diff --git a/lib/auth/dh_common.c b/lib/auth/dh_common.c
3f2b2e
index 252eea0cb..fcd696d4d 100644
3f2b2e
--- a/lib/auth/dh_common.c
3f2b2e
+++ b/lib/auth/dh_common.c
3f2b2e
@@ -259,7 +259,7 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session,
3f2b2e
 
3f2b2e
 #ifdef ENABLE_FIPS140
3f2b2e
 	if (gnutls_fips140_mode_enabled() &&
3f2b2e
-	    !_gnutls_dh_prime_is_fips_approved(data_p, n_p, data_g, n_g)) {
3f2b2e
+	    !_gnutls_dh_prime_match_fips_approved(data_p, n_p, data_g, n_g, NULL, NULL)) {
3f2b2e
 		gnutls_assert();
3f2b2e
 		return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
3f2b2e
 	}
3f2b2e
diff --git a/lib/dh-primes.c b/lib/dh-primes.c
3f2b2e
index a43a8e5de..a440b5b98 100644
3f2b2e
--- a/lib/dh-primes.c
3f2b2e
+++ b/lib/dh-primes.c
3f2b2e
@@ -1894,25 +1894,28 @@ const gnutls_datum_t gnutls_modp_8192_group_generator = {
3f2b2e
 const unsigned int gnutls_modp_8192_key_bits = 512;
3f2b2e
 
3f2b2e
 unsigned
3f2b2e
-_gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
3f2b2e
-				  size_t prime_size,
3f2b2e
-				  const uint8_t *generator,
3f2b2e
-				  size_t generator_size)
3f2b2e
+_gnutls_dh_prime_match_fips_approved(const uint8_t *prime,
3f2b2e
+				     size_t prime_size,
3f2b2e
+				     const uint8_t *generator,
3f2b2e
+				     size_t generator_size,
3f2b2e
+				     uint8_t **q,
3f2b2e
+				     size_t *q_size)
3f2b2e
 {
3f2b2e
 	static const struct {
3f2b2e
 		const gnutls_datum_t *prime;
3f2b2e
 		const gnutls_datum_t *generator;
3f2b2e
+		const gnutls_datum_t *q;
3f2b2e
 	} primes[] = {
3f2b2e
-		{ &gnutls_ffdhe_8192_group_prime, &gnutls_ffdhe_8192_group_generator },
3f2b2e
-		{ &gnutls_ffdhe_6144_group_prime, &gnutls_ffdhe_6144_group_generator },
3f2b2e
-		{ &gnutls_ffdhe_4096_group_prime, &gnutls_ffdhe_4096_group_generator },
3f2b2e
-		{ &gnutls_ffdhe_3072_group_prime, &gnutls_ffdhe_3072_group_generator },
3f2b2e
-		{ &gnutls_ffdhe_2048_group_prime, &gnutls_ffdhe_2048_group_generator },
3f2b2e
-		{ &gnutls_modp_8192_group_prime, &gnutls_modp_8192_group_generator },
3f2b2e
-		{ &gnutls_modp_6144_group_prime, &gnutls_modp_6144_group_generator },
3f2b2e
-		{ &gnutls_modp_4096_group_prime, &gnutls_modp_4096_group_generator },
3f2b2e
-		{ &gnutls_modp_3072_group_prime, &gnutls_modp_3072_group_generator },
3f2b2e
-		{ &gnutls_modp_2048_group_prime, &gnutls_modp_2048_group_generator },
3f2b2e
+		{ &gnutls_ffdhe_8192_group_prime, &gnutls_ffdhe_8192_group_generator, &gnutls_ffdhe_8192_group_q },
3f2b2e
+		{ &gnutls_ffdhe_6144_group_prime, &gnutls_ffdhe_6144_group_generator, &gnutls_ffdhe_6144_group_q },
3f2b2e
+		{ &gnutls_ffdhe_4096_group_prime, &gnutls_ffdhe_4096_group_generator, &gnutls_ffdhe_4096_group_q },
3f2b2e
+		{ &gnutls_ffdhe_3072_group_prime, &gnutls_ffdhe_3072_group_generator, &gnutls_ffdhe_3072_group_q },
3f2b2e
+		{ &gnutls_ffdhe_2048_group_prime, &gnutls_ffdhe_2048_group_generator, &gnutls_ffdhe_2048_group_q },
3f2b2e
+		{ &gnutls_modp_8192_group_prime, &gnutls_modp_8192_group_generator, &gnutls_modp_8192_group_q },
3f2b2e
+		{ &gnutls_modp_6144_group_prime, &gnutls_modp_6144_group_generator, &gnutls_modp_6144_group_q },
3f2b2e
+		{ &gnutls_modp_4096_group_prime, &gnutls_modp_4096_group_generator, &gnutls_modp_4096_group_q },
3f2b2e
+		{ &gnutls_modp_3072_group_prime, &gnutls_modp_3072_group_generator, &gnutls_modp_3072_group_q },
3f2b2e
+		{ &gnutls_modp_2048_group_prime, &gnutls_modp_2048_group_generator, &gnutls_modp_2048_group_q },
3f2b2e
 	};
3f2b2e
 	size_t i;
3f2b2e
 
3f2b2e
@@ -1920,8 +1923,13 @@ _gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
3f2b2e
 		if (primes[i].prime->size == prime_size &&
3f2b2e
 		    memcmp(primes[i].prime->data, prime, primes[i].prime->size) == 0 &&
3f2b2e
 		    primes[i].generator->size == generator_size &&
3f2b2e
-		    memcmp(primes[i].generator->data, generator, primes[i].generator->size) == 0)
3f2b2e
+		    memcmp(primes[i].generator->data, generator, primes[i].generator->size) == 0) {
3f2b2e
+			if (q) {
3f2b2e
+				*q = primes[i].q->data;
3f2b2e
+				*q_size = primes[i].q->size;
3f2b2e
+			}
3f2b2e
 			return 1;
3f2b2e
+		}
3f2b2e
 	}
3f2b2e
 
3f2b2e
 	return 0;
3f2b2e
diff --git a/lib/dh.h b/lib/dh.h
3f2b2e
index 672451947..f5c2c0924 100644
3f2b2e
--- a/lib/dh.h
3f2b2e
+++ b/lib/dh.h
3f2b2e
@@ -61,9 +61,11 @@ extern const gnutls_datum_t gnutls_modp_2048_group_generator;
3f2b2e
 extern const unsigned int gnutls_modp_2048_key_bits;
3f2b2e
 
3f2b2e
 unsigned
3f2b2e
-_gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
3f2b2e
-				  size_t prime_size,
3f2b2e
-				  const uint8_t *generator,
3f2b2e
-				  size_t generator_size);
3f2b2e
+_gnutls_dh_prime_match_fips_approved(const uint8_t *prime,
3f2b2e
+				     size_t prime_size,
3f2b2e
+				     const uint8_t *generator,
3f2b2e
+				     size_t generator_size,
3f2b2e
+				     uint8_t **q,
3f2b2e
+				     size_t *q_size);
3f2b2e
 
3f2b2e
 #endif /* GNUTLS_LIB_DH_H */
3f2b2e
-- 
3f2b2e
2.26.2
3f2b2e
3f2b2e
3f2b2e
From 8b575625614fbe5a22b68dc8d1877efb1d44dd37 Mon Sep 17 00:00:00 2001
3f2b2e
From: Daiki Ueno <ueno@gnu.org>
3f2b2e
Date: Fri, 17 Jul 2020 17:47:06 +0200
3f2b2e
Subject: [PATCH 4/5] dh: perform SP800-56A rev3 full pubkey validation on
3f2b2e
 keygen
3f2b2e
3f2b2e
This implements full public key validation required in SP800-56A rev3,
3f2b2e
section 5.6.2.3.1.
3f2b2e
3f2b2e
Signed-off-by: Daiki Ueno <ueno@gnu.org>
3f2b2e
---
3f2b2e
 lib/nettle/pk.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
3f2b2e
 1 file changed, 90 insertions(+)
3f2b2e
3f2b2e
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
3f2b2e
index 7f0fa8e03..057836bc2 100644
3f2b2e
--- a/lib/nettle/pk.c
3f2b2e
+++ b/lib/nettle/pk.c
3f2b2e
@@ -71,6 +71,7 @@
3f2b2e
 #include "int/dsa-compute-k.h"
3f2b2e
 #include <gnettle.h>
3f2b2e
 #include <fips.h>
3f2b2e
+#include "dh.h"
3f2b2e
 
3f2b2e
 static inline const struct ecc_curve *get_supported_nist_curve(int curve);
3f2b2e
 static inline const struct ecc_curve *get_supported_gost_curve(int curve);
3f2b2e
@@ -2131,6 +2132,53 @@ edwards_curve_mul_g(gnutls_pk_algorithm_t algo,
3f2b2e
 	}
3f2b2e
 }
3f2b2e
 
3f2b2e
+static inline int
3f2b2e
+dh_find_q(const gnutls_pk_params_st *pk_params, mpz_t q)
3f2b2e
+{
3f2b2e
+	gnutls_datum_t prime = { NULL, 0 };
3f2b2e
+	gnutls_datum_t generator = { NULL, 0 };
3f2b2e
+	uint8_t *data_q;
3f2b2e
+	size_t n_q;
3f2b2e
+	bigint_t _q;
3f2b2e
+	int ret = 0;
3f2b2e
+
3f2b2e
+	ret = _gnutls_mpi_dprint(pk_params->params[DSA_P], &prime);
3f2b2e
+	if (ret < 0) {
3f2b2e
+		gnutls_assert();
3f2b2e
+		goto cleanup;
3f2b2e
+	}
3f2b2e
+
3f2b2e
+	ret = _gnutls_mpi_dprint(pk_params->params[DSA_G], &generator);
3f2b2e
+	if (ret < 0) {
3f2b2e
+		gnutls_assert();
3f2b2e
+		goto cleanup;
3f2b2e
+	}
3f2b2e
+
3f2b2e
+	if (!_gnutls_dh_prime_match_fips_approved(prime.data,
3f2b2e
+						  prime.size,
3f2b2e
+						  generator.data,
3f2b2e
+						  generator.size,
3f2b2e
+						  &data_q,
3f2b2e
+						  &n_q)) {
3f2b2e
+		ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
3f2b2e
+		goto cleanup;
3f2b2e
+	}
3f2b2e
+
3f2b2e
+	if (_gnutls_mpi_init_scan_nz(&_q, data_q, n_q) != 0) {
3f2b2e
+		ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED);
3f2b2e
+		goto cleanup;
3f2b2e
+	}
3f2b2e
+
3f2b2e
+	mpz_set(q, TOMPZ(_q));
3f2b2e
+	_gnutls_mpi_release(&_q);
3f2b2e
+
3f2b2e
+ cleanup:
3f2b2e
+	gnutls_free(prime.data);
3f2b2e
+	gnutls_free(generator.data);
3f2b2e
+
3f2b2e
+	return ret;
3f2b2e
+}
3f2b2e
+
3f2b2e
 /* To generate a DH key either q must be set in the params or
3f2b2e
  * level should be set to the number of required bits.
3f2b2e
  */
3f2b2e
@@ -2212,6 +2260,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
3f2b2e
 			mpz_t x, y;
3f2b2e
 			int max_tries;
3f2b2e
 			unsigned have_q = 0;
3f2b2e
+			mpz_t q;
3f2b2e
+			mpz_t primesub1;
3f2b2e
+			mpz_t ypowq;
3f2b2e
 
3f2b2e
 			if (algo != params->algo)
3f2b2e
 				return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
3f2b2e
@@ -2229,6 +2280,10 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
3f2b2e
 			mpz_init(x);
3f2b2e
 			mpz_init(y);
3f2b2e
 
3f2b2e
+			mpz_init(q);
3f2b2e
+			mpz_init(primesub1);
3f2b2e
+			mpz_init(ypowq);
3f2b2e
+
3f2b2e
 			max_tries = 3;
3f2b2e
 			do {
3f2b2e
 				if (have_q) {
3f2b2e
@@ -2260,8 +2315,40 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
3f2b2e
 					ret = GNUTLS_E_LIB_IN_ERROR_STATE;
3f2b2e
 					goto dh_fail;
3f2b2e
 				}
3f2b2e
+
3f2b2e
 			} while(mpz_cmp_ui(y, 1) == 0);
3f2b2e
 
3f2b2e
+#ifdef ENABLE_FIPS140
3f2b2e
+			if (_gnutls_fips_mode_enabled()) {
3f2b2e
+				/* Perform FFC full public key validation checks
3f2b2e
+				 * according to SP800-56A (revision 3), 5.6.2.3.1.
3f2b2e
+				 */
3f2b2e
+
3f2b2e
+				/* Step 1: 2 <= y <= p - 2 */
3f2b2e
+				mpz_sub_ui(primesub1, pub.p, 1);
3f2b2e
+
3f2b2e
+				if (mpz_cmp_ui(y, 2) < 0 || mpz_cmp(y, primesub1) >= 0) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
3f2b2e
+					goto dh_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				/* Step 2: 1 = y^q mod p */
3f2b2e
+				if (have_q)
3f2b2e
+					mpz_set(q, pub.q);
3f2b2e
+				else {
3f2b2e
+					ret = dh_find_q(params, q);
3f2b2e
+					if (ret < 0)
3f2b2e
+						goto dh_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				mpz_powm(ypowq, y, q, pub.p);
3f2b2e
+				if (mpz_cmp_ui(ypowq, 1) != 0) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
3f2b2e
+					goto dh_fail;
3f2b2e
+				}
3f2b2e
+			}
3f2b2e
+#endif
3f2b2e
+
3f2b2e
 			ret = _gnutls_mpi_init_multi(&params->params[DSA_Y], &params->params[DSA_X], NULL);
3f2b2e
 			if (ret < 0) {
3f2b2e
 				gnutls_assert();
3f2b2e
@@ -2278,6 +2365,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
3f2b2e
 			mpz_clear(r);
3f2b2e
 			mpz_clear(x);
3f2b2e
 			mpz_clear(y);
3f2b2e
+			mpz_clear(q);
3f2b2e
+			mpz_clear(primesub1);
3f2b2e
+			mpz_clear(ypowq);
3f2b2e
 
3f2b2e
 			if (ret < 0)
3f2b2e
 				goto fail;
3f2b2e
-- 
3f2b2e
2.26.2
3f2b2e
3f2b2e
3f2b2e
From 23756c8580dff99d0856adca49dd22a55352ad62 Mon Sep 17 00:00:00 2001
3f2b2e
From: Daiki Ueno <ueno@gnu.org>
3f2b2e
Date: Sat, 18 Jul 2020 08:26:48 +0200
3f2b2e
Subject: [PATCH 5/5] ecdh: perform SP800-56A rev3 full pubkey validation on
3f2b2e
 keygen
3f2b2e
3f2b2e
This implements full public key validation required in
3f2b2e
SP800-56A rev3, section 5.6.2.3.3.
3f2b2e
3f2b2e
Signed-off-by: Daiki Ueno <ueno@gnu.org>
3f2b2e
---
3f2b2e
 lib/nettle/pk.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++-
3f2b2e
 1 file changed, 180 insertions(+), 2 deletions(-)
3f2b2e
3f2b2e
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
3f2b2e
index 057836bc2..588e9df50 100644
3f2b2e
--- a/lib/nettle/pk.c
3f2b2e
+++ b/lib/nettle/pk.c
3f2b2e
@@ -1552,6 +1552,80 @@ static inline const struct ecc_curve *get_supported_nist_curve(int curve)
3f2b2e
 	}
3f2b2e
 }
3f2b2e
 
3f2b2e
+static inline const char *get_supported_nist_curve_order(int curve)
3f2b2e
+{
3f2b2e
+	static const struct {
3f2b2e
+		int curve;
3f2b2e
+		const char *order;
3f2b2e
+	} orders[] = {
3f2b2e
+#ifdef ENABLE_NON_SUITEB_CURVES
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP192R1,
3f2b2e
+		  "ffffffffffffffffffffffff99def836"
3f2b2e
+		  "146bc9b1b4d22831" },
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP224R1,
3f2b2e
+		  "ffffffffffffffffffffffffffff16a2"
3f2b2e
+		  "e0b8f03e13dd29455c5c2a3d" },
3f2b2e
+#endif
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP256R1,
3f2b2e
+		  "ffffffff00000000ffffffffffffffff"
3f2b2e
+		  "bce6faada7179e84f3b9cac2fc632551" },
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP384R1,
3f2b2e
+		  "ffffffffffffffffffffffffffffffff"
3f2b2e
+		  "ffffffffffffffffc7634d81f4372ddf"
3f2b2e
+		  "581a0db248b0a77aecec196accc52973" },
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP521R1,
3f2b2e
+		  "1fffffffffffffffffffffffffffffff"
3f2b2e
+		  "ffffffffffffffffffffffffffffffff"
3f2b2e
+		  "ffa51868783bf2f966b7fcc0148f709a"
3f2b2e
+		  "5d03bb5c9b8899c47aebb6fb71e91386"
3f2b2e
+		  "409" },
3f2b2e
+	};
3f2b2e
+	size_t i;
3f2b2e
+
3f2b2e
+	for (i = 0; i < sizeof(orders)/sizeof(orders[0]); i++) {
3f2b2e
+		if (orders[i].curve == curve)
3f2b2e
+			return orders[i].order;
3f2b2e
+	}
3f2b2e
+	return NULL;
3f2b2e
+}
3f2b2e
+
3f2b2e
+static inline const char *get_supported_nist_curve_modulus(int curve)
3f2b2e
+{
3f2b2e
+	static const struct {
3f2b2e
+		int curve;
3f2b2e
+		const char *order;
3f2b2e
+	} orders[] = {
3f2b2e
+#ifdef ENABLE_NON_SUITEB_CURVES
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP192R1,
3f2b2e
+		  "fffffffffffffffffffffffffffffffe"
3f2b2e
+		  "ffffffffffffffff" },
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP224R1,
3f2b2e
+		  "ffffffffffffffffffffffffffffffff"
3f2b2e
+		  "000000000000000000000001" },
3f2b2e
+#endif
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP256R1,
3f2b2e
+		  "ffffffff000000010000000000000000"
3f2b2e
+		  "00000000ffffffffffffffffffffffff" },
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP384R1,
3f2b2e
+		  "ffffffffffffffffffffffffffffffff"
3f2b2e
+		  "fffffffffffffffffffffffffffffffe"
3f2b2e
+		  "ffffffff0000000000000000ffffffff" },
3f2b2e
+		{ GNUTLS_ECC_CURVE_SECP521R1,
3f2b2e
+		  "1ff"
3f2b2e
+		  "ffffffffffffffffffffffffffffffff"
3f2b2e
+		  "ffffffffffffffffffffffffffffffff"
3f2b2e
+		  "ffffffffffffffffffffffffffffffff"
3f2b2e
+		  "ffffffffffffffffffffffffffffffff" },
3f2b2e
+	};
3f2b2e
+	size_t i;
3f2b2e
+
3f2b2e
+	for (i = 0; i < sizeof(orders)/sizeof(orders[0]); i++) {
3f2b2e
+		if (orders[i].curve == curve)
3f2b2e
+			return orders[i].order;
3f2b2e
+	}
3f2b2e
+	return NULL;
3f2b2e
+}
3f2b2e
+
3f2b2e
 static inline const struct ecc_curve *get_supported_gost_curve(int curve)
3f2b2e
 {
3f2b2e
 	switch (curve) {
3f2b2e
@@ -2507,6 +2581,10 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
3f2b2e
 			struct ecc_scalar key;
3f2b2e
 			struct ecc_point pub;
3f2b2e
 			const struct ecc_curve *curve;
3f2b2e
+			struct ecc_scalar n;
3f2b2e
+			struct ecc_scalar m;
3f2b2e
+			struct ecc_point r;
3f2b2e
+			mpz_t x, y, xx, yy, nn, mm;
3f2b2e
 
3f2b2e
 			curve = get_supported_nist_curve(level);
3f2b2e
 			if (curve == NULL)
3f2b2e
@@ -2514,8 +2592,18 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
3f2b2e
 				    gnutls_assert_val
3f2b2e
 				    (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
3f2b2e
 
3f2b2e
+			mpz_init(x);
3f2b2e
+			mpz_init(y);
3f2b2e
+			mpz_init(xx);
3f2b2e
+			mpz_init(yy);
3f2b2e
+			mpz_init(nn);
3f2b2e
+			mpz_init(mm);
3f2b2e
+
3f2b2e
 			ecc_scalar_init(&key, curve);
3f2b2e
 			ecc_point_init(&pub, curve);
3f2b2e
+			ecc_scalar_init(&n, curve);
3f2b2e
+			ecc_scalar_init(&m, curve);
3f2b2e
+			ecc_point_init(&r, curve);
3f2b2e
 
3f2b2e
 			ecdsa_generate_keypair(&pub, &key, NULL, rnd_func);
3f2b2e
 			if (HAVE_LIB_ERROR()) {
3f2b2e
@@ -2533,15 +2621,105 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
3f2b2e
 			params->curve = level;
3f2b2e
 			params->params_nr = ECC_PRIVATE_PARAMS;
3f2b2e
 
3f2b2e
-			ecc_point_get(&pub, TOMPZ(params->params[ECC_X]),
3f2b2e
-				      TOMPZ(params->params[ECC_Y]));
3f2b2e
+			ecc_point_get(&pub, x, y);
3f2b2e
+
3f2b2e
+#ifdef ENABLE_FIPS140
3f2b2e
+			if (_gnutls_fips_mode_enabled()) {
3f2b2e
+				/* Perform ECC full public key validation checks
3f2b2e
+				 * according to SP800-56A (revision 3), 5.6.2.3.3.
3f2b2e
+				 */
3f2b2e
+
3f2b2e
+				const char *order, *modulus;
3f2b2e
+
3f2b2e
+				/* Step 1: verify that Q is not an identity
3f2b2e
+				 * element (an infinity point).  Note that this
3f2b2e
+				 * cannot happen in the nettle implementation,
3f2b2e
+				 * because it cannot represent an infinity point
3f2b2e
+				 * on curves. */
3f2b2e
+				if (mpz_cmp_ui(x, 0) == 0 && mpz_cmp_ui(y, 0) == 0) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
3f2b2e
+					goto ecc_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				/* Step 2: verify that both coordinates of Q are
3f2b2e
+				 * in the range [0, p - 1].
3f2b2e
+				 *
3f2b2e
+				 * Step 3: verify that Q lie on the curve
3f2b2e
+				 *
3f2b2e
+				 * Both checks are performed in nettle.  */
3f2b2e
+				if (!ecc_point_set(&r, x, y)) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
3f2b2e
+					goto ecc_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				/* Step 4: verify that n * Q, where n is the
3f2b2e
+				 * curve order, result in an identity element
3f2b2e
+				 *
3f2b2e
+				 * Since nettle internally cannot represent an
3f2b2e
+				 * identity element on curves, we validate this
3f2b2e
+				 * instead:
3f2b2e
+				 *
3f2b2e
+				 *   (n - 1) * Q = -Q
3f2b2e
+				 *
3f2b2e
+				 * That effectively means: n * Q = -Q + Q = O
3f2b2e
+				 */
3f2b2e
+				order = get_supported_nist_curve_order(level);
3f2b2e
+				if (unlikely(order == NULL)) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
3f2b2e
+					goto ecc_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				ret = mpz_set_str(nn, order, 16);
3f2b2e
+				if (unlikely(ret < 0)) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED);
3f2b2e
+					goto ecc_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				modulus = get_supported_nist_curve_modulus(level);
3f2b2e
+				if (unlikely(modulus == NULL)) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
3f2b2e
+					goto ecc_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				ret = mpz_set_str(mm, modulus, 16);
3f2b2e
+				if (unlikely(ret < 0)) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED);
3f2b2e
+					goto ecc_fail;
3f2b2e
+				}
3f2b2e
+
3f2b2e
+				/* (n - 1) * Q = -Q */
3f2b2e
+				mpz_sub_ui (nn, nn, 1);
3f2b2e
+				ecc_scalar_set(&n, nn);
3f2b2e
+				ecc_point_mul(&r, &n, &r);
3f2b2e
+				ecc_point_get(&r, xx, yy);
3f2b2e
+				mpz_sub (mm, mm, y);
3f2b2e
+
3f2b2e
+				if (mpz_cmp(xx, x) != 0 || mpz_cmp(yy, mm) != 0) {
3f2b2e
+					ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
3f2b2e
+					goto ecc_fail;
3f2b2e
+				}
3f2b2e
+			}
3f2b2e
+#endif
3f2b2e
+
3f2b2e
+			mpz_set(TOMPZ(params->params[ECC_X]), x);
3f2b2e
+			mpz_set(TOMPZ(params->params[ECC_Y]), y);
3f2b2e
+
3f2b2e
 			ecc_scalar_get(&key, TOMPZ(params->params[ECC_K]));
3f2b2e
 
3f2b2e
 			ret = 0;
3f2b2e
 
3f2b2e
 		      ecc_fail:
3f2b2e
+			mpz_clear(x);
3f2b2e
+			mpz_clear(y);
3f2b2e
+			mpz_clear(xx);
3f2b2e
+			mpz_clear(yy);
3f2b2e
+			mpz_clear(nn);
3f2b2e
+			mpz_clear(mm);
3f2b2e
 			ecc_point_clear(&pub;;
3f2b2e
 			ecc_scalar_clear(&key);
3f2b2e
+			ecc_point_clear(&r);
3f2b2e
+			ecc_scalar_clear(&n);
3f2b2e
+			ecc_scalar_clear(&m);
3f2b2e
 
3f2b2e
 			if (ret < 0)
3f2b2e
 				goto fail;
3f2b2e
-- 
3f2b2e
2.26.2
3f2b2e