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

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