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

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