From 0eebef3b64c6ace052f00e30eb2fdf2093451b38 Mon Sep 17 00:00:00 2001 From: Alexander Sosedkin Date: Mon, 1 Sep 2025 18:10:54 +0200 Subject: [PATCH] Fix CVE-2025-9820, CVE-2025-14831, drop unused patches - Fix PKCS#11 token initialization label overflow (CVE-2025-9820) - Fix name constraint processing performance issue (CVE-2025-14831) - Drop unused patches Resolves: RHEL-147830 --- gnutls-3.7.3-fips-dsa-post.patch | 29 - gnutls-3.7.6-fips-sha1-sigver.patch | 107 - ....7.8-ktls_skip_tls12_chachapoly_test.patch | 25 - gnutls-3.8.10-CVE-2025-14831.patch | 1630 +++++++++ gnutls-3.8.10-CVE-2025-9820.patch | 411 +++ gnutls-3.8.6-compression-dlwrap.patch | 2131 ----------- gnutls-3.8.6-liboqs-x25519-kyber768d00.patch | 3246 ----------------- gnutls-3.8.6-nettle-rsa-oaep.patch | 27 - gnutls-3.8.6-nettle-static.patch | 13 - gnutls-3.8.7-nettle-static.patch | 165 - gnutls-3.8.7-pkgconf-dlopen.patch | 170 - gnutls-3.8.9-cli-earlydata.patch | 196 - gnutls-3.8.9-leancrypto-init.patch | 43 - gnutls-3.8.9-limit-shuffle-extensions.patch | 213 -- gnutls-3.8.9-year2038-tests.patch | 59 - gnutls.spec | 7 + leancrypto-1.3.0-preserve-arm-registers.patch | 346 -- 17 files changed, 2048 insertions(+), 6770 deletions(-) delete mode 100644 gnutls-3.7.3-fips-dsa-post.patch delete mode 100644 gnutls-3.7.6-fips-sha1-sigver.patch delete mode 100644 gnutls-3.7.8-ktls_skip_tls12_chachapoly_test.patch create mode 100644 gnutls-3.8.10-CVE-2025-14831.patch create mode 100644 gnutls-3.8.10-CVE-2025-9820.patch delete mode 100644 gnutls-3.8.6-compression-dlwrap.patch delete mode 100644 gnutls-3.8.6-liboqs-x25519-kyber768d00.patch delete mode 100644 gnutls-3.8.6-nettle-rsa-oaep.patch delete mode 100644 gnutls-3.8.6-nettle-static.patch delete mode 100644 gnutls-3.8.7-nettle-static.patch delete mode 100644 gnutls-3.8.7-pkgconf-dlopen.patch delete mode 100644 gnutls-3.8.9-cli-earlydata.patch delete mode 100644 gnutls-3.8.9-leancrypto-init.patch delete mode 100644 gnutls-3.8.9-limit-shuffle-extensions.patch delete mode 100644 gnutls-3.8.9-year2038-tests.patch delete mode 100644 leancrypto-1.3.0-preserve-arm-registers.patch diff --git a/gnutls-3.7.3-fips-dsa-post.patch b/gnutls-3.7.3-fips-dsa-post.patch deleted file mode 100644 index e47c859..0000000 --- a/gnutls-3.7.3-fips-dsa-post.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b6c6e699ec79820bc949db3c71992ce277eef141 Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Thu, 15 Aug 2024 09:37:55 +0900 -Subject: [PATCH] gnutls-3.7.3-fips-dsa-post.patch - -Signed-off-by: rpm-build ---- - lib/fips.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/lib/fips.c b/lib/fips.c -index 1611200..8a9824a 100644 ---- a/lib/fips.c -+++ b/lib/fips.c -@@ -611,11 +611,6 @@ int _gnutls_fips_perform_self_checks2(void) - } - } - -- ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA); -- if (ret < 0) { -- return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); -- } -- - ret = gnutls_pk_self_test(0, GNUTLS_PK_EC); - if (ret < 0) { - return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); --- -2.46.0 - diff --git a/gnutls-3.7.6-fips-sha1-sigver.patch b/gnutls-3.7.6-fips-sha1-sigver.patch deleted file mode 100644 index ceda350..0000000 --- a/gnutls-3.7.6-fips-sha1-sigver.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 115c0edc929a3f09b0a252507112c0de70026b5e Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Mon, 10 Feb 2025 11:43:51 +0900 -Subject: [PATCH] gnutls-3.7.6-fips-sha1-sigver.patch - -Signed-off-by: rpm-build ---- - lib/nettle/pk.c | 11 ++++------- - lib/pubkey.c | 3 --- - tests/fips-test.c | 8 ++++---- - 3 files changed, 8 insertions(+), 14 deletions(-) - -diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c -index 91eaffd..0b4788a 100644 ---- a/lib/nettle/pk.c -+++ b/lib/nettle/pk.c -@@ -2784,10 +2784,7 @@ static int _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo, - if (hash_len > vdata->size) - hash_len = vdata->size; - -- /* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy -- * mode */ - switch (DIG_TO_MAC(sign_params->dsa_dig)) { -- case GNUTLS_MAC_SHA1: - case GNUTLS_MAC_SHA256: - case GNUTLS_MAC_SHA384: - case GNUTLS_MAC_SHA512: -@@ -2857,7 +2854,7 @@ static int _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo, - bits = mpz_sizeinbase(pub.n, 2); - - /* In FIPS 140-3, RSA key size should be larger than 2048-bit. -- * In addition to this, only SHA-1 and SHA-2 are allowed -+ * In addition to this, only SHA-2 is allowed - * for SigVer; it is checked in _pkcs1_rsa_verify_sig in - * lib/pubkey.c. - */ -@@ -2903,9 +2900,9 @@ static int _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo, - } - - /* RSA modulus size should be 2048-bit or larger in FIPS -- * 140-3. In addition to this, only SHA-1 and SHA-2 are -- * allowed for SigVer, while Nettle only supports -- * SHA256, SHA384, and SHA512 for RSA-PSS (see -+ * 140-3. In addition to this, only SHA-2 is allowed -+ * for SigVer, while Nettle only supports SHA256, -+ * SHA384, and SHA512 for RSA-PSS (see - * _rsa_pss_verify_digest in this file for the details). - */ - if (unlikely(mpz_sizeinbase(pub.n, 2) < 2048)) { -diff --git a/lib/pubkey.c b/lib/pubkey.c -index 1e5ecf3..811e531 100644 ---- a/lib/pubkey.c -+++ b/lib/pubkey.c -@@ -2516,10 +2516,7 @@ static int _pkcs1_rsa_verify_sig(gnutls_pk_algorithm_t pk, - d.size = digest_size; - - if (pk == GNUTLS_PK_RSA) { -- /* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy -- * mode */ - switch (me->id) { -- case GNUTLS_MAC_SHA1: - case GNUTLS_MAC_SHA256: - case GNUTLS_MAC_SHA384: - case GNUTLS_MAC_SHA512: -diff --git a/tests/fips-test.c b/tests/fips-test.c -index 3af4df7..c024427 100644 ---- a/tests/fips-test.c -+++ b/tests/fips-test.c -@@ -596,7 +596,7 @@ void doit(void) - } - FIPS_POP_CONTEXT(NOT_APPROVED); - -- /* Verify a signature created with 2432-bit RSA and SHA-1; approved */ -+ /* Verify a signature created with 2432-bit RSA and SHA-1; not approved */ - FIPS_PUSH_CONTEXT(); - ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, - GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, -@@ -604,7 +604,7 @@ void doit(void) - if (ret < 0) { - fail("gnutls_pubkey_verify_data2 failed\n"); - } -- FIPS_POP_CONTEXT(APPROVED); -+ FIPS_POP_CONTEXT(NOT_APPROVED); - gnutls_free(signature.data); - gnutls_pubkey_deinit(pubkey); - gnutls_privkey_deinit(privkey); -@@ -707,7 +707,7 @@ void doit(void) - } - FIPS_POP_CONTEXT(NOT_APPROVED); - -- /* Verify a signature created with ECDSA and SHA-1; approved */ -+ /* Verify a signature created with ECDSA and SHA-1; not approved */ - FIPS_PUSH_CONTEXT(); - ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA1, - GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, -@@ -715,7 +715,7 @@ void doit(void) - if (ret < 0) { - fail("gnutls_pubkey_verify_data2 failed\n"); - } -- FIPS_POP_CONTEXT(APPROVED); -+ FIPS_POP_CONTEXT(NOT_APPROVED); - gnutls_free(signature.data); - - /* Create a signature with ECDSA and SHA-1 (old API); not approved */ --- -2.48.1 - diff --git a/gnutls-3.7.8-ktls_skip_tls12_chachapoly_test.patch b/gnutls-3.7.8-ktls_skip_tls12_chachapoly_test.patch deleted file mode 100644 index c3a5ace..0000000 --- a/gnutls-3.7.8-ktls_skip_tls12_chachapoly_test.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 18c555b4d2461ad202996398609552b9c4ecd43b Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Wed, 22 Nov 2023 15:21:49 +0900 -Subject: [PATCH] gnutls-3.7.8-ktls_skip_tls12_chachapoly_test.patch - -Signed-off-by: rpm-build ---- - tests/gnutls_ktls.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/tests/gnutls_ktls.c b/tests/gnutls_ktls.c -index ccbe566..049c888 100644 ---- a/tests/gnutls_ktls.c -+++ b/tests/gnutls_ktls.c -@@ -347,7 +347,6 @@ void doit(void) - { - run("NORMAL:-VERS-ALL:+VERS-TLS1.2:-CIPHER-ALL:+AES-128-GCM"); - run("NORMAL:-VERS-ALL:+VERS-TLS1.2:-CIPHER-ALL:+AES-256-GCM"); -- run("NORMAL:-VERS-ALL:+VERS-TLS1.2:-CIPHER-ALL:+CHACHA20-POLY1305"); - run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM"); - run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM"); - run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+CHACHA20-POLY1305"); --- -2.41.0 - diff --git a/gnutls-3.8.10-CVE-2025-14831.patch b/gnutls-3.8.10-CVE-2025-14831.patch new file mode 100644 index 0000000..e89b2c9 --- /dev/null +++ b/gnutls-3.8.10-CVE-2025-14831.patch @@ -0,0 +1,1630 @@ +From 98fa09e31884c44fe663bbee8719c215c827a9c8 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Mon, 26 Jan 2026 19:02:27 +0100 +Subject: [PATCH 1/9] x509/name_constraints: use actual zeroes in universal + exclude IP NC + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index 3c6e30630..e88461211 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -61,7 +61,7 @@ struct gnutls_name_constraints_st { + + static struct name_constraints_node_st * + name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type, +- unsigned char *data, unsigned int size); ++ const unsigned char *data, unsigned int size); + + static int + name_constraints_node_list_add(struct name_constraints_node_list_st *list, +@@ -285,7 +285,7 @@ static void name_constraints_node_free(struct name_constraints_node_st *node) + -*/ + static struct name_constraints_node_st * + name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type, +- unsigned char *data, unsigned int size) ++ const unsigned char *data, unsigned int size) + { + struct name_constraints_node_st *tmp; + int ret; +@@ -339,6 +339,7 @@ static int name_constraints_node_list_intersect( + struct name_constraints_node_list_st removed = { .data = NULL, + .size = 0, + .capacity = 0 }; ++ static const unsigned char universal_ip[32] = { 0 }; + + /* temporary array to see, if we need to add universal excluded constraints + * (see phase 3 for details) +@@ -471,7 +472,7 @@ static int name_constraints_node_list_intersect( + case GNUTLS_SAN_IPADDRESS: + // add universal restricted range for IPv4 + tmp = name_constraints_node_new( +- nc, GNUTLS_SAN_IPADDRESS, NULL, 8); ++ nc, GNUTLS_SAN_IPADDRESS, universal_ip, 8); + if (tmp == NULL) { + gnutls_assert(); + ret = GNUTLS_E_MEMORY_ERROR; +@@ -484,7 +485,7 @@ static int name_constraints_node_list_intersect( + } + // add universal restricted range for IPv6 + tmp = name_constraints_node_new( +- nc, GNUTLS_SAN_IPADDRESS, NULL, 32); ++ nc, GNUTLS_SAN_IPADDRESS, universal_ip, 32); + if (tmp == NULL) { + gnutls_assert(); + ret = GNUTLS_E_MEMORY_ERROR; +-- +2.52.0 + + +From 6f204d1b913db76c1425d993a4986bd99aac0c4c Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Mon, 26 Jan 2026 19:10:58 +0100 +Subject: [PATCH 2/9] tests/name-constraints-ip: stop swallowing errors... + +... now when it started to pass + +Signed-off-by: Alexander Sosedkin +--- + tests/name-constraints-ip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/name-constraints-ip.c b/tests/name-constraints-ip.c +index 7a196088d..a0cf172b7 100644 +--- a/tests/name-constraints-ip.c ++++ b/tests/name-constraints-ip.c +@@ -772,5 +772,5 @@ int main(int argc, char **argv) + cmocka_unit_test_setup_teardown( + check_ipv4v6_single_constraint_each, setup, teardown) + }; +- cmocka_run_group_tests(tests, NULL, NULL); ++ return cmocka_run_group_tests(tests, NULL, NULL); + } +-- +2.52.0 + + +From acc30a22329ad2c8f577c14c05c4321849991905 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Mon, 26 Jan 2026 20:14:33 +0100 +Subject: [PATCH 3/9] x509/name_constraints: reject some malformed domain names + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index e88461211..c62609ba5 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -159,6 +159,23 @@ static int validate_name_constraints_node(gnutls_x509_subject_alt_name_t type, + return gnutls_assert_val(GNUTLS_E_MALFORMED_CIDR); + } + ++ /* Validate DNS names and email addresses for malformed input */ ++ if (type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME) { ++ unsigned int i; ++ if (name->size == 0) ++ return GNUTLS_E_SUCCESS; ++ ++ /* reject names with consecutive dots... */ ++ for (i = 0; i + 1 < name->size; i++) { ++ if (name->data[i] == '.' && name->data[i + 1] == '.') ++ return gnutls_assert_val( ++ GNUTLS_E_ILLEGAL_PARAMETER); ++ } ++ /* ... or names consisting exclusively of dots */ ++ if (name->size == 1 && name->data[0] == '.') ++ return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); ++ } ++ + return GNUTLS_E_SUCCESS; + } + +-- +2.52.0 + + +From 614f2f95b5ceba00fbe05bffbcc23c0574b03ea0 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Thu, 5 Feb 2026 13:22:10 +0100 +Subject: [PATCH 4/9] x509/name_constraints: + name_constraints_node_add_{new,copy} + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 112 ++++++++++++++++-------------------- + 1 file changed, 51 insertions(+), 61 deletions(-) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index c62609ba5..f0c8191c3 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -86,6 +86,38 @@ name_constraints_node_list_add(struct name_constraints_node_list_st *list, + return 0; + } + ++static int ++name_constraints_node_add_new(gnutls_x509_name_constraints_t nc, ++ struct name_constraints_node_list_st *list, ++ unsigned type, const unsigned char *data, ++ unsigned int size) ++{ ++ struct name_constraints_node_st *node; ++ int ret; ++ node = name_constraints_node_new(nc, type, data, size); ++ if (node == NULL) { ++ gnutls_assert(); ++ return GNUTLS_E_MEMORY_ERROR; ++ } ++ ret = name_constraints_node_list_add(list, node); ++ if (ret < 0) { ++ gnutls_assert(); ++ return ret; ++ } ++ return GNUTLS_E_SUCCESS; ++} ++ ++static int ++name_constraints_node_add_copy(gnutls_x509_name_constraints_t nc, ++ struct name_constraints_node_list_st *dest, ++ const struct name_constraints_node_st *src) ++{ ++ if (!src) ++ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ return name_constraints_node_add_new(nc, dest, src->type, ++ src->name.data, src->name.size); ++} ++ + // for documentation see the implementation + static int name_constraints_intersect_nodes( + gnutls_x509_name_constraints_t nc, +@@ -188,7 +220,6 @@ static int extract_name_constraints(gnutls_x509_name_constraints_t nc, + unsigned indx; + gnutls_datum_t tmp = { NULL, 0 }; + unsigned int type; +- struct name_constraints_node_st *node; + + for (indx = 1;; indx++) { + snprintf(tmpstr, sizeof(tmpstr), "%s.?%u.base", vstr, indx); +@@ -231,15 +262,9 @@ static int extract_name_constraints(gnutls_x509_name_constraints_t nc, + goto cleanup; + } + +- node = name_constraints_node_new(nc, type, tmp.data, tmp.size); ++ ret = name_constraints_node_add_new(nc, nodes, type, tmp.data, ++ tmp.size); + _gnutls_free_datum(&tmp); +- if (node == NULL) { +- gnutls_assert(); +- ret = GNUTLS_E_MEMORY_ERROR; +- goto cleanup; +- } +- +- ret = name_constraints_node_list_add(nodes, node); + if (ret < 0) { + gnutls_assert(); + goto cleanup; +@@ -459,14 +484,7 @@ static int name_constraints_node_list_intersect( + // Beware: also copies nodes other than DNS, email, IP, + // since their counterpart may have been moved in phase 1. + if (!used) { +- tmp = name_constraints_node_new( +- nc, t2->type, t2->name.data, t2->name.size); +- if (tmp == NULL) { +- gnutls_assert(); +- ret = GNUTLS_E_MEMORY_ERROR; +- goto cleanup; +- } +- ret = name_constraints_node_list_add(permitted, tmp); ++ ret = name_constraints_node_add_copy(nc, permitted, t2); + if (ret < 0) { + gnutls_assert(); + goto cleanup; +@@ -488,27 +506,17 @@ static int name_constraints_node_list_intersect( + switch (type) { + case GNUTLS_SAN_IPADDRESS: + // add universal restricted range for IPv4 +- tmp = name_constraints_node_new( +- nc, GNUTLS_SAN_IPADDRESS, universal_ip, 8); +- if (tmp == NULL) { +- gnutls_assert(); +- ret = GNUTLS_E_MEMORY_ERROR; +- goto cleanup; +- } +- ret = name_constraints_node_list_add(excluded, tmp); ++ ret = name_constraints_node_add_new( ++ nc, excluded, GNUTLS_SAN_IPADDRESS, ++ universal_ip, 8); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + // add universal restricted range for IPv6 +- tmp = name_constraints_node_new( +- nc, GNUTLS_SAN_IPADDRESS, universal_ip, 32); +- if (tmp == NULL) { +- gnutls_assert(); +- ret = GNUTLS_E_MEMORY_ERROR; +- goto cleanup; +- } +- ret = name_constraints_node_list_add(excluded, tmp); ++ ret = name_constraints_node_add_new( ++ nc, excluded, GNUTLS_SAN_IPADDRESS, ++ universal_ip, 32); + if (ret < 0) { + gnutls_assert(); + goto cleanup; +@@ -516,13 +524,8 @@ static int name_constraints_node_list_intersect( + break; + case GNUTLS_SAN_DNSNAME: + case GNUTLS_SAN_RFC822NAME: +- tmp = name_constraints_node_new(nc, type, NULL, 0); +- if (tmp == NULL) { +- gnutls_assert(); +- ret = GNUTLS_E_MEMORY_ERROR; +- goto cleanup; +- } +- ret = name_constraints_node_list_add(excluded, tmp); ++ ret = name_constraints_node_add_new(nc, excluded, type, ++ NULL, 0); + if (ret < 0) { + gnutls_assert(); + goto cleanup; +@@ -544,20 +547,13 @@ static int name_constraints_node_list_concat( + struct name_constraints_node_list_st *nodes, + const struct name_constraints_node_list_st *nodes2) + { ++ int ret; ++ + for (size_t i = 0; i < nodes2->size; i++) { +- const struct name_constraints_node_st *node = nodes2->data[i]; +- struct name_constraints_node_st *tmp; +- int ret; +- +- tmp = name_constraints_node_new(nc, node->type, node->name.data, +- node->name.size); +- if (tmp == NULL) { +- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); +- } +- ret = name_constraints_node_list_add(nodes, tmp); ++ ret = name_constraints_node_add_copy(nc, nodes, ++ nodes2->data[i]); + if (ret < 0) { +- name_constraints_node_free(tmp); +- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ++ return gnutls_assert_val(ret); + } + } + +@@ -687,7 +683,6 @@ static int name_constraints_add(gnutls_x509_name_constraints_t nc, + gnutls_x509_subject_alt_name_t type, + const gnutls_datum_t *name, unsigned permitted) + { +- struct name_constraints_node_st *tmp; + struct name_constraints_node_list_st *nodes; + int ret; + +@@ -697,15 +692,10 @@ static int name_constraints_add(gnutls_x509_name_constraints_t nc, + + nodes = permitted ? &nc->permitted : &nc->excluded; + +- tmp = name_constraints_node_new(nc, type, name->data, name->size); +- if (tmp == NULL) +- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); +- +- ret = name_constraints_node_list_add(nodes, tmp); +- if (ret < 0) { +- name_constraints_node_free(tmp); ++ ret = name_constraints_node_add_new(nc, nodes, type, name->data, ++ name->size); ++ if (ret < 0) + return gnutls_assert_val(ret); +- } + + return 0; + } +-- +2.52.0 + + +From 4a39cd884e33fd7d4845046166b4b32b492cffc5 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Mon, 26 Jan 2026 20:16:36 +0100 +Subject: [PATCH 5/9] x509/name_constraints: introduce a rich comparator + +These are preparatory changes before implementing N * log N intersection +over sorted lists of constraints. + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 411 ++++++++++++++++++++++++++++-------- + 1 file changed, 320 insertions(+), 91 deletions(-) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index f0c8191c3..b4f1fc00c 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -39,6 +39,9 @@ + #include "ip.h" + #include "ip-in-cidr.h" + #include "intprops.h" ++#include "minmax.h" ++ ++#include + + #define MAX_NC_CHECKS (1 << 20) + +@@ -63,6 +66,282 @@ static struct name_constraints_node_st * + name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type, + const unsigned char *data, unsigned int size); + ++/* An enum for "rich" comparisons that not only let us sort name constraints, ++ * children-before-parent, but also subsume them during intersection. */ ++enum name_constraint_relation { ++ NC_SORTS_BEFORE = -2, /* unrelated constraints */ ++ NC_INCLUDED_BY = -1, /* nc1 is included by nc2 / children sort first */ ++ NC_EQUAL = 0, /* exact match */ ++ NC_INCLUDES = 1, /* nc1 includes nc2 / parents sort last */ ++ NC_SORTS_AFTER = 2 /* unrelated constraints */ ++}; ++ ++/* A helper to compare just a pair of strings with this rich comparison */ ++static enum name_constraint_relation ++compare_strings(const void *n1, size_t n1_len, const void *n2, size_t n2_len) ++{ ++ int r = memcmp(n1, n2, MIN(n1_len, n2_len)); ++ if (r < 0) ++ return NC_SORTS_BEFORE; ++ if (r > 0) ++ return NC_SORTS_AFTER; ++ if (n1_len < n2_len) ++ return NC_SORTS_BEFORE; ++ if (n1_len > n2_len) ++ return NC_SORTS_AFTER; ++ return NC_EQUAL; ++} ++ ++/* Rich-compare DNS names. Example order/relationships: ++ * z.x.a INCLUDED_BY x.a BEFORE y.a INCLUDED_BY a BEFORE x.b BEFORE y.b */ ++static enum name_constraint_relation compare_dns_names(const gnutls_datum_t *n1, ++ const gnutls_datum_t *n2) ++{ ++ enum name_constraint_relation rel; ++ unsigned int i, j, i_end, j_end; ++ ++ /* start from the end of each name */ ++ i = i_end = n1->size; ++ j = j_end = n2->size; ++ ++ /* skip the trailing dots for the comparison */ ++ while (i && n1->data[i - 1] == '.') ++ i_end = i = i - 1; ++ while (j && n2->data[j - 1] == '.') ++ j_end = j = j - 1; ++ ++ while (1) { ++ // rewind back to beginning or an after-dot position ++ while (i && n1->data[i - 1] != '.') ++ i--; ++ while (j && n2->data[j - 1] != '.') ++ j--; ++ ++ rel = compare_strings(&n1->data[i], i_end - i, &n2->data[j], ++ j_end - j); ++ if (rel == NC_SORTS_BEFORE) /* x.a BEFORE y.a */ ++ return NC_SORTS_BEFORE; ++ if (rel == NC_SORTS_AFTER) /* y.a AFTER x.a */ ++ return NC_SORTS_AFTER; ++ if (!i && j) /* x.a INCLUDES z.x.a */ ++ return NC_INCLUDES; ++ if (i && !j) /* z.x.a INCLUDED_BY x.a */ ++ return NC_INCLUDED_BY; ++ ++ if (!i && !j) /* r == 0, we ran out of components to compare */ ++ return NC_EQUAL; ++ /* r == 0, i && j: step back past a dot and keep comparing */ ++ i_end = i = i - 1; ++ j_end = j = j - 1; ++ ++ /* support for non-standard ".gr INCLUDES example.gr" [1] */ ++ if (!i && j) /* .a INCLUDES x.a */ ++ return NC_INCLUDES; ++ if (i && !j) /* x.a INCLUDED_BY .a */ ++ return NC_INCLUDED_BY; ++ } ++} ++/* [1] https://mailarchive.ietf.org/arch/msg/saag/Bw6PtreW0G7aEG7SikfzKHES4VA */ ++ ++/* Rich-compare email name constraints. Example order/relationships: ++ * z@x.a INCLUDED_BY x.a BEFORE y.a INCLUDED_BY a BEFORE x@b BEFORE y@b */ ++static enum name_constraint_relation compare_emails(const gnutls_datum_t *n1, ++ const gnutls_datum_t *n2) ++{ ++ enum name_constraint_relation domains_rel; ++ unsigned int i, j, i_end, j_end; ++ gnutls_datum_t d1, d2; /* borrow from n1 and n2 */ ++ ++ /* start from the end of each name */ ++ i = i_end = n1->size; ++ j = j_end = n2->size; ++ ++ /* rewind to @s to look for domains */ ++ while (i && n1->data[i - 1] != '@') ++ i--; ++ d1.size = i_end - i; ++ d1.data = &n1->data[i]; ++ while (j && n2->data[j - 1] != '@') ++ j--; ++ d2.size = j_end - j; ++ d2.data = &n2->data[j]; ++ ++ domains_rel = compare_dns_names(&d1, &d2); ++ ++ /* email constraint semantics differ from DNS ++ * DNS: x.a INCLUDED_BY a ++ * Email: x.a INCLUDED_BY .a BEFORE a */ ++ if (domains_rel == NC_INCLUDED_BY || domains_rel == NC_INCLUDES) { ++ bool d1_has_dot = (d1.size > 0 && d1.data[0] == '.'); ++ bool d2_has_dot = (d2.size > 0 && d2.data[0] == '.'); ++ /* a constraint without a dot is exact, excluding subdomains */ ++ if (!d2_has_dot && domains_rel == NC_INCLUDED_BY) ++ domains_rel = NC_SORTS_BEFORE; /* x.a BEFORE a */ ++ if (!d1_has_dot && domains_rel == NC_INCLUDES) ++ domains_rel = NC_SORTS_AFTER; /* a AFTER x.a */ ++ } ++ ++ if (!i && !j) { /* both are domains-only */ ++ return domains_rel; ++ } else if (i && !j) { /* n1 is email, n2 is domain */ ++ switch (domains_rel) { ++ case NC_SORTS_AFTER: ++ return NC_SORTS_AFTER; ++ case NC_SORTS_BEFORE: ++ return NC_SORTS_BEFORE; ++ case NC_INCLUDES: /* n2 is more specific, a@x.a AFTER z.x.a */ ++ return NC_SORTS_AFTER; ++ case NC_EQUAL: /* subdomains match, z@x.a INCLUDED_BY x.a */ ++ case NC_INCLUDED_BY: /* n1 is more specific */ ++ return NC_INCLUDED_BY; ++ } ++ } else if (!i && j) { /* n1 is domain, n2 is email */ ++ switch (domains_rel) { ++ case NC_SORTS_AFTER: ++ return NC_SORTS_AFTER; ++ case NC_SORTS_BEFORE: ++ return NC_SORTS_BEFORE; ++ case NC_INCLUDES: /* n2 is more specific, a AFTER z@x.a */ ++ return NC_SORTS_AFTER; ++ case NC_EQUAL: /* subdomains match, x.a INCLUDES z@x.a */ ++ return NC_INCLUDES; ++ case NC_INCLUDED_BY: /* n1 is more specific, x.a BEFORE z@a */ ++ return NC_SORTS_BEFORE; ++ } ++ } else if (i && j) { /* both are emails */ ++ switch (domains_rel) { ++ case NC_SORTS_AFTER: ++ return NC_SORTS_AFTER; ++ case NC_SORTS_BEFORE: ++ return NC_SORTS_BEFORE; ++ case NC_INCLUDES: // n2 is more specific ++ return NC_SORTS_AFTER; ++ case NC_INCLUDED_BY: // n1 is more specific ++ return NC_SORTS_BEFORE; ++ case NC_EQUAL: // only case when we need to look before the @ ++ break; // see below for readability ++ } ++ } ++ ++ /* i && j, both are emails, domain names match, compare up to @ */ ++ return compare_strings(n1->data, i - 1, n2->data, j - 1); ++} ++ ++/* Rich-compare IP address constraints. Example order/relationships: ++ * 10.0.0.0/24 INCLUDED_BY 10.0.0.0/16 BEFORE 1::1/128 INCLUDED_BY 1::1/127 */ ++static enum name_constraint_relation compare_ip_ncs(const gnutls_datum_t *n1, ++ const gnutls_datum_t *n2) ++{ ++ unsigned int len, i; ++ int r; ++ const unsigned char *ip1, *ip2, *mask1, *mask2; ++ unsigned char masked11[16], masked22[16], masked12[16], masked21[16]; ++ ++ if (n1->size < n2->size) ++ return NC_SORTS_BEFORE; ++ if (n1->size > n2->size) ++ return NC_SORTS_AFTER; ++ len = n1->size / 2; /* 4 for IPv4, 16 for IPv6 */ ++ ++ /* data is a concatenation of prefix and mask */ ++ ip1 = n1->data; ++ ip2 = n2->data; ++ mask1 = n1->data + len; ++ mask2 = n2->data + len; ++ for (i = 0; i < len; i++) { ++ masked11[i] = ip1[i] & mask1[i]; ++ masked22[i] = ip2[i] & mask2[i]; ++ masked12[i] = ip1[i] & mask2[i]; ++ masked21[i] = ip2[i] & mask1[i]; ++ } ++ ++ r = memcmp(mask1, mask2, len); ++ if (r < 0 && !memcmp(masked11, masked21, len)) /* prefix1 < prefix2 */ ++ return NC_INCLUDES; /* ip1 & mask1 == ip2 & mask1 */ ++ if (r > 0 && !memcmp(masked12, masked22, len)) /* prefix1 > prefix2 */ ++ return NC_INCLUDED_BY; /* ip1 & mask2 == ip2 & mask2 */ ++ ++ r = memcmp(masked11, masked22, len); ++ if (r < 0) ++ return NC_SORTS_BEFORE; ++ else if (r > 0) ++ return NC_SORTS_AFTER; ++ return NC_EQUAL; ++} ++ ++static inline bool is_supported_type(unsigned type) ++{ ++ return type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME || ++ type == GNUTLS_SAN_IPADDRESS; ++} ++ ++/* Universal comparison for name constraint nodes. ++ * Unsupported types sort before supported types to allow early handling. ++ * NULL represents end-of-list and sorts after everything else. */ ++static enum name_constraint_relation ++compare_name_constraint_nodes(const struct name_constraints_node_st *n1, ++ const struct name_constraints_node_st *n2) ++{ ++ bool n1_supported, n2_supported; ++ ++ if (!n1 && !n2) ++ return NC_EQUAL; ++ if (!n1) ++ return NC_SORTS_AFTER; ++ if (!n2) ++ return NC_SORTS_BEFORE; ++ ++ n1_supported = is_supported_type(n1->type); ++ n2_supported = is_supported_type(n2->type); ++ ++ /* unsupported types bubble up (sort first). intersect relies on this */ ++ if (!n1_supported && n2_supported) ++ return NC_SORTS_BEFORE; ++ if (n1_supported && !n2_supported) ++ return NC_SORTS_AFTER; ++ ++ /* next, sort by type */ ++ if (n1->type < n2->type) ++ return NC_SORTS_BEFORE; ++ if (n1->type > n2->type) ++ return NC_SORTS_AFTER; ++ ++ /* now look deeper */ ++ switch (n1->type) { ++ case GNUTLS_SAN_DNSNAME: ++ return compare_dns_names(&n1->name, &n2->name); ++ case GNUTLS_SAN_RFC822NAME: ++ return compare_emails(&n1->name, &n2->name); ++ case GNUTLS_SAN_IPADDRESS: ++ return compare_ip_ncs(&n1->name, &n2->name); ++ default: ++ /* unsupported types: stable lexicographic order */ ++ return compare_strings(n1->name.data, n1->name.size, ++ n2->name.data, n2->name.size); ++ } ++} ++ ++/* qsort-compatible wrapper */ ++static int compare_name_constraint_nodes_qsort(const void *a, const void *b) ++{ ++ const struct name_constraints_node_st *const *n1 = a; ++ const struct name_constraints_node_st *const *n2 = b; ++ enum name_constraint_relation rel; ++ ++ rel = compare_name_constraint_nodes(*n1, *n2); ++ switch (rel) { ++ case NC_SORTS_BEFORE: ++ case NC_INCLUDED_BY: ++ return -1; ++ case NC_SORTS_AFTER: ++ case NC_INCLUDES: ++ return 1; ++ case NC_EQUAL: ++ default: ++ return 0; ++ } ++} ++ + static int + name_constraints_node_list_add(struct name_constraints_node_list_st *list, + struct name_constraints_node_st *node) +@@ -420,9 +699,7 @@ static int name_constraints_node_list_intersect( + } + } + +- if (found != NULL && (t->type == GNUTLS_SAN_DNSNAME || +- t->type == GNUTLS_SAN_RFC822NAME || +- t->type == GNUTLS_SAN_IPADDRESS)) { ++ if (found != NULL && is_supported_type(t->type)) { + /* move node from PERMITTED to REMOVED */ + ret = name_constraints_node_list_add(&removed, t); + if (ret < 0) { +@@ -824,61 +1101,14 @@ cleanup: + return ret; + } + +-static unsigned ends_with(const gnutls_datum_t *str, +- const gnutls_datum_t *suffix) +-{ +- unsigned char *tree; +- unsigned int treelen; +- +- if (suffix->size >= str->size) +- return 0; +- +- tree = suffix->data; +- treelen = suffix->size; +- if ((treelen > 0) && (tree[0] == '.')) { +- tree++; +- treelen--; +- } +- +- if (memcmp(str->data + str->size - treelen, tree, treelen) == 0 && +- str->data[str->size - treelen - 1] == '.') +- return 1; /* match */ +- +- return 0; +-} +- +-static unsigned email_ends_with(const gnutls_datum_t *str, +- const gnutls_datum_t *suffix) +-{ +- if (suffix->size >= str->size) { +- return 0; +- } +- +- if (suffix->size > 0 && memcmp(str->data + str->size - suffix->size, +- suffix->data, suffix->size) != 0) { +- return 0; +- } +- +- if (suffix->size > 1 && suffix->data[0] == '.') { /* .domain.com */ +- return 1; /* match */ +- } else if (str->data[str->size - suffix->size - 1] == '@') { +- return 1; /* match */ +- } +- +- return 0; +-} +- + static unsigned dnsname_matches(const gnutls_datum_t *name, + const gnutls_datum_t *suffix) + { + _gnutls_hard_log("matching %.*s with DNS constraint %.*s\n", name->size, + name->data, suffix->size, suffix->data); + +- if (suffix->size == name->size && +- memcmp(suffix->data, name->data, suffix->size) == 0) +- return 1; /* match */ +- +- return ends_with(name, suffix); ++ enum name_constraint_relation rel = compare_dns_names(name, suffix); ++ return rel == NC_EQUAL || rel == NC_INCLUDED_BY; + } + + static unsigned email_matches(const gnutls_datum_t *name, +@@ -887,11 +1117,8 @@ static unsigned email_matches(const gnutls_datum_t *name, + _gnutls_hard_log("matching %.*s with e-mail constraint %.*s\n", + name->size, name->data, suffix->size, suffix->data); + +- if (suffix->size == name->size && +- memcmp(suffix->data, name->data, suffix->size) == 0) +- return 1; /* match */ +- +- return email_ends_with(name, suffix); ++ enum name_constraint_relation rel = compare_emails(name, suffix); ++ return rel == NC_EQUAL || rel == NC_INCLUDED_BY; + } + + /*- +@@ -915,8 +1142,7 @@ static int name_constraints_intersect_nodes( + // presume empty intersection + struct name_constraints_node_st *intersection = NULL; + const struct name_constraints_node_st *to_copy = NULL; +- unsigned iplength = 0; +- unsigned byte; ++ enum name_constraint_relation rel; + + *_intersection = NULL; + +@@ -925,32 +1151,49 @@ static int name_constraints_intersect_nodes( + } + switch (node1->type) { + case GNUTLS_SAN_DNSNAME: +- if (!dnsname_matches(&node2->name, &node1->name)) ++ rel = compare_dns_names(&node1->name, &node2->name); ++ switch (rel) { ++ case NC_EQUAL: // equal means doesn't matter which one ++ case NC_INCLUDES: // node2 is more specific ++ to_copy = node2; ++ break; ++ case NC_INCLUDED_BY: // node1 is more specific ++ to_copy = node1; ++ break; ++ case NC_SORTS_BEFORE: // no intersection ++ case NC_SORTS_AFTER: // no intersection + return GNUTLS_E_SUCCESS; +- to_copy = node2; ++ } + break; + case GNUTLS_SAN_RFC822NAME: +- if (!email_matches(&node2->name, &node1->name)) ++ rel = compare_emails(&node1->name, &node2->name); ++ switch (rel) { ++ case NC_EQUAL: // equal means doesn't matter which one ++ case NC_INCLUDES: // node2 is more specific ++ to_copy = node2; ++ break; ++ case NC_INCLUDED_BY: // node1 is more specific ++ to_copy = node1; ++ break; ++ case NC_SORTS_BEFORE: // no intersection ++ case NC_SORTS_AFTER: // no intersection + return GNUTLS_E_SUCCESS; +- to_copy = node2; ++ } + break; + case GNUTLS_SAN_IPADDRESS: +- if (node1->name.size != node2->name.size) ++ rel = compare_ip_ncs(&node1->name, &node2->name); ++ switch (rel) { ++ case NC_EQUAL: // equal means doesn't matter which one ++ case NC_INCLUDES: // node2 is more specific ++ to_copy = node2; ++ break; ++ case NC_INCLUDED_BY: // node1 is more specific ++ to_copy = node1; ++ break; ++ case NC_SORTS_BEFORE: // no intersection ++ case NC_SORTS_AFTER: // no intersection + return GNUTLS_E_SUCCESS; +- iplength = node1->name.size / 2; +- for (byte = 0; byte < iplength; byte++) { +- if (((node1->name.data[byte] ^ +- node2->name.data[byte]) // XOR of addresses +- & node1->name.data[byte + +- iplength] // AND mask from nc1 +- & node2->name.data[byte + +- iplength]) // AND mask from nc2 +- != 0) { +- // CIDRS do not intersect +- return GNUTLS_E_SUCCESS; +- } + } +- to_copy = node2; + break; + default: + // for other types, we don't know how to do the intersection, assume empty +@@ -967,20 +1210,6 @@ static int name_constraints_intersect_nodes( + intersection = *_intersection; + + assert(intersection->name.data != NULL); +- +- if (intersection->type == GNUTLS_SAN_IPADDRESS) { +- // make sure both IP addresses are correctly masked +- _gnutls_mask_ip(intersection->name.data, +- intersection->name.data + iplength, +- iplength); +- _gnutls_mask_ip(node1->name.data, +- node1->name.data + iplength, iplength); +- // update intersection, if necessary (we already know one is subset of other) +- for (byte = 0; byte < 2 * iplength; byte++) { +- intersection->name.data[byte] |= +- node1->name.data[byte]; +- } +- } + } + + return GNUTLS_E_SUCCESS; +-- +2.52.0 + + +From 8f5bf94225156ac09f8928b2d0da9d6c40f0aba8 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Wed, 4 Feb 2026 09:09:46 +0100 +Subject: [PATCH 6/9] x509/name_constraints: add sorted_view in preparation... + +... for actually using it later for performance gains. + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 62 ++++++++++++++++++++++++++++++------- + 1 file changed, 51 insertions(+), 11 deletions(-) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index b4f1fc00c..f2c279946 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -54,6 +54,9 @@ struct name_constraints_node_list_st { + struct name_constraints_node_st **data; + size_t size; + size_t capacity; ++ /* sorted-on-demand view, valid only when dirty == false */ ++ bool dirty; ++ struct name_constraints_node_st **sorted_view; + }; + + struct gnutls_name_constraints_st { +@@ -342,6 +345,37 @@ static int compare_name_constraint_nodes_qsort(const void *a, const void *b) + } + } + ++/* Bring the sorted view up to date with the list data; clear the dirty flag. */ ++static int ensure_sorted(struct name_constraints_node_list_st *list) ++{ ++ struct name_constraints_node_st **new_data; ++ ++ if (!list->dirty) ++ return GNUTLS_E_SUCCESS; ++ if (!list->size) { ++ list->dirty = false; ++ return GNUTLS_E_SUCCESS; ++ } ++ ++ /* reallocate sorted view to match current size */ ++ new_data = ++ _gnutls_reallocarray(list->sorted_view, list->size, ++ sizeof(struct name_constraints_node_st *)); ++ if (!new_data) ++ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ++ list->sorted_view = new_data; ++ ++ /* copy pointers and sort in-place */ ++ memcpy(list->sorted_view, list->data, ++ list->size * sizeof(struct name_constraints_node_st *)); ++ qsort(list->sorted_view, list->size, ++ sizeof(struct name_constraints_node_st *), ++ compare_name_constraint_nodes_qsort); ++ ++ list->dirty = false; ++ return GNUTLS_E_SUCCESS; ++} ++ + static int + name_constraints_node_list_add(struct name_constraints_node_list_st *list, + struct name_constraints_node_st *node) +@@ -361,10 +395,23 @@ name_constraints_node_list_add(struct name_constraints_node_list_st *list, + list->capacity = new_capacity; + list->data = new_data; + } ++ list->dirty = true; + list->data[list->size++] = node; + return 0; + } + ++static void ++name_constraints_node_list_clear(struct name_constraints_node_list_st *list) ++{ ++ gnutls_free(list->data); ++ gnutls_free(list->sorted_view); ++ list->data = NULL; ++ list->sorted_view = NULL; ++ list->capacity = 0; ++ list->size = 0; ++ list->dirty = false; ++} ++ + static int + name_constraints_node_add_new(gnutls_x509_name_constraints_t nc, + struct name_constraints_node_list_st *list, +@@ -711,6 +758,7 @@ static int name_constraints_node_list_intersect( + permitted->data[i] = + permitted->data[permitted->size - 1]; + permitted->size--; ++ permitted->dirty = true; + continue; + } + i++; +@@ -905,17 +953,9 @@ void _gnutls_x509_name_constraints_clear(gnutls_x509_name_constraints_t nc) + struct name_constraints_node_st *node = nc->nodes.data[i]; + name_constraints_node_free(node); + } +- gnutls_free(nc->nodes.data); +- nc->nodes.capacity = 0; +- nc->nodes.size = 0; +- +- gnutls_free(nc->permitted.data); +- nc->permitted.capacity = 0; +- nc->permitted.size = 0; +- +- gnutls_free(nc->excluded.data); +- nc->excluded.capacity = 0; +- nc->excluded.size = 0; ++ name_constraints_node_list_clear(&nc->nodes); ++ name_constraints_node_list_clear(&nc->permitted); ++ name_constraints_node_list_clear(&nc->excluded); + } + + /** +-- +2.52.0 + + +From 998bc5d6761d29f7e3c0f07feff318e4a7e9b933 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Wed, 4 Feb 2026 13:30:08 +0100 +Subject: [PATCH 7/9] x509/name_constraints: implement + name_constraints_node_list_union + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 98 ++++++++++++++++++++++++++++++++----- + 1 file changed, 86 insertions(+), 12 deletions(-) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index f2c279946..230bd0079 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -41,6 +41,7 @@ + #include "intprops.h" + #include "minmax.h" + ++#include + #include + + #define MAX_NC_CHECKS (1 << 20) +@@ -867,22 +868,95 @@ cleanup: + return ret; + } + +-static int name_constraints_node_list_concat( +- gnutls_x509_name_constraints_t nc, +- struct name_constraints_node_list_st *nodes, +- const struct name_constraints_node_list_st *nodes2) ++static int ++name_constraints_node_list_union(gnutls_x509_name_constraints_t nc, ++ struct name_constraints_node_list_st *nodes, ++ struct name_constraints_node_list_st *nodes2) + { + int ret; ++ size_t i = 0, j = 0; ++ struct name_constraints_node_st *nc1; ++ const struct name_constraints_node_st *nc2; ++ enum name_constraint_relation rel; ++ struct name_constraints_node_list_st result = { 0 }; + +- for (size_t i = 0; i < nodes2->size; i++) { +- ret = name_constraints_node_add_copy(nc, nodes, +- nodes2->data[i]); ++ if (nodes2->size == 0) /* nothing to do */ ++ return GNUTLS_E_SUCCESS; ++ ++ ret = ensure_sorted(nodes); ++ if (ret < 0) { ++ gnutls_assert(); ++ goto cleanup; ++ } ++ ret = ensure_sorted(nodes2); ++ if (ret < 0) { ++ gnutls_assert(); ++ goto cleanup; ++ } ++ ++ /* traverse both lists in a single pass and merge them w/o duplicates */ ++ while (i < nodes->size || j < nodes2->size) { ++ nc1 = (i < nodes->size) ? nodes->sorted_view[i] : NULL; ++ nc2 = (j < nodes2->size) ? nodes2->sorted_view[j] : NULL; ++ ++ rel = compare_name_constraint_nodes(nc1, nc2); ++ switch (rel) { ++ case NC_SORTS_BEFORE: ++ assert(nc1 != NULL); /* comparator-guaranteed */ ++ ret = name_constraints_node_list_add(&result, nc1); ++ i++; ++ break; ++ case NC_SORTS_AFTER: ++ assert(nc2 != NULL); /* comparator-guaranteed */ ++ ret = name_constraints_node_add_copy(nc, &result, nc2); ++ j++; ++ break; ++ case NC_INCLUDES: /* nc1 is broader, shallow-copy it */ ++ assert(nc1 != NULL && nc2 != NULL); /* comparator */ ++ ret = name_constraints_node_list_add(&result, nc1); ++ i++; ++ j++; ++ break; ++ case NC_INCLUDED_BY: /* nc2 is broader, deep-copy it */ ++ assert(nc1 != NULL && nc2 != NULL); /* comparator */ ++ ret = name_constraints_node_add_copy(nc, &result, nc2); ++ i++; ++ j++; ++ break; ++ case NC_EQUAL: ++ assert(nc1 != NULL && nc2 != NULL); /* loop condition */ ++ ret = name_constraints_node_list_add(&result, nc1); ++ i++; ++ j++; ++ break; ++ } + if (ret < 0) { +- return gnutls_assert_val(ret); ++ gnutls_assert(); ++ goto cleanup; + } + } + +- return 0; ++ gnutls_free(nodes->data); ++ gnutls_free(nodes->sorted_view); ++ nodes->data = result.data; ++ nodes->sorted_view = NULL; ++ nodes->size = result.size; ++ nodes->capacity = result.capacity; ++ nodes->dirty = true; ++ /* since we know it's sorted, populate sorted_view almost for free */ ++ nodes->sorted_view = gnutls_calloc( ++ nodes->size, sizeof(struct name_constraints_node_st *)); ++ if (!nodes->sorted_view) ++ return GNUTLS_E_SUCCESS; /* we tried, no harm done */ ++ memcpy(nodes->sorted_view, nodes->data, ++ nodes->size * sizeof(struct name_constraints_node_st *)); ++ nodes->dirty = false; ++ ++ result.data = NULL; ++ return GNUTLS_E_SUCCESS; ++cleanup: ++ name_constraints_node_list_clear(&result); ++ return gnutls_assert_val(ret); + } + + /** +@@ -1023,7 +1097,7 @@ static int name_constraints_add(gnutls_x509_name_constraints_t nc, + * @nc2: The name constraints to be merged with + * + * This function will merge the provided name constraints structures +- * as per RFC5280 p6.1.4. That is, the excluded constraints will be appended, ++ * as per RFC5280 p6.1.4. That is, the excluded constraints will be unioned, + * and permitted will be intersected. The intersection assumes that @nc + * is the root CA constraints. + * +@@ -1045,8 +1119,8 @@ int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc, + return ret; + } + +- ret = name_constraints_node_list_concat(nc, &nc->excluded, +- &nc2->excluded); ++ ret = name_constraints_node_list_union(nc, &nc->excluded, ++ &nc2->excluded); + if (ret < 0) { + gnutls_assert(); + return ret; +-- +2.52.0 + + +From dce5fded86d227ba492b37cc91822c8aabff0337 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Wed, 4 Feb 2026 18:31:37 +0100 +Subject: [PATCH 8/9] x509/name_constraints: make types_with_empty_intersection + a bitmask + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 39 +++++++++++++++++++++++++++---------- + 1 file changed, 29 insertions(+), 10 deletions(-) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index 230bd0079..d1006eb8d 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -275,6 +275,7 @@ static enum name_constraint_relation compare_ip_ncs(const gnutls_datum_t *n1, + + static inline bool is_supported_type(unsigned type) + { ++ /* all of these should be under GNUTLS_SAN_MAX (intersect bitmasks) */ + return type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME || + type == GNUTLS_SAN_IPADDRESS; + } +@@ -683,6 +684,21 @@ name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type, + return tmp; + } + ++static int ++name_constraints_node_list_union(gnutls_x509_name_constraints_t nc, ++ struct name_constraints_node_list_st *nodes, ++ struct name_constraints_node_list_st *nodes2); ++ ++#define type_bitmask_t uint8_t /* increase if GNUTLS_SAN_MAX grows */ ++#define type_bitmask_set(mask, t) ((mask) |= (1u << (t))) ++#define type_bitmask_clr(mask, t) ((mask) &= ~(1u << (t))) ++#define type_bitmask_in(mask, t) ((mask) & (1u << (t))) ++/* C99-compatible compile-time assertions; gnutls_int.h undefines verify */ ++typedef char assert_san_max[(GNUTLS_SAN_MAX < 8) ? 1 : -1]; ++typedef char assert_dnsname[(GNUTLS_SAN_DNSNAME <= GNUTLS_SAN_MAX) ? 1 : -1]; ++typedef char assert_rfc822[(GNUTLS_SAN_RFC822NAME <= GNUTLS_SAN_MAX) ? 1 : -1]; ++typedef char assert_ipaddr[(GNUTLS_SAN_IPADDRESS <= GNUTLS_SAN_MAX) ? 1 : -1]; ++ + /*- + * @brief name_constraints_node_list_intersect: + * @nc: %gnutls_x509_name_constraints_t +@@ -710,12 +726,9 @@ static int name_constraints_node_list_intersect( + .capacity = 0 }; + static const unsigned char universal_ip[32] = { 0 }; + +- /* temporary array to see, if we need to add universal excluded constraints +- * (see phase 3 for details) +- * indexed directly by (gnutls_x509_subject_alt_name_t enum - 1) */ +- unsigned char types_with_empty_intersection[GNUTLS_SAN_MAX]; +- memset(types_with_empty_intersection, 0, +- sizeof(types_with_empty_intersection)); ++ /* bitmask to see if we need to add universal excluded constraints ++ * (see phase 3 for details) */ ++ type_bitmask_t types_with_empty_intersection = 0; + + if (permitted->size == 0 || permitted2->size == 0) + return 0; +@@ -741,7 +754,8 @@ static int name_constraints_node_list_intersect( + // note the possibility of empty intersection for this type + // if we add something to the intersection in phase 2, + // we will reset this flag back to 0 then +- types_with_empty_intersection[t->type - 1] = 1; ++ type_bitmask_set(types_with_empty_intersection, ++ t->type); + found = t2; + break; + } +@@ -795,8 +809,8 @@ static int name_constraints_node_list_intersect( + GNUTLS_E_INTERNAL_ERROR); + } + // we will not add universal excluded constraint for this type +- types_with_empty_intersection[tmp->type - 1] = +- 0; ++ type_bitmask_clr(types_with_empty_intersection, ++ tmp->type); + // add intersection node to PERMITTED + ret = name_constraints_node_list_add(permitted, + tmp); +@@ -824,7 +838,7 @@ static int name_constraints_node_list_intersect( + * excluded constraint with universal wildcard + * (since the intersection of permitted is now empty). */ + for (type = 1; type <= GNUTLS_SAN_MAX; type++) { +- if (types_with_empty_intersection[type - 1] == 0) ++ if (!type_bitmask_in(types_with_empty_intersection, type)) + continue; + _gnutls_hard_log( + "Adding universal excluded name constraint for type %d.\n", +@@ -868,6 +882,11 @@ cleanup: + return ret; + } + ++#undef type_bitmask_t ++#undef type_bitmask_set ++#undef type_bitmask_clr ++#undef type_bitmask_in ++ + static int + name_constraints_node_list_union(gnutls_x509_name_constraints_t nc, + struct name_constraints_node_list_st *nodes, +-- +2.52.0 + + +From 5f54d43c5523347a56adf4c3b46ec38b11feaa79 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Wed, 4 Feb 2026 20:03:49 +0100 +Subject: [PATCH 9/9] x509/name_constraints: + name_constraints_node_list_intersect over sorted + +Fixes: CVE-2025-14831 + +Signed-off-by: Alexander Sosedkin +--- + lib/x509/name_constraints.c | 343 ++++++++++++++---------------------- + 1 file changed, 133 insertions(+), 210 deletions(-) + +diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c +index d1006eb8d..04722bdf4 100644 +--- a/lib/x509/name_constraints.c ++++ b/lib/x509/name_constraints.c +@@ -446,13 +446,6 @@ name_constraints_node_add_copy(gnutls_x509_name_constraints_t nc, + src->name.data, src->name.size); + } + +-// for documentation see the implementation +-static int name_constraints_intersect_nodes( +- gnutls_x509_name_constraints_t nc, +- const struct name_constraints_node_st *node1, +- const struct name_constraints_node_st *node2, +- struct name_constraints_node_st **intersection); +- + /*- + * _gnutls_x509_name_constraints_is_empty: + * @nc: name constraints structure +@@ -716,129 +709,143 @@ typedef char assert_ipaddr[(GNUTLS_SAN_IPADDRESS <= GNUTLS_SAN_MAX) ? 1 : -1]; + static int name_constraints_node_list_intersect( + gnutls_x509_name_constraints_t nc, + struct name_constraints_node_list_st *permitted, +- const struct name_constraints_node_list_st *permitted2, ++ struct name_constraints_node_list_st *permitted2, + struct name_constraints_node_list_st *excluded) + { +- struct name_constraints_node_st *tmp; +- int ret, type, used; +- struct name_constraints_node_list_st removed = { .data = NULL, +- .size = 0, +- .capacity = 0 }; ++ struct name_constraints_node_st *nc1, *nc2; ++ struct name_constraints_node_list_st result = { 0 }; ++ struct name_constraints_node_list_st unsupp2 = { 0 }; ++ enum name_constraint_relation rel; ++ unsigned type; ++ int ret = GNUTLS_E_SUCCESS; ++ size_t i, j, p1_unsupp = 0, p2_unsupp = 0; ++ type_bitmask_t universal_exclude_needed = 0; ++ type_bitmask_t types_in_p1 = 0, types_in_p2 = 0; + static const unsigned char universal_ip[32] = { 0 }; + +- /* bitmask to see if we need to add universal excluded constraints +- * (see phase 3 for details) */ +- type_bitmask_t types_with_empty_intersection = 0; +- + if (permitted->size == 0 || permitted2->size == 0) +- return 0; ++ return GNUTLS_E_SUCCESS; + +- /* Phase 1 +- * For each name in PERMITTED, if a PERMITTED2 does not contain a name +- * with the same type, move the original name to REMOVED. +- * Do this also for node of unknown type (not DNS, email, IP) */ +- for (size_t i = 0; i < permitted->size;) { +- struct name_constraints_node_st *t = permitted->data[i]; +- const struct name_constraints_node_st *found = NULL; ++ /* make sorted views of the arrays */ ++ ret = ensure_sorted(permitted); ++ if (ret < 0) { ++ gnutls_assert(); ++ goto cleanup; ++ } ++ ret = ensure_sorted(permitted2); ++ if (ret < 0) { ++ gnutls_assert(); ++ goto cleanup; ++ } + +- for (size_t j = 0; j < permitted2->size; j++) { +- const struct name_constraints_node_st *t2 = +- permitted2->data[j]; +- if (t->type == t2->type) { +- // check bounds (we will use 't->type' as index) +- if (t->type > GNUTLS_SAN_MAX || t->type == 0) { +- gnutls_assert(); +- ret = GNUTLS_E_INTERNAL_ERROR; +- goto cleanup; +- } +- // note the possibility of empty intersection for this type +- // if we add something to the intersection in phase 2, +- // we will reset this flag back to 0 then +- type_bitmask_set(types_with_empty_intersection, +- t->type); +- found = t2; +- break; +- } ++ /* deal with the leading unsupported types first: count, then union */ ++ while (p1_unsupp < permitted->size && ++ !is_supported_type(permitted->sorted_view[p1_unsupp]->type)) ++ p1_unsupp++; ++ while (p2_unsupp < permitted2->size && ++ !is_supported_type(permitted2->sorted_view[p2_unsupp]->type)) ++ p2_unsupp++; ++ if (p1_unsupp) { /* copy p1 unsupported type pointers into result */ ++ result.data = gnutls_calloc( ++ p1_unsupp, sizeof(struct name_constraints_node_st *)); ++ if (!result.data) { ++ ret = GNUTLS_E_MEMORY_ERROR; ++ gnutls_assert(); ++ goto cleanup; ++ } ++ memcpy(result.data, permitted->sorted_view, ++ p1_unsupp * sizeof(struct name_constraints_node_st *)); ++ result.size = result.capacity = p1_unsupp; ++ result.dirty = true; ++ } ++ if (p2_unsupp) { /* union will make deep copies from p2 */ ++ unsupp2.data = permitted2->sorted_view; /* so, just alias */ ++ unsupp2.size = unsupp2.capacity = p2_unsupp; ++ unsupp2.dirty = false; /* we know it's sorted */ ++ unsupp2.sorted_view = permitted2->sorted_view; ++ ret = name_constraints_node_list_union(nc, &result, &unsupp2); ++ if (ret < 0) { ++ gnutls_assert(); ++ goto cleanup; + } ++ } + +- if (found != NULL && is_supported_type(t->type)) { +- /* move node from PERMITTED to REMOVED */ +- ret = name_constraints_node_list_add(&removed, t); +- if (ret < 0) { +- gnutls_assert(); +- goto cleanup; +- } +- /* remove node by swapping */ +- if (i < permitted->size - 1) +- permitted->data[i] = +- permitted->data[permitted->size - 1]; +- permitted->size--; +- permitted->dirty = true; +- continue; ++ /* with that out of the way, pre-compute the supported types we have */ ++ for (i = p1_unsupp; i < permitted->size; i++) { ++ type = permitted->sorted_view[i]->type; ++ if (type < 1 || type > GNUTLS_SAN_MAX) { ++ ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ goto cleanup; ++ } ++ type_bitmask_set(types_in_p1, type); ++ } ++ for (j = p2_unsupp; j < permitted2->size; j++) { ++ type = permitted2->sorted_view[j]->type; ++ if (type < 1 || type > GNUTLS_SAN_MAX) { ++ ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ goto cleanup; + } +- i++; ++ type_bitmask_set(types_in_p2, type); + } ++ /* universal excludes might be needed for types intersecting to empty */ ++ universal_exclude_needed = types_in_p1 & types_in_p2; + +- /* Phase 2 +- * iterate through all combinations from PERMITTED2 and PERMITTED +- * and create intersections of nodes with same type */ +- for (size_t i = 0; i < permitted2->size; i++) { +- const struct name_constraints_node_st *t2 = permitted2->data[i]; ++ /* go through supported type NCs and intersect in a single pass */ ++ i = p1_unsupp; ++ j = p2_unsupp; ++ while (i < permitted->size || j < permitted2->size) { ++ nc1 = (i < permitted->size) ? permitted->sorted_view[i] : NULL; ++ nc2 = (j < permitted2->size) ? permitted2->sorted_view[j] : ++ NULL; ++ rel = compare_name_constraint_nodes(nc1, nc2); + +- // current PERMITTED2 node has not yet been used for any intersection +- // (and is not in REMOVED either) +- used = 0; +- for (size_t j = 0; j < removed.size; j++) { +- const struct name_constraints_node_st *t = +- removed.data[j]; +- // save intersection of name constraints into tmp +- ret = name_constraints_intersect_nodes(nc, t, t2, &tmp); +- if (ret < 0) { +- gnutls_assert(); +- goto cleanup; +- } +- used = 1; +- // if intersection is not empty +- if (tmp != +- NULL) { // intersection for this type is not empty +- // check bounds +- if (tmp->type > GNUTLS_SAN_MAX || +- tmp->type == 0) { +- gnutls_free(tmp); +- return gnutls_assert_val( +- GNUTLS_E_INTERNAL_ERROR); +- } +- // we will not add universal excluded constraint for this type +- type_bitmask_clr(types_with_empty_intersection, +- tmp->type); +- // add intersection node to PERMITTED +- ret = name_constraints_node_list_add(permitted, +- tmp); +- if (ret < 0) { +- gnutls_assert(); +- goto cleanup; +- } +- } ++ switch (rel) { ++ case NC_SORTS_BEFORE: ++ assert(nc1 != NULL); /* comparator-guaranteed */ ++ /* if nothing to intersect with, shallow-copy nc1 */ ++ if (!type_bitmask_in(types_in_p2, nc1->type)) ++ ret = name_constraints_node_list_add(&result, ++ nc1); ++ i++; /* otherwise skip nc1 */ ++ break; ++ case NC_SORTS_AFTER: ++ assert(nc2 != NULL); /* comparator-guaranteed */ ++ /* if nothing to intersect with, deep-copy nc2 */ ++ if (!type_bitmask_in(types_in_p1, nc2->type)) ++ ret = name_constraints_node_add_copy( ++ nc, &result, nc2); ++ j++; /* otherwise skip nc2 */ ++ break; ++ case NC_INCLUDED_BY: /* add nc1, shallow-copy */ ++ assert(nc1 != NULL && nc2 != NULL); /* comparator */ ++ type_bitmask_clr(universal_exclude_needed, nc1->type); ++ ret = name_constraints_node_list_add(&result, nc1); ++ i++; ++ break; ++ case NC_INCLUDES: /* pick nc2, deep-copy */ ++ assert(nc1 != NULL && nc2 != NULL); /* comparator */ ++ type_bitmask_clr(universal_exclude_needed, nc2->type); ++ ret = name_constraints_node_add_copy(nc, &result, nc2); ++ j++; ++ break; ++ case NC_EQUAL: /* pick whichever: nc1, shallow-copy */ ++ assert(nc1 != NULL && nc2 != NULL); /* loop condition */ ++ type_bitmask_clr(universal_exclude_needed, nc1->type); ++ ret = name_constraints_node_list_add(&result, nc1); ++ i++; ++ j++; ++ break; + } +- // if the node from PERMITTED2 was not used for intersection, copy it to DEST +- // Beware: also copies nodes other than DNS, email, IP, +- // since their counterpart may have been moved in phase 1. +- if (!used) { +- ret = name_constraints_node_add_copy(nc, permitted, t2); +- if (ret < 0) { +- gnutls_assert(); +- goto cleanup; +- } ++ if (ret < 0) { ++ gnutls_assert(); ++ goto cleanup; + } + } + +- /* Phase 3 +- * For each type: If we have empty permitted name constraints now +- * and we didn't have at the beginning, we have to add a new +- * excluded constraint with universal wildcard +- * (since the intersection of permitted is now empty). */ ++ /* finishing touch: add universal excluded constraints for types where ++ * both lists had constraints, but all intersections ended up empty */ + for (type = 1; type <= GNUTLS_SAN_MAX; type++) { +- if (!type_bitmask_in(types_with_empty_intersection, type)) ++ if (!type_bitmask_in(universal_exclude_needed, type)) + continue; + _gnutls_hard_log( + "Adding universal excluded name constraint for type %d.\n", +@@ -871,14 +878,24 @@ static int name_constraints_node_list_intersect( + goto cleanup; + } + break; +- default: // do nothing, at least one node was already moved in phase 1 +- break; ++ default: /* unsupported type; should be unreacheable */ ++ ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ goto cleanup; + } + } ++ ++ gnutls_free(permitted->data); ++ gnutls_free(permitted->sorted_view); ++ permitted->data = result.data; ++ permitted->sorted_view = NULL; ++ permitted->size = result.size; ++ permitted->capacity = result.capacity; ++ permitted->dirty = true; ++ ++ result.data = NULL; + ret = GNUTLS_E_SUCCESS; +- + cleanup: +- gnutls_free(removed.data); ++ name_constraints_node_list_clear(&result); + return ret; + } + +@@ -1254,100 +1271,6 @@ static unsigned email_matches(const gnutls_datum_t *name, + return rel == NC_EQUAL || rel == NC_INCLUDED_BY; + } + +-/*- +- * name_constraints_intersect_nodes: +- * @nc1: name constraints node 1 +- * @nc2: name constraints node 2 +- * @_intersection: newly allocated node with intersected constraints, +- * NULL if the intersection is empty +- * +- * Inspect 2 name constraints nodes (of possibly different types) and allocate +- * a new node with intersection of given constraints. +- * +- * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value. +- -*/ +-static int name_constraints_intersect_nodes( +- gnutls_x509_name_constraints_t nc, +- const struct name_constraints_node_st *node1, +- const struct name_constraints_node_st *node2, +- struct name_constraints_node_st **_intersection) +-{ +- // presume empty intersection +- struct name_constraints_node_st *intersection = NULL; +- const struct name_constraints_node_st *to_copy = NULL; +- enum name_constraint_relation rel; +- +- *_intersection = NULL; +- +- if (node1->type != node2->type) { +- return GNUTLS_E_SUCCESS; +- } +- switch (node1->type) { +- case GNUTLS_SAN_DNSNAME: +- rel = compare_dns_names(&node1->name, &node2->name); +- switch (rel) { +- case NC_EQUAL: // equal means doesn't matter which one +- case NC_INCLUDES: // node2 is more specific +- to_copy = node2; +- break; +- case NC_INCLUDED_BY: // node1 is more specific +- to_copy = node1; +- break; +- case NC_SORTS_BEFORE: // no intersection +- case NC_SORTS_AFTER: // no intersection +- return GNUTLS_E_SUCCESS; +- } +- break; +- case GNUTLS_SAN_RFC822NAME: +- rel = compare_emails(&node1->name, &node2->name); +- switch (rel) { +- case NC_EQUAL: // equal means doesn't matter which one +- case NC_INCLUDES: // node2 is more specific +- to_copy = node2; +- break; +- case NC_INCLUDED_BY: // node1 is more specific +- to_copy = node1; +- break; +- case NC_SORTS_BEFORE: // no intersection +- case NC_SORTS_AFTER: // no intersection +- return GNUTLS_E_SUCCESS; +- } +- break; +- case GNUTLS_SAN_IPADDRESS: +- rel = compare_ip_ncs(&node1->name, &node2->name); +- switch (rel) { +- case NC_EQUAL: // equal means doesn't matter which one +- case NC_INCLUDES: // node2 is more specific +- to_copy = node2; +- break; +- case NC_INCLUDED_BY: // node1 is more specific +- to_copy = node1; +- break; +- case NC_SORTS_BEFORE: // no intersection +- case NC_SORTS_AFTER: // no intersection +- return GNUTLS_E_SUCCESS; +- } +- break; +- default: +- // for other types, we don't know how to do the intersection, assume empty +- return GNUTLS_E_SUCCESS; +- } +- +- // copy existing node if applicable +- if (to_copy != NULL) { +- *_intersection = name_constraints_node_new(nc, to_copy->type, +- to_copy->name.data, +- to_copy->name.size); +- if (*_intersection == NULL) +- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); +- intersection = *_intersection; +- +- assert(intersection->name.data != NULL); +- } +- +- return GNUTLS_E_SUCCESS; +-} +- + /* + * Returns: true if the certification is acceptable, and false otherwise. + */ +-- +2.52.0 + diff --git a/gnutls-3.8.10-CVE-2025-9820.patch b/gnutls-3.8.10-CVE-2025-9820.patch new file mode 100644 index 0000000..19e6008 --- /dev/null +++ b/gnutls-3.8.10-CVE-2025-9820.patch @@ -0,0 +1,411 @@ +From f23de850c8f37bd498bbdb1adc491ee05614ca11 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 6 Feb 2026 15:43:54 +0100 +Subject: [PATCH 1/2] tests/pkcs11/pkcs11-mock4: add, modified for 3.8.10 + +--- + tests/Makefile.am | 6 ++ + tests/pkcs11/pkcs11-mock4.c | 125 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 131 insertions(+) + create mode 100644 tests/pkcs11/pkcs11-mock4.c + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 9e5c7de84..62c4ec2f9 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -358,6 +358,11 @@ libpkcs11mock3_la_SOURCES = pkcs11/pkcs11-mock3.c + libpkcs11mock3_la_LDFLAGS = -shared -rpath $(pkglibdir) -module -no-undefined -avoid-version + libpkcs11mock3_la_LIBADD = ../gl/libgnu.la + ++noinst_LTLIBRARIES += libpkcs11mock4.la ++libpkcs11mock4_la_SOURCES = pkcs11/pkcs11-mock4.c ++libpkcs11mock4_la_LDFLAGS = -shared -rpath $(pkglibdir) -module -no-undefined -avoid-version ++libpkcs11mock4_la_LIBADD = ../gl/libgnu.la ++ + pkcs11_cert_import_url_exts_SOURCES = pkcs11/pkcs11-cert-import-url-exts.c + pkcs11_cert_import_url_exts_DEPENDENCIES = libpkcs11mock1.la libutils.la + +@@ -655,6 +660,7 @@ TESTS_ENVIRONMENT += \ + P11MOCKLIB1=$(abs_builddir)/.libs/libpkcs11mock1.so \ + P11MOCKLIB2=$(abs_builddir)/.libs/libpkcs11mock2.so \ + P11MOCKLIB3=$(abs_builddir)/.libs/libpkcs11mock3.so \ ++ P11MOCKLIB4=$(abs_builddir)/.libs/libpkcs11mock4.so \ + PKCS12_MANY_CERTS_FILE=$(srcdir)/cert-tests/data/pkcs12_5certs.p12 \ + PKCS12FILE=$(srcdir)/cert-tests/data/client.p12 \ + PKCS12PASSWORD=foobar \ +diff --git a/tests/pkcs11/pkcs11-mock4.c b/tests/pkcs11/pkcs11-mock4.c +new file mode 100644 +index 000000000..a6dd21cdd +--- /dev/null ++++ b/tests/pkcs11/pkcs11-mock4.c +@@ -0,0 +1,125 @@ ++/* ++ * Copyright (C) 2025 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * 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 ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "softhsm.h" ++ ++/* This provides a mock PKCS #11 module that delegates all the ++ * operations to SoftHSM except that it returns CKR_CANT_LOCK upon ++ * C_Initialize if CKF_OS_LOCKING_OK is set. ++ */ ++ ++static void *dl; ++static CK_C_Initialize base_C_Initialize; ++static CK_FUNCTION_LIST override_funcs; ++ ++#ifdef __sun ++#pragma fini(mock_deinit) ++#pragma init(mock_init) ++#define _CONSTRUCTOR ++#define _DESTRUCTOR ++#else ++#define _CONSTRUCTOR __attribute__((constructor)) ++#define _DESTRUCTOR __attribute__((destructor)) ++#endif ++ ++#define LOCK_FLAGS (CKF_LIBRARY_CANT_CREATE_OS_THREADS | CKF_OS_LOCKING_OK) ++ ++static CK_RV override_C_Initialize(void *args) ++{ ++ CK_C_INITIALIZE_ARGS *init_args = args; ++ static bool first = true; ++ ++ // we don't have threadsafe initialization/fallback in 3.8.10... ++ /* ++ if (first) { ++ assert(init_args && ++ (init_args->flags & LOCK_FLAGS) == LOCK_FLAGS); ++ first = false; ++ return CKR_CANT_LOCK; ++ } else { ++ assert(!init_args || ++ (init_args->flags & LOCK_FLAGS) != LOCK_FLAGS); ++ } ++ */ ++ // ... so we expect 3.8.10 behaviour ++ assert(first); ++ assert(init_args); ++ assert(!(init_args->flags & LOCK_FLAGS) != LOCK_FLAGS); ++ first = false; ++ ++ return base_C_Initialize(args); ++} ++ ++CK_RV C_GetFunctionList(CK_FUNCTION_LIST **function_list) ++{ ++ CK_C_GetFunctionList func; ++ CK_FUNCTION_LIST *funcs; ++ ++ assert(dl); ++ ++ func = dlsym(dl, "C_GetFunctionList"); ++ if (func == NULL) { ++ return CKR_GENERAL_ERROR; ++ } ++ ++ func(&funcs); ++ ++ base_C_Initialize = funcs->C_Initialize; ++ ++ memcpy(&override_funcs, funcs, sizeof(CK_FUNCTION_LIST)); ++ override_funcs.C_Initialize = override_C_Initialize; ++ *function_list = &override_funcs; ++ ++ return CKR_OK; ++} ++ ++static _CONSTRUCTOR void mock_init(void) ++{ ++ const char *lib; ++ ++ /* suppress compiler warning */ ++ (void)set_softhsm_conf; ++ ++ lib = softhsm_lib(); ++ ++ dl = dlopen(lib, RTLD_NOW); ++ if (dl == NULL) ++ exit(77); ++} ++ ++static _DESTRUCTOR void mock_deinit(void) ++{ ++ dlclose(dl); ++} +-- +2.52.0 + + +From 87fc01fb853911e412e0fe238b069a68376ad8de Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Tue, 18 Nov 2025 13:17:55 +0900 +Subject: [PATCH 2/2] pkcs11: avoid stack overwrite when initializing a token + +If gnutls_pkcs11_token_init is called with label longer than 32 +characters, the internal storage used to blank-fill it would +overflow. This adds a guard to prevent that. + +Signed-off-by: Daiki Ueno +--- + lib/pkcs11_write.c | 5 +- + tests/Makefile.am | 4 +- + tests/pkcs11/long-label.c | 164 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 170 insertions(+), 3 deletions(-) + create mode 100644 tests/pkcs11/long-label.c + +diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c +index f5e9058e0..64b85a2df 100644 +--- a/lib/pkcs11_write.c ++++ b/lib/pkcs11_write.c +@@ -28,6 +28,7 @@ + #include "pkcs11x.h" + #include "x509/common.h" + #include "pk.h" ++#include "minmax.h" + + static const ck_bool_t tval = 1; + static const ck_bool_t fval = 0; +@@ -1172,7 +1173,7 @@ int gnutls_pkcs11_delete_url(const char *object_url, unsigned int flags) + * gnutls_pkcs11_token_init: + * @token_url: A PKCS #11 URL specifying a token + * @so_pin: Security Officer's PIN +- * @label: A name to be used for the token ++ * @label: A name to be used for the token, at most 32 characters + * + * This function will initialize (format) a token. If the token is + * at a factory defaults state the security officer's PIN given will be +@@ -1210,7 +1211,7 @@ int gnutls_pkcs11_token_init(const char *token_url, const char *so_pin, + /* so it seems memset has other uses than zeroing! */ + memset(flabel, ' ', sizeof(flabel)); + if (label != NULL) +- memcpy(flabel, label, strlen(label)); ++ memcpy(flabel, label, MIN(sizeof(flabel), strlen(label))); + + rv = pkcs11_init_token(module, slot, (uint8_t *)so_pin, strlen(so_pin), + (uint8_t *)flabel); +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 62c4ec2f9..0e4d04342 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -508,13 +508,15 @@ pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \ + if ENABLE_PKCS11 + if !WINDOWS + ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \ +- global-init-override pkcs11/distrust-after ++ global-init-override pkcs11/distrust-after pkcs11/long-label + tls13_post_handshake_with_cert_pkcs11_DEPENDENCIES = libpkcs11mock2.la libutils.la + tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL) + pkcs11_tls_neg_pkcs11_no_key_DEPENDENCIES = libpkcs11mock2.la libutils.la + pkcs11_tls_neg_pkcs11_no_key_LDADD = $(LDADD) $(LIBDL) + pkcs11_distrust_after_DEPENDENCIES = libpkcs11mock3.la libutils.la + pkcs11_distrust_after_LDADD = $(LDADD) $(LIBDL) ++pkcs11_long_label_DEPENDENCIES = libpkcs11mock4.la libutils.la ++pkcs11_long_label_LDADD = $(LDADD) $(LIBDL) + endif + endif + +diff --git a/tests/pkcs11/long-label.c b/tests/pkcs11/long-label.c +new file mode 100644 +index 000000000..a70bc9728 +--- /dev/null ++++ b/tests/pkcs11/long-label.c +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2025 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * 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 ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++ ++#if defined(_WIN32) ++ ++int main(void) ++{ ++ exit(77); ++} ++ ++#else ++ ++#include ++#include ++#include ++ ++#include "cert-common.h" ++#include "pkcs11/softhsm.h" ++#include "utils.h" ++ ++/* This program tests that a token can be initialized with ++ * a label longer than 32 characters. ++ */ ++ ++static void tls_log_func(int level, const char *str) ++{ ++ fprintf(stderr, "server|<%d>| %s", level, str); ++} ++ ++#define PIN "1234" ++ ++#define CONFIG_NAME "softhsm-long-label" ++#define CONFIG CONFIG_NAME ".config" ++ ++static int pin_func(void *userdata, int attempt, const char *url, ++ const char *label, unsigned flags, char *pin, ++ size_t pin_max) ++{ ++ if (attempt == 0) { ++ strcpy(pin, PIN); ++ return 0; ++ } ++ return -1; ++} ++ ++static void test(const char *provider) ++{ ++ int ret; ++ size_t i; ++ ++ gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); ++ ++ success("test with %s\n", provider); ++ ++ if (debug) { ++ gnutls_global_set_log_function(tls_log_func); ++ gnutls_global_set_log_level(4711); ++ } ++ ++ /* point to SoftHSM token that libpkcs11mock4.so internally uses */ ++ setenv(SOFTHSM_ENV, CONFIG, 1); ++ ++ gnutls_pkcs11_set_pin_function(pin_func, NULL); ++ ++ ret = gnutls_pkcs11_add_provider(provider, "trusted"); ++ if (ret != 0) { ++ fail("gnutls_pkcs11_add_provider: %s\n", gnutls_strerror(ret)); ++ } ++ ++ /* initialize softhsm token */ ++ ret = gnutls_pkcs11_token_init( ++ SOFTHSM_URL, PIN, ++ "this is a very long label whose length exceeds 32"); ++ if (ret < 0) { ++ fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); ++ } ++ ++ for (i = 0;; i++) { ++ char *url = NULL; ++ ++ ret = gnutls_pkcs11_token_get_url(i, 0, &url); ++ if (ret < 0) ++ break; ++ if (strstr(url, ++ "token=this%20is%20a%20very%20long%20label%20whose")) ++ break; ++ } ++ if (ret < 0) ++ fail("gnutls_pkcs11_token_get_url: %s\n", gnutls_strerror(ret)); ++ ++ gnutls_pkcs11_deinit(); ++} ++ ++void doit(void) ++{ ++ const char *bin; ++ const char *lib; ++ char buf[128]; ++ ++ if (gnutls_fips140_mode_enabled()) ++ exit(77); ++ ++ /* this must be called once in the program */ ++ global_init(); ++ ++ /* we call gnutls_pkcs11_init manually */ ++ gnutls_pkcs11_deinit(); ++ ++ /* check if softhsm module is loadable */ ++ lib = softhsm_lib(); ++ ++ /* initialize SoftHSM token that libpkcs11mock4.so internally uses */ ++ bin = softhsm_bin(); ++ ++ set_softhsm_conf(CONFIG); ++ snprintf(buf, sizeof(buf), ++ "%s --init-token --slot 0 --label test --so-pin " PIN ++ " --pin " PIN, ++ bin); ++ system(buf); ++ ++ test(lib); ++ ++ lib = getenv("P11MOCKLIB4"); ++ if (lib == NULL) { ++ fail("P11MOCKLIB4 is not set\n"); ++ } ++ ++ set_softhsm_conf(CONFIG); ++ snprintf(buf, sizeof(buf), ++ "%s --init-token --slot 0 --label test --so-pin " PIN ++ " --pin " PIN, ++ bin); ++ system(buf); ++ ++ test(lib); ++} ++#endif /* _WIN32 */ +-- +2.52.0 + diff --git a/gnutls-3.8.6-compression-dlwrap.patch b/gnutls-3.8.6-compression-dlwrap.patch deleted file mode 100644 index 835f151..0000000 --- a/gnutls-3.8.6-compression-dlwrap.patch +++ /dev/null @@ -1,2131 +0,0 @@ -From dd7f8c30ca44695992bbb92146e385b4b700f285 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sat, 29 Jun 2024 09:52:55 +0900 -Subject: [PATCH 1/4] m4: factor out soname check into a separate macro - -This moves the SONAME detection from configure.ac to m4/hooks.m4 as -the LIBGNUTLS_CHECK_SONAME macro. The new macro doesn't implicitly -set *_LIBRARY_SONAME to "none", so the callers need to adjust -themselves depending on whether the macro is defined. - -Signed-off-by: Daiki Ueno ---- - configure.ac | 50 ++++++++++++-------------------------------------- - lib/fips.c | 26 ++++++++++++++------------ - lib/fipshmac.c | 14 ++++++++++++++ - lib/global.c | 6 ++++++ - m4/hooks.m4 | 20 ++++++++++++++++++++ - 5 files changed, 66 insertions(+), 50 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 1744813b79..3f001998b4 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -810,61 +810,35 @@ save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS $GMP_CFLAGS" - save_LIBS=$LIBS - LIBS="$LIBS $GMP_LIBS" --AC_MSG_CHECKING([gmp soname]) --AC_LINK_IFELSE([AC_LANG_PROGRAM([ -+LIBGNUTLS_CHECK_SONAME([gmp], [AC_LANG_PROGRAM([ - #include ],[ - mpz_t n; -- mpz_init(n);])], -- [gmp_so=`(eval "$LDDPROG conftest$EXEEXT $LDDPOSTPROC") | grep '^libgmp\.so'`], -- [gmp_so=none]) --if test -z "$gmp_so"; then -- gmp_so=none --fi --AC_MSG_RESULT($gmp_so) --if test "$gmp_so" != none; then -- AC_DEFINE_UNQUOTED([GMP_LIBRARY_SONAME], ["$gmp_so"], [The soname of gmp library]) --fi --LIBS=$save_LIBS --CFLAGS=$save_CFLAGS -+ mpz_init(n);])]) -+LIBS="$save_LIBS" -+CFLAGS="$save_CFLAGS" - - save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS $NETTLE_CFLAGS" - save_LIBS=$LIBS - LIBS="$LIBS $NETTLE_LIBS" --AC_MSG_CHECKING([nettle soname]) --AC_LINK_IFELSE([AC_LANG_PROGRAM([ -+LIBGNUTLS_CHECK_SONAME([nettle], [AC_LANG_PROGRAM([ - #include ],[ - struct sha256_ctx ctx; -- sha256_init(&ctx);])], -- [nettle_so=`(eval "$LDDPROG conftest$EXEEXT $LDDPOSTPROC") | grep '^libnettle\.so'`], -- [nettle_so=none]) --if test -z "$nettle_so"; then -- nettle_so=none --fi --AC_MSG_RESULT($nettle_so) --AC_DEFINE_UNQUOTED([NETTLE_LIBRARY_SONAME], ["$nettle_so"], [The soname of nettle library]) --LIBS=$save_LIBS --CFLAGS=$save_CFLAGS -+ sha256_init(&ctx);])]) -+LIBS="$save_LIBS" -+CFLAGS="$save_CFLAGS" - - save_CFLAGS=$CFLAGS - # includes - CFLAGS="$CFLAGS $HOGWEED_CFLAGS $GMP_CFLAGS" - save_LIBS=$LIBS - LIBS="$LIBS $HOGWEED_LIBS" --AC_MSG_CHECKING([hogweed soname]) --AC_LINK_IFELSE([AC_LANG_PROGRAM([ -+LIBGNUTLS_CHECK_SONAME([hogweed], [AC_LANG_PROGRAM([ - #include ],[ - struct rsa_private_key priv; -- nettle_rsa_private_key_init(&priv);])], -- [hogweed_so=`(eval "$LDDPROG conftest$EXEEXT $LDDPOSTPROC") | grep '^libhogweed\.so'`], -- [hogweed_so=none]) --if test -z "$hogweed_so"; then -- hogweed_so=none --fi --AC_MSG_RESULT($hogweed_so) --AC_DEFINE_UNQUOTED([HOGWEED_LIBRARY_SONAME], ["$hogweed_so"], [The soname of hogweed library]) --LIBS=$save_LIBS --CFLAGS=$save_CFLAGS -+ nettle_rsa_private_key_init(&priv);])]) -+LIBS="$save_LIBS" -+CFLAGS="$save_CFLAGS" - - gnutls_so=libgnutls.so.`expr "$LT_CURRENT" - "$LT_AGE"` - AC_DEFINE_UNQUOTED([GNUTLS_LIBRARY_SONAME], ["$gnutls_so"], [The soname of gnutls library]) -diff --git a/lib/fips.c b/lib/fips.c -index 1611200be8..e5fce6b1b9 100644 ---- a/lib/fips.c -+++ b/lib/fips.c -@@ -152,15 +152,17 @@ void _gnutls_fips_mode_reset_zombie(void) - } - } - --/* These only works with the platform where SONAME is part of the ABI. -- * For example, *_SONAME will be set to "none" on Windows platforms. */ --#define GNUTLS_LIBRARY_NAME GNUTLS_LIBRARY_SONAME --#define NETTLE_LIBRARY_NAME NETTLE_LIBRARY_SONAME --#define HOGWEED_LIBRARY_NAME HOGWEED_LIBRARY_SONAME -+/* These only works with the platform where SONAME is part of the ABI. */ -+#ifndef GNUTLS_LIBRARY_SONAME -+#define GNUTLS_LIBRARY_SONAME "none" -+#endif - --/* GMP can be statically linked. */ --#ifdef GMP_LIBRARY_SONAME --#define GMP_LIBRARY_NAME GMP_LIBRARY_SONAME -+#ifndef NETTLE_LIBRARY_SONAME -+#define NETTLE_LIBRARY_SONAME "none" -+#endif -+ -+#ifndef HOGWEED_LIBRARY_SONAME -+#define HOGWEED_LIBRARY_SONAME "none" - #endif - - #define HMAC_SIZE 32 -@@ -246,14 +248,14 @@ static int handler(void *user, const char *section, const char *name, - } else { - return 0; - } -- } else if (!strcmp(section, GNUTLS_LIBRARY_NAME)) { -+ } else if (!strcmp(section, GNUTLS_LIBRARY_SONAME)) { - return lib_handler(&p->gnutls, section, name, value); -- } else if (!strcmp(section, NETTLE_LIBRARY_NAME)) { -+ } else if (!strcmp(section, NETTLE_LIBRARY_SONAME)) { - return lib_handler(&p->nettle, section, name, value); -- } else if (!strcmp(section, HOGWEED_LIBRARY_NAME)) { -+ } else if (!strcmp(section, HOGWEED_LIBRARY_SONAME)) { - return lib_handler(&p->hogweed, section, name, value); - #ifdef GMP_LIBRARY_SONAME -- } else if (!strcmp(section, GMP_LIBRARY_NAME)) { -+ } else if (!strcmp(section, GMP_LIBRARY_SONAME)) { - return lib_handler(&p->gmp, section, name, value); - #endif - } else { -diff --git a/lib/fipshmac.c b/lib/fipshmac.c -index 6a4883a131..d3561b4c47 100644 ---- a/lib/fipshmac.c -+++ b/lib/fipshmac.c -@@ -34,6 +34,20 @@ - #include "errors.h" - - #define FORMAT_VERSION 1 -+ -+/* These only works with the platform where SONAME is part of the ABI. */ -+#ifndef GNUTLS_LIBRARY_SONAME -+#define GNUTLS_LIBRARY_SONAME "none" -+#endif -+ -+#ifndef NETTLE_LIBRARY_SONAME -+#define NETTLE_LIBRARY_SONAME "none" -+#endif -+ -+#ifndef HOGWEED_LIBRARY_SONAME -+#define HOGWEED_LIBRARY_SONAME "none" -+#endif -+ - #define HMAC_SIZE 32 - #define HMAC_ALGO GNUTLS_MAC_SHA256 - #define HMAC_STR_SIZE (2 * HMAC_SIZE + 1) -diff --git a/lib/global.c b/lib/global.c -index 718740c103..b434140bbf 100644 ---- a/lib/global.c -+++ b/lib/global.c -@@ -563,9 +563,15 @@ static const struct gnutls_library_config_st _gnutls_library_config[] = { - #ifdef FIPS_MODULE_VERSION - { "fips-module-version", FIPS_MODULE_VERSION }, - #endif -+#ifdef GNUTLS_LIBRARY_SONAME - { "libgnutls-soname", GNUTLS_LIBRARY_SONAME }, -+#endif -+#ifdef NETTLE_LIBRARY_SONAME - { "libnettle-soname", NETTLE_LIBRARY_SONAME }, -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - { "libhogweed-soname", HOGWEED_LIBRARY_SONAME }, -+#endif - #ifdef GMP_LIBRARY_SONAME - { "libgmp-soname", GMP_LIBRARY_SONAME }, - #endif -diff --git a/m4/hooks.m4 b/m4/hooks.m4 -index cf6064ca1d..a786d35150 100644 ---- a/m4/hooks.m4 -+++ b/m4/hooks.m4 -@@ -421,3 +421,23 @@ dnl #AM_ICONV - dnl m4_ifdef([gl_ICONV_MODULE_INDICATOR], - dnl [gl_ICONV_MODULE_INDICATOR([iconv])]) - ]) -+ -+AC_DEFUN([LIBGNUTLS_CHECK_SONAME], -+[ -+ m4_pushdef([soname], AS_TR_SH([$1])) -+ m4_pushdef([SONAME], AS_TR_CPP([$1])) -+ AC_MSG_CHECKING([$1 [soname]]) -+ AC_LINK_IFELSE([$2], -+ [soname[]_so=`(eval "$LDDPROG conftest$EXEEXT $LDDPOSTPROC") | grep '^lib[]$1\.so'`], -+ [soname[]_so=none]) -+ if test -z "$soname[]_so"; then -+ soname[]_so=none -+ fi -+ AC_MSG_RESULT($soname[]_so) -+ if test "$soname[]_so" != none; then -+ SONAME[]_LIBRARY_SONAME="$soname[]_so" -+ AC_DEFINE_UNQUOTED([SONAME[]_LIBRARY_SONAME], ["$soname[]_so"], [The soname of $1 library]) -+ fi -+ m4_popdef([soname]) -+ m4_popdef([SONAME]) -+]) --- -2.45.2 - - -From 0647139f50b6c14f2f2d22d40a42a8fdfaead5d5 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sat, 6 Jul 2024 11:59:08 +0900 -Subject: [PATCH 2/4] build: check if dlopen(SONAME) works in configure - -Signed-off-by: Daiki Ueno ---- - configure.ac | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/configure.ac b/configure.ac -index 3f001998b4..8d8c4038b6 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -946,6 +946,27 @@ AM_CONDITIONAL(P11KIT_0_23_11_API, $PKG_CONFIG --atleast-version=0.23.11 p11-kit - - AM_CONDITIONAL(ENABLE_PKCS11, test "$with_p11_kit" != "no") - -+save_LIBS=$LIBS -+LIBS="$LIBS -lm" -+LIBGNUTLS_CHECK_SONAME([m], [AC_LANG_PROGRAM([ -+ #include ],[ -+ trunc (0);])]) -+LIBS="$save_LIBS" -+CFLAGS="$save_CFLAGS" -+ -+AC_RUN_IFELSE( -+ [AC_LANG_PROGRAM( -+ [[#include -+ #include -+ ]], -+ [[void *handle = dlopen("$M_LIBRARY_SONAME", RTLD_LAZY | RTLD_GLOBAL); -+ return handle != NULL ? 0 : 1; -+ ]])], -+ [ac_cv_dlopen_soname_works=yes], -+ [ac_cv_dlopen_soname_works=no], -+ [ac_cv_dlopen_soname_works=cross-compiling]) -+ -+AM_CONDITIONAL([ENABLE_DLOPEN], [test "$ac_cv_dlopen_soname_works" = yes]) - need_ltlibdl=no - - AC_ARG_WITH(tpm2, --- -2.45.2 - - -From 297c83d2830e44a675e8e52d65a66e0ba327f788 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sat, 29 Jun 2024 13:34:36 +0900 -Subject: [PATCH 3/4] build: detect SONAME for compression libraries at - configure - -Instead of hard-coding the SONAMEs for zlib, libzstd, libbrotlienc, -and libbrotlidec, this checks the actual SONAMEs at configure time, so -the first argument of dlopen is more acurate when a SONAME is bumped. - -Signed-off-by: Daiki Ueno ---- - configure.ac | 82 +++++++++++++++++++++++++++++++++++++++----------- - lib/compress.c | 8 ++--- - 2 files changed, 68 insertions(+), 22 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 8d8c4038b6..28d6895efb 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1048,8 +1048,6 @@ AC_DEFINE_UNQUOTED([TROUSERS_LIB], ["$ac_trousers_lib"], [the location of the tr - AC_SUBST(TROUSERS_LIB) - - --AM_CONDITIONAL(NEED_LTLIBDL, test "$need_ltlibdl" = yes) -- - # For minitasn1. - AC_CHECK_SIZEOF(unsigned long int, 4) - AC_CHECK_SIZEOF(unsigned int, 4) -@@ -1058,35 +1056,45 @@ AC_CHECK_SIZEOF(time_t, 4) - AC_ARG_WITH(zlib, AS_HELP_STRING([--without-zlib], - [disable zlib compression support]), - ac_zlib=$withval, ac_zlib=yes) --AC_MSG_CHECKING([whether to include zlib compression support]) --if test x$ac_zlib != xno; then -- AC_MSG_RESULT(yes) -- AC_LIB_HAVE_LINKFLAGS(z,, [#include ], [compress (0, 0, 0, 0);]) -- if test x$ac_cv_libz != xyes; then -- AC_MSG_WARN( -- *** -- *** ZLIB was not found. You will not be able to use ZLIB compression.) --fi --else -- AC_MSG_RESULT(no) --fi -- --PKG_CHECK_EXISTS(zlib, ZLIB_HAS_PKGCONFIG=y, ZLIB_HAS_PKGCONFIG=n) -- - if test x$ac_zlib != xno; then -+ PKG_CHECK_EXISTS(zlib, ZLIB_HAS_PKGCONFIG=y, ZLIB_HAS_PKGCONFIG=n) - if test "$ZLIB_HAS_PKGCONFIG" = "y" ; then -+ PKG_CHECK_MODULES(ZLIB, [zlib]) - if test "x$GNUTLS_REQUIRES_PRIVATE" = x; then - GNUTLS_REQUIRES_PRIVATE="Requires.private: zlib" - else - GNUTLS_REQUIRES_PRIVATE="$GNUTLS_REQUIRES_PRIVATE, zlib" - fi -- LIBZ_PC="" -+ ac_zlib=yes - else -+ AC_LIB_HAVE_LINKFLAGS(z,, [#include ], [compress (0, 0, 0, 0);]) -+ if test x$ac_cv_libz != xyes; then -+ AC_MSG_WARN([[ -+*** -+*** ZLIB was not found. You will not be able to use ZLIB compression. -+*** ]]) -+ fi -+ ac_zlib=$ac_cv_libz -+ ZLIB_LIBS=$LIBZ - LIBZ_PC=$LIBZ - fi - fi -+if test x$ac_zlib != xno; then -+ AC_DEFINE([HAVE_LIBZ], 1, [Define if ZLIB compression is enabled.]) -+ need_ltlibdl=yes -+fi - AC_SUBST(LIBZ_PC) - -+AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ -+ save_LIBS=$LIBS -+ LIBS="$LIBS $ZLIB_LIBS" -+ LIBGNUTLS_CHECK_SONAME([z], [AC_LANG_PROGRAM([ -+ #include ],[ -+ compress (0, 0, 0, 0);])]) -+ LIBS="$save_LIBS" -+ CFLAGS="$save_CFLAGS" -+]) -+ - AC_ARG_WITH(brotli, - AS_HELP_STRING([--without-brotli], [disable brotli compression support]), - ac_brotli=$withval, ac_brotli=yes) -@@ -1102,6 +1110,7 @@ if test x$ac_brotli != xno; then - else - GNUTLS_REQUIRES_PRIVATE="${GNUTLS_REQUIRES_PRIVATE}, libbrotlienc, libbrotlidec" - fi -+ need_ltlibdl=yes - else - AC_MSG_WARN(*** LIBBROTLI was not found. You will not be able to use BROTLI compression.) - fi -@@ -1110,6 +1119,28 @@ else - fi - AM_CONDITIONAL(HAVE_LIBBROTLI, test "$with_libbrotlienc" != "no" && test "$with_libbrotlidec" != "no") - -+AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ -+ save_CFLAGS=$CFLAGS -+ CFLAGS="$CFLAGS $LIBBROTLIENC_CFLAGS" -+ save_LIBS=$LIBS -+ LIBS="$LIBS $LIBBROTLIENC_LIBS" -+ LIBGNUTLS_CHECK_SONAME([brotlienc], [AC_LANG_PROGRAM([ -+ #include ],[ -+ BrotliEncoderVersion();])]) -+ LIBS="$save_LIBS" -+ CFLAGS="$save_CFLAGS" -+ -+ save_CFLAGS=$CFLAGS -+ CFLAGS="$CFLAGS $LIBBROTLIDEC_CFLAGS" -+ save_LIBS=$LIBS -+ LIBS="$LIBS $LIBBROTLIDEC_LIBS" -+ LIBGNUTLS_CHECK_SONAME([brotlidec], [AC_LANG_PROGRAM([ -+ #include ],[ -+ BrotliDecoderVersion();])]) -+ LIBS="$save_LIBS" -+ CFLAGS="$save_CFLAGS" -+]) -+ - AC_ARG_WITH(zstd, - AS_HELP_STRING([--without-zstd], [disable zstd compression support]), - ac_zstd=$withval, ac_zstd=yes) -@@ -1124,6 +1155,7 @@ if test x$ac_zstd != xno; then - else - GNUTLS_REQUIRES_PRIVATE="${GNUTLS_REQUIRES_PRIVATE}, libzstd" - fi -+ need_ltlibdl=yes - else - AC_MSG_WARN(*** LIBZSTD was not found. You will not be able to use ZSTD compression.) - fi -@@ -1132,6 +1164,20 @@ else - fi - AM_CONDITIONAL(HAVE_LIBZSTD, test "$with_libzstd" != "no") - -+AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ -+ save_CFLAGS=$CFLAGS -+ CFLAGS="$CFLAGS $LIBZSTD_CFLAGS" -+ save_LIBS=$LIBS -+ LIBS="$LIBS $LIBZSTD_LIBS" -+ LIBGNUTLS_CHECK_SONAME([zstd], [AC_LANG_PROGRAM([ -+ #include ],[ -+ ZSTD_versionNumber();])]) -+ LIBS="$save_LIBS" -+ CFLAGS="$save_CFLAGS" -+]) -+ -+AM_CONDITIONAL(NEED_LTLIBDL, test "$need_ltlibdl" = yes) -+ - # export for use in scripts - AC_SUBST(ac_cv_sizeof_time_t) - -diff --git a/lib/compress.c b/lib/compress.c -index a0a7c699c3..26ea2912c2 100644 ---- a/lib/compress.c -+++ b/lib/compress.c -@@ -72,7 +72,7 @@ static int zlib_init(void) - #ifndef _WIN32 - if (_zlib_handle != NULL) - return 0; -- if ((_zlib_handle = dlopen("libz.so.1", RTLD_NOW | RTLD_GLOBAL)) == -+ if ((_zlib_handle = dlopen(Z_LIBRARY_SONAME, RTLD_NOW | RTLD_GLOBAL)) == - NULL) - goto error; - if ((_gnutls_zlib_compressBound = -@@ -135,10 +135,10 @@ static int brotli_init(void) - #ifndef _WIN32 - if (_brotlienc_handle != NULL || _brotlidec_handle != NULL) - return 0; -- if ((_brotlienc_handle = dlopen("libbrotlienc.so.1", -+ if ((_brotlienc_handle = dlopen(BROTLIENC_LIBRARY_SONAME, - RTLD_NOW | RTLD_GLOBAL)) == NULL) - goto error; -- if ((_brotlidec_handle = dlopen("libbrotlidec.so.1", -+ if ((_brotlidec_handle = dlopen(BROTLIDEC_LIBRARY_SONAME, - RTLD_NOW | RTLD_GLOBAL)) == NULL) - goto error; - if ((_gnutls_BrotliEncoderMaxCompressedSize = -@@ -195,7 +195,7 @@ static int zstd_init(void) - #ifndef _WIN32 - if (_zstd_handle != NULL) - return 0; -- if ((_zstd_handle = dlopen("libzstd.so.1", RTLD_NOW | RTLD_GLOBAL)) == -+ if ((_zstd_handle = dlopen(ZSTD_LIBRARY_SONAME, RTLD_NOW | RTLD_GLOBAL)) == - NULL) - goto error; - if ((_gnutls_ZSTD_isError = dlsym(_zstd_handle, "ZSTD_isError")) == --- -2.45.2 - - -From 3e5be1315a15ac6e1e33e08f28030b8215b6d234 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sat, 29 Jun 2024 13:36:58 +0900 -Subject: [PATCH 4/4] build: switch to using dlwrap for loading compression - libraries - -This switches the logic to load compression libraries from the -hand-written code to the automatically generated code by the dlwrap -tool[1], which enables to select whether to use dlopen or link to the -library at build time. - -1. https://crates.io/crates/dlwrap - -Signed-off-by: Daiki Ueno ---- - cfg.mk | 2 +- - configure.ac | 1 + - devel/check-headers.sh | 4 +- - devel/dlwrap/brotli.license | 4 + - devel/dlwrap/brotlidec.syms | 1 + - devel/dlwrap/brotlienc.syms | 2 + - devel/dlwrap/z.license | 20 ++++ - devel/dlwrap/z.syms | 3 + - devel/dlwrap/zstd.license | 7 ++ - devel/dlwrap/zstd.syms | 4 + - devel/generate-dlwrap.sh | 37 ++++++ - devel/indent-gnutls | 2 +- - lib/Makefile.am | 40 ++++++- - lib/compress.c | 218 ++++++++++-------------------------- - lib/dlwrap/brotlidec.c | 182 ++++++++++++++++++++++++++++++ - lib/dlwrap/brotlidec.h | 47 ++++++++ - lib/dlwrap/brotlidecfuncs.h | 9 ++ - lib/dlwrap/brotlienc.c | 182 ++++++++++++++++++++++++++++++ - lib/dlwrap/brotlienc.h | 47 ++++++++ - lib/dlwrap/brotliencfuncs.h | 10 ++ - lib/dlwrap/zlib.c | 182 ++++++++++++++++++++++++++++++ - lib/dlwrap/zlib.h | 47 ++++++++ - lib/dlwrap/zlibfuncs.h | 27 +++++ - lib/dlwrap/zstd.c | 182 ++++++++++++++++++++++++++++++ - lib/dlwrap/zstd.h | 47 ++++++++ - lib/dlwrap/zstdfuncs.h | 15 +++ - 26 files changed, 1154 insertions(+), 168 deletions(-) - create mode 100644 devel/dlwrap/brotli.license - create mode 100644 devel/dlwrap/brotlidec.syms - create mode 100644 devel/dlwrap/brotlienc.syms - create mode 100644 devel/dlwrap/z.license - create mode 100644 devel/dlwrap/z.syms - create mode 100644 devel/dlwrap/zstd.license - create mode 100644 devel/dlwrap/zstd.syms - create mode 100755 devel/generate-dlwrap.sh - create mode 100644 lib/dlwrap/brotlidec.c - create mode 100644 lib/dlwrap/brotlidec.h - create mode 100644 lib/dlwrap/brotlidecfuncs.h - create mode 100644 lib/dlwrap/brotlienc.c - create mode 100644 lib/dlwrap/brotlienc.h - create mode 100644 lib/dlwrap/brotliencfuncs.h - create mode 100644 lib/dlwrap/zlib.c - create mode 100644 lib/dlwrap/zlib.h - create mode 100644 lib/dlwrap/zlibfuncs.h - create mode 100644 lib/dlwrap/zstd.c - create mode 100644 lib/dlwrap/zstd.h - create mode 100644 lib/dlwrap/zstdfuncs.h - -diff --git a/cfg.mk b/cfg.mk -index 5ef839a2c1..1b94279633 100644 ---- a/cfg.mk -+++ b/cfg.mk -@@ -24,7 +24,7 @@ PACKAGE ?= gnutls - - .PHONY: config glimport - --INDENT_SOURCES = `find . -name \*.[ch] -o -name gnutls.h.in | grep -v -e ^./build-aux/ -e ^./config.h -e ^./devel/ -e ^./gnulib -e ^./lib/minitasn1/ -e ^./lib/includes/gnutls/gnutls.h -e ^./lib/nettle/backport/ -e ^./lib/priority_options.h -e ^./lib/unistring/ -e ^./lib/x509/supported_exts.h -e ^./lib/build-aux/ -e ^./gl/ -e ^./src/gl/ -e ^./src/.*-options.[ch] -e -args.[ch] -e asn1_tab.c -e ^./tests/suite/` -+INDENT_SOURCES = `find . -name \*.[ch] -o -name gnutls.h.in | grep -v -e ^./build-aux/ -e ^./config.h -e ^./devel/ -e ^./gnulib -e ^./lib/minitasn1/ -e ^./lib/includes/gnutls/gnutls.h -e ^./lib/nettle/backport/ -e ^./lib/priority_options.h -e ^./lib/unistring/ -e ^./lib/x509/supported_exts.h -e ^./lib/build-aux/ -e ^./lib/dlwrap/ -e ^./gl/ -e ^./src/gl/ -e ^./src/.*-options.[ch] -e -args.[ch] -e asn1_tab.c -e ^./tests/suite/` - - ifeq ($(.DEFAULT_GOAL),abort-due-to-no-makefile) - .DEFAULT_GOAL := bootstrap -diff --git a/configure.ac b/configure.ac -index 28d6895efb..62a7fbdf66 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1083,6 +1083,7 @@ if test x$ac_zlib != xno; then - AC_DEFINE([HAVE_LIBZ], 1, [Define if ZLIB compression is enabled.]) - need_ltlibdl=yes - fi -+AM_CONDITIONAL(HAVE_ZLIB, test "$ac_zlib" = "yes") - AC_SUBST(LIBZ_PC) - - AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ -diff --git a/devel/dlwrap/brotli.license b/devel/dlwrap/brotli.license -new file mode 100644 -index 0000000000..d65b39b1ac ---- /dev/null -+++ b/devel/dlwrap/brotli.license -@@ -0,0 +1,4 @@ -+Copyright 2013 Google Inc. All Rights Reserved. -+ -+Distributed under MIT license. -+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT -diff --git a/devel/dlwrap/brotlidec.syms b/devel/dlwrap/brotlidec.syms -new file mode 100644 -index 0000000000..97edbad15e ---- /dev/null -+++ b/devel/dlwrap/brotlidec.syms -@@ -0,0 +1 @@ -+BrotliDecoderDecompress -diff --git a/devel/dlwrap/brotlienc.syms b/devel/dlwrap/brotlienc.syms -new file mode 100644 -index 0000000000..d618292047 ---- /dev/null -+++ b/devel/dlwrap/brotlienc.syms -@@ -0,0 +1,2 @@ -+BrotliEncoderMaxCompressedSize -+BrotliEncoderCompress -diff --git a/devel/dlwrap/z.license b/devel/dlwrap/z.license -new file mode 100644 -index 0000000000..94ce4ae9c9 ---- /dev/null -+++ b/devel/dlwrap/z.license -@@ -0,0 +1,20 @@ -+Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler -+ -+This software is provided 'as-is', without any express or implied -+warranty. In no event will the authors be held liable for any damages -+arising from the use of this software. -+ -+Permission is granted to anyone to use this software for any purpose, -+including commercial applications, and to alter it and redistribute it -+freely, subject to the following restrictions: -+ -+1. The origin of this software must not be misrepresented; you must not -+ claim that you wrote the original software. If you use this software -+ in a product, an acknowledgment in the product documentation would be -+ appreciated but is not required. -+2. Altered source versions must be plainly marked as such, and must not be -+ misrepresented as being the original software. -+3. This notice may not be removed or altered from any source distribution. -+ -+Jean-loup Gailly Mark Adler -+jloup@gzip.org madler@alumni.caltech.edu -diff --git a/devel/dlwrap/z.syms b/devel/dlwrap/z.syms -new file mode 100644 -index 0000000000..e3ed6c13f2 ---- /dev/null -+++ b/devel/dlwrap/z.syms -@@ -0,0 +1,3 @@ -+compressBound -+compress -+uncompress -diff --git a/devel/dlwrap/zstd.license b/devel/dlwrap/zstd.license -new file mode 100644 -index 0000000000..4b585386bf ---- /dev/null -+++ b/devel/dlwrap/zstd.license -@@ -0,0 +1,7 @@ -+Copyright (c) Meta Platforms, Inc. and affiliates. -+All rights reserved. -+ -+This source code is licensed under both the BSD-style license (found in the -+LICENSE file in the root directory of this source tree) and the GPLv2 (found -+in the COPYING file in the root directory of this source tree). -+You may select, at your option, one of the above-listed licenses. -diff --git a/devel/dlwrap/zstd.syms b/devel/dlwrap/zstd.syms -new file mode 100644 -index 0000000000..881bdc8135 ---- /dev/null -+++ b/devel/dlwrap/zstd.syms -@@ -0,0 +1,4 @@ -+ZSTD_isError -+ZSTD_compressBound -+ZSTD_compress -+ZSTD_decompress -diff --git a/devel/generate-dlwrap.sh b/devel/generate-dlwrap.sh -new file mode 100755 -index 0000000000..dbcf870612 ---- /dev/null -+++ b/devel/generate-dlwrap.sh -@@ -0,0 +1,37 @@ -+#!/bin/sh -+ -+# This script generates dlopen stubs for optional libraries using dlwrap tool: -+# https://crates.io/crates/dlwrap -+ -+# Copyright (c) 2023 Daiki Ueno -+# License: GPLv3+ -+ -+set +e -+ -+: ${srcdir=.} -+: ${DLWRAP=dlwrap} -+ -+if ! "$DLWRAP" -V >& /dev/null; then -+ echo 1>&2 "$0: "$DLWRAP" is missing" -+ exit 77 -+fi -+ -+SRC="$srcdir/devel/$DLWRAP" -+DST="$srcdir/lib/$DLWRAP" -+ -+echo "Generating $DST/zlib.h" -+ -+"$DLWRAP" --input /usr/include/zlib.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/z.syms" --license-file "$SRC/z.license" --soname Z_LIBRARY_SONAME --prefix gnutls_zlib --header-guard GNUTLS_LIB_DLWRAP_ZLIB_H_ --include "" -+ -+echo "Generating $DST/zstd.h" -+ -+"$DLWRAP" --input /usr/include/zstd.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/zstd.syms" --license-file "$SRC/zstd.license" --soname ZSTD_LIBRARY_SONAME --prefix gnutls_zstd --header-guard GNUTLS_LIB_DLWRAP_ZSTD_H_ --include "" -+ -+echo "Generating $DST/brotlienc.h" -+ -+"$DLWRAP" --input /usr/include/brotli/encode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlienc.syms" --license-file "$SRC/brotli.license" --soname BROTLIENC_LIBRARY_SONAME --prefix gnutls_brotlienc --loader-basename brotlienc --header-guard GNUTLS_LIB_DLWRAP_BROTLIENC_H_ --include "" -+ -+echo "Generating $DST/brotlidec.h" -+ -+"$DLWRAP" --input /usr/include/brotli/decode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlidec.syms" --license-file "$SRC/brotli.license" --soname BROTLIDEC_LIBRARY_SONAME --prefix gnutls_brotlidec --loader-basename brotlidec --header-guard GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ --include "" -+ -diff --git a/lib/Makefile.am b/lib/Makefile.am -index a50d3114ea..d1bd07248e 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -33,7 +33,7 @@ localedir = $(datadir)/locale - - include $(top_srcdir)/lib/common.mk - --AM_CPPFLAGS = \ -+AM_CPPFLAGS = \ - -DLOCALEDIR=\"$(localedir)\" \ - -I$(srcdir)/../gl \ - -I$(builddir)/../gl \ -@@ -45,7 +45,8 @@ AM_CPPFLAGS = \ - $(LIBTASN1_CFLAGS) \ - $(P11_KIT_CFLAGS) \ - $(TSS2_CFLAGS) -- $(LIBZSTD_CFLAGS) -+ -+thirdparty_libadd = - - if !HAVE_LIBUNISTRING - SUBDIRS += unistring -@@ -85,6 +86,39 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c gthreads.h handshake-tls - hello_ext_lib.c hello_ext_lib.h ocsp-api.c stek.c cert-cred-rawpk.c \ - iov.c iov.h system/ktls.c system/ktls.h pathbuf.c pathbuf.h - -+if HAVE_ZLIB -+COBJECTS += dlwrap/zlib.c dlwrap/zlibfuncs.h dlwrap/zlib.h -+ -+if ENABLE_DLOPEN -+AM_CPPFLAGS += $(ZLIB_CFLAGS) -DGNUTLS_ZLIB_ENABLE_DLOPEN=1 -+else -+thirdparty_libadd += $(ZLIB_LIBS) -+endif -+endif -+ -+if HAVE_LIBZSTD -+COBJECTS += dlwrap/zstd.c dlwrap/zstdfuncs.h dlwrap/zstd.h -+ -+if ENABLE_DLOPEN -+AM_CPPFLAGS += $(LIBZSTD_CFLAGS) -DGNUTLS_ZSTD_ENABLE_DLOPEN=1 -+else -+thirdparty_libadd += $(LIBZSTD_LIBS) -+endif -+endif -+ -+if HAVE_LIBBROTLI -+COBJECTS += dlwrap/brotlienc.c dlwrap/brotliencfuncs.h dlwrap/brotlienc.h -+COBJECTS += dlwrap/brotlidec.c dlwrap/brotlidecfuncs.h dlwrap/brotlidec.h -+ -+if ENABLE_DLOPEN -+AM_CPPFLAGS += $(LIBBROTLIENC_CFLAGS) -DGNUTLS_BROTLIENC_ENABLE_DLOPEN=1 -+AM_CPPFLAGS += $(LIBBROTLIDEC_CFLAGS) -DGNUTLS_BROTLIDEC_ENABLE_DLOPEN=1 -+else -+thirdparty_libadd += $(LIBBROTLIENC_LIBS) -+thirdparty_libadd += $(LIBBROTLIDEC_LIBS) -+endif -+endif -+ - if ENABLE_GOST - COBJECTS += vko.c - endif -@@ -156,7 +190,7 @@ libgnutls_la_LIBADD = ../gl/libgnu.la x509/libgnutls_x509.la \ - ext/libgnutls_ext.la \ - auth/libgnutls_auth.la algorithms/libgnutls_alg.la \ - extras/libgnutls_extras.la --thirdparty_libadd = $(LTLIBINTL) $(LIBSOCKET) $(LTLIBNSL) \ -+thirdparty_libadd += $(LTLIBINTL) $(LIBSOCKET) $(LTLIBNSL) \ - $(P11_KIT_LIBS) $(LIB_SELECT) $(GNUTLS_LIBS_PRIVATE) - - if HAVE_LIBIDN2 -diff --git a/lib/compress.c b/lib/compress.c -index 26ea2912c2..936a459532 100644 ---- a/lib/compress.c -+++ b/lib/compress.c -@@ -25,198 +25,91 @@ - - #include "compress.h" - --#ifndef _WIN32 -+#ifdef _WIN32 -+#define RTLD_NOW 0 -+#define RTLD_GLOBAL 0 -+#else - #include - #endif - -+#ifndef Z_LIBRARY_SONAME -+#define Z_LIBRARY_SONAME "none" -+#endif -+ -+#ifndef BROTLIENC_LIBRARY_SONAME -+#define BROTLIENC_LIBRARY_SONAME "none" -+#endif -+ -+#ifndef BROTLIDEC_LIBRARY_SONAME -+#define BROTLIDEC_LIBRARY_SONAME "none" -+#endif -+ -+#ifndef ZSTD_LIBRARY_SONAME -+#define ZSTD_LIBRARY_SONAME "none" -+#endif -+ - #ifdef HAVE_LIBZ --#include -+#include "dlwrap/zlib.h" - #endif - - #ifdef HAVE_LIBBROTLI --#include --#include -+#include "dlwrap/brotlienc.h" -+#include "dlwrap/brotlidec.h" - #endif - - #ifdef HAVE_LIBZSTD --#include -+#include "dlwrap/zstd.h" - #endif - - #ifdef HAVE_LIBZ --static void *_zlib_handle; -- --#if HAVE___TYPEOF__ --static __typeof__(compressBound)(*_gnutls_zlib_compressBound); --static __typeof__(compress)(*_gnutls_zlib_compress); --static __typeof__(uncompress)(*_gnutls_zlib_uncompress); --#else --static uLong (*_gnutls_zlib_compressBound)(uLong sourceLen); --static int (*_gnutls_zlib_compress)(Bytef *dest, uLongf *destLen, -- const Bytef *source, uLong sourceLen); --static int (*_gnutls_zlib_uncompress)(Bytef *dest, uLongf *destLen, -- const Bytef *source, uLong sourceLen); --#endif /* HAVE___TYPEOF__ */ -- - static void zlib_deinit(void) - { --#ifndef _WIN32 -- if (_zlib_handle != NULL) { -- dlclose(_zlib_handle); -- _zlib_handle = NULL; -- } --#endif /* _WIN32 */ -+ gnutls_zlib_unload_library(); - } - - static int zlib_init(void) - { --#ifndef _WIN32 -- if (_zlib_handle != NULL) -- return 0; -- if ((_zlib_handle = dlopen(Z_LIBRARY_SONAME, RTLD_NOW | RTLD_GLOBAL)) == -- NULL) -- goto error; -- if ((_gnutls_zlib_compressBound = -- dlsym(_zlib_handle, "compressBound")) == NULL) -- goto error; -- if ((_gnutls_zlib_compress = dlsym(_zlib_handle, "compress")) == NULL) -- goto error; -- if ((_gnutls_zlib_uncompress = dlsym(_zlib_handle, "uncompress")) == -- NULL) -- goto error; -+ if (gnutls_zlib_ensure_library(Z_LIBRARY_SONAME, -+ RTLD_NOW | RTLD_GLOBAL) < 0) -+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - return 0; --error: -- zlib_deinit(); -- return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); --#else -- return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); --#endif /* _WIN32 */ - } - #endif /* HAVE_LIBZ */ - - #ifdef HAVE_LIBBROTLI --static void *_brotlienc_handle; --static void *_brotlidec_handle; -- --#if HAVE___TYPEOF__ --static __typeof__(BrotliEncoderMaxCompressedSize)( -- *_gnutls_BrotliEncoderMaxCompressedSize); --static __typeof__(BrotliEncoderCompress)(*_gnutls_BrotliEncoderCompress); --static __typeof__(BrotliDecoderDecompress)(*_gnutls_BrotliDecoderDecompress); --#else --static size_t (*_gnutls_BrotliEncoderMaxCompressedSize)(size_t input_size); --static BROTLI_BOOL (*_gnutls_BrotliEncoderCompress)( -- int quality, int lgwin, BrotliEncoderMode mode, size_t input_size, -- const uint8_t input_buffer[BROTLI_ARRAY_PARAM(input_size)], -- size_t *encoded_size, -- uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(*encoded_size)]); --static BrotliDecoderResult (*_gnutls_BrotliDecoderDecompress)( -- size_t encoded_size, -- const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)], -- size_t *decoded_size, -- uint8_t decoded_buffer[BROTLI_ARRAY_PARAM(*decoded_size)]); --#endif /* HAVE___TYPEOF__ */ - - static void brotli_deinit(void) - { --#ifndef _WIN32 -- if (_brotlienc_handle != NULL) { -- dlclose(_brotlienc_handle); -- _brotlienc_handle = NULL; -- } -- if (_brotlidec_handle != NULL) { -- dlclose(_brotlidec_handle); -- _brotlidec_handle = NULL; -- } --#endif /* _WIN32 */ -+ gnutls_brotlienc_unload_library(); -+ gnutls_brotlidec_unload_library(); - } - - static int brotli_init(void) - { --#ifndef _WIN32 -- if (_brotlienc_handle != NULL || _brotlidec_handle != NULL) -- return 0; -- if ((_brotlienc_handle = dlopen(BROTLIENC_LIBRARY_SONAME, -- RTLD_NOW | RTLD_GLOBAL)) == NULL) -- goto error; -- if ((_brotlidec_handle = dlopen(BROTLIDEC_LIBRARY_SONAME, -- RTLD_NOW | RTLD_GLOBAL)) == NULL) -- goto error; -- if ((_gnutls_BrotliEncoderMaxCompressedSize = -- dlsym(_brotlienc_handle, -- "BrotliEncoderMaxCompressedSize")) == NULL) -- goto error; -- if ((_gnutls_BrotliEncoderCompress = -- dlsym(_brotlienc_handle, "BrotliEncoderCompress")) == NULL) -- goto error; -- if ((_gnutls_BrotliDecoderDecompress = dlsym( -- _brotlidec_handle, "BrotliDecoderDecompress")) == NULL) -- goto error; -+ if (gnutls_brotlienc_ensure_library(BROTLIENC_LIBRARY_SONAME, -+ RTLD_NOW | RTLD_GLOBAL) < 0) -+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); -+ -+ if (gnutls_brotlidec_ensure_library(BROTLIDEC_LIBRARY_SONAME, -+ RTLD_NOW | RTLD_GLOBAL) < 0) -+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - return 0; --error: -- brotli_deinit(); -- return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); --#else -- return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); --#endif /* _WIN32 */ - } - #endif /* HAVE_LIBBROTLI */ - - #ifdef HAVE_LIBZSTD --static void *_zstd_handle; -- --#if HAVE___TYPEOF__ --static __typeof__(ZSTD_isError)(*_gnutls_ZSTD_isError); --static __typeof__(ZSTD_compressBound)(*_gnutls_ZSTD_compressBound); --static __typeof__(ZSTD_compress)(*_gnutls_ZSTD_compress); --static __typeof__(ZSTD_decompress)(*_gnutls_ZSTD_decompress); --#else --static unsigned (*_gnutls_ZSTD_isError)(size_t code); --static size_t (*_gnutls_ZSTD_compressBound)(size_t srcSize); --static size_t (*_gnutls_ZSTD_compress)(void *dst, size_t dstCapacity, -- const void *src, size_t srcSize, -- int compressionLevel); --static size_t (*_gnutls_ZSTD_decompress)(void *dst, size_t dstCapacity, -- const void *src, -- size_t compressedSize); --#endif /* HAVE___TYPEOF__ */ - - static void zstd_deinit(void) - { --#ifndef _WIN32 -- if (_zstd_handle != NULL) { -- dlclose(_zstd_handle); -- _zstd_handle = NULL; -- } --#endif /* _WIN32 */ -+ gnutls_zstd_unload_library(); - } - - static int zstd_init(void) - { --#ifndef _WIN32 -- if (_zstd_handle != NULL) -- return 0; -- if ((_zstd_handle = dlopen(ZSTD_LIBRARY_SONAME, RTLD_NOW | RTLD_GLOBAL)) == -- NULL) -- goto error; -- if ((_gnutls_ZSTD_isError = dlsym(_zstd_handle, "ZSTD_isError")) == -- NULL) -- goto error; -- if ((_gnutls_ZSTD_compressBound = -- dlsym(_zstd_handle, "ZSTD_compressBound")) == NULL) -- goto error; -- if ((_gnutls_ZSTD_compress = dlsym(_zstd_handle, "ZSTD_compress")) == -- NULL) -- goto error; -- if ((_gnutls_ZSTD_decompress = -- dlsym(_zstd_handle, "ZSTD_decompress")) == NULL) -- goto error; -+ if (gnutls_zstd_ensure_library(ZSTD_LIBRARY_SONAME, -+ RTLD_NOW | RTLD_GLOBAL) < 0) -+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - return 0; --error: -- zstd_deinit(); -- return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); --#else -- return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); --#endif /* _WIN32 */ - } - #endif /* HAVE_LIBZSTD */ - -@@ -345,15 +238,16 @@ size_t _gnutls_compress_bound(gnutls_compression_method_t alg, size_t src_len) - switch (alg) { - #ifdef HAVE_LIBZ - case GNUTLS_COMP_ZLIB: -- return _gnutls_zlib_compressBound(src_len); -+ return GNUTLS_ZLIB_FUNC(compressBound)(src_len); - #endif - #ifdef HAVE_LIBBROTLI - case GNUTLS_COMP_BROTLI: -- return _gnutls_BrotliEncoderMaxCompressedSize(src_len); -+ return GNUTLS_BROTLIENC_FUNC(BrotliEncoderMaxCompressedSize)( -+ src_len); - #endif - #ifdef HAVE_LIBZSTD - case GNUTLS_COMP_ZSTD: -- return _gnutls_ZSTD_compressBound(src_len); -+ return GNUTLS_ZSTD_FUNC(ZSTD_compressBound)(src_len); - #endif - default: - return 0; -@@ -372,7 +266,7 @@ int _gnutls_compress(gnutls_compression_method_t alg, uint8_t *dst, - int err; - uLongf comp_len = dst_len; - -- err = _gnutls_zlib_compress(dst, &comp_len, src, src_len); -+ err = GNUTLS_ZLIB_FUNC(compress)(dst, &comp_len, src, src_len); - if (err != Z_OK) - return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED); - ret = comp_len; -@@ -383,7 +277,7 @@ int _gnutls_compress(gnutls_compression_method_t alg, uint8_t *dst, - BROTLI_BOOL err; - size_t comp_len = dst_len; - -- err = _gnutls_BrotliEncoderCompress( -+ err = GNUTLS_BROTLIENC_FUNC(BrotliEncoderCompress)( - BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, - BROTLI_DEFAULT_MODE, src_len, src, &comp_len, dst); - if (!err) -@@ -395,9 +289,9 @@ int _gnutls_compress(gnutls_compression_method_t alg, uint8_t *dst, - case GNUTLS_COMP_ZSTD: { - size_t comp_len; - -- comp_len = _gnutls_ZSTD_compress(dst, dst_len, src, src_len, -- ZSTD_CLEVEL_DEFAULT); -- if (_gnutls_ZSTD_isError(comp_len)) -+ comp_len = GNUTLS_ZSTD_FUNC(ZSTD_compress)( -+ dst, dst_len, src, src_len, ZSTD_CLEVEL_DEFAULT); -+ if (GNUTLS_ZSTD_FUNC(ZSTD_isError)(comp_len)) - return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED); - ret = comp_len; - } break; -@@ -425,7 +319,8 @@ int _gnutls_decompress(gnutls_compression_method_t alg, uint8_t *dst, - int err; - uLongf plain_len = dst_len; - -- err = _gnutls_zlib_uncompress(dst, &plain_len, src, src_len); -+ err = GNUTLS_ZLIB_FUNC(uncompress)(dst, &plain_len, src, -+ src_len); - if (err != Z_OK) - return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED); - ret = plain_len; -@@ -436,8 +331,8 @@ int _gnutls_decompress(gnutls_compression_method_t alg, uint8_t *dst, - BrotliDecoderResult err; - size_t plain_len = dst_len; - -- err = _gnutls_BrotliDecoderDecompress(src_len, src, &plain_len, -- dst); -+ err = GNUTLS_BROTLIDEC_FUNC( -+ BrotliDecoderDecompress)(src_len, src, &plain_len, dst); - if (err != BROTLI_DECODER_RESULT_SUCCESS) - return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED); - ret = plain_len; -@@ -447,8 +342,9 @@ int _gnutls_decompress(gnutls_compression_method_t alg, uint8_t *dst, - case GNUTLS_COMP_ZSTD: { - size_t plain_len; - -- plain_len = _gnutls_ZSTD_decompress(dst, dst_len, src, src_len); -- if (_gnutls_ZSTD_isError(plain_len)) -+ plain_len = GNUTLS_ZSTD_FUNC(ZSTD_decompress)(dst, dst_len, src, -+ src_len); -+ if (GNUTLS_ZSTD_FUNC(ZSTD_isError)(plain_len)) - return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED); - ret = plain_len; - } break; -diff --git a/lib/dlwrap/brotlidec.c b/lib/dlwrap/brotlidec.c -new file mode 100644 -index 0000000000..45c9b4b259 ---- /dev/null -+++ b/lib/dlwrap/brotlidec.c -@@ -0,0 +1,182 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "brotlidec.h" -+ -+#if defined(GNUTLS_BROTLIDEC_ENABLE_DLOPEN) && GNUTLS_BROTLIDEC_ENABLE_DLOPEN -+ -+#include -+#include -+#include -+#include -+ -+/* If BROTLIDEC_LIBRARY_SONAME is defined, dlopen handle can be automatically -+ * set; otherwise, the caller needs to call -+ * gnutls_brotlidec_ensure_library with soname determined at run time. -+ */ -+#ifdef BROTLIDEC_LIBRARY_SONAME -+ -+static void -+ensure_library (void) -+{ -+ if (gnutls_brotlidec_ensure_library (BROTLIDEC_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ abort (); -+} -+ -+#if defined(GNUTLS_BROTLIDEC_ENABLE_PTHREAD) && GNUTLS_BROTLIDEC_ENABLE_PTHREAD -+#include -+ -+static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; -+ -+#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library) -+ -+#else /* GNUTLS_BROTLIDEC_ENABLE_PTHREAD */ -+ -+#define ENSURE_LIBRARY do { \ -+ if (!gnutls_brotlidec_dlhandle) \ -+ ensure_library(); \ -+ } while (0) -+ -+#endif /* !GNUTLS_BROTLIDEC_ENABLE_PTHREAD */ -+ -+#else /* BROTLIDEC_LIBRARY_SONAME */ -+ -+#define ENSURE_LIBRARY do {} while (0) -+ -+#endif /* !BROTLIDEC_LIBRARY_SONAME */ -+ -+static void *gnutls_brotlidec_dlhandle; -+ -+/* Define redirection symbols */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#if (2 <= __GNUC__ || (4 <= __clang_major__)) -+#define FUNC(ret, name, args, cargs) \ -+ static __typeof__(name)(*gnutls_brotlidec_sym_##name); -+#else -+#define FUNC(ret, name, args, cargs) \ -+ static ret(*gnutls_brotlidec_sym_##name)args; -+#endif -+#define VOID_FUNC FUNC -+#include "brotlidecfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+/* Define redirection wrapper functions */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ret gnutls_brotlidec_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_brotlidec_sym_##name); \ -+ return gnutls_brotlidec_sym_##name cargs; \ -+} -+#define VOID_FUNC(ret, name, args, cargs) \ -+ret gnutls_brotlidec_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_brotlidec_sym_##name); \ -+ gnutls_brotlidec_sym_##name cargs; \ -+} -+#include "brotlidecfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+static int -+ensure_symbol (const char *name, void **symp) -+{ -+ if (!*symp) -+ { -+ void *sym = dlsym (gnutls_brotlidec_dlhandle, name); -+ if (!sym) -+ return -errno; -+ *symp = sym; -+ } -+ return 0; -+} -+ -+int -+gnutls_brotlidec_ensure_library (const char *soname, int flags) -+{ -+ int err; -+ -+ if (!gnutls_brotlidec_dlhandle) -+ { -+ gnutls_brotlidec_dlhandle = dlopen (soname, flags); -+ if (!gnutls_brotlidec_dlhandle) -+ return -errno; -+ } -+ -+#define ENSURE_SYMBOL(name) \ -+ ensure_symbol(#name, (void **)&gnutls_brotlidec_sym_##name) -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ return err; -+#define VOID_FUNC FUNC -+#include "brotlidecfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef ENSURE_SYMBOL -+ return 0; -+} -+ -+void -+gnutls_brotlidec_unload_library (void) -+{ -+ if (gnutls_brotlidec_dlhandle) -+ dlclose (gnutls_brotlidec_dlhandle); -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ gnutls_brotlidec_sym_##name = NULL; -+#define VOID_FUNC FUNC -+#include "brotlidecfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef RESET_SYMBOL -+} -+ -+#else /* GNUTLS_BROTLIDEC_ENABLE_DLOPEN */ -+ -+int -+gnutls_brotlidec_ensure_library (const char *soname, int flags) -+{ -+ (void) soname; -+ (void) flags; -+ return 0; -+} -+ -+void -+gnutls_brotlidec_unload_library (void) -+{ -+} -+ -+#endif /* !GNUTLS_BROTLIDEC_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/brotlidec.h b/lib/dlwrap/brotlidec.h -new file mode 100644 -index 0000000000..31397f24cf ---- /dev/null -+++ b/lib/dlwrap/brotlidec.h -@@ -0,0 +1,47 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifndef GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ -+#define GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ -+ -+#include -+ -+#if defined(GNUTLS_BROTLIDEC_ENABLE_DLOPEN) && GNUTLS_BROTLIDEC_ENABLE_DLOPEN -+ -+#define FUNC(ret, name, args, cargs) \ -+ ret gnutls_brotlidec_func_##name args; -+#define VOID_FUNC FUNC -+#include "brotlidecfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#define GNUTLS_BROTLIDEC_FUNC(name) gnutls_brotlidec_func_##name -+ -+#else -+ -+#define GNUTLS_BROTLIDEC_FUNC(name) name -+ -+#endif /* GNUTLS_BROTLIDEC_ENABLE_DLOPEN */ -+ -+/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary -+ * symbols are resolved. -+ * -+ * Returns 0 on success; negative error code otherwise. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+int gnutls_brotlidec_ensure_library (const char *soname, int flags); -+ -+/* Unload library and reset symbols. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+void gnutls_brotlidec_unload_library (void); -+ -+#endif /* GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ */ -diff --git a/lib/dlwrap/brotlidecfuncs.h b/lib/dlwrap/brotlidecfuncs.h -new file mode 100644 -index 0000000000..aa033e3a8b ---- /dev/null -+++ b/lib/dlwrap/brotlidecfuncs.h -@@ -0,0 +1,9 @@ -+/* -+ * This file was automatically generated from decode.h, -+ * which is covered by the following license: -+ * Copyright 2013 Google Inc. All Rights Reserved. -+ * -+ * Distributed under MIT license. -+ * See file LICENSE for detail or copy at https://opensource.org/licenses/MIT -+ */ -+FUNC(BrotliDecoderResult, BrotliDecoderDecompress, (size_t encoded_size, const uint8_t encoded_buffer[], size_t *decoded_size, uint8_t decoded_buffer[]), (encoded_size, encoded_buffer, decoded_size, decoded_buffer)) -diff --git a/lib/dlwrap/brotlienc.c b/lib/dlwrap/brotlienc.c -new file mode 100644 -index 0000000000..9dd8ff37c6 ---- /dev/null -+++ b/lib/dlwrap/brotlienc.c -@@ -0,0 +1,182 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "brotlienc.h" -+ -+#if defined(GNUTLS_BROTLIENC_ENABLE_DLOPEN) && GNUTLS_BROTLIENC_ENABLE_DLOPEN -+ -+#include -+#include -+#include -+#include -+ -+/* If BROTLIENC_LIBRARY_SONAME is defined, dlopen handle can be automatically -+ * set; otherwise, the caller needs to call -+ * gnutls_brotlienc_ensure_library with soname determined at run time. -+ */ -+#ifdef BROTLIENC_LIBRARY_SONAME -+ -+static void -+ensure_library (void) -+{ -+ if (gnutls_brotlienc_ensure_library (BROTLIENC_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ abort (); -+} -+ -+#if defined(GNUTLS_BROTLIENC_ENABLE_PTHREAD) && GNUTLS_BROTLIENC_ENABLE_PTHREAD -+#include -+ -+static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; -+ -+#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library) -+ -+#else /* GNUTLS_BROTLIENC_ENABLE_PTHREAD */ -+ -+#define ENSURE_LIBRARY do { \ -+ if (!gnutls_brotlienc_dlhandle) \ -+ ensure_library(); \ -+ } while (0) -+ -+#endif /* !GNUTLS_BROTLIENC_ENABLE_PTHREAD */ -+ -+#else /* BROTLIENC_LIBRARY_SONAME */ -+ -+#define ENSURE_LIBRARY do {} while (0) -+ -+#endif /* !BROTLIENC_LIBRARY_SONAME */ -+ -+static void *gnutls_brotlienc_dlhandle; -+ -+/* Define redirection symbols */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#if (2 <= __GNUC__ || (4 <= __clang_major__)) -+#define FUNC(ret, name, args, cargs) \ -+ static __typeof__(name)(*gnutls_brotlienc_sym_##name); -+#else -+#define FUNC(ret, name, args, cargs) \ -+ static ret(*gnutls_brotlienc_sym_##name)args; -+#endif -+#define VOID_FUNC FUNC -+#include "brotliencfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+/* Define redirection wrapper functions */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ret gnutls_brotlienc_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_brotlienc_sym_##name); \ -+ return gnutls_brotlienc_sym_##name cargs; \ -+} -+#define VOID_FUNC(ret, name, args, cargs) \ -+ret gnutls_brotlienc_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_brotlienc_sym_##name); \ -+ gnutls_brotlienc_sym_##name cargs; \ -+} -+#include "brotliencfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+static int -+ensure_symbol (const char *name, void **symp) -+{ -+ if (!*symp) -+ { -+ void *sym = dlsym (gnutls_brotlienc_dlhandle, name); -+ if (!sym) -+ return -errno; -+ *symp = sym; -+ } -+ return 0; -+} -+ -+int -+gnutls_brotlienc_ensure_library (const char *soname, int flags) -+{ -+ int err; -+ -+ if (!gnutls_brotlienc_dlhandle) -+ { -+ gnutls_brotlienc_dlhandle = dlopen (soname, flags); -+ if (!gnutls_brotlienc_dlhandle) -+ return -errno; -+ } -+ -+#define ENSURE_SYMBOL(name) \ -+ ensure_symbol(#name, (void **)&gnutls_brotlienc_sym_##name) -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ return err; -+#define VOID_FUNC FUNC -+#include "brotliencfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef ENSURE_SYMBOL -+ return 0; -+} -+ -+void -+gnutls_brotlienc_unload_library (void) -+{ -+ if (gnutls_brotlienc_dlhandle) -+ dlclose (gnutls_brotlienc_dlhandle); -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ gnutls_brotlienc_sym_##name = NULL; -+#define VOID_FUNC FUNC -+#include "brotliencfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef RESET_SYMBOL -+} -+ -+#else /* GNUTLS_BROTLIENC_ENABLE_DLOPEN */ -+ -+int -+gnutls_brotlienc_ensure_library (const char *soname, int flags) -+{ -+ (void) soname; -+ (void) flags; -+ return 0; -+} -+ -+void -+gnutls_brotlienc_unload_library (void) -+{ -+} -+ -+#endif /* !GNUTLS_BROTLIENC_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/brotlienc.h b/lib/dlwrap/brotlienc.h -new file mode 100644 -index 0000000000..ed1af45e04 ---- /dev/null -+++ b/lib/dlwrap/brotlienc.h -@@ -0,0 +1,47 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifndef GNUTLS_LIB_DLWRAP_BROTLIENC_H_ -+#define GNUTLS_LIB_DLWRAP_BROTLIENC_H_ -+ -+#include -+ -+#if defined(GNUTLS_BROTLIENC_ENABLE_DLOPEN) && GNUTLS_BROTLIENC_ENABLE_DLOPEN -+ -+#define FUNC(ret, name, args, cargs) \ -+ ret gnutls_brotlienc_func_##name args; -+#define VOID_FUNC FUNC -+#include "brotliencfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#define GNUTLS_BROTLIENC_FUNC(name) gnutls_brotlienc_func_##name -+ -+#else -+ -+#define GNUTLS_BROTLIENC_FUNC(name) name -+ -+#endif /* GNUTLS_BROTLIENC_ENABLE_DLOPEN */ -+ -+/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary -+ * symbols are resolved. -+ * -+ * Returns 0 on success; negative error code otherwise. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+int gnutls_brotlienc_ensure_library (const char *soname, int flags); -+ -+/* Unload library and reset symbols. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+void gnutls_brotlienc_unload_library (void); -+ -+#endif /* GNUTLS_LIB_DLWRAP_BROTLIENC_H_ */ -diff --git a/lib/dlwrap/brotliencfuncs.h b/lib/dlwrap/brotliencfuncs.h -new file mode 100644 -index 0000000000..1a4f884d35 ---- /dev/null -+++ b/lib/dlwrap/brotliencfuncs.h -@@ -0,0 +1,10 @@ -+/* -+ * This file was automatically generated from encode.h, -+ * which is covered by the following license: -+ * Copyright 2013 Google Inc. All Rights Reserved. -+ * -+ * Distributed under MIT license. -+ * See file LICENSE for detail or copy at https://opensource.org/licenses/MIT -+ */ -+FUNC(size_t, BrotliEncoderMaxCompressedSize, (size_t input_size), (input_size)) -+FUNC(int, BrotliEncoderCompress, (int quality, int lgwin, BrotliEncoderMode mode, size_t input_size, const uint8_t input_buffer[], size_t *encoded_size, uint8_t encoded_buffer[]), (quality, lgwin, mode, input_size, input_buffer, encoded_size, encoded_buffer)) -diff --git a/lib/dlwrap/zlib.c b/lib/dlwrap/zlib.c -new file mode 100644 -index 0000000000..455485c63f ---- /dev/null -+++ b/lib/dlwrap/zlib.c -@@ -0,0 +1,182 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "zlib.h" -+ -+#if defined(GNUTLS_ZLIB_ENABLE_DLOPEN) && GNUTLS_ZLIB_ENABLE_DLOPEN -+ -+#include -+#include -+#include -+#include -+ -+/* If Z_LIBRARY_SONAME is defined, dlopen handle can be automatically -+ * set; otherwise, the caller needs to call -+ * gnutls_zlib_ensure_library with soname determined at run time. -+ */ -+#ifdef Z_LIBRARY_SONAME -+ -+static void -+ensure_library (void) -+{ -+ if (gnutls_zlib_ensure_library (Z_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ abort (); -+} -+ -+#if defined(GNUTLS_ZLIB_ENABLE_PTHREAD) && GNUTLS_ZLIB_ENABLE_PTHREAD -+#include -+ -+static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; -+ -+#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library) -+ -+#else /* GNUTLS_ZLIB_ENABLE_PTHREAD */ -+ -+#define ENSURE_LIBRARY do { \ -+ if (!gnutls_zlib_dlhandle) \ -+ ensure_library(); \ -+ } while (0) -+ -+#endif /* !GNUTLS_ZLIB_ENABLE_PTHREAD */ -+ -+#else /* Z_LIBRARY_SONAME */ -+ -+#define ENSURE_LIBRARY do {} while (0) -+ -+#endif /* !Z_LIBRARY_SONAME */ -+ -+static void *gnutls_zlib_dlhandle; -+ -+/* Define redirection symbols */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#if (2 <= __GNUC__ || (4 <= __clang_major__)) -+#define FUNC(ret, name, args, cargs) \ -+ static __typeof__(name)(*gnutls_zlib_sym_##name); -+#else -+#define FUNC(ret, name, args, cargs) \ -+ static ret(*gnutls_zlib_sym_##name)args; -+#endif -+#define VOID_FUNC FUNC -+#include "zlibfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+/* Define redirection wrapper functions */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ret gnutls_zlib_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_zlib_sym_##name); \ -+ return gnutls_zlib_sym_##name cargs; \ -+} -+#define VOID_FUNC(ret, name, args, cargs) \ -+ret gnutls_zlib_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_zlib_sym_##name); \ -+ gnutls_zlib_sym_##name cargs; \ -+} -+#include "zlibfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+static int -+ensure_symbol (const char *name, void **symp) -+{ -+ if (!*symp) -+ { -+ void *sym = dlsym (gnutls_zlib_dlhandle, name); -+ if (!sym) -+ return -errno; -+ *symp = sym; -+ } -+ return 0; -+} -+ -+int -+gnutls_zlib_ensure_library (const char *soname, int flags) -+{ -+ int err; -+ -+ if (!gnutls_zlib_dlhandle) -+ { -+ gnutls_zlib_dlhandle = dlopen (soname, flags); -+ if (!gnutls_zlib_dlhandle) -+ return -errno; -+ } -+ -+#define ENSURE_SYMBOL(name) \ -+ ensure_symbol(#name, (void **)&gnutls_zlib_sym_##name) -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ return err; -+#define VOID_FUNC FUNC -+#include "zlibfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef ENSURE_SYMBOL -+ return 0; -+} -+ -+void -+gnutls_zlib_unload_library (void) -+{ -+ if (gnutls_zlib_dlhandle) -+ dlclose (gnutls_zlib_dlhandle); -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ gnutls_zlib_sym_##name = NULL; -+#define VOID_FUNC FUNC -+#include "zlibfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef RESET_SYMBOL -+} -+ -+#else /* GNUTLS_ZLIB_ENABLE_DLOPEN */ -+ -+int -+gnutls_zlib_ensure_library (const char *soname, int flags) -+{ -+ (void) soname; -+ (void) flags; -+ return 0; -+} -+ -+void -+gnutls_zlib_unload_library (void) -+{ -+} -+ -+#endif /* !GNUTLS_ZLIB_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/zlib.h b/lib/dlwrap/zlib.h -new file mode 100644 -index 0000000000..a9666d27f5 ---- /dev/null -+++ b/lib/dlwrap/zlib.h -@@ -0,0 +1,47 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifndef GNUTLS_LIB_DLWRAP_ZLIB_H_ -+#define GNUTLS_LIB_DLWRAP_ZLIB_H_ -+ -+#include -+ -+#if defined(GNUTLS_ZLIB_ENABLE_DLOPEN) && GNUTLS_ZLIB_ENABLE_DLOPEN -+ -+#define FUNC(ret, name, args, cargs) \ -+ ret gnutls_zlib_func_##name args; -+#define VOID_FUNC FUNC -+#include "zlibfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#define GNUTLS_ZLIB_FUNC(name) gnutls_zlib_func_##name -+ -+#else -+ -+#define GNUTLS_ZLIB_FUNC(name) name -+ -+#endif /* GNUTLS_ZLIB_ENABLE_DLOPEN */ -+ -+/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary -+ * symbols are resolved. -+ * -+ * Returns 0 on success; negative error code otherwise. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+int gnutls_zlib_ensure_library (const char *soname, int flags); -+ -+/* Unload library and reset symbols. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+void gnutls_zlib_unload_library (void); -+ -+#endif /* GNUTLS_LIB_DLWRAP_ZLIB_H_ */ -diff --git a/lib/dlwrap/zlibfuncs.h b/lib/dlwrap/zlibfuncs.h -new file mode 100644 -index 0000000000..efe01455d2 ---- /dev/null -+++ b/lib/dlwrap/zlibfuncs.h -@@ -0,0 +1,27 @@ -+/* -+ * This file was automatically generated from zlib.h, -+ * which is covered by the following license: -+ * Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler -+ * -+ * This software is provided 'as-is', without any express or implied -+ * warranty. In no event will the authors be held liable for any damages -+ * arising from the use of this software. -+ * -+ * Permission is granted to anyone to use this software for any purpose, -+ * including commercial applications, and to alter it and redistribute it -+ * freely, subject to the following restrictions: -+ * -+ * 1. The origin of this software must not be misrepresented; you must not -+ * claim that you wrote the original software. If you use this software -+ * in a product, an acknowledgment in the product documentation would be -+ * appreciated but is not required. -+ * 2. Altered source versions must be plainly marked as such, and must not be -+ * misrepresented as being the original software. -+ * 3. This notice may not be removed or altered from any source distribution. -+ * -+ * Jean-loup Gailly Mark Adler -+ * jloup@gzip.org madler@alumni.caltech.edu -+ */ -+FUNC(int, compress, (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen), (dest, destLen, source, sourceLen)) -+FUNC(uLong, compressBound, (uLong sourceLen), (sourceLen)) -+FUNC(int, uncompress, (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen), (dest, destLen, source, sourceLen)) -diff --git a/lib/dlwrap/zstd.c b/lib/dlwrap/zstd.c -new file mode 100644 -index 0000000000..2ea7252975 ---- /dev/null -+++ b/lib/dlwrap/zstd.c -@@ -0,0 +1,182 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "zstd.h" -+ -+#if defined(GNUTLS_ZSTD_ENABLE_DLOPEN) && GNUTLS_ZSTD_ENABLE_DLOPEN -+ -+#include -+#include -+#include -+#include -+ -+/* If ZSTD_LIBRARY_SONAME is defined, dlopen handle can be automatically -+ * set; otherwise, the caller needs to call -+ * gnutls_zstd_ensure_library with soname determined at run time. -+ */ -+#ifdef ZSTD_LIBRARY_SONAME -+ -+static void -+ensure_library (void) -+{ -+ if (gnutls_zstd_ensure_library (ZSTD_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ abort (); -+} -+ -+#if defined(GNUTLS_ZSTD_ENABLE_PTHREAD) && GNUTLS_ZSTD_ENABLE_PTHREAD -+#include -+ -+static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; -+ -+#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library) -+ -+#else /* GNUTLS_ZSTD_ENABLE_PTHREAD */ -+ -+#define ENSURE_LIBRARY do { \ -+ if (!gnutls_zstd_dlhandle) \ -+ ensure_library(); \ -+ } while (0) -+ -+#endif /* !GNUTLS_ZSTD_ENABLE_PTHREAD */ -+ -+#else /* ZSTD_LIBRARY_SONAME */ -+ -+#define ENSURE_LIBRARY do {} while (0) -+ -+#endif /* !ZSTD_LIBRARY_SONAME */ -+ -+static void *gnutls_zstd_dlhandle; -+ -+/* Define redirection symbols */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#if (2 <= __GNUC__ || (4 <= __clang_major__)) -+#define FUNC(ret, name, args, cargs) \ -+ static __typeof__(name)(*gnutls_zstd_sym_##name); -+#else -+#define FUNC(ret, name, args, cargs) \ -+ static ret(*gnutls_zstd_sym_##name)args; -+#endif -+#define VOID_FUNC FUNC -+#include "zstdfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+/* Define redirection wrapper functions */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ret gnutls_zstd_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_zstd_sym_##name); \ -+ return gnutls_zstd_sym_##name cargs; \ -+} -+#define VOID_FUNC(ret, name, args, cargs) \ -+ret gnutls_zstd_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_zstd_sym_##name); \ -+ gnutls_zstd_sym_##name cargs; \ -+} -+#include "zstdfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+static int -+ensure_symbol (const char *name, void **symp) -+{ -+ if (!*symp) -+ { -+ void *sym = dlsym (gnutls_zstd_dlhandle, name); -+ if (!sym) -+ return -errno; -+ *symp = sym; -+ } -+ return 0; -+} -+ -+int -+gnutls_zstd_ensure_library (const char *soname, int flags) -+{ -+ int err; -+ -+ if (!gnutls_zstd_dlhandle) -+ { -+ gnutls_zstd_dlhandle = dlopen (soname, flags); -+ if (!gnutls_zstd_dlhandle) -+ return -errno; -+ } -+ -+#define ENSURE_SYMBOL(name) \ -+ ensure_symbol(#name, (void **)&gnutls_zstd_sym_##name) -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ return err; -+#define VOID_FUNC FUNC -+#include "zstdfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef ENSURE_SYMBOL -+ return 0; -+} -+ -+void -+gnutls_zstd_unload_library (void) -+{ -+ if (gnutls_zstd_dlhandle) -+ dlclose (gnutls_zstd_dlhandle); -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ gnutls_zstd_sym_##name = NULL; -+#define VOID_FUNC FUNC -+#include "zstdfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef RESET_SYMBOL -+} -+ -+#else /* GNUTLS_ZSTD_ENABLE_DLOPEN */ -+ -+int -+gnutls_zstd_ensure_library (const char *soname, int flags) -+{ -+ (void) soname; -+ (void) flags; -+ return 0; -+} -+ -+void -+gnutls_zstd_unload_library (void) -+{ -+} -+ -+#endif /* !GNUTLS_ZSTD_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/zstd.h b/lib/dlwrap/zstd.h -new file mode 100644 -index 0000000000..80ac2fbd46 ---- /dev/null -+++ b/lib/dlwrap/zstd.h -@@ -0,0 +1,47 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifndef GNUTLS_LIB_DLWRAP_ZSTD_H_ -+#define GNUTLS_LIB_DLWRAP_ZSTD_H_ -+ -+#include -+ -+#if defined(GNUTLS_ZSTD_ENABLE_DLOPEN) && GNUTLS_ZSTD_ENABLE_DLOPEN -+ -+#define FUNC(ret, name, args, cargs) \ -+ ret gnutls_zstd_func_##name args; -+#define VOID_FUNC FUNC -+#include "zstdfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#define GNUTLS_ZSTD_FUNC(name) gnutls_zstd_func_##name -+ -+#else -+ -+#define GNUTLS_ZSTD_FUNC(name) name -+ -+#endif /* GNUTLS_ZSTD_ENABLE_DLOPEN */ -+ -+/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary -+ * symbols are resolved. -+ * -+ * Returns 0 on success; negative error code otherwise. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+int gnutls_zstd_ensure_library (const char *soname, int flags); -+ -+/* Unload library and reset symbols. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+void gnutls_zstd_unload_library (void); -+ -+#endif /* GNUTLS_LIB_DLWRAP_ZSTD_H_ */ -diff --git a/lib/dlwrap/zstdfuncs.h b/lib/dlwrap/zstdfuncs.h -new file mode 100644 -index 0000000000..8e3eb9ff59 ---- /dev/null -+++ b/lib/dlwrap/zstdfuncs.h -@@ -0,0 +1,15 @@ -+/* -+ * This file was automatically generated from zstd.h, -+ * which is covered by the following license: -+ * Copyright (c) Meta Platforms, Inc. and affiliates. -+ * All rights reserved. -+ * -+ * This source code is licensed under both the BSD-style license (found in the -+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found -+ * in the COPYING file in the root directory of this source tree). -+ * You may select, at your option, one of the above-listed licenses. -+ */ -+FUNC(size_t, ZSTD_compress, (void *dst, size_t dstCapacity, const void *src, size_t srcSize, int compressionLevel), (dst, dstCapacity, src, srcSize, compressionLevel)) -+FUNC(size_t, ZSTD_decompress, (void *dst, size_t dstCapacity, const void *src, size_t compressedSize), (dst, dstCapacity, src, compressedSize)) -+FUNC(size_t, ZSTD_compressBound, (size_t srcSize), (srcSize)) -+FUNC(unsigned int, ZSTD_isError, (size_t code), (code)) --- -2.45.2 - diff --git a/gnutls-3.8.6-liboqs-x25519-kyber768d00.patch b/gnutls-3.8.6-liboqs-x25519-kyber768d00.patch deleted file mode 100644 index d807f76..0000000 --- a/gnutls-3.8.6-liboqs-x25519-kyber768d00.patch +++ /dev/null @@ -1,3246 +0,0 @@ -From 39dad633e6acb18c3853b7cb182324ccd250ba46 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Fri, 31 May 2024 09:18:27 +0900 -Subject: [PATCH 1/2] build: plumb liboqs as an optional dependency - -This exposes OQS functions necessary to implement Kyber768 through -dlopen with stub implementation for lower-level cryptographic -primitives, such as SHA3 and DRBG. - -Signed-off-by: Daiki Ueno ---- - .gitignore | 1 + - cfg.mk | 2 +- - configure.ac | 37 ++++ - devel/dlwrap/oqs.syms | 9 + - devel/generate-dlwrap.sh | 3 + - devel/indent-gnutls | 2 +- - lib/Makefile.am | 14 ++ - lib/dlwrap/oqs.c | 182 ++++++++++++++++ - lib/dlwrap/oqs.h | 53 +++++ - lib/dlwrap/oqsfuncs.h | 14 ++ - lib/global.c | 8 + - lib/liboqs/Makefile.am | 43 ++++ - lib/liboqs/backport/sha3_ops.h | 256 ++++++++++++++++++++++ - lib/liboqs/liboqs.c | 41 ++++ - lib/liboqs/liboqs.h | 27 +++ - lib/liboqs/rand.c | 43 ++++ - lib/liboqs/rand.h | 27 +++ - lib/liboqs/sha3.c | 373 +++++++++++++++++++++++++++++++++ - lib/liboqs/sha3.h | 27 +++ - 19 files changed, 1160 insertions(+), 2 deletions(-) - create mode 100644 devel/dlwrap/oqs.syms - create mode 100644 lib/dlwrap/oqs.c - create mode 100644 lib/dlwrap/oqs.h - create mode 100644 lib/dlwrap/oqsfuncs.h - create mode 100644 lib/liboqs/Makefile.am - create mode 100644 lib/liboqs/backport/sha3_ops.h - create mode 100644 lib/liboqs/liboqs.c - create mode 100644 lib/liboqs/liboqs.h - create mode 100644 lib/liboqs/rand.c - create mode 100644 lib/liboqs/rand.h - create mode 100644 lib/liboqs/sha3.c - create mode 100644 lib/liboqs/sha3.h - -diff --git a/cfg.mk b/cfg.mk -index 1b94279633..88f6df480d 100644 ---- a/cfg.mk -+++ b/cfg.mk -@@ -24,7 +24,7 @@ PACKAGE ?= gnutls - - .PHONY: config glimport - --INDENT_SOURCES = `find . -name \*.[ch] -o -name gnutls.h.in | grep -v -e ^./build-aux/ -e ^./config.h -e ^./devel/ -e ^./gnulib -e ^./lib/minitasn1/ -e ^./lib/includes/gnutls/gnutls.h -e ^./lib/nettle/backport/ -e ^./lib/priority_options.h -e ^./lib/unistring/ -e ^./lib/x509/supported_exts.h -e ^./lib/build-aux/ -e ^./lib/dlwrap/ -e ^./gl/ -e ^./src/gl/ -e ^./src/.*-options.[ch] -e -args.[ch] -e asn1_tab.c -e ^./tests/suite/` -+INDENT_SOURCES = `find . -name \*.[ch] -o -name gnutls.h.in | grep -v -e ^./build-aux/ -e ^./config.h -e ^./devel/ -e ^./gnulib -e ^./lib/minitasn1/ -e ^./lib/includes/gnutls/gnutls.h -e ^./lib/nettle/backport/ -e ^./lib/priority_options.h -e ^./lib/unistring/ -e ^./lib/x509/supported_exts.h -e ^./lib/build-aux/ -e ^./lib/dlwrap/ -e ^./lib/liboqs/backport/ -e ^./gl/ -e ^./src/gl/ -e ^./src/.*-options.[ch] -e -args.[ch] -e asn1_tab.c -e ^./tests/suite/` - - ifeq ($(.DEFAULT_GOAL),abort-due-to-no-makefile) - .DEFAULT_GOAL := bootstrap -diff --git a/configure.ac b/configure.ac -index fb0aefe1f4..145eada690 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1185,6 +1185,41 @@ AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ - CFLAGS="$save_CFLAGS" - ]) - -+AC_ARG_WITH(liboqs, -+ AS_HELP_STRING([--with-liboqs], -+ [Enable liboqs support.]), -+ [with_liboqs=$withval], [with_liboqs=no]) -+AS_IF([test "$with_liboqs" != "no"], [PKG_CHECK_MODULES(LIBOQS, [liboqs >= 0.10.1], [have_liboqs=yes], [have_liboqs=no])]) -+AS_IF([test "$have_liboqs" = "yes"], [AC_DEFINE([HAVE_LIBOQS], 1, [Have liboqs])], -+ [test "$with_liboqs" = "yes"], [AC_MSG_ERROR([[ -+*** -+*** liboqs support was requested but the required libraries were not found. -+*** ]])]) -+ -+save_CFLAGS=$CFLAGS -+CFLAGS="$CFLAGS $LIBOQS_CFLAGS" -+AC_CHECK_DECLS([OQS_SHA3_set_callbacks]) -+CFLAGS="$save_CFLAGS" -+ -+# liboqs 0.10.1 didn't expose OQS_SHA3_set_callbacks from the header -+# file, so extra treatment is needed: -+# https://github.com/open-quantum-safe/liboqs/pull/1832 -+AM_CONDITIONAL(NEED_LIBOQS_SHA3_OPS_H, test "$ac_cv_have_decl_OQS_SHA3_set_callbacks" != yes) -+ -+AM_CONDITIONAL(ENABLE_LIBOQS, test "$have_liboqs" = "yes") -+ -+AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ -+ save_CFLAGS=$CFLAGS -+ CFLAGS="$CFLAGS $LIBOQS_CFLAGS" -+ save_LIBS=$LIBS -+ LIBS="$LIBS $LIBOQS_LIBS" -+ LIBGNUTLS_CHECK_SONAME([oqs], [AC_LANG_PROGRAM([ -+ #include ],[ -+ OQS_version ();])]) -+ LIBS="$save_LIBS" -+ CFLAGS="$save_CFLAGS" -+]) -+ - AM_CONDITIONAL(NEED_LTLIBDL, test "$need_ltlibdl" = yes) - - # export for use in scripts -@@ -1382,6 +1417,7 @@ AC_CONFIG_FILES([ - lib/gnutls.pc - lib/includes/Makefile - lib/includes/gnutls/gnutls.h -+ lib/liboqs/Makefile - lib/minitasn1/Makefile - lib/nettle/Makefile - lib/x509/Makefile -@@ -1463,6 +1499,7 @@ if features are disabled) - Non-SuiteB curves: $enable_non_suiteb - FIPS140 mode: $enable_fips - Strict DER time: $ac_strict_der_time -+ liboqs: $have_liboqs - ]) - - AC_MSG_NOTICE([Optional libraries: -diff --git a/devel/dlwrap/oqs.syms b/devel/dlwrap/oqs.syms -new file mode 100644 -index 0000000000..8f067b2dd3 ---- /dev/null -+++ b/devel/dlwrap/oqs.syms -@@ -0,0 +1,9 @@ -+OQS_SHA3_set_callbacks -+OQS_init -+OQS_destroy -+OQS_KEM_new -+OQS_KEM_encaps -+OQS_KEM_decaps -+OQS_KEM_keypair -+OQS_KEM_free -+OQS_randombytes_custom_algorithm -\ No newline at end of file -diff --git a/devel/generate-dlwrap.sh b/devel/generate-dlwrap.sh -index dbcf870612..3e253d9228 100755 ---- a/devel/generate-dlwrap.sh -+++ b/devel/generate-dlwrap.sh -@@ -35,3 +35,6 @@ echo "Generating $DST/brotlidec.h" - - "$DLWRAP" --input /usr/include/brotli/decode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlidec.syms" --license-file "$SRC/brotli.license" --soname BROTLIDEC_LIBRARY_SONAME --prefix gnutls_brotlidec --loader-basename brotlidec --header-guard GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ --include "" - -+echo "Generating $DST/oqs.h" -+ -+"$DLWRAP" --input /usr/include/oqs/oqs.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/oqs.syms" --license "SPDX-License-Identifier: MIT" --soname OQS_LIBRARY_SONAME --prefix gnutls_oqs --header-guard GNUTLS_LIB_DLWRAP_OQS_H_ --include "" -diff --git a/lib/Makefile.am b/lib/Makefile.am -index d1bd07248e..067772c322 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -29,6 +29,10 @@ if ENABLE_MINITASN1 - SUBDIRS += minitasn1 - endif - -+if ENABLE_LIBOQS -+SUBDIRS += liboqs -+endif -+ - localedir = $(datadir)/locale - - include $(top_srcdir)/lib/common.mk -@@ -119,6 +123,16 @@ thirdparty_libadd += $(LIBBROTLIDEC_LIBS) - endif - endif - -+if ENABLE_LIBOQS -+COBJECTS += dlwrap/oqs.c dlwrap/oqsfuncs.h dlwrap/oqs.h -+ -+if ENABLE_DLOPEN -+AM_CPPFLAGS += $(LIBOQS_CFLAGS) -DGNUTLS_OQS_ENABLE_DLOPEN=1 -+else -+thirdparty_libadd += $(LIBOQS_LIBS) -+endif -+endif -+ - if ENABLE_GOST - COBJECTS += vko.c - endif -diff --git a/lib/dlwrap/oqs.c b/lib/dlwrap/oqs.c -new file mode 100644 -index 0000000000..d7fcc9c80c ---- /dev/null -+++ b/lib/dlwrap/oqs.c -@@ -0,0 +1,182 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "oqs.h" -+ -+#if defined(GNUTLS_OQS_ENABLE_DLOPEN) && GNUTLS_OQS_ENABLE_DLOPEN -+ -+#include -+#include -+#include -+#include -+ -+/* If OQS_LIBRARY_SONAME is defined, dlopen handle can be automatically -+ * set; otherwise, the caller needs to call -+ * gnutls_oqs_ensure_library with soname determined at run time. -+ */ -+#ifdef OQS_LIBRARY_SONAME -+ -+static void -+ensure_library (void) -+{ -+ if (gnutls_oqs_ensure_library (OQS_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ abort (); -+} -+ -+#if defined(GNUTLS_OQS_ENABLE_PTHREAD) && GNUTLS_OQS_ENABLE_PTHREAD -+#include -+ -+static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; -+ -+#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library) -+ -+#else /* GNUTLS_OQS_ENABLE_PTHREAD */ -+ -+#define ENSURE_LIBRARY do { \ -+ if (!gnutls_oqs_dlhandle) \ -+ ensure_library(); \ -+ } while (0) -+ -+#endif /* !GNUTLS_OQS_ENABLE_PTHREAD */ -+ -+#else /* OQS_LIBRARY_SONAME */ -+ -+#define ENSURE_LIBRARY do {} while (0) -+ -+#endif /* !OQS_LIBRARY_SONAME */ -+ -+static void *gnutls_oqs_dlhandle; -+ -+/* Define redirection symbols */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#if (2 <= __GNUC__ || (4 <= __clang_major__)) -+#define FUNC(ret, name, args, cargs) \ -+ static __typeof__(name)(*gnutls_oqs_sym_##name); -+#else -+#define FUNC(ret, name, args, cargs) \ -+ static ret(*gnutls_oqs_sym_##name)args; -+#endif -+#define VOID_FUNC FUNC -+#include "oqsfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+/* Define redirection wrapper functions */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ret gnutls_oqs_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_oqs_sym_##name); \ -+ return gnutls_oqs_sym_##name cargs; \ -+} -+#define VOID_FUNC(ret, name, args, cargs) \ -+ret gnutls_oqs_func_##name args \ -+{ \ -+ ENSURE_LIBRARY; \ -+ assert (gnutls_oqs_sym_##name); \ -+ gnutls_oqs_sym_##name cargs; \ -+} -+#include "oqsfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+static int -+ensure_symbol (const char *name, void **symp) -+{ -+ if (!*symp) -+ { -+ void *sym = dlsym (gnutls_oqs_dlhandle, name); -+ if (!sym) -+ return -errno; -+ *symp = sym; -+ } -+ return 0; -+} -+ -+int -+gnutls_oqs_ensure_library (const char *soname, int flags) -+{ -+ int err; -+ -+ if (!gnutls_oqs_dlhandle) -+ { -+ gnutls_oqs_dlhandle = dlopen (soname, flags); -+ if (!gnutls_oqs_dlhandle) -+ return -errno; -+ } -+ -+#define ENSURE_SYMBOL(name) \ -+ ensure_symbol(#name, (void **)&gnutls_oqs_sym_##name) -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ return err; -+#define VOID_FUNC FUNC -+#include "oqsfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef ENSURE_SYMBOL -+ return 0; -+} -+ -+void -+gnutls_oqs_unload_library (void) -+{ -+ if (gnutls_oqs_dlhandle) -+ dlclose (gnutls_oqs_dlhandle); -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-macros" -+ -+#define FUNC(ret, name, args, cargs) \ -+ gnutls_oqs_sym_##name = NULL; -+#define VOID_FUNC FUNC -+#include "oqsfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#pragma GCC diagnostic pop -+ -+#undef RESET_SYMBOL -+} -+ -+#else /* GNUTLS_OQS_ENABLE_DLOPEN */ -+ -+int -+gnutls_oqs_ensure_library (const char *soname, int flags) -+{ -+ (void) soname; -+ (void) flags; -+ return 0; -+} -+ -+void -+gnutls_oqs_unload_library (void) -+{ -+} -+ -+#endif /* !GNUTLS_OQS_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/oqs.h b/lib/dlwrap/oqs.h -new file mode 100644 -index 0000000000..6a1d8e0766 ---- /dev/null -+++ b/lib/dlwrap/oqs.h -@@ -0,0 +1,53 @@ -+/* -+ * Copying and distribution of this file, with or without modification, -+ * are permitted in any medium without royalty provided the copyright -+ * notice and this notice are preserved. This file is offered as-is, -+ * without any warranty. -+ */ -+ -+#ifndef GNUTLS_LIB_DLWRAP_OQS_H_ -+#define GNUTLS_LIB_DLWRAP_OQS_H_ -+ -+/* Local modification: remove this once liboqs 0.10.2 is released */ -+#include "config.h" -+#if !HAVE_DECL_OQS_SHA3_SET_CALLBACKS -+#include "liboqs/backport/sha3_ops.h" -+#endif -+ -+#include -+ -+#if defined(GNUTLS_OQS_ENABLE_DLOPEN) && GNUTLS_OQS_ENABLE_DLOPEN -+ -+#define FUNC(ret, name, args, cargs) \ -+ ret gnutls_oqs_func_##name args; -+#define VOID_FUNC FUNC -+#include "oqsfuncs.h" -+#undef VOID_FUNC -+#undef FUNC -+ -+#define GNUTLS_OQS_FUNC(name) gnutls_oqs_func_##name -+ -+#else -+ -+#define GNUTLS_OQS_FUNC(name) name -+ -+#endif /* GNUTLS_OQS_ENABLE_DLOPEN */ -+ -+/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary -+ * symbols are resolved. -+ * -+ * Returns 0 on success; negative error code otherwise. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+int gnutls_oqs_ensure_library (const char *soname, int flags); -+ -+/* Unload library and reset symbols. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+void gnutls_oqs_unload_library (void); -+ -+#endif /* GNUTLS_LIB_DLWRAP_OQS_H_ */ -diff --git a/lib/dlwrap/oqsfuncs.h b/lib/dlwrap/oqsfuncs.h -new file mode 100644 -index 0000000000..95c1b083dc ---- /dev/null -+++ b/lib/dlwrap/oqsfuncs.h -@@ -0,0 +1,14 @@ -+/* -+ * This file was automatically generated from oqs.h, -+ * which is covered by the following license: -+ * SPDX-License-Identifier: MIT -+ */ -+VOID_FUNC(void, OQS_init, (void), ()) -+VOID_FUNC(void, OQS_destroy, (void), ()) -+VOID_FUNC(void, OQS_SHA3_set_callbacks, (struct OQS_SHA3_callbacks *new_callbacks), (new_callbacks)) -+VOID_FUNC(void, OQS_randombytes_custom_algorithm, (void (*algorithm_ptr)(uint8_t *, size_t)), (algorithm_ptr)) -+FUNC(OQS_KEM *, OQS_KEM_new, (const char *method_name), (method_name)) -+FUNC(OQS_STATUS, OQS_KEM_keypair, (const OQS_KEM *kem, uint8_t *public_key, uint8_t *secret_key), (kem, public_key, secret_key)) -+FUNC(OQS_STATUS, OQS_KEM_encaps, (const OQS_KEM *kem, uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key), (kem, ciphertext, shared_secret, public_key)) -+FUNC(OQS_STATUS, OQS_KEM_decaps, (const OQS_KEM *kem, uint8_t *shared_secret, const uint8_t *ciphertext, const uint8_t *secret_key), (kem, shared_secret, ciphertext, secret_key)) -+VOID_FUNC(void, OQS_KEM_free, (OQS_KEM *kem), (kem)) -diff --git a/lib/global.c b/lib/global.c -index b434140bbf..ae2f7f54dc 100644 ---- a/lib/global.c -+++ b/lib/global.c -@@ -41,6 +41,7 @@ - #include "system-keys.h" - #include "str.h" - #include "global.h" -+#include "liboqs/liboqs.h" - - /* Minimum library versions we accept. */ - #define GNUTLS_MIN_LIBTASN1_VERSION "0.3.4" -@@ -328,6 +329,10 @@ static int _gnutls_global_init(unsigned constructor) - goto out; - } - -+#ifdef HAVE_LIBOQS -+ _gnutls_liboqs_init(); -+#endif -+ - #ifndef _WIN32 - ret = _gnutls_register_fork_handler(); - if (ret < 0) { -@@ -444,6 +449,9 @@ static void _gnutls_global_deinit(unsigned destructor) - #ifdef HAVE_TPM2 - _gnutls_tpm2_deinit(); - #endif -+#ifdef HAVE_LIBOQS -+ _gnutls_liboqs_deinit(); -+#endif - - _gnutls_nss_keylog_deinit(); - } else { -diff --git a/lib/liboqs/Makefile.am b/lib/liboqs/Makefile.am -new file mode 100644 -index 0000000000..a20e7cbdf9 ---- /dev/null -+++ b/lib/liboqs/Makefile.am -@@ -0,0 +1,43 @@ -+## Process this file with automake to produce Makefile.in -+# Copyright (C) 2004-2012 Free Software Foundation, Inc. -+# Copyright (C) 2024 Red Hat, Inc. -+# -+# Author: Daiki Ueno -+# -+# This file is part of GNUTLS. -+# -+# The GNUTLS library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public License -+# as published by the Free Software Foundation; either version 3 of -+# the License, or (at your option) any later version. -+# -+# The GNUTLS library 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 -+# Lesser 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 -+ -+include $(top_srcdir)/lib/common.mk -+ -+AM_CFLAGS += $(LIBOQS_CFLAGS) -+ -+AM_CPPFLAGS = \ -+ -I$(srcdir)/../../gl \ -+ -I$(builddir)/../../gl \ -+ -I$(srcdir)/../includes \ -+ -I$(builddir)/../includes \ -+ -I$(srcdir)/.. -+ -+if ENABLE_DLOPEN -+AM_CPPFLAGS += $(LIBOQS_CFLAGS) -DGNUTLS_OQS_ENABLE_DLOPEN=1 -+endif -+ -+noinst_LTLIBRARIES = libcrypto.la -+ -+libcrypto_la_SOURCES = liboqs.h liboqs.c rand.h rand.c sha3.h sha3.c -+ -+if NEED_LIBOQS_SHA3_OPS_H -+libcrypto_la_SOURCES += backport/sha3_ops.h -+endif -diff --git a/lib/liboqs/backport/sha3_ops.h b/lib/liboqs/backport/sha3_ops.h -new file mode 100644 -index 0000000000..694fc21873 ---- /dev/null -+++ b/lib/liboqs/backport/sha3_ops.h -@@ -0,0 +1,256 @@ -+/** -+ * \file sha3_ops.h -+ * \brief Header defining the callback API for OQS SHA3 and SHAKE -+ * -+ * \author John Underhill, Douglas Stebila -+ * -+ * SPDX-License-Identifier: MIT -+ */ -+ -+#ifndef OQS_SHA3_OPS_H -+#define OQS_SHA3_OPS_H -+ -+#include -+#include -+ -+#include -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+/** Data structure for the state of the incremental SHA3-256 API. */ -+typedef struct { -+ /** Internal state. */ -+ void *ctx; -+} OQS_SHA3_sha3_256_inc_ctx; -+ -+/** Data structure for the state of the incremental SHA3-384 API. */ -+typedef struct { -+ /** Internal state. */ -+ void *ctx; -+} OQS_SHA3_sha3_384_inc_ctx; -+ -+/** Data structure for the state of the incremental SHA3-512 API. */ -+typedef struct { -+ /** Internal state. */ -+ void *ctx; -+} OQS_SHA3_sha3_512_inc_ctx; -+ -+/** Data structure for the state of the incremental SHAKE-128 API. */ -+typedef struct { -+ /** Internal state. */ -+ void *ctx; -+} OQS_SHA3_shake128_inc_ctx; -+ -+/** Data structure for the state of the incremental SHAKE-256 API. */ -+typedef struct { -+ /** Internal state. */ -+ void *ctx; -+} OQS_SHA3_shake256_inc_ctx; -+ -+/** Data structure implemented by cryptographic provider for SHA-3 operations. -+ */ -+struct OQS_SHA3_callbacks { -+ /** -+ * Implementation of function OQS_SHA3_sha3_256. -+ */ -+ void (*SHA3_sha3_256)(uint8_t *output, const uint8_t *input, size_t inplen); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_256_inc_init. -+ */ -+ void (*SHA3_sha3_256_inc_init)(OQS_SHA3_sha3_256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_256_inc_absorb. -+ */ -+ void (*SHA3_sha3_256_inc_absorb)(OQS_SHA3_sha3_256_inc_ctx *state, const uint8_t *input, size_t inlen); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_256_inc_finalize. -+ */ -+ void (*SHA3_sha3_256_inc_finalize)(uint8_t *output, OQS_SHA3_sha3_256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_256_inc_ctx_release. -+ */ -+ void (*SHA3_sha3_256_inc_ctx_release)(OQS_SHA3_sha3_256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_256_inc_ctx_reset. -+ */ -+ void (*SHA3_sha3_256_inc_ctx_reset)(OQS_SHA3_sha3_256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_256_inc_ctx_clone. -+ */ -+ void (*SHA3_sha3_256_inc_ctx_clone)(OQS_SHA3_sha3_256_inc_ctx *dest, const OQS_SHA3_sha3_256_inc_ctx *src); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_384. -+ */ -+ void (*SHA3_sha3_384)(uint8_t *output, const uint8_t *input, size_t inplen); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_384_inc_init. -+ */ -+ void (*SHA3_sha3_384_inc_init)(OQS_SHA3_sha3_384_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_384_inc_absorb. -+ */ -+ void (*SHA3_sha3_384_inc_absorb)(OQS_SHA3_sha3_384_inc_ctx *state, const uint8_t *input, size_t inlen); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_384_inc_finalize. -+ */ -+ void (*SHA3_sha3_384_inc_finalize)(uint8_t *output, OQS_SHA3_sha3_384_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_384_inc_ctx_release. -+ */ -+ void (*SHA3_sha3_384_inc_ctx_release)(OQS_SHA3_sha3_384_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_384_inc_ctx_reset. -+ */ -+ void (*SHA3_sha3_384_inc_ctx_reset)(OQS_SHA3_sha3_384_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_384_inc_ctx_clone. -+ */ -+ void (*SHA3_sha3_384_inc_ctx_clone)(OQS_SHA3_sha3_384_inc_ctx *dest, const OQS_SHA3_sha3_384_inc_ctx *src); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_512. -+ */ -+ void (*SHA3_sha3_512)(uint8_t *output, const uint8_t *input, size_t inplen); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_512_inc_init. -+ */ -+ void (*SHA3_sha3_512_inc_init)(OQS_SHA3_sha3_512_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_512_inc_absorb. -+ */ -+ void (*SHA3_sha3_512_inc_absorb)(OQS_SHA3_sha3_512_inc_ctx *state, const uint8_t *input, size_t inlen); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_512_inc_finalize. -+ */ -+ void (*SHA3_sha3_512_inc_finalize)(uint8_t *output, OQS_SHA3_sha3_512_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_512_inc_ctx_release. -+ */ -+ void (*SHA3_sha3_512_inc_ctx_release)(OQS_SHA3_sha3_512_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_512_inc_ctx_reset. -+ */ -+ void (*SHA3_sha3_512_inc_ctx_reset)(OQS_SHA3_sha3_512_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_sha3_512_inc_ctx_clone. -+ */ -+ void (*SHA3_sha3_512_inc_ctx_clone)(OQS_SHA3_sha3_512_inc_ctx *dest, const OQS_SHA3_sha3_512_inc_ctx *src); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128. -+ */ -+ void (*SHA3_shake128)(uint8_t *output, size_t outlen, const uint8_t *input, size_t inplen); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128_inc_init. -+ */ -+ void (*SHA3_shake128_inc_init)(OQS_SHA3_shake128_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128_inc_absorb. -+ */ -+ void (*SHA3_shake128_inc_absorb)(OQS_SHA3_shake128_inc_ctx *state, const uint8_t *input, size_t inlen); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128_inc_finalize. -+ */ -+ void (*SHA3_shake128_inc_finalize)(OQS_SHA3_shake128_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128_inc_squeeze. -+ */ -+ void (*SHA3_shake128_inc_squeeze)(uint8_t *output, size_t outlen, OQS_SHA3_shake128_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128_inc_ctx_release. -+ */ -+ void (*SHA3_shake128_inc_ctx_release)(OQS_SHA3_shake128_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128_inc_ctx_clone. -+ */ -+ void (*SHA3_shake128_inc_ctx_clone)(OQS_SHA3_shake128_inc_ctx *dest, const OQS_SHA3_shake128_inc_ctx *src); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake128_inc_ctx_reset. -+ */ -+ void (*SHA3_shake128_inc_ctx_reset)(OQS_SHA3_shake128_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256. -+ */ -+ void (*SHA3_shake256)(uint8_t *output, size_t outlen, const uint8_t *input, size_t inplen); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256_inc_init. -+ */ -+ void (*SHA3_shake256_inc_init)(OQS_SHA3_shake256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256_inc_absorb. -+ */ -+ void (*SHA3_shake256_inc_absorb)(OQS_SHA3_shake256_inc_ctx *state, const uint8_t *input, size_t inlen); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256_inc_finalize. -+ */ -+ void (*SHA3_shake256_inc_finalize)(OQS_SHA3_shake256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256_inc_squeeze. -+ */ -+ void (*SHA3_shake256_inc_squeeze)(uint8_t *output, size_t outlen, OQS_SHA3_shake256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256_inc_ctx_release. -+ */ -+ void (*SHA3_shake256_inc_ctx_release)(OQS_SHA3_shake256_inc_ctx *state); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256_inc_ctx_clone. -+ */ -+ void (*SHA3_shake256_inc_ctx_clone)(OQS_SHA3_shake256_inc_ctx *dest, const OQS_SHA3_shake256_inc_ctx *src); -+ -+ /** -+ * Implementation of function OQS_SHA3_shake256_inc_ctx_reset. -+ */ -+ void (*SHA3_shake256_inc_ctx_reset)(OQS_SHA3_shake256_inc_ctx *state); -+}; -+ -+/** -+ * Set callback functions for SHA3 operations. -+ * -+ * This function may be called before OQS_init to switch the -+ * cryptographic provider for SHA3 operations. If it is not called, -+ * the default provider determined at build time will be used. -+ * -+ * @param new_callbacks Callback functions defined in OQS_SHA3_callbacks struct -+ */ -+OQS_API void OQS_SHA3_set_callbacks(struct OQS_SHA3_callbacks *new_callbacks); -+ -+#if defined(__cplusplus) -+} // extern "C" -+#endif -+ -+#endif // OQS_SHA3_OPS_H -diff --git a/lib/liboqs/liboqs.c b/lib/liboqs/liboqs.c -new file mode 100644 -index 0000000000..88f2369719 ---- /dev/null -+++ b/lib/liboqs/liboqs.c -@@ -0,0 +1,41 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. -+ * -+ * This file is part of GNUTLS. -+ * -+ * The GNUTLS library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public License -+ * as published by the Free Software Foundation; either version 2.1 of -+ * the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser 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 -+ * -+ */ -+ -+#include "config.h" -+ -+#include "liboqs/liboqs.h" -+ -+#include "dlwrap/oqs.h" -+#include "liboqs/rand.h" -+#include "liboqs/sha3.h" -+ -+void _gnutls_liboqs_init(void) -+{ -+ _gnutls_liboqs_sha3_init(); -+ GNUTLS_OQS_FUNC(OQS_init)(); -+ _gnutls_liboqs_rand_init(); -+} -+ -+void _gnutls_liboqs_deinit(void) -+{ -+ _gnutls_liboqs_rand_deinit(); -+ _gnutls_liboqs_sha3_deinit(); -+ GNUTLS_OQS_FUNC(OQS_destroy)(); -+} -diff --git a/lib/liboqs/liboqs.h b/lib/liboqs/liboqs.h -new file mode 100644 -index 0000000000..b6c1659212 ---- /dev/null -+++ b/lib/liboqs/liboqs.h -@@ -0,0 +1,27 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. -+ * -+ * This file is part of GNUTLS. -+ * -+ * The GNUTLS library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public License -+ * as published by the Free Software Foundation; either version 2.1 of -+ * the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser 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 -+ * -+ */ -+ -+#ifndef GNUTLS_LIB_LIBOQS_LIBOQS_H -+#define GNUTLS_LIB_LIBOQS_LIBOQS_H -+ -+void _gnutls_liboqs_init(void); -+void _gnutls_liboqs_deinit(void); -+ -+#endif /* GNUTLS_LIB_LIBOQS_LIBOQS_H */ -diff --git a/lib/liboqs/rand.c b/lib/liboqs/rand.c -new file mode 100644 -index 0000000000..40496800ad ---- /dev/null -+++ b/lib/liboqs/rand.c -@@ -0,0 +1,43 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. -+ * -+ * This file is part of GNUTLS. -+ * -+ * The GNUTLS library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public License -+ * as published by the Free Software Foundation; either version 2.1 of -+ * the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser 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 -+ * -+ */ -+ -+#include "config.h" -+ -+#include "liboqs/rand.h" -+ -+#include "dlwrap/oqs.h" -+#include "fips.h" -+#include -+#include -+ -+static void rand_bytes(uint8_t *data, size_t size) -+{ -+ if (gnutls_rnd(GNUTLS_RND_RANDOM, data, size) < 0) -+ _gnutls_switch_lib_state(LIB_STATE_ERROR); -+} -+ -+void _gnutls_liboqs_rand_init(void) -+{ -+ GNUTLS_OQS_FUNC(OQS_randombytes_custom_algorithm)(rand_bytes); -+} -+ -+void _gnutls_liboqs_rand_deinit(void) -+{ -+} -diff --git a/lib/liboqs/rand.h b/lib/liboqs/rand.h -new file mode 100644 -index 0000000000..b27ac23362 ---- /dev/null -+++ b/lib/liboqs/rand.h -@@ -0,0 +1,27 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. -+ * -+ * This file is part of GNUTLS. -+ * -+ * The GNUTLS library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public License -+ * as published by the Free Software Foundation; either version 2.1 of -+ * the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser 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 -+ * -+ */ -+ -+#ifndef GNUTLS_LIB_LIBOQS_RAND_H -+#define GNUTLS_LIB_LIBOQS_RAND_H -+ -+void _gnutls_liboqs_rand_init(void); -+void _gnutls_liboqs_rand_deinit(void); -+ -+#endif /* GNUTLS_LIB_LIBOQS_RAND_H */ -diff --git a/lib/liboqs/sha3.c b/lib/liboqs/sha3.c -new file mode 100644 -index 0000000000..9f5977e425 ---- /dev/null -+++ b/lib/liboqs/sha3.c -@@ -0,0 +1,373 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. -+ * -+ * This file is part of GNUTLS. -+ * -+ * The GNUTLS library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public License -+ * as published by the Free Software Foundation; either version 2.1 of -+ * the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser 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 -+ * -+ */ -+ -+#include "config.h" -+ -+#include "liboqs/sha3.h" -+ -+#include "dlwrap/oqs.h" -+#include -+#include -+#include -+ -+/* SHA3-256 */ -+ -+static void SHA3_sha3_256(uint8_t *output, const uint8_t *input, size_t inplen) -+{ -+ gnutls_hash_fast(GNUTLS_DIG_SHA3_256, input, inplen, output); -+} -+ -+/* SHA3-256 incremental */ -+ -+static void SHA3_sha3_256_inc_init(OQS_SHA3_sha3_256_inc_ctx *state) -+{ -+ gnutls_hash_hd_t hd; -+ int ret; -+ -+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHA3_256); -+ assert(ret == 0); -+ state->ctx = hd; -+} -+ -+static void SHA3_sha3_256_inc_absorb(OQS_SHA3_sha3_256_inc_ctx *state, -+ const uint8_t *input, size_t inplen) -+{ -+ int ret; -+ -+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen); -+ assert(ret == 0); -+} -+ -+static void SHA3_sha3_256_inc_finalize(uint8_t *output, -+ OQS_SHA3_sha3_256_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, output); -+} -+ -+static void SHA3_sha3_256_inc_ctx_release(OQS_SHA3_sha3_256_inc_ctx *state) -+{ -+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+static void SHA3_sha3_256_inc_ctx_clone(OQS_SHA3_sha3_256_inc_ctx *dest, -+ const OQS_SHA3_sha3_256_inc_ctx *src) -+{ -+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx); -+} -+ -+static void SHA3_sha3_256_inc_ctx_reset(OQS_SHA3_sha3_256_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+/* SHA3-384 */ -+ -+static void SHA3_sha3_384(uint8_t *output, const uint8_t *input, size_t inplen) -+{ -+ gnutls_hash_fast(GNUTLS_DIG_SHA3_384, input, inplen, output); -+} -+ -+/* SHA3-384 incremental */ -+static void SHA3_sha3_384_inc_init(OQS_SHA3_sha3_384_inc_ctx *state) -+{ -+ gnutls_hash_hd_t hd; -+ int ret; -+ -+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHA3_384); -+ assert(ret == 0); -+ state->ctx = hd; -+} -+ -+static void SHA3_sha3_384_inc_absorb(OQS_SHA3_sha3_384_inc_ctx *state, -+ const uint8_t *input, size_t inplen) -+{ -+ int ret; -+ -+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen); -+ assert(ret == 0); -+} -+ -+static void SHA3_sha3_384_inc_finalize(uint8_t *output, -+ OQS_SHA3_sha3_384_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, output); -+} -+ -+static void SHA3_sha3_384_inc_ctx_release(OQS_SHA3_sha3_384_inc_ctx *state) -+{ -+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+static void SHA3_sha3_384_inc_ctx_clone(OQS_SHA3_sha3_384_inc_ctx *dest, -+ const OQS_SHA3_sha3_384_inc_ctx *src) -+{ -+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx); -+} -+ -+static void SHA3_sha3_384_inc_ctx_reset(OQS_SHA3_sha3_384_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+/* SHA3-512 */ -+ -+static void SHA3_sha3_512(uint8_t *output, const uint8_t *input, size_t inplen) -+{ -+ gnutls_hash_fast(GNUTLS_DIG_SHA3_512, input, inplen, output); -+} -+ -+/* SHA3-512 incremental */ -+ -+static void SHA3_sha3_512_inc_init(OQS_SHA3_sha3_512_inc_ctx *state) -+{ -+ gnutls_hash_hd_t hd; -+ int ret; -+ -+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHA3_512); -+ assert(ret == 0); -+ state->ctx = hd; -+} -+ -+static void SHA3_sha3_512_inc_absorb(OQS_SHA3_sha3_512_inc_ctx *state, -+ const uint8_t *input, size_t inplen) -+{ -+ int ret; -+ -+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen); -+ assert(ret == 0); -+} -+ -+static void SHA3_sha3_512_inc_finalize(uint8_t *output, -+ OQS_SHA3_sha3_512_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, output); -+} -+ -+static void SHA3_sha3_512_inc_ctx_release(OQS_SHA3_sha3_512_inc_ctx *state) -+{ -+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+static void SHA3_sha3_512_inc_ctx_clone(OQS_SHA3_sha3_512_inc_ctx *dest, -+ const OQS_SHA3_sha3_512_inc_ctx *src) -+{ -+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx); -+} -+ -+static void SHA3_sha3_512_inc_ctx_reset(OQS_SHA3_sha3_512_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+/* SHAKE-128 */ -+ -+static void SHA3_shake128(uint8_t *output, size_t outlen, const uint8_t *input, -+ size_t inplen) -+{ -+ gnutls_hash_hd_t hd; -+ int ret; -+ -+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_128); -+ assert(ret == 0); -+ -+ ret = gnutls_hash(hd, input, inplen); -+ assert(ret == 0); -+ -+ ret = gnutls_hash_squeeze(hd, output, outlen); -+ assert(ret == 0); -+ -+ gnutls_hash_deinit(hd, NULL); -+} -+ -+/* SHAKE-128 incremental -+ */ -+ -+static void SHA3_shake128_inc_init(OQS_SHA3_shake128_inc_ctx *state) -+{ -+ gnutls_hash_hd_t hd; -+ int ret; -+ -+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_128); -+ assert(ret == 0); -+ -+ state->ctx = hd; -+} -+ -+static void SHA3_shake128_inc_absorb(OQS_SHA3_shake128_inc_ctx *state, -+ const uint8_t *input, size_t inplen) -+{ -+ int ret; -+ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL); -+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen); -+ assert(ret == 0); -+} -+ -+static void SHA3_shake128_inc_finalize(OQS_SHA3_shake128_inc_ctx *state) -+{ -+ (void)state; -+} -+ -+static void SHA3_shake128_inc_squeeze(uint8_t *output, size_t outlen, -+ OQS_SHA3_shake128_inc_ctx *state) -+{ -+ int ret; -+ -+ ret = gnutls_hash_squeeze((gnutls_hash_hd_t)state->ctx, output, outlen); -+ assert(ret == 0); -+} -+ -+static void SHA3_shake128_inc_ctx_release(OQS_SHA3_shake128_inc_ctx *state) -+{ -+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+static void SHA3_shake128_inc_ctx_clone(OQS_SHA3_shake128_inc_ctx *dest, -+ const OQS_SHA3_shake128_inc_ctx *src) -+{ -+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx); -+} -+ -+static void SHA3_shake128_inc_ctx_reset(OQS_SHA3_shake128_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+/* SHAKE-256 */ -+ -+static void SHA3_shake256(uint8_t *output, size_t outlen, const uint8_t *input, -+ size_t inplen) -+{ -+ gnutls_hash_hd_t hd; -+ int ret; -+ -+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_256); -+ assert(ret == 0); -+ -+ ret = gnutls_hash(hd, input, inplen); -+ assert(ret == 0); -+ -+ ret = gnutls_hash_squeeze(hd, output, outlen); -+ assert(ret == 0); -+ -+ gnutls_hash_deinit(hd, NULL); -+} -+ -+/* SHAKE-256 incremental */ -+ -+static void SHA3_shake256_inc_init(OQS_SHA3_shake256_inc_ctx *state) -+{ -+ gnutls_hash_hd_t hd; -+ int ret; -+ -+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_256); -+ assert(ret == 0); -+ -+ state->ctx = hd; -+} -+ -+static void SHA3_shake256_inc_absorb(OQS_SHA3_shake256_inc_ctx *state, -+ const uint8_t *input, size_t inplen) -+{ -+ int ret; -+ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL); -+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen); -+ assert(ret == 0); -+} -+ -+static void SHA3_shake256_inc_finalize(OQS_SHA3_shake256_inc_ctx *state) -+{ -+ (void)state; -+} -+ -+static void SHA3_shake256_inc_squeeze(uint8_t *output, size_t outlen, -+ OQS_SHA3_shake256_inc_ctx *state) -+{ -+ int ret; -+ -+ ret = gnutls_hash_squeeze((gnutls_hash_hd_t)state->ctx, output, outlen); -+ assert(ret == 0); -+} -+ -+static void SHA3_shake256_inc_ctx_release(OQS_SHA3_shake256_inc_ctx *state) -+{ -+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+static void SHA3_shake256_inc_ctx_clone(OQS_SHA3_shake256_inc_ctx *dest, -+ const OQS_SHA3_shake256_inc_ctx *src) -+{ -+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx); -+} -+ -+static void SHA3_shake256_inc_ctx_reset(OQS_SHA3_shake256_inc_ctx *state) -+{ -+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL); -+} -+ -+static struct OQS_SHA3_callbacks sha3_callbacks = { -+ SHA3_sha3_256, -+ SHA3_sha3_256_inc_init, -+ SHA3_sha3_256_inc_absorb, -+ SHA3_sha3_256_inc_finalize, -+ SHA3_sha3_256_inc_ctx_release, -+ SHA3_sha3_256_inc_ctx_reset, -+ SHA3_sha3_256_inc_ctx_clone, -+ SHA3_sha3_384, -+ SHA3_sha3_384_inc_init, -+ SHA3_sha3_384_inc_absorb, -+ SHA3_sha3_384_inc_finalize, -+ SHA3_sha3_384_inc_ctx_release, -+ SHA3_sha3_384_inc_ctx_reset, -+ SHA3_sha3_384_inc_ctx_clone, -+ SHA3_sha3_512, -+ SHA3_sha3_512_inc_init, -+ SHA3_sha3_512_inc_absorb, -+ SHA3_sha3_512_inc_finalize, -+ SHA3_sha3_512_inc_ctx_release, -+ SHA3_sha3_512_inc_ctx_reset, -+ SHA3_sha3_512_inc_ctx_clone, -+ SHA3_shake128, -+ SHA3_shake128_inc_init, -+ SHA3_shake128_inc_absorb, -+ SHA3_shake128_inc_finalize, -+ SHA3_shake128_inc_squeeze, -+ SHA3_shake128_inc_ctx_release, -+ SHA3_shake128_inc_ctx_clone, -+ SHA3_shake128_inc_ctx_reset, -+ SHA3_shake256, -+ SHA3_shake256_inc_init, -+ SHA3_shake256_inc_absorb, -+ SHA3_shake256_inc_finalize, -+ SHA3_shake256_inc_squeeze, -+ SHA3_shake256_inc_ctx_release, -+ SHA3_shake256_inc_ctx_clone, -+ SHA3_shake256_inc_ctx_reset, -+}; -+ -+void _gnutls_liboqs_sha3_init(void) -+{ -+ GNUTLS_OQS_FUNC(OQS_SHA3_set_callbacks)(&sha3_callbacks); -+} -+ -+void _gnutls_liboqs_sha3_deinit(void) -+{ -+} -diff --git a/lib/liboqs/sha3.h b/lib/liboqs/sha3.h -new file mode 100644 -index 0000000000..8b9058aa0d ---- /dev/null -+++ b/lib/liboqs/sha3.h -@@ -0,0 +1,27 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. -+ * -+ * This file is part of GNUTLS. -+ * -+ * The GNUTLS library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public License -+ * as published by the Free Software Foundation; either version 2.1 of -+ * the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser 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 -+ * -+ */ -+ -+#ifndef GNUTLS_LIB_LIBOQS_SHA3_H -+#define GNUTLS_LIB_LIBOQS_SHA3_H -+ -+void _gnutls_liboqs_sha3_init(void); -+void _gnutls_liboqs_sha3_deinit(void); -+ -+#endif /* GNUTLS_LIB_LIBOQS_SHA3_H */ --- -2.45.2 - - -From 1bc78c387a9796e8248ffb644576074f8de4e6ad Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sun, 2 Jun 2024 07:19:14 +0900 -Subject: [PATCH 2/2] key_share: support X25519Kyber768Draft00 - -This implements X25519Kyber768Draft00 hybrid post-quantum key exchange -in TLS 1.3, based on the draft: -https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/ - -Signed-off-by: Daiki Ueno ---- - lib/Makefile.am | 4 + - lib/algorithms/groups.c | 8 ++ - lib/algorithms/publickey.c | 6 ++ - lib/crypto-backend.h | 7 ++ - lib/ext/key_share.c | 148 ++++++++++++++++++++++++++-- - lib/gnutls_int.h | 2 + - lib/includes/gnutls/gnutls.h.in | 12 ++- - lib/nettle/Makefile.am | 4 + - lib/nettle/pk.c | 164 ++++++++++++++++++++++++++++++++ - lib/pk.h | 4 + - lib/state.c | 1 + - tests/Makefile.am | 4 + - tests/pqc-hybrid-kx.sh | 54 +++++++++++ - 13 files changed, 409 insertions(+), 9 deletions(-) - create mode 100644 tests/pqc-hybrid-kx.sh - -diff --git a/lib/Makefile.am b/lib/Makefile.am -index 067772c322..0e89fdf184 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -273,6 +273,10 @@ thirdparty_libadd += $(NETTLE_LIBS) $(HOGWEED_LIBS) $(GMP_LIBS) - libgnutls_la_LIBADD += nettle/libcrypto.la - endif - -+if ENABLE_LIBOQS -+libgnutls_la_LIBADD += liboqs/libcrypto.la -+endif -+ - if HAVE_LD_OUTPUT_DEF - libgnutls_la_LDFLAGS += -Wl,--output-def,libgnutls-$(DLL_VERSION).def - libgnutls-$(DLL_VERSION).def: libgnutls.la -diff --git a/lib/algorithms/groups.c b/lib/algorithms/groups.c -index 9093de6eb2..a329c746e9 100644 ---- a/lib/algorithms/groups.c -+++ b/lib/algorithms/groups.c -@@ -169,6 +169,14 @@ static const gnutls_group_entry_st supported_groups[] = { - .q_bits = &gnutls_ffdhe_8192_key_bits, - .pk = GNUTLS_PK_DH, - .tls_id = 0x104 }, -+#endif -+#ifdef HAVE_LIBOQS -+ { .name = "X25519-KYBER768", -+ .id = GNUTLS_GROUP_EXP_X25519_KYBER768, -+ .curve = GNUTLS_ECC_CURVE_X25519, -+ .pk = GNUTLS_PK_ECDH_X25519, -+ .pk2 = GNUTLS_PK_EXP_KYBER768, -+ .tls_id = 0x6399 }, - #endif - { 0, 0, 0 } - }; -diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c -index 0ef0834933..10938bce0e 100644 ---- a/lib/algorithms/publickey.c -+++ b/lib/algorithms/publickey.c -@@ -202,6 +202,12 @@ static const gnutls_pk_entry pk_algorithms[] = { - .oid = ECDH_X448_OID, - .id = GNUTLS_PK_ECDH_X448, - .curve = GNUTLS_ECC_CURVE_X448 }, -+#ifdef HAVE_LIBOQS -+ { .name = "KYBER768", -+ .oid = NULL, -+ .id = GNUTLS_PK_EXP_KYBER768, -+ .curve = GNUTLS_ECC_CURVE_INVALID }, -+#endif - { .name = "UNKNOWN", - .oid = NULL, - .id = GNUTLS_PK_UNKNOWN, -diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h -index fd8ee0c728..5c0630adaa 100644 ---- a/lib/crypto-backend.h -+++ b/lib/crypto-backend.h -@@ -411,6 +411,13 @@ typedef struct gnutls_crypto_pk { - const gnutls_pk_params_st *pub, - const gnutls_datum_t *nonce, unsigned int flags); - -+ int (*encaps)(gnutls_pk_algorithm_t, gnutls_datum_t *ciphertext, -+ gnutls_datum_t *shared_secret, const gnutls_datum_t *pub); -+ -+ int (*decaps)(gnutls_pk_algorithm_t, gnutls_datum_t *shared_secret, -+ const gnutls_datum_t *ciphertext, -+ const gnutls_datum_t *priv); -+ - int (*curve_exists)(gnutls_ecc_curve_t); /* true/false */ - int (*pk_exists)(gnutls_pk_algorithm_t); /* true/false */ - int (*sign_exists)(gnutls_sign_algorithm_t); /* true/false */ -diff --git a/lib/ext/key_share.c b/lib/ext/key_share.c -index 575ffaf8f2..6926cdd00e 100644 ---- a/lib/ext/key_share.c -+++ b/lib/ext/key_share.c -@@ -120,6 +120,8 @@ static int client_gen_key_share(gnutls_session_t session, - - } else if (group->pk == GNUTLS_PK_ECDH_X25519 || - group->pk == GNUTLS_PK_ECDH_X448) { -+ unsigned int length_pos; -+ - gnutls_pk_params_release(&session->key.kshare.ecdhx_params); - gnutls_pk_params_init(&session->key.kshare.ecdhx_params); - -@@ -129,6 +131,8 @@ static int client_gen_key_share(gnutls_session_t session, - if (ret < 0) - return gnutls_assert_val(ret); - -+ length_pos = extdata->length; -+ - ret = _gnutls_buffer_append_data_prefix( - extdata, 16, - session->key.kshare.ecdhx_params.raw_pub.data, -@@ -141,6 +145,33 @@ static int client_gen_key_share(gnutls_session_t session, - session->key.kshare.ecdhx_params.algo = group->pk; - session->key.kshare.ecdhx_params.curve = group->curve; - -+ if (group->pk2 != GNUTLS_PK_UNKNOWN) { -+ gnutls_pk_params_release( -+ &session->key.kshare.kem_params); -+ gnutls_pk_params_init(&session->key.kshare.kem_params); -+ -+ ret = _gnutls_pk_generate_keys( -+ group->pk2, 0, &session->key.kshare.kem_params, -+ 1); -+ if (ret < 0) { -+ gnutls_assert(); -+ goto cleanup; -+ } -+ -+ ret = _gnutls_buffer_append_data( -+ extdata, -+ session->key.kshare.kem_params.raw_pub.data, -+ session->key.kshare.kem_params.raw_pub.size); -+ if (ret < 0) { -+ gnutls_assert(); -+ goto cleanup; -+ } -+ -+ /* copy actual length */ -+ _gnutls_write_uint16(extdata->length - length_pos - 2, -+ &extdata->data[length_pos]); -+ } -+ - ret = 0; - - } else if (group->pk == GNUTLS_PK_DH) { -@@ -243,6 +274,10 @@ static int server_gen_key_share(gnutls_session_t session, - - } else if (group->pk == GNUTLS_PK_ECDH_X25519 || - group->pk == GNUTLS_PK_ECDH_X448) { -+ unsigned int length_pos; -+ -+ length_pos = extdata->length; -+ - ret = _gnutls_buffer_append_data_prefix( - extdata, 16, - session->key.kshare.ecdhx_params.raw_pub.data, -@@ -250,8 +285,22 @@ static int server_gen_key_share(gnutls_session_t session, - if (ret < 0) - return gnutls_assert_val(ret); - -- ret = 0; -+ if (group->pk2 != GNUTLS_PK_UNKNOWN) { -+ ret = _gnutls_buffer_append_data( -+ extdata, -+ session->key.kshare.kem_params.raw_pub.data, -+ session->key.kshare.kem_params.raw_pub.size); -+ if (ret < 0) { -+ gnutls_assert(); -+ goto cleanup; -+ } - -+ /* copy actual length */ -+ _gnutls_write_uint16(extdata->length - length_pos - 2, -+ &extdata->data[length_pos]); -+ } -+ -+ ret = 0; - } else if (group->pk == GNUTLS_PK_DH) { - ret = _gnutls_buffer_append_prefix(extdata, 16, - group->prime->size); -@@ -333,9 +382,15 @@ static int server_use_key_share(gnutls_session_t session, - - curve = _gnutls_ecc_curve_get_params(group->curve); - -- if (curve->size != data_size) -- return gnutls_assert_val( -- GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); -+ if (group->pk2 != GNUTLS_PK_UNKNOWN) { -+ if (curve->size > data_size) -+ return gnutls_assert_val( -+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); -+ } else { -+ if (curve->size != data_size) -+ return gnutls_assert_val( -+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); -+ } - - /* generate our key */ - ret = _gnutls_pk_generate_keys( -@@ -351,7 +406,7 @@ static int server_use_key_share(gnutls_session_t session, - pub.curve = curve->id; - - pub.raw_pub.data = (void *)data; -- pub.raw_pub.size = data_size; -+ pub.raw_pub.size = curve->size; - - /* We don't mask the MSB in the final byte as required - * by RFC7748. This will be done internally by nettle 3.3 or later. -@@ -363,6 +418,50 @@ static int server_use_key_share(gnutls_session_t session, - return gnutls_assert_val(ret); - } - -+ if (group->pk2 != GNUTLS_PK_UNKNOWN) { -+ gnutls_datum_t key; -+ gnutls_datum_t peer_pub; -+ -+ gnutls_pk_params_release( -+ &session->key.kshare.kem_params); -+ gnutls_pk_params_init(&session->key.kshare.kem_params); -+ -+ /* generate our key */ -+ ret = _gnutls_pk_generate_keys( -+ group->pk2, 0, &session->key.kshare.kem_params, -+ 1); -+ if (ret < 0) -+ return gnutls_assert_val(ret); -+ -+ /* server's public key is unused, but the raw_pub field -+ * is used to store ciphertext */ -+ gnutls_free( -+ session->key.kshare.kem_params.raw_pub.data); -+ -+ peer_pub.data = (uint8_t *)data + curve->size; -+ peer_pub.size = data_size - curve->size; -+ -+ ret = _gnutls_pk_encaps( -+ group->pk2, -+ &session->key.kshare.kem_params.raw_pub, &key, -+ &peer_pub); -+ if (ret < 0) -+ return gnutls_assert_val(ret); -+ -+ session->key.key.data = gnutls_realloc_fast( -+ session->key.key.data, -+ session->key.key.size + key.size); -+ if (!session->key.key.data) { -+ _gnutls_free_datum(&key); -+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ } -+ -+ memcpy(session->key.key.data + session->key.key.size, -+ key.data, key.size); -+ session->key.key.size += key.size; -+ _gnutls_free_datum(&key); -+ } -+ - ret = 0; - - } else if (group->pk == GNUTLS_PK_DH) { -@@ -496,9 +595,15 @@ static int client_use_key_share(gnutls_session_t session, - return gnutls_assert_val( - GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - -- if (curve->size != data_size) -- return gnutls_assert_val( -- GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); -+ if (group->pk2 != GNUTLS_PK_UNKNOWN) { -+ if (curve->size > data_size) -+ return gnutls_assert_val( -+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); -+ } else { -+ if (curve->size != data_size) -+ return gnutls_assert_val( -+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); -+ } - - /* read the public key and generate shared */ - gnutls_pk_params_init(&pub); -@@ -519,6 +624,33 @@ static int client_use_key_share(gnutls_session_t session, - return gnutls_assert_val(ret); - } - -+ if (group->pk2 != GNUTLS_PK_UNKNOWN) { -+ gnutls_datum_t key; -+ gnutls_datum_t ciphertext; -+ -+ ciphertext.data = (uint8_t *)data + curve->size; -+ ciphertext.size = data_size - curve->size; -+ -+ ret = _gnutls_pk_decaps( -+ group->pk2, &key, &ciphertext, -+ &session->key.kshare.kem_params.raw_priv); -+ if (ret < 0) -+ return gnutls_assert_val(ret); -+ -+ session->key.key.data = gnutls_realloc_fast( -+ session->key.key.data, -+ session->key.key.size + key.size); -+ if (!session->key.key.data) { -+ _gnutls_free_datum(&key); -+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ } -+ -+ memcpy(session->key.key.data + session->key.key.size, -+ key.data, key.size); -+ session->key.key.size += key.size; -+ _gnutls_free_datum(&key); -+ } -+ - ret = 0; - - } else if (group->pk == GNUTLS_PK_DH) { -diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h -index 258a08c842..5727739bdc 100644 ---- a/lib/gnutls_int.h -+++ b/lib/gnutls_int.h -@@ -594,6 +594,7 @@ struct gnutls_key_st { - gnutls_pk_params_st ecdh_params; - gnutls_pk_params_st ecdhx_params; - gnutls_pk_params_st dh_params; -+ gnutls_pk_params_st kem_params; - } kshare; - - /* The union contents depend on the negotiated protocol. -@@ -764,6 +765,7 @@ typedef struct gnutls_group_entry_st { - const unsigned *q_bits; - gnutls_ecc_curve_t curve; - gnutls_pk_algorithm_t pk; -+ gnutls_pk_algorithm_t pk2; - unsigned tls_id; /* The RFC4492 namedCurve ID or TLS 1.3 group ID */ - } gnutls_group_entry_st; - -diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in -index 6b87610c44..790406e4df 100644 ---- a/lib/includes/gnutls/gnutls.h.in -+++ b/lib/includes/gnutls/gnutls.h.in -@@ -908,7 +908,12 @@ typedef enum { - GNUTLS_PK_ECDH_X448 = 11, - GNUTLS_PK_EDDSA_ED448 = 12, - GNUTLS_PK_RSA_OAEP = 13, -- GNUTLS_PK_MAX = GNUTLS_PK_RSA_OAEP -+ GNUTLS_PK_MAX = GNUTLS_PK_RSA_OAEP, -+ -+ /* Experimental algorithms */ -+ GNUTLS_PK_EXP_MIN = 256, -+ GNUTLS_PK_EXP_KYBER768 = GNUTLS_PK_EXP_MIN, -+ GNUTLS_PK_EXP_MAX = GNUTLS_PK_EXP_KYBER768 - } gnutls_pk_algorithm_t; - - const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm); -@@ -1136,6 +1141,11 @@ typedef enum { - GNUTLS_GROUP_FFDHE8192, - GNUTLS_GROUP_FFDHE6144, - GNUTLS_GROUP_MAX = GNUTLS_GROUP_FFDHE6144, -+ -+ /* Experimental algorithms */ -+ GNUTLS_GROUP_EXP_MIN = 512, -+ GNUTLS_GROUP_EXP_X25519_KYBER768 = GNUTLS_GROUP_EXP_MIN, -+ GNUTLS_GROUP_EXP_MAX = GNUTLS_GROUP_EXP_X25519_KYBER768 - } gnutls_group_t; - - /* macros to allow specifying a specific curve in gnutls_privkey_generate() -diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am -index b855c8c193..0f21823cb4 100644 ---- a/lib/nettle/Makefile.am -+++ b/lib/nettle/Makefile.am -@@ -36,6 +36,10 @@ if ENABLE_MINITASN1 - AM_CPPFLAGS += -I$(srcdir)/../minitasn1 - endif - -+if ENABLE_DLOPEN -+AM_CPPFLAGS += $(LIBOQS_CFLAGS) -DGNUTLS_OQS_ENABLE_DLOPEN=1 -+endif -+ - noinst_LTLIBRARIES = libcrypto.la - - libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c init.c \ -diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c -index b317b790d7..4155a540ed 100644 ---- a/lib/nettle/pk.c -+++ b/lib/nettle/pk.c -@@ -70,6 +70,9 @@ - #include "gnettle.h" - #include "fips.h" - #include "dh.h" -+#ifdef HAVE_LIBOQS -+#include "dlwrap/oqs.h" -+#endif - - static inline const struct ecc_curve *get_supported_nist_curve(int curve); - static inline const struct ecc_curve *get_supported_gost_curve(int curve); -@@ -687,6 +690,111 @@ cleanup: - return ret; - } - -+static int _wrap_nettle_pk_encaps(gnutls_pk_algorithm_t algo, -+ gnutls_datum_t *ciphertext, -+ gnutls_datum_t *shared_secret, -+ const gnutls_datum_t *pub) -+{ -+ int ret; -+ -+ switch (algo) { -+#ifdef HAVE_LIBOQS -+ case GNUTLS_PK_EXP_KYBER768: { -+ OQS_KEM *kem = NULL; -+ OQS_STATUS rc; -+ -+ kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); -+ if (kem == NULL) -+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ -+ ciphertext->data = gnutls_malloc(kem->length_ciphertext); -+ if (ciphertext->data == NULL) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ goto cleanup; -+ } -+ ciphertext->size = kem->length_ciphertext; -+ -+ shared_secret->data = gnutls_malloc(kem->length_shared_secret); -+ if (shared_secret->data == NULL) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ goto cleanup; -+ } -+ shared_secret->size = kem->length_shared_secret; -+ -+ rc = GNUTLS_OQS_FUNC(OQS_KEM_encaps)( -+ kem, ciphertext->data, shared_secret->data, pub->data); -+ if (rc != OQS_SUCCESS) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); -+ goto cleanup; -+ } -+ -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = 0; -+ } break; -+#endif -+ default: -+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM); -+ goto cleanup; -+ } -+ -+cleanup: -+ if (ret < 0) { -+ gnutls_free(ciphertext->data); -+ gnutls_free(shared_secret->data); -+ } -+ return ret; -+} -+ -+static int _wrap_nettle_pk_decaps(gnutls_pk_algorithm_t algo, -+ gnutls_datum_t *shared_secret, -+ const gnutls_datum_t *ciphertext, -+ const gnutls_datum_t *priv) -+{ -+ int ret; -+ -+ switch (algo) { -+#ifdef HAVE_LIBOQS -+ case GNUTLS_PK_EXP_KYBER768: { -+ OQS_KEM *kem = NULL; -+ OQS_STATUS rc; -+ -+ kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); -+ if (kem == NULL) -+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ -+ shared_secret->data = gnutls_malloc(kem->length_shared_secret); -+ if (shared_secret->data == NULL) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ goto cleanup; -+ } -+ shared_secret->size = kem->length_shared_secret; -+ -+ rc = GNUTLS_OQS_FUNC(OQS_KEM_decaps)( -+ kem, shared_secret->data, ciphertext->data, priv->data); -+ if (rc != OQS_SUCCESS) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); -+ goto cleanup; -+ } -+ -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = 0; -+ } break; -+#endif -+ default: -+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM); -+ goto cleanup; -+ } -+cleanup: -+ if (ret < 0) -+ gnutls_free(shared_secret->data); -+ return ret; -+} -+ - /* This wraps nettle_rsa_encrypt so it returns ciphertext as a byte - * array instead of a mpz_t value. Returns 1 on success; 0 otherwise. - */ -@@ -2234,6 +2342,9 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk) - case GNUTLS_PK_RSA_PSS: - case GNUTLS_PK_RSA_OAEP: - case GNUTLS_PK_EDDSA_ED25519: -+#ifdef HAVE_LIBOQS -+ case GNUTLS_PK_EXP_KYBER768: -+#endif - #if ENABLE_GOST - case GNUTLS_PK_GOST_01: - case GNUTLS_PK_GOST_12_256: -@@ -2875,6 +2986,9 @@ static int pct_test(gnutls_pk_algorithm_t algo, - } - case GNUTLS_PK_ECDH_X25519: - case GNUTLS_PK_ECDH_X448: -+#ifdef HAVE_LIBOQS -+ case GNUTLS_PK_EXP_KYBER768: -+#endif - ret = 0; - goto cleanup; - default: -@@ -3605,6 +3719,49 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo, - goto cleanup; - break; - } -+#ifdef HAVE_LIBOQS -+ case GNUTLS_PK_EXP_KYBER768: { -+ OQS_KEM *kem = NULL; -+ OQS_STATUS rc; -+ -+ not_approved = true; -+ -+ kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); -+ if (kem == NULL) { -+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ goto cleanup; -+ } -+ -+ params->raw_priv.size = kem->length_secret_key; -+ params->raw_priv.data = gnutls_malloc(params->raw_priv.size); -+ if (params->raw_priv.data == NULL) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ goto cleanup; -+ } -+ -+ params->raw_pub.size = kem->length_public_key; -+ params->raw_pub.data = gnutls_malloc(params->raw_pub.size); -+ if (params->raw_pub.data == NULL) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -+ goto cleanup; -+ } -+ -+ rc = GNUTLS_OQS_FUNC(OQS_KEM_keypair)(kem, params->raw_pub.data, -+ params->raw_priv.data); -+ if (rc != OQS_SUCCESS) { -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); -+ goto cleanup; -+ } -+ -+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem); -+ -+ ret = 0; -+ break; -+ } -+#endif - default: - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; -@@ -3858,6 +4015,11 @@ static int wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo, - ret = 0; - break; - } -+#ifdef HAVE_LIBOQS -+ case GNUTLS_PK_EXP_KYBER768: -+ ret = 0; -+ break; -+#endif - #if ENABLE_GOST - case GNUTLS_PK_GOST_01: - case GNUTLS_PK_GOST_12_256: -@@ -4307,6 +4469,8 @@ gnutls_crypto_pk_st _gnutls_pk_ops = { - .generate_keys = wrap_nettle_pk_generate_keys, - .pk_fixup_private_params = wrap_nettle_pk_fixup, - .derive = _wrap_nettle_pk_derive, -+ .encaps = _wrap_nettle_pk_encaps, -+ .decaps = _wrap_nettle_pk_decaps, - .curve_exists = _wrap_nettle_pk_curve_exists, - .pk_exists = _wrap_nettle_pk_exists, - .sign_exists = _wrap_nettle_pk_sign_exists -diff --git a/lib/pk.h b/lib/pk.h -index 20fe314f94..eca4e02d73 100644 ---- a/lib/pk.h -+++ b/lib/pk.h -@@ -46,6 +46,10 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops; - _gnutls_pk_ops.derive(algo, out, pub, priv, nonce, 0) - #define _gnutls_pk_derive_tls13(algo, out, pub, priv) \ - _gnutls_pk_ops.derive(algo, out, pub, priv, NULL, PK_DERIVE_TLS13) -+#define _gnutls_pk_encaps(algo, ciphertext, shared_secret, pub) \ -+ _gnutls_pk_ops.encaps(algo, ciphertext, shared_secret, pub) -+#define _gnutls_pk_decaps(algo, shared_secret, ciphertext, priv) \ -+ _gnutls_pk_ops.decaps(algo, shared_secret, ciphertext, priv) - #define _gnutls_pk_generate_keys(algo, bits, params, temporal) \ - _gnutls_pk_ops.generate_keys(algo, bits, params, temporal) - #define _gnutls_pk_generate_params(algo, bits, priv) \ -diff --git a/lib/state.c b/lib/state.c -index ec514c0cd2..f2c74d97d0 100644 ---- a/lib/state.c -+++ b/lib/state.c -@@ -459,6 +459,7 @@ static void deinit_keys(gnutls_session_t session) - gnutls_pk_params_release(&session->key.kshare.ecdhx_params); - gnutls_pk_params_release(&session->key.kshare.ecdh_params); - gnutls_pk_params_release(&session->key.kshare.dh_params); -+ gnutls_pk_params_release(&session->key.kshare.kem_params); - - if (!vers->tls13_sem && session->key.binders[0].prf == NULL) { - gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params); -diff --git a/tests/Makefile.am b/tests/Makefile.am -index c674835c1f..ca76736d2e 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -600,6 +600,10 @@ ctests += win32-certopenstore - - endif - -+if ENABLE_LIBOQS -+dist_check_SCRIPTS += pqc-hybrid-kx.sh -+endif -+ - cpptests = - if ENABLE_CXX - if HAVE_CMOCKA -diff --git a/tests/pqc-hybrid-kx.sh b/tests/pqc-hybrid-kx.sh -new file mode 100644 -index 0000000000..b9302b43b1 ---- /dev/null -+++ b/tests/pqc-hybrid-kx.sh -@@ -0,0 +1,54 @@ -+#!/bin/sh -+ -+# Copyright (C) 2022 Red Hat, Inc. -+# -+# Author: Daiki Ueno -+# -+# 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 General Public License -+# along with GnuTLS. If not, see . -+ -+: ${srcdir=.} -+: ${SERV=../src/gnutls-serv${EXEEXT}} -+: ${CLI=../src/gnutls-cli${EXEEXT}} -+ -+if ! test -x "${SERV}"; then -+ exit 77 -+fi -+ -+if ! test -x "${CLI}"; then -+ exit 77 -+fi -+ -+. "${srcdir}/scripts/common.sh" -+testdir=`create_testdir pqc-hybrid-kx` -+ -+KEY="$srcdir/../doc/credentials/x509/key-ed25519.pem" -+CERT="$srcdir/../doc/credentials/x509/cert-ed25519.pem" -+CACERT="$srcdir/../doc/credentials/x509/ca.pem" -+ -+eval "${GETPORT}" -+launch_server --echo --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509keyfile="$KEY" --x509certfile="$CERT" -+PID=$! -+wait_server ${PID} -+ -+${VALGRIND} "${CLI}" -p "${PORT}" 127.0.0.1 --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509cafile="$CACERT" --logfile="$testdir/cli.log" -Date: Tue, 23 Jul 2024 11:25:18 +0900 -Subject: [PATCH 1/3] dlwrap: use different macro for library soname in - generated code - -As GnuTLS opt in for manual initialization of dlopen'ed libraries, -config.h shouldn't define the SONAME macro used in the generated code. - -Signed-off-by: Daiki Ueno ---- - devel/generate-dlwrap.sh | 18 +++++++++++++----- - lib/dlwrap/brotlidec.c | 17 +++++++++-------- - lib/dlwrap/brotlienc.c | 17 +++++++++-------- - lib/dlwrap/oqs.c | 17 +++++++++-------- - lib/dlwrap/zlib.c | 17 +++++++++-------- - lib/dlwrap/zstd.c | 17 +++++++++-------- - 6 files changed, 58 insertions(+), 45 deletions(-) - -diff --git a/devel/generate-dlwrap.sh b/devel/generate-dlwrap.sh -index 3e253d9228..0394655bbf 100755 ---- a/devel/generate-dlwrap.sh -+++ b/devel/generate-dlwrap.sh -@@ -21,20 +21,28 @@ DST="$srcdir/lib/$DLWRAP" - - echo "Generating $DST/zlib.h" - --"$DLWRAP" --input /usr/include/zlib.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/z.syms" --license-file "$SRC/z.license" --soname Z_LIBRARY_SONAME --prefix gnutls_zlib --header-guard GNUTLS_LIB_DLWRAP_ZLIB_H_ --include "" -+"$DLWRAP" --input /usr/include/zlib.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/z.syms" --license-file "$SRC/z.license" --soname Z_LIBRARY_SONAME_UNUSED --prefix gnutls_zlib --header-guard GNUTLS_LIB_DLWRAP_ZLIB_H_ --include "" - - echo "Generating $DST/zstd.h" - --"$DLWRAP" --input /usr/include/zstd.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/zstd.syms" --license-file "$SRC/zstd.license" --soname ZSTD_LIBRARY_SONAME --prefix gnutls_zstd --header-guard GNUTLS_LIB_DLWRAP_ZSTD_H_ --include "" -+"$DLWRAP" --input /usr/include/zstd.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/zstd.syms" --license-file "$SRC/zstd.license" --soname ZSTD_LIBRARY_SONAME_UNUSED --prefix gnutls_zstd --header-guard GNUTLS_LIB_DLWRAP_ZSTD_H_ --include "" - - echo "Generating $DST/brotlienc.h" - --"$DLWRAP" --input /usr/include/brotli/encode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlienc.syms" --license-file "$SRC/brotli.license" --soname BROTLIENC_LIBRARY_SONAME --prefix gnutls_brotlienc --loader-basename brotlienc --header-guard GNUTLS_LIB_DLWRAP_BROTLIENC_H_ --include "" -+"$DLWRAP" --input /usr/include/brotli/encode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlienc.syms" --license-file "$SRC/brotli.license" --soname BROTLIENC_LIBRARY_SONAME_UNUSED --prefix gnutls_brotlienc --loader-basename brotlienc --header-guard GNUTLS_LIB_DLWRAP_BROTLIENC_H_ --include "" - - echo "Generating $DST/brotlidec.h" - --"$DLWRAP" --input /usr/include/brotli/decode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlidec.syms" --license-file "$SRC/brotli.license" --soname BROTLIDEC_LIBRARY_SONAME --prefix gnutls_brotlidec --loader-basename brotlidec --header-guard GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ --include "" -+"$DLWRAP" --input /usr/include/brotli/decode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlidec.syms" --license-file "$SRC/brotli.license" --soname BROTLIDEC_LIBRARY_SONAME_UNUSED --prefix gnutls_brotlidec --loader-basename brotlidec --header-guard GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ --include "" - - echo "Generating $DST/oqs.h" - --"$DLWRAP" --input /usr/include/oqs/oqs.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/oqs.syms" --license "SPDX-License-Identifier: MIT" --soname OQS_LIBRARY_SONAME --prefix gnutls_oqs --header-guard GNUTLS_LIB_DLWRAP_OQS_H_ --include "" -+"$DLWRAP" --input /usr/include/oqs/oqs.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/oqs.syms" --license "SPDX-License-Identifier: MIT" --soname OQS_LIBRARY_SONAME_UNUSED --prefix gnutls_oqs --header-guard GNUTLS_LIB_DLWRAP_OQS_H_ --include "" -+ -+sed -i '/^#include /i\ -+/* Local modification: remove this once liboqs 0.10.2 is released */\ -+#include "config.h"\ -+#if !HAVE_DECL_OQS_SHA3_SET_CALLBACKS\ -+#include "liboqs/backport/sha3_ops.h"\ -+#endif\ -+' "$DST/oqs.h" -diff --git a/lib/dlwrap/brotlidec.c b/lib/dlwrap/brotlidec.c -index 45c9b4b259..15cee63bd6 100644 ---- a/lib/dlwrap/brotlidec.c -+++ b/lib/dlwrap/brotlidec.c -@@ -18,16 +18,16 @@ - #include - #include - --/* If BROTLIDEC_LIBRARY_SONAME is defined, dlopen handle can be automatically -+/* If BROTLIDEC_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically - * set; otherwise, the caller needs to call - * gnutls_brotlidec_ensure_library with soname determined at run time. - */ --#ifdef BROTLIDEC_LIBRARY_SONAME -+#ifdef BROTLIDEC_LIBRARY_SONAME_UNUSED - - static void - ensure_library (void) - { -- if (gnutls_brotlidec_ensure_library (BROTLIDEC_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ if (gnutls_brotlidec_ensure_library (BROTLIDEC_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0) - abort (); - } - -@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; - - #endif /* !GNUTLS_BROTLIDEC_ENABLE_PTHREAD */ - --#else /* BROTLIDEC_LIBRARY_SONAME */ -+#else /* BROTLIDEC_LIBRARY_SONAME_UNUSED */ - - #define ENSURE_LIBRARY do {} while (0) - --#endif /* !BROTLIDEC_LIBRARY_SONAME */ -+#endif /* !BROTLIDEC_LIBRARY_SONAME_UNUSED */ - - static void *gnutls_brotlidec_dlhandle; - -@@ -147,7 +147,10 @@ void - gnutls_brotlidec_unload_library (void) - { - if (gnutls_brotlidec_dlhandle) -- dlclose (gnutls_brotlidec_dlhandle); -+ { -+ dlclose (gnutls_brotlidec_dlhandle); -+ gnutls_brotlidec_dlhandle = NULL; -+ } - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" -@@ -160,8 +163,6 @@ gnutls_brotlidec_unload_library (void) - #undef FUNC - - #pragma GCC diagnostic pop -- --#undef RESET_SYMBOL - } - - #else /* GNUTLS_BROTLIDEC_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/brotlienc.c b/lib/dlwrap/brotlienc.c -index 9dd8ff37c6..1deff747e2 100644 ---- a/lib/dlwrap/brotlienc.c -+++ b/lib/dlwrap/brotlienc.c -@@ -18,16 +18,16 @@ - #include - #include - --/* If BROTLIENC_LIBRARY_SONAME is defined, dlopen handle can be automatically -+/* If BROTLIENC_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically - * set; otherwise, the caller needs to call - * gnutls_brotlienc_ensure_library with soname determined at run time. - */ --#ifdef BROTLIENC_LIBRARY_SONAME -+#ifdef BROTLIENC_LIBRARY_SONAME_UNUSED - - static void - ensure_library (void) - { -- if (gnutls_brotlienc_ensure_library (BROTLIENC_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ if (gnutls_brotlienc_ensure_library (BROTLIENC_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0) - abort (); - } - -@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; - - #endif /* !GNUTLS_BROTLIENC_ENABLE_PTHREAD */ - --#else /* BROTLIENC_LIBRARY_SONAME */ -+#else /* BROTLIENC_LIBRARY_SONAME_UNUSED */ - - #define ENSURE_LIBRARY do {} while (0) - --#endif /* !BROTLIENC_LIBRARY_SONAME */ -+#endif /* !BROTLIENC_LIBRARY_SONAME_UNUSED */ - - static void *gnutls_brotlienc_dlhandle; - -@@ -147,7 +147,10 @@ void - gnutls_brotlienc_unload_library (void) - { - if (gnutls_brotlienc_dlhandle) -- dlclose (gnutls_brotlienc_dlhandle); -+ { -+ dlclose (gnutls_brotlienc_dlhandle); -+ gnutls_brotlienc_dlhandle = NULL; -+ } - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" -@@ -160,8 +163,6 @@ gnutls_brotlienc_unload_library (void) - #undef FUNC - - #pragma GCC diagnostic pop -- --#undef RESET_SYMBOL - } - - #else /* GNUTLS_BROTLIENC_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/oqs.c b/lib/dlwrap/oqs.c -index d7fcc9c80c..c05f883127 100644 ---- a/lib/dlwrap/oqs.c -+++ b/lib/dlwrap/oqs.c -@@ -18,16 +18,16 @@ - #include - #include - --/* If OQS_LIBRARY_SONAME is defined, dlopen handle can be automatically -+/* If OQS_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically - * set; otherwise, the caller needs to call - * gnutls_oqs_ensure_library with soname determined at run time. - */ --#ifdef OQS_LIBRARY_SONAME -+#ifdef OQS_LIBRARY_SONAME_UNUSED - - static void - ensure_library (void) - { -- if (gnutls_oqs_ensure_library (OQS_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ if (gnutls_oqs_ensure_library (OQS_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0) - abort (); - } - -@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; - - #endif /* !GNUTLS_OQS_ENABLE_PTHREAD */ - --#else /* OQS_LIBRARY_SONAME */ -+#else /* OQS_LIBRARY_SONAME_UNUSED */ - - #define ENSURE_LIBRARY do {} while (0) - --#endif /* !OQS_LIBRARY_SONAME */ -+#endif /* !OQS_LIBRARY_SONAME_UNUSED */ - - static void *gnutls_oqs_dlhandle; - -@@ -147,7 +147,10 @@ void - gnutls_oqs_unload_library (void) - { - if (gnutls_oqs_dlhandle) -- dlclose (gnutls_oqs_dlhandle); -+ { -+ dlclose (gnutls_oqs_dlhandle); -+ gnutls_oqs_dlhandle = NULL; -+ } - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" -@@ -160,8 +163,6 @@ gnutls_oqs_unload_library (void) - #undef FUNC - - #pragma GCC diagnostic pop -- --#undef RESET_SYMBOL - } - - #else /* GNUTLS_OQS_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/zlib.c b/lib/dlwrap/zlib.c -index 455485c63f..878070c0a4 100644 ---- a/lib/dlwrap/zlib.c -+++ b/lib/dlwrap/zlib.c -@@ -18,16 +18,16 @@ - #include - #include - --/* If Z_LIBRARY_SONAME is defined, dlopen handle can be automatically -+/* If Z_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically - * set; otherwise, the caller needs to call - * gnutls_zlib_ensure_library with soname determined at run time. - */ --#ifdef Z_LIBRARY_SONAME -+#ifdef Z_LIBRARY_SONAME_UNUSED - - static void - ensure_library (void) - { -- if (gnutls_zlib_ensure_library (Z_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ if (gnutls_zlib_ensure_library (Z_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0) - abort (); - } - -@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; - - #endif /* !GNUTLS_ZLIB_ENABLE_PTHREAD */ - --#else /* Z_LIBRARY_SONAME */ -+#else /* Z_LIBRARY_SONAME_UNUSED */ - - #define ENSURE_LIBRARY do {} while (0) - --#endif /* !Z_LIBRARY_SONAME */ -+#endif /* !Z_LIBRARY_SONAME_UNUSED */ - - static void *gnutls_zlib_dlhandle; - -@@ -147,7 +147,10 @@ void - gnutls_zlib_unload_library (void) - { - if (gnutls_zlib_dlhandle) -- dlclose (gnutls_zlib_dlhandle); -+ { -+ dlclose (gnutls_zlib_dlhandle); -+ gnutls_zlib_dlhandle = NULL; -+ } - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" -@@ -160,8 +163,6 @@ gnutls_zlib_unload_library (void) - #undef FUNC - - #pragma GCC diagnostic pop -- --#undef RESET_SYMBOL - } - - #else /* GNUTLS_ZLIB_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/zstd.c b/lib/dlwrap/zstd.c -index 2ea7252975..532c80b610 100644 ---- a/lib/dlwrap/zstd.c -+++ b/lib/dlwrap/zstd.c -@@ -18,16 +18,16 @@ - #include - #include - --/* If ZSTD_LIBRARY_SONAME is defined, dlopen handle can be automatically -+/* If ZSTD_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically - * set; otherwise, the caller needs to call - * gnutls_zstd_ensure_library with soname determined at run time. - */ --#ifdef ZSTD_LIBRARY_SONAME -+#ifdef ZSTD_LIBRARY_SONAME_UNUSED - - static void - ensure_library (void) - { -- if (gnutls_zstd_ensure_library (ZSTD_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) -+ if (gnutls_zstd_ensure_library (ZSTD_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0) - abort (); - } - -@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; - - #endif /* !GNUTLS_ZSTD_ENABLE_PTHREAD */ - --#else /* ZSTD_LIBRARY_SONAME */ -+#else /* ZSTD_LIBRARY_SONAME_UNUSED */ - - #define ENSURE_LIBRARY do {} while (0) - --#endif /* !ZSTD_LIBRARY_SONAME */ -+#endif /* !ZSTD_LIBRARY_SONAME_UNUSED */ - - static void *gnutls_zstd_dlhandle; - -@@ -147,7 +147,10 @@ void - gnutls_zstd_unload_library (void) - { - if (gnutls_zstd_dlhandle) -- dlclose (gnutls_zstd_dlhandle); -+ { -+ dlclose (gnutls_zstd_dlhandle); -+ gnutls_zstd_dlhandle = NULL; -+ } - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" -@@ -160,8 +163,6 @@ gnutls_zstd_unload_library (void) - #undef FUNC - - #pragma GCC diagnostic pop -- --#undef RESET_SYMBOL - } - - #else /* GNUTLS_ZSTD_ENABLE_DLOPEN */ --- -2.45.2 - - -From ec65c64e6c904d5a408e2afb31ecacc2b52ed7dc Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Tue, 23 Jul 2024 15:12:11 +0900 -Subject: [PATCH 2/3] liboqs: manually load liboqs.so at startup - -Signed-off-by: Daiki Ueno ---- - lib/global.c | 6 +++++- - lib/liboqs/liboqs.c | 21 ++++++++++++++++++++- - lib/liboqs/liboqs.h | 2 +- - 3 files changed, 26 insertions(+), 3 deletions(-) - -diff --git a/lib/global.c b/lib/global.c -index ae2f7f54dc..4aaf79a768 100644 ---- a/lib/global.c -+++ b/lib/global.c -@@ -330,7 +330,11 @@ static int _gnutls_global_init(unsigned constructor) - } - - #ifdef HAVE_LIBOQS -- _gnutls_liboqs_init(); -+ ret = _gnutls_liboqs_init(); -+ if (ret < 0) { -+ gnutls_assert(); -+ goto out; -+ } - #endif - - #ifndef _WIN32 -diff --git a/lib/liboqs/liboqs.c b/lib/liboqs/liboqs.c -index 88f2369719..c5531d4796 100644 ---- a/lib/liboqs/liboqs.c -+++ b/lib/liboqs/liboqs.c -@@ -22,15 +22,33 @@ - - #include "liboqs/liboqs.h" - -+#ifdef _WIN32 -+#define RTLD_NOW 0 -+#define RTLD_GLOBAL 0 -+#else -+#include -+#endif -+ -+#ifndef OQS_LIBRARY_SONAME -+#define OQS_LIBRARY_SONAME "none" -+#endif -+ -+#include "errors.h" -+ - #include "dlwrap/oqs.h" - #include "liboqs/rand.h" - #include "liboqs/sha3.h" - --void _gnutls_liboqs_init(void) -+int _gnutls_liboqs_init(void) - { -+ if (gnutls_oqs_ensure_library(OQS_LIBRARY_SONAME, -+ RTLD_NOW | RTLD_GLOBAL) < 0) -+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); -+ - _gnutls_liboqs_sha3_init(); - GNUTLS_OQS_FUNC(OQS_init)(); - _gnutls_liboqs_rand_init(); -+ return 0; - } - - void _gnutls_liboqs_deinit(void) -@@ -38,4 +56,5 @@ void _gnutls_liboqs_deinit(void) - _gnutls_liboqs_rand_deinit(); - _gnutls_liboqs_sha3_deinit(); - GNUTLS_OQS_FUNC(OQS_destroy)(); -+ gnutls_oqs_unload_library(); - } -diff --git a/lib/liboqs/liboqs.h b/lib/liboqs/liboqs.h -index b6c1659212..50206fa77c 100644 ---- a/lib/liboqs/liboqs.h -+++ b/lib/liboqs/liboqs.h -@@ -21,7 +21,7 @@ - #ifndef GNUTLS_LIB_LIBOQS_LIBOQS_H - #define GNUTLS_LIB_LIBOQS_LIBOQS_H - --void _gnutls_liboqs_init(void); -+int _gnutls_liboqs_init(void); - void _gnutls_liboqs_deinit(void); - - #endif /* GNUTLS_LIB_LIBOQS_LIBOQS_H */ --- -2.45.2 - - -From ecc41197f2233494d066114e2747b17b24d24543 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Tue, 23 Jul 2024 09:50:04 +0900 -Subject: [PATCH 3/3] tests: pqc-hybrid-kx: use key and certificate in - distribution - -The Ed25519 key and certificate in doc/credentials/x509/ are currently -not included in the distribution. Use the ECDSA ones in the test to -make the test work. - -Signed-off-by: Daiki Ueno ---- - tests/pqc-hybrid-kx.sh | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/tests/pqc-hybrid-kx.sh b/tests/pqc-hybrid-kx.sh -index b9302b43b1..b587587bd2 100644 ---- a/tests/pqc-hybrid-kx.sh -+++ b/tests/pqc-hybrid-kx.sh -@@ -34,8 +34,8 @@ fi - . "${srcdir}/scripts/common.sh" - testdir=`create_testdir pqc-hybrid-kx` - --KEY="$srcdir/../doc/credentials/x509/key-ed25519.pem" --CERT="$srcdir/../doc/credentials/x509/cert-ed25519.pem" -+KEY="$srcdir/../doc/credentials/x509/key-ecc.pem" -+CERT="$srcdir/../doc/credentials/x509/cert-ecc.pem" - CACERT="$srcdir/../doc/credentials/x509/ca.pem" - - eval "${GETPORT}" -@@ -43,12 +43,12 @@ launch_server --echo --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509k - PID=$! - wait_server ${PID} - --${VALGRIND} "${CLI}" -p "${PORT}" 127.0.0.1 --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509cafile="$CACERT" --logfile="$testdir/cli.log" -Date: Tue, 23 Jul 2024 20:48:26 +0900 -Subject: [PATCH] liboqs: defer loading of liboqs at run-time - -Instead of loading liboqs at startup, this defers it until the liboqs -functions are actually used. - -Signed-off-by: Daiki Ueno ---- - lib/dlwrap/brotlidec.c | 24 ++++++++++++++++++---- - lib/dlwrap/brotlidec.h | 7 +++++++ - lib/dlwrap/brotlienc.c | 24 ++++++++++++++++++---- - lib/dlwrap/brotlienc.h | 7 +++++++ - lib/dlwrap/oqs.c | 24 ++++++++++++++++++---- - lib/dlwrap/oqs.h | 7 +++++++ - lib/dlwrap/zlib.c | 24 ++++++++++++++++++---- - lib/dlwrap/zlib.h | 7 +++++++ - lib/dlwrap/zstd.c | 24 ++++++++++++++++++---- - lib/dlwrap/zstd.h | 7 +++++++ - lib/global.c | 8 -------- - lib/liboqs/liboqs.c | 46 +++++++++++++++++++++++++++++++++++------- - lib/liboqs/liboqs.h | 2 +- - lib/nettle/pk.c | 33 ++++++++++++++++++++++++------ - 14 files changed, 202 insertions(+), 42 deletions(-) - -diff --git a/lib/dlwrap/brotlidec.c b/lib/dlwrap/brotlidec.c -index 15cee63bd6..7e4546a8e7 100644 ---- a/lib/dlwrap/brotlidec.c -+++ b/lib/dlwrap/brotlidec.c -@@ -128,10 +128,13 @@ gnutls_brotlidec_ensure_library (const char *soname, int flags) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" - --#define FUNC(ret, name, args, cargs) \ -- err = ENSURE_SYMBOL(name); \ -- if (err < 0) \ -- return err; -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ { \ -+ gnutls_brotlidec_dlhandle = NULL; \ -+ return err; \ -+ } - #define VOID_FUNC FUNC - #include "brotlidecfuncs.h" - #undef VOID_FUNC -@@ -165,6 +168,12 @@ gnutls_brotlidec_unload_library (void) - #pragma GCC diagnostic pop - } - -+unsigned -+gnutls_brotlidec_is_usable (void) -+{ -+ return gnutls_brotlidec_dlhandle != NULL; -+} -+ - #else /* GNUTLS_BROTLIDEC_ENABLE_DLOPEN */ - - int -@@ -180,4 +189,11 @@ gnutls_brotlidec_unload_library (void) - { - } - -+unsigned -+gnutls_brotlidec_is_usable (void) -+{ -+ /* The library is linked at build time, thus always usable */ -+ return 1; -+} -+ - #endif /* !GNUTLS_BROTLIDEC_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/brotlidec.h b/lib/dlwrap/brotlidec.h -index 31397f24cf..f7d97eed35 100644 ---- a/lib/dlwrap/brotlidec.h -+++ b/lib/dlwrap/brotlidec.h -@@ -44,4 +44,11 @@ int gnutls_brotlidec_ensure_library (const char *soname, int flags); - */ - void gnutls_brotlidec_unload_library (void); - -+/* Return 1 if the library is loaded and usable. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+unsigned gnutls_brotlidec_is_usable (void); -+ - #endif /* GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ */ -diff --git a/lib/dlwrap/brotlienc.c b/lib/dlwrap/brotlienc.c -index 1deff747e2..fae13ed313 100644 ---- a/lib/dlwrap/brotlienc.c -+++ b/lib/dlwrap/brotlienc.c -@@ -128,10 +128,13 @@ gnutls_brotlienc_ensure_library (const char *soname, int flags) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" - --#define FUNC(ret, name, args, cargs) \ -- err = ENSURE_SYMBOL(name); \ -- if (err < 0) \ -- return err; -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ { \ -+ gnutls_brotlienc_dlhandle = NULL; \ -+ return err; \ -+ } - #define VOID_FUNC FUNC - #include "brotliencfuncs.h" - #undef VOID_FUNC -@@ -165,6 +168,12 @@ gnutls_brotlienc_unload_library (void) - #pragma GCC diagnostic pop - } - -+unsigned -+gnutls_brotlienc_is_usable (void) -+{ -+ return gnutls_brotlienc_dlhandle != NULL; -+} -+ - #else /* GNUTLS_BROTLIENC_ENABLE_DLOPEN */ - - int -@@ -180,4 +189,11 @@ gnutls_brotlienc_unload_library (void) - { - } - -+unsigned -+gnutls_brotlienc_is_usable (void) -+{ -+ /* The library is linked at build time, thus always usable */ -+ return 1; -+} -+ - #endif /* !GNUTLS_BROTLIENC_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/brotlienc.h b/lib/dlwrap/brotlienc.h -index ed1af45e04..4dfbf3b838 100644 ---- a/lib/dlwrap/brotlienc.h -+++ b/lib/dlwrap/brotlienc.h -@@ -44,4 +44,11 @@ int gnutls_brotlienc_ensure_library (const char *soname, int flags); - */ - void gnutls_brotlienc_unload_library (void); - -+/* Return 1 if the library is loaded and usable. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+unsigned gnutls_brotlienc_is_usable (void); -+ - #endif /* GNUTLS_LIB_DLWRAP_BROTLIENC_H_ */ -diff --git a/lib/dlwrap/oqs.c b/lib/dlwrap/oqs.c -index c05f883127..f9ae269faa 100644 ---- a/lib/dlwrap/oqs.c -+++ b/lib/dlwrap/oqs.c -@@ -128,10 +128,13 @@ gnutls_oqs_ensure_library (const char *soname, int flags) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" - --#define FUNC(ret, name, args, cargs) \ -- err = ENSURE_SYMBOL(name); \ -- if (err < 0) \ -- return err; -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ { \ -+ gnutls_oqs_dlhandle = NULL; \ -+ return err; \ -+ } - #define VOID_FUNC FUNC - #include "oqsfuncs.h" - #undef VOID_FUNC -@@ -165,6 +168,12 @@ gnutls_oqs_unload_library (void) - #pragma GCC diagnostic pop - } - -+unsigned -+gnutls_oqs_is_usable (void) -+{ -+ return gnutls_oqs_dlhandle != NULL; -+} -+ - #else /* GNUTLS_OQS_ENABLE_DLOPEN */ - - int -@@ -180,4 +189,11 @@ gnutls_oqs_unload_library (void) - { - } - -+unsigned -+gnutls_oqs_is_usable (void) -+{ -+ /* The library is linked at build time, thus always usable */ -+ return 1; -+} -+ - #endif /* !GNUTLS_OQS_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/oqs.h b/lib/dlwrap/oqs.h -index 6a1d8e0766..1cf5d015a5 100644 ---- a/lib/dlwrap/oqs.h -+++ b/lib/dlwrap/oqs.h -@@ -50,4 +50,11 @@ int gnutls_oqs_ensure_library (const char *soname, int flags); - */ - void gnutls_oqs_unload_library (void); - -+/* Return 1 if the library is loaded and usable. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+unsigned gnutls_oqs_is_usable (void); -+ - #endif /* GNUTLS_LIB_DLWRAP_OQS_H_ */ -diff --git a/lib/dlwrap/zlib.c b/lib/dlwrap/zlib.c -index 878070c0a4..19851513a9 100644 ---- a/lib/dlwrap/zlib.c -+++ b/lib/dlwrap/zlib.c -@@ -128,10 +128,13 @@ gnutls_zlib_ensure_library (const char *soname, int flags) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" - --#define FUNC(ret, name, args, cargs) \ -- err = ENSURE_SYMBOL(name); \ -- if (err < 0) \ -- return err; -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ { \ -+ gnutls_zlib_dlhandle = NULL; \ -+ return err; \ -+ } - #define VOID_FUNC FUNC - #include "zlibfuncs.h" - #undef VOID_FUNC -@@ -165,6 +168,12 @@ gnutls_zlib_unload_library (void) - #pragma GCC diagnostic pop - } - -+unsigned -+gnutls_zlib_is_usable (void) -+{ -+ return gnutls_zlib_dlhandle != NULL; -+} -+ - #else /* GNUTLS_ZLIB_ENABLE_DLOPEN */ - - int -@@ -180,4 +189,11 @@ gnutls_zlib_unload_library (void) - { - } - -+unsigned -+gnutls_zlib_is_usable (void) -+{ -+ /* The library is linked at build time, thus always usable */ -+ return 1; -+} -+ - #endif /* !GNUTLS_ZLIB_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/zlib.h b/lib/dlwrap/zlib.h -index a9666d27f5..0d7113febf 100644 ---- a/lib/dlwrap/zlib.h -+++ b/lib/dlwrap/zlib.h -@@ -44,4 +44,11 @@ int gnutls_zlib_ensure_library (const char *soname, int flags); - */ - void gnutls_zlib_unload_library (void); - -+/* Return 1 if the library is loaded and usable. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+unsigned gnutls_zlib_is_usable (void); -+ - #endif /* GNUTLS_LIB_DLWRAP_ZLIB_H_ */ -diff --git a/lib/dlwrap/zstd.c b/lib/dlwrap/zstd.c -index 532c80b610..bd5153e464 100644 ---- a/lib/dlwrap/zstd.c -+++ b/lib/dlwrap/zstd.c -@@ -128,10 +128,13 @@ gnutls_zstd_ensure_library (const char *soname, int flags) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" - --#define FUNC(ret, name, args, cargs) \ -- err = ENSURE_SYMBOL(name); \ -- if (err < 0) \ -- return err; -+#define FUNC(ret, name, args, cargs) \ -+ err = ENSURE_SYMBOL(name); \ -+ if (err < 0) \ -+ { \ -+ gnutls_zstd_dlhandle = NULL; \ -+ return err; \ -+ } - #define VOID_FUNC FUNC - #include "zstdfuncs.h" - #undef VOID_FUNC -@@ -165,6 +168,12 @@ gnutls_zstd_unload_library (void) - #pragma GCC diagnostic pop - } - -+unsigned -+gnutls_zstd_is_usable (void) -+{ -+ return gnutls_zstd_dlhandle != NULL; -+} -+ - #else /* GNUTLS_ZSTD_ENABLE_DLOPEN */ - - int -@@ -180,4 +189,11 @@ gnutls_zstd_unload_library (void) - { - } - -+unsigned -+gnutls_zstd_is_usable (void) -+{ -+ /* The library is linked at build time, thus always usable */ -+ return 1; -+} -+ - #endif /* !GNUTLS_ZSTD_ENABLE_DLOPEN */ -diff --git a/lib/dlwrap/zstd.h b/lib/dlwrap/zstd.h -index 80ac2fbd46..4a68a45e37 100644 ---- a/lib/dlwrap/zstd.h -+++ b/lib/dlwrap/zstd.h -@@ -44,4 +44,11 @@ int gnutls_zstd_ensure_library (const char *soname, int flags); - */ - void gnutls_zstd_unload_library (void); - -+/* Return 1 if the library is loaded and usable. -+ * -+ * Note that this function is NOT thread-safe; when calling it from -+ * multi-threaded programs, protect it with a locking mechanism. -+ */ -+unsigned gnutls_zstd_is_usable (void); -+ - #endif /* GNUTLS_LIB_DLWRAP_ZSTD_H_ */ -diff --git a/lib/global.c b/lib/global.c -index 4aaf79a768..42d90ee9d5 100644 ---- a/lib/global.c -+++ b/lib/global.c -@@ -329,14 +329,6 @@ static int _gnutls_global_init(unsigned constructor) - goto out; - } - --#ifdef HAVE_LIBOQS -- ret = _gnutls_liboqs_init(); -- if (ret < 0) { -- gnutls_assert(); -- goto out; -- } --#endif -- - #ifndef _WIN32 - ret = _gnutls_register_fork_handler(); - if (ret < 0) { -diff --git a/lib/liboqs/liboqs.c b/lib/liboqs/liboqs.c -index c5531d4796..3c0df56644 100644 ---- a/lib/liboqs/liboqs.c -+++ b/lib/liboqs/liboqs.c -@@ -34,27 +34,59 @@ - #endif - - #include "errors.h" -+#include "locks.h" - - #include "dlwrap/oqs.h" - #include "liboqs/rand.h" - #include "liboqs/sha3.h" - --int _gnutls_liboqs_init(void) -+/* We can't use GNUTLS_ONCE here, as it wouldn't allow manual unloading */ -+GNUTLS_STATIC_MUTEX(liboqs_init_mutex); -+static int _liboqs_init = 0; -+ -+int _gnutls_liboqs_ensure(void) - { -+ int ret; -+ -+ if (_liboqs_init) -+ return GNUTLS_E_SUCCESS; -+ -+ ret = gnutls_static_mutex_lock(&liboqs_init_mutex); -+ if (unlikely(ret < 0)) -+ return gnutls_assert_val(ret); -+ - if (gnutls_oqs_ensure_library(OQS_LIBRARY_SONAME, -- RTLD_NOW | RTLD_GLOBAL) < 0) -- return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); -+ RTLD_NOW | RTLD_GLOBAL) < 0) { -+ _gnutls_debug_log( -+ "liboqs: unable to initialize liboqs functions\n"); -+ ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); -+ goto out; -+ } - - _gnutls_liboqs_sha3_init(); - GNUTLS_OQS_FUNC(OQS_init)(); - _gnutls_liboqs_rand_init(); -- return 0; -+ -+ _liboqs_init = 1; -+ ret = GNUTLS_E_SUCCESS; -+ -+out: -+ (void)gnutls_static_mutex_unlock(&liboqs_init_mutex); -+ -+ return ret; - } - -+/* This is not thread-safe: call this function only from -+ * gnutls_global_deinit, which has a proper protection. -+ */ - void _gnutls_liboqs_deinit(void) - { -- _gnutls_liboqs_rand_deinit(); -- _gnutls_liboqs_sha3_deinit(); -- GNUTLS_OQS_FUNC(OQS_destroy)(); -+ if (_liboqs_init) { -+ _gnutls_liboqs_rand_deinit(); -+ _gnutls_liboqs_sha3_deinit(); -+ GNUTLS_OQS_FUNC(OQS_destroy)(); -+ } -+ - gnutls_oqs_unload_library(); -+ _liboqs_init = 0; - } -diff --git a/lib/liboqs/liboqs.h b/lib/liboqs/liboqs.h -index 50206fa77c..3717454275 100644 ---- a/lib/liboqs/liboqs.h -+++ b/lib/liboqs/liboqs.h -@@ -21,7 +21,7 @@ - #ifndef GNUTLS_LIB_LIBOQS_LIBOQS_H - #define GNUTLS_LIB_LIBOQS_LIBOQS_H - --int _gnutls_liboqs_init(void); -+int _gnutls_liboqs_ensure(void); - void _gnutls_liboqs_deinit(void); - - #endif /* GNUTLS_LIB_LIBOQS_LIBOQS_H */ -diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c -index 4155a540ed..79f7988d50 100644 ---- a/lib/nettle/pk.c -+++ b/lib/nettle/pk.c -@@ -72,6 +72,7 @@ - #include "dh.h" - #ifdef HAVE_LIBOQS - #include "dlwrap/oqs.h" -+#include "liboqs/liboqs.h" - #endif - - static inline const struct ecc_curve *get_supported_nist_curve(int curve); -@@ -703,6 +704,9 @@ static int _wrap_nettle_pk_encaps(gnutls_pk_algorithm_t algo, - OQS_KEM *kem = NULL; - OQS_STATUS rc; - -+ if (_gnutls_liboqs_ensure() < 0) -+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); -+ - kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); - if (kem == NULL) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -@@ -761,6 +765,9 @@ static int _wrap_nettle_pk_decaps(gnutls_pk_algorithm_t algo, - OQS_KEM *kem = NULL; - OQS_STATUS rc; - -+ if (_gnutls_liboqs_ensure() < 0) -+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); -+ - kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); - if (kem == NULL) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); -@@ -2342,9 +2349,6 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk) - case GNUTLS_PK_RSA_PSS: - case GNUTLS_PK_RSA_OAEP: - case GNUTLS_PK_EDDSA_ED25519: --#ifdef HAVE_LIBOQS -- case GNUTLS_PK_EXP_KYBER768: --#endif - #if ENABLE_GOST - case GNUTLS_PK_GOST_01: - case GNUTLS_PK_GOST_12_256: -@@ -2353,6 +2357,10 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk) - case GNUTLS_PK_ECDH_X448: - case GNUTLS_PK_EDDSA_ED448: - return 1; -+#ifdef HAVE_LIBOQS -+ case GNUTLS_PK_EXP_KYBER768: -+ return _gnutls_liboqs_ensure() == 0; -+#endif - default: - return 0; - } -@@ -2986,11 +2994,15 @@ static int pct_test(gnutls_pk_algorithm_t algo, - } - case GNUTLS_PK_ECDH_X25519: - case GNUTLS_PK_ECDH_X448: -+ break; - #ifdef HAVE_LIBOQS - case GNUTLS_PK_EXP_KYBER768: -+ if (_gnutls_liboqs_ensure() < 0) { -+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); -+ goto cleanup; -+ } - #endif -- ret = 0; -- goto cleanup; -+ break; - default: - ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); - goto cleanup; -@@ -3724,6 +3736,13 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo, - OQS_KEM *kem = NULL; - OQS_STATUS rc; - -+#ifdef HAVE_LIBOQS -+ if (_gnutls_liboqs_ensure() < 0) { -+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); -+ goto cleanup; -+ } -+#endif -+ - not_approved = true; - - kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); -@@ -4017,7 +4036,9 @@ static int wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo, - } - #ifdef HAVE_LIBOQS - case GNUTLS_PK_EXP_KYBER768: -- ret = 0; -+ ret = _gnutls_liboqs_ensure(); -+ if (ret < 0) -+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); - break; - #endif - #if ENABLE_GOST --- -2.45.2 - -From dfac4bb0d96507a409e3c3434c04bd8f79ac479f Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Mon, 29 Jul 2024 08:40:34 +0900 -Subject: [PATCH 1/2] liboqs: check whether Kyber768 is compiled in - -In the default build configuration of liboqs 0.10.1, Kyber768 is -disabled. This adds a guard against it and skip tests if not -available. - -Signed-off-by: Daiki Ueno ---- - devel/dlwrap/oqs.syms | 1 + - lib/dlwrap/oqsfuncs.h | 1 + - lib/nettle/pk.c | 27 ++++++++++++++++++--------- - tests/pqc-hybrid-kx.sh | 4 ++++ - 4 files changed, 24 insertions(+), 9 deletions(-) - -diff --git a/devel/dlwrap/oqs.syms b/devel/dlwrap/oqs.syms -index 8f067b2dd3..413f887598 100644 ---- a/devel/dlwrap/oqs.syms -+++ b/devel/dlwrap/oqs.syms -@@ -1,6 +1,7 @@ - OQS_SHA3_set_callbacks - OQS_init - OQS_destroy -+OQS_KEM_alg_is_enabled - OQS_KEM_new - OQS_KEM_encaps - OQS_KEM_decaps -diff --git a/lib/dlwrap/oqsfuncs.h b/lib/dlwrap/oqsfuncs.h -index 95c1b083dc..4aa0ba4ab4 100644 ---- a/lib/dlwrap/oqsfuncs.h -+++ b/lib/dlwrap/oqsfuncs.h -@@ -7,6 +7,7 @@ VOID_FUNC(void, OQS_init, (void), ()) - VOID_FUNC(void, OQS_destroy, (void), ()) - VOID_FUNC(void, OQS_SHA3_set_callbacks, (struct OQS_SHA3_callbacks *new_callbacks), (new_callbacks)) - VOID_FUNC(void, OQS_randombytes_custom_algorithm, (void (*algorithm_ptr)(uint8_t *, size_t)), (algorithm_ptr)) -+FUNC(int, OQS_KEM_alg_is_enabled, (const char *method_name), (method_name)) - FUNC(OQS_KEM *, OQS_KEM_new, (const char *method_name), (method_name)) - FUNC(OQS_STATUS, OQS_KEM_keypair, (const OQS_KEM *kem, uint8_t *public_key, uint8_t *secret_key), (kem, public_key, secret_key)) - FUNC(OQS_STATUS, OQS_KEM_encaps, (const OQS_KEM *kem, uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key), (kem, ciphertext, shared_secret, public_key)) -diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c -index eb8c44459d..8a987ed121 100644 ---- a/lib/nettle/pk.c -+++ b/lib/nettle/pk.c -@@ -704,7 +704,9 @@ static int _wrap_nettle_pk_encaps(gnutls_pk_algorithm_t algo, - OQS_KEM *kem = NULL; - OQS_STATUS rc; - -- if (_gnutls_liboqs_ensure() < 0) -+ if (_gnutls_liboqs_ensure() < 0 || -+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)( -+ OQS_KEM_alg_kyber_768)) - return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); - - kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); -@@ -765,7 +767,9 @@ static int _wrap_nettle_pk_decaps(gnutls_pk_algorithm_t algo, - OQS_KEM *kem = NULL; - OQS_STATUS rc; - -- if (_gnutls_liboqs_ensure() < 0) -+ if (_gnutls_liboqs_ensure() < 0 || -+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)( -+ OQS_KEM_alg_kyber_768)) - return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); - - kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768); -@@ -2359,7 +2363,9 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk) - return 1; - #ifdef HAVE_LIBOQS - case GNUTLS_PK_EXP_KYBER768: -- return _gnutls_liboqs_ensure() == 0; -+ return _gnutls_liboqs_ensure() == 0 && -+ GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)( -+ OQS_KEM_alg_kyber_768); - #endif - default: - return 0; -@@ -2997,7 +3003,9 @@ static int pct_test(gnutls_pk_algorithm_t algo, - break; - #ifdef HAVE_LIBOQS - case GNUTLS_PK_EXP_KYBER768: -- if (_gnutls_liboqs_ensure() < 0) { -+ if (_gnutls_liboqs_ensure() < 0 || -+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)( -+ OQS_KEM_alg_kyber_768)) { - ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); - goto cleanup; - } -@@ -3736,12 +3744,12 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo, - OQS_KEM *kem = NULL; - OQS_STATUS rc; - --#ifdef HAVE_LIBOQS -- if (_gnutls_liboqs_ensure() < 0) { -+ if (_gnutls_liboqs_ensure() < 0 || -+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)( -+ OQS_KEM_alg_kyber_768)) { - ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); - goto cleanup; - } --#endif - - not_approved = true; - -@@ -4038,8 +4046,9 @@ static int wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo, - } - #ifdef HAVE_LIBOQS - case GNUTLS_PK_EXP_KYBER768: -- ret = _gnutls_liboqs_ensure(); -- if (ret < 0) -+ if (_gnutls_liboqs_ensure() < 0 || -+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)( -+ OQS_KEM_alg_kyber_768)) - ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); - break; - #endif -diff --git a/tests/pqc-hybrid-kx.sh b/tests/pqc-hybrid-kx.sh -index b587587bd2..6d47105fa0 100644 ---- a/tests/pqc-hybrid-kx.sh -+++ b/tests/pqc-hybrid-kx.sh -@@ -31,6 +31,10 @@ if ! test -x "${CLI}"; then - exit 77 - fi - -+if ! "${CLI}" --list | grep '^Public Key Systems: .*Kyber768.*' >/dev/null; then -+ exit 77 -+fi -+ - . "${srcdir}/scripts/common.sh" - testdir=`create_testdir pqc-hybrid-kx` - --- -2.45.2 - diff --git a/gnutls-3.8.6-nettle-rsa-oaep.patch b/gnutls-3.8.6-nettle-rsa-oaep.patch deleted file mode 100644 index d8f0b4b..0000000 --- a/gnutls-3.8.6-nettle-rsa-oaep.patch +++ /dev/null @@ -1,27 +0,0 @@ -From a9800309197fe5aef913944b2fc77164946f0689 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Tue, 23 Jul 2024 16:04:56 +0900 -Subject: [PATCH] build: link against libhogweed when checking - nettle_rsa_oaep_* - -Signed-off-by: Daiki Ueno ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index fb0aefe1f4..8b55808bd7 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -795,7 +795,7 @@ AM_CONDITIONAL([NEED_SIV_GCM], [test "$ac_cv_func_nettle_siv_gcm_encrypt_message - - # Check for RSA-OAEP - save_LIBS=$LIBS --LIBS="$LIBS $NETTLE_LIBS" -+LIBS="$LIBS $HOGWEED_LIBS $NETTLE_LIBS $GMP_LIBS" - AC_CHECK_FUNCS(nettle_rsa_oaep_sha256_encrypt) - LIBS=$save_LIBS - AM_CONDITIONAL([NEED_RSA_OAEP], [test "$ac_cv_func_nettle_rsa_oaep_sha256_encrypt" != yes]) --- -2.45.2 - diff --git a/gnutls-3.8.6-nettle-static.patch b/gnutls-3.8.6-nettle-static.patch deleted file mode 100644 index 837c602..0000000 --- a/gnutls-3.8.6-nettle-static.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/lib/Makefile.am b/lib/Makefile.am -index 0e89fdf..5179858 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -269,7 +269,7 @@ thirdparty_libadd += $(LIBTASN1_LIBS) - endif - - if ENABLE_NETTLE --thirdparty_libadd += $(NETTLE_LIBS) $(HOGWEED_LIBS) $(GMP_LIBS) -+thirdparty_libadd += $(HOGWEED_LIBS) $(NETTLE_LIBS) $(GMP_LIBS) - libgnutls_la_LIBADD += nettle/libcrypto.la - endif - diff --git a/gnutls-3.8.7-nettle-static.patch b/gnutls-3.8.7-nettle-static.patch deleted file mode 100644 index 2eda034..0000000 --- a/gnutls-3.8.7-nettle-static.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 558cf23853f6ad0537daff4613d316265857b7fd Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Wed, 21 Aug 2024 14:50:54 +0900 -Subject: [PATCH] fips: skip HMAC checks of nettle libraries when statically - linked - -Since commit b6e9b10347ed577a9a37b7b28e1a039c5f6ccb16, it is possible -to link Nettle libraries statically. In that case, FIPS integrity -checks against the Nettle shared libraries should be skipped as they -are not used by GnuTLS. - -Signed-off-by: Daiki Ueno ---- - lib/fips.c | 32 ++++++++++++++++++++++++-------- - lib/fipshmac.c | 12 ++++-------- - 2 files changed, 28 insertions(+), 16 deletions(-) - -diff --git a/lib/fips.c b/lib/fips.c -index e5fce6b1b9..dc86a44354 100644 ---- a/lib/fips.c -+++ b/lib/fips.c -@@ -157,14 +157,6 @@ void _gnutls_fips_mode_reset_zombie(void) - #define GNUTLS_LIBRARY_SONAME "none" - #endif - --#ifndef NETTLE_LIBRARY_SONAME --#define NETTLE_LIBRARY_SONAME "none" --#endif -- --#ifndef HOGWEED_LIBRARY_SONAME --#define HOGWEED_LIBRARY_SONAME "none" --#endif -- - #define HMAC_SIZE 32 - #define HMAC_ALGO GNUTLS_MAC_SHA256 - #define HMAC_FORMAT_VERSION 1 -@@ -177,8 +169,12 @@ struct hmac_entry { - struct hmac_file { - int version; - struct hmac_entry gnutls; -+#ifdef NETTLE_LIBRARY_SONAME - struct hmac_entry nettle; -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - struct hmac_entry hogweed; -+#endif - #ifdef GMP_LIBRARY_SONAME - struct hmac_entry gmp; - #endif -@@ -186,8 +182,12 @@ struct hmac_file { - - struct lib_paths { - char gnutls[GNUTLS_PATH_MAX]; -+#ifdef NETTLE_LIBRARY_SONAME - char nettle[GNUTLS_PATH_MAX]; -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - char hogweed[GNUTLS_PATH_MAX]; -+#endif - #ifdef GMP_LIBRARY_SONAME - char gmp[GNUTLS_PATH_MAX]; - #endif -@@ -250,10 +250,14 @@ static int handler(void *user, const char *section, const char *name, - } - } else if (!strcmp(section, GNUTLS_LIBRARY_SONAME)) { - return lib_handler(&p->gnutls, section, name, value); -+#ifdef NETTLE_LIBRARY_SONAME - } else if (!strcmp(section, NETTLE_LIBRARY_SONAME)) { - return lib_handler(&p->nettle, section, name, value); -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - } else if (!strcmp(section, HOGWEED_LIBRARY_SONAME)) { - return lib_handler(&p->hogweed, section, name, value); -+#endif - #ifdef GMP_LIBRARY_SONAME - } else if (!strcmp(section, GMP_LIBRARY_SONAME)) { - return lib_handler(&p->gmp, section, name, value); -@@ -403,10 +407,14 @@ static int callback(struct dl_phdr_info *info, size_t size, void *data) - - if (!strcmp(soname, GNUTLS_LIBRARY_SONAME)) - _gnutls_str_cpy(paths->gnutls, GNUTLS_PATH_MAX, path); -+#ifdef NETTLE_LIBRARY_SONAME - else if (!strcmp(soname, NETTLE_LIBRARY_SONAME)) - _gnutls_str_cpy(paths->nettle, GNUTLS_PATH_MAX, path); -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - else if (!strcmp(soname, HOGWEED_LIBRARY_SONAME)) - _gnutls_str_cpy(paths->hogweed, GNUTLS_PATH_MAX, path); -+#endif - #ifdef GMP_LIBRARY_SONAME - else if (!strcmp(soname, GMP_LIBRARY_SONAME)) - _gnutls_str_cpy(paths->gmp, GNUTLS_PATH_MAX, path); -@@ -423,14 +431,18 @@ static int load_lib_paths(struct lib_paths *paths) - _gnutls_debug_log("Gnutls library path was not found\n"); - return gnutls_assert_val(GNUTLS_E_FILE_ERROR); - } -+#ifdef NETTLE_LIBRARY_SONAME - if (paths->nettle[0] == '\0') { - _gnutls_debug_log("Nettle library path was not found\n"); - return gnutls_assert_val(GNUTLS_E_FILE_ERROR); - } -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - if (paths->hogweed[0] == '\0') { - _gnutls_debug_log("Hogweed library path was not found\n"); - return gnutls_assert_val(GNUTLS_E_FILE_ERROR); - } -+#endif - #ifdef GMP_LIBRARY_SONAME - if (paths->gmp[0] == '\0') { - _gnutls_debug_log("Gmp library path was not found\n"); -@@ -483,12 +495,16 @@ static int check_binary_integrity(void) - ret = check_lib_hmac(&hmac.gnutls, paths.gnutls); - if (ret < 0) - return ret; -+#ifdef NETTLE_LIBRARY_SONAME - ret = check_lib_hmac(&hmac.nettle, paths.nettle); - if (ret < 0) - return ret; -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - ret = check_lib_hmac(&hmac.hogweed, paths.hogweed); - if (ret < 0) - return ret; -+#endif - #ifdef GMP_LIBRARY_SONAME - ret = check_lib_hmac(&hmac.gmp, paths.gmp); - if (ret < 0) -diff --git a/lib/fipshmac.c b/lib/fipshmac.c -index d3561b4c47..5c3202c561 100644 ---- a/lib/fipshmac.c -+++ b/lib/fipshmac.c -@@ -40,14 +40,6 @@ - #define GNUTLS_LIBRARY_SONAME "none" - #endif - --#ifndef NETTLE_LIBRARY_SONAME --#define NETTLE_LIBRARY_SONAME "none" --#endif -- --#ifndef HOGWEED_LIBRARY_SONAME --#define HOGWEED_LIBRARY_SONAME "none" --#endif -- - #define HMAC_SIZE 32 - #define HMAC_ALGO GNUTLS_MAC_SHA256 - #define HMAC_STR_SIZE (2 * HMAC_SIZE + 1) -@@ -117,10 +109,14 @@ static int callback(struct dl_phdr_info *info, size_t size, void *data) - - if (!strcmp(soname, GNUTLS_LIBRARY_SONAME)) - return print_lib(data ? data : path, soname); -+#ifdef NETTLE_LIBRARY_SONAME - if (!strcmp(soname, NETTLE_LIBRARY_SONAME)) - return print_lib(path, soname); -+#endif -+#ifdef HOGWEED_LIBRARY_SONAME - if (!strcmp(soname, HOGWEED_LIBRARY_SONAME)) - return print_lib(path, soname); -+#endif - #ifdef GMP_LIBRARY_SONAME - if (!strcmp(soname, GMP_LIBRARY_SONAME)) - return print_lib(path, soname); --- -2.46.0 - diff --git a/gnutls-3.8.7-pkgconf-dlopen.patch b/gnutls-3.8.7-pkgconf-dlopen.patch deleted file mode 100644 index 2adcae7..0000000 --- a/gnutls-3.8.7-pkgconf-dlopen.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 292f96f26d7ce80e4a165c903c4fd569b85c1c1f Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Fri, 16 Aug 2024 09:42:15 +0900 -Subject: [PATCH 1/2] build: fix setting AM_CONDITIONAL for brotli and zstd - -As the with_{libbrotli,libzsttd} variables are unset if configured -with --without-{brotli,zstd}, check the unequality to "no" doesn't -work; use explicit matching with "yes" instead. - -Signed-off-by: Daiki Ueno ---- - configure.ac | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 95ec4c1515..a476176800 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1158,7 +1158,7 @@ if test x$ac_brotli != xno; then - else - AC_MSG_RESULT(no) - fi --AM_CONDITIONAL(HAVE_LIBBROTLI, test "$with_libbrotlienc" != "no" && test "$with_libbrotlidec" != "no") -+AM_CONDITIONAL(HAVE_LIBBROTLI, test "$with_libbrotlienc" = yes && test "$with_libbrotlidec" = yes) - - AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ - save_CFLAGS=$CFLAGS -@@ -1203,7 +1203,7 @@ if test x$ac_zstd != xno; then - else - AC_MSG_RESULT(no) - fi --AM_CONDITIONAL(HAVE_LIBZSTD, test "$with_libzstd" != "no") -+AM_CONDITIONAL(HAVE_LIBZSTD, test "$with_libzstd" = yes) - - AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ - save_CFLAGS=$CFLAGS --- -2.46.0 - - -From 546153198d2fb8fc4902f23de6254bb7988de534 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Fri, 16 Aug 2024 09:48:31 +0900 -Subject: [PATCH 2/2] build: don't emit Requires.private for dlopened libraries - -Signed-off-by: Daiki Ueno ---- - configure.ac | 36 +++++++++++++++++++++--------------- - 1 file changed, 21 insertions(+), 15 deletions(-) - -diff --git a/configure.ac b/configure.ac -index a476176800..f3e7a3aeae 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1100,11 +1100,6 @@ if test x$ac_zlib != xno; then - PKG_CHECK_EXISTS(zlib, ZLIB_HAS_PKGCONFIG=y, ZLIB_HAS_PKGCONFIG=n) - if test "$ZLIB_HAS_PKGCONFIG" = "y" ; then - PKG_CHECK_MODULES(ZLIB, [zlib]) -- if test "x$GNUTLS_REQUIRES_PRIVATE" = x; then -- GNUTLS_REQUIRES_PRIVATE="Requires.private: zlib" -- else -- GNUTLS_REQUIRES_PRIVATE="$GNUTLS_REQUIRES_PRIVATE, zlib" -- fi - ac_zlib=yes - else - AC_LIB_HAVE_LINKFLAGS(z,, [#include ], [compress (0, 0, 0, 0);]) -@@ -1134,6 +1129,13 @@ AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ - compress (0, 0, 0, 0);])]) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -+], -+ [test "$ZLIB_HAS_PKGCONFIG" = y && test "$ac_zlib" = yes], [ -+ if test "x$GNUTLS_REQUIRES_PRIVATE" = x; then -+ GNUTLS_REQUIRES_PRIVATE="Requires.private: zlib" -+ else -+ GNUTLS_REQUIRES_PRIVATE="$GNUTLS_REQUIRES_PRIVATE, zlib" -+ fi - ]) - - AC_ARG_WITH(brotli, -@@ -1146,11 +1148,6 @@ if test x$ac_brotli != xno; then - PKG_CHECK_MODULES(LIBBROTLIDEC, [libbrotlidec >= 1.0.0], [with_libbrotlidec=yes], [with_libbrotlidec=no]) - if test "${with_libbrotlienc}" = "yes" && test "${with_libbrotlidec}" = "yes"; then - AC_DEFINE([HAVE_LIBBROTLI], 1, [Define if BROTLI compression is enabled.]) -- if test "x$GNUTLS_REQUIRES_PRIVATE" = "x"; then -- GNUTLS_REQUIRES_PRIVATE="Requires.private: libbrotlienc, libbrotlidec" -- else -- GNUTLS_REQUIRES_PRIVATE="${GNUTLS_REQUIRES_PRIVATE}, libbrotlienc, libbrotlidec" -- fi - need_ltlibdl=yes - else - AC_MSG_WARN(*** LIBBROTLI was not found. You will not be able to use BROTLI compression.) -@@ -1180,6 +1177,13 @@ AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ - BrotliDecoderVersion();])]) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -+], -+ [test "$with_libbrotlienc" = yes && test "$with_libbrotlidec" = yes], [ -+ if test "x$GNUTLS_REQUIRES_PRIVATE" = "x"; then -+ GNUTLS_REQUIRES_PRIVATE="Requires.private: libbrotlienc, libbrotlidec" -+ else -+ GNUTLS_REQUIRES_PRIVATE="${GNUTLS_REQUIRES_PRIVATE}, libbrotlienc, libbrotlidec" -+ fi - ]) - - AC_ARG_WITH(zstd, -@@ -1191,11 +1195,6 @@ if test x$ac_zstd != xno; then - PKG_CHECK_MODULES(LIBZSTD, [libzstd >= 1.3.0], [with_libzstd=yes], [with_libzstd=no]) - if test "${with_libzstd}" = "yes"; then - AC_DEFINE([HAVE_LIBZSTD], 1, [Define if ZSTD compression is enabled.]) -- if test "x$GNUTLS_REQUIRES_PRIVATE" = "x"; then -- GNUTLS_REQUIRES_PRIVATE="Requires.private: libzstd" -- else -- GNUTLS_REQUIRES_PRIVATE="${GNUTLS_REQUIRES_PRIVATE}, libzstd" -- fi - need_ltlibdl=yes - else - AC_MSG_WARN(*** LIBZSTD was not found. You will not be able to use ZSTD compression.) -@@ -1215,6 +1214,13 @@ AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ - ZSTD_versionNumber();])]) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -+], -+ [test "$with_libzstd" = yes], [ -+ if test "x$GNUTLS_REQUIRES_PRIVATE" = "x"; then -+ GNUTLS_REQUIRES_PRIVATE="Requires.private: libzstd" -+ else -+ GNUTLS_REQUIRES_PRIVATE="${GNUTLS_REQUIRES_PRIVATE}, libzstd" -+ fi - ]) - - AC_ARG_WITH(liboqs, --- -2.46.0 - -From 8d0ec0ccdfeaae0d56426169d4c7b490e3b07826 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Fri, 16 Aug 2024 13:35:47 +0900 -Subject: [PATCH] build: add liboqs in Requires.private in gnutls.pc if needed - -When --with-liboqs is specified and liboqs cannot be dlopen'ed, it -will be linked at build time. In that case gnutls.pc should indicate -that through Requires.private. - -Signed-off-by: Daiki Ueno ---- - configure.ac | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/configure.ac b/configure.ac -index f3e7a3aeae..93ba723323 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1256,6 +1256,13 @@ AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [ - OQS_version ();])]) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -+], -+ [test "$have_liboqs" = yes], [ -+ if test "x$GNUTLS_REQUIRES_PRIVATE" = x; then -+ GNUTLS_REQUIRES_PRIVATE="Requires.private: liboqs" -+ else -+ GNUTLS_REQUIRES_PRIVATE="$GNUTLS_REQUIRES_PRIVATE, liboqs" -+ fi - ]) - - AM_CONDITIONAL(NEED_LTLIBDL, test "$need_ltlibdl" = yes) --- -2.46.0 - diff --git a/gnutls-3.8.9-cli-earlydata.patch b/gnutls-3.8.9-cli-earlydata.patch deleted file mode 100644 index 783c5b1..0000000 --- a/gnutls-3.8.9-cli-earlydata.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 54c06a9cd7bcf8f245cf5f9da760f91939259f69 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sun, 16 Feb 2025 09:02:46 +0900 -Subject: [PATCH 1/3] serv: fix detection of early data reception - -Upon success, gnutls_record_recv_early_data returns the amount of data -received, so the application should treat positive numbers as an -indication of early data reception. - -Signed-off-by: Daiki Ueno ---- - src/serv.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/serv.c b/src/serv.c -index 17db12c5ca..86008c9523 100644 ---- a/src/serv.c -+++ b/src/serv.c -@@ -1690,7 +1690,7 @@ static void tcp_server(const char *name, int port, int timeout) - GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - j->earlydata_eof = 1; - } -- if (r == 0) { -+ if (r >= 0) { - earlydata_read = 1; - } - } --- -2.49.0 - - -From 8c488288ea05a759977dccd4ee4d61610da4dc38 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Mon, 17 Mar 2025 09:00:44 +0900 -Subject: [PATCH 2/3] cli: send early data only after session data is set - -Now that max_early_data_size is recorded as part of the stored -resumption data, this needs to be read before attempting to send early -data. - -Signed-off-by: Daiki Ueno ---- - src/socket.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/src/socket.c b/src/socket.c -index 48784b67fa..f32910c239 100644 ---- a/src/socket.c -+++ b/src/socket.c -@@ -580,6 +580,11 @@ void socket_open_int(socket_st *hd, const char *hostname, const char *service, - } - - if (hd->session) { -+ if (hd->rdata.data) { -+ gnutls_session_set_data(hd->session, -+ hd->rdata.data, -+ hd->rdata.size); -+ } - if (hd->edata.data) { - ret = gnutls_record_send_early_data( - hd->session, hd->edata.data, -@@ -591,11 +596,6 @@ void socket_open_int(socket_st *hd, const char *hostname, const char *service, - exit(1); - } - } -- if (hd->rdata.data) { -- gnutls_session_set_data(hd->session, -- hd->rdata.data, -- hd->rdata.size); -- } - - if (client_trace || server_trace) { - hd->server_trace = server_trace; --- -2.49.0 - - -From 56fa5e1901fe40a97553cf3141a4d205c4286702 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sun, 16 Feb 2025 09:04:50 +0900 -Subject: [PATCH 3/3] tests: add basic tests for 0-RTT with gnutls-serv and - gnutls-cli - -Signed-off-by: Daiki Ueno ---- - tests/Makefile.am | 2 +- - tests/gnutls-cli-earlydata.sh | 84 +++++++++++++++++++++++++++++++++++ - 2 files changed, 85 insertions(+), 1 deletion(-) - create mode 100755 tests/gnutls-cli-earlydata.sh - -diff --git a/tests/Makefile.am b/tests/Makefile.am -index ec8fd982c5..72926e9da4 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -546,7 +546,7 @@ dist_check_SCRIPTS += fastopen.sh pkgconfig.sh starttls.sh starttls-ftp.sh start - sni-resume.sh ocsp-tests/ocsptool.sh cert-reencoding.sh pkcs7-cat.sh long-crl.sh \ - serv-udp.sh logfile-option.sh gnutls-cli-resume.sh profile-tests.sh \ - server-weak-keys.sh ocsp-tests/ocsp-signer-verify.sh cfg-test.sh \ -- sanity-lib.sh -+ sanity-lib.sh gnutls-cli-earlydata.sh - - if !DISABLE_SYSTEM_CONFIG - dist_check_SCRIPTS += system-override-sig.sh system-override-hash.sh \ -diff --git a/tests/gnutls-cli-earlydata.sh b/tests/gnutls-cli-earlydata.sh -new file mode 100755 -index 0000000000..72763f029f ---- /dev/null -+++ b/tests/gnutls-cli-earlydata.sh -@@ -0,0 +1,84 @@ -+#!/bin/sh -+ -+# Copyright (C) 2025 Red Hat, Inc. -+# -+# Author: Daiki Ueno -+# -+# 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 -+# -+ -+: ${srcdir=.} -+: ${SERV=../src/gnutls-serv${EXEEXT}} -+: ${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 -n "$VALGRIND"; then -+ VALGRIND="${LIBTOOL:-libtool} --mode=execute $VALGRIND --error-exitcode=1" -+fi -+ -+SERV="$SERV -q" -+ -+. "$srcdir/scripts/common.sh" -+ -+: ${ac_cv_sizeof_time_t=8} -+if test "$ac_cv_sizeof_time_t" -ge 8; then -+ ATTIME_VALID="2038-10-12" # almost the pregenerated cert expiration -+else -+ ATTIME_VALID="2030-12-17" # end of epoch − 2590 days of validity -+fi -+ -+testdir=`create_testdir earlydata` -+KEY="$srcdir/../doc/credentials/x509/key-ecc.pem" -+CERT="$srcdir/../doc/credentials/x509/cert-ecc.pem" -+CACERT="$srcdir/../doc/credentials/x509/ca.pem" -+ -+eval "$GETPORT" -+launch_server --echo --x509keyfile "$KEY" --x509certfile "$CERT" --disable-client-cert --earlydata --maxearlydata 1000 -+PID=$! -+wait_server "$PID" -+ -+echo "This is a test message" > "$testdir/earlydata.txt" -+ -+$VALGRIND "$CLI" --attime="$ATTIME_VALID" -p "$PORT" localhost --logfile="$testdir/cli.log" --priority="NORMAL:-VERS-ALL:+VERS-TLS1.3" --x509cafile "$CACERT" --resume --waitresumption --earlydata="$testdir/earlydata.txt" "$testdir/cli.out" -+if test $? -ne 0; then -+ cat "$testdir/cli.log" -+ fail "$PID" "failed to communicate with the server" -+fi -+ -+if ! grep "This is a resumed session" "$testdir/cli.log" > /dev/null; then -+ fail "$PID" "session is not resumed" -+fi -+ -+if ! cmp "$testdir/earlydata.txt" "$testdir/cli.out" > /dev/null; then -+ fail "$PID" "early data has not been sent back" -+fi -+ -+kill "$PID" -+wait -+ -+exit 0 --- -2.49.0 - diff --git a/gnutls-3.8.9-leancrypto-init.patch b/gnutls-3.8.9-leancrypto-init.patch deleted file mode 100644 index 80f5dd8..0000000 --- a/gnutls-3.8.9-leancrypto-init.patch +++ /dev/null @@ -1,43 +0,0 @@ -From b33c2f1f372f0f985be5c398021aad8a5532855e Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Wed, 19 Mar 2025 18:29:55 +0900 -Subject: [PATCH] global: call lc_init at startup - -When leancrypto is statically linked, their constructor will not be -called and which prevents some low-level algorithms being -functional. This adds a manual initialization with lc_init() at the -startup of the GnuTLS library. - -Suggested-by: Stephan Mueller -Signed-off-by: Daiki Ueno ---- - lib/global.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/lib/global.c b/lib/global.c -index 42d90ee9d5..dc80e6302d 100644 ---- a/lib/global.c -+++ b/lib/global.c -@@ -42,6 +42,9 @@ - #include "str.h" - #include "global.h" - #include "liboqs/liboqs.h" -+#ifdef HAVE_LEANCRYPTO -+#include -+#endif - - /* Minimum library versions we accept. */ - #define GNUTLS_MIN_LIBTASN1_VERSION "0.3.4" -@@ -366,6 +369,9 @@ static int _gnutls_global_init(unsigned constructor) - _gnutls_register_accel_crypto(); - _gnutls_cryptodev_init(); - _gnutls_afalg_init(); -+#ifdef HAVE_LEANCRYPTO -+ lc_init(0); -+#endif - - #ifdef ENABLE_FIPS140 - /* These self tests are performed on the overridden algorithms --- -2.49.0 - diff --git a/gnutls-3.8.9-limit-shuffle-extensions.patch b/gnutls-3.8.9-limit-shuffle-extensions.patch deleted file mode 100644 index 8526252..0000000 --- a/gnutls-3.8.9-limit-shuffle-extensions.patch +++ /dev/null @@ -1,213 +0,0 @@ -From dc5ee80c3a28577e9de0f82fb08164e4c02b96af Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Sun, 9 Feb 2025 10:31:20 +0900 -Subject: [PATCH] handshake: only shuffle extensions in the first Client Hello - -RFC 8446 section 4.1.2 states that the second Client Hello after HRR -should preserve the same content as the first Client Hello with -limited exceptions. Since GnuTLS 3.8.5, however, the library started -shuffling the order of extensions for privacy reasons and that didn't -comply with the RFC, leading to a connectivity issue against the -server configuration with a stricter check on that. - -Signed-off-by: Daiki Ueno ---- - lib/gnutls_int.h | 4 +++ - lib/hello_ext.c | 41 ++++++++++++++++--------- - lib/state.c | 2 ++ - tests/tls13/hello_retry_request.c | 51 ++++++++++++++++++++++++++++--- - 4 files changed, 79 insertions(+), 19 deletions(-) - -diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h -index d10a028b59..572de5aba3 100644 ---- a/lib/gnutls_int.h -+++ b/lib/gnutls_int.h -@@ -1666,6 +1666,10 @@ typedef struct { - /* Compression method for certificate compression */ - gnutls_compression_method_t compress_certificate_method; - -+ /* To shuffle extension sending order */ -+ extensions_t client_hello_exts[MAX_EXT_TYPES]; -+ bool client_hello_exts_set; -+ - /* If you add anything here, check _gnutls_handshake_internal_state_clear(). - */ - } internals_st; -diff --git a/lib/hello_ext.c b/lib/hello_ext.c -index 40af8c2b10..d677addd75 100644 ---- a/lib/hello_ext.c -+++ b/lib/hello_ext.c -@@ -438,8 +438,6 @@ int _gnutls_gen_hello_extensions(gnutls_session_t session, - int pos, ret; - size_t i; - hello_ext_ctx_st ctx; -- /* To shuffle extension sending order */ -- extensions_t indices[MAX_EXT_TYPES]; - - msg &= GNUTLS_EXT_FLAG_SET_ONLY_FLAGS_MASK; - -@@ -469,26 +467,39 @@ int _gnutls_gen_hello_extensions(gnutls_session_t session, - ret - 4); - } - -- /* Initializing extensions array */ -- for (i = 0; i < MAX_EXT_TYPES; i++) { -- indices[i] = i; -- } -+ if (msg & GNUTLS_EXT_FLAG_CLIENT_HELLO && -+ !session->internals.client_hello_exts_set) { -+ /* Initializing extensions array */ -+ for (i = 0; i < MAX_EXT_TYPES; i++) { -+ session->internals.client_hello_exts[i] = i; -+ } - -- if (!session->internals.priorities->no_shuffle_extensions) { -- /* Ordering padding and pre_shared_key as last extensions */ -- swap_exts(indices, MAX_EXT_TYPES - 2, GNUTLS_EXTENSION_DUMBFW); -- swap_exts(indices, MAX_EXT_TYPES - 1, -- GNUTLS_EXTENSION_PRE_SHARED_KEY); -+ if (!session->internals.priorities->no_shuffle_extensions) { -+ /* Ordering padding and pre_shared_key as last extensions */ -+ swap_exts(session->internals.client_hello_exts, -+ MAX_EXT_TYPES - 2, GNUTLS_EXTENSION_DUMBFW); -+ swap_exts(session->internals.client_hello_exts, -+ MAX_EXT_TYPES - 1, -+ GNUTLS_EXTENSION_PRE_SHARED_KEY); - -- ret = shuffle_exts(indices, MAX_EXT_TYPES - 2); -- if (ret < 0) -- return gnutls_assert_val(ret); -+ ret = shuffle_exts(session->internals.client_hello_exts, -+ MAX_EXT_TYPES - 2); -+ if (ret < 0) -+ return gnutls_assert_val(ret); -+ } -+ session->internals.client_hello_exts_set = true; - } - - /* hello_ext_send() ensures we don't send duplicates, in case - * of overridden extensions */ - for (i = 0; i < MAX_EXT_TYPES; i++) { -- size_t ii = indices[i]; -+ size_t ii; -+ -+ if (msg & GNUTLS_EXT_FLAG_CLIENT_HELLO) -+ ii = session->internals.client_hello_exts[i]; -+ else -+ ii = i; -+ - if (!extfunc[ii]) - continue; - -diff --git a/lib/state.c b/lib/state.c -index 9d3ece7570..43e961cfa2 100644 ---- a/lib/state.c -+++ b/lib/state.c -@@ -516,6 +516,8 @@ static void handshake_internal_state_clear1(gnutls_session_t session) - - session->internals.hrr_cs[0] = CS_INVALID_MAJOR; - session->internals.hrr_cs[1] = CS_INVALID_MINOR; -+ -+ session->internals.client_hello_exts_set = false; - } - - /* This function will clear all the variables in internals -diff --git a/tests/tls13/hello_retry_request.c b/tests/tls13/hello_retry_request.c -index f407b64234..6c5f698f01 100644 ---- a/tests/tls13/hello_retry_request.c -+++ b/tests/tls13/hello_retry_request.c -@@ -51,14 +51,37 @@ static void tls_log_func(int level, const char *str) - } - - #define HANDSHAKE_SESSION_ID_POS 34 -+#define MAX_EXT_TYPES 64 - - struct ctx_st { - unsigned hrr_seen; - unsigned hello_counter; - uint8_t session_id[32]; - size_t session_id_len; -+ unsigned extensions[MAX_EXT_TYPES]; -+ size_t extensions_size1; -+ size_t extensions_size2; - }; - -+static int ext_callback(void *_ctx, unsigned tls_id, const unsigned char *data, -+ unsigned size) -+{ -+ struct ctx_st *ctx = _ctx; -+ if (ctx->hello_counter == 0) { -+ assert(ctx->extensions_size1 < MAX_EXT_TYPES); -+ ctx->extensions[ctx->extensions_size1++] = tls_id; -+ } else { -+ assert(ctx->extensions_size2 < MAX_EXT_TYPES); -+ if (tls_id != ctx->extensions[ctx->extensions_size2]) { -+ fail("extension doesn't match at position %zu, %u != %u\n", -+ ctx->extensions_size2, tls_id, -+ ctx->extensions[ctx->extensions_size2]); -+ } -+ ctx->extensions_size2++; -+ } -+ return 0; -+} -+ - static int hello_callback(gnutls_session_t session, unsigned int htype, - unsigned post, unsigned int incoming, - const gnutls_datum_t *msg) -@@ -73,15 +96,25 @@ static int hello_callback(gnutls_session_t session, unsigned int htype, - post == GNUTLS_HOOK_POST) { - size_t session_id_len; - uint8_t *session_id; -+ unsigned pos = HANDSHAKE_SESSION_ID_POS; -+ gnutls_datum_t mmsg; -+ int ret; - -- assert(msg->size > HANDSHAKE_SESSION_ID_POS + 1); -- session_id_len = msg->data[HANDSHAKE_SESSION_ID_POS]; -- session_id = &msg->data[HANDSHAKE_SESSION_ID_POS + 1]; -+ assert(msg->size > pos + 1); -+ session_id_len = msg->data[pos]; -+ session_id = &msg->data[pos + 1]; -+ -+ SKIP8(pos, msg->size); -+ SKIP16(pos, msg->size); -+ SKIP8(pos, msg->size); -+ -+ mmsg.data = &msg->data[pos]; -+ mmsg.size = msg->size - pos; - - if (ctx->hello_counter > 0) { - assert(msg->size > 4); - if (msg->data[0] != 0x03 || msg->data[1] != 0x03) { -- fail("version is %d.%d expected 3,3\n", -+ fail("version is %d.%d expected 3.3\n", - (int)msg->data[0], (int)msg->data[1]); - } - -@@ -95,6 +128,12 @@ static int hello_callback(gnutls_session_t session, unsigned int htype, - ctx->session_id_len = session_id_len; - memcpy(ctx->session_id, session_id, session_id_len); - -+ ret = gnutls_ext_raw_parse(ctx, ext_callback, &mmsg, 0); -+ if (ret < 0) { -+ fail("unable to parse extensions: %s\n", -+ gnutls_strerror(ret)); -+ } -+ - ctx->hello_counter++; - } - -@@ -164,6 +203,10 @@ void doit(void) - myfail("group doesn't match the expected: %s\n", - gnutls_group_get_name(gnutls_group_get(server))); - -+ if (ctx.extensions_size1 != ctx.extensions_size2) -+ myfail("the number of extensions don't match in second Client Hello: %zu != %zu\n", -+ ctx.extensions_size1, ctx.extensions_size2); -+ - gnutls_bye(client, GNUTLS_SHUT_WR); - gnutls_bye(server, GNUTLS_SHUT_WR); - --- -2.48.1 - diff --git a/gnutls-3.8.9-year2038-tests.patch b/gnutls-3.8.9-year2038-tests.patch deleted file mode 100644 index 5803e9b..0000000 --- a/gnutls-3.8.9-year2038-tests.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 54a42b44522986b8fab2081c2f18026b44f3c0b1 Mon Sep 17 00:00:00 2001 -From: Daiki Ueno -Date: Thu, 13 Feb 2025 16:23:07 +0900 -Subject: [PATCH] tests: make pqc-hybrid-kx.sh work when system time set beyond - 2038 - -Signed-off-by: Daiki Ueno ---- - tests/pqc-hybrid-kx.sh | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/tests/pqc-hybrid-kx.sh b/tests/pqc-hybrid-kx.sh -index f67b07c45b..9174a3d5bc 100644 ---- a/tests/pqc-hybrid-kx.sh -+++ b/tests/pqc-hybrid-kx.sh -@@ -33,6 +33,13 @@ fi - - . "${srcdir}/scripts/common.sh" - -+: ${ac_cv_sizeof_time_t=8} -+if test "${ac_cv_sizeof_time_t}" -ge 8; then -+ ATTIME_VALID="2038-10-12" # almost the pregenerated cert expiration -+else -+ ATTIME_VALID="2030-12-17" # end of epoch − 2590 days of validity -+fi -+ - # First check any mismatch in the gnutls-cli --list - if ! "${CLI}" --list | grep '^Groups: .*GROUP-X25519-KYBER768.*' >/dev/null; then - if "${CLI}" --list | grep '^Public Key Systems: .*KYBER768.*' >/dev/null; then -@@ -93,7 +100,7 @@ for group in X25519-KYBER768 SECP256R1-MLKEM768 SECP384R1-MLKEM1024 X25519-MLKEM - PID=$! - wait_server ${PID} - -- ${VALGRIND} "${CLI}" -p "${PORT}" localhost --priority "NORMAL:-GROUP-ALL:+GROUP-$group" --x509cafile="$CACERT" --logfile="$testdir/cli.log" -Date: Thu, 8 May 2025 12:34:21 +0200 -Subject: [PATCH] ARMv8: properly save/restore SIMD register v8 through v15 - -Those registers are used by ML-DSA and ML-KEM. - -Signed-off-by: Stephan Mueller ---- - internal/api/armv8_helper.h | 67 ++++++++++++ - ml-dsa/src/armv8/dilithium_signature_armv8.c | 101 +++++++++++++++++-- - ml-kem/src/armv8/kyber_indcpa_armv8.c | 13 +++ - 4 files changed, 173 insertions(+), 10 deletions(-) - create mode 100644 internal/api/armv8_helper.h - -diff --git a/internal/api/armv8_helper.h b/internal/api/armv8_helper.h -new file mode 100644 -index 00000000..456f3239 ---- /dev/null -+++ b/internal/api/armv8_helper.h -@@ -0,0 +1,67 @@ -+/* -+ * Copyright (C) 2025, Stephan Mueller -+ * -+ * License: see LICENSE file in root directory -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ */ -+ -+#ifndef ARMV8_HELPER_H -+#define ARMV8_HELPER_H -+ -+#include "ext_headers.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * The ARMv8 Kyber implementation uses the SIMD registers v8 through v15 which -+ * must be preserved by the callee. -+ * -+ * Store only the lower 64 bits of the FP registers v8 through v15 according to -+ * https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#612simd-and-floating-point-registers -+ */ -+static inline void store_fp_regs(uint64_t tmp[8]) -+{ -+ __asm__ volatile("mov %0, v8.d[0]" : "=r"(tmp[0]) : : "memory" ); -+ __asm__ volatile("mov %0, v9.d[0]" : "=r"(tmp[1]) : : "memory" ); -+ __asm__ volatile("mov %0, v10.d[0]" : "=r"(tmp[2]) : : "memory" ); -+ __asm__ volatile("mov %0, v11.d[0]" : "=r"(tmp[3]) : : "memory" ); -+ __asm__ volatile("mov %0, v12.d[0]" : "=r"(tmp[4]) : : "memory" ); -+ __asm__ volatile("mov %0, v13.d[0]" : "=r"(tmp[5]) : : "memory" ); -+ __asm__ volatile("mov %0, v14.d[0]" : "=r"(tmp[6]) : : "memory" ); -+ __asm__ volatile("mov %0, v15.d[0]" : "=r"(tmp[7]) : : "memory" ); -+} -+ -+/* -+ * Reload the stored register content into the SIMD registers -+ */ -+static inline void reload_fp_regs(uint64_t tmp[8]) -+{ -+ __asm__ volatile("mov v8.d[0], %0" : : "r"(tmp[0]) : "memory" ); -+ __asm__ volatile("mov v9.d[0], %0" : : "r"(tmp[1]) : "memory" ); -+ __asm__ volatile("mov v10.d[0], %0" : : "r"(tmp[2]) : "memory" ); -+ __asm__ volatile("mov v11.d[0], %0" : : "r"(tmp[3]) : "memory" ); -+ __asm__ volatile("mov v12.d[0], %0" : : "r"(tmp[4]) : "memory" ); -+ __asm__ volatile("mov v13.d[0], %0" : : "r"(tmp[5]) : "memory" ); -+ __asm__ volatile("mov v14.d[0], %0" : : "r"(tmp[6]) : "memory" ); -+ __asm__ volatile("mov v15.d[0], %0" : : "r"(tmp[7]) : "memory" ); -+} -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* ARMV8_HELPER_H */ -diff --git a/ml-dsa/src/armv8/dilithium_signature_armv8.c b/ml-dsa/src/armv8/dilithium_signature_armv8.c -index a661ffe9..5bc64387 100644 ---- a/ml-dsa/src/armv8/dilithium_signature_armv8.c -+++ b/ml-dsa/src/armv8/dilithium_signature_armv8.c -@@ -17,6 +17,7 @@ - * DAMAGE. - */ - -+#include "armv8_helper.h" - #include "dilithium_type.h" - #include "dilithium_signature_armv8.h" - #include "visibility.h" -@@ -36,14 +37,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_from_seed_armv8, - struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk, - const uint8_t *seed, size_t seedlen) - { -- return lc_dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_armv8, - struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk, - struct lc_rng_ctx *rng_ctx) - { -- return lc_dilithium_keypair_impl(pk, sk, rng_ctx); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_keypair_impl(pk, sk, rng_ctx); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_armv8, -@@ -51,7 +68,15 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_armv8, - size_t mlen, const struct lc_dilithium_sk *sk, - struct lc_rng_ctx *rng_ctx) - { -- return lc_dilithium_sign_impl(sig, m, mlen, sk, rng_ctx); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_sign_impl(sig, m, mlen, sk, rng_ctx); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_armv8, -@@ -60,14 +85,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_armv8, - size_t mlen, const struct lc_dilithium_sk *sk, - struct lc_rng_ctx *rng_ctx) - { -- return lc_dilithium_sign_ctx_impl(sig, ctx, m, mlen, sk, rng_ctx); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_sign_ctx_impl(sig, ctx, m, mlen, sk, rng_ctx); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_init_armv8, - struct lc_dilithium_ctx *ctx, - const struct lc_dilithium_sk *sk) - { -- return lc_dilithium_sign_init_impl(ctx, sk); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_sign_init_impl(ctx, sk); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_update_armv8, -@@ -83,14 +124,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_final_armv8, - const struct lc_dilithium_sk *sk, - struct lc_rng_ctx *rng_ctx) - { -- return lc_dilithium_sign_final_impl(sig, ctx, sk, rng_ctx); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_sign_final_impl(sig, ctx, sk, rng_ctx); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_armv8, - const struct lc_dilithium_sig *sig, const uint8_t *m, - size_t mlen, const struct lc_dilithium_pk *pk) - { -- return lc_dilithium_verify_impl(sig, m, mlen, pk); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_verify_impl(sig, m, mlen, pk); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_armv8, -@@ -98,14 +155,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_armv8, - struct lc_dilithium_ctx *ctx, const uint8_t *m, - size_t mlen, const struct lc_dilithium_pk *pk) - { -- return lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_init_armv8, - struct lc_dilithium_ctx *ctx, - const struct lc_dilithium_pk *pk) - { -- return lc_dilithium_verify_init_impl(ctx, pk); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_verify_init_impl(ctx, pk); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } - - LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_update_armv8, -@@ -120,5 +193,13 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_final_armv8, - struct lc_dilithium_ctx *ctx, - const struct lc_dilithium_pk *pk) - { -- return lc_dilithium_verify_final_impl(sig, ctx, pk); -+ uint64_t saved_regs[8]; -+ int ret; -+ -+ store_fp_regs(saved_regs); -+ ret = lc_dilithium_verify_final_impl(sig, ctx, pk); -+ reload_fp_regs(saved_regs); -+ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); -+ -+ return ret; - } -diff --git a/ml-kem/src/armv8/kyber_indcpa_armv8.c b/ml-kem/src/armv8/kyber_indcpa_armv8.c -index 26b797d8..d6289d73 100644 ---- a/ml-kem/src/armv8/kyber_indcpa_armv8.c -+++ b/ml-kem/src/armv8/kyber_indcpa_armv8.c -@@ -23,6 +23,7 @@ - * That code is released under MIT license. - */ - -+#include "armv8_helper.h" - #include "build_bug_on.h" - #include "kyber_indcpa_armv8.h" - #include "kyber_poly_armv8.h" -@@ -229,6 +230,7 @@ int indcpa_keypair_armv8(uint8_t pk[LC_KYBER_INDCPA_PUBLICKEYBYTES], - uint8_t buf[2 * LC_KYBER_SYMBYTES]; - uint8_t poly_getnoise_eta1_buf[POLY_GETNOISE_ETA1_BUFSIZE]; - polyvec a[LC_KYBER_K], e, pkpv, skpv; -+ uint64_t saved_regs[8]; - }; - static const uint8_t kval = LC_KYBER_K; - unsigned int i; -@@ -239,6 +241,8 @@ int indcpa_keypair_armv8(uint8_t pk[LC_KYBER_INDCPA_PUBLICKEYBYTES], - LC_HASH_CTX_ON_STACK(sha3_512_ctx, lc_sha3_512); - LC_DECLARE_MEM(ws, struct workspace, 32); - -+ store_fp_regs(ws->saved_regs); -+ - buf = ws->buf; - publicseed = ws->buf; - noiseseed = ws->buf + LC_KYBER_SYMBYTES; -@@ -282,6 +286,7 @@ int indcpa_keypair_armv8(uint8_t pk[LC_KYBER_INDCPA_PUBLICKEYBYTES], - unpoison(pk, LC_KYBER_INDCPA_PUBLICKEYBYTES); - - out: -+ reload_fp_regs(ws->saved_regs); - LC_RELEASE_MEM(ws); - return ret; - } -@@ -299,12 +304,15 @@ int indcpa_enc_armv8(uint8_t c[LC_KYBER_INDCPA_BYTES], - //uint8_t poly_getnoise_eta2_buf[POLY_GETNOISE_ETA2_BUFSIZE]; - polyvec sp, pkpv, ep, at[LC_KYBER_K], b; - poly v, k, epp; -+ uint64_t saved_regs[8]; - }; - unsigned int i; - uint8_t nonce = 0, nonce2 = LC_KYBER_K; - int ret; - LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t)); - -+ store_fp_regs(ws->saved_regs); -+ - /* - * Use the poly_getnoise_eta1_buf for this operation as seed is smaller - * than poly_getnoise_eta1_buf and has the same alignment. -@@ -354,6 +362,7 @@ int indcpa_enc_armv8(uint8_t c[LC_KYBER_INDCPA_BYTES], - pack_ciphertext(c, &ws->b, &ws->v); - - out: -+ reload_fp_regs(ws->saved_regs); - LC_RELEASE_MEM(ws); - return ret; - } -@@ -365,9 +374,12 @@ int indcpa_dec_armv8(uint8_t m[LC_KYBER_INDCPA_MSGBYTES], - struct workspace { - polyvec b, skpv; - poly v, mp; -+ uint64_t saved_regs[8]; - }; - LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t)); - -+ store_fp_regs(ws->saved_regs); -+ - unpack_sk(&ws->skpv, sk); - - /* Validate input */ -@@ -386,6 +398,7 @@ int indcpa_dec_armv8(uint8_t m[LC_KYBER_INDCPA_MSGBYTES], - - poly_tomsg(m, &ws->mp); - -+ reload_fp_regs(ws->saved_regs); - LC_RELEASE_MEM(ws); - return 0; - }