diff --git a/SOURCES/gnutls-3.6.14-fips-dh-check.patch b/SOURCES/gnutls-3.6.14-fips-dh-check.patch
new file mode 100644
index 0000000..40d579f
--- /dev/null
+++ b/SOURCES/gnutls-3.6.14-fips-dh-check.patch
@@ -0,0 +1,676 @@
+From bea53f1b46a64d6dcf5bbe4794740c4d4459f9bf Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 10 Jul 2020 09:35:49 +0200
+Subject: [PATCH 1/5] dh: check validity of Z before export
+
+SP800-56A rev3 section 5.7.1.1 step 2 mandates that the validity of the
+calculated shared secret is verified before the data is returned to the
+caller.  This patch adds the validation check.
+
+Suggested by Stephan Mueller.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/nettle/pk.c | 26 +++++++++++++++++---------
+ 1 file changed, 17 insertions(+), 9 deletions(-)
+
+diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
+index 57a8560ed..08c7d4860 100644
+--- a/lib/nettle/pk.c
++++ b/lib/nettle/pk.c
+@@ -288,7 +288,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
+ 	switch (algo) {
+ 	case GNUTLS_PK_DH: {
+ 		bigint_t f, x, q, prime;
+-		bigint_t k = NULL, ff = NULL, r = NULL;
++		bigint_t k = NULL, primesub1 = NULL, r = NULL;
+ 		unsigned int bits;
+ 
+ 		if (nonce != NULL)
+@@ -299,21 +299,20 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
+ 		q = priv->params[DH_Q];
+ 		prime = priv->params[DH_P];
+ 
+-		ret = _gnutls_mpi_init_multi(&k, &ff, &r, NULL);
++		ret = _gnutls_mpi_init_multi(&k, &primesub1, &r, NULL);
+ 		if (ret < 0)
+ 			return gnutls_assert_val(ret);
+ 
+-		ret = _gnutls_mpi_add_ui(ff, f, 1);
++		ret = _gnutls_mpi_sub_ui(primesub1, prime, 1);
+ 		if (ret < 0) {
+ 			gnutls_assert();
+ 			goto dh_cleanup;
+ 		}
+ 
+-		/* check if f==0,1, or f >= p-1.
+-		 * or (ff=f+1) equivalently ff==1,2, ff >= p */
+-		if ((_gnutls_mpi_cmp_ui(ff, 2) == 0)
+-		    || (_gnutls_mpi_cmp_ui(ff, 1) == 0)
+-		    || (_gnutls_mpi_cmp(ff, prime) >= 0)) {
++		/* check if f==0,1, or f >= p-1 */
++		if ((_gnutls_mpi_cmp_ui(f, 1) == 0)
++		    || (_gnutls_mpi_cmp_ui(f, 0) == 0)
++		    || (_gnutls_mpi_cmp(f, primesub1) >= 0)) {
+ 			gnutls_assert();
+ 			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ 			goto dh_cleanup;
+@@ -354,6 +353,15 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
+ 			goto dh_cleanup;
+ 		}
+ 
++		/* check if k==0,1, or k = p-1 */
++		if ((_gnutls_mpi_cmp_ui(k, 1) == 0)
++		    || (_gnutls_mpi_cmp_ui(k, 0) == 0)
++		    || (_gnutls_mpi_cmp(k, primesub1) == 0)) {
++			gnutls_assert();
++			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
++			goto dh_cleanup;
++		}
++
+ 		if (flags & PK_DERIVE_TLS13) {
+ 			ret =
+ 			    _gnutls_mpi_dprint_size(k, out,
+@@ -370,7 +378,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
+ 		ret = 0;
+ dh_cleanup:
+ 		_gnutls_mpi_release(&r);
+-		_gnutls_mpi_release(&ff);
++		_gnutls_mpi_release(&primesub1);
+ 		zrelease_temp_mpi_key(&k);
+ 		if (ret < 0)
+ 			goto cleanup;
+-- 
+2.26.2
+
+
+From 13202600d3e42258d8758b05ff45a3e3d0f07e4e Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 10 Jul 2020 09:42:30 +0200
+Subject: [PATCH 2/5] ecdh: check validity of P before export
+
+SP800-56A rev3 section 5.7.1.2 step 2 mandates that the validity of
+the calculated shared secret is verified before the data is returned
+to the caller.  This patch adds the validation check.
+
+Suggested by Stephan Mueller.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/nettle/pk.c | 27 +++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
+index 08c7d4860..7f0fa8e03 100644
+--- a/lib/nettle/pk.c
++++ b/lib/nettle/pk.c
+@@ -229,25 +229,38 @@ _gost_params_to_pubkey(const gnutls_pk_params_st * pk_params,
+ }
+ #endif
+ 
+-static void
++static int
+ ecc_shared_secret(struct ecc_scalar *private_key,
+ 		  struct ecc_point *public_key, void *out, unsigned size)
+ {
+ 	struct ecc_point r;
+-	mpz_t x;
++	mpz_t x, y;
++	int ret = 0;
+ 
+ 	mpz_init(x);
++	mpz_init(y);
+ 	ecc_point_init(&r, public_key->ecc);
+ 
+ 	ecc_point_mul(&r, private_key, public_key);
+ 
+-	ecc_point_get(&r, x, NULL);
++	ecc_point_get(&r, x, y);
++
++	/* Check if the point is not an identity element.  Note that this cannot
++	 * happen in nettle implementation, because it cannot represent an
++	 * infinity point. */
++	if (mpz_cmp_ui(x, 0) == 0 && mpz_cmp_ui(y, 0) == 0) {
++		ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
++		goto cleanup;
++	}
++
+ 	nettle_mpz_get_str_256(size, out, x);
+ 
++ cleanup:
+ 	mpz_clear(x);
++	mpz_clear(y);
+ 	ecc_point_clear(&r);
+ 
+-	return;
++	return ret;
+ }
+ 
+ #define MAX_DH_BITS DEFAULT_MAX_VERIFY_BITS
+@@ -423,8 +436,10 @@ dh_cleanup:
+ 				goto ecc_cleanup;
+ 			}
+ 
+-			ecc_shared_secret(&ecc_priv, &ecc_pub, out->data,
+-					  out->size);
++			ret = ecc_shared_secret(&ecc_priv, &ecc_pub, out->data,
++						out->size);
++			if (ret < 0)
++				gnutls_free(out->data);
+ 
+ 		      ecc_cleanup:
+ 			ecc_point_clear(&ecc_pub);
+-- 
+2.26.2
+
+
+From 245fb622e82bfa7b80d2cec7cafdbc65014ca3cb Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 17 Jul 2020 17:45:17 +0200
+Subject: [PATCH 3/5] dh-primes: make the FIPS approved check return Q value
+
+This is necessary for full public key validation in
+SP800-56A (revision 3), section 5.6.2.3.1.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/auth/dh_common.c |  2 +-
+ lib/dh-primes.c      | 38 +++++++++++++++++++++++---------------
+ lib/dh.h             | 10 ++++++----
+ 3 files changed, 30 insertions(+), 20 deletions(-)
+
+diff --git a/lib/auth/dh_common.c b/lib/auth/dh_common.c
+index 252eea0cb..fcd696d4d 100644
+--- a/lib/auth/dh_common.c
++++ b/lib/auth/dh_common.c
+@@ -259,7 +259,7 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session,
+ 
+ #ifdef ENABLE_FIPS140
+ 	if (gnutls_fips140_mode_enabled() &&
+-	    !_gnutls_dh_prime_is_fips_approved(data_p, n_p, data_g, n_g)) {
++	    !_gnutls_dh_prime_match_fips_approved(data_p, n_p, data_g, n_g, NULL, NULL)) {
+ 		gnutls_assert();
+ 		return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ 	}
+diff --git a/lib/dh-primes.c b/lib/dh-primes.c
+index a43a8e5de..a440b5b98 100644
+--- a/lib/dh-primes.c
++++ b/lib/dh-primes.c
+@@ -1894,25 +1894,28 @@ const gnutls_datum_t gnutls_modp_8192_group_generator = {
+ const unsigned int gnutls_modp_8192_key_bits = 512;
+ 
+ unsigned
+-_gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
+-				  size_t prime_size,
+-				  const uint8_t *generator,
+-				  size_t generator_size)
++_gnutls_dh_prime_match_fips_approved(const uint8_t *prime,
++				     size_t prime_size,
++				     const uint8_t *generator,
++				     size_t generator_size,
++				     uint8_t **q,
++				     size_t *q_size)
+ {
+ 	static const struct {
+ 		const gnutls_datum_t *prime;
+ 		const gnutls_datum_t *generator;
++		const gnutls_datum_t *q;
+ 	} primes[] = {
+-		{ &gnutls_ffdhe_8192_group_prime, &gnutls_ffdhe_8192_group_generator },
+-		{ &gnutls_ffdhe_6144_group_prime, &gnutls_ffdhe_6144_group_generator },
+-		{ &gnutls_ffdhe_4096_group_prime, &gnutls_ffdhe_4096_group_generator },
+-		{ &gnutls_ffdhe_3072_group_prime, &gnutls_ffdhe_3072_group_generator },
+-		{ &gnutls_ffdhe_2048_group_prime, &gnutls_ffdhe_2048_group_generator },
+-		{ &gnutls_modp_8192_group_prime, &gnutls_modp_8192_group_generator },
+-		{ &gnutls_modp_6144_group_prime, &gnutls_modp_6144_group_generator },
+-		{ &gnutls_modp_4096_group_prime, &gnutls_modp_4096_group_generator },
+-		{ &gnutls_modp_3072_group_prime, &gnutls_modp_3072_group_generator },
+-		{ &gnutls_modp_2048_group_prime, &gnutls_modp_2048_group_generator },
++		{ &gnutls_ffdhe_8192_group_prime, &gnutls_ffdhe_8192_group_generator, &gnutls_ffdhe_8192_group_q },
++		{ &gnutls_ffdhe_6144_group_prime, &gnutls_ffdhe_6144_group_generator, &gnutls_ffdhe_6144_group_q },
++		{ &gnutls_ffdhe_4096_group_prime, &gnutls_ffdhe_4096_group_generator, &gnutls_ffdhe_4096_group_q },
++		{ &gnutls_ffdhe_3072_group_prime, &gnutls_ffdhe_3072_group_generator, &gnutls_ffdhe_3072_group_q },
++		{ &gnutls_ffdhe_2048_group_prime, &gnutls_ffdhe_2048_group_generator, &gnutls_ffdhe_2048_group_q },
++		{ &gnutls_modp_8192_group_prime, &gnutls_modp_8192_group_generator, &gnutls_modp_8192_group_q },
++		{ &gnutls_modp_6144_group_prime, &gnutls_modp_6144_group_generator, &gnutls_modp_6144_group_q },
++		{ &gnutls_modp_4096_group_prime, &gnutls_modp_4096_group_generator, &gnutls_modp_4096_group_q },
++		{ &gnutls_modp_3072_group_prime, &gnutls_modp_3072_group_generator, &gnutls_modp_3072_group_q },
++		{ &gnutls_modp_2048_group_prime, &gnutls_modp_2048_group_generator, &gnutls_modp_2048_group_q },
+ 	};
+ 	size_t i;
+ 
+@@ -1920,8 +1923,13 @@ _gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
+ 		if (primes[i].prime->size == prime_size &&
+ 		    memcmp(primes[i].prime->data, prime, primes[i].prime->size) == 0 &&
+ 		    primes[i].generator->size == generator_size &&
+-		    memcmp(primes[i].generator->data, generator, primes[i].generator->size) == 0)
++		    memcmp(primes[i].generator->data, generator, primes[i].generator->size) == 0) {
++			if (q) {
++				*q = primes[i].q->data;
++				*q_size = primes[i].q->size;
++			}
+ 			return 1;
++		}
+ 	}
+ 
+ 	return 0;
+diff --git a/lib/dh.h b/lib/dh.h
+index 672451947..f5c2c0924 100644
+--- a/lib/dh.h
++++ b/lib/dh.h
+@@ -61,9 +61,11 @@ extern const gnutls_datum_t gnutls_modp_2048_group_generator;
+ extern const unsigned int gnutls_modp_2048_key_bits;
+ 
+ unsigned
+-_gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
+-				  size_t prime_size,
+-				  const uint8_t *generator,
+-				  size_t generator_size);
++_gnutls_dh_prime_match_fips_approved(const uint8_t *prime,
++				     size_t prime_size,
++				     const uint8_t *generator,
++				     size_t generator_size,
++				     uint8_t **q,
++				     size_t *q_size);
+ 
+ #endif /* GNUTLS_LIB_DH_H */
+-- 
+2.26.2
+
+
+From 8b575625614fbe5a22b68dc8d1877efb1d44dd37 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 17 Jul 2020 17:47:06 +0200
+Subject: [PATCH 4/5] dh: perform SP800-56A rev3 full pubkey validation on
+ keygen
+
+This implements full public key validation required in SP800-56A rev3,
+section 5.6.2.3.1.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/nettle/pk.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 90 insertions(+)
+
+diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
+index 7f0fa8e03..057836bc2 100644
+--- a/lib/nettle/pk.c
++++ b/lib/nettle/pk.c
+@@ -71,6 +71,7 @@
+ #include "int/dsa-compute-k.h"
+ #include <gnettle.h>
+ #include <fips.h>
++#include "dh.h"
+ 
+ static inline const struct ecc_curve *get_supported_nist_curve(int curve);
+ static inline const struct ecc_curve *get_supported_gost_curve(int curve);
+@@ -2131,6 +2132,53 @@ edwards_curve_mul_g(gnutls_pk_algorithm_t algo,
+ 	}
+ }
+ 
++static inline int
++dh_find_q(const gnutls_pk_params_st *pk_params, mpz_t q)
++{
++	gnutls_datum_t prime = { NULL, 0 };
++	gnutls_datum_t generator = { NULL, 0 };
++	uint8_t *data_q;
++	size_t n_q;
++	bigint_t _q;
++	int ret = 0;
++
++	ret = _gnutls_mpi_dprint(pk_params->params[DSA_P], &prime);
++	if (ret < 0) {
++		gnutls_assert();
++		goto cleanup;
++	}
++
++	ret = _gnutls_mpi_dprint(pk_params->params[DSA_G], &generator);
++	if (ret < 0) {
++		gnutls_assert();
++		goto cleanup;
++	}
++
++	if (!_gnutls_dh_prime_match_fips_approved(prime.data,
++						  prime.size,
++						  generator.data,
++						  generator.size,
++						  &data_q,
++						  &n_q)) {
++		ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
++		goto cleanup;
++	}
++
++	if (_gnutls_mpi_init_scan_nz(&_q, data_q, n_q) != 0) {
++		ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED);
++		goto cleanup;
++	}
++
++	mpz_set(q, TOMPZ(_q));
++	_gnutls_mpi_release(&_q);
++
++ cleanup:
++	gnutls_free(prime.data);
++	gnutls_free(generator.data);
++
++	return ret;
++}
++
+ /* To generate a DH key either q must be set in the params or
+  * level should be set to the number of required bits.
+  */
+@@ -2212,6 +2260,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
+ 			mpz_t x, y;
+ 			int max_tries;
+ 			unsigned have_q = 0;
++			mpz_t q;
++			mpz_t primesub1;
++			mpz_t ypowq;
+ 
+ 			if (algo != params->algo)
+ 				return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+@@ -2229,6 +2280,10 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
+ 			mpz_init(x);
+ 			mpz_init(y);
+ 
++			mpz_init(q);
++			mpz_init(primesub1);
++			mpz_init(ypowq);
++
+ 			max_tries = 3;
+ 			do {
+ 				if (have_q) {
+@@ -2260,8 +2315,40 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
+ 					ret = GNUTLS_E_LIB_IN_ERROR_STATE;
+ 					goto dh_fail;
+ 				}
++
+ 			} while(mpz_cmp_ui(y, 1) == 0);
+ 
++#ifdef ENABLE_FIPS140
++			if (_gnutls_fips_mode_enabled()) {
++				/* Perform FFC full public key validation checks
++				 * according to SP800-56A (revision 3), 5.6.2.3.1.
++				 */
++
++				/* Step 1: 2 <= y <= p - 2 */
++				mpz_sub_ui(primesub1, pub.p, 1);
++
++				if (mpz_cmp_ui(y, 2) < 0 || mpz_cmp(y, primesub1) >= 0) {
++					ret = gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
++					goto dh_fail;
++				}
++
++				/* Step 2: 1 = y^q mod p */
++				if (have_q)
++					mpz_set(q, pub.q);
++				else {
++					ret = dh_find_q(params, q);
++					if (ret < 0)
++						goto dh_fail;
++				}
++
++				mpz_powm(ypowq, y, q, pub.p);
++				if (mpz_cmp_ui(ypowq, 1) != 0) {
++					ret = gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
++					goto dh_fail;
++				}
++			}
++#endif
++
+ 			ret = _gnutls_mpi_init_multi(&params->params[DSA_Y], &params->params[DSA_X], NULL);
+ 			if (ret < 0) {
+ 				gnutls_assert();
+@@ -2278,6 +2365,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
+ 			mpz_clear(r);
+ 			mpz_clear(x);
+ 			mpz_clear(y);
++			mpz_clear(q);
++			mpz_clear(primesub1);
++			mpz_clear(ypowq);
+ 
+ 			if (ret < 0)
+ 				goto fail;
+-- 
+2.26.2
+
+
+From 23756c8580dff99d0856adca49dd22a55352ad62 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Sat, 18 Jul 2020 08:26:48 +0200
+Subject: [PATCH 5/5] ecdh: perform SP800-56A rev3 full pubkey validation on
+ keygen
+
+This implements full public key validation required in
+SP800-56A rev3, section 5.6.2.3.3.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/nettle/pk.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 180 insertions(+), 2 deletions(-)
+
+diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
+index 057836bc2..588e9df50 100644
+--- a/lib/nettle/pk.c
++++ b/lib/nettle/pk.c
+@@ -1552,6 +1552,80 @@ static inline const struct ecc_curve *get_supported_nist_curve(int curve)
+ 	}
+ }
+ 
++static inline const char *get_supported_nist_curve_order(int curve)
++{
++	static const struct {
++		int curve;
++		const char *order;
++	} orders[] = {
++#ifdef ENABLE_NON_SUITEB_CURVES
++		{ GNUTLS_ECC_CURVE_SECP192R1,
++		  "ffffffffffffffffffffffff99def836"
++		  "146bc9b1b4d22831" },
++		{ GNUTLS_ECC_CURVE_SECP224R1,
++		  "ffffffffffffffffffffffffffff16a2"
++		  "e0b8f03e13dd29455c5c2a3d" },
++#endif
++		{ GNUTLS_ECC_CURVE_SECP256R1,
++		  "ffffffff00000000ffffffffffffffff"
++		  "bce6faada7179e84f3b9cac2fc632551" },
++		{ GNUTLS_ECC_CURVE_SECP384R1,
++		  "ffffffffffffffffffffffffffffffff"
++		  "ffffffffffffffffc7634d81f4372ddf"
++		  "581a0db248b0a77aecec196accc52973" },
++		{ GNUTLS_ECC_CURVE_SECP521R1,
++		  "1fffffffffffffffffffffffffffffff"
++		  "ffffffffffffffffffffffffffffffff"
++		  "ffa51868783bf2f966b7fcc0148f709a"
++		  "5d03bb5c9b8899c47aebb6fb71e91386"
++		  "409" },
++	};
++	size_t i;
++
++	for (i = 0; i < sizeof(orders)/sizeof(orders[0]); i++) {
++		if (orders[i].curve == curve)
++			return orders[i].order;
++	}
++	return NULL;
++}
++
++static inline const char *get_supported_nist_curve_modulus(int curve)
++{
++	static const struct {
++		int curve;
++		const char *order;
++	} orders[] = {
++#ifdef ENABLE_NON_SUITEB_CURVES
++		{ GNUTLS_ECC_CURVE_SECP192R1,
++		  "fffffffffffffffffffffffffffffffe"
++		  "ffffffffffffffff" },
++		{ GNUTLS_ECC_CURVE_SECP224R1,
++		  "ffffffffffffffffffffffffffffffff"
++		  "000000000000000000000001" },
++#endif
++		{ GNUTLS_ECC_CURVE_SECP256R1,
++		  "ffffffff000000010000000000000000"
++		  "00000000ffffffffffffffffffffffff" },
++		{ GNUTLS_ECC_CURVE_SECP384R1,
++		  "ffffffffffffffffffffffffffffffff"
++		  "fffffffffffffffffffffffffffffffe"
++		  "ffffffff0000000000000000ffffffff" },
++		{ GNUTLS_ECC_CURVE_SECP521R1,
++		  "1ff"
++		  "ffffffffffffffffffffffffffffffff"
++		  "ffffffffffffffffffffffffffffffff"
++		  "ffffffffffffffffffffffffffffffff"
++		  "ffffffffffffffffffffffffffffffff" },
++	};
++	size_t i;
++
++	for (i = 0; i < sizeof(orders)/sizeof(orders[0]); i++) {
++		if (orders[i].curve == curve)
++			return orders[i].order;
++	}
++	return NULL;
++}
++
+ static inline const struct ecc_curve *get_supported_gost_curve(int curve)
+ {
+ 	switch (curve) {
+@@ -2507,6 +2581,10 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
+ 			struct ecc_scalar key;
+ 			struct ecc_point pub;
+ 			const struct ecc_curve *curve;
++			struct ecc_scalar n;
++			struct ecc_scalar m;
++			struct ecc_point r;
++			mpz_t x, y, xx, yy, nn, mm;
+ 
+ 			curve = get_supported_nist_curve(level);
+ 			if (curve == NULL)
+@@ -2514,8 +2592,18 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
+ 				    gnutls_assert_val
+ 				    (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+ 
++			mpz_init(x);
++			mpz_init(y);
++			mpz_init(xx);
++			mpz_init(yy);
++			mpz_init(nn);
++			mpz_init(mm);
++
+ 			ecc_scalar_init(&key, curve);
+ 			ecc_point_init(&pub, curve);
++			ecc_scalar_init(&n, curve);
++			ecc_scalar_init(&m, curve);
++			ecc_point_init(&r, curve);
+ 
+ 			ecdsa_generate_keypair(&pub, &key, NULL, rnd_func);
+ 			if (HAVE_LIB_ERROR()) {
+@@ -2533,15 +2621,105 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
+ 			params->curve = level;
+ 			params->params_nr = ECC_PRIVATE_PARAMS;
+ 
+-			ecc_point_get(&pub, TOMPZ(params->params[ECC_X]),
+-				      TOMPZ(params->params[ECC_Y]));
++			ecc_point_get(&pub, x, y);
++
++#ifdef ENABLE_FIPS140
++			if (_gnutls_fips_mode_enabled()) {
++				/* Perform ECC full public key validation checks
++				 * according to SP800-56A (revision 3), 5.6.2.3.3.
++				 */
++
++				const char *order, *modulus;
++
++				/* Step 1: verify that Q is not an identity
++				 * element (an infinity point).  Note that this
++				 * cannot happen in the nettle implementation,
++				 * because it cannot represent an infinity point
++				 * on curves. */
++				if (mpz_cmp_ui(x, 0) == 0 && mpz_cmp_ui(y, 0) == 0) {
++					ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
++					goto ecc_fail;
++				}
++
++				/* Step 2: verify that both coordinates of Q are
++				 * in the range [0, p - 1].
++				 *
++				 * Step 3: verify that Q lie on the curve
++				 *
++				 * Both checks are performed in nettle.  */
++				if (!ecc_point_set(&r, x, y)) {
++					ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
++					goto ecc_fail;
++				}
++
++				/* Step 4: verify that n * Q, where n is the
++				 * curve order, result in an identity element
++				 *
++				 * Since nettle internally cannot represent an
++				 * identity element on curves, we validate this
++				 * instead:
++				 *
++				 *   (n - 1) * Q = -Q
++				 *
++				 * That effectively means: n * Q = -Q + Q = O
++				 */
++				order = get_supported_nist_curve_order(level);
++				if (unlikely(order == NULL)) {
++					ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
++					goto ecc_fail;
++				}
++
++				ret = mpz_set_str(nn, order, 16);
++				if (unlikely(ret < 0)) {
++					ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED);
++					goto ecc_fail;
++				}
++
++				modulus = get_supported_nist_curve_modulus(level);
++				if (unlikely(modulus == NULL)) {
++					ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
++					goto ecc_fail;
++				}
++
++				ret = mpz_set_str(mm, modulus, 16);
++				if (unlikely(ret < 0)) {
++					ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED);
++					goto ecc_fail;
++				}
++
++				/* (n - 1) * Q = -Q */
++				mpz_sub_ui (nn, nn, 1);
++				ecc_scalar_set(&n, nn);
++				ecc_point_mul(&r, &n, &r);
++				ecc_point_get(&r, xx, yy);
++				mpz_sub (mm, mm, y);
++
++				if (mpz_cmp(xx, x) != 0 || mpz_cmp(yy, mm) != 0) {
++					ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
++					goto ecc_fail;
++				}
++			}
++#endif
++
++			mpz_set(TOMPZ(params->params[ECC_X]), x);
++			mpz_set(TOMPZ(params->params[ECC_Y]), y);
++
+ 			ecc_scalar_get(&key, TOMPZ(params->params[ECC_K]));
+ 
+ 			ret = 0;
+ 
+ 		      ecc_fail:
++			mpz_clear(x);
++			mpz_clear(y);
++			mpz_clear(xx);
++			mpz_clear(yy);
++			mpz_clear(nn);
++			mpz_clear(mm);
+ 			ecc_point_clear(&pub);
+ 			ecc_scalar_clear(&key);
++			ecc_point_clear(&r);
++			ecc_scalar_clear(&n);
++			ecc_scalar_clear(&m);
+ 
+ 			if (ret < 0)
+ 				goto fail;
+-- 
+2.26.2
+
diff --git a/SOURCES/gnutls-3.6.14-fips-dh-primes.patch b/SOURCES/gnutls-3.6.14-fips-dh-primes.patch
new file mode 100644
index 0000000..4aa5846
--- /dev/null
+++ b/SOURCES/gnutls-3.6.14-fips-dh-primes.patch
@@ -0,0 +1,1843 @@
+From 481e48f3236be42ff1fcb96f96c4efcbb2b69242 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 26 Jun 2020 09:43:02 +0200
+Subject: [PATCH 1/2] dh-primes: add MODP primes from RFC 3526
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/dh-primes.c | 933 ++++++++++++++++++++++++++++++++++++++++++++++++
+ lib/dh.h        |  29 ++
+ 2 files changed, 962 insertions(+)
+
+diff --git a/lib/dh-primes.c b/lib/dh-primes.c
+index d785584d0..5d2dce0fb 100644
+--- a/lib/dh-primes.c
++++ b/lib/dh-primes.c
+@@ -960,4 +960,937 @@ const gnutls_datum_t gnutls_ffdhe_8192_group_generator = {
+ };
+ const unsigned int gnutls_ffdhe_8192_key_bits = 512;
+ 
++static const unsigned char modp_generator = 0x02;
++
++static const unsigned char modp_params_2048[] = {
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68,
++	0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80,
++	0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08,
++	0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE,
++	0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A,
++	0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF,
++	0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14,
++	0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51,
++	0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62,
++	0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
++	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C,
++	0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38,
++	0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE,
++	0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B,
++	0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63,
++	0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C,
++	0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8,
++	0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D,
++	0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62,
++	0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E,
++	0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98,
++	0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18,
++	0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E,
++	0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C,
++	0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83,
++	0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5,
++	0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE,
++	0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A,
++	0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA,
++	0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A,
++	0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xFF, 0xFF, 0xFF
++};
++
++static const unsigned char modp_q_2048[] = {
++	0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4,
++	0x61, 0x1A, 0x62, 0x63, 0x31, 0x45, 0xC0,
++	0x6E, 0x0E, 0x68, 0x94, 0x81, 0x27, 0x04,
++	0x45, 0x33, 0xE6, 0x3A, 0x01, 0x05, 0xDF,
++	0x53, 0x1D, 0x89, 0xCD, 0x91, 0x28, 0xA5,
++	0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, 0xF7,
++	0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
++	0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A,
++	0x1B, 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8,
++	0xE1, 0x22, 0xF2, 0x42, 0xDA, 0xBB, 0x31,
++	0x2F, 0x3F, 0x63, 0x7A, 0x26, 0x21, 0x74,
++	0xD3, 0x1B, 0xF6, 0xB5, 0x85, 0xFF, 0xAE,
++	0x5B, 0x7A, 0x03, 0x5B, 0xF6, 0xF7, 0x1C,
++	0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, 0xD7,
++	0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
++	0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D,
++	0x9E, 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1,
++	0xDF, 0x82, 0xCC, 0x6D, 0x24, 0x1B, 0x0E,
++	0x2A, 0xE9, 0xCD, 0x34, 0x8B, 0x1F, 0xD4,
++	0x7E, 0x92, 0x67, 0xAF, 0xC1, 0xB2, 0xAE,
++	0x91, 0xEE, 0x51, 0xD6, 0xCB, 0x0E, 0x31,
++	0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, 0xCF,
++	0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
++	0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C,
++	0x02, 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C,
++	0x10, 0xBE, 0x19, 0x48, 0x2F, 0x23, 0x17,
++	0x1B, 0x67, 0x1D, 0xF1, 0xCF, 0x3B, 0x96,
++	0x0C, 0x07, 0x43, 0x01, 0xCD, 0x93, 0xC1,
++	0xD1, 0x76, 0x03, 0xD1, 0x47, 0xDA, 0xE2,
++	0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, 0xEF,
++	0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
++	0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5,
++	0x72, 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D,
++	0x02, 0x88, 0x0A, 0xB9, 0x47, 0x2D, 0x45,
++	0x56, 0x55, 0x34, 0x7F, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xFF, 0xFF, 0xFF
++};
++
++const gnutls_datum_t gnutls_modp_2048_group_prime = {
++	(void *) modp_params_2048, sizeof(modp_params_2048)
++};
++const gnutls_datum_t gnutls_modp_2048_group_q = {
++	(void *) modp_q_2048, sizeof(modp_q_2048)
++};
++const gnutls_datum_t gnutls_modp_2048_group_generator = {
++	(void *) &modp_generator, sizeof(modp_generator)
++};
++const unsigned int gnutls_modp_2048_key_bits = 256;
++
++static const unsigned char modp_params_3072[] = {
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68,
++	0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80,
++	0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08,
++	0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE,
++	0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A,
++	0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF,
++	0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14,
++	0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51,
++	0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62,
++	0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
++	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C,
++	0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38,
++	0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE,
++	0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B,
++	0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63,
++	0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C,
++	0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8,
++	0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D,
++	0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62,
++	0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E,
++	0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98,
++	0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18,
++	0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E,
++	0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C,
++	0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83,
++	0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5,
++	0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE,
++	0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A,
++	0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA,
++	0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A,
++	0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D,
++	0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21,
++	0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB,
++	0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A,
++	0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4,
++	0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09,
++	0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A,
++	0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26,
++	0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA,
++	0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76,
++	0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52,
++	0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D,
++	0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9,
++	0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74,
++	0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC,
++	0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1,
++	0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF,
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++};
++
++static const unsigned char modp_q_3072[] = {
++	0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4,
++	0x61, 0x1A, 0x62, 0x63, 0x31, 0x45, 0xC0,
++	0x6E, 0x0E, 0x68, 0x94, 0x81, 0x27, 0x04,
++	0x45, 0x33, 0xE6, 0x3A, 0x01, 0x05, 0xDF,
++	0x53, 0x1D, 0x89, 0xCD, 0x91, 0x28, 0xA5,
++	0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, 0xF7,
++	0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
++	0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A,
++	0x1B, 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8,
++	0xE1, 0x22, 0xF2, 0x42, 0xDA, 0xBB, 0x31,
++	0x2F, 0x3F, 0x63, 0x7A, 0x26, 0x21, 0x74,
++	0xD3, 0x1B, 0xF6, 0xB5, 0x85, 0xFF, 0xAE,
++	0x5B, 0x7A, 0x03, 0x5B, 0xF6, 0xF7, 0x1C,
++	0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, 0xD7,
++	0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
++	0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D,
++	0x9E, 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1,
++	0xDF, 0x82, 0xCC, 0x6D, 0x24, 0x1B, 0x0E,
++	0x2A, 0xE9, 0xCD, 0x34, 0x8B, 0x1F, 0xD4,
++	0x7E, 0x92, 0x67, 0xAF, 0xC1, 0xB2, 0xAE,
++	0x91, 0xEE, 0x51, 0xD6, 0xCB, 0x0E, 0x31,
++	0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, 0xCF,
++	0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
++	0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C,
++	0x02, 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C,
++	0x10, 0xBE, 0x19, 0x48, 0x2F, 0x23, 0x17,
++	0x1B, 0x67, 0x1D, 0xF1, 0xCF, 0x3B, 0x96,
++	0x0C, 0x07, 0x43, 0x01, 0xCD, 0x93, 0xC1,
++	0xD1, 0x76, 0x03, 0xD1, 0x47, 0xDA, 0xE2,
++	0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, 0xEF,
++	0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
++	0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5,
++	0x72, 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D,
++	0x02, 0x88, 0x0A, 0xB9, 0x47, 0x2D, 0x45,
++	0x55, 0x62, 0x16, 0xD6, 0x99, 0x8B, 0x86,
++	0x82, 0x28, 0x3D, 0x19, 0xD4, 0x2A, 0x90,
++	0xD5, 0xEF, 0x8E, 0x5D, 0x32, 0x76, 0x7D,
++	0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, 0x45,
++	0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
++	0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2,
++	0x63, 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84,
++	0x99, 0xEB, 0x8F, 0x46, 0x4A, 0x70, 0x25,
++	0x12, 0xB0, 0xCE, 0xE7, 0x71, 0xE9, 0x13,
++	0x0D, 0x69, 0x77, 0x35, 0xF8, 0x97, 0xFD,
++	0x03, 0x6C, 0xC5, 0x04, 0x32, 0x6C, 0x3B,
++	0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, 0x29,
++	0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
++	0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE,
++	0xB6, 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C,
++	0xA3, 0x71, 0x04, 0x71, 0x27, 0xD0, 0x3A,
++	0x72, 0xD5, 0x98, 0xA1, 0xED, 0xAD, 0xFE,
++	0x70, 0x7E, 0x88, 0x47, 0x25, 0xC1, 0x68,
++	0x90, 0x54, 0x9D, 0x69, 0x65, 0x7F, 0xFF,
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++};
++
++const gnutls_datum_t gnutls_modp_3072_group_prime = {
++	(void *) modp_params_3072, sizeof(modp_params_3072)
++};
++const gnutls_datum_t gnutls_modp_3072_group_q = {
++	(void *) modp_q_3072, sizeof(modp_q_3072)
++};
++const gnutls_datum_t gnutls_modp_3072_group_generator = {
++	(void *) &modp_generator, sizeof(modp_generator)
++};
++const unsigned int gnutls_modp_3072_key_bits = 276;
++
++static const unsigned char modp_params_4096[] = {
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68,
++	0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80,
++	0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08,
++	0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE,
++	0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A,
++	0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF,
++	0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14,
++	0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51,
++	0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62,
++	0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
++	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C,
++	0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38,
++	0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE,
++	0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B,
++	0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63,
++	0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C,
++	0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8,
++	0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D,
++	0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62,
++	0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E,
++	0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98,
++	0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18,
++	0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E,
++	0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C,
++	0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83,
++	0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5,
++	0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE,
++	0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A,
++	0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA,
++	0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A,
++	0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D,
++	0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21,
++	0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB,
++	0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A,
++	0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4,
++	0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09,
++	0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A,
++	0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26,
++	0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA,
++	0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76,
++	0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52,
++	0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D,
++	0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9,
++	0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74,
++	0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC,
++	0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1,
++	0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72,
++	0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88,
++	0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
++	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2,
++	0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15,
++	0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A,
++	0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB,
++	0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC,
++	0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C,
++	0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99,
++	0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
++	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7,
++	0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2,
++	0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21,
++	0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27,
++	0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA,
++	0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF,
++	0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D,
++	0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF
++};
++
++static const unsigned char modp_q_4096[] = {
++	0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4,
++	0x61, 0x1A, 0x62, 0x63, 0x31, 0x45, 0xC0,
++	0x6E, 0x0E, 0x68, 0x94, 0x81, 0x27, 0x04,
++	0x45, 0x33, 0xE6, 0x3A, 0x01, 0x05, 0xDF,
++	0x53, 0x1D, 0x89, 0xCD, 0x91, 0x28, 0xA5,
++	0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, 0xF7,
++	0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
++	0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A,
++	0x1B, 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8,
++	0xE1, 0x22, 0xF2, 0x42, 0xDA, 0xBB, 0x31,
++	0x2F, 0x3F, 0x63, 0x7A, 0x26, 0x21, 0x74,
++	0xD3, 0x1B, 0xF6, 0xB5, 0x85, 0xFF, 0xAE,
++	0x5B, 0x7A, 0x03, 0x5B, 0xF6, 0xF7, 0x1C,
++	0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, 0xD7,
++	0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
++	0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D,
++	0x9E, 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1,
++	0xDF, 0x82, 0xCC, 0x6D, 0x24, 0x1B, 0x0E,
++	0x2A, 0xE9, 0xCD, 0x34, 0x8B, 0x1F, 0xD4,
++	0x7E, 0x92, 0x67, 0xAF, 0xC1, 0xB2, 0xAE,
++	0x91, 0xEE, 0x51, 0xD6, 0xCB, 0x0E, 0x31,
++	0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, 0xCF,
++	0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
++	0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C,
++	0x02, 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C,
++	0x10, 0xBE, 0x19, 0x48, 0x2F, 0x23, 0x17,
++	0x1B, 0x67, 0x1D, 0xF1, 0xCF, 0x3B, 0x96,
++	0x0C, 0x07, 0x43, 0x01, 0xCD, 0x93, 0xC1,
++	0xD1, 0x76, 0x03, 0xD1, 0x47, 0xDA, 0xE2,
++	0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, 0xEF,
++	0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
++	0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5,
++	0x72, 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D,
++	0x02, 0x88, 0x0A, 0xB9, 0x47, 0x2D, 0x45,
++	0x55, 0x62, 0x16, 0xD6, 0x99, 0x8B, 0x86,
++	0x82, 0x28, 0x3D, 0x19, 0xD4, 0x2A, 0x90,
++	0xD5, 0xEF, 0x8E, 0x5D, 0x32, 0x76, 0x7D,
++	0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, 0x45,
++	0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
++	0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2,
++	0x63, 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84,
++	0x99, 0xEB, 0x8F, 0x46, 0x4A, 0x70, 0x25,
++	0x12, 0xB0, 0xCE, 0xE7, 0x71, 0xE9, 0x13,
++	0x0D, 0x69, 0x77, 0x35, 0xF8, 0x97, 0xFD,
++	0x03, 0x6C, 0xC5, 0x04, 0x32, 0x6C, 0x3B,
++	0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, 0x29,
++	0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
++	0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE,
++	0xB6, 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C,
++	0xA3, 0x71, 0x04, 0x71, 0x27, 0xD0, 0x3A,
++	0x72, 0xD5, 0x98, 0xA1, 0xED, 0xAD, 0xFE,
++	0x70, 0x7E, 0x88, 0x47, 0x25, 0xC1, 0x68,
++	0x90, 0x54, 0x90, 0x84, 0x00, 0x8D, 0x39,
++	0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, 0xC4,
++	0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
++	0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71,
++	0x1E, 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A,
++	0x85, 0xED, 0x12, 0xC1, 0xF4, 0xE5, 0x15,
++	0x6A, 0x26, 0x74, 0x6D, 0xDD, 0xE1, 0x6D,
++	0x82, 0x6F, 0x47, 0x7C, 0x97, 0x47, 0x7E,
++	0x0A, 0x0F, 0xDF, 0x65, 0x53, 0x14, 0x3E,
++	0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, 0xCC,
++	0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
++	0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3,
++	0xF6, 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71,
++	0x6B, 0xD7, 0xDC, 0x0D, 0xEE, 0xBB, 0x10,
++	0xB8, 0x24, 0x0E, 0x68, 0x03, 0x48, 0x93,
++	0xEA, 0xD8, 0x2D, 0x54, 0xC9, 0xDA, 0x75,
++	0x4C, 0x46, 0xC7, 0xEE, 0xE0, 0xC3, 0x7F,
++	0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, 0xA6,
++	0xFA, 0x1A, 0xE4, 0x9A, 0x03, 0x18, 0xCC,
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF
++};
++
++const gnutls_datum_t gnutls_modp_4096_group_prime = {
++	(void *) modp_params_4096, sizeof(modp_params_4096)
++};
++const gnutls_datum_t gnutls_modp_4096_group_q = {
++	(void *) modp_q_4096, sizeof(modp_q_4096)
++};
++const gnutls_datum_t gnutls_modp_4096_group_generator = {
++	(void *) &modp_generator, sizeof(modp_generator)
++};
++const unsigned int gnutls_modp_4096_key_bits = 336;
++
++static const unsigned char modp_params_6144[] = {
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68,
++	0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80,
++	0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08,
++	0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE,
++	0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A,
++	0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF,
++	0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14,
++	0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51,
++	0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62,
++	0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
++	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C,
++	0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38,
++	0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE,
++	0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B,
++	0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63,
++	0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C,
++	0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8,
++	0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D,
++	0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62,
++	0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E,
++	0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98,
++	0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18,
++	0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E,
++	0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C,
++	0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83,
++	0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5,
++	0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE,
++	0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A,
++	0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA,
++	0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A,
++	0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D,
++	0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21,
++	0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB,
++	0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A,
++	0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4,
++	0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09,
++	0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A,
++	0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26,
++	0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA,
++	0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76,
++	0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52,
++	0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D,
++	0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9,
++	0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74,
++	0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC,
++	0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1,
++	0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72,
++	0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88,
++	0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
++	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2,
++	0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15,
++	0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A,
++	0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB,
++	0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC,
++	0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C,
++	0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99,
++	0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
++	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7,
++	0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2,
++	0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21,
++	0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27,
++	0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA,
++	0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF,
++	0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D,
++	0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
++	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70,
++	0x26, 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26,
++	0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D,
++	0xBA, 0x37, 0xBD, 0xF8, 0xFF, 0x94, 0x06,
++	0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38,
++	0x2F, 0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A,
++	0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, 0x17,
++	0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
++	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14,
++	0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4,
++	0xBB, 0x1B, 0xDB, 0x7F, 0x14, 0x47, 0xE6,
++	0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51,
++	0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4,
++	0x01, 0x37, 0x8C, 0xD2, 0xBF, 0x59, 0x83,
++	0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0,
++	0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
++	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE,
++	0xF6, 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98,
++	0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90,
++	0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F,
++	0xBE, 0xC7, 0xE8, 0xF3, 0x23, 0xA9, 0x7A,
++	0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D,
++	0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B,
++	0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
++	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1,
++	0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80,
++	0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2,
++	0x9B, 0xE3, 0x28, 0x06, 0xA1, 0xD5, 0x8B,
++	0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA,
++	0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19,
++	0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, 0xDA,
++	0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
++	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04,
++	0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48,
++	0x60, 0xEE, 0x12, 0xBF, 0x2D, 0x5B, 0x0B,
++	0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E,
++	0x6D, 0xCC, 0x40, 0x24, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++};
++
++static const unsigned char modp_q_6144[] = {
++	0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4,
++	0x61, 0x1A, 0x62, 0x63, 0x31, 0x45, 0xC0,
++	0x6E, 0x0E, 0x68, 0x94, 0x81, 0x27, 0x04,
++	0x45, 0x33, 0xE6, 0x3A, 0x01, 0x05, 0xDF,
++	0x53, 0x1D, 0x89, 0xCD, 0x91, 0x28, 0xA5,
++	0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, 0xF7,
++	0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
++	0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A,
++	0x1B, 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8,
++	0xE1, 0x22, 0xF2, 0x42, 0xDA, 0xBB, 0x31,
++	0x2F, 0x3F, 0x63, 0x7A, 0x26, 0x21, 0x74,
++	0xD3, 0x1B, 0xF6, 0xB5, 0x85, 0xFF, 0xAE,
++	0x5B, 0x7A, 0x03, 0x5B, 0xF6, 0xF7, 0x1C,
++	0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, 0xD7,
++	0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
++	0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D,
++	0x9E, 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1,
++	0xDF, 0x82, 0xCC, 0x6D, 0x24, 0x1B, 0x0E,
++	0x2A, 0xE9, 0xCD, 0x34, 0x8B, 0x1F, 0xD4,
++	0x7E, 0x92, 0x67, 0xAF, 0xC1, 0xB2, 0xAE,
++	0x91, 0xEE, 0x51, 0xD6, 0xCB, 0x0E, 0x31,
++	0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, 0xCF,
++	0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
++	0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C,
++	0x02, 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C,
++	0x10, 0xBE, 0x19, 0x48, 0x2F, 0x23, 0x17,
++	0x1B, 0x67, 0x1D, 0xF1, 0xCF, 0x3B, 0x96,
++	0x0C, 0x07, 0x43, 0x01, 0xCD, 0x93, 0xC1,
++	0xD1, 0x76, 0x03, 0xD1, 0x47, 0xDA, 0xE2,
++	0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, 0xEF,
++	0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
++	0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5,
++	0x72, 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D,
++	0x02, 0x88, 0x0A, 0xB9, 0x47, 0x2D, 0x45,
++	0x55, 0x62, 0x16, 0xD6, 0x99, 0x8B, 0x86,
++	0x82, 0x28, 0x3D, 0x19, 0xD4, 0x2A, 0x90,
++	0xD5, 0xEF, 0x8E, 0x5D, 0x32, 0x76, 0x7D,
++	0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, 0x45,
++	0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
++	0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2,
++	0x63, 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84,
++	0x99, 0xEB, 0x8F, 0x46, 0x4A, 0x70, 0x25,
++	0x12, 0xB0, 0xCE, 0xE7, 0x71, 0xE9, 0x13,
++	0x0D, 0x69, 0x77, 0x35, 0xF8, 0x97, 0xFD,
++	0x03, 0x6C, 0xC5, 0x04, 0x32, 0x6C, 0x3B,
++	0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, 0x29,
++	0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
++	0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE,
++	0xB6, 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C,
++	0xA3, 0x71, 0x04, 0x71, 0x27, 0xD0, 0x3A,
++	0x72, 0xD5, 0x98, 0xA1, 0xED, 0xAD, 0xFE,
++	0x70, 0x7E, 0x88, 0x47, 0x25, 0xC1, 0x68,
++	0x90, 0x54, 0x90, 0x84, 0x00, 0x8D, 0x39,
++	0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, 0xC4,
++	0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
++	0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71,
++	0x1E, 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A,
++	0x85, 0xED, 0x12, 0xC1, 0xF4, 0xE5, 0x15,
++	0x6A, 0x26, 0x74, 0x6D, 0xDD, 0xE1, 0x6D,
++	0x82, 0x6F, 0x47, 0x7C, 0x97, 0x47, 0x7E,
++	0x0A, 0x0F, 0xDF, 0x65, 0x53, 0x14, 0x3E,
++	0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, 0xCC,
++	0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
++	0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3,
++	0xF6, 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71,
++	0x6B, 0xD7, 0xDC, 0x0D, 0xEE, 0xBB, 0x10,
++	0xB8, 0x24, 0x0E, 0x68, 0x03, 0x48, 0x93,
++	0xEA, 0xD8, 0x2D, 0x54, 0xC9, 0xDA, 0x75,
++	0x4C, 0x46, 0xC7, 0xEE, 0xE0, 0xC3, 0x7F,
++	0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, 0xA6,
++	0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
++	0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38,
++	0x13, 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13,
++	0x23, 0x6F, 0x64, 0xBA, 0x8F, 0x3B, 0x1E,
++	0xDD, 0x1B, 0xDE, 0xFC, 0x7F, 0xCA, 0x03,
++	0x56, 0xCF, 0x29, 0x87, 0x72, 0xED, 0x9C,
++	0x17, 0xA0, 0x98, 0x00, 0xD7, 0x58, 0x35,
++	0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18, 0x8B,
++	0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
++	0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A,
++	0x76, 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A,
++	0x5D, 0x8D, 0xED, 0xBF, 0x8A, 0x23, 0xF3,
++	0x66, 0x12, 0xA5, 0x99, 0x90, 0x28, 0xA8,
++	0x95, 0xEB, 0xD7, 0xA1, 0x37, 0xDC, 0x7A,
++	0x00, 0x9B, 0xC6, 0x69, 0x5F, 0xAC, 0xC1,
++	0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76, 0x78,
++	0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
++	0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F,
++	0x7B, 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C,
++	0x06, 0x41, 0x5A, 0xD4, 0x20, 0x18, 0xC8,
++	0x05, 0x8E, 0x4F, 0x2C, 0xF3, 0xE4, 0xBF,
++	0xDF, 0x63, 0xF4, 0x79, 0x91, 0xD4, 0xBD,
++	0x3F, 0x1B, 0x66, 0x44, 0x5F, 0x07, 0x8E,
++	0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62, 0xA5,
++	0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
++	0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70,
++	0xEC, 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0,
++	0x1B, 0xF0, 0x53, 0xCB, 0x8A, 0xF7, 0x79,
++	0x4D, 0xF1, 0x94, 0x03, 0x50, 0xEA, 0xC5,
++	0xDB, 0xE2, 0xED, 0x3B, 0x7A, 0xA8, 0x55,
++	0x1E, 0xC5, 0x0F, 0xDF, 0xF8, 0x75, 0x8C,
++	0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE, 0x6D,
++	0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
++	0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02,
++	0x34, 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4,
++	0x30, 0x77, 0x09, 0x5F, 0x96, 0xAD, 0x85,
++	0xBA, 0x3A, 0x6B, 0x73, 0x4A, 0x7C, 0x8F,
++	0x36, 0xE6, 0x20, 0x12, 0x7F, 0xFF, 0xFF,
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++};
++
++const gnutls_datum_t gnutls_modp_6144_group_prime = {
++	(void *) modp_params_6144, sizeof(modp_params_6144)
++};
++const gnutls_datum_t gnutls_modp_6144_group_q = {
++	(void *) modp_q_6144, sizeof(modp_q_6144)
++};
++const gnutls_datum_t gnutls_modp_6144_group_generator = {
++	(void *) &modp_generator, sizeof(modp_generator)
++};
++const unsigned int gnutls_modp_6144_key_bits = 376;
++
++static const unsigned char modp_params_8192[] = {
++	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68,
++	0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80,
++	0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08,
++	0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE,
++	0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A,
++	0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF,
++	0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14,
++	0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51,
++	0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62,
++	0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
++	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C,
++	0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38,
++	0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE,
++	0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B,
++	0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63,
++	0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C,
++	0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8,
++	0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D,
++	0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62,
++	0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E,
++	0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98,
++	0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18,
++	0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E,
++	0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C,
++	0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83,
++	0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5,
++	0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE,
++	0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A,
++	0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA,
++	0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A,
++	0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D,
++	0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21,
++	0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB,
++	0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A,
++	0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4,
++	0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09,
++	0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A,
++	0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26,
++	0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA,
++	0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76,
++	0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52,
++	0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D,
++	0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9,
++	0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74,
++	0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC,
++	0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1,
++	0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72,
++	0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88,
++	0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
++	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2,
++	0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15,
++	0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A,
++	0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB,
++	0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC,
++	0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C,
++	0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99,
++	0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
++	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7,
++	0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2,
++	0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21,
++	0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27,
++	0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA,
++	0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF,
++	0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D,
++	0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
++	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70,
++	0x26, 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26,
++	0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D,
++	0xBA, 0x37, 0xBD, 0xF8, 0xFF, 0x94, 0x06,
++	0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38,
++	0x2F, 0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A,
++	0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, 0x17,
++	0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
++	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14,
++	0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4,
++	0xBB, 0x1B, 0xDB, 0x7F, 0x14, 0x47, 0xE6,
++	0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51,
++	0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4,
++	0x01, 0x37, 0x8C, 0xD2, 0xBF, 0x59, 0x83,
++	0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0,
++	0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
++	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE,
++	0xF6, 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98,
++	0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90,
++	0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F,
++	0xBE, 0xC7, 0xE8, 0xF3, 0x23, 0xA9, 0x7A,
++	0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D,
++	0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B,
++	0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
++	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1,
++	0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80,
++	0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2,
++	0x9B, 0xE3, 0x28, 0x06, 0xA1, 0xD5, 0x8B,
++	0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA,
++	0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19,
++	0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, 0xDA,
++	0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
++	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04,
++	0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48,
++	0x60, 0xEE, 0x12, 0xBF, 0x2D, 0x5B, 0x0B,
++	0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E,
++	0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92,
++	0x6F, 0x12, 0xFE, 0xE5, 0xE4, 0x38, 0x77,
++	0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8,
++	0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
++	0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3,
++	0x00, 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC,
++	0x47, 0xED, 0x25, 0x76, 0xF6, 0x93, 0x6B,
++	0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C,
++	0x5A, 0xE4, 0xF5, 0x68, 0x34, 0x23, 0xB4,
++	0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F,
++	0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, 0xE3,
++	0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
++	0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C,
++	0x07, 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23,
++	0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C,
++	0xEA, 0x30, 0x6B, 0x4B, 0xCB, 0xC8, 0x86,
++	0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B,
++	0x7F, 0xA2, 0xC0, 0x87, 0xE8, 0x79, 0x68,
++	0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, 0x06,
++	0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
++	0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8,
++	0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB,
++	0x6A, 0x36, 0x45, 0x97, 0xE8, 0x99, 0xA0,
++	0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5,
++	0x08, 0x46, 0x85, 0x1D, 0xF9, 0xAB, 0x48,
++	0x19, 0x5D, 0xED, 0x7E, 0xA1, 0xB1, 0xD5,
++	0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, 0xFA,
++	0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68,
++	0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F,
++	0x92, 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C,
++	0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E, 0xD5,
++	0xEE, 0x38, 0x2B, 0xC9, 0x19, 0x0D, 0xA6,
++	0xFC, 0x02, 0x6E, 0x47, 0x95, 0x58, 0xE4,
++	0x47, 0x56, 0x77, 0xE9, 0xAA, 0x9E, 0x30,
++	0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, 0xC8,
++	0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
++	0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3,
++	0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xFF
++};
++
++static const unsigned char modp_q_8192[] = {
++	0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4,
++	0x61, 0x1A, 0x62, 0x63, 0x31, 0x45, 0xC0,
++	0x6E, 0x0E, 0x68, 0x94, 0x81, 0x27, 0x04,
++	0x45, 0x33, 0xE6, 0x3A, 0x01, 0x05, 0xDF,
++	0x53, 0x1D, 0x89, 0xCD, 0x91, 0x28, 0xA5,
++	0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, 0xF7,
++	0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
++	0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A,
++	0x1B, 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8,
++	0xE1, 0x22, 0xF2, 0x42, 0xDA, 0xBB, 0x31,
++	0x2F, 0x3F, 0x63, 0x7A, 0x26, 0x21, 0x74,
++	0xD3, 0x1B, 0xF6, 0xB5, 0x85, 0xFF, 0xAE,
++	0x5B, 0x7A, 0x03, 0x5B, 0xF6, 0xF7, 0x1C,
++	0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, 0xD7,
++	0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
++	0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D,
++	0x9E, 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1,
++	0xDF, 0x82, 0xCC, 0x6D, 0x24, 0x1B, 0x0E,
++	0x2A, 0xE9, 0xCD, 0x34, 0x8B, 0x1F, 0xD4,
++	0x7E, 0x92, 0x67, 0xAF, 0xC1, 0xB2, 0xAE,
++	0x91, 0xEE, 0x51, 0xD6, 0xCB, 0x0E, 0x31,
++	0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, 0xCF,
++	0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
++	0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C,
++	0x02, 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C,
++	0x10, 0xBE, 0x19, 0x48, 0x2F, 0x23, 0x17,
++	0x1B, 0x67, 0x1D, 0xF1, 0xCF, 0x3B, 0x96,
++	0x0C, 0x07, 0x43, 0x01, 0xCD, 0x93, 0xC1,
++	0xD1, 0x76, 0x03, 0xD1, 0x47, 0xDA, 0xE2,
++	0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, 0xEF,
++	0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
++	0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5,
++	0x72, 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D,
++	0x02, 0x88, 0x0A, 0xB9, 0x47, 0x2D, 0x45,
++	0x55, 0x62, 0x16, 0xD6, 0x99, 0x8B, 0x86,
++	0x82, 0x28, 0x3D, 0x19, 0xD4, 0x2A, 0x90,
++	0xD5, 0xEF, 0x8E, 0x5D, 0x32, 0x76, 0x7D,
++	0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, 0x45,
++	0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
++	0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2,
++	0x63, 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84,
++	0x99, 0xEB, 0x8F, 0x46, 0x4A, 0x70, 0x25,
++	0x12, 0xB0, 0xCE, 0xE7, 0x71, 0xE9, 0x13,
++	0x0D, 0x69, 0x77, 0x35, 0xF8, 0x97, 0xFD,
++	0x03, 0x6C, 0xC5, 0x04, 0x32, 0x6C, 0x3B,
++	0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, 0x29,
++	0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
++	0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE,
++	0xB6, 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C,
++	0xA3, 0x71, 0x04, 0x71, 0x27, 0xD0, 0x3A,
++	0x72, 0xD5, 0x98, 0xA1, 0xED, 0xAD, 0xFE,
++	0x70, 0x7E, 0x88, 0x47, 0x25, 0xC1, 0x68,
++	0x90, 0x54, 0x90, 0x84, 0x00, 0x8D, 0x39,
++	0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, 0xC4,
++	0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
++	0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71,
++	0x1E, 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A,
++	0x85, 0xED, 0x12, 0xC1, 0xF4, 0xE5, 0x15,
++	0x6A, 0x26, 0x74, 0x6D, 0xDD, 0xE1, 0x6D,
++	0x82, 0x6F, 0x47, 0x7C, 0x97, 0x47, 0x7E,
++	0x0A, 0x0F, 0xDF, 0x65, 0x53, 0x14, 0x3E,
++	0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, 0xCC,
++	0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
++	0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3,
++	0xF6, 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71,
++	0x6B, 0xD7, 0xDC, 0x0D, 0xEE, 0xBB, 0x10,
++	0xB8, 0x24, 0x0E, 0x68, 0x03, 0x48, 0x93,
++	0xEA, 0xD8, 0x2D, 0x54, 0xC9, 0xDA, 0x75,
++	0x4C, 0x46, 0xC7, 0xEE, 0xE0, 0xC3, 0x7F,
++	0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, 0xA6,
++	0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
++	0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38,
++	0x13, 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13,
++	0x23, 0x6F, 0x64, 0xBA, 0x8F, 0x3B, 0x1E,
++	0xDD, 0x1B, 0xDE, 0xFC, 0x7F, 0xCA, 0x03,
++	0x56, 0xCF, 0x29, 0x87, 0x72, 0xED, 0x9C,
++	0x17, 0xA0, 0x98, 0x00, 0xD7, 0x58, 0x35,
++	0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18, 0x8B,
++	0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
++	0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A,
++	0x76, 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A,
++	0x5D, 0x8D, 0xED, 0xBF, 0x8A, 0x23, 0xF3,
++	0x66, 0x12, 0xA5, 0x99, 0x90, 0x28, 0xA8,
++	0x95, 0xEB, 0xD7, 0xA1, 0x37, 0xDC, 0x7A,
++	0x00, 0x9B, 0xC6, 0x69, 0x5F, 0xAC, 0xC1,
++	0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76, 0x78,
++	0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
++	0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F,
++	0x7B, 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C,
++	0x06, 0x41, 0x5A, 0xD4, 0x20, 0x18, 0xC8,
++	0x05, 0x8E, 0x4F, 0x2C, 0xF3, 0xE4, 0xBF,
++	0xDF, 0x63, 0xF4, 0x79, 0x91, 0xD4, 0xBD,
++	0x3F, 0x1B, 0x66, 0x44, 0x5F, 0x07, 0x8E,
++	0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62, 0xA5,
++	0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
++	0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70,
++	0xEC, 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0,
++	0x1B, 0xF0, 0x53, 0xCB, 0x8A, 0xF7, 0x79,
++	0x4D, 0xF1, 0x94, 0x03, 0x50, 0xEA, 0xC5,
++	0xDB, 0xE2, 0xED, 0x3B, 0x7A, 0xA8, 0x55,
++	0x1E, 0xC5, 0x0F, 0xDF, 0xF8, 0x75, 0x8C,
++	0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE, 0x6D,
++	0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
++	0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02,
++	0x34, 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4,
++	0x30, 0x77, 0x09, 0x5F, 0x96, 0xAD, 0x85,
++	0xBA, 0x3A, 0x6B, 0x73, 0x4A, 0x7C, 0x8F,
++	0x36, 0xDF, 0x08, 0xAC, 0xBA, 0x51, 0xC9,
++	0x37, 0x89, 0x7F, 0x72, 0xF2, 0x1C, 0x3B,
++	0xBE, 0x5B, 0x54, 0x99, 0x6F, 0xC6, 0x6C,
++	0x5F, 0x62, 0x68, 0x39, 0xDC, 0x98, 0xDD,
++	0x1D, 0xE4, 0x19, 0x5B, 0x46, 0xCE, 0xE9,
++	0x80, 0x3A, 0x0F, 0xD3, 0xDF, 0xC5, 0x7E,
++	0x23, 0xF6, 0x92, 0xBB, 0x7B, 0x49, 0xB5,
++	0xD2, 0x12, 0x33, 0x1D, 0x55, 0xB1, 0xCE,
++	0x2D, 0x72, 0x7A, 0xB4, 0x1A, 0x11, 0xDA,
++	0x3A, 0x15, 0xF8, 0xE4, 0xBC, 0x11, 0xC7,
++	0x8B, 0x65, 0xF1, 0xCE, 0xB2, 0x96, 0xF1,
++	0xFE, 0xDC, 0x5F, 0x7E, 0x42, 0x45, 0x6C,
++	0x91, 0x11, 0x17, 0x02, 0x52, 0x01, 0xBE,
++	0x03, 0x89, 0xF5, 0xAB, 0xD4, 0x0D, 0x11,
++	0xF8, 0x63, 0x9A, 0x39, 0xFE, 0x32, 0x36,
++	0x75, 0x18, 0x35, 0xA5, 0xE5, 0xE4, 0x43,
++	0x17, 0xC1, 0xC2, 0xEE, 0xFD, 0x4E, 0xA5,
++	0xBF, 0xD1, 0x60, 0x43, 0xF4, 0x3C, 0xB4,
++	0x19, 0x81, 0xF6, 0xAD, 0xEE, 0x9D, 0x03,
++	0x15, 0x9E, 0x7A, 0xD9, 0xD1, 0x3C, 0x53,
++	0x36, 0x95, 0x09, 0xFC, 0x1F, 0xA2, 0x7C,
++	0x16, 0xEF, 0x98, 0x87, 0x70, 0x3A, 0x55,
++	0xB5, 0x1B, 0x22, 0xCB, 0xF4, 0x4C, 0xD0,
++	0x12, 0xAE, 0xE0, 0xB2, 0x79, 0x8E, 0x62,
++	0x84, 0x23, 0x42, 0x8E, 0xFC, 0xD5, 0xA4,
++	0x0C, 0xAE, 0xF6, 0xBF, 0x50, 0xD8, 0xEA,
++	0x88, 0x5E, 0xBF, 0x73, 0xA6, 0xB9, 0xFD,
++	0x79, 0xB5, 0xE1, 0x8F, 0x67, 0xD1, 0x34,
++	0x1A, 0xC8, 0x23, 0x7A, 0x75, 0xC3, 0xCF,
++	0xC9, 0x20, 0x04, 0xA1, 0xC5, 0xA4, 0x0E,
++	0x36, 0x6B, 0xC4, 0x4D, 0x00, 0x17, 0x6A,
++	0xF7, 0x1C, 0x15, 0xE4, 0x8C, 0x86, 0xD3,
++	0x7E, 0x01, 0x37, 0x23, 0xCA, 0xAC, 0x72,
++	0x23, 0xAB, 0x3B, 0xF4, 0xD5, 0x4F, 0x18,
++	0x28, 0x71, 0x3B, 0x2B, 0x4A, 0x6F, 0xE4,
++	0x0F, 0xAB, 0x74, 0x40, 0x5C, 0xB7, 0x38,
++	0xB0, 0x64, 0xC0, 0x6E, 0xCC, 0x76, 0xE9,
++	0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++	0xFF, 0xFF
++};
++
++const gnutls_datum_t gnutls_modp_8192_group_prime = {
++	(void *) modp_params_8192, sizeof(modp_params_8192)
++};
++const gnutls_datum_t gnutls_modp_8192_group_q = {
++	(void *) modp_q_8192, sizeof(modp_q_8192)
++};
++const gnutls_datum_t gnutls_modp_8192_group_generator = {
++	(void *) &modp_generator, sizeof(modp_generator)
++};
++const unsigned int gnutls_modp_8192_key_bits = 512;
++
+ #endif
+diff --git a/lib/dh.h b/lib/dh.h
+index 9f3dc2a70..a64a4eb5e 100644
+--- a/lib/dh.h
++++ b/lib/dh.h
+@@ -31,4 +31,33 @@ _gnutls_figure_dh_params(gnutls_session_t session, gnutls_dh_params_t dh_params,
+ 
+ int _gnutls_set_cred_dh_params(gnutls_dh_params_t *cparams, gnutls_sec_param_t sec_param);
+ 
++/* The static parameters defined in RFC 3526, used for the approved
++ * primes check in SP800-56A (Appendix D).
++ */
++
++extern const gnutls_datum_t gnutls_modp_8192_group_prime;
++extern const gnutls_datum_t gnutls_modp_8192_group_q;
++extern const gnutls_datum_t gnutls_modp_8192_group_generator;
++extern const unsigned int gnutls_modp_8192_key_bits;
++
++extern const gnutls_datum_t gnutls_modp_6144_group_prime;
++extern const gnutls_datum_t gnutls_modp_6144_group_q;
++extern const gnutls_datum_t gnutls_modp_6144_group_generator;
++extern const unsigned int gnutls_modp_6144_key_bits;
++
++extern const gnutls_datum_t gnutls_modp_4096_group_prime;
++extern const gnutls_datum_t gnutls_modp_4096_group_q;
++extern const gnutls_datum_t gnutls_modp_4096_group_generator;
++extern const unsigned int gnutls_modp_4096_key_bits;
++
++extern const gnutls_datum_t gnutls_modp_3072_group_prime;
++extern const gnutls_datum_t gnutls_modp_3072_group_q;
++extern const gnutls_datum_t gnutls_modp_3072_group_generator;
++extern const unsigned int gnutls_modp_3072_key_bits;
++
++extern const gnutls_datum_t gnutls_modp_2048_group_prime;
++extern const gnutls_datum_t gnutls_modp_2048_group_q;
++extern const gnutls_datum_t gnutls_modp_2048_group_generator;
++extern const unsigned int gnutls_modp_2048_key_bits;
++
+ #endif /* GNUTLS_LIB_DH_H */
+-- 
+2.26.2
+
+
+From 3f4532862bf9140976d970ab14e102cede61d1c7 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 26 Jun 2020 10:21:26 +0200
+Subject: [PATCH 2/2] dhe: check if DH params in SKE match the FIPS approved
+ algorithms
+
+SP800-56A rev. 3 restricts the FIPS compliant clients to use only
+approved DH parameters, defined in RFC 7919 and RFC 3526.  This adds a
+check in the handling of ServerKeyExchange if DHE is negotiated.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ doc/credentials/Makefile.am                   |  24 ++++
+ .../dhparams/rfc2409-group-1-768.pem          |   5 +
+ .../dhparams/rfc2409-group-2-1024.pem         |   5 +
+ .../dhparams/rfc3526-group-14-2048.pem        |   8 ++
+ .../dhparams/rfc3526-group-15-3072.pem        |  11 ++
+ .../dhparams/rfc3526-group-16-4096.pem        |  13 ++
+ .../dhparams/rfc3526-group-17-6144.pem        |  19 +++
+ .../dhparams/rfc3526-group-18-8192.pem        |  24 ++++
+ .../dhparams/rfc3526-group-5-1536.pem         |   7 +
+ doc/credentials/dhparams/rfc5054-1024.pem     |   5 +
+ doc/credentials/dhparams/rfc5054-1536.pem     |   7 +
+ doc/credentials/dhparams/rfc5054-2048.pem     |   8 ++
+ doc/credentials/dhparams/rfc5054-3072.pem     |  11 ++
+ doc/credentials/dhparams/rfc5054-4096.pem     |  13 ++
+ doc/credentials/dhparams/rfc5054-6144.pem     |  19 +++
+ doc/credentials/dhparams/rfc5054-8192.pem     |  24 ++++
+ .../dhparams/rfc5114-group-22-1024.pem        |   8 ++
+ .../dhparams/rfc5114-group-23-2048.pem        |  13 ++
+ .../dhparams/rfc5114-group-24-2048.pem        |  13 ++
+ .../dhparams/rfc7919-ffdhe2048.pem            |   8 ++
+ .../dhparams/rfc7919-ffdhe3072.pem            |  11 ++
+ .../dhparams/rfc7919-ffdhe4096.pem            |  14 ++
+ .../dhparams/rfc7919-ffdhe6144.pem            |  19 +++
+ .../dhparams/rfc7919-ffdhe8192.pem            |  24 ++++
+ lib/auth/dh_common.c                          |   8 ++
+ lib/dh-primes.c                               |  34 +++++
+ lib/dh.h                                      |   6 +
+ tests/Makefile.am                             |   2 +
+ tests/client-sign-md5-rep.c                   |   5 +
+ tests/dh-fips-approved.sh                     | 127 ++++++++++++++++++
+ tests/utils.c                                 |  58 ++++----
+ 31 files changed, 521 insertions(+), 32 deletions(-)
+ create mode 100644 doc/credentials/dhparams/rfc2409-group-1-768.pem
+ create mode 100644 doc/credentials/dhparams/rfc2409-group-2-1024.pem
+ create mode 100644 doc/credentials/dhparams/rfc3526-group-14-2048.pem
+ create mode 100644 doc/credentials/dhparams/rfc3526-group-15-3072.pem
+ create mode 100644 doc/credentials/dhparams/rfc3526-group-16-4096.pem
+ create mode 100644 doc/credentials/dhparams/rfc3526-group-17-6144.pem
+ create mode 100644 doc/credentials/dhparams/rfc3526-group-18-8192.pem
+ create mode 100644 doc/credentials/dhparams/rfc3526-group-5-1536.pem
+ create mode 100644 doc/credentials/dhparams/rfc5054-1024.pem
+ create mode 100644 doc/credentials/dhparams/rfc5054-1536.pem
+ create mode 100644 doc/credentials/dhparams/rfc5054-2048.pem
+ create mode 100644 doc/credentials/dhparams/rfc5054-3072.pem
+ create mode 100644 doc/credentials/dhparams/rfc5054-4096.pem
+ create mode 100644 doc/credentials/dhparams/rfc5054-6144.pem
+ create mode 100644 doc/credentials/dhparams/rfc5054-8192.pem
+ create mode 100644 doc/credentials/dhparams/rfc5114-group-22-1024.pem
+ create mode 100644 doc/credentials/dhparams/rfc5114-group-23-2048.pem
+ create mode 100644 doc/credentials/dhparams/rfc5114-group-24-2048.pem
+ create mode 100644 doc/credentials/dhparams/rfc7919-ffdhe2048.pem
+ create mode 100644 doc/credentials/dhparams/rfc7919-ffdhe3072.pem
+ create mode 100644 doc/credentials/dhparams/rfc7919-ffdhe4096.pem
+ create mode 100644 doc/credentials/dhparams/rfc7919-ffdhe6144.pem
+ create mode 100644 doc/credentials/dhparams/rfc7919-ffdhe8192.pem
+ create mode 100755 tests/dh-fips-approved.sh
+
+diff --git a/doc/credentials/Makefile.am b/doc/credentials/Makefile.am
+index ecdd57a10..25778856f 100644
+--- a/doc/credentials/Makefile.am
++++ b/doc/credentials/Makefile.am
+@@ -31,3 +31,27 @@ EXTRA_DIST += srp-passwd.txt  srp-tpasswd.conf
+ 
+ EXTRA_DIST += psk-passwd.txt
+ 
++EXTRA_DIST += \
++	dhparams/rfc2409-group-1-768.pem	\
++	dhparams/rfc2409-group-2-1024.pem	\
++	dhparams/rfc3526-group-14-2048.pem	\
++	dhparams/rfc3526-group-15-3072.pem	\
++	dhparams/rfc3526-group-16-4096.pem	\
++	dhparams/rfc3526-group-17-6144.pem	\
++	dhparams/rfc3526-group-18-8192.pem	\
++	dhparams/rfc3526-group-5-1536.pem	\
++	dhparams/rfc5054-1024.pem		\
++	dhparams/rfc5054-1536.pem		\
++	dhparams/rfc5054-2048.pem		\
++	dhparams/rfc5054-3072.pem		\
++	dhparams/rfc5054-4096.pem		\
++	dhparams/rfc5054-6144.pem		\
++	dhparams/rfc5054-8192.pem		\
++	dhparams/rfc5114-group-22-1024.pem	\
++	dhparams/rfc5114-group-23-2048.pem	\
++	dhparams/rfc5114-group-24-2048.pem	\
++	dhparams/rfc7919-ffdhe2048.pem		\
++	dhparams/rfc7919-ffdhe3072.pem		\
++	dhparams/rfc7919-ffdhe4096.pem		\
++	dhparams/rfc7919-ffdhe6144.pem		\
++	dhparams/rfc7919-ffdhe8192.pem
+diff --git a/doc/credentials/dhparams/rfc2409-group-1-768.pem b/doc/credentials/dhparams/rfc2409-group-1-768.pem
+new file mode 100644
+index 000000000..33a617018
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc2409-group-1-768.pem
+@@ -0,0 +1,5 @@
++-----BEGIN DH PARAMETERS-----
++MGYCYQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5siUUoI
++eY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummOjYg////
++//////8CAQI=
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc2409-group-2-1024.pem b/doc/credentials/dhparams/rfc2409-group-2-1024.pem
+new file mode 100644
+index 000000000..bbfb1bfb6
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc2409-group-2-1024.pem
+@@ -0,0 +1,5 @@
++-----BEGIN DH PARAMETERS-----
++MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE
++3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/ta
++iZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc3526-group-14-2048.pem b/doc/credentials/dhparams/rfc3526-group-14-2048.pem
+new file mode 100644
+index 000000000..b15071532
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc3526-group-14-2048.pem
+@@ -0,0 +1,8 @@
++-----BEGIN DH PARAMETERS-----
++MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc3526-group-15-3072.pem b/doc/credentials/dhparams/rfc3526-group-15-3072.pem
+new file mode 100644
+index 000000000..f27b77820
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc3526-group-15-3072.pem
+@@ -0,0 +1,11 @@
++-----BEGIN DH PARAMETERS-----
++MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS
++yv//////////AgEC
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc3526-group-16-4096.pem b/doc/credentials/dhparams/rfc3526-group-16-4096.pem
+new file mode 100644
+index 000000000..a734b9050
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc3526-group-16-4096.pem
+@@ -0,0 +1,13 @@
++-----BEGIN DH PARAMETERS-----
++MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI
++ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O
+++S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI
++HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQI=
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc3526-group-17-6144.pem b/doc/credentials/dhparams/rfc3526-group-17-6144.pem
+new file mode 100644
+index 000000000..d8307bda3
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc3526-group-17-6144.pem
+@@ -0,0 +1,19 @@
++-----BEGIN DH PARAMETERS-----
++MIIDCAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI
++ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O
+++S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI
++HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG
++3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU
++7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId
++A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha
++xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/
++8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA
++JP//////////AgEC
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc3526-group-18-8192.pem b/doc/credentials/dhparams/rfc3526-group-18-8192.pem
+new file mode 100644
+index 000000000..af54dd656
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc3526-group-18-8192.pem
+@@ -0,0 +1,24 @@
++-----BEGIN DH PARAMETERS-----
++MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI
++ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O
+++S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI
++HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG
++3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU
++7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId
++A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha
++xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/
++8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R
++WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk
++ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw
++xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4
++Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i
++aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU
++38gfVuiAuW5xYMmA3Zjt09///////////wIBAg==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc3526-group-5-1536.pem b/doc/credentials/dhparams/rfc3526-group-5-1536.pem
+new file mode 100644
+index 000000000..44df6de65
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc3526-group-5-1536.pem
+@@ -0,0 +1,7 @@
++-----BEGIN DH PARAMETERS-----
++MIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR
++Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL
++/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7ORbPcIAfLihY78FmNpINhxV05pp
++Fj+o/STPX4NlXSPco62WHGLzViCFUrue1SkHcJaWbWcMNU5KvJgE8XRsCMojcyf/
++/////////wIBAg==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5054-1024.pem b/doc/credentials/dhparams/rfc5054-1024.pem
+new file mode 100644
+index 000000000..33aed9fab
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5054-1024.pem
+@@ -0,0 +1,5 @@
++-----BEGIN DH PARAMETERS-----
++MIGHAoGBAO6vCrmts43WnDP4CvqPxehgcmGHdf88C56iMUycJWV21nTfdJbqgdM4
++O0gT1pLG4ODV2OJQuYvkjklcHWCJ2tFdx9e0YVTWts6O9K1psV1JglWbKXvPGIXF
++KfVmZg5X7GjtvDwFcmzAL9TL9Jduqpr9UTj+g3ZDW5/GHS/A6wbjAgEC
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5054-1536.pem b/doc/credentials/dhparams/rfc5054-1536.pem
+new file mode 100644
+index 000000000..dc2db6b42
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5054-1536.pem
+@@ -0,0 +1,7 @@
++-----BEGIN DH PARAMETERS-----
++MIHHAoHBAJ3vPK+5OSd6sfEqhheke7vbpR30maxMgL7uqWFLGcxNX09fVW4ny95R
++xqlL5GB6KRVYkDug0PhDgLZVu5oi6NzfAop87Gfw0IE0sci5eYkUm2CeC+O6tj1H
++VIOB28Wx/HZOP0tT3Z2hFYv9PiucjPVu3wGVOTSWJ9sv1T0kt8SGZXcuQ31sf4zk
++QnNK98y3roN8Jkrjqb64f4ov6bi1KS5aAh//XpFHnoznoowkQsbzFRgPk0maI03P
++duP+0TX5uwIBAg==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5054-2048.pem b/doc/credentials/dhparams/rfc5054-2048.pem
+new file mode 100644
+index 000000000..814e70ce6
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5054-2048.pem
+@@ -0,0 +1,8 @@
++-----BEGIN DH PARAMETERS-----
++MIIBCAKCAQEArGvbQTJKmpvxZt5eE4lYL69ytmUZh+4H/DGSlD21YFCjcynLtKCZ
++7YGT4HV3Z6E91SMSq0sDMQ3Nf0ip2gT9UOgIOWntt2ewz2CVF5oWOrNmGgX71fqq
++6CkYqZYvC5O4Vfl5k+yXXuqoDXQK2/T/dHNZ0EHVwz6nHSgeRGsUdzvKl7Q6I/uA
++Fna9IHpDbGSB8dK5B4cXRhpbnTLmiPh3SFRFI7UksNV9Xqd6J3XS7PoDLPvb9S+z
++eGFgJ5AE5Xrmr4dOcwPOUymczAQce8MI2CpWmPOo0MOCca41+Onb+7aUtcgD2J96
++5DXeI21SX1R1m2XjcvzWjvIPpxEfnkr/cwIBAg==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5054-3072.pem b/doc/credentials/dhparams/rfc5054-3072.pem
+new file mode 100644
+index 000000000..d84b2424a
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5054-3072.pem
+@@ -0,0 +1,11 @@
++-----BEGIN DH PARAMETERS-----
++MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS
++yv//////////AgEF
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5054-4096.pem b/doc/credentials/dhparams/rfc5054-4096.pem
+new file mode 100644
+index 000000000..99ca4456b
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5054-4096.pem
+@@ -0,0 +1,13 @@
++-----BEGIN DH PARAMETERS-----
++MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI
++ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O
+++S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI
++HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQU=
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5054-6144.pem b/doc/credentials/dhparams/rfc5054-6144.pem
+new file mode 100644
+index 000000000..97d8d21a9
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5054-6144.pem
+@@ -0,0 +1,19 @@
++-----BEGIN DH PARAMETERS-----
++MIIDCAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI
++ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O
+++S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI
++HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG
++3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU
++7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId
++A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha
++xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/
++8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA
++JP//////////AgEF
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5054-8192.pem b/doc/credentials/dhparams/rfc5054-8192.pem
+new file mode 100644
+index 000000000..bb54575c7
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5054-8192.pem
+@@ -0,0 +1,24 @@
++-----BEGIN DH PARAMETERS-----
++MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI
++ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O
+++S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI
++HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG
++3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU
++7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId
++A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha
++xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/
++8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R
++WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk
++ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw
++xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4
++Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i
++aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU
++38gfVuiAuW5xYMmA3Zjt09///////////wIBEw==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5114-group-22-1024.pem b/doc/credentials/dhparams/rfc5114-group-22-1024.pem
+new file mode 100644
+index 000000000..759afcb2f
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5114-group-22-1024.pem
+@@ -0,0 +1,8 @@
++-----BEGIN DH PARAMETERS-----
++MIIBCAKBgQCxC4+WoIDgHd6S3l6uXVTsUsmfvPsGo8aaap3KUtI7YWBz4oZ1oj0Y
++mDjvHi7mUsAT7LSuqQYRIySXXDzUm4O/rMvdfZDEvXCYSI6cIZpzck7/1vrlZEc4
+++qMaT/VbzMChUa9fDci0vUW/N982XBpl5oz9p21NpwjfH7K8LkpDcQKBgQCk0cvV
++w/00EmdlpELvuZkF+BBN0lisUH/WQGz/FCZtMSZv6h5cQVZLd35pD1UE8hMWAhe0
++sBuIal6RVH+eJ0n01/vX07mpLuGQnQ0iY/gKdqaiTAh6CR9THb8KAWm2oorWYqTR
++jnOvoy13nVkY0IvIhY9Nzvl8KiSFXm7rIrOy5Q==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5114-group-23-2048.pem b/doc/credentials/dhparams/rfc5114-group-23-2048.pem
+new file mode 100644
+index 000000000..d4f360ef2
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5114-group-23-2048.pem
+@@ -0,0 +1,13 @@
++-----BEGIN DH PARAMETERS-----
++MIICCgKCAQEArRB+HpEjqdDWYPqnlVnFH6INZOVoO5/RtUsVl7YdCnXm+hQd+VpW
++26+aPEB7od8V6z1oijCcGA4d5rhaEnSgpm0/gVKtasISkDfJ7e/aTfjZHo/vVbc5
++S3rVt9C2wSIHyfmNEe002/bGugssi7wnvmoA4KC5xJcIs7+KMXCRiDaBKGEwvImF
++2xYC5xRBXZMwJ4Jzx94x79xzEPcSH9WgdBWYfZrcCkhtzfk6zEQyg4cxXXXhmMZB
++pIDNhqG55YfovmDmnMkosrnFIXLkEwQumyPxCw4W55djybU9z0uoCinj+3PBa451
++uX7zY+L/ox9xz53lOE5xuBwKxN/+DBDmTwKCAQEArEAy708tmuOd8wtcj/2sUGze
++vnuJmYyvdIZqCM/k/+OmgkpOELmm8N2SHwGnDEr6q3OddwDCn1LFfbF8YgqGUr5e
++kAGo1mrXwXZpEBmZAkr00CcnWsE0i7inYtBSG8mK4kcVBCLqHtQJk51U2nRgzbX2
++xrJQcXy+8YDrNBGOmNEZUppF1vg0Vm4wJeMWozDvu3eobwwasVsFGuPUKMj4rLcK
++gTcVC47rEOGD7dGZY93Z4mPkdwWJ72qiHn9fL/OBtTnM40CdE81Wavu0jWwBkYHh
++vP6UswJp7f5y/ptqpL17Wg8ccc//TBnEGOH27AF5gbwIfypwZbOEuJDTGR8r+g==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc5114-group-24-2048.pem b/doc/credentials/dhparams/rfc5114-group-24-2048.pem
+new file mode 100644
+index 000000000..dc0211648
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc5114-group-24-2048.pem
+@@ -0,0 +1,13 @@
++-----BEGIN DH PARAMETERS-----
++MIICCQKCAQEAh6jmHbS2Zjz/u9GcZRlZmYzu9ghmDdDyXSzu1ENeOwDgDfjx1hlX
++1Pr330VhsqowFsPZETQJb6o79Cltgw6afCCeDGSXUXq9WoqdMGvPZ+2R+eZyW0dY
++wCLgse9Cdb97bFv8EdRfkIi5QfVOseWbuLw5oL8SMH9cT9twxYGyP3a2Osrhyqa3
++kC1SUmc1SIoO8TxtmlG/pKs62DR3llJNjvahZ7WkGCXZZ+FE5RQFZCUcysuD5rSG
++9rPKP3lxUGAmwLhX9omWKFbe1AEKvQvmIcOjlgpU5xDDdfJjddcBQQOktUMwwZiv
++EmEW0iduEXFfaTh3+tfvCcrbCUrpHhoVlwKCAQA/syybcxNNCy53UGZg7b1ITKex
++jyHvIFQH9Hk6GguhJRDbwVB3vkY//0/tSqwLtVW+OmwbDGtHsbw3c79+jG9ikBIo
+++MKMuxilWuMTQQAKZQGW+THHelfy3fRj5ensFEt3feYqqrioYorDdtKC1u04ZOZ5
++gkKOvIMdFDSPby+Rk7UEWvJ2cWTh38lnwfs/LlWkvRv/6DucgNBSuYXRguoK2yo7
++cxPT/hTISEseBSWIubfSu9LfAWGZ7NBuFVfNCRWzNTu7ZODsN3/QKDcN+StSx4kU
++KM3GfrYYS1I9HbJGwy9jB4SQ8A741kfRSNR5VFFeIyfP75jFgmZLTA9sxBZZ
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc7919-ffdhe2048.pem b/doc/credentials/dhparams/rfc7919-ffdhe2048.pem
+new file mode 100644
+index 000000000..9b182b720
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc7919-ffdhe2048.pem
+@@ -0,0 +1,8 @@
++-----BEGIN DH PARAMETERS-----
++MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
++87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
++YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
++7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
++ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc7919-ffdhe3072.pem b/doc/credentials/dhparams/rfc7919-ffdhe3072.pem
+new file mode 100644
+index 000000000..fb31ccda5
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc7919-ffdhe3072.pem
+@@ -0,0 +1,11 @@
++-----BEGIN DH PARAMETERS-----
++MIIBiAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
++87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
++YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
++7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
++ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
++7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
++nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu
++N///////////AgEC
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc7919-ffdhe4096.pem b/doc/credentials/dhparams/rfc7919-ffdhe4096.pem
+new file mode 100644
+index 000000000..ad9f68b1e
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc7919-ffdhe4096.pem
+@@ -0,0 +1,14 @@
++-----BEGIN DH PARAMETERS-----
++MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
++87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
++YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
++7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
++ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
++7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
++nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e
++8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx
++iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K
++zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI=
++-----END DH PARAMETERS-----
++
+diff --git a/doc/credentials/dhparams/rfc7919-ffdhe6144.pem b/doc/credentials/dhparams/rfc7919-ffdhe6144.pem
+new file mode 100644
+index 000000000..d8239bb05
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc7919-ffdhe6144.pem
+@@ -0,0 +1,19 @@
++-----BEGIN DH PARAMETERS-----
++MIIDCAKCAwEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
++87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
++YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
++7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
++ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
++7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
++nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e
++8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx
++iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K
++zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eDdkCC/1ktkUDbHpOZ30sOFMq
++OiO6RELK9T6mO7RUMpt2JMiRe91kscD9TLOOjDNMcBw6za0GV/zP7HGbH1w+TkYE
++HziBR/tM/bR3pSRx96mpaRC4VTIu22NA2KAO8JI1BRHjCr7B//njom5/sp+MGDAj
++w1h+ONoAd9m0dj5OS5Syu8GUxmUed8r5ku6qwCMqKBv2s6c5wSJhFoIK6NtYR6Z8
++vvnJCRtGLVOM1ysDdGrnf15iKSwxFWKoRlBdyC24VDOK5J9SNclbkReMzy3Vys70
++A+ydGBDGJysEWztx+dxrgNY/3UqOmtseaWKmlSbUMWHBpB1XDXk42tSkDjKc0OQO
++Zf//////////AgEC
++-----END DH PARAMETERS-----
+diff --git a/doc/credentials/dhparams/rfc7919-ffdhe8192.pem b/doc/credentials/dhparams/rfc7919-ffdhe8192.pem
+new file mode 100644
+index 000000000..4484cf885
+--- /dev/null
++++ b/doc/credentials/dhparams/rfc7919-ffdhe8192.pem
+@@ -0,0 +1,24 @@
++-----BEGIN DH PARAMETERS-----
++MIIECAKCBAEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
++87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
++YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
++7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
++ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
++7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
++nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e
++8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx
++iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K
++zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eDdkCC/1ktkUDbHpOZ30sOFMq
++OiO6RELK9T6mO7RUMpt2JMiRe91kscD9TLOOjDNMcBw6za0GV/zP7HGbH1w+TkYE
++HziBR/tM/bR3pSRx96mpaRC4VTIu22NA2KAO8JI1BRHjCr7B//njom5/sp+MGDAj
++w1h+ONoAd9m0dj5OS5Syu8GUxmUed8r5ku6qwCMqKBv2s6c5wSJhFoIK6NtYR6Z8
++vvnJCRtGLVOM1ysDdGrnf15iKSwxFWKoRlBdyC24VDOK5J9SNclbkReMzy3Vys70
++A+ydGBDGJysEWztx+dxrgNY/3UqOmtseaWKmlSbUMWHBpB1XDXk42tSkDjKcz/Rq
++qjatAEz2AMg4HkJaMdlRrmT9sj/OyVCdQ2h/62nt0cxeC4zDvfZLEO+GtjFCo6uI
++KVVbL3R8kyZlyywPHMAb1wIpOIg50q8F5FRQSseLdYKCKEbAujXDX1xZFgzARv2C
++UVQfxoychrAiu3CZh2pGDnRRqKkxCXA/7hwhfmw4JuUsUappHg5CPPyZ6eMWUMEh
++e2JIFs2tmpX51bgBlIjZwKCh/jB1pXfiMYP4HUo/L6RXHvyM4LqKT+i2hV3+crCm
++bt7S+6v75Yow+vq+HF1xqH4vdB74wf6G/qa7/eUwZ38Nl9EdSfeoRD0IIuUGqfRh
++TgEeKpSDj/iM1oyLt8XGQkz//////////wIBAg==
++-----END DH PARAMETERS-----
+diff --git a/lib/auth/dh_common.c b/lib/auth/dh_common.c
+index 19c205bbe..252eea0cb 100644
+--- a/lib/auth/dh_common.c
++++ b/lib/auth/dh_common.c
+@@ -257,6 +257,14 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session,
+ 		}
+ 	}
+ 
++#ifdef ENABLE_FIPS140
++	if (gnutls_fips140_mode_enabled() &&
++	    !_gnutls_dh_prime_is_fips_approved(data_p, n_p, data_g, n_g)) {
++		gnutls_assert();
++		return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
++	}
++#endif
++
+ 	if (_gnutls_mpi_init_scan_nz(&session->key.proto.tls12.dh.params.params[DH_G], data_g, _n_g) != 0) {
+ 		gnutls_assert();
+ 		return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+diff --git a/lib/dh-primes.c b/lib/dh-primes.c
+index 5d2dce0fb..a43a8e5de 100644
+--- a/lib/dh-primes.c
++++ b/lib/dh-primes.c
+@@ -1893,4 +1893,38 @@ const gnutls_datum_t gnutls_modp_8192_group_generator = {
+ };
+ const unsigned int gnutls_modp_8192_key_bits = 512;
+ 
++unsigned
++_gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
++				  size_t prime_size,
++				  const uint8_t *generator,
++				  size_t generator_size)
++{
++	static const struct {
++		const gnutls_datum_t *prime;
++		const gnutls_datum_t *generator;
++	} primes[] = {
++		{ &gnutls_ffdhe_8192_group_prime, &gnutls_ffdhe_8192_group_generator },
++		{ &gnutls_ffdhe_6144_group_prime, &gnutls_ffdhe_6144_group_generator },
++		{ &gnutls_ffdhe_4096_group_prime, &gnutls_ffdhe_4096_group_generator },
++		{ &gnutls_ffdhe_3072_group_prime, &gnutls_ffdhe_3072_group_generator },
++		{ &gnutls_ffdhe_2048_group_prime, &gnutls_ffdhe_2048_group_generator },
++		{ &gnutls_modp_8192_group_prime, &gnutls_modp_8192_group_generator },
++		{ &gnutls_modp_6144_group_prime, &gnutls_modp_6144_group_generator },
++		{ &gnutls_modp_4096_group_prime, &gnutls_modp_4096_group_generator },
++		{ &gnutls_modp_3072_group_prime, &gnutls_modp_3072_group_generator },
++		{ &gnutls_modp_2048_group_prime, &gnutls_modp_2048_group_generator },
++	};
++	size_t i;
++
++	for (i = 0; i < sizeof(primes) / sizeof(primes[0]); i++) {
++		if (primes[i].prime->size == prime_size &&
++		    memcmp(primes[i].prime->data, prime, primes[i].prime->size) == 0 &&
++		    primes[i].generator->size == generator_size &&
++		    memcmp(primes[i].generator->data, generator, primes[i].generator->size) == 0)
++			return 1;
++	}
++
++	return 0;
++}
++
+ #endif
+diff --git a/lib/dh.h b/lib/dh.h
+index a64a4eb5e..672451947 100644
+--- a/lib/dh.h
++++ b/lib/dh.h
+@@ -60,4 +60,10 @@ extern const gnutls_datum_t gnutls_modp_2048_group_q;
+ extern const gnutls_datum_t gnutls_modp_2048_group_generator;
+ extern const unsigned int gnutls_modp_2048_key_bits;
+ 
++unsigned
++_gnutls_dh_prime_is_fips_approved(const uint8_t *prime,
++				  size_t prime_size,
++				  const uint8_t *generator,
++				  size_t generator_size);
++
+ #endif /* GNUTLS_LIB_DH_H */
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 7cdf828e0..13d7ba385 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -522,6 +522,8 @@ endif
+ 
+ dist_check_SCRIPTS += gnutls-cli-self-signed.sh gnutls-cli-invalid-crl.sh gnutls-cli-rawpk.sh
+ 
++dist_check_SCRIPTS += dh-fips-approved.sh
++
+ if ENABLE_PKCS11
+ dist_check_SCRIPTS += p11-kit-trust.sh testpkcs11.sh certtool-pkcs11.sh
+ 
+diff --git a/tests/client-sign-md5-rep.c b/tests/client-sign-md5-rep.c
+index 1c7877fbd..b1ad46ce9 100644
+--- a/tests/client-sign-md5-rep.c
++++ b/tests/client-sign-md5-rep.c
+@@ -468,6 +468,11 @@ void doit(void)
+ 	int sockets[2];
+ 	int err;
+ 
++	/* tls1_hello contains ServerKeyExchange with custom DH
++	 * parameters */
++	if (gnutls_fips140_mode_enabled())
++		exit(77);
++
+ 	signal(SIGPIPE, SIG_IGN);
+ 
+ 	err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
+diff --git a/tests/dh-fips-approved.sh b/tests/dh-fips-approved.sh
+new file mode 100755
+index 000000000..136dd15f3
+--- /dev/null
++++ b/tests/dh-fips-approved.sh
+@@ -0,0 +1,127 @@
++#!/bin/sh
++
++# Copyright (C) 2017 Nikos Mavrogiannopoulos
++#
++# Author: Nikos Mavrogiannopoulos
++#
++# This file is part of GnuTLS.
++#
++# GnuTLS is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by the
++# Free Software Foundation; either version 3 of the License, or (at
++# your option) any later version.
++#
++# GnuTLS is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public License
++# along with this program.  If not, see <https://www.gnu.org/licenses/>
++
++srcdir="${srcdir:-.}"
++SERV="${SERV:-../src/gnutls-serv${EXEEXT}}"
++CLI="${CLI:-../src/gnutls-cli${EXEEXT}}"
++unset RETCODE
++
++if ! test -x "${SERV}"; then
++	exit 77
++fi
++
++if ! test -x "${CLI}"; then
++	exit 77
++fi
++
++if test "${WINDIR}" != ""; then
++	exit 77
++fi
++
++if ! test -z "${VALGRIND}"; then
++	VALGRIND="${LIBTOOL:-libtool} --mode=execute ${VALGRIND} --error-exitcode=15"
++fi
++
++
++SERV="${SERV} -q"
++
++. "${srcdir}/scripts/common.sh"
++
++KEY1=${srcdir}/../doc/credentials/x509/key-rsa.pem
++CERT1=${srcdir}/../doc/credentials/x509/cert-rsa.pem
++CA1=${srcdir}/../doc/credentials/x509/ca.pem
++
++ALLOWED_PARAMS="
++rfc3526-group-14-2048
++rfc3526-group-15-3072
++rfc3526-group-16-4096
++rfc3526-group-17-6144
++rfc3526-group-18-8192
++rfc7919-ffdhe2048
++rfc7919-ffdhe3072
++rfc7919-ffdhe4096
++rfc7919-ffdhe6144
++rfc7919-ffdhe8192
++"
++
++DISALLOWED_PARAMS="
++rfc2409-group-2-1024
++rfc3526-group-5-1536
++rfc5054-1024
++rfc5054-1536
++rfc5054-2048
++rfc5054-3072
++rfc5054-4096
++rfc5054-6144
++rfc5054-8192
++rfc5114-group-22-1024
++rfc5114-group-23-2048
++rfc5114-group-24-2048
++"
++
++OPTS="--priority=NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-RSA:+AES-128-GCM:-GROUP-ALL"
++
++for params in $ALLOWED_PARAMS; do
++	echo "Checking with approved DH params: $params"
++
++	PARAMS=${srcdir}/../doc/credentials/dhparams/${params}.pem
++
++	eval "${GETPORT}"
++	launch_server $$ ${OPTS} --x509keyfile ${KEY1} --x509certfile ${CERT1} --dhparams ${PARAMS}
++	PID=$!
++	wait_server ${PID}
++
++	${VALGRIND} "${CLI}" ${OPTS} -p "${PORT}" 127.0.0.1 --verify-hostname=localhost --x509cafile ${CA1} </dev/null >/dev/null || \
++		fail ${PID} "handshake should have succeeded!"
++
++	kill ${PID}
++	wait
++done
++
++for params in $DISALLOWED_PARAMS; do
++	echo "Checking with non-approved DH params: $params"
++
++	PARAMS=${srcdir}/../doc/credentials/dhparams/${params}.pem
++
++	eval "${GETPORT}"
++	launch_server $$ ${OPTS} --x509keyfile ${KEY1} --x509certfile ${CERT1} --dhparams ${PARAMS}
++	PID=$!
++	wait_server ${PID}
++
++	${VALGRIND} "${CLI}" ${OPTS} -p "${PORT}" 127.0.0.1 --verify-hostname=localhost --x509cafile ${CA1} </dev/null >/dev/null
++
++	RET=$?
++
++	if test $RET -eq 0; then
++		if test "${GNUTLS_FORCE_FIPS_MODE}" = 1; then
++			fail ${PID} "handshake should have failed (FIPS mode 1)!"
++		fi
++	else
++		if test "${GNUTLS_FORCE_FIPS_MODE}" != 1; then
++			fail ${PID} "handshake should have succeeded (FIPS mode 0)!"
++		fi
++	fi
++
++	kill ${PID}
++	wait
++done
++
++exit 0
+diff --git a/tests/utils.c b/tests/utils.c
+index 9186a1757..60cd79b35 100644
+--- a/tests/utils.c
++++ b/tests/utils.c
+@@ -50,47 +50,41 @@ int debug = 0;
+ int error_count = 0;
+ int break_on_error = 0;
+ 
++/* doc/credentials/dhparams/rfc3526-group-14-2048.pem */
+ const char *pkcs3 =
+     "-----BEGIN DH PARAMETERS-----\n"
+-    "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
+-    "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
+-    "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
++    "MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
++    "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
++    "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
++    "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
++    "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
++    "5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==\n"
+     "-----END DH PARAMETERS-----\n";
+ 
++/* doc/credentials/dhparams/rfc7919-ffdhe2048.pem */
+ const char *pkcs3_2048 =
+     "-----BEGIN DH PARAMETERS-----\n"
+-    "MIICDgKCAQEAvVNCqM8M9ZoVYBKEkV2KN8ELHHJ75aTZiK9z6170iKSgbITkOxsd\n"
+-    "aBCLzHZd7d6/2aNofUeuWdDGHm73d8v53ma2HRVCNESeC2LKsEDFG9FjjUeugvfl\n"
+-    "zb85TLZwWT9Lb35Ddhdk7CtxoukjS0/JkCE+8RGzmk5+57N8tNffs4aSSHSe4+cw\n"
+-    "i4wULDxiG2p052czAMP3YR5egWvMuiByhy0vKShiZmOy1/Os5r6E/GUF+298gDjG\n"
+-    "OeaEUF9snrTcoBwB4yNjVSEbuAh5fMd5zFtz2+dzrk9TYZ44u4DQYkgToW05WcmC\n"
+-    "+LG0bLAH6lrJR5OMgyheZEo6F20z/d2yyQKCAQEAtzcuTHW61SFQiDRouk6eD0Yx\n"
+-    "0k1RJdaQdlRf6/Dcc6lEqnbezL90THzvxkBwfJ5jG1VZE7JlVCvLRkBtgb0/6SCf\n"
+-    "MATfEKG2JMOnKsJxvidmKEp4uN32LketXRrrEBl7rS+HABEfKAzqx+J6trBaq25E\n"
+-    "7FVJFsyoa8IL8N8YUWwhE2UuEfmiqQQaeoIUYC/xD2arMXn9N0W84Nyy2S9IL4ct\n"
+-    "e3Azi1Wc8MMfpbxxDRxXCnM2uMkLYWs1lQmcUUX+Uygv3P8lgS+RJ1Pi3+BWMx0S\n"
+-    "ocsZXqOr6dbEF1WOLObQRK7h/MZp80iVUyrBgX0MbVFN9M5i2u4KKTG95VKRtgIC\n"
+-    "AQA=\n" "-----END DH PARAMETERS-----\n";
++    "MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
++    "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
++    "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
++    "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
++    "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
++    "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==\n"
++    "-----END DH PARAMETERS-----\n";
+ 
++/* doc/credentials/dhparams/rfc7919-ffdhe3072.pem */
+ const char *pkcs3_3072 =
+     "-----BEGIN DH PARAMETERS-----\n"
+-    "MIIDDgKCAYEAtRUay8nDgwE5dSVzW525wEu/d0vrFolvYJSevxg2myj5S+gr3Fgq\n"
+-    "OGaZc4zrBxkxsELc7GuCqaXSOWL4yobT8N05yGbYWkWRPf4crRMx3P7/Gba9WsmH\n"
+-    "BlL71uPf1IN9CanAlabkhV89RKiYaCpUI19+/sq+N2dO874ToBZCNhxZnTgRZ+po\n"
+-    "Gdr6XWM0lQ8imIKSer0px3ZHI+/5gmyPry35tGpwlbyclJAg3wlTSdnqDcLxq7AF\n"
+-    "OZ23PzC3ij7SFErOX9EFBdS2bjtU47O3OkPc9EIYMEv5nwnXICLHslwVifmURAjV\n"
+-    "LfpObL8LYGN4Gac4tFxuDa0PMg0ES5ADugYBwdRFTAtCy5WOYXINzAAOrH9MommT\n"
+-    "rMkELf7JOCaV2ktBsvTlrgMAXeyqbf2YSG6CGjj4QnUuqPybSgwPru7VlahsS2lo\n"
+-    "qjutBPpgIxS53o97Wi3V5kQedKJiNuIDNnJMFNuTADAM+OYwClTH7ZSwTsxEgVpr\n"
+-    "tMH+WnTI7KTJAoIBgQCrELwIUB4oNbf0x+fIpVndhDpl/WcFc/lDtmiRuym5gWbb\n"
+-    "NPeI+1rdhnS2R3+nCJODFQTcPNMgIJuSu2EnDCSs5xJ2k08SAgSzyxEdjBpY7qJe\n"
+-    "+lJPJ12zhcl0vgcvMhb/YgqVe2MKz0RvnYZPwHM/aJbjYjq/6OpK3fVw4M1ZccBK\n"
+-    "QD4OHK8HOvGU7Wf6kRIcxUlfn15spMCIsrAZQBddWLmQgktsxJNUS+AnaPwTBoOv\n"
+-    "nGCr1vzw8OS1DtS03VCmtqt3otXhJ3D2oCIG6ogxVAKfHR30KIfzZLBfmCjdzHmH\n"
+-    "x4OwYTN1wy5juA438QtiDtcgK60ZqSzQO08ZklRncA/TkkyEH6kPn5KSh/hW9O3D\n"
+-    "KZeAY/KF0/Bc1XNtqPEYFb7Vo3rbTsyjXkICN1Hk9S0OIKL42K7rWBepO9KuddSd\n"
+-    "aXgH9staP0HXCyyW1VAyqo0TwcWDhE/R7IQQGGwGyd4rD0T+ySW/t09ox23O6X8J\n"
+-    "FSp6mOVNcuvhB5U2gW8CAgEA\n" "-----END DH PARAMETERS-----\n";
++    "MIIBiAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
++    "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
++    "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
++    "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
++    "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
++    "ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3\n"
++    "7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32\n"
++    "nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu\n"
++    "N///////////AgEC\n"
++    "-----END DH PARAMETERS-----\n";
+ 
+ void _fail(const char *format, ...)
+ {
+-- 
+2.26.2
+
diff --git a/SOURCES/gnutls-3.6.14-fips-dh-selftests.patch b/SOURCES/gnutls-3.6.14-fips-dh-selftests.patch
new file mode 100644
index 0000000..adcb83c
--- /dev/null
+++ b/SOURCES/gnutls-3.6.14-fips-dh-selftests.patch
@@ -0,0 +1,204 @@
+From f09b7627a63defb1c55e9965fb05e0bbddb90247 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Tue, 6 Oct 2020 11:54:21 +0200
+Subject: [PATCH] fips: use larger prime for DH self-tests
+
+According to FIPS140-2 IG 7.5, the minimum key size of FFC through
+2030 is defined as 2048 bits.  This updates the relevant self-test
+using ffdhe3072 defined in RFC 7919.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/crypto-selftests-pk.c | 142 ++++++++++++++++++++++++++++++++++----
+ lib/dh-primes.c           |   4 --
+ 2 files changed, 130 insertions(+), 16 deletions(-)
+
+diff --git a/lib/crypto-selftests-pk.c b/lib/crypto-selftests-pk.c
+index 70b0f618f..9b7c692a8 100644
+--- a/lib/crypto-selftests-pk.c
++++ b/lib/crypto-selftests-pk.c
+@@ -620,32 +620,150 @@ static int test_dh(void)
+ 	gnutls_pk_params_st priv;
+ 	gnutls_pk_params_st pub;
+ 	gnutls_datum_t out = {NULL, 0};
++
++	/* FFDHE 3072 test vector provided by Stephan Mueller in:
++	 * https://gitlab.com/gnutls/gnutls/-/merge_requests/1342#note_424430996
++	 */
+ 	static const uint8_t known_dh_k[] = {
+-		0x10, 0x25, 0x04, 0xb5, 0xc6, 0xc2, 0xcb, 
+-		0x0c, 0xe9, 0xc5, 0x58, 0x0d, 0x22, 0x62};
+-	static const uint8_t test_p[] = {
+-		0x24, 0x85, 0xdd, 0x3a, 0x74, 0x42, 0xe4, 
+-		0xb3, 0xf1, 0x0b, 0x13, 0xf9, 0x17, 0x4d };
+-	static const uint8_t test_g[] = { 0x02 };
++		0xec, 0xb3, 0x85, 0x0c, 0x72, 0x55, 0x55, 0xc2, 0x98, 0x36,
++		0xbe, 0x75, 0x9e, 0xc9, 0x9d, 0x8b, 0x16, 0xa6, 0xe6, 0x84,
++		0x33, 0x12, 0x80, 0x1d, 0xac, 0xde, 0x6a, 0xd7, 0x3b, 0x1e,
++		0x15, 0xca, 0x5d, 0x26, 0xb3, 0x0a, 0x35, 0xf4, 0xbb, 0xad,
++		0x71, 0xcb, 0x03, 0x1a, 0xcb, 0xfb, 0x83, 0xf0, 0xa8, 0xde,
++		0xed, 0x5e, 0x3d, 0x98, 0xd2, 0xb0, 0xef, 0xad, 0xdf, 0x32,
++		0xa0, 0x16, 0x7d, 0x0e, 0x29, 0xd8, 0x85, 0xca, 0x12, 0x97,
++		0x56, 0xab, 0x6a, 0x26, 0xa4, 0x46, 0x3d, 0x87, 0xd7, 0xe0,
++		0xb4, 0x3e, 0x28, 0x75, 0xac, 0x59, 0xc5, 0x71, 0x3a, 0x24,
++		0x15, 0x76, 0x98, 0x72, 0x94, 0x2d, 0xd0, 0x0e, 0xbc, 0x9a,
++		0x77, 0xd4, 0xe2, 0xb2, 0x76, 0x54, 0x4a, 0x56, 0xbe, 0x0b,
++		0x43, 0xf8, 0x21, 0x6f, 0x54, 0x32, 0xde, 0xb7, 0xd5, 0xb7,
++		0x08, 0x00, 0xd2, 0x57, 0x8c, 0x0b, 0x8b, 0x02, 0x3e, 0xdb,
++		0x72, 0x54, 0x3a, 0xc0, 0x50, 0x66, 0xbc, 0xc9, 0x67, 0xf5,
++		0x22, 0x28, 0xf2, 0x3c, 0x51, 0x94, 0x61, 0x26, 0x9a, 0xc6,
++		0x42, 0x0e, 0x8b, 0x42, 0xad, 0x79, 0x40, 0xa9, 0x0b, 0xdc,
++		0x84, 0xd5, 0x71, 0x83, 0x94, 0xd9, 0x83, 0x2f, 0x08, 0x74,
++		0xbc, 0x37, 0x6a, 0x3e, 0x1e, 0xbc, 0xcc, 0x09, 0x23, 0x30,
++		0x79, 0x01, 0x39, 0xf6, 0xe3, 0xa8, 0xc0, 0xfa, 0x7e, 0xdb,
++		0x0b, 0x71, 0x3e, 0x4f, 0x1f, 0x69, 0x84, 0xa6, 0x58, 0x6c,
++		0x36, 0x2c, 0xcc, 0xb4, 0x7c, 0x94, 0xec, 0x06, 0x0b, 0x11,
++		0x53, 0x95, 0xe6, 0x05, 0x43, 0xa4, 0xe4, 0xea, 0x1d, 0x4f,
++		0xdc, 0xd0, 0x38, 0x0e, 0x32, 0xa1, 0xde, 0xd9, 0x8d, 0xd8,
++		0x20, 0xac, 0x04, 0x83, 0xf8, 0x1b, 0x55, 0x52, 0x16, 0x20,
++		0xe3, 0x2e, 0x6d, 0x11, 0x15, 0x29, 0x2f, 0x3a, 0x7c, 0x80,
++		0x0a, 0x71, 0x3d, 0x31, 0x9c, 0x1b, 0x73, 0x59, 0xe1, 0x0d,
++		0x27, 0xc5, 0xc0, 0x6a, 0x72, 0x3a, 0x5b, 0xd6, 0xf6, 0x50,
++		0xe6, 0x69, 0x48, 0x1e, 0xfd, 0xeb, 0x4a, 0x47, 0x73, 0xfb,
++		0x88, 0x14, 0xea, 0x6d, 0x36, 0xe1, 0x4c, 0x2c, 0xf9, 0x04,
++		0xc1, 0xb7, 0x29, 0xfc, 0x5d, 0x02, 0x5d, 0x1c, 0x4d, 0x31,
++		0x4a, 0x51, 0x3f, 0xa4, 0x45, 0x19, 0x29, 0xc4, 0x32, 0xa6,
++		0x45, 0xdb, 0x94, 0x3a, 0xbd, 0x76, 0x2c, 0xd6, 0x1a, 0xb1,
++		0xff, 0xe7, 0x62, 0x75, 0x16, 0xe5, 0x0b, 0xa3, 0x3a, 0x93,
++		0x84, 0xd6, 0xad, 0xc2, 0x24, 0x68, 0x3d, 0xd6, 0x07, 0xe4,
++		0xbe, 0x5a, 0x49, 0x31, 0x06, 0xad, 0x3f, 0x31, 0x4a, 0x1c,
++		0xf7, 0x58, 0xdf, 0x34, 0xcb, 0xc8, 0xa9, 0x07, 0x24, 0x42,
++		0x63, 0xa5, 0x8e, 0xdd, 0x37, 0x78, 0x92, 0x68, 0x3f, 0xd8,
++		0x2f, 0xea, 0x8c, 0xf1, 0x8e, 0xd4, 0x8b, 0xa7, 0x3f, 0xa0,
++		0xfa, 0xaf, 0xf0, 0x35,
++	};
+ 	static const uint8_t test_x[] = {
+-		0x06, 0x2c, 0x96, 0xae, 0x0e, 0x9e, 0x9b, 
+-		0xbb, 0x41, 0x51, 0x7a, 0xa7, 0xc5, 0xfe };
++		0x16, 0x5c, 0xa6, 0xe0, 0x9b, 0x87, 0xfa, 0x2d, 0xbc, 0x13,
++		0x20, 0xcd, 0xac, 0x4e, 0xcc, 0x60, 0x1e, 0x48, 0xec, 0xbe,
++		0x73, 0x0c, 0xa8, 0x6b, 0x6e, 0x2a, 0xee, 0xdd, 0xd8, 0xf3,
++		0x2d, 0x5f, 0x75, 0xf3, 0x07, 0x94, 0x88, 0x3d, 0xb1, 0x38,
++		0xcf, 0xae, 0x4a, 0xcc, 0xcb, 0x6a, 0x80, 0xbc, 0xeb, 0x3b,
++		0xaa, 0x0b, 0x18, 0x74, 0x58, 0x7c, 0x3e, 0x74, 0xef, 0xb6,
++		0xd3, 0x15, 0xee, 0x73, 0x29, 0x88, 0x7b, 0x65, 0x02, 0x39,
++		0x33, 0xec, 0x22, 0x06, 0x8c, 0x5b, 0xd6, 0x2f, 0x4c, 0xf7,
++		0xe0, 0x97, 0x6d, 0x2a, 0x90, 0x36, 0xfe, 0x1a, 0x44, 0x4d,
++		0x9d, 0x41, 0x4b, 0xcb, 0xec, 0x25, 0xf4, 0xc3, 0xa5, 0x91,
++		0xd0, 0x90, 0xc9, 0x34, 0x7b, 0xba, 0x27, 0x30, 0x5a, 0xa2,
++		0x21, 0x58, 0xce, 0x88, 0x25, 0x39, 0xaf, 0xf1, 0x17, 0x02,
++		0x12, 0xf8, 0x55, 0xdc, 0xd2, 0x08, 0x5b, 0xd3, 0xc7, 0x8e,
++		0xcf, 0x29, 0x85, 0x85, 0xdb, 0x5c, 0x08, 0xc2, 0xd7, 0xb0,
++		0x33, 0x0e, 0xe3, 0xb9, 0x2c, 0x1a, 0x1d, 0x4b, 0xe5, 0x76,
++		0x8f, 0xd3, 0x14, 0xb6, 0x8c, 0xdc, 0x9a, 0xe8, 0x15, 0x60,
++		0x60, 0x5e, 0xaa, 0xf9, 0xfa, 0xa6, 0xb2, 0x4f, 0xff, 0x46,
++		0xc1, 0x5e, 0x93, 0x50, 0x90, 0x7e, 0x4c, 0x26, 0xd7, 0xbb,
++		0x21, 0x05, 0x3d, 0x27, 0xc5, 0x9b, 0x0d, 0x46, 0x69, 0xe4,
++		0x74, 0x87, 0x74, 0x55, 0xee, 0x5f, 0xe5, 0x72, 0x04, 0x46,
++		0x1f, 0x2e, 0x55, 0xc7, 0xcc, 0x2b, 0x2b, 0x39, 0x6d, 0x90,
++		0x60, 0x31, 0x37, 0x5b, 0x44, 0xde, 0xfd, 0xf2, 0xd1, 0xc6,
++		0x9c, 0x12, 0x82, 0xcc, 0x7c, 0xb1, 0x0e, 0xa9, 0x95, 0x9d,
++		0xe0, 0xa8, 0x3e, 0xc1, 0xa3, 0x4a, 0x6a, 0x37, 0x59, 0x17,
++		0x93, 0x63, 0x1e, 0xbf, 0x04, 0xa3, 0xaa, 0xc0, 0x1d, 0xc4,
++		0x6d, 0x7a, 0xdc, 0x69, 0x9c, 0xb0, 0x22, 0x56, 0xd9, 0x76,
++		0x92, 0x2d, 0x1e, 0x62, 0xae, 0xfd, 0xd6, 0x9b, 0xfd, 0x08,
++		0x2c, 0x95, 0xec, 0xe7, 0x02, 0x43, 0x62, 0x68, 0x1a, 0xaf,
++		0x46, 0x59, 0xb7, 0xce, 0x8e, 0x42, 0x24, 0xae, 0xf7, 0x0e,
++		0x9a, 0x3b, 0xf8, 0x77, 0xdf, 0x26, 0x85, 0x9f, 0x45, 0xad,
++		0x8c, 0xa9, 0x54, 0x9c, 0x46, 0x44, 0xd5, 0x8a, 0xe9, 0xcc,
++		0x34, 0x5e, 0xc5, 0xd1, 0x42, 0x6f, 0x44, 0xf3, 0x0f, 0x90,
++		0x3a, 0x32, 0x1a, 0x9c, 0x2a, 0x63, 0xec, 0x21, 0xb4, 0xfc,
++		0xfa, 0xa5, 0xcf, 0xe7, 0x9e, 0x43, 0xc7, 0x49, 0x56, 0xbc,
++		0x50, 0xc5, 0x84, 0xf0, 0x42, 0xc8, 0x6a, 0xf1, 0x78, 0xe4,
++		0xaa, 0x06, 0x37, 0xe1, 0x30, 0xf7, 0x65, 0x97, 0xca, 0xfd,
++		0x35, 0xfa, 0xeb, 0x48, 0x6d, 0xaa, 0x45, 0x46, 0x9d, 0xbc,
++		0x1d, 0x98, 0x17, 0x45, 0xa3, 0xee, 0x21, 0xa0, 0x97, 0x38,
++		0x80, 0xc5, 0x28, 0x1f,
++	};
+ 	static const uint8_t test_y[] = { /* y=g^x mod p */
+-		0x1e, 0xca, 0x23, 0x2a, 0xfd, 0x34, 0xe1, 
+-		0x10, 0x7a, 0xff, 0xaf, 0x2d, 0xaa, 0x53 };
++		0x93, 0xeb, 0x5c, 0x37, 0x1d, 0x3c, 0x06, 0x6f, 0xbf, 0xbe,
++		0x96, 0x51, 0x26, 0x58, 0x81, 0x36, 0xc6, 0x4f, 0x9a, 0x34,
++		0xc4, 0xc5, 0xa8, 0xa3, 0x2c, 0x41, 0x76, 0xa8, 0xc6, 0xc0,
++		0xa0, 0xc8, 0x51, 0x36, 0xc4, 0x40, 0x4e, 0x2c, 0x69, 0xf7,
++		0x51, 0xbb, 0xb0, 0xd6, 0xf5, 0xdb, 0x40, 0x29, 0x50, 0x3b,
++		0x8a, 0xf9, 0xf3, 0x53, 0x78, 0xfc, 0x86, 0xe9, 0xf1, 0xe9,
++		0xac, 0x85, 0x13, 0x65, 0x62, 0x22, 0x04, 0x1b, 0x14, 0x2a,
++		0xf4, 0x8f, 0x2f, 0xf1, 0x2f, 0x81, 0xd6, 0x18, 0x0e, 0x76,
++		0x91, 0x43, 0xb2, 0xfc, 0x7c, 0x6f, 0x0c, 0x45, 0x37, 0x31,
++		0x31, 0x58, 0x5c, 0xdf, 0x42, 0x24, 0x7a, 0xba, 0x8b, 0x7f,
++		0x79, 0x06, 0x07, 0xef, 0xd6, 0x06, 0xeb, 0xcb, 0x3c, 0xbd,
++		0xbc, 0xe5, 0xff, 0xfd, 0x62, 0x15, 0x0c, 0x40, 0x46, 0x37,
++		0xef, 0xd0, 0xa1, 0xde, 0x63, 0x4f, 0x20, 0x0b, 0x45, 0x7d,
++		0x06, 0x77, 0xfd, 0x23, 0xc1, 0x32, 0x8a, 0x89, 0x65, 0x16,
++		0xe8, 0x48, 0x12, 0x1c, 0x25, 0x33, 0x2d, 0xbd, 0xd8, 0x9f,
++		0x1c, 0x9d, 0xbc, 0xe3, 0x08, 0x60, 0x87, 0x1a, 0xc6, 0x06,
++		0x36, 0xd2, 0xac, 0x09, 0x6d, 0x99, 0x02, 0x89, 0xc6, 0x12,
++		0x93, 0x8c, 0x4b, 0xd0, 0x7e, 0x36, 0x8a, 0xd6, 0xa0, 0x97,
++		0x4f, 0x97, 0x3f, 0x97, 0x0b, 0xfe, 0x05, 0xfc, 0xc8, 0xef,
++		0x21, 0x4d, 0x4a, 0x06, 0x6e, 0xb4, 0xa6, 0x4f, 0xe1, 0xdd,
++		0x44, 0x06, 0xfa, 0xd5, 0x0e, 0x54, 0xf5, 0x54, 0x3e, 0x8c,
++		0xb9, 0x85, 0x86, 0x00, 0x40, 0x98, 0xe7, 0x01, 0xdd, 0x93,
++		0x9d, 0x95, 0xea, 0xf0, 0xd3, 0x99, 0x4b, 0xeb, 0xd5, 0x79,
++		0x47, 0xa4, 0xad, 0x2a, 0xe0, 0x4d, 0x36, 0x3b, 0x46, 0x10,
++		0x96, 0xbb, 0x48, 0xe9, 0xa1, 0x78, 0x01, 0x35, 0x0a, 0x5c,
++		0x7b, 0x3f, 0xf5, 0xf7, 0xb1, 0xe3, 0x97, 0x17, 0x4d, 0x76,
++		0x10, 0x8d, 0x68, 0x4c, 0x94, 0x7d, 0xee, 0x0e, 0x20, 0x8b,
++		0xce, 0x7d, 0x0a, 0xa3, 0x51, 0xfb, 0xe6, 0xcf, 0xf0, 0x0e,
++		0x7f, 0x3c, 0xd4, 0xef, 0x56, 0x31, 0xb2, 0x95, 0xf0, 0x5f,
++		0x4b, 0x9c, 0x03, 0x9e, 0xae, 0xb1, 0xc1, 0x46, 0xd7, 0xc0,
++		0x4f, 0xb0, 0xf6, 0x6c, 0xe1, 0xe9, 0x2a, 0x97, 0xe0, 0x3f,
++		0x3a, 0x93, 0x04, 0xcd, 0x41, 0x7d, 0x45, 0x03, 0xb3, 0x40,
++		0x20, 0xe6, 0xad, 0x2d, 0xd3, 0xf7, 0x32, 0x7b, 0xcc, 0x4f,
++		0x81, 0x18, 0x4c, 0x50, 0x77, 0xc4, 0xb7, 0x6a, 0x4d, 0x05,
++		0xd8, 0x6d, 0xbf, 0x6f, 0xba, 0x1d, 0x38, 0x78, 0x87, 0xd2,
++		0x8e, 0xc2, 0x6d, 0xb6, 0xed, 0x66, 0x61, 0xa8, 0xb9, 0x19,
++		0x0e, 0x93, 0xd1, 0xcd, 0x5b, 0xbe, 0x19, 0x05, 0x52, 0x43,
++		0xd6, 0xc1, 0x07, 0x3c, 0x6a, 0x62, 0xbd, 0x33, 0x9b, 0x1b,
++		0x02, 0x42, 0x61, 0x14,
++	};
+ 
+ 	gnutls_pk_params_init(&priv);
+ 	gnutls_pk_params_init(&pub);
+ 	
+ 	priv.algo = pub.algo = GNUTLS_PK_DH;
+ 	
+-	ret = _gnutls_mpi_init_scan(&priv.params[DH_P], test_p, sizeof(test_p));
++	ret = _gnutls_mpi_init_scan(&priv.params[DH_P],
++				    gnutls_ffdhe_3072_group_prime.data,
++				    gnutls_ffdhe_3072_group_prime.size);
+ 	if (ret < 0) {
+ 		gnutls_assert();
+ 		goto cleanup;
+ 	}
+ 
+-	ret = _gnutls_mpi_init_scan(&priv.params[DH_G], test_g, sizeof(test_g));
++	ret = _gnutls_mpi_init_scan(&priv.params[DH_G],
++				    gnutls_ffdhe_3072_group_generator.data,
++				    gnutls_ffdhe_3072_group_generator.size);
+ 	if (ret < 0) {
+ 		gnutls_assert();
+ 		goto cleanup;
+diff --git a/lib/dh-primes.c b/lib/dh-primes.c
+index a440b5b98..94b69e345 100644
+--- a/lib/dh-primes.c
++++ b/lib/dh-primes.c
+@@ -23,8 +23,6 @@
+ #include "gnutls_int.h"
+ #include <gnutls/gnutls.h>
+ 
+-#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
+-
+ #include "dh.h"
+ 
+ static const unsigned char ffdhe_generator = 0x02;
+@@ -1934,5 +1932,3 @@ _gnutls_dh_prime_match_fips_approved(const uint8_t *prime,
+ 
+ 	return 0;
+ }
+-
+-#endif
+-- 
+2.26.2
+
diff --git a/SOURCES/gnutls-3.6.14-fips-kdf-selftests.patch b/SOURCES/gnutls-3.6.14-fips-kdf-selftests.patch
new file mode 100644
index 0000000..e6fdbb2
--- /dev/null
+++ b/SOURCES/gnutls-3.6.14-fips-kdf-selftests.patch
@@ -0,0 +1,713 @@
+From 93c0e3ba4d2cfee86b32f28f33303a2193c4133c Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Mon, 5 Oct 2020 16:12:46 +0200
+Subject: [PATCH 1/4] fips: add self-tests for HKDF
+
+FIPS140-2 IG D.8 mandates self-test on approved KDF algorithms.  As
+the guidance only requires running a single instance of each KDF
+mechanism, this only exercises HKDF-Extract and HKDF-Expand operations
+with HMAC-SHA-256 as the underlying MAC.
+
+Although HKDF is non-approved, it would be sensible to do that as it
+will be approved in FIPS140-3.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ devel/libgnutls-latest-x86_64.abi |   1 +
+ lib/crypto-selftests.c            | 159 ++++++++++++++++++++++++++++++
+ lib/fips.c                        |   7 ++
+ lib/includes/gnutls/self-test.h   |   1 +
+ lib/libgnutls.map                 |   1 +
+ 5 files changed, 169 insertions(+)
+
+diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
+index 7a1c7729c..bd148b6af 100644
+--- a/lib/crypto-selftests.c
++++ b/lib/crypto-selftests.c
+@@ -2917,3 +2917,162 @@ int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest)
+ 
+ 	return 0;
+ }
++
++struct hkdf_vectors_st {
++	const uint8_t *ikm;
++	unsigned int ikm_size;
++	const uint8_t *salt;
++	unsigned int salt_size;
++	const uint8_t *prk;
++	unsigned int prk_size;
++	const uint8_t *info;
++	unsigned int info_size;
++	const uint8_t *okm;
++	unsigned int okm_size;
++};
++
++const struct hkdf_vectors_st hkdf_sha256_vectors[] = {
++	/* RFC 5869: A.1. Test Case 1: Basic test case with SHA-256 */
++	{
++		STR(ikm, ikm_size,
++		    "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
++		    "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
++		STR(salt, salt_size,
++		    "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c"),
++		STR(prk, prk_size,
++		    "\x07\x77\x09\x36\x2c\x2e\x32\xdf\x0d\xdc\x3f\x0d\xc4\x7b"
++		    "\xba\x63\x90\xb6\xc7\x3b\xb5\x0f\x9c\x31\x22\xec\x84\x4a"
++		    "\xd7\xc2\xb3\xe5"),
++		STR(info, info_size,
++		    "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9"),
++		STR(okm, okm_size,
++		    "\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36"
++		    "\x2f\x2a\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56"
++		    "\xec\xc4\xc5\xbf\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65"),
++	},
++	/* RFC 5869: A.2. Test Case 2: Test with SHA-256 and longer inputs/outputs */
++	{
++		STR(ikm, ikm_size,
++		    "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d"
++		    "\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b"
++		    "\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29"
++		    "\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37"
++		    "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45"
++		    "\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"),
++		STR(salt, salt_size,
++		    "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d"
++		    "\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b"
++		    "\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89"
++		    "\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97"
++		    "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5"
++		    "\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"),
++		STR(prk, prk_size,
++		    "\x06\xa6\xb8\x8c\x58\x53\x36\x1a\x06\x10\x4c\x9c\xeb\x35"
++		    "\xb4\x5c\xef\x76\x00\x14\x90\x46\x71\x01\x4a\x19\x3f\x40"
++		    "\xc1\x5f\xc2\x44"),
++		STR(info, info_size,
++		    "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd"
++		    "\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb"
++		    "\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9"
++		    "\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
++		    "\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5"
++		    "\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"),
++		STR(okm, okm_size,
++		    "\xb1\x1e\x39\x8d\xc8\x03\x27\xa1\xc8\xe7\xf7\x8c\x59\x6a"
++		    "\x49\x34\x4f\x01\x2e\xda\x2d\x4e\xfa\xd8\xa0\x50\xcc\x4c"
++		    "\x19\xaf\xa9\x7c\x59\x04\x5a\x99\xca\xc7\x82\x72\x71\xcb"
++		    "\x41\xc6\x5e\x59\x0e\x09\xda\x32\x75\x60\x0c\x2f\x09\xb8"
++		    "\x36\x77\x93\xa9\xac\xa3\xdb\x71\xcc\x30\xc5\x81\x79\xec"
++		    "\x3e\x87\xc1\x4c\x01\xd5\xc1\xf3\x43\x4f\x1d\x87"),
++	},
++};
++
++static int test_hkdf(gnutls_mac_algorithm_t mac,
++		     const struct hkdf_vectors_st *vectors,
++		     size_t vectors_size, unsigned flags)
++{
++	unsigned int i;
++
++	for (i = 0; i < vectors_size; i++) {
++		gnutls_datum_t ikm, prk, salt, info;
++		uint8_t output[4096];
++		int ret;
++
++		ikm.data = (void *) vectors[i].ikm;
++		ikm.size = vectors[i].ikm_size;
++		salt.data = (void *) vectors[i].salt;
++		salt.size = vectors[i].salt_size;
++
++		ret = gnutls_hkdf_extract(mac, &ikm, &salt, output);
++		if (ret < 0) {
++			_gnutls_debug_log("error extracting HKDF: MAC-%s\n",
++					  gnutls_mac_get_name(mac));
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++
++		if (memcmp(output, vectors[i].prk, vectors[i].prk_size) != 0) {
++			_gnutls_debug_log
++			    ("HKDF extract: MAC-%s test vector failed!\n",
++			     gnutls_mac_get_name(mac));
++
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++
++		prk.data = (void *) vectors[i].prk;
++		prk.size = vectors[i].prk_size;
++		info.data = (void *) vectors[i].info;
++		info.size = vectors[i].info_size;
++
++		ret = gnutls_hkdf_expand(mac, &prk, &info,
++					 output, vectors[i].okm_size);
++		if (ret < 0) {
++			_gnutls_debug_log("error extracting HKDF: MAC-%s\n",
++					  gnutls_mac_get_name(mac));
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++
++		if (memcmp(output, vectors[i].okm, vectors[i].okm_size) != 0) {
++			_gnutls_debug_log
++			    ("HKDF expand: MAC-%s test vector failed!\n",
++			     gnutls_mac_get_name(mac));
++
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++	}
++
++	_gnutls_debug_log
++	    ("HKDF: MAC-%s self check succeeded\n",
++	     gnutls_mac_get_name(mac));
++
++	return 0;
++}
++
++/*-
++ * gnutls_hkdf_self_test:
++ * @flags: GNUTLS_SELF_TEST_FLAG flags
++ * @mac: the message authentication algorithm to use
++ *
++ * This function will run self tests on HKDF with the provided mac.
++ *
++ * Returns: Zero or a negative error code on error.
++ *
++ * Since: 3.3.0-FIPS140
++ -*/
++int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
++{
++	int ret;
++
++	if (flags & GNUTLS_SELF_TEST_FLAG_ALL)
++		mac = GNUTLS_MAC_UNKNOWN;
++
++	switch (mac) {
++	case GNUTLS_MAC_UNKNOWN:
++		CASE(GNUTLS_MAC_SHA256, test_hkdf, hkdf_sha256_vectors);
++
++		break;
++	default:
++		return gnutls_assert_val(GNUTLS_E_NO_SELF_TEST);
++	}
++
++	return 0;
++}
+diff --git a/lib/fips.c b/lib/fips.c
+index f8b10f750..48891ed57 100644
+--- a/lib/fips.c
++++ b/lib/fips.c
+@@ -423,6 +423,13 @@ int _gnutls_fips_perform_self_checks2(void)
+ 		goto error;
+ 	}
+ 
++	/* HKDF */
++	ret = gnutls_hkdf_self_test(0, GNUTLS_MAC_SHA256);
++	if (ret < 0) {
++		gnutls_assert();
++		goto error;
++	}
++
+ 	if (_gnutls_rnd_ops.self_test == NULL) {
+ 		gnutls_assert();
+ 		goto error;
+diff --git a/lib/includes/gnutls/self-test.h b/lib/includes/gnutls/self-test.h
+index aacbe94ca..9b7be8159 100644
+--- a/lib/includes/gnutls/self-test.h
++++ b/lib/includes/gnutls/self-test.h
+@@ -34,5 +34,6 @@ int gnutls_cipher_self_test(unsigned flags, gnutls_cipher_algorithm_t cipher);
+ int gnutls_mac_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+ int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest);
+ int gnutls_pk_self_test(unsigned flags, gnutls_pk_algorithm_t pk);
++int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+ 
+ #endif
+diff --git a/lib/libgnutls.map b/lib/libgnutls.map
+index 61276e534..386b66f83 100644
+--- a/lib/libgnutls.map
++++ b/lib/libgnutls.map
+@@ -1347,6 +1347,7 @@ GNUTLS_FIPS140_3_4 {
+ 	gnutls_pk_self_test;
+ 	gnutls_mac_self_test;
+ 	gnutls_digest_self_test;
++	gnutls_hkdf_self_test;
+ 	#for FIPS140-2 validation
+ 	drbg_aes_reseed;
+ 	drbg_aes_init;
+-- 
+2.26.2
+
+
+From 31cc94275cd267f4e0db60999cc932fd76d43d5a Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Mon, 5 Oct 2020 16:59:50 +0200
+Subject: [PATCH 2/4] fips: add self-tests for PBKDF2
+
+FIPS140-2 IG D.8 mandates self-tests on approved KDF algorithms.  As
+the guidance only requires running a single instance of each KDF
+mechanism, this only exercises PBKDF2 with HMAC-SHA-256 as the
+underlying MAC algorithm.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ devel/libgnutls-latest-x86_64.abi |   1 +
+ lib/crypto-selftests.c            | 107 ++++++++++++++++++++++++++++++
+ lib/fips.c                        |   7 ++
+ lib/includes/gnutls/self-test.h   |   1 +
+ lib/libgnutls.map                 |   1 +
+ 5 files changed, 117 insertions(+)
+
+diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
+index bd148b6af..c4b0bd207 100644
+--- a/lib/crypto-selftests.c
++++ b/lib/crypto-selftests.c
+@@ -3076,3 +3076,110 @@ int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
+ 
+ 	return 0;
+ }
++
++struct pbkdf2_vectors_st {
++	const uint8_t *key;
++	size_t key_size;
++	const uint8_t *salt;
++	size_t salt_size;
++	unsigned iter_count;
++	const uint8_t *output;
++	size_t output_size;
++};
++
++const struct pbkdf2_vectors_st pbkdf2_sha256_vectors[] = {
++	/* RFC 7914: 11. Test Vectors for PBKDF2 with HMAC-SHA-256 */
++	{
++		STR(key, key_size, "passwd"),
++		STR(salt, salt_size, "salt"),
++		.iter_count = 1,
++		STR(output, output_size,
++		    "\x55\xac\x04\x6e\x56\xe3\x08\x9f\xec\x16\x91\xc2\x25\x44"
++		    "\xb6\x05\xf9\x41\x85\x21\x6d\xde\x04\x65\xe6\x8b\x9d\x57"
++		    "\xc2\x0d\xac\xbc\x49\xca\x9c\xcc\xf1\x79\xb6\x45\x99\x16"
++		    "\x64\xb3\x9d\x77\xef\x31\x7c\x71\xb8\x45\xb1\xe3\x0b\xd5"
++		    "\x09\x11\x20\x41\xd3\xa1\x97\x83"),
++	},
++	/* RFC 7914: 11. Test Vectors for PBKDF2 with HMAC-SHA-256 */
++	{
++		STR(key, key_size, "Password"),
++		STR(salt, salt_size, "NaCl"),
++		.iter_count = 80000,
++		STR(output, output_size,
++		    "\x4d\xdc\xd8\xf6\x0b\x98\xbe\x21\x83\x0c\xee\x5e\xf2\x27"
++		    "\x01\xf9\x64\x1a\x44\x18\xd0\x4c\x04\x14\xae\xff\x08\x87"
++		    "\x6b\x34\xab\x56\xa1\xd4\x25\xa1\x22\x58\x33\x54\x9a\xdb"
++		    "\x84\x1b\x51\xc9\xb3\x17\x6a\x27\x2b\xde\xbb\xa1\xd0\x78"
++		    "\x47\x8f\x62\xb3\x97\xf3\x3c\x8d"),
++	},
++};
++
++static int test_pbkdf2(gnutls_mac_algorithm_t mac,
++		       const struct pbkdf2_vectors_st *vectors,
++		       size_t vectors_size, unsigned flags)
++{
++	unsigned int i;
++
++	for (i = 0; i < vectors_size; i++) {
++		gnutls_datum_t key, salt;
++		uint8_t output[4096];
++		int ret;
++
++		key.data = (void *) vectors[i].key;
++		key.size = vectors[i].key_size;
++		salt.data = (void *) vectors[i].salt;
++		salt.size = vectors[i].salt_size;
++
++		ret = gnutls_pbkdf2(mac, &key, &salt, vectors[i].iter_count,
++				    output, vectors[i].output_size);
++		if (ret < 0) {
++			_gnutls_debug_log("error calculating PBKDF2: MAC-%s\n",
++					  gnutls_mac_get_name(mac));
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++
++		if (memcmp(output, vectors[i].output, vectors[i].output_size) != 0) {
++			_gnutls_debug_log
++			    ("PBKDF2: MAC-%s test vector failed!\n",
++			     gnutls_mac_get_name(mac));
++
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++	}
++
++	_gnutls_debug_log
++	    ("PBKDF2: MAC-%s self check succeeded\n",
++	     gnutls_mac_get_name(mac));
++
++	return 0;
++}
++
++/*-
++ * gnutls_pbkdf2_self_test:
++ * @flags: GNUTLS_SELF_TEST_FLAG flags
++ * @mac: the message authentication algorithm to use
++ *
++ * This function will run self tests on PBKDF2 with the provided mac.
++ *
++ * Returns: Zero or a negative error code on error.
++ *
++ * Since: 3.3.0-FIPS140
++ -*/
++int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
++{
++	int ret;
++
++	if (flags & GNUTLS_SELF_TEST_FLAG_ALL)
++		mac = GNUTLS_MAC_UNKNOWN;
++
++	switch (mac) {
++	case GNUTLS_MAC_UNKNOWN:
++		CASE(GNUTLS_MAC_SHA256, test_pbkdf2, pbkdf2_sha256_vectors);
++
++		break;
++	default:
++		return gnutls_assert_val(GNUTLS_E_NO_SELF_TEST);
++	}
++
++	return 0;
++}
+diff --git a/lib/fips.c b/lib/fips.c
+index 48891ed57..7cfab1049 100644
+--- a/lib/fips.c
++++ b/lib/fips.c
+@@ -430,6 +430,13 @@ int _gnutls_fips_perform_self_checks2(void)
+ 		goto error;
+ 	}
+ 
++	/* PBKDF2 */
++	ret = gnutls_pbkdf2_self_test(0, GNUTLS_MAC_SHA256);
++	if (ret < 0) {
++		gnutls_assert();
++		goto error;
++	}
++
+ 	if (_gnutls_rnd_ops.self_test == NULL) {
+ 		gnutls_assert();
+ 		goto error;
+diff --git a/lib/includes/gnutls/self-test.h b/lib/includes/gnutls/self-test.h
+index 9b7be8159..958c0da8f 100644
+--- a/lib/includes/gnutls/self-test.h
++++ b/lib/includes/gnutls/self-test.h
+@@ -35,5 +35,6 @@ int gnutls_mac_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+ int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest);
+ int gnutls_pk_self_test(unsigned flags, gnutls_pk_algorithm_t pk);
+ int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
++int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+ 
+ #endif
+diff --git a/lib/libgnutls.map b/lib/libgnutls.map
+index 386b66f83..f5537a386 100644
+--- a/lib/libgnutls.map
++++ b/lib/libgnutls.map
+@@ -1348,6 +1348,7 @@ GNUTLS_FIPS140_3_4 {
+ 	gnutls_mac_self_test;
+ 	gnutls_digest_self_test;
+ 	gnutls_hkdf_self_test;
++	gnutls_pbkdf2_self_test;
+ 	#for FIPS140-2 validation
+ 	drbg_aes_reseed;
+ 	drbg_aes_init;
+-- 
+2.26.2
+
+
+From d1a3235e8c829855969d00364d8b5456fce2c78c Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Mon, 5 Oct 2020 17:44:30 +0200
+Subject: [PATCH 3/4] fips: add self-tests for TLS-PRF
+
+FIPS140-2 IG D.8 mandates self-tests on approved KDF algorithms.  As
+the guidance only requires to run a single instance of each KDF
+mechanism, this only exercises TLS1.2 PRF with HMAC-SHA-256 as the
+underlying MAC algorithm.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ devel/libgnutls-latest-x86_64.abi |   1 +
+ lib/crypto-selftests.c            | 196 ++++++++++++++++++++++++++++++
+ lib/fips.c                        |   7 ++
+ lib/includes/gnutls/self-test.h   |   1 +
+ lib/libgnutls.map                 |   1 +
+ 5 files changed, 206 insertions(+)
+
+diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
+index c4b0bd207..b740936d6 100644
+--- a/lib/crypto-selftests.c
++++ b/lib/crypto-selftests.c
+@@ -3183,3 +3183,199 @@ int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
+ 
+ 	return 0;
+ }
++
++struct tlsprf_vectors_st {
++	const uint8_t *key;
++	size_t key_size;
++	const uint8_t *label;
++	size_t label_size;
++	const uint8_t *seed;
++	size_t seed_size;
++	const uint8_t *output;
++	size_t output_size;
++};
++
++const struct tlsprf_vectors_st tls10prf_vectors[] = {
++	/* tests/tls10-prf.c: test1 */
++	{
++		STR(key, key_size,
++		    "\x26\x3b\xdb\xbb\x6f\x6d\x4c\x66\x4e\x05\x8d\x0a\xa9\xd3"
++		    "\x21\xbe"),
++		STR(label, label_size,
++		    "test label"),
++		STR(seed, seed_size,
++		    "\xb9\x20\x57\x3b\x19\x96\x01\x02\x4f\x04\xd6\xdc\x61\x96"
++		    "\x6e\x65"),
++		STR(output, output_size,
++		    "\x66\x17\x99\x37\x65\xfa\x6c\xa7\x03\xd1\x9e\xc7\x0d\xd5"
++		    "\xdd\x16\x0f\xfc\xc0\x77\x25\xfa\xfb\x71\x4a\x9f\x81\x5a"
++		    "\x2a\x30\xbf\xb7\xe3\xbb\xfb\x7e\xee\x57\x4b\x3b\x61\x3e"
++		    "\xb7\xfe\x80\xee\xc9\x69\x1d\x8c\x1b\x0e\x2d\x9b\x3c\x8b"
++		    "\x4b\x02\xb6\xb6\xd6\xdb\x88\xe2\x09\x46\x23\xef\x62\x40"
++		    "\x60\x7e\xda\x7a\xbe\x3c\x84\x6e\x82\xa3"),
++	},
++};
++
++const struct tlsprf_vectors_st tls12prf_sha256_vectors[] = {
++	/* tests/tls12-prf.c: sha256_test1 */
++	{
++		STR(key, key_size,
++		    "\x04\x50\xb0\xea\x9e\xcd\x36\x02\xee\x0d\x76\xc5\xc3\xc8"
++		    "\x6f\x4a"),
++		STR(label, label_size,
++		    "test label"),
++		STR(seed, seed_size,
++		    "\x20\x7a\xcc\x02\x54\xb8\x67\xf5\xb9\x25\xb4\x5a\x33\x60"
++		    "\x1d\x8b"),
++		STR(output, output_size,
++		    "\xae\x67\x9e\x0e\x71\x4f\x59\x75\x76\x37\x68\xb1\x66\x97"
++		    "\x9e\x1d"),
++	},
++	/* tests/tls12-prf.c: sha256_test2 */
++	{
++		STR(key, key_size,
++		    "\x34\x20\x4a\x9d\xf0\xbe\x6e\xb4\xe9\x25\xa8\x02\x7c\xf6"
++		    "\xc6\x02"),
++		STR(label, label_size,
++		    "test label"),
++		STR(seed, seed_size,
++		    "\x98\xb2\xc4\x0b\xcd\x66\x4c\x83\xbb\x92\x0c\x18\x20\x1a"
++		    "\x63\x95"),
++		STR(output, output_size,
++		    "\xaf\xa9\x31\x24\x53\xc2\x2f\xa8\x3d\x2b\x51\x1b\x37\x2d"
++		    "\x73\xa4\x02\xa2\xa6\x28\x73\x23\x9a\x51\xfa\xde\x45\x08"
++		    "\x2f\xaf\x3f\xd2\xbb\x7f\xfb\x3e\x9b\xf3\x6e\x28\xb3\x14"
++		    "\x1a\xab\xa4\x84\x00\x53\x32\xa9\xf9\xe3\x88\xa4\xd3\x29"
++		    "\xf1\x58\x7a\x4b\x31\x7d\xa0\x77\x08\xea\x1b\xa9\x5a\x53"
++		    "\xf8\x78\x67\x24\xbd\x83\xce\x4b\x03\xaf"),
++	},
++	/* tests/tls12-prf.c: sha256_test3 */
++	{
++		STR(key, key_size,
++		    "\xa3\x69\x1a\xa1\xf6\x81\x4b\x80\x59\x2b\xf1\xcf\x2a\xcf"
++		    "\x16\x97"),
++		STR(label, label_size,
++		    "test label"),
++		STR(seed, seed_size,
++		    "\x55\x23\xd4\x1e\x32\x0e\x69\x4d\x0c\x1f\xf5\x73\x4d\x83"
++		    "\x0b\x93\x3e\x46\x92\x70\x71\xc9\x26\x21"),
++		STR(output, output_size,
++		    "\x6a\xd0\x98\x4f\xa0\x6f\x78\xfe\x16\x1b\xd4\x6d\x7c\x26"
++		    "\x1d\xe4\x33\x40\xd7\x28\xdd\xdc\x3d\x0f\xf0\xdd\x7e\x0d"),
++	},
++	/* tests/tls12-prf.c: sha256_test4 */
++	{
++		STR(key, key_size,
++		    "\x21\x0e\xc9\x37\x06\x97\x07\xe5\x46\x5b\xc4\x6b\xf7\x79"
++		    "\xe1\x04\x10\x8b\x18\xfd\xb7\x93\xbe\x7b\x21\x8d\xbf\x14"
++		    "\x5c\x86\x41\xf3"),
++		STR(label, label_size,
++		    "test label"),
++		STR(seed, seed_size,
++		    "\x1e\x35\x1a\x0b\xaf\x35\xc7\x99\x45\x92\x43\x94\xb8\x81"
++		    "\xcf\xe3\x1d\xae\x8f\x1c\x1e\xd5\x4d\x3b"),
++		STR(output, output_size,
++		    "\x76\x53\xfa\x80\x9c\xde\x3b\x55\x3c\x4a\x17\xe2\xcd\xbc"
++		    "\xc9\x18\xf3\x65\x27\xf2\x22\x19\xa7\xd7\xf9\x5d\x97\x24"
++		    "\x3f\xf2\xd5\xde\xe8\x26\x5e\xf0\xaf\x03"),
++	},
++};
++
++const struct tlsprf_vectors_st tls12prf_sha384_vectors[] = {
++	/* tests/tls12-prf.c: sha384_test1
++	 * https://www.ietf.org/mail-archive/web/tls/current/msg03416.html
++	 */
++	{
++		STR(key, key_size,
++		    "\xb8\x0b\x73\x3d\x6c\xee\xfc\xdc\x71\x56\x6e\xa4\x8e\x55"
++		    "\x67\xdf"),
++		STR(label, label_size,
++		    "test label"),
++		STR(seed, seed_size,
++		    "\xcd\x66\x5c\xf6\xa8\x44\x7d\xd6\xff\x8b\x27\x55\x5e\xdb"
++		    "\x74\x65"),
++		STR(output, output_size,
++		    "\x7b\x0c\x18\xe9\xce\xd4\x10\xed\x18\x04\xf2\xcf\xa3\x4a"
++		    "\x33\x6a\x1c\x14\xdf\xfb\x49\x00\xbb\x5f\xd7\x94\x21\x07"
++		    "\xe8\x1c\x83\xcd\xe9\xca\x0f\xaa\x60\xbe\x9f\xe3\x4f\x82"
++		    "\xb1\x23\x3c\x91\x46\xa0\xe5\x34\xcb\x40\x0f\xed\x27\x00"
++		    "\x88\x4f\x9d\xc2\x36\xf8\x0e\xdd\x8b\xfa\x96\x11\x44\xc9"
++		    "\xe8\xd7\x92\xec\xa7\x22\xa7\xb3\x2f\xc3\xd4\x16\xd4\x73"
++		    "\xeb\xc2\xc5\xfd\x4a\xbf\xda\xd0\x5d\x91\x84\x25\x9b\x5b"
++		    "\xf8\xcd\x4d\x90\xfa\x0d\x31\xe2\xde\xc4\x79\xe4\xf1\xa2"
++		    "\x60\x66\xf2\xee\xa9\xa6\x92\x36\xa3\xe5\x26\x55\xc9\xe9"
++		    "\xae\xe6\x91\xc8\xf3\xa2\x68\x54\x30\x8d\x5e\xaa\x3b\xe8"
++		    "\x5e\x09\x90\x70\x3d\x73\xe5\x6f"),
++	},
++};
++
++static int test_tlsprf(gnutls_mac_algorithm_t mac,
++		       const struct tlsprf_vectors_st *vectors,
++		       size_t vectors_size, unsigned flags)
++{
++	unsigned int i;
++
++	for (i = 0; i < vectors_size; i++) {
++		char output[4096];
++		int ret;
++
++		ret = _gnutls_prf_raw(mac,
++				      vectors[i].key_size, vectors[i].key,
++				      vectors[i].label_size, (const char *)vectors[i].label,
++				      vectors[i].seed_size, vectors[i].seed,
++				      vectors[i].output_size, output);
++		if (ret < 0) {
++			_gnutls_debug_log("error calculating TLS-PRF: MAC-%s\n",
++					  gnutls_mac_get_name(mac));
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++
++		if (memcmp(output, vectors[i].output, vectors[i].output_size) != 0) {
++			_gnutls_debug_log
++			    ("TLS-PRF: MAC-%s test vector failed!\n",
++			     gnutls_mac_get_name(mac));
++
++			return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
++		}
++	}
++
++	_gnutls_debug_log
++	    ("TLS-PRF: MAC-%s self check succeeded\n",
++	     gnutls_mac_get_name(mac));
++
++	return 0;
++}
++
++/*-
++ * gnutls_tlsprf_self_test:
++ * @flags: GNUTLS_SELF_TEST_FLAG flags
++ * @mac: the message authentication algorithm to use
++ *
++ * This function will run self tests on TLS-PRF with the provided mac.
++ *
++ * Returns: Zero or a negative error code on error.
++ *
++ * Since: 3.3.0-FIPS140
++ -*/
++int gnutls_tlsprf_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
++{
++	int ret;
++
++	if (flags & GNUTLS_SELF_TEST_FLAG_ALL)
++		mac = GNUTLS_MAC_UNKNOWN;
++
++	switch (mac) {
++	case GNUTLS_MAC_UNKNOWN:
++		NON_FIPS_CASE(GNUTLS_MAC_MD5_SHA1, test_tlsprf, tls10prf_vectors);
++		FALLTHROUGH;
++		CASE(GNUTLS_MAC_SHA256, test_tlsprf, tls12prf_sha256_vectors);
++		FALLTHROUGH;
++		CASE(GNUTLS_MAC_SHA384, test_tlsprf, tls12prf_sha384_vectors);
++
++		break;
++	default:
++		return gnutls_assert_val(GNUTLS_E_NO_SELF_TEST);
++	}
++
++	return 0;
++}
+diff --git a/lib/fips.c b/lib/fips.c
+index 7cfab1049..30d396b2c 100644
+--- a/lib/fips.c
++++ b/lib/fips.c
+@@ -437,6 +437,13 @@ int _gnutls_fips_perform_self_checks2(void)
+ 		goto error;
+ 	}
+ 
++	/* TLS-PRF */
++	ret = gnutls_tlsprf_self_test(0, GNUTLS_MAC_SHA256);
++	if (ret < 0) {
++		gnutls_assert();
++		goto error;
++	}
++
+ 	if (_gnutls_rnd_ops.self_test == NULL) {
+ 		gnutls_assert();
+ 		goto error;
+diff --git a/lib/includes/gnutls/self-test.h b/lib/includes/gnutls/self-test.h
+index 958c0da8f..88b5a8dbf 100644
+--- a/lib/includes/gnutls/self-test.h
++++ b/lib/includes/gnutls/self-test.h
+@@ -36,5 +36,6 @@ int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest);
+ int gnutls_pk_self_test(unsigned flags, gnutls_pk_algorithm_t pk);
+ int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+ int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
++int gnutls_tlsprf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+ 
+ #endif
+diff --git a/lib/libgnutls.map b/lib/libgnutls.map
+index f5537a386..643d400a1 100644
+--- a/lib/libgnutls.map
++++ b/lib/libgnutls.map
+@@ -1349,6 +1349,7 @@ GNUTLS_FIPS140_3_4 {
+ 	gnutls_digest_self_test;
+ 	gnutls_hkdf_self_test;
+ 	gnutls_pbkdf2_self_test;
++	gnutls_tlsprf_self_test;
+ 	#for FIPS140-2 validation
+ 	drbg_aes_reseed;
+ 	drbg_aes_init;
+-- 
+2.26.2
+
+
+From af3df0102fc377591a6de3112b034d4a492fc92c Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Mon, 5 Oct 2020 17:59:46 +0200
+Subject: [PATCH 4/4] fips: run CMAC self-tests
+
+FIPS140-2 IG D.8 mandates self-tests on CMAC.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/fips.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/lib/fips.c b/lib/fips.c
+index 30d396b2c..51567953d 100644
+--- a/lib/fips.c
++++ b/lib/fips.c
+@@ -398,6 +398,12 @@ int _gnutls_fips_perform_self_checks2(void)
+ 		goto error;
+ 	}
+ 
++	ret = gnutls_mac_self_test(0, GNUTLS_MAC_AES_CMAC_256);
++	if (ret < 0) {
++		gnutls_assert();
++		goto error;
++	}
++
+ 	/* PK */
+ 	ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA);
+ 	if (ret < 0) {
+-- 
+2.26.2
+
diff --git a/SOURCES/gnutls-3.6.14-fix-iovec-memory-leak.patch b/SOURCES/gnutls-3.6.14-fix-iovec-memory-leak.patch
new file mode 100644
index 0000000..15b2c51
--- /dev/null
+++ b/SOURCES/gnutls-3.6.14-fix-iovec-memory-leak.patch
@@ -0,0 +1,152 @@
+From 6fbff7fc8aabeee2254405f254220bbe8c05c67d Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 5 Jun 2020 16:26:33 +0200
+Subject: [PATCH] crypto-api: always allocate memory when serializing iovec_t
+
+The AEAD iov interface falls back to serializing the input buffers if
+the low-level cipher doesn't support scatter/gather encryption.
+However, there was a bug in the functions used for the serialization,
+which causes memory leaks under a certain condition (i.e. the number
+of input buffers is 1).
+
+This patch makes the logic of the functions simpler, by removing a
+micro-optimization that tries to minimize the number of calls to
+malloc/free.
+
+The original problem was reported by Marius Steffen in:
+https://bugzilla.samba.org/show_bug.cgi?id=14399
+and the cause was investigated by Alexander Haase in:
+https://gitlab.com/gnutls/gnutls/-/merge_requests/1277
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/crypto-api.c        | 36 +++++++++++-------------------------
+ tests/aead-cipher-vec.c | 33 ++++++++++++++++++---------------
+ 2 files changed, 29 insertions(+), 40 deletions(-)
+
+diff --git a/lib/crypto-api.c b/lib/crypto-api.c
+index 45be64ed1..8524f5ed4 100644
+--- a/lib/crypto-api.c
++++ b/lib/crypto-api.c
+@@ -891,32 +891,23 @@ gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
+ struct iov_store_st {
+ 	void *data;
+ 	size_t size;
+-	unsigned allocated;
+ };
+ 
+ static void iov_store_free(struct iov_store_st *s)
+ {
+-	if (s->allocated) {
+-		gnutls_free(s->data);
+-		s->allocated = 0;
+-	}
++	gnutls_free(s->data);
+ }
+ 
+ static int iov_store_grow(struct iov_store_st *s, size_t length)
+ {
+-	if (s->allocated || s->data == NULL) {
+-		s->size += length;
+-		s->data = gnutls_realloc(s->data, s->size);
+-		if (s->data == NULL)
+-			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+-		s->allocated = 1;
+-	} else {
+-		void *data = s->data;
+-		size_t size = s->size + length;
+-		s->data = gnutls_malloc(size);
+-		memcpy(s->data, data, s->size);
+-		s->size += length;
+-	}
++	void *data;
++
++	s->size += length;
++	data = gnutls_realloc(s->data, s->size);
++	if (data == NULL)
++		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
++
++	s->data = data;
+ 	return 0;
+ }
+ 
+@@ -926,11 +917,6 @@ copy_from_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt)
+ 	memset(dst, 0, sizeof(*dst));
+ 	if (iovcnt == 0) {
+ 		return 0;
+-	} else if (iovcnt == 1) {
+-		dst->data = iov[0].iov_base;
+-		dst->size = iov[0].iov_len;
+-		/* implies: dst->allocated = 0; */
+-		return 0;
+ 	} else {
+ 		int i;
+ 		uint8_t *p;
+@@ -944,11 +930,11 @@ copy_from_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt)
+ 
+ 		p = dst->data;
+ 		for (i=0;i<iovcnt;i++) {
+-			memcpy(p, iov[i].iov_base, iov[i].iov_len);
++			if (iov[i].iov_len > 0)
++				memcpy(p, iov[i].iov_base, iov[i].iov_len);
+ 			p += iov[i].iov_len;
+ 		}
+ 
+-		dst->allocated = 1;
+ 		return 0;
+ 	}
+ }
+diff --git a/tests/aead-cipher-vec.c b/tests/aead-cipher-vec.c
+index fba9010d9..6a30a35f7 100644
+--- a/tests/aead-cipher-vec.c
++++ b/tests/aead-cipher-vec.c
+@@ -49,6 +49,7 @@ static void start(const char *name, int algo)
+ 	giovec_t auth_iov[2];
+ 	uint8_t tag[64];
+ 	size_t tag_size = 0;
++	size_t i;
+ 
+ 	key.data = key16;
+ 	key.size = gnutls_cipher_get_key_size(algo);
+@@ -82,21 +83,23 @@ static void start(const char *name, int algo)
+ 	if (ret < 0)
+ 		fail("gnutls_cipher_init: %s\n", gnutls_strerror(ret));
+ 
+-	ret = gnutls_aead_cipher_encryptv2(ch,
+-					   iv.data, iv.size,
+-					   auth_iov, 2,
+-					   iov, 3,
+-					   tag, &tag_size);
+-	if (ret < 0)
+-		fail("could not encrypt data: %s\n", gnutls_strerror(ret));
+-
+-	ret = gnutls_aead_cipher_decryptv2(ch,
+-					   iv.data, iv.size,
+-					   auth_iov, 2,
+-					   iov, 3,
+-					   tag, tag_size);
+-	if (ret < 0)
+-		fail("could not decrypt data: %s\n", gnutls_strerror(ret));
++	for (i = 0; i < 2; i++) {
++		ret = gnutls_aead_cipher_encryptv2(ch,
++						   iv.data, iv.size,
++						   auth_iov, 2,
++						   iov, i + 1,
++						   tag, &tag_size);
++		if (ret < 0)
++			fail("could not encrypt data: %s\n", gnutls_strerror(ret));
++
++		ret = gnutls_aead_cipher_decryptv2(ch,
++						   iv.data, iv.size,
++						   auth_iov, 2,
++						   iov, i + 1,
++						   tag, tag_size);
++		if (ret < 0)
++			fail("could not decrypt data: %s\n", gnutls_strerror(ret));
++	}
+ 
+ 	gnutls_aead_cipher_deinit(ch);
+ }
+-- 
+2.25.4
+
diff --git a/SOURCES/gnutls-3.6.14-memcmp.patch b/SOURCES/gnutls-3.6.14-memcmp.patch
new file mode 100644
index 0000000..a211c97
--- /dev/null
+++ b/SOURCES/gnutls-3.6.14-memcmp.patch
@@ -0,0 +1,131 @@
+From 9acc0f68320db4c7c6dadacb974e77c7fbca72a7 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Sun, 21 Jun 2020 16:03:54 +0200
+Subject: [PATCH] safe_memcmp: remove in favor of gnutls_memcmp
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/accelerated/x86/aes-xts-x86-aesni.c | 2 +-
+ lib/ext/pre_shared_key.c                | 2 +-
+ lib/mem.h                               | 9 ---------
+ lib/nettle/cipher.c                     | 8 ++++----
+ lib/tls13/finished.c                    | 2 +-
+ lib/x509/x509.c                         | 3 ++-
+ 6 files changed, 9 insertions(+), 17 deletions(-)
+
+diff --git a/lib/accelerated/x86/aes-xts-x86-aesni.c b/lib/accelerated/x86/aes-xts-x86-aesni.c
+index 3371d0812..b904cbf00 100644
+--- a/lib/accelerated/x86/aes-xts-x86-aesni.c
++++ b/lib/accelerated/x86/aes-xts-x86-aesni.c
+@@ -72,7 +72,7 @@ x86_aes_xts_cipher_setkey(void *_ctx, const void *userkey, size_t keysize)
+ 
+ 	/* Check key block according to FIPS-140-2 IG A.9 */
+ 	if (_gnutls_fips_mode_enabled()){
+-		if (safe_memcmp(key, key + (keysize / 2), keysize / 2) == 0) {
++		if (gnutls_memcmp(key, key + (keysize / 2), keysize / 2) == 0) {
+ 			_gnutls_switch_lib_state(LIB_STATE_ERROR);
+ 			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ 		}
+diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c
+index fef67d341..240be2162 100644
+--- a/lib/ext/pre_shared_key.c
++++ b/lib/ext/pre_shared_key.c
+@@ -650,7 +650,7 @@ static int server_recv_params(gnutls_session_t session,
+ 	}
+ 
+ 	if (_gnutls_mac_get_algo_len(prf) != binder_recvd.size ||
+-	    safe_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) {
++	    gnutls_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) {
+ 		gnutls_assert();
+ 		ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ 		goto fail;
+diff --git a/lib/mem.h b/lib/mem.h
+index dc838a2b4..d3eea97a4 100644
+--- a/lib/mem.h
++++ b/lib/mem.h
+@@ -35,15 +35,6 @@ char *_gnutls_strdup(const char *);
+ 
+ unsigned _gnutls_mem_is_zero(const uint8_t *ptr, unsigned size);
+ 
+-/* To avoid undefined behavior when s1 or s2 are null and n = 0 */
+-inline static
+-int safe_memcmp(const void *s1, const void *s2, size_t n)
+-{
+-	if (n == 0)
+-		return 0;
+-	return memcmp(s1, s2, n);
+-}
+-
+ #define zrelease_mpi_key(mpi) if (*mpi!=NULL) { \
+ 		_gnutls_mpi_clear(*mpi); \
+ 		_gnutls_mpi_release(mpi); \
+diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
+index b0a52deb5..ec0c1ab04 100644
+--- a/lib/nettle/cipher.c
++++ b/lib/nettle/cipher.c
+@@ -482,7 +482,7 @@ _xts_aes128_set_encrypt_key(struct xts_aes128_key *xts_key,
+ 			    const uint8_t *key)
+ {
+ 	if (_gnutls_fips_mode_enabled() &&
+-	    safe_memcmp(key, key + AES128_KEY_SIZE, AES128_KEY_SIZE) == 0)
++	    gnutls_memcmp(key, key + AES128_KEY_SIZE, AES128_KEY_SIZE) == 0)
+ 		_gnutls_switch_lib_state(LIB_STATE_ERROR);
+ 
+ 	xts_aes128_set_encrypt_key(xts_key, key);
+@@ -493,7 +493,7 @@ _xts_aes128_set_decrypt_key(struct xts_aes128_key *xts_key,
+ 			    const uint8_t *key)
+ {
+ 	if (_gnutls_fips_mode_enabled() &&
+-	    safe_memcmp(key, key + AES128_KEY_SIZE, AES128_KEY_SIZE) == 0)
++	    gnutls_memcmp(key, key + AES128_KEY_SIZE, AES128_KEY_SIZE) == 0)
+ 		_gnutls_switch_lib_state(LIB_STATE_ERROR);
+ 
+ 	xts_aes128_set_decrypt_key(xts_key, key);
+@@ -504,7 +504,7 @@ _xts_aes256_set_encrypt_key(struct xts_aes256_key *xts_key,
+ 			    const uint8_t *key)
+ {
+ 	if (_gnutls_fips_mode_enabled() &&
+-	    safe_memcmp(key, key + AES256_KEY_SIZE, AES256_KEY_SIZE) == 0)
++	    gnutls_memcmp(key, key + AES256_KEY_SIZE, AES256_KEY_SIZE) == 0)
+ 		_gnutls_switch_lib_state(LIB_STATE_ERROR);
+ 
+ 	xts_aes256_set_encrypt_key(xts_key, key);
+@@ -515,7 +515,7 @@ _xts_aes256_set_decrypt_key(struct xts_aes256_key *xts_key,
+ 			    const uint8_t *key)
+ {
+ 	if (_gnutls_fips_mode_enabled() &&
+-	    safe_memcmp(key, key + AES256_KEY_SIZE, AES256_KEY_SIZE) == 0)
++	    gnutls_memcmp(key, key + AES256_KEY_SIZE, AES256_KEY_SIZE) == 0)
+ 		_gnutls_switch_lib_state(LIB_STATE_ERROR);
+ 
+ 	xts_aes256_set_decrypt_key(xts_key, key);
+diff --git a/lib/tls13/finished.c b/lib/tls13/finished.c
+index 68eab993e..ec646e673 100644
+--- a/lib/tls13/finished.c
++++ b/lib/tls13/finished.c
+@@ -112,7 +112,7 @@ int _gnutls13_recv_finished(gnutls_session_t session)
+ #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+ # warning This is unsafe for production builds
+ #else
+-	if (safe_memcmp(verifier, buf.data, buf.length) != 0) {
++	if (gnutls_memcmp(verifier, buf.data, buf.length) != 0) {
+ 		gnutls_assert();
+ 		ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET;
+ 		goto cleanup;
+diff --git a/lib/x509/x509.c b/lib/x509/x509.c
+index 2091f3ae6..2b68fe440 100644
+--- a/lib/x509/x509.c
++++ b/lib/x509/x509.c
+@@ -360,7 +360,8 @@ static int compare_sig_algorithm(gnutls_x509_crt_t cert)
+ 	}
+ 
+ 	if (empty1 != empty2 ||
+-	    sp1.size != sp2.size || safe_memcmp(sp1.data, sp2.data, sp1.size) != 0) {
++	    sp1.size != sp2.size ||
++	    (sp1.size > 0 && memcmp(sp1.data, sp2.data, sp1.size) != 0)) {
+ 		gnutls_assert();
+ 		ret = GNUTLS_E_CERTIFICATE_ERROR;
+ 		goto cleanup;
+-- 
+2.26.2
+
diff --git a/SOURCES/gnutls-3.6.14-no-renegotiation.patch b/SOURCES/gnutls-3.6.14-no-renegotiation.patch
new file mode 100644
index 0000000..cb935bc
--- /dev/null
+++ b/SOURCES/gnutls-3.6.14-no-renegotiation.patch
@@ -0,0 +1,118 @@
+From 29ee67c205855e848a0a26e6d0e4f65b6b943e0a Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Sat, 22 Aug 2020 17:19:39 +0200
+Subject: [PATCH] handshake: reject no_renegotiation alert if handshake is
+ incomplete
+
+If the initial handshake is incomplete and the server sends a
+no_renegotiation alert, the client should treat it as a fatal error
+even if its level is warning.  Otherwise the same handshake
+state (e.g., DHE parameters) are reused in the next gnutls_handshake
+call, if it is called in the loop idiom:
+
+  do {
+          ret = gnutls_handshake(session);
+  } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ ...a04b3d3f7dcc0ab4571cf0df3b67ab7e1005e9e7a8 | Bin 0 -> 671 bytes
+ ...1da801fb3c6d1f7f846f227721e221adea08aa319c | Bin 0 -> 729 bytes
+ lib/gnutls_int.h                              |   1 +
+ lib/handshake.c                               |  48 +++++++++++++-----
+ 4 files changed, 36 insertions(+), 13 deletions(-)
+ create mode 100644 fuzz/gnutls_client_fuzzer.in/00ea40761ce11e769f1817a04b3d3f7dcc0ab4571cf0df3b67ab7e1005e9e7a8
+ create mode 100644 fuzz/gnutls_psk_client_fuzzer.in/b16434290b77e13d7a983d1da801fb3c6d1f7f846f227721e221adea08aa319c
+
+diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
+index bb6c19713..31cec5c0c 100644
+--- a/lib/gnutls_int.h
++++ b/lib/gnutls_int.h
+@@ -1370,6 +1370,7 @@ typedef struct {
+ #define HSK_RECORD_SIZE_LIMIT_RECEIVED (1<<26) /* server: record_size_limit extension was seen but not accepted yet */
+ #define HSK_OCSP_REQUESTED (1<<27) /* server: client requested OCSP stapling */
+ #define HSK_CLIENT_OCSP_REQUESTED (1<<28) /* client: server requested OCSP stapling */
++#define HSK_SERVER_HELLO_RECEIVED (1<<29) /* client: Server Hello message has been received */
+ 
+ 	/* The hsk_flags are for use within the ongoing handshake;
+ 	 * they are reset to zero prior to handshake start by gnutls_handshake. */
+diff --git a/lib/handshake.c b/lib/handshake.c
+index b40f84b3d..ce2d160e2 100644
+--- a/lib/handshake.c
++++ b/lib/handshake.c
+@@ -2061,6 +2061,8 @@ read_server_hello(gnutls_session_t session,
+ 	if (ret < 0)
+ 		return gnutls_assert_val(ret);
+ 
++	session->internals.hsk_flags |= HSK_SERVER_HELLO_RECEIVED;
++
+ 	return 0;
+ }
+ 
+@@ -2585,16 +2587,42 @@ int gnutls_rehandshake(gnutls_session_t session)
+ 	return 0;
+ }
+ 
++/* This function checks whether the error code should be treated fatal
++ * or not, and also does the necessary state transition.  In
++ * particular, in the case of a rehandshake abort it resets the
++ * handshake's internal state.
++ */
+ inline static int
+ _gnutls_abort_handshake(gnutls_session_t session, int ret)
+ {
+-	if (((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) &&
+-	     (gnutls_alert_get(session) == GNUTLS_A_NO_RENEGOTIATION))
+-	    || ret == GNUTLS_E_GOT_APPLICATION_DATA)
+-		return 0;
++	switch (ret) {
++	case GNUTLS_E_WARNING_ALERT_RECEIVED:
++		if (gnutls_alert_get(session) == GNUTLS_A_NO_RENEGOTIATION) {
++			/* The server always toleretes a "no_renegotiation" alert. */
++			if (session->security_parameters.entity == GNUTLS_SERVER) {
++				STATE = STATE0;
++				return ret;
++			}
++
++			/* The client should tolerete a "no_renegotiation" alert only if:
++			 * - the initial handshake has completed, or
++			 * - a Server Hello is not yet received
++			 */
++			if (session->internals.initial_negotiation_completed ||
++			    !(session->internals.hsk_flags & HSK_SERVER_HELLO_RECEIVED)) {
++				STATE = STATE0;
++				return ret;
++			}
+ 
+-	/* this doesn't matter */
+-	return GNUTLS_E_INTERNAL_ERROR;
++			return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
++		}
++		return ret;
++	case GNUTLS_E_GOT_APPLICATION_DATA:
++		STATE = STATE0;
++		return ret;
++	default:
++		return ret;
++	}
+ }
+ 
+ 
+@@ -2756,13 +2784,7 @@ int gnutls_handshake(gnutls_session_t session)
+ 	}
+ 
+ 	if (ret < 0) {
+-		/* In the case of a rehandshake abort
+-		 * we should reset the handshake's internal state.
+-		 */
+-		if (_gnutls_abort_handshake(session, ret) == 0)
+-			STATE = STATE0;
+-
+-		return ret;
++		return _gnutls_abort_handshake(session, ret);
+ 	}
+ 
+ 	/* clear handshake buffer */
+-- 
+2.26.2
+
diff --git a/SPECS/gnutls.spec b/SPECS/gnutls.spec
index d4caf4b..c3a7103 100644
--- a/SPECS/gnutls.spec
+++ b/SPECS/gnutls.spec
@@ -1,10 +1,17 @@
 Version:	3.6.14
-Release: 3%{?dist}
+Release: 7%{?dist}
 Patch1:	gnutls-3.2.7-rpath.patch
 Patch2:	gnutls-3.6.4-no-now-guile.patch
 Patch3:	gnutls-3.6.13-enable-intel-cet.patch
 Patch4:	gnutls-3.6.14-autogen-int.patch
 Patch5:	gnutls-3.6.14-fips-mode-check.patch
+Patch6:	gnutls-3.6.14-fips-dh-primes.patch
+Patch7:	gnutls-3.6.14-memcmp.patch
+Patch8:	gnutls-3.6.14-fips-dh-check.patch
+Patch9:	gnutls-3.6.14-fix-iovec-memory-leak.patch
+Patch10:	gnutls-3.6.14-fips-dh-selftests.patch
+Patch11:	gnutls-3.6.14-fips-kdf-selftests.patch
+Patch12:	gnutls-3.6.14-no-renegotiation.patch
 %bcond_without dane
 %if 0%{?rhel}
 %bcond_with guile
@@ -288,6 +295,20 @@ fi
 %endif
 
 %changelog
+* Tue Nov  3 2020 Daiki Ueno <dueno@redhat.com> - 3.6.14-7
+- Increase DH key bits to >= 2048 in self-tests (#1879506)
+- Implement self-tests for KDF and CMAC (#1890870)
+- Fix CVE-2020-24659: heap buffer-overflow when "no_renegotiation" alert is received (#1873959)
+
+* Mon Aug 24 2020 Daiki Ueno <dueno@redhat.com> - 3.6.14-6
+- Fix memory leak when serializing iovec_t (#1844112)
+
+* Sat Jul 18 2020 Daiki Ueno <dueno@redhat.com> - 3.6.14-5
+- Perform validation checks on (EC)DH public keys and share secrets (#1855803)
+
+* Mon Jun 29 2020 Daiki Ueno <dueno@redhat.com> - 3.6.14-4
+- Tighten FIPS DH primes check according to SP800-56A (rev 3) (#1849079)
+
 * Fri Jun  5 2020 Daiki Ueno <dueno@redhat.com> - 3.6.14-3
 - Update gnutls-3.6.14-fips-mode-check.patch