summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-17 08:55:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-17 08:55:56 +0000
commitf7f60c0deb84b0591f5a270c7c1ccf7679b08067 (patch)
tree05bb2064791a1193ef7d56ef7a8ea380b1220326
parentAdding debian version 3.7.9-2+deb12u2. (diff)
downloadgnutls28-debian.tar.xz
gnutls28-debian.zip
Adding debian version 3.7.9-2+deb12u3.debian/3.7.9-2+deb12u3debian
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--debian/changelog30
-rw-r--r--debian/patches/53-fips-fix-checking-on-hash-algorithm-used-in-ECDSA.patch306
-rw-r--r--debian/patches/54-fips-mark-composite-signature-API-not-approved.patch215
-rw-r--r--debian/patches/60-auth-rsa_psk-side-step-potential-side-channel.patch29
-rw-r--r--debian/patches/61-x509-detect-loop-in-certificate-chain.patch13
-rw-r--r--debian/patches/62-rsa-psk-minimize-branching-after-decryption.patch18
-rw-r--r--debian/patches/63_01-gnutls_x509_trust_list_verify_crt2-remove-length-lim.patch467
-rw-r--r--debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch493
-rw-r--r--debian/patches/63_03-serv-fix-memleak-when-a-connected-client-disappears.patch26
-rw-r--r--debian/patches/63_04-lib-fix-a-segfault-in-_gnutls13_recv_end_of_early_da.patch40
-rw-r--r--debian/patches/63_05-lib-fix-a-potential-segfault-in-_gnutls13_recv_finis.patch37
-rw-r--r--debian/patches/series7
12 files changed, 1650 insertions, 31 deletions
diff --git a/debian/changelog b/debian/changelog
index 34bc950..8c432bb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,33 @@
+gnutls28 (3.7.9-2+deb12u3) bookworm; urgency=medium
+
+ * Update to 3.7.11:
+ + Replace 60-auth-rsa_psk-side-step-potential-side-channel.patch
+ 61-x509-detect-loop-in-certificate-chain.patch
+ 62-rsa-psk-minimize-branching-after-decryption.patch with versions from
+ gnutls_3_7_x branch instead of manual backports from 3.8.x.
+ + Add 53-fips-fix-checking-on-hash-algorithm-used-in-ECDSA.patch (Fix
+ checking on hash algorithm used in ECDSA in FIPS mode) and
+ 54-fips-mark-composite-signature-API-not-approved.patch (Mark composite
+ signature API non-approved in FIPS mode.) to allow
+ straight cherry-picking of later patches.
+ + 63_01-gnutls_x509_trust_list_verify_crt2-remove-length-lim.patch
+ libgnutls: Fixed a bug where certtool crashed when verifying a
+ certificate chain with more than 16 certificates. Reported by William
+ Woodruff (#1525) and yixiangzhike (#1527). [GNUTLS-SA-2024-01-23, CVSS:
+ medium] [CVE-2024-28835] Closes: #1067463
+ + 63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch
+ libgnutls: Fix side-channel in the deterministic ECDSA.
+ Reported by George Pantelakis (#1516). [GNUTLS-SA-2023-12-04, CVSS:
+ medium] [CVE-2024-28834] Closes: #1067464
+ + 63_03-serv-fix-memleak-when-a-connected-client-disappears.patch
+ Fix a memleak in gnutls-serv when a connected client disappears.
+ + 63_04-lib-fix-a-segfault-in-_gnutls13_recv_end_of_early_da.patch
+ Fix a segfault in _gnutls13_recv_end_of_early_data().
+ + 63_05-lib-fix-a-potential-segfault-in-_gnutls13_recv_finis.patch
+ Fix a potential segfault in _gnutls13_recv_finished().
+
+ -- Andreas Metzler <ametzler@debian.org> Sat, 15 Jun 2024 13:22:35 +0200
+
gnutls28 (3.7.9-2+deb12u2) bookworm; urgency=medium
* Cherrypick two CVE fixes from 3.8.3:
diff --git a/debian/patches/53-fips-fix-checking-on-hash-algorithm-used-in-ECDSA.patch b/debian/patches/53-fips-fix-checking-on-hash-algorithm-used-in-ECDSA.patch
new file mode 100644
index 0000000..5e9080f
--- /dev/null
+++ b/debian/patches/53-fips-fix-checking-on-hash-algorithm-used-in-ECDSA.patch
@@ -0,0 +1,306 @@
+From 48bb9d0cf5de06cfb483aea66ff5a2c7aa3eb46f Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Tue, 20 Sep 2022 16:06:13 +0900
+Subject: [PATCH 08/29] fips: fix checking on hash algorithm used in ECDSA
+
+Previously we checked against the "preferred" hash algorithm based on
+the curve, instead of the one actually used.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/crypto-backend.h | 12 ++++---
+ lib/nettle/pk.c | 33 ++++++++---------
+ lib/pubkey.c | 5 ++-
+ tests/fips-test.c | 86 ++++++++++++++++++++++++++++++++++++++++++--
+ 4 files changed, 111 insertions(+), 25 deletions(-)
+
+--- a/lib/crypto-backend.h
++++ b/lib/crypto-backend.h
+@@ -245,15 +245,17 @@ typedef enum {
+ GNUTLS_PK_FLAG_PROVABLE = 1,
+ GNUTLS_PK_FLAG_REPRODUCIBLE = 2,
+ GNUTLS_PK_FLAG_RSA_PSS_FIXED_SALT_LENGTH = 4
+ } gnutls_pk_flag_t;
+
+-#define FIX_SIGN_PARAMS(params, flags, dig) do { \
+- if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) { \
+- (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE; \
+- (params).dsa_dig = (dig); \
+- } \
++#define FIX_SIGN_PARAMS(params, flags, dig) do { \
++ if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) { \
++ (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE; \
++ } \
++ if ((params).pk == GNUTLS_PK_DSA || (params).pk == GNUTLS_PK_ECDSA) { \
++ (params).dsa_dig = (dig); \
++ } \
+ } while (0)
+
+ void gnutls_pk_params_release(gnutls_pk_params_st * p);
+ void gnutls_pk_params_clear(gnutls_pk_params_st * p);
+ void gnutls_pk_params_init(gnutls_pk_params_st * p);
+--- a/lib/nettle/pk.c
++++ b/lib/nettle/pk.c
+@@ -1102,29 +1102,29 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ dsa_signature_init(&sig);
+
+ me = _gnutls_dsa_q_to_hash(pk_params,
+ &hash_len);
+
++ if (hash_len > vdata->size) {
++ gnutls_assert();
++ _gnutls_debug_log
++ ("Security level of algorithm requires hash %s(%d) or better\n",
++ _gnutls_mac_get_name(me), hash_len);
++ hash_len = vdata->size;
++ }
++
+ /* Only SHA-2 is allowed in FIPS 140-3 */
+- switch (me->id) {
++ switch (DIG_TO_MAC(sign_params->dsa_dig)) {
+ case GNUTLS_MAC_SHA256:
+ case GNUTLS_MAC_SHA384:
+ case GNUTLS_MAC_SHA512:
+ case GNUTLS_MAC_SHA224:
+ break;
+ default:
+ not_approved = true;
+ }
+
+- if (hash_len > vdata->size) {
+- gnutls_assert();
+- _gnutls_debug_log
+- ("Security level of algorithm requires hash %s(%d) or better\n",
+- _gnutls_mac_get_name(me), hash_len);
+- hash_len = vdata->size;
+- }
+-
+ mpz_init(k);
+ if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
+ (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
+ ret = _gnutls_ecdsa_compute_k(k,
+ curve_id,
+@@ -1543,11 +1543,10 @@ _wrap_nettle_pk_verify(gnutls_pk_algorit
+ {
+ struct ecc_point pub;
+ struct dsa_signature sig;
+ int curve_id = pk_params->curve;
+ const struct ecc_curve *curve;
+- const mac_entry_st *me;
+
+ curve = get_supported_nist_curve(curve_id);
+ if (curve == NULL) {
+ ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+ goto cleanup;
+@@ -1569,28 +1568,28 @@ _wrap_nettle_pk_verify(gnutls_pk_algorit
+ }
+
+ memcpy(sig.r, tmp[0], SIZEOF_MPZT);
+ memcpy(sig.s, tmp[1], SIZEOF_MPZT);
+
+- me = _gnutls_dsa_q_to_hash(pk_params, &hash_len);
++ (void)_gnutls_dsa_q_to_hash(pk_params, &hash_len);
++
++ if (hash_len > vdata->size)
++ hash_len = vdata->size;
+
+ /* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy
+ * mode */
+- switch (me->id) {
++ switch (DIG_TO_MAC(sign_params->dsa_dig)) {
+ case GNUTLS_MAC_SHA1:
+ case GNUTLS_MAC_SHA256:
+ case GNUTLS_MAC_SHA384:
+ case GNUTLS_MAC_SHA512:
+ case GNUTLS_MAC_SHA224:
+ break;
+ default:
+ not_approved = true;
+ }
+
+- if (hash_len > vdata->size)
+- hash_len = vdata->size;
+-
+ ret =
+ ecdsa_verify(&pub, hash_len, vdata->data,
+ &sig);
+ if (ret == 0) {
+ gnutls_assert();
+@@ -2388,12 +2387,14 @@ static int pct_test(gnutls_pk_algorithm_
+
+ memcpy(&spki, &params->spki, sizeof(spki));
+
+ if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) {
+ unsigned hash_len;
++ const mac_entry_st *me;
+
+- _gnutls_dsa_q_to_hash(params, &hash_len);
++ me = _gnutls_dsa_q_to_hash(params, &hash_len);
++ spki.dsa_dig = MAC_TO_DIG(me->id);
+ gen_data = gnutls_malloc(hash_len);
+ gnutls_rnd(GNUTLS_RND_NONCE, gen_data, hash_len);
+
+ ddata.data = (void*)gen_data;
+ ddata.size = hash_len;
+--- a/lib/pubkey.c
++++ b/lib/pubkey.c
+@@ -1983,11 +1983,11 @@ gnutls_pubkey_import_dsa_raw(gnutls_pubk
+ /* Updates the gnutls_x509_spki_st parameters based on the signature
+ * information, and reports any incompatibilities between the existing
+ * parameters (if any) with the signature algorithm */
+ static
+ int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_entry_st *se,
+- const mac_entry_st *me, gnutls_x509_spki_st *params)
++ const mac_entry_st *me, gnutls_x509_spki_st *params)
+ {
+ unsigned bits;
+
+ if (se->pk != key_params->algo) {
+ if (!sign_supports_priv_pk_algorithm(se, key_params->algo)) {
+@@ -2016,10 +2016,13 @@ int fixup_spki_params(const gnutls_pk_pa
+ params->salt_size = ret;
+ }
+
+ if (params->rsa_pss_dig != se->hash)
+ return gnutls_assert_val(GNUTLS_E_CONSTRAINT_ERROR);
++ } else if (params->pk == GNUTLS_PK_DSA ||
++ params->pk == GNUTLS_PK_ECDSA) {
++ params->dsa_dig = se->hash;
+ }
+
+ return 0;
+ }
+
+--- a/tests/fips-test.c
++++ b/tests/fips-test.c
+@@ -78,12 +78,26 @@ static const uint8_t rsa2342_sha1_sig_da
+ static const gnutls_datum_t rsa2342_sha1_sig = {
+ .data = (unsigned char *)rsa2342_sha1_sig_data,
+ .size = sizeof(rsa2342_sha1_sig_data),
+ };
+
++static const uint8_t ecc256_sha1_sig_data[] = {
++ 0x30, 0x45, 0x02, 0x21, 0x00, 0x9a, 0x28, 0xc9, 0xbf, 0xc8, 0x70, 0x4f,
++ 0x27, 0x2d, 0xe1, 0x66, 0xc4, 0xa5, 0xc6, 0xf2, 0xdc, 0x33, 0xb9, 0x41,
++ 0xdf, 0x78, 0x98, 0x8a, 0x22, 0x4d, 0x29, 0x37, 0xa0, 0x0f, 0x6f, 0xd4,
++ 0xed, 0x02, 0x20, 0x0b, 0x15, 0xca, 0x30, 0x09, 0x2d, 0x55, 0x44, 0xb4,
++ 0x1d, 0x3f, 0x48, 0x7a, 0xc3, 0xd1, 0x2a, 0xc1, 0x0e, 0x47, 0xfa, 0xe6,
++ 0xe9, 0x0f, 0x03, 0xe2, 0x01, 0x4e, 0xe4, 0x73, 0x37, 0xa7, 0x90,
++};
++
++static const gnutls_datum_t ecc256_sha1_sig = {
++ .data = (unsigned char *)ecc256_sha1_sig_data,
++ .size = sizeof(ecc256_sha1_sig_data),
++};
++
+ static void
+-rsa_import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
++import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
+ const char *filename)
+ {
+ const char *srcdir;
+ char path[256];
+ gnutls_datum_t tmp;
+@@ -422,11 +436,11 @@ void doit(void)
+ gnutls_x509_privkey_deinit(xprivkey);
+ FIPS_POP_CONTEXT(ERROR);
+
+ /* Import 2432-bit RSA key; not a security function */
+ FIPS_PUSH_CONTEXT();
+- rsa_import_keypair(&privkey, &pubkey, "rsa-2432.pem");
++ import_keypair(&privkey, &pubkey, "rsa-2432.pem");
+ FIPS_POP_CONTEXT(INITIAL);
+
+ /* Create a signature with 2432-bit RSA and SHA256; approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
+@@ -468,11 +482,11 @@ void doit(void)
+ gnutls_pubkey_deinit(pubkey);
+ gnutls_privkey_deinit(privkey);
+
+ /* Import 512-bit RSA key; not a security function */
+ FIPS_PUSH_CONTEXT();
+- rsa_import_keypair(&privkey, &pubkey, "rsa-512.pem");
++ import_keypair(&privkey, &pubkey, "rsa-512.pem");
+ FIPS_POP_CONTEXT(INITIAL);
+
+ /* Create a signature with 512-bit RSA and SHA256; not approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
+@@ -491,10 +505,76 @@ void doit(void)
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+ gnutls_pubkey_deinit(pubkey);
+ gnutls_privkey_deinit(privkey);
++
++ /* Import ECDSA key; not a security function */
++ FIPS_PUSH_CONTEXT();
++ import_keypair(&privkey, &pubkey, "ecc256.pem");
++ FIPS_POP_CONTEXT(INITIAL);
++
++ /* Create a signature with ECDSA and SHA256; approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
++ &data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_data2 failed\n");
++ }
++ FIPS_POP_CONTEXT(APPROVED);
++
++ /* Verify a signature with ECDSA and SHA256; approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
++ &data, &signature);
++ if (ret < 0) {
++ fail("gnutls_pubkey_verify_data2 failed\n");
++ }
++ FIPS_POP_CONTEXT(APPROVED);
++ gnutls_free(signature.data);
++
++ /* Create a signature with ECDSA and SHA256 (old API); approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
++ &data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_data failed\n");
++ }
++ FIPS_POP_CONTEXT(APPROVED);
++ gnutls_free(signature.data);
++
++ /* Create a signature with ECDSA and SHA-1; not approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
++ &data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_data2 failed\n");
++ }
++ FIPS_POP_CONTEXT(NOT_APPROVED);
++
++ /* Verify a signature created with ECDSA and SHA-1; approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA1,
++ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, &data,
++ &ecc256_sha1_sig);
++ if (ret < 0) {
++ fail("gnutls_pubkey_verify_data2 failed\n");
++ }
++ FIPS_POP_CONTEXT(APPROVED);
++ gnutls_free(signature.data);
++
++ /* Create a signature with ECDSA and SHA-1 (old API); not approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0,
++ &data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_data failed\n");
++ }
++ FIPS_POP_CONTEXT(NOT_APPROVED);
++ gnutls_free(signature.data);
++ gnutls_pubkey_deinit(pubkey);
++ gnutls_privkey_deinit(privkey);
+
+ /* Test RND functions */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16));
+ if (ret < 0) {
diff --git a/debian/patches/54-fips-mark-composite-signature-API-not-approved.patch b/debian/patches/54-fips-mark-composite-signature-API-not-approved.patch
new file mode 100644
index 0000000..6091367
--- /dev/null
+++ b/debian/patches/54-fips-mark-composite-signature-API-not-approved.patch
@@ -0,0 +1,215 @@
+From 02faaf6f8b490fee465d07e020473386425ffdd2 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Thu, 29 Sep 2022 17:13:00 +0900
+Subject: [PATCH 09/29] fips: mark composite signature API not-approved
+
+This makes the FIPS service indicator to transit to not-approved when
+gnutls_privkey_sign_hash* is used. In FIPS, single-shot
+API (gnutls_privkey_sign_data*) is preferred over composite API.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/privkey.c | 42 ++++++++++++++++++++++---------
+ tests/fips-test.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 94 insertions(+), 12 deletions(-)
+
+--- a/lib/privkey.c
++++ b/lib/privkey.c
+@@ -1249,31 +1249,40 @@ gnutls_privkey_sign_hash2(gnutls_privkey
+ /* the corresponding signature algorithm is SIGN_RSA_RAW,
+ * irrespective of hash algorithm. */
+ se = _gnutls_sign_to_entry(GNUTLS_SIGN_RSA_RAW);
+ } else {
+ se = _gnutls_sign_to_entry(algo);
+- if (unlikely(se == NULL))
+- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+-
++ if (unlikely(se == NULL)) {
++ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
++ goto cleanup;
++ }
+ }
+
+ ret = _gnutls_privkey_get_spki_params(signer, &params);
+ if (ret < 0) {
+ gnutls_assert();
+- return ret;
++ goto cleanup;
+ }
+
+ ret = _gnutls_privkey_update_spki_params(signer, se->pk, se->hash,
+ flags, &params);
+ if (ret < 0) {
+ gnutls_assert();
+- return ret;
++ goto cleanup;
+ }
+
+ FIX_SIGN_PARAMS(params, flags, se->hash);
+
+- return privkey_sign_prehashed(signer, se, hash_data, signature, &params);
++ ret = privkey_sign_prehashed(signer, se, hash_data, signature, &params);
++
++ cleanup:
++ if (ret < 0) {
++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
++ } else {
++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
++ }
++ return ret;
+ }
+
+ int
+ privkey_sign_and_hash_data(gnutls_privkey_t signer,
+ const gnutls_sign_entry_st *se,
+@@ -1364,18 +1373,18 @@ gnutls_privkey_sign_hash(gnutls_privkey_
+ const gnutls_sign_entry_st *se;
+
+ ret = _gnutls_privkey_get_spki_params(signer, &params);
+ if (ret < 0) {
+ gnutls_assert();
+- return ret;
++ goto cleanup;
+ }
+
+ ret = _gnutls_privkey_update_spki_params(signer, signer->pk_algorithm,
+ hash_algo, flags, &params);
+ if (ret < 0) {
+ gnutls_assert();
+- return ret;
++ goto cleanup;
+ }
+
+ /* legacy callers of this API could use a hash algorithm of 0 (unknown)
+ * to indicate raw hashing. As we now always want to know the signing
+ * algorithm involved, we try discovering the hash algorithm. */
+@@ -1389,17 +1398,26 @@ gnutls_privkey_sign_hash(gnutls_privkey_
+ se = _gnutls_sign_to_entry(GNUTLS_SIGN_RSA_RAW);
+ } else {
+ se = _gnutls_pk_to_sign_entry(params.pk, hash_algo);
+ }
+
+- if (unlikely(se == NULL))
+- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
++ if (unlikely(se == NULL)) {
++ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
++ goto cleanup;
++ }
+
+ FIX_SIGN_PARAMS(params, flags, hash_algo);
+
+- return privkey_sign_prehashed(signer, se,
+- hash_data, signature, &params);
++ ret = privkey_sign_prehashed(signer, se,
++ hash_data, signature, &params);
++ cleanup:
++ if (ret < 0) {
++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
++ } else {
++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
++ }
++ return ret;
+ }
+
+ static int
+ privkey_sign_prehashed(gnutls_privkey_t signer,
+ const gnutls_sign_entry_st *se,
+--- a/tests/fips-test.c
++++ b/tests/fips-test.c
+@@ -286,10 +286,12 @@ void doit(void)
+ gnutls_datum_t key = { key16, sizeof(key16) };
+ gnutls_datum_t iv = { iv16, sizeof(iv16) };
+ gnutls_datum_t signature;
+ unsigned int bits;
+ uint8_t hmac[64];
++ uint8_t hash[64];
++ gnutls_datum_t hashed_data;
+
+ fprintf(stderr,
+ "Please note that if in FIPS140 mode, you need to assure the library's integrity prior to running this test\n");
+
+ gnutls_global_set_log_function(tls_log_func);
+@@ -538,10 +540,40 @@ void doit(void)
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_data failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
++
++ /* Create a SHA256 hashed data for 2-pass signature API; not a
++ * crypto operation */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, data.data, data.size, hash);
++ if (ret < 0) {
++ fail("gnutls_hash_fast failed\n");
++ }
++ hashed_data.data = hash;
++ hashed_data.size = 32;
++ FIPS_POP_CONTEXT(INITIAL);
++
++ /* Create a signature with ECDSA and SHA256 (2-pass API); not-approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
++ &hashed_data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_hash2 failed\n");
++ }
++ FIPS_POP_CONTEXT(NOT_APPROVED);
++ gnutls_free(signature.data);
++
++ /* Create a signature with ECDSA and SHA256 (2-pass old API); not-approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA256, 0,
++ &hashed_data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_hash failed\n");
++ }
++ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA-1; not approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
+@@ -569,10 +601,42 @@ void doit(void)
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_data failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
++
++ /* Create a SHA1 hashed data for 2-pass signature API; not a
++ * crypto operation */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, data.data, data.size, hash);
++ if (ret < 0) {
++ fail("gnutls_hash_fast failed\n");
++ }
++ hashed_data.data = hash;
++ hashed_data.size = 20;
++ FIPS_POP_CONTEXT(INITIAL);
++
++ /* Create a signature with ECDSA and SHA1 (2-pass API); not-approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
++ &hashed_data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_hash2 failed\n");
++ }
++ FIPS_POP_CONTEXT(NOT_APPROVED);
++ gnutls_free(signature.data);
++
++ /* Create a signature with ECDSA and SHA1 (2-pass old API); not-approved */
++ FIPS_PUSH_CONTEXT();
++ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, 0,
++ &hashed_data, &signature);
++ if (ret < 0) {
++ fail("gnutls_privkey_sign_hash failed\n");
++ }
++ FIPS_POP_CONTEXT(NOT_APPROVED);
++ gnutls_free(signature.data);
++
+ gnutls_pubkey_deinit(pubkey);
+ gnutls_privkey_deinit(privkey);
+
+ /* Test RND functions */
+ FIPS_PUSH_CONTEXT();
diff --git a/debian/patches/60-auth-rsa_psk-side-step-potential-side-channel.patch b/debian/patches/60-auth-rsa_psk-side-step-potential-side-channel.patch
index e85c16a..d87bb10 100644
--- a/debian/patches/60-auth-rsa_psk-side-step-potential-side-channel.patch
+++ b/debian/patches/60-auth-rsa_psk-side-step-potential-side-channel.patch
@@ -1,7 +1,7 @@
-From 29d6298d0b04cfff970b993915db71ba3f580b6d Mon Sep 17 00:00:00 2001
+From c176c35e17d0add934785cb8db1a6c2d14ae9659 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 23 Oct 2023 09:26:57 +0900
-Subject: [PATCH] auth/rsa_psk: side-step potential side-channel
+Subject: [PATCH 11/29] auth/rsa_psk: side-step potential side-channel
This removes branching that depends on secret data, porting changes
for regular RSA key exchange from
@@ -13,10 +13,10 @@ depending on the branching.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/auth/rsa.c | 2 +-
- lib/auth/rsa_psk.c | 90 ++++++++++++++++++----------------------------
- lib/gnutls_int.h | 4 ---
+ lib/auth/rsa_psk.c | 93 +++++++++++++++++-----------------------------
+ lib/gnutls_int.h | 4 --
lib/priority.c | 1 -
- 4 files changed, 35 insertions(+), 62 deletions(-)
+ 4 files changed, 35 insertions(+), 65 deletions(-)
--- a/lib/auth/rsa.c
+++ b/lib/auth/rsa.c
@@ -55,7 +55,7 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
if (cred == NULL) {
-@@ -327,75 +326,53 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_se
+@@ -327,75 +326,51 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_se
gnutls_assert();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
@@ -101,6 +101,10 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
+ premaster_secret.data = gnutls_malloc(GNUTLS_MASTER_SIZE);
+ if (premaster_secret.data == NULL) {
++ gnutls_assert();
++ return GNUTLS_E_MEMORY_ERROR;
++ }
++ premaster_secret.size = GNUTLS_MASTER_SIZE;
- if (randomize_key != 0) {
- premaster_secret.size = GNUTLS_MASTER_SIZE;
@@ -122,19 +126,14 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
- } else {
- premaster_secret.data = plaintext.data;
- premaster_secret.size = plaintext.size;
-+ gnutls_assert();
-+ return GNUTLS_E_MEMORY_ERROR;
- }
-+ premaster_secret.size = GNUTLS_MASTER_SIZE;
-+
+ /* Fallback value when decryption fails. Needs to be unpredictable. */
+ ret = gnutls_rnd(GNUTLS_RND_NONCE, premaster_secret.data,
+ premaster_secret.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
-+ }
-+
+ }
+
+ gnutls_privkey_decrypt_data2(session->internals.selected_key, 0,
+ &ciphertext, premaster_secret.data,
+ premaster_secret.size);
@@ -152,11 +151,11 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
+ * in the paper "Attacking RSA-based sessions in SSL/TLS" by
+ * Vlastimil Klima, Ondej Pokorny and Tomas Rosa.
+ */
-
++
/* This is here to avoid the version check attack
* discussed above.
*/
-
+-
- premaster_secret.data[0] = _gnutls_get_adv_version_major(session);
- premaster_secret.data[1] = _gnutls_get_adv_version_minor(session);
+ premaster_secret.data[0] = ver_maj;
diff --git a/debian/patches/61-x509-detect-loop-in-certificate-chain.patch b/debian/patches/61-x509-detect-loop-in-certificate-chain.patch
index 8464ca4..9959931 100644
--- a/debian/patches/61-x509-detect-loop-in-certificate-chain.patch
+++ b/debian/patches/61-x509-detect-loop-in-certificate-chain.patch
@@ -1,7 +1,7 @@
-From 9edbdaa84e38b1bfb53a7d72c1de44f8de373405 Mon Sep 17 00:00:00 2001
+From 2774bd6db7968d62297c97d36e28d8d9cb508cb9 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Thu, 11 Jan 2024 15:45:11 +0900
-Subject: [PATCH 1/2] x509: detect loop in certificate chain
+Subject: [PATCH 12/29] x509: detect loop in certificate chain
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -17,8 +17,8 @@ manner.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/x509/common.c | 4 ++
- tests/test-chains.h | 125 ++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 129 insertions(+)
+ tests/test-chains.h | 124 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 128 insertions(+)
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -173,14 +173,13 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
# pragma GCC diagnostic ignored "-Wunused-variable"
#endif
-@@ -4440,10 +4563,12 @@ static struct
+@@ -4440,10 +4563,11 @@ static struct
0, NULL, 1620052390, 1},
{ "rsa-sha1 not in trusted - not ok",
rsa_sha1_not_in_trusted, rsa_sha1_not_in_trusted_ca,
GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM),
GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID, NULL, 1620118136, 1},
-+ { "cross signed - ok", cross_signed, cross_signed_ca, 0, 0, 0,
-+ 1704955300 },
++ { "cross signed - ok", cross_signed, cross_signed_ca, 0, 0, 0, 1704955300 },
{ NULL, NULL, NULL, 0, 0}
};
diff --git a/debian/patches/62-rsa-psk-minimize-branching-after-decryption.patch b/debian/patches/62-rsa-psk-minimize-branching-after-decryption.patch
index 47de317..b0ba2ce 100644
--- a/debian/patches/62-rsa-psk-minimize-branching-after-decryption.patch
+++ b/debian/patches/62-rsa-psk-minimize-branching-after-decryption.patch
@@ -1,7 +1,7 @@
-From 40dbbd8de499668590e8af51a15799fbc430595e Mon Sep 17 00:00:00 2001
+From f0aa7285c3ef702d4e5c13e54d6fe741e44244c3 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Wed, 10 Jan 2024 19:13:17 +0900
-Subject: [PATCH 2/2] rsa-psk: minimize branching after decryption
+Subject: [PATCH 13/29] rsa-psk: minimize branching after decryption
This moves any non-trivial code between gnutls_privkey_decrypt_data2
and the function return in _gnutls_proc_rsa_psk_client_kx up until the
@@ -9,8 +9,8 @@ decryption. This also avoids an extra memcpy to session->key.key.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
- lib/auth/rsa_psk.c | 69 ++++++++++++++++++++++++----------------------
- 1 file changed, 36 insertions(+), 33 deletions(-)
+ lib/auth/rsa_psk.c | 68 ++++++++++++++++++++++++----------------------
+ 1 file changed, 35 insertions(+), 33 deletions(-)
--- a/lib/auth/rsa_psk.c
+++ b/lib/auth/rsa_psk.c
@@ -26,7 +26,7 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
cred = (gnutls_psk_server_credentials_t)
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
-@@ -329,29 +328,52 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_se
+@@ -329,28 +328,52 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_se
ciphertext.size = dsize;
ver_maj = _gnutls_get_adv_version_major(session);
@@ -34,6 +34,7 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
- premaster_secret.data = gnutls_malloc(GNUTLS_MASTER_SIZE);
- if (premaster_secret.data == NULL) {
+- gnutls_assert();
+ /* Find the key of this username. A random value will be
+ * filled in if the key is not found.
+ */
@@ -41,8 +42,7 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
+ strlen(info->username), &pwd_psk);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
-
-- gnutls_assert();
++
+ /* Allocate memory for premaster secret, and fill in the
+ * fields except the decryption result.
+ */
@@ -88,12 +88,12 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
* channel that can be used as an oracle, so tread carefully */
/* Error handling logic:
-@@ -367,35 +389,14 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_se
+@@ -365,35 +388,14 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_se
+ */
/* This is here to avoid the version check attack
* discussed above.
*/
-
- premaster_secret.data[0] = ver_maj;
- premaster_secret.data[1] = ver_min;
-
diff --git a/debian/patches/63_01-gnutls_x509_trust_list_verify_crt2-remove-length-lim.patch b/debian/patches/63_01-gnutls_x509_trust_list_verify_crt2-remove-length-lim.patch
new file mode 100644
index 0000000..e211d66
--- /dev/null
+++ b/debian/patches/63_01-gnutls_x509_trust_list_verify_crt2-remove-length-lim.patch
@@ -0,0 +1,467 @@
+From af594c776a8502dab04e61e97228efdcff32bf19 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Mon, 29 Jan 2024 13:52:46 +0900
+Subject: [PATCH 1/5] gnutls_x509_trust_list_verify_crt2: remove length limit
+ of input
+
+Previously, if cert_list_size exceeded DEFAULT_MAX_VERIFY_DEPTH, the
+chain verification logic crashed with assertion failure. This patch
+removes the restriction while keeping the maximum number of
+retrieved certificates being DEFAULT_MAX_VERIFY_DEPTH.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/gnutls_int.h | 5 +-
+ lib/x509/common.c | 10 +-
+ lib/x509/verify-high.c | 73 ++++++++------
+ tests/test-chains.h | 212 ++++++++++++++++++++++++++++++++++++++++-
+ 4 files changed, 268 insertions(+), 32 deletions(-)
+
+--- a/lib/gnutls_int.h
++++ b/lib/gnutls_int.h
+@@ -222,11 +222,14 @@ typedef enum record_send_state_t {
+ processes before aborting. */
+ #define MAX_HANDSHAKE_HELLO_VERIFY_REQUESTS 5
+
+ #define MAX_PK_PARAM_SIZE 2048
+
+-/* defaults for verification functions
++/* Defaults for verification functions.
++ *
++ * update many_icas in tests/test-chains.h when increasing
++ * DEFAULT_MAX_VERIFY_DEPTH.
+ */
+ #define DEFAULT_MAX_VERIFY_DEPTH 16
+ #define DEFAULT_MAX_VERIFY_BITS (MAX_PK_PARAM_SIZE*8)
+ #define MAX_VERIFY_DEPTH 4096
+
+--- a/lib/x509/common.c
++++ b/lib/x509/common.c
+@@ -1753,11 +1753,19 @@ unsigned int _gnutls_sort_clist(gnutls_x
+ unsigned int i, j, k;
+ int issuer[DEFAULT_MAX_VERIFY_DEPTH]; /* contain the index of the issuers */
+ bool insorted[DEFAULT_MAX_VERIFY_DEPTH]; /* non zero if clist[i] used in sorted list */
+ gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH];
+
+- assert(clist_size <= DEFAULT_MAX_VERIFY_DEPTH);
++ /* Limit the number of certificates in the chain, to avoid DoS
++ * because of the O(n^2) sorting below. FIXME: Switch to a
++ * topological sort algorithm which should be linear to the
++ * number of certificates and subject-issuer relationships.
++ */
++ if (clist_size > DEFAULT_MAX_VERIFY_DEPTH) {
++ _gnutls_debug_log("too many certificates; skipping sorting\n");
++ return 1;
++ }
+
+ for (i = 0; i < DEFAULT_MAX_VERIFY_DEPTH; i++) {
+ issuer[i] = -1;
+ insorted[i] = 0;
+ }
+--- a/lib/x509/verify-high.c
++++ b/lib/x509/verify-high.c
+@@ -22,15 +22,15 @@
+ */
+
+ #include "gnutls_int.h"
+ #include "errors.h"
+ #include <libtasn1.h>
+-#include <global.h>
+-#include <num.h> /* MAX */
+-#include <tls-sig.h>
+-#include <str.h>
+-#include <datum.h>
++#include "global.h"
++#include "num.h" /* MIN */
++#include "tls-sig.h"
++#include "str.h"
++#include "datum.h"
+ #include <hash-pjw-bare.h>
+ #include "x509_int.h"
+ #include <common.h>
+ #include <gnutls/x509-ext.h>
+ #include "verify-high.h"
+@@ -1355,11 +1355,12 @@ gnutls_x509_trust_list_verify_crt2(gnutl
+ gnutls_verify_output_function func)
+ {
+ int ret = 0;
+ unsigned int i;
+ size_t hash;
+- gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH];
++ gnutls_x509_crt_t *cert_list_copy = NULL;
++ unsigned int cert_list_max_size = 0;
+ gnutls_x509_crt_t retrieved[DEFAULT_MAX_VERIFY_DEPTH];
+ unsigned int retrieved_size = 0;
+ const char *hostname = NULL, *purpose = NULL, *email = NULL;
+ unsigned hostname_size = 0;
+ unsigned have_set_name = 0;
+@@ -1409,30 +1410,44 @@ gnutls_x509_trust_list_verify_crt2(gnutl
+ *voutput = vtmp;
+ return 0;
+ }
+ }
+
+- memcpy(sorted, cert_list, cert_list_size * sizeof(gnutls_x509_crt_t));
+- cert_list = sorted;
++ /* Allocate extra for retrieved certificates. */
++ if (!INT_ADD_OK(cert_list_size, DEFAULT_MAX_VERIFY_DEPTH,
++ &cert_list_max_size))
++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+- records = gl_list_nx_create_empty(GL_LINKEDHASH_LIST, cert_eq, cert_hashcode, NULL, false);
+- if (records == NULL)
++ cert_list_copy = _gnutls_reallocarray(NULL, cert_list_max_size,
++ sizeof(gnutls_x509_crt_t));
++ if (!cert_list_copy)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+- for (i = 0; i < cert_list_size &&
+- cert_list_size <= DEFAULT_MAX_VERIFY_DEPTH; ) {
++ memcpy(cert_list_copy, cert_list,
++ cert_list_size * sizeof(gnutls_x509_crt_t));
++ cert_list = cert_list_copy;
++
++ records = gl_list_nx_create_empty(GL_LINKEDHASH_LIST, cert_eq,
++ cert_hashcode, NULL, false);
++ if (records == NULL) {
++ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
++ goto cleanup;
++ }
++
++ for (i = 0; i < cert_list_size;) {
+ unsigned int sorted_size = 1;
+ unsigned int j;
+ gnutls_x509_crt_t issuer;
+
+ if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN)) {
+ sorted_size = _gnutls_sort_clist(&cert_list[i],
+ cert_list_size - i);
+ }
+
+- /* Remove duplicates. Start with index 1, as the first element
+- * may be re-checked after issuer retrieval. */
++ assert(sorted_size > 0);
++
++ /* Remove duplicates. */
+ for (j = 0; j < sorted_size; j++) {
+ if (gl_list_search(records, cert_list[i + j])) {
+ if (i + j < cert_list_size - 1) {
+ memmove(&cert_list[i + j],
+ &cert_list[i + j + 1],
+@@ -1472,23 +1487,22 @@ gnutls_x509_trust_list_verify_crt2(gnutl
+ gnutls_x509_crt_check_issuer(cert_list[i - 1],
+ cert_list[i])) {
+ continue;
+ }
+
+- ret = retrieve_issuers(list,
+- cert_list[i - 1],
+- &retrieved[retrieved_size],
+- DEFAULT_MAX_VERIFY_DEPTH -
+- MAX(retrieved_size,
+- cert_list_size));
++ ret = retrieve_issuers(
++ list, cert_list[i - 1], &retrieved[retrieved_size],
++ MIN(DEFAULT_MAX_VERIFY_DEPTH - retrieved_size,
++ cert_list_max_size - cert_list_size));
+ if (ret < 0) {
+ break;
+ } else if (ret > 0) {
+ assert((unsigned int)ret <=
+- DEFAULT_MAX_VERIFY_DEPTH - cert_list_size);
+- memmove(&cert_list[i + ret],
+- &cert_list[i],
++ DEFAULT_MAX_VERIFY_DEPTH - retrieved_size);
++ assert((unsigned int)ret <=
++ cert_list_max_size - cert_list_size);
++ memmove(&cert_list[i + ret], &cert_list[i],
+ (cert_list_size - i) *
+ sizeof(gnutls_x509_crt_t));
+ memcpy(&cert_list[i],
+ &retrieved[retrieved_size],
+ ret * sizeof(gnutls_x509_crt_t));
+@@ -1500,12 +1514,14 @@ gnutls_x509_trust_list_verify_crt2(gnutl
+ gl_list_remove(records, cert_list[i]);
+ }
+ }
+
+ cert_list_size = shorten_clist(list, cert_list, cert_list_size);
+- if (cert_list_size <= 0)
+- return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
++ if (cert_list_size <= 0) {
++ ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
++ goto cleanup;
++ }
+
+ hash =
+ hash_pjw_bare(cert_list[cert_list_size - 1]->raw_issuer_dn.
+ data,
+ cert_list[cert_list_size -
+@@ -1651,15 +1667,18 @@ gnutls_x509_trust_list_verify_crt2(gnutl
+ ret = 0;
+ goto cleanup;
+ }
+ }
+
+- cleanup:
++cleanup:
++ gnutls_free(cert_list_copy);
+ for (i = 0; i < retrieved_size; i++) {
+ gnutls_x509_crt_deinit(retrieved[i]);
+ }
+- gl_list_free(records);
++ if (records) {
++ gl_list_free(records);
++ }
+ return ret;
+ }
+
+ /**
+ * gnutls_x509_trust_list_verify_named_crt:
+--- a/tests/test-chains.h
++++ b/tests/test-chains.h
+@@ -21,13 +21,11 @@
+ */
+
+ #ifndef GNUTLS_TESTS_TEST_CHAINS_H
+ #define GNUTLS_TESTS_TEST_CHAINS_H
+
+-/* *INDENT-OFF* */
+-
+-#define MAX_CHAIN 10
++#define MAX_CHAIN 17
+
+ static const char *chain_with_no_subject_id_in_ca_ok[] = {
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIFVDCCBDygAwIBAgIQR+AAAAAAXtwVoBdbGUjUQDANBgkqhkiG9w0BAQsFADBv\n"
+ "MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRowGAYDVQQLExFTZWN1\n"
+@@ -4384,10 +4382,217 @@ static const char *cross_signed_ca[] = {
+ "bDeZ2XJH+BdVFwg=\n"
+ "-----END CERTIFICATE-----\n",
+ NULL
+ };
+
++/* This assumes DEFAULT_MAX_VERIFY_DEPTH to be 16 */
++static const char *many_icas[] = {
++ /* Server */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBqzCCAV2gAwIBAgIUIK3+SD3GmqJlRLZ/ESyhTzkSDL8wBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowNzEbMBkGA1UEChMSR251VExTIHRlc3Qgc2VydmVyMRgwFgYD\n"
++ "VQQDEw90ZXN0LmdudXRscy5vcmcwKjAFBgMrZXADIQAWGjx45NIJiKFsNBxxRRjm\n"
++ "NxUT5KYK7xXr5HPVywwgLaOBkjCBjzAMBgNVHRMBAf8EAjAAMBoGA1UdEQQTMBGC\n"
++ "D3Rlc3QuZ251dGxzLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8E\n"
++ "BAMCB4AwHQYDVR0OBBYEFKgNAQWZPx76/vXqQOdIi5mTftsaMB8GA1UdIwQYMBaA\n"
++ "FDaPsY6WAGuRtrhYJE6Gk/bg5qbdMAUGAytlcANBAMIDh8aGcIIFDTUrzfV7tnkX\n"
++ "hHrxyFKBH/cApf6xcJQTfDXm23po627Ibp+WgLaWMY08Fn9Y2V6Ev8ADfqXNbQ8=\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA16 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUSnE0PKdm/dsnZSWBh5Ct4pS6DcwwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAxq9SI8vp0QH1dDBBuZW+t+bLLROppQbjSQ4O1BEonDOjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBQ2j7GOlgBrkba4\n"
++ "WCROhpP24Oam3TAfBgNVHSMEGDAWgBRvdUKX0aw3nfUIdvivXGSfRO7zyjAFBgMr\n"
++ "ZXADQQBsI2Hc7X5hXoHTvk01qMc5a1I27QHAFRARJnvIQ15wxNS2LVLzGk+AUmwr\n"
++ "sOhBKAcVfS55uWtYdjoWQ80h238H\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA15 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUQk4XkgQVImnp6OPZas7ctwgBza4wBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAs3yVKLJd3sKbNVmj6Bxy2j1x025rksyQpZZWnCx5a+CjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBRvdUKX0aw3nfUI\n"
++ "dvivXGSfRO7zyjAfBgNVHSMEGDAWgBRhGfUXYPh4YQsdtTWYUozLphGgfzAFBgMr\n"
++ "ZXADQQBXTtm56x6/pHXdW8dTvZLc/8RufNQrMlc23TCgX0apUnrZdTsNAb7OE4Uu\n"
++ "9PBuxK+CC9NL/BL2hXsKvAT+NWME\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA14 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUKfwz7UUYRvYlvqwmnLJlTOS9o1AwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAXbUetQ08t+F4+IcKL++HpeclqTxXZ7cG4mwqvHmTUEWjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBRhGfUXYPh4YQsd\n"
++ "tTWYUozLphGgfzAfBgNVHSMEGDAWgBQYRQqO+V1kefF7QvNnFU1fX5H9+jAFBgMr\n"
++ "ZXADQQAiSHNMTLPFP3oa6q13Dj8jSxF9trQDJGM1ArWffFcPZUt2U4/ODHdcMTHx\n"
++ "kGwhIj+ghBlu6ykgu6J2wewCUooC\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA13 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUUKOs59gyCPAZzoC7zMZQSh6AnQgwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAmvqhj5GYqsXIpsr1BXBfD+2mTP/m/TEpKIYSZHM62dijYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBQYRQqO+V1kefF7\n"
++ "QvNnFU1fX5H9+jAfBgNVHSMEGDAWgBQ27HzvP5hl2xR+LOzRcPfmY5ndXjAFBgMr\n"
++ "ZXADQQBrB3NkrYC7EQ74qgeesVOE71rW012dPOOKPAV0laR+JLEgsv9sfus+AdBF\n"
++ "WBNwR3KeYBTi/MFDuecxBHU2m5gD\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA12 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUUQooGfH21+sR7/pSgCWm13gg2H4wBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAK2of/B4wMpk6k/KdugC5dMS+jo2fseUM7/PvXkE6HASjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBQ27HzvP5hl2xR+\n"
++ "LOzRcPfmY5ndXjAfBgNVHSMEGDAWgBSJDHU0Mj1Xr0e8ErCnRK24w7XwTTAFBgMr\n"
++ "ZXADQQDY8d2bAZpj7oGhdl2dBsCE48jEWj49da0PbgN12koAj3gf4hjMPd8G7p5z\n"
++ "8RsURAwQmCkE8ShvdNw/Qr2tDL0E\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA11 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUW9Dw0hU2pfjXhb5Stip+mk9SndIwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAn5ISjLVV6RBWsnxDWHDicpye7SjFwGOTwzF01/psiJ2jYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBSJDHU0Mj1Xr0e8\n"
++ "ErCnRK24w7XwTTAfBgNVHSMEGDAWgBSR9UU27RI0XohiEgHDxNo/9HP4djAFBgMr\n"
++ "ZXADQQCfQg6MDHk71vhyrEo4/5PcLb2Li5F/FKURyux7snv2TbkSdInloAqca9UR\n"
++ "DtqHSLCNLXCNdSPr5QwIt5p29rsE\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA10 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUR4uTedG8e6MibKViQ3eX7QzXG1swBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAnslX04kSVOL5LAf1e+Ze3ggNnDJcEAxLDk8I/IhyjTyjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBSR9UU27RI0Xohi\n"
++ "EgHDxNo/9HP4djAfBgNVHSMEGDAWgBRC7US5gJYnvd5F7EN+C4anMgd2NzAFBgMr\n"
++ "ZXADQQDo+jHt07Tvz3T5Lbz6apBrSln8xKYfJk2W1wP85XAnf7sZT9apM1bS4EyD\n"
++ "Kckw+KG+9x7myOZz6AXJgZB5OGAO\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA9 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUSIIIRjrNpE+kEPkiJMOqaNAazvQwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAZKy7p1Gn4W/reRxKJN99+QkHt2q9aELktCKe5PqrX5ejYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBRC7US5gJYnvd5F\n"
++ "7EN+C4anMgd2NzAfBgNVHSMEGDAWgBSOhR7Ornis2x8g0J+bvTTwMnW60zAFBgMr\n"
++ "ZXADQQA0MEcC4FgKZEAfalVpApU2to0G158MVz/WTNcSc7fnl8ifJ/g56dVHL1jr\n"
++ "REvC/S28dn/CGAlbVXUAgxnHAbgE\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA8 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUGGFSgD95vOTSj7iFxfXA5vq6vsYwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAg3W/bTdW0fR32NeZEVMXICpa30d7rSdddLOYDvqqUO+jYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBSOhR7Ornis2x8g\n"
++ "0J+bvTTwMnW60zAfBgNVHSMEGDAWgBT3zK8Hbn9aVTAOOFY6RSxJ2o5x2jAFBgMr\n"
++ "ZXADQQBl4gnzE463iMFg57gPvjHdVzA39sJBpiu0kUGfRcLnoRI/VOaLcx7WnJ9+\n"
++ "c3KxPZBec76EdIoQDkTmI6m2FIAM\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA7 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUGktMGXhNuaMhKyAlecymmLD+/GIwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEA/Z1oc76hOQ0Hi+2hePaGIntnMIDqBlb7RDMjRpYONP2jYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBT3zK8Hbn9aVTAO\n"
++ "OFY6RSxJ2o5x2jAfBgNVHSMEGDAWgBSPae3JUN3jP0NgUJqDV3eYxcaM3DAFBgMr\n"
++ "ZXADQQBMkwKaUZlvG/hax8rv3nnDv8kJOr6KVHBnxSx3hZ+8HIBT7GFm1+YDeYOB\n"
++ "jhNg66kyeFPGXXBCe+mvNQFFjCEE\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA6 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUKn3gz5lAUpKqWlHKLKYDbOJ4rygwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAZ/eD4eTe91ddvHusm7YlLPxU4ByGFc6suAmlP1CxXkWjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBSPae3JUN3jP0Ng\n"
++ "UJqDV3eYxcaM3DAfBgNVHSMEGDAWgBT9f/qSI/jhxvGI7aMtkpraDcjBnjAFBgMr\n"
++ "ZXADQQAMRnkmRhnLGdmJaY8B42gfyaAsqCMyds/Tw4OHYy+N48XuAxRjKkhf3szC\n"
++ "0lY71oU043mNP1yx/dzAuCTrVSgI\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA5 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUEgEYbBXXEyGv3vOq10JQv1SBiUUwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAs2xEDPw8RVal53nX9GVwUd1blq1wjtVFC8S1V7up7MWjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBT9f/qSI/jhxvGI\n"
++ "7aMtkpraDcjBnjAfBgNVHSMEGDAWgBRBVkLu9BmCKz7HNI8md4vPpoE/7jAFBgMr\n"
++ "ZXADQQCCufAyLijtzzmeCuO3K50rBSbGvB3FQfep7g6kVsQKM3bw/olWK5/Ji0dD\n"
++ "ubJ0cFl1FmfAda7aVxLBtJOvO6MI\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA4 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIULj8GkaHw+92HuOTnXnXlxCy3VrEwBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAiedxh4dvtwDellMAHc/pZH0MAOXobRenTUgF1yj5l12jYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBRBVkLu9BmCKz7H\n"
++ "NI8md4vPpoE/7jAfBgNVHSMEGDAWgBSDtNRgQ36KwW/ASaMyr6WeDt0STDAFBgMr\n"
++ "ZXADQQDL8U2ckzur7CktdrVUNvfLhVCOz33d/62F28vQFHUa8h/4h+Mi1MMbXOKT\n"
++ "1bL2TvpFpU7Fx/vcIPXDielVqr4C\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA3 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUQXl74TDDw6MQRMbQUSPa6Qrvba8wBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEA7l0jQ0f4fJRw7Qja/Hz2qn8y91SI7CokxhSf+FT+9M6jYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBSDtNRgQ36KwW/A\n"
++ "SaMyr6WeDt0STDAfBgNVHSMEGDAWgBQ2inEK4KH6ATftmybxKE1dZUzOozAFBgMr\n"
++ "ZXADQQCnP7Oqx1epGnFnO7TrTJwcUukXDEYsINve2GeUsi8HEIeKKlMcLZ2Cnaj7\n"
++ "5v9NGuWh3QJpmmSGpEemiv8dJc4A\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA2 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBYTCCAROgAwIBAgIUP7Nmof8H2F1LyDkjqlYIUpGdXE8wBQYDK2VwMB0xGzAZ\n"
++ "BgNVBAMMEkdudVRMUyB0ZXN0IElDQSAkaTAgFw0yNDAzMTIyMjUzMzlaGA85OTk5\n"
++ "MTIzMTIzNTk1OVowHTEbMBkGA1UEAwwSR251VExTIHRlc3QgSUNBICRpMCowBQYD\n"
++ "K2VwAyEAkW9Rod3CXAnha6nlaHkDbCOegq94lgmjqclA9sOIt3yjYzBhMA8GA1Ud\n"
++ "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBQ2inEK4KH6ATft\n"
++ "mybxKE1dZUzOozAfBgNVHSMEGDAWgBRPq/CQlK/zuXkjZvTCibu+vejD+jAFBgMr\n"
++ "ZXADQQBU+A+uF0yrtO/yv9cRUdCoL3Y1NKM35INg8BQDnkv724cW9zk1x0q9Fuou\n"
++ "zvfSVb8S3vT8fF5ZDOxarQs6ZH0C\n"
++ "-----END CERTIFICATE-----\n",
++ /* ICA1 */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBXTCCAQ+gAwIBAgIUfUWP+AQHpdFTRKTf21mMzjaJsp0wBQYDK2VwMBkxFzAV\n"
++ "BgNVBAMTDkdudVRMUyB0ZXN0IENBMCAXDTI0MDMxMjIyNTMzOVoYDzk5OTkxMjMx\n"
++ "MjM1OTU5WjAdMRswGQYDVQQDDBJHbnVUTFMgdGVzdCBJQ0EgJGkwKjAFBgMrZXAD\n"
++ "IQAVmfBAvLbT+pTD24pQrr6S0jEIFIV/qOv93yYvAUzpzKNjMGEwDwYDVR0TAQH/\n"
++ "BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0OBBYEFE+r8JCUr/O5eSNm9MKJ\n"
++ "u7696MP6MB8GA1UdIwQYMBaAFAFpt5wrFsqCtHc4PpluPDvwcxQLMAUGAytlcANB\n"
++ "AC6+XZnthjlUD0TbBKRF3qT5if3Pp29Bgvutw8859unzUZW8FkHg5KeDBj9ncgJc\n"
++ "O2tFnNH2hV6LDPJzU0rtLQc=\n"
++ "-----END CERTIFICATE-----\n",
++ NULL
++};
++
++static const char *many_icas_ca[] = {
++ /* CA (self-signed) */
++ "-----BEGIN CERTIFICATE-----\n"
++ "MIIBNzCB6qADAgECAhRjaokcQwcrtW8tjuVFz3A33F8POjAFBgMrZXAwGTEXMBUG\n"
++ "A1UEAxMOR251VExTIHRlc3QgQ0EwIBcNMjQwMzEyMjI1MzM5WhgPOTk5OTEyMzEy\n"
++ "MzU5NTlaMBkxFzAVBgNVBAMTDkdudVRMUyB0ZXN0IENBMCowBQYDK2VwAyEAvoxP\n"
++ "TNdbWktxA8qQNNH+25Cx9rzP+DxLGeI/7ODwrQGjQjBAMA8GA1UdEwEB/wQFMAMB\n"
++ "Af8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBQBabecKxbKgrR3OD6Zbjw78HMU\n"
++ "CzAFBgMrZXADQQCP5IUD74M7WrUx20uqzrzuj+s2jnBVmLQfWf/Ucetx+oTRFeq4\n"
++ "xZB/adWhycSeJUAB1zKqYUV9hgT8FWHbnHII\n"
++ "-----END CERTIFICATE-----\n",
++ NULL
++};
++
+ #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+ # pragma GCC diagnostic push
+ # pragma GCC diagnostic ignored "-Wunused-variable"
+ #endif
+
+@@ -4564,10 +4769,11 @@ static struct
+ { "rsa-sha1 not in trusted - not ok",
+ rsa_sha1_not_in_trusted, rsa_sha1_not_in_trusted_ca,
+ GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM),
+ GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID, NULL, 1620118136, 1},
+ { "cross signed - ok", cross_signed, cross_signed_ca, 0, 0, 0, 1704955300 },
++ { "many intermediates - ok", many_icas, many_icas_ca, 0, 0, 0, 1710284400 },
+ { NULL, NULL, NULL, 0, 0}
+ };
+
+ #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+ # pragma GCC diagnostic pop
diff --git a/debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch b/debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch
new file mode 100644
index 0000000..71a751d
--- /dev/null
+++ b/debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch
@@ -0,0 +1,493 @@
+From 6f6c8db008e943967a5d0f706e2884c23baa0aa7 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 12 Jan 2024 17:56:58 +0900
+Subject: [PATCH 2/5] nettle: avoid normalization of mpz_t in deterministic
+ ECDSA
+
+This removes function calls that potentially leak bit-length of a
+private key used to calculate a nonce in deterministic ECDSA. Namely:
+
+- _gnutls_dsa_compute_k has been rewritten to work on always
+ zero-padded mp_limb_t arrays instead of mpz_t
+- rnd_mpz_func has been replaced with rnd_datum_func, which is backed
+ by a byte array instead of an mpz_t value
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/nettle/int/dsa-compute-k.c | 84 +++++++++++++++++++------------
+ lib/nettle/int/dsa-compute-k.h | 31 +++++++++---
+ lib/nettle/int/ecdsa-compute-k.c | 33 +++---------
+ lib/nettle/int/ecdsa-compute-k.h | 8 +--
+ lib/nettle/pk.c | 79 ++++++++++++++++++++---------
+ tests/sign-verify-deterministic.c | 2 +-
+ 6 files changed, 139 insertions(+), 98 deletions(-)
+
+--- a/lib/nettle/int/dsa-compute-k.c
++++ b/lib/nettle/int/dsa-compute-k.c
+@@ -29,53 +29,58 @@
+ #include "gnutls_int.h"
+ #include "mem.h"
+ #include "mpn-base256.h"
+ #include <string.h>
+
+-#define BITS_TO_LIMBS(bits) (((bits) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
++/* For mini-gmp */
++#ifndef GMP_LIMB_BITS
++#define GMP_LIMB_BITS GMP_NUMB_BITS
++#endif
++
++static inline int is_zero_limb(mp_limb_t x)
++{
++ x |= (x << 1);
++ return ((x >> 1) - 1) >> (GMP_LIMB_BITS - 1);
++}
++
++static int sec_zero_p(const mp_limb_t *ap, mp_size_t n)
++{
++ volatile mp_limb_t w;
++ mp_size_t i;
++
++ for (i = 0, w = 0; i < n; i++)
++ w |= ap[i];
+
+-/* The maximum size of q, chosen from the fact that we support
+- * 521-bit elliptic curve generator and 512-bit DSA subgroup at
+- * maximum. */
+-#define MAX_Q_BITS 521
+-#define MAX_Q_SIZE ((MAX_Q_BITS + 7) / 8)
+-#define MAX_Q_LIMBS BITS_TO_LIMBS(MAX_Q_BITS)
+-
+-#define MAX_HASH_BITS (MAX_HASH_SIZE * 8)
+-#define MAX_HASH_LIMBS BITS_TO_LIMBS(MAX_HASH_BITS)
+-
+-int
+-_gnutls_dsa_compute_k(mpz_t k,
+- const mpz_t q,
+- const mpz_t x,
+- gnutls_mac_algorithm_t mac,
+- const uint8_t *digest,
+- size_t length)
++ return is_zero_limb(w);
++}
++
++int _gnutls_dsa_compute_k(mp_limb_t *h, const mp_limb_t *q, const mp_limb_t *x,
++ mp_size_t qn, mp_bitcnt_t q_bits,
++ gnutls_mac_algorithm_t mac, const uint8_t *digest,
++ size_t length)
+ {
+ uint8_t V[MAX_HASH_SIZE];
+ uint8_t K[MAX_HASH_SIZE];
+ uint8_t xp[MAX_Q_SIZE];
+ uint8_t tp[MAX_Q_SIZE];
+- mp_limb_t h[MAX(MAX_Q_LIMBS, MAX_HASH_LIMBS)];
+- mp_bitcnt_t q_bits = mpz_sizeinbase (q, 2);
+- mp_size_t qn = mpz_size(q);
+ mp_bitcnt_t h_bits = length * 8;
+ mp_size_t hn = BITS_TO_LIMBS(h_bits);
+ size_t nbytes = (q_bits + 7) / 8;
+ const uint8_t c0 = 0x00;
+ const uint8_t c1 = 0x01;
+ mp_limb_t cy;
+ gnutls_hmac_hd_t hd;
+ int ret = 0;
++ mp_limb_t scratch[MAX_Q_LIMBS];
+
+ if (unlikely(q_bits > MAX_Q_BITS))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ if (unlikely(length > MAX_HASH_SIZE))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ /* int2octets(x) */
+- mpn_get_base256(xp, nbytes, mpz_limbs_read(x), qn);
++ mpn_get_base256(xp, nbytes, x, qn);
+
+ /* bits2octets(h) */
+ mpn_set_base256(h, hn, digest, length);
+
+ if (hn < qn)
+@@ -95,16 +100,16 @@ _gnutls_dsa_compute_k(mpz_t k,
+
+ if (shift % GMP_NUMB_BITS > 0)
+ mpn_rshift(h, h, hn, shift % GMP_NUMB_BITS);
+ }
+
+- cy = mpn_sub_n(h, h, mpz_limbs_read(q), qn);
++ cy = mpn_sub_n(h, h, q, qn);
+ /* Fall back to addmul_1, if nettle is linked with mini-gmp. */
+ #ifdef mpn_cnd_add_n
+- mpn_cnd_add_n(cy, h, h, mpz_limbs_read(q), qn);
++ mpn_cnd_add_n(cy, h, h, q, qn);
+ #else
+- mpn_addmul_1(h, mpz_limbs_read(q), qn, cy != 0);
++ mpn_addmul_1(h, q, qn, cy != 0);
+ #endif
+ mpn_get_base256(tp, nbytes, h, qn);
+
+ /* Step b */
+ memset(V, c1, length);
+@@ -176,16 +181,12 @@ _gnutls_dsa_compute_k(mpz_t k,
+ /* Step 3 */
+ mpn_set_base256 (h, qn, tp, tlen);
+ if (tlen * 8 > q_bits)
+ mpn_rshift (h, h, qn, tlen * 8 - q_bits);
+ /* Check if k is in [1,q-1] */
+- if (!mpn_zero_p (h, qn) &&
+- mpn_cmp (h, mpz_limbs_read(q), qn) < 0) {
+- mpn_copyi(mpz_limbs_write(k, qn), h, qn);
+- mpz_limbs_finish(k, qn);
++ if (!sec_zero_p(h, qn) && mpn_sub_n(scratch, h, q, qn))
+ break;
+- }
+
+ ret = gnutls_hmac_init(&hd, mac, K, length);
+ if (ret < 0)
+ goto out;
+ ret = gnutls_hmac(hd, V, length);
+@@ -205,5 +206,26 @@ _gnutls_dsa_compute_k(mpz_t k,
+ zeroize_key(xp, sizeof(xp));
+ zeroize_key(tp, sizeof(tp));
+
+ return ret;
+ }
++
++/* cancel-out dsa_sign's addition of 1 to random data */
++void _gnutls_dsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
++ mp_size_t n)
++{
++ /* Fall back to sub_1, if nettle is linked with mini-gmp. */
++#ifdef mpn_sec_sub_1
++ mp_limb_t t[MAX_Q_LIMBS];
++
++ mpn_sec_sub_1(h, h, n, 1, t);
++#else
++ mpn_sub_1(h, h, n, 1);
++#endif
++ mpn_get_base256(k, nbytes, h, n);
++}
++
++void _gnutls_ecdsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
++ mp_size_t n)
++{
++ mpn_get_base256(k, nbytes, h, n);
++}
+--- a/lib/nettle/int/dsa-compute-k.h
++++ b/lib/nettle/int/dsa-compute-k.h
+@@ -24,14 +24,31 @@
+ #define GNUTLS_LIB_NETTLE_INT_DSA_COMPUTE_K_H
+
+ #include <gnutls/gnutls.h>
+ #include <nettle/bignum.h> /* includes gmp.h */
+
+-int
+-_gnutls_dsa_compute_k(mpz_t k,
+- const mpz_t q,
+- const mpz_t x,
+- gnutls_mac_algorithm_t mac,
+- const uint8_t *digest,
+- size_t length);
++#define BITS_TO_LIMBS(bits) (((bits) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
++
++/* The maximum size of q, chosen from the fact that we support
++ * 521-bit elliptic curve generator and 512-bit DSA subgroup at
++ * maximum. */
++#define MAX_Q_BITS 521
++#define MAX_Q_SIZE ((MAX_Q_BITS + 7) / 8)
++#define MAX_Q_LIMBS BITS_TO_LIMBS(MAX_Q_BITS)
++
++#define MAX_HASH_BITS (MAX_HASH_SIZE * 8)
++#define MAX_HASH_LIMBS BITS_TO_LIMBS(MAX_HASH_BITS)
++
++#define DSA_COMPUTE_K_ITCH MAX(MAX_Q_LIMBS, MAX_HASH_LIMBS)
++
++int _gnutls_dsa_compute_k(mp_limb_t *h, const mp_limb_t *q, const mp_limb_t *x,
++ mp_size_t qn, mp_bitcnt_t q_bits,
++ gnutls_mac_algorithm_t mac, const uint8_t *digest,
++ size_t length);
++
++void _gnutls_dsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
++ mp_size_t n);
++
++void _gnutls_ecdsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
++ mp_size_t n);
+
+ #endif /* GNUTLS_LIB_NETTLE_INT_DSA_COMPUTE_K_H */
+--- a/lib/nettle/int/ecdsa-compute-k.c
++++ b/lib/nettle/int/ecdsa-compute-k.c
+@@ -27,43 +27,42 @@
+ #include "ecdsa-compute-k.h"
+
+ #include "dsa-compute-k.h"
+ #include "gnutls_int.h"
+
+-static inline int
+-_gnutls_ecc_curve_to_dsa_q(mpz_t *q, gnutls_ecc_curve_t curve)
++int _gnutls_ecc_curve_to_dsa_q(mpz_t q, gnutls_ecc_curve_t curve)
+ {
+ switch (curve) {
+ #ifdef ENABLE_NON_SUITEB_CURVES
+ case GNUTLS_ECC_CURVE_SECP192R1:
+- mpz_init_set_str(*q,
++ mpz_init_set_str(q,
+ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836"
+ "146BC9B1B4D22831",
+ 16);
+ return 0;
+ case GNUTLS_ECC_CURVE_SECP224R1:
+- mpz_init_set_str(*q,
++ mpz_init_set_str(q,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2"
+ "E0B8F03E13DD29455C5C2A3D",
+ 16);
+ return 0;
+ #endif
+ case GNUTLS_ECC_CURVE_SECP256R1:
+- mpz_init_set_str(*q,
++ mpz_init_set_str(q,
+ "FFFFFFFF00000000FFFFFFFFFFFFFFFF"
+ "BCE6FAADA7179E84F3B9CAC2FC632551",
+ 16);
+ return 0;
+ case GNUTLS_ECC_CURVE_SECP384R1:
+- mpz_init_set_str(*q,
++ mpz_init_set_str(q,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFFFFFFFFFFFFFFFC7634D81F4372DDF"
+ "581A0DB248B0A77AECEC196ACCC52973",
+ 16);
+ return 0;
+ case GNUTLS_ECC_CURVE_SECP521R1:
+- mpz_init_set_str(*q,
++ mpz_init_set_str(q,
+ "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFA51868783BF2F966B7FCC0148F709A"
+ "5D03BB5C9B8899C47AEBB6FB71E91386"
+ "409",
+@@ -71,25 +70,5 @@ _gnutls_ecc_curve_to_dsa_q(mpz_t *q, gnu
+ return 0;
+ default:
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ }
+ }
+-
+-int
+-_gnutls_ecdsa_compute_k (mpz_t k,
+- gnutls_ecc_curve_t curve,
+- const mpz_t x,
+- gnutls_mac_algorithm_t mac,
+- const uint8_t *digest,
+- size_t length)
+-{
+- mpz_t q;
+- int ret;
+-
+- ret = _gnutls_ecc_curve_to_dsa_q(&q, curve);
+- if (ret < 0)
+- return gnutls_assert_val(ret);
+-
+- ret = _gnutls_dsa_compute_k (k, q, x, mac, digest, length);
+- mpz_clear(q);
+- return ret;
+-}
+--- a/lib/nettle/int/ecdsa-compute-k.h
++++ b/lib/nettle/int/ecdsa-compute-k.h
+@@ -24,14 +24,8 @@
+ #define GNUTLS_LIB_NETTLE_INT_ECDSA_COMPUTE_K_H
+
+ #include <gnutls/gnutls.h>
+ #include <nettle/bignum.h> /* includes gmp.h */
+
+-int
+-_gnutls_ecdsa_compute_k (mpz_t k,
+- gnutls_ecc_curve_t curve,
+- const mpz_t x,
+- gnutls_mac_algorithm_t mac,
+- const uint8_t *digest,
+- size_t length);
++int _gnutls_ecc_curve_to_dsa_q(mpz_t q, gnutls_ecc_curve_t curve);
+
+ #endif /* GNUTLS_LIB_NETTLE_INT_ECDSA_COMPUTE_K_H */
+--- a/lib/nettle/pk.c
++++ b/lib/nettle/pk.c
+@@ -95,14 +95,20 @@ static void rnd_nonce_func(void *_ctx, s
+ if (gnutls_rnd(GNUTLS_RND_NONCE, data, length) < 0) {
+ _gnutls_switch_lib_state(LIB_STATE_ERROR);
+ }
+ }
+
+-static void rnd_mpz_func(void *_ctx, size_t length, uint8_t * data)
++static void rnd_datum_func(void *ctx, size_t length, uint8_t *data)
+ {
+- mpz_t *k = _ctx;
+- nettle_mpz_get_str_256 (length, data, *k);
++ gnutls_datum_t *d = ctx;
++
++ if (length > d->size) {
++ memset(data, 0, length - d->size);
++ memcpy(data + (length - d->size), d->data, d->size);
++ } else {
++ memcpy(data, d->data, length);
++ }
+ }
+
+ static void rnd_nonce_func_fallback(void *_ctx, size_t length, uint8_t * data)
+ {
+ if (unlikely(_gnutls_get_lib_state() != LIB_STATE_SELFTEST)) {
+@@ -1074,11 +1080,14 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ {
+ struct ecc_scalar priv;
+ struct dsa_signature sig;
+ int curve_id = pk_params->curve;
+ const struct ecc_curve *curve;
+- mpz_t k;
++ mpz_t q;
++ /* 521-bit elliptic curve generator at maximum */
++ uint8_t buf[(521 + 7) / 8];
++ gnutls_datum_t k = { NULL, 0 };
+ void *random_ctx;
+ nettle_random_func *random_func;
+
+ curve = get_supported_nist_curve(curve_id);
+ if (curve == NULL) {
+@@ -1121,23 +1130,36 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ break;
+ default:
+ not_approved = true;
+ }
+
+- mpz_init(k);
++ mpz_init(q);
++
+ if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
+ (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
+- ret = _gnutls_ecdsa_compute_k(k,
+- curve_id,
+- pk_params->params[ECC_K],
+- DIG_TO_MAC(sign_params->dsa_dig),
+- vdata->data,
+- vdata->size);
++ mp_limb_t h[DSA_COMPUTE_K_ITCH];
++
++ ret = _gnutls_ecc_curve_to_dsa_q(q, curve_id);
++ if (ret < 0)
++ goto ecdsa_cleanup;
++
++ ret = _gnutls_dsa_compute_k(
++ h, mpz_limbs_read(q), priv.p,
++ ecc_size(priv.ecc), ecc_bit_size(priv.ecc),
++ DIG_TO_MAC(sign_params->dsa_dig), vdata->data,
++ vdata->size);
+ if (ret < 0)
+ goto ecdsa_cleanup;
++
++ k.data = buf;
++ k.size = (ecc_bit_size(priv.ecc) + 7) / 8;
++
++ _gnutls_ecdsa_compute_k_finish(k.data, k.size, h,
++ ecc_size(priv.ecc));
++
+ random_ctx = &k;
+- random_func = rnd_mpz_func;
++ random_func = rnd_datum_func;
+ } else {
+ random_ctx = NULL;
+ random_func = rnd_nonce_func;
+ }
+ ecdsa_sign(&priv, random_ctx, random_func, hash_len,
+@@ -1154,11 +1176,11 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ &sig.s);
+
+ ecdsa_cleanup:
+ dsa_signature_clear(&sig);
+ ecc_scalar_zclear(&priv);
+- mpz_clear(k);
++ mpz_clear(q);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+@@ -1167,11 +1189,13 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ case GNUTLS_PK_DSA:
+ {
+ struct dsa_params pub;
+ bigint_t priv;
+ struct dsa_signature sig;
+- mpz_t k;
++ /* 512-bit DSA subgroup at maximum */
++ uint8_t buf[(512 + 7) / 8];
++ gnutls_datum_t k = { NULL, 0 };
+ void *random_ctx;
+ nettle_random_func *random_func;
+
+ /* DSA is currently being defined as sunset with the
+ * current draft of FIPS 186-5 */
+@@ -1194,25 +1218,31 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ ("Security level of algorithm requires hash %s(%d) or better (have: %d)\n",
+ _gnutls_mac_get_name(me), hash_len, (int)vdata->size);
+ hash_len = vdata->size;
+ }
+
+- mpz_init(k);
+ if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
+ (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
+- ret = _gnutls_dsa_compute_k(k,
+- pub.q,
+- TOMPZ(priv),
+- DIG_TO_MAC(sign_params->dsa_dig),
+- vdata->data,
+- vdata->size);
++ mp_limb_t h[DSA_COMPUTE_K_ITCH];
++
++ ret = _gnutls_dsa_compute_k(
++ h, mpz_limbs_read(pub.q),
++ mpz_limbs_read(TOMPZ(priv)), mpz_size(pub.q),
++ mpz_sizeinbase(pub.q, 2),
++ DIG_TO_MAC(sign_params->dsa_dig), vdata->data,
++ vdata->size);
+ if (ret < 0)
+ goto dsa_fail;
+- /* cancel-out dsa_sign's addition of 1 to random data */
+- mpz_sub_ui (k, k, 1);
++
++ k.data = buf;
++ k.size = (mpz_sizeinbase(pub.q, 2) + 7) / 8;
++
++ _gnutls_dsa_compute_k_finish(k.data, k.size, h,
++ mpz_size(pub.q));
++
+ random_ctx = &k;
+- random_func = rnd_mpz_func;
++ random_func = rnd_datum_func;
+ } else {
+ random_ctx = NULL;
+ random_func = rnd_nonce_func;
+ }
+ ret =
+@@ -1228,11 +1258,10 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ _gnutls_encode_ber_rs(signature, &sig.r,
+ &sig.s);
+
+ dsa_fail:
+ dsa_signature_clear(&sig);
+- mpz_clear(k);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+--- a/tests/sign-verify-deterministic.c
++++ b/tests/sign-verify-deterministic.c
+@@ -195,11 +195,11 @@ void doit(void)
+ ret =
+ gnutls_pubkey_verify_data2(pubkey, tests[i].sigalgo, 0, &tests[i].msg,
+ &signature);
+ if (ret < 0)
+ testfail("gnutls_pubkey_verify_data2\n");
+- success(" - pass");
++ success(" - pass\n");
+
+ next:
+ gnutls_free(signature.data);
+ gnutls_privkey_deinit(privkey);
+ gnutls_pubkey_deinit(pubkey);
diff --git a/debian/patches/63_03-serv-fix-memleak-when-a-connected-client-disappears.patch b/debian/patches/63_03-serv-fix-memleak-when-a-connected-client-disappears.patch
new file mode 100644
index 0000000..b54a9d8
--- /dev/null
+++ b/debian/patches/63_03-serv-fix-memleak-when-a-connected-client-disappears.patch
@@ -0,0 +1,26 @@
+From 88e9d7f27fa23dead8b0da21f5461a9810d48286 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Sat, 27 Jan 2024 11:09:18 +0900
+Subject: [PATCH 3/5] serv: fix memleak when a connected client disappears
+
+Reported by Hubert Kario.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ src/serv.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/src/serv.c
++++ b/src/serv.c
+@@ -183,10 +183,11 @@ static void listener_free(const void *el
+ gnutls_bye(j->tls_session, GNUTLS_SHUT_WR);
+ shutdown(j->fd, 2);
+ close(j->fd);
+ gnutls_deinit(j->tls_session);
+ }
++ free(j);
+ }
+
+
+ /* we use primes up to 1024 in this server.
+ * otherwise we should add them here.
diff --git a/debian/patches/63_04-lib-fix-a-segfault-in-_gnutls13_recv_end_of_early_da.patch b/debian/patches/63_04-lib-fix-a-segfault-in-_gnutls13_recv_end_of_early_da.patch
new file mode 100644
index 0000000..7a51305
--- /dev/null
+++ b/debian/patches/63_04-lib-fix-a-segfault-in-_gnutls13_recv_end_of_early_da.patch
@@ -0,0 +1,40 @@
+From 8b648e99d2d16f228a63b4075c487c9f3ec26927 Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Thu, 1 Feb 2024 16:50:22 -0500
+Subject: [PATCH 4/5] lib: fix a segfault in _gnutls13_recv_end_of_early_data
+
+A crash occur in my app that uses gnutls13 early data, stack trace:
+
+ #0 free (libc.so.6 + 0x97bf0)
+ #1 _gnutls_buffer_clear (libgnutls.so.30 + 0x77c8c)
+ #2 _gnutls13_recv_end_of_early_data (libgnutls.so.30 + 0xaf308)
+ #3 _gnutls13_handshake_server (libgnutls.so.30 + 0x42d6c)
+ #4 handshake_server (libgnutls.so.30 + 0x4ff6c)
+
+The root cause is that _gnutls_buffer_clear() was trying to free
+'buf' that is not initialized or set if GNUTLS_NO_END_OF_EARLY_DATA
+flag is set on server side.
+
+This patch fixes it by simply initializing buf at the begginning of
+_gnutls13_recv_end_of_early_data().
+
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+---
+ lib/tls13/early_data.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/lib/tls13/early_data.c
++++ b/lib/tls13/early_data.c
+@@ -79,10 +79,12 @@ int _gnutls13_send_end_of_early_data(gnu
+ int _gnutls13_recv_end_of_early_data(gnutls_session_t session)
+ {
+ int ret;
+ gnutls_buffer_st buf;
+
++ _gnutls_buffer_init(&buf);
++
+ if (!(session->security_parameters.entity == GNUTLS_SERVER &&
+ session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED))
+ return 0;
+
+ if (!(session->internals.flags & GNUTLS_NO_END_OF_EARLY_DATA)) {
diff --git a/debian/patches/63_05-lib-fix-a-potential-segfault-in-_gnutls13_recv_finis.patch b/debian/patches/63_05-lib-fix-a-potential-segfault-in-_gnutls13_recv_finis.patch
new file mode 100644
index 0000000..c23dbb2
--- /dev/null
+++ b/debian/patches/63_05-lib-fix-a-potential-segfault-in-_gnutls13_recv_finis.patch
@@ -0,0 +1,37 @@
+From 263917ec9fe00e9767487636593921444fb0b0af Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Thu, 1 Feb 2024 17:21:05 -0500
+Subject: [PATCH 5/5] lib: fix a potential segfault in _gnutls13_recv_finished
+
+In _gnutls13_recv_finished(), 'buf' is not initialized or set when
+_gnutls13_compute_finished() returns an err, and goto cleanup may
+cause a segfault crash as it frees the uninitialized buf.allocd in
+_gnutls_buffer_clear().
+
+So fix it by return if _gnutls13_compute_finished() returns an err
+in _gnutls13_recv_finished().
+
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+---
+ lib/tls13/finished.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/lib/tls13/finished.c
++++ b/lib/tls13/finished.c
+@@ -89,14 +89,12 @@ int _gnutls13_recv_finished(gnutls_sessi
+
+ ret = _gnutls13_compute_finished(session->security_parameters.prf,
+ base_key,
+ &session->internals.handshake_hash_buffer,
+ verifier);
+- if (ret < 0) {
+- gnutls_assert();
+- goto cleanup;
+- }
++ if (ret < 0)
++ return gnutls_assert_val(ret);
+
+ ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_FINISHED, 0, &buf);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
diff --git a/debian/patches/series b/debian/patches/series
index 7e7162f..ed4b28c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -3,6 +3,13 @@
40_srptest_doubletimeout.diff
50_Fix-removal-of-duplicate-certs-during-verification.patch
51_add-gnulib-linkedhash-list-module.diff
+53-fips-fix-checking-on-hash-algorithm-used-in-ECDSA.patch
+54-fips-mark-composite-signature-API-not-approved.patch
60-auth-rsa_psk-side-step-potential-side-channel.patch
61-x509-detect-loop-in-certificate-chain.patch
62-rsa-psk-minimize-branching-after-decryption.patch
+63_01-gnutls_x509_trust_list_verify_crt2-remove-length-lim.patch
+63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch
+63_03-serv-fix-memleak-when-a-connected-client-disappears.patch
+63_04-lib-fix-a-segfault-in-_gnutls13_recv_end_of_early_da.patch
+63_05-lib-fix-a-potential-segfault-in-_gnutls13_recv_finis.patch