public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/openssl] rebase_40beta: - Synchorize patches in CentOS 10 and Fedora with the following changes
@ 2026-06-09 12:45 Sahana Prasad
  0 siblings, 0 replies; only message in thread
From: Sahana Prasad @ 2026-06-09 12:45 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/openssl
            Branch : rebase_40beta
            Commit : 2a66dc637de1930e06a318267f73de025245f76a
            Author : Sahana Prasad <sahana@redhat.com>
            Date   : 2024-09-12T15:56:27+02:00
            Stats  : +4702/-237 in 20 file(s)
            URL    : https://src.fedoraproject.org/rpms/openssl/c/2a66dc637de1930e06a318267f73de025245f76a?branch=rebase_40beta

            Log:
            - Synchorize patches in CentOS 10 and Fedora with the following changes
- Fix CVE-2024-5535: SSL_select_next_proto buffer overread
- Use PBMAC1 by default when creating PKCS#12 files in FIPS mode
- Support key encapsulation/decapsulation in openssl pkeyutl command
- Fix typo in the patch numeration
- Enable KTLS, temporary disable KTLS tests
- Speedup SSL_add_{file,dir}_cert_subjects_to_stack
- Resolve SAST package scan results
- An interface to create PKCS #12 files in FIPS compliant way

Signed-off-by: Sahana Prasad <sahana@redhat.com>

---
diff --git a/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch b/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch
index 3b3a772..5189459 100644
--- a/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch
+++ b/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch
@@ -226,10 +226,11 @@ index 8360991ce4..33c23efb0d 100644
      }
  
      /*
-@@ -1611,7 +1667,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx,
+@@ -1611,8 +1667,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx,
+     num_of_alias_max = num_of_ciphers + num_of_group_aliases + 1;
      ca_list = OPENSSL_malloc(sizeof(*ca_list) * num_of_alias_max);
      if (ca_list == NULL) {
-         OPENSSL_free(co_list);
+-        OPENSSL_free(co_list);
 -        return NULL;          /* Failure */
 +        goto err;
      }

diff --git a/0123-kdf-Preserve-backward-compatibility-with-older-provi.patch b/0123-kdf-Preserve-backward-compatibility-with-older-provi.patch
new file mode 100644
index 0000000..85f97c6
--- /dev/null
+++ b/0123-kdf-Preserve-backward-compatibility-with-older-provi.patch
@@ -0,0 +1,62 @@
+From a4daab0c29bce044d385bdeada177a88c32cba4c Mon Sep 17 00:00:00 2001
+From: Tomas Mraz <tomas@openssl.org>
+Date: Mon, 17 Jun 2024 16:48:26 +0200
+Subject: [PATCH] Fix regression of EVP_PKEY_CTX_add1_hkdf_info() with older
+ providers
+
+If there is no get_ctx_params() implemented in the key exchange
+provider implementation the fallback will not work. Instead
+check the gettable_ctx_params() to see if the fallback should be
+performed.
+
+Fixes #24611
+
+Reviewed-by: Paul Dale <ppzgs1@gmail.com>
+Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com>
+(Merged from https://github.com/openssl/openssl/pull/24661)
+
+(cherry picked from commit 663dbc9c9c897392a9f9d18aa9a8400ca024dc5d)
+---
+ crypto/evp/pmeth_lib.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
+index 2caff2cd6d..d15e43be05 100644
+--- a/crypto/evp/pmeth_lib.c
++++ b/crypto/evp/pmeth_lib.c
+@@ -1026,6 +1026,7 @@ static int evp_pkey_ctx_add1_octet_string(EVP_PKEY_CTX *ctx, int fallback,
+                                           int datalen)
+ {
+     OSSL_PARAM os_params[2];
++    const OSSL_PARAM *gettables;
+     unsigned char *info = NULL;
+     size_t info_len = 0;
+     size_t info_alloc = 0;
+@@ -1049,6 +1050,12 @@ static int evp_pkey_ctx_add1_octet_string(EVP_PKEY_CTX *ctx, int fallback,
+         return 1;
+     }
+ 
++    /* Check for older provider that doesn't support getting this parameter */
++    gettables = EVP_PKEY_CTX_gettable_params(ctx);
++    if (gettables == NULL || OSSL_PARAM_locate_const(gettables, param) == NULL)
++        return evp_pkey_ctx_set1_octet_string(ctx, fallback, param, op, ctrl,
++                                              data, datalen);
++
+     /* Get the original value length */
+     os_params[0] = OSSL_PARAM_construct_octet_string(param, NULL, 0);
+     os_params[1] = OSSL_PARAM_construct_end();
+@@ -1056,9 +1063,9 @@ static int evp_pkey_ctx_add1_octet_string(EVP_PKEY_CTX *ctx, int fallback,
+     if (!EVP_PKEY_CTX_get_params(ctx, os_params))
+         return 0;
+ 
+-    /* Older provider that doesn't support getting this parameter */
++    /* This should not happen but check to be sure. */
+     if (os_params[0].return_size == OSSL_PARAM_UNMODIFIED)
+-        return evp_pkey_ctx_set1_octet_string(ctx, fallback, param, op, ctrl, data, datalen);
++        return 0;
+ 
+     info_alloc = os_params[0].return_size + datalen;
+     if (info_alloc == 0)
+-- 
+2.45.1
+

diff --git a/0124-PBMAC1-PKCS12-FIPS-support.patch b/0124-PBMAC1-PKCS12-FIPS-support.patch
new file mode 100644
index 0000000..6e1cc96
--- /dev/null
+++ b/0124-PBMAC1-PKCS12-FIPS-support.patch
@@ -0,0 +1,1525 @@
+From d959252c47af0eb0dd55bc032606901fedaf029b Mon Sep 17 00:00:00 2001
+From: Dmitry Belyavskiy <beldmit@gmail.com>
+Date: Fri, 7 Jun 2024 14:37:57 +0200
+Subject: [PATCH 1/4] Implementation of the RFC 9579, PBMAC1 in PKCS#12
+
+---
+ apps/pkcs12.c               |  63 ++++++--
+ crypto/asn1/p5_pbev2.c      |   7 +
+ crypto/evp/digest.c         |  54 +++++++
+ crypto/pkcs12/p12_mutl.c    | 296 ++++++++++++++++++++++++++++++++----
+ include/crypto/evp.h        |   3 +
+ include/openssl/pkcs12.h.in |   3 +
+ include/openssl/x509.h.in   |  15 +-
+ 7 files changed, 394 insertions(+), 47 deletions(-)
+
+diff --git a/apps/pkcs12.c b/apps/pkcs12.c
+index 54323a9713393..cbe133742a8be 100644
+--- a/apps/pkcs12.c
++++ b/apps/pkcs12.c
+@@ -70,7 +70,7 @@ typedef enum OPTION_choice {
+     OPT_NAME, OPT_CSP, OPT_CANAME,
+     OPT_IN, OPT_OUT, OPT_PASSIN, OPT_PASSOUT, OPT_PASSWORD, OPT_CAPATH,
+     OPT_CAFILE, OPT_CASTORE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_ENGINE,
+-    OPT_R_ENUM, OPT_PROV_ENUM, OPT_JDKTRUST,
++    OPT_R_ENUM, OPT_PROV_ENUM, OPT_JDKTRUST, OPT_PBMAC1_PBKDF2, OPT_PBMAC1_PBKDF2_MD,
+ #ifndef OPENSSL_NO_DES
+     OPT_LEGACY_ALG
+ #endif
+@@ -147,6 +147,8 @@ const OPTIONS pkcs12_options[] = {
+ #endif
+     {"macalg", OPT_MACALG, 's',
+      "Digest algorithm to use in MAC (default SHA256)"},
++    {"pbmac1_pbkdf2", OPT_PBMAC1_PBKDF2, '-', "Use PBMAC1 with PBKDF2 instead of MAC"},
++    {"pbmac1_pbkdf2_md", OPT_PBMAC1_PBKDF2_MD, 's', "Digest to use for PBMAC1 KDF (default SHA256)"},
+     {"iter", OPT_ITER, 'p', "Specify the iteration count for encryption and MAC"},
+     {"noiter", OPT_NOITER, '-', "Don't use encryption iteration"},
+     {"nomaciter", OPT_NOMACITER, '-', "Don't use MAC iteration)"},
+@@ -170,14 +172,14 @@ int pkcs12_main(int argc, char **argv)
+     int use_legacy = 0;
+ #endif
+     /* use library defaults for the iter, maciter, cert, and key PBE */
+-    int iter = 0, maciter = 0;
++    int iter = 0, maciter = 0, pbmac1_pbkdf2 = 0;
+     int macsaltlen = PKCS12_SALT_LEN;
+     int cert_pbe = NID_undef;
+     int key_pbe = NID_undef;
+     int ret = 1, macver = 1, add_lmk = 0, private = 0;
+     int noprompt = 0;
+     char *passinarg = NULL, *passoutarg = NULL, *passarg = NULL;
+-    char *passin = NULL, *passout = NULL, *macalg = NULL;
++    char *passin = NULL, *passout = NULL, *macalg = NULL, *pbmac1_pbkdf2_md = NULL;
+     char *cpass = NULL, *mpass = NULL, *badpass = NULL;
+     const char *CApath = NULL, *CAfile = NULL, *CAstore = NULL, *prog;
+     int noCApath = 0, noCAfile = 0, noCAstore = 0;
+@@ -283,6 +285,12 @@ int pkcs12_main(int argc, char **argv)
+         case OPT_MACALG:
+             macalg = opt_arg();
+             break;
++        case OPT_PBMAC1_PBKDF2:
++            pbmac1_pbkdf2 = 1;
++            break;
++        case OPT_PBMAC1_PBKDF2_MD:
++            pbmac1_pbkdf2_md = opt_arg();
++            break;
+         case OPT_CERTPBE:
+             if (!set_pbe(&cert_pbe, opt_arg()))
+                 goto opthelp;
+@@ -700,10 +708,20 @@ int pkcs12_main(int argc, char **argv)
+         }
+ 
+         if (maciter != -1) {
+-            if (!PKCS12_set_mac(p12, mpass, -1, NULL, macsaltlen, maciter, macmd)) {
+-                BIO_printf(bio_err, "Error creating PKCS12 MAC; no PKCS12KDF support?\n");
+-                BIO_printf(bio_err, "Use -nomac if MAC not required and PKCS12KDF support not available.\n");
+-                goto export_end;
++            if (pbmac1_pbkdf2 == 1) {
++                if (!PKCS12_set_pbmac1_pbkdf2(p12, mpass, -1, NULL,
++                                              macsaltlen, maciter,
++                                              macmd, pbmac1_pbkdf2_md)) {
++                    BIO_printf(bio_err, "Error creating PBMAC1\n");
++                    goto export_end;
++                }
++            } else {
++                if (!PKCS12_set_mac(p12, mpass, -1, NULL, macsaltlen, maciter, macmd)) {
++                    BIO_printf(bio_err, "Error creating PKCS12 MAC; no PKCS12KDF support?\n");
++                    BIO_printf(bio_err,
++                               "Use -nomac or -pbmac1_pbkdf2 if PKCS12KDF support not available\n");
++                    goto export_end;
++                }
+             }
+         }
+         assert(private);
+@@ -774,23 +792,54 @@ int pkcs12_main(int argc, char **argv)
+         X509_ALGOR_get0(&macobj, NULL, NULL, macalgid);
+         BIO_puts(bio_err, "MAC: ");
+         i2a_ASN1_OBJECT(bio_err, macobj);
+-        BIO_printf(bio_err, ", Iteration %ld\n",
+-                   tmaciter != NULL ? ASN1_INTEGER_get(tmaciter) : 1L);
+-        BIO_printf(bio_err, "MAC length: %ld, salt length: %ld\n",
+-                   tmac != NULL ? ASN1_STRING_length(tmac) : 0L,
+-                   tsalt != NULL ? ASN1_STRING_length(tsalt) : 0L);
++        if (OBJ_obj2nid(macobj) == NID_pbmac1) {
++            PBKDF2PARAM *pbkdf2_param = PBMAC1_get1_pbkdf2_param(macalgid);
++
++            if (pbkdf2_param == NULL) {
++                BIO_printf(bio_err, ", Unsupported KDF or params for PBMAC1\n");
++            } else {
++                const ASN1_OBJECT *prfobj;
++
++                BIO_printf(bio_err, " using PBKDF2, Iteration %ld\n",
++                           ASN1_INTEGER_get(pbkdf2_param->iter));
++                BIO_printf(bio_err, "Key length: %ld, Salt length: %d\n",
++                           ASN1_INTEGER_get(pbkdf2_param->keylength),
++                           ASN1_STRING_length(pbkdf2_param->salt->value.octet_string));
++                X509_ALGOR_get0(&prfobj, NULL, NULL, pbkdf2_param->prf);
++                BIO_printf(bio_err, "PBKDF2 PRF: ");
++                i2a_ASN1_OBJECT(bio_err, prfobj);
++                BIO_printf(bio_err, "\n");
++            }
++            PBKDF2PARAM_free(pbkdf2_param);
++        } else {
++            BIO_printf(bio_err, ", Iteration %ld\n",
++                       tmaciter != NULL ? ASN1_INTEGER_get(tmaciter) : 1L);
++            BIO_printf(bio_err, "MAC length: %ld, salt length: %ld\n",
++                       tmac != NULL ? ASN1_STRING_length(tmac) : 0L,
++                       tsalt != NULL ? ASN1_STRING_length(tsalt) : 0L);
++        }
+     }
++
+     if (macver) {
+-        EVP_KDF *pkcs12kdf;
++        const X509_ALGOR *macalgid;
++        const ASN1_OBJECT *macobj;
+ 
+-        pkcs12kdf = EVP_KDF_fetch(app_get0_libctx(), "PKCS12KDF",
+-                                  app_get0_propq());
+-        if (pkcs12kdf == NULL) {
+-            BIO_printf(bio_err, "Error verifying PKCS12 MAC; no PKCS12KDF support.\n");
+-            BIO_printf(bio_err, "Use -nomacver if MAC verification is not required.\n");
+-            goto end;
++        PKCS12_get0_mac(NULL, &macalgid, NULL, NULL, p12);
++        X509_ALGOR_get0(&macobj, NULL, NULL, macalgid);
++
++        if (OBJ_obj2nid(macobj) != NID_pbmac1) {
++            EVP_KDF *pkcs12kdf;
++
++            pkcs12kdf = EVP_KDF_fetch(app_get0_libctx(), "PKCS12KDF",
++                                      app_get0_propq());
++            if (pkcs12kdf == NULL) {
++                BIO_printf(bio_err, "Error verifying PKCS12 MAC; no PKCS12KDF support.\n");
++                BIO_printf(bio_err, "Use -nomacver if MAC verification is not required.\n");
++                goto end;
++            }
++            EVP_KDF_free(pkcs12kdf);
+         }
+-        EVP_KDF_free(pkcs12kdf);
++
+         /* If we enter empty password try no password first */
+         if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) {
+             /* If mac and crypto pass the same set it to NULL too */
+diff --git a/crypto/asn1/p5_pbev2.c b/crypto/asn1/p5_pbev2.c
+index 8575d05bf6d5a..c22cc6b77075d 100644
+--- a/crypto/asn1/p5_pbev2.c
++++ b/crypto/asn1/p5_pbev2.c
+@@ -35,6 +35,13 @@ ASN1_SEQUENCE(PBKDF2PARAM) = {
+ 
+ IMPLEMENT_ASN1_FUNCTIONS(PBKDF2PARAM)
+ 
++ASN1_SEQUENCE(PBMAC1PARAM) = {
++    ASN1_SIMPLE(PBMAC1PARAM, keyDerivationFunc, X509_ALGOR),
++    ASN1_SIMPLE(PBMAC1PARAM, messageAuthScheme, X509_ALGOR)
++} ASN1_SEQUENCE_END(PBMAC1PARAM)
++
++IMPLEMENT_ASN1_FUNCTIONS(PBMAC1PARAM)
++
+ /*
+  * Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm: yes I know
+  * this is horrible! Extended version to allow application supplied PRF NID
+diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
+index 18a64329b7a35..a74e2fa42c5bb 100644
+--- a/crypto/evp/digest.c
++++ b/crypto/evp/digest.c
+@@ -20,6 +20,7 @@
+ #include <openssl/params.h>
+ #include <openssl/core_names.h>
+ #include "internal/cryptlib.h"
++#include "internal/nelem.h"
+ #include "internal/provider.h"
+ #include "internal/core.h"
+ #include "crypto/evp.h"
+@@ -1185,3 +1186,56 @@ void EVP_MD_do_all_provided(OSSL_LIB_CTX *libctx,
+                        (void (*)(void *, void *))fn, arg,
+                        evp_md_from_algorithm, evp_md_up_ref, evp_md_free);
+ }
++
++typedef struct {
++    int md_nid;
++    int hmac_nid;
++} ossl_hmacmd_pair;
++
++static const ossl_hmacmd_pair ossl_hmacmd_pairs[] = {
++    {NID_sha1, NID_hmacWithSHA1},
++    {NID_md5, NID_hmacWithMD5},
++    {NID_sha224, NID_hmacWithSHA224},
++    {NID_sha256, NID_hmacWithSHA256},
++    {NID_sha384, NID_hmacWithSHA384},
++    {NID_sha512, NID_hmacWithSHA512},
++    {NID_id_GostR3411_94, NID_id_HMACGostR3411_94},
++    {NID_id_GostR3411_2012_256, NID_id_tc26_hmac_gost_3411_2012_256},
++    {NID_id_GostR3411_2012_512, NID_id_tc26_hmac_gost_3411_2012_512},
++    {NID_sha3_224, NID_hmac_sha3_224},
++    {NID_sha3_256, NID_hmac_sha3_256},
++    {NID_sha3_384, NID_hmac_sha3_384},
++    {NID_sha3_512, NID_hmac_sha3_512},
++    {NID_sha512_224, NID_hmacWithSHA512_224},
++    {NID_sha512_256, NID_hmacWithSHA512_256}
++};
++
++int ossl_hmac2mdnid(int hmac_nid)
++{
++    int md_nid = NID_undef;
++    size_t i;
++
++    for (i = 0; i < OSSL_NELEM(ossl_hmacmd_pairs); i++) {
++        if (ossl_hmacmd_pairs[i].hmac_nid == hmac_nid) {
++            md_nid = ossl_hmacmd_pairs[i].md_nid;
++            break;
++        }
++    }
++
++    return md_nid;
++}
++
++int ossl_md2hmacnid(int md_nid)
++{
++    int hmac_nid = NID_undef;
++    size_t i;
++
++    for (i = 0; i < OSSL_NELEM(ossl_hmacmd_pairs); i++) {
++        if (ossl_hmacmd_pairs[i].md_nid == md_nid) {
++            hmac_nid = ossl_hmacmd_pairs[i].hmac_nid;
++            break;
++        }
++    }
++
++    return hmac_nid;
++}
+diff --git a/crypto/pkcs12/p12_mutl.c b/crypto/pkcs12/p12_mutl.c
+index 4091e61d9dd06..d410978a49e1e 100644
+--- a/crypto/pkcs12/p12_mutl.c
++++ b/crypto/pkcs12/p12_mutl.c
+@@ -15,12 +15,19 @@
+ 
+ #include <stdio.h>
+ #include "internal/cryptlib.h"
++#include "crypto/evp.h"
+ #include <openssl/crypto.h>
+ #include <openssl/hmac.h>
+ #include <openssl/rand.h>
+ #include <openssl/pkcs12.h>
+ #include "p12_local.h"
+ 
++static int pkcs12_pbmac1_pbkdf2_key_gen(const char *pass, int passlen,
++                                        unsigned char *salt, int saltlen,
++                                        int id, int iter, int keylen,
++                                        unsigned char *out,
++                                        const EVP_MD *md_type);
++
+ int PKCS12_mac_present(const PKCS12 *p12)
+ {
+     return p12->mac ? 1 : 0;
+@@ -72,9 +79,76 @@ static int pkcs12_gen_gost_mac_key(const char *pass, int passlen,
+     return 1;
+ }
+ 
+-/* Generate a MAC */
++PBKDF2PARAM *PBMAC1_get1_pbkdf2_param(const X509_ALGOR *macalg)
++{
++    PBMAC1PARAM *param = NULL;
++    PBKDF2PARAM *pbkdf2_param = NULL;
++    const ASN1_OBJECT *kdf_oid;
++
++    param = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBMAC1PARAM), macalg->parameter);
++    if (param == NULL) {
++        ERR_raise(ERR_LIB_PKCS12, ERR_R_PASSED_INVALID_ARGUMENT);
++        return NULL;
++    }
++
++    X509_ALGOR_get0(&kdf_oid, NULL, NULL, param->keyDerivationFunc);
++    if (OBJ_obj2nid(kdf_oid) != NID_id_pbkdf2) {
++        ERR_raise(ERR_LIB_PKCS12, ERR_R_PASSED_INVALID_ARGUMENT);
++        PBMAC1PARAM_free(param);
++        return NULL;
++    }
++
++    pbkdf2_param = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBKDF2PARAM),
++                                             param->keyDerivationFunc->parameter);
++    PBMAC1PARAM_free(param);
++
++    return pbkdf2_param;
++}
++
++static int PBMAC1_PBKDF2_HMAC(OSSL_LIB_CTX *ctx, const char *propq,
++                              const char *pass, int passlen,
++                              const X509_ALGOR *macalg, unsigned char *key)
++{
++    PBKDF2PARAM *pbkdf2_param = NULL;
++    const ASN1_OBJECT *kdf_hmac_oid;
++    int ret = -1;
++    int keylen = 0;
++    EVP_MD *kdf_md = NULL;
++    const ASN1_OCTET_STRING *pbkdf2_salt = NULL;
++
++    pbkdf2_param = PBMAC1_get1_pbkdf2_param(macalg);
++    if (pbkdf2_param == NULL) {
++        ERR_raise(ERR_LIB_PKCS12, ERR_R_UNSUPPORTED);
++        goto err;
++    }
++    keylen = ASN1_INTEGER_get(pbkdf2_param->keylength);
++    pbkdf2_salt = pbkdf2_param->salt->value.octet_string;
++    X509_ALGOR_get0(&kdf_hmac_oid, NULL, NULL, pbkdf2_param->prf);
++
++    kdf_md = EVP_MD_fetch(ctx, OBJ_nid2sn(ossl_hmac2mdnid(OBJ_obj2nid(kdf_hmac_oid))), propq);
++    if (kdf_md == NULL) {
++        ERR_raise(ERR_LIB_PKCS12, ERR_R_FETCH_FAILED);
++        goto err;
++    }
++
++    if (PKCS5_PBKDF2_HMAC(pass, passlen, pbkdf2_salt->data, pbkdf2_salt->length,
++                          ASN1_INTEGER_get(pbkdf2_param->iter), kdf_md, keylen, key) <= 0) {
++        ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++    ret = keylen;
++
++ err:
++    EVP_MD_free(kdf_md);
++    PBKDF2PARAM_free(pbkdf2_param);
++
++    return ret;
++}
++
++/* Generate a MAC, also used for verification */
+ static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
+                           unsigned char *mac, unsigned int *maclen,
++                          int pbmac1_md_nid, int pbmac1_kdf_nid,
+                           int (*pkcs12_key_gen)(const char *pass, int passlen,
+                                                 unsigned char *salt, int slen,
+                                                 int id, int iter, int n,
+@@ -88,8 +162,8 @@ static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
+     unsigned char key[EVP_MAX_MD_SIZE], *salt;
+     int saltlen, iter;
+     char md_name[80];
+-    int md_size = 0;
+-    int md_nid;
++    int keylen = 0;
++    int md_nid = NID_undef;
+     const X509_ALGOR *macalg;
+     const ASN1_OBJECT *macoid;
+ 
+@@ -111,9 +185,13 @@ static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
+         iter = ASN1_INTEGER_get(p12->mac->iter);
+     X509_SIG_get0(p12->mac->dinfo, &macalg, NULL);
+     X509_ALGOR_get0(&macoid, NULL, NULL, macalg);
+-    if (OBJ_obj2txt(md_name, sizeof(md_name), macoid, 0) < 0)
+-        return 0;
+-
++    if (OBJ_obj2nid(macoid) == NID_pbmac1) {
++        if (OBJ_obj2txt(md_name, sizeof(md_name), OBJ_nid2obj(pbmac1_md_nid), 0) < 0)
++            return 0;
++    } else {
++        if (OBJ_obj2txt(md_name, sizeof(md_name), macoid, 0) < 0)
++            return 0;
++    }
+     (void)ERR_set_mark();
+     md = md_fetch = EVP_MD_fetch(p12->authsafes->ctx.libctx, md_name,
+                                  p12->authsafes->ctx.propq);
+@@ -127,40 +205,61 @@ static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
+     }
+     (void)ERR_pop_to_mark();
+ 
+-    md_size = EVP_MD_get_size(md);
++    keylen = EVP_MD_get_size(md);
+     md_nid = EVP_MD_get_type(md);
+-    if (md_size < 0)
++    if (keylen < 0)
+         goto err;
+-    if ((md_nid == NID_id_GostR3411_94
+-         || md_nid == NID_id_GostR3411_2012_256
+-         || md_nid == NID_id_GostR3411_2012_512)
+-        && ossl_safe_getenv("LEGACY_GOST_PKCS12") == NULL) {
+-        md_size = TK26_MAC_KEY_LEN;
++
++    /* For PBMAC1 we use a special keygen callback if not provided (e.g. on verification) */
++    if (pbmac1_md_nid != NID_undef && pkcs12_key_gen == NULL) {
++        keylen = PBMAC1_PBKDF2_HMAC(p12->authsafes->ctx.libctx, p12->authsafes->ctx.propq,
++                                    pass, passlen, macalg, key);
++        if (keylen < 0)
++            goto err;
++    } else if ((md_nid == NID_id_GostR3411_94
++                || md_nid == NID_id_GostR3411_2012_256
++                || md_nid == NID_id_GostR3411_2012_512)
++               && ossl_safe_getenv("LEGACY_GOST_PKCS12") == NULL) {
++        keylen = TK26_MAC_KEY_LEN;
+         if (!pkcs12_gen_gost_mac_key(pass, passlen, salt, saltlen, iter,
+-                                     md_size, key, md)) {
++                                     keylen, key, md)) {
+             ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR);
+             goto err;
+         }
+     } else {
++        EVP_MD *hmac_md = (EVP_MD *)md;
++        int fetched = 0;
++
++        if (pbmac1_kdf_nid != NID_undef) {
++            char hmac_md_name[128];
++
++            if (OBJ_obj2txt(hmac_md_name, sizeof(hmac_md_name), OBJ_nid2obj(pbmac1_kdf_nid), 0) < 0)
++                goto err;
++            hmac_md = EVP_MD_fetch(NULL, hmac_md_name, NULL);
++            fetched = 1;
++        }
+         if (pkcs12_key_gen != NULL) {
+-            if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_MAC_ID,
+-                                   iter, md_size, key, md)) {
++            int res = (*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_MAC_ID,
++                                        iter, keylen, key, hmac_md);
++
++            if (fetched)
++                EVP_MD_free(hmac_md);
++            if (res != 1) {
+                 ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR);
+                 goto err;
+             }
+         } else {
+             /* Default to UTF-8 password */
+             if (!PKCS12_key_gen_utf8_ex(pass, passlen, salt, saltlen, PKCS12_MAC_ID,
+-                                       iter, md_size, key, md,
+-                                       p12->authsafes->ctx.libctx,
+-                                       p12->authsafes->ctx.propq)) {
++                                        iter, keylen, key, md,
++                                        p12->authsafes->ctx.libctx, p12->authsafes->ctx.propq)) {
+                 ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR);
+                 goto err;
+             }
+         }
+     }
+     if ((hmac = HMAC_CTX_new()) == NULL
+-        || !HMAC_Init_ex(hmac, key, md_size, md, NULL)
++        || !HMAC_Init_ex(hmac, key, keylen, md, NULL)
+         || !HMAC_Update(hmac, p12->authsafes->d.data->data,
+                         p12->authsafes->d.data->length)
+         || !HMAC_Final(hmac, mac, maclen)) {
+@@ -178,7 +277,7 @@ static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
+ int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
+                    unsigned char *mac, unsigned int *maclen)
+ {
+-    return pkcs12_gen_mac(p12, pass, passlen, mac, maclen, NULL);
++    return pkcs12_gen_mac(p12, pass, passlen, mac, maclen, NID_undef, NID_undef, NULL);
+ }
+ 
+ /* Verify the mac */
+@@ -187,14 +286,40 @@ int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen)
+     unsigned char mac[EVP_MAX_MD_SIZE];
+     unsigned int maclen;
+     const ASN1_OCTET_STRING *macoct;
++    const X509_ALGOR *macalg;
++    const ASN1_OBJECT *macoid;
+ 
+     if (p12->mac == NULL) {
+         ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_ABSENT);
+         return 0;
+     }
+-    if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, NULL)) {
+-        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR);
+-        return 0;
++
++    X509_SIG_get0(p12->mac->dinfo, &macalg, NULL);
++    X509_ALGOR_get0(&macoid, NULL, NULL, macalg);
++    if (OBJ_obj2nid(macoid) == NID_pbmac1) {
++        PBMAC1PARAM *param = NULL;
++        const ASN1_OBJECT *hmac_oid;
++        int md_nid = NID_undef;
++
++        param = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBMAC1PARAM), macalg->parameter);
++        if (param == NULL) {
++            ERR_raise(ERR_LIB_PKCS12, ERR_R_UNSUPPORTED);
++            return 0;
++        }
++        X509_ALGOR_get0(&hmac_oid, NULL, NULL, param->messageAuthScheme);
++        md_nid = ossl_hmac2mdnid(OBJ_obj2nid(hmac_oid));
++
++        if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, md_nid, NID_undef, NULL)) {
++            ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR);
++            PBMAC1PARAM_free(param);
++            return 0;
++        }
++        PBMAC1PARAM_free(param);
++    } else {
++        if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, NID_undef, NID_undef, NULL)) {
++            ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR);
++            return 0;
++        }
+     }
+     X509_SIG_get0(p12->mac->dinfo, NULL, &macoct);
+     if ((maclen != (unsigned int)ASN1_STRING_length(macoct))
+@@ -205,7 +330,6 @@ int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen)
+ }
+ 
+ /* Set a mac */
+-
+ int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
+                    unsigned char *salt, int saltlen, int iter,
+                    const EVP_MD *md_type)
+@@ -226,7 +350,7 @@ int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
+     /*
+      * Note that output mac is forced to UTF-8...
+      */
+-    if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, NULL)) {
++    if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, NID_undef, NID_undef, NULL)) {
+         ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR);
+         return 0;
+     }
+@@ -238,9 +362,18 @@ int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
+     return 1;
+ }
+ 
+-/* Set up a mac structure */
+-int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, int saltlen,
+-                     const EVP_MD *md_type)
++static int pkcs12_pbmac1_pbkdf2_key_gen(const char *pass, int passlen,
++                                        unsigned char *salt, int saltlen,
++                                        int id, int iter, int keylen,
++                                        unsigned char *out,
++                                        const EVP_MD *md_type)
++{
++    return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter,
++                             md_type, keylen, out);
++}
++
++static int pkcs12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, int saltlen,
++                            int nid)
+ {
+     X509_ALGOR *macalg;
+ 
+@@ -274,11 +407,112 @@ int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, int saltlen,
+         memcpy(p12->mac->salt->data, salt, saltlen);
+     }
+     X509_SIG_getm(p12->mac->dinfo, &macalg, NULL);
+-    if (!X509_ALGOR_set0(macalg, OBJ_nid2obj(EVP_MD_get_type(md_type)),
+-                         V_ASN1_NULL, NULL)) {
++    if (!X509_ALGOR_set0(macalg, OBJ_nid2obj(nid), V_ASN1_NULL, NULL)) {
+         ERR_raise(ERR_LIB_PKCS12, ERR_R_ASN1_LIB);
+         return 0;
+     }
+ 
+     return 1;
+ }
++
++/* Set up a mac structure */
++int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, int saltlen,
++                     const EVP_MD *md_type)
++{
++    return pkcs12_setup_mac(p12, iter, salt, saltlen, EVP_MD_get_type(md_type));
++}
++
++int PKCS12_set_pbmac1_pbkdf2(PKCS12 *p12, const char *pass, int passlen,
++                             unsigned char *salt, int saltlen, int iter,
++                             const EVP_MD *md_type, const char *prf_md_name)
++{
++    unsigned char mac[EVP_MAX_MD_SIZE];
++    unsigned int maclen;
++    ASN1_OCTET_STRING *macoct;
++    X509_ALGOR *alg = NULL;
++    int ret = 0;
++    int prf_md_nid = NID_undef, prf_nid = NID_undef, hmac_nid;
++    unsigned char *known_salt = NULL;
++    int keylen = 0;
++    PBMAC1PARAM *param = NULL;
++    X509_ALGOR  *hmac_alg = NULL, *macalg = NULL;
++
++    if (md_type == NULL)
++        /* No need to do a fetch as the md_type is used only to get a NID */
++        md_type = EVP_sha256();
++
++    if (prf_md_name == NULL)
++        prf_md_nid = EVP_MD_get_type(md_type);
++    else
++        prf_md_nid = OBJ_txt2nid(prf_md_name);
++
++    if (iter == 0)
++        iter = PKCS12_DEFAULT_ITER;
++
++    keylen = EVP_MD_get_size(md_type);
++
++    prf_nid  = ossl_md2hmacnid(prf_md_nid);
++    hmac_nid = ossl_md2hmacnid(EVP_MD_get_type(md_type));
++
++    if (prf_nid == NID_undef || hmac_nid == NID_undef) {
++        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM);
++        goto err;
++    }
++
++    if (salt == NULL) {
++        known_salt = OPENSSL_malloc(saltlen);
++        if (known_salt == NULL)
++            goto err;
++
++        if (RAND_bytes_ex(NULL, known_salt, saltlen, 0) <= 0) {
++            ERR_raise(ERR_LIB_PKCS12, ERR_R_RAND_LIB);
++            goto err;
++        }
++    }
++
++    param = PBMAC1PARAM_new();
++    hmac_alg = X509_ALGOR_new();
++    alg = PKCS5_pbkdf2_set(iter, salt ? salt : known_salt, saltlen, prf_nid, keylen);
++    if (param == NULL || hmac_alg == NULL || alg == NULL)
++        goto err;
++
++    if (pkcs12_setup_mac(p12, iter, salt ? salt : known_salt, saltlen,
++                         NID_pbmac1) == PKCS12_ERROR) {
++        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_SETUP_ERROR);
++        goto err;
++    }
++
++    if (!X509_ALGOR_set0(hmac_alg, OBJ_nid2obj(hmac_nid), V_ASN1_NULL, NULL)) {
++        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_SETUP_ERROR);
++        goto err;
++    }
++
++    X509_ALGOR_free(param->keyDerivationFunc);
++    X509_ALGOR_free(param->messageAuthScheme);
++    param->keyDerivationFunc = alg;
++    param->messageAuthScheme = hmac_alg;
++
++    X509_SIG_getm(p12->mac->dinfo, &macalg, &macoct);
++    if (!ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBMAC1PARAM), param, &macalg->parameter))
++        goto err;
++
++    /*
++     * Note that output mac is forced to UTF-8...
++     */
++    if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen,
++                        EVP_MD_get_type(md_type), prf_md_nid,
++                        pkcs12_pbmac1_pbkdf2_key_gen)) {
++        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR);
++        goto err;
++    }
++    if (!ASN1_OCTET_STRING_set(macoct, mac, maclen)) {
++        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_STRING_SET_ERROR);
++        goto err;
++    }
++    ret = 1;
++
++ err:
++    PBMAC1PARAM_free(param);
++    OPENSSL_free(known_salt);
++    return ret;
++}
+diff --git a/include/crypto/evp.h b/include/crypto/evp.h
+index 32c60f223c78c..72d9995e8f0f4 100644
+--- a/include/crypto/evp.h
++++ b/include/crypto/evp.h
+@@ -964,4 +964,7 @@ int evp_pkey_decrypt_alloc(EVP_PKEY_CTX *ctx, unsigned char **outp,
+                            size_t *outlenp, size_t expected_outlen,
+                            const unsigned char *in, size_t inlen);
+ 
++int ossl_md2hmacnid(int mdnid);
++int ossl_hmac2mdnid(int hmac_nid);
++
+ #endif /* OSSL_CRYPTO_EVP_H */
+diff --git a/include/openssl/pkcs12.h.in b/include/openssl/pkcs12.h.in
+index 35759d4deadc3..ab62207e49b55 100644
+--- a/include/openssl/pkcs12.h.in
++++ b/include/openssl/pkcs12.h.in
+@@ -269,6 +269,9 @@ int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen);
+ int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
+                    unsigned char *salt, int saltlen, int iter,
+                    const EVP_MD *md_type);
++int PKCS12_set_pbmac1_pbkdf2(PKCS12 *p12, const char *pass, int passlen,
++                             unsigned char *salt, int saltlen, int iter,
++                             const EVP_MD *md_type, const char *prf_md_name);
+ int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt,
+                      int saltlen, const EVP_MD *md_type);
+ unsigned char *OPENSSL_asc2uni(const char *asc, int asclen,
+diff --git a/include/openssl/x509.h.in b/include/openssl/x509.h.in
+index 99bc4aab29133..b7f080a5360db 100644
+--- a/include/openssl/x509.h.in
++++ b/include/openssl/x509.h.in
+@@ -279,7 +279,12 @@ typedef struct PBKDF2PARAM_st {
+     X509_ALGOR *prf;
+ } PBKDF2PARAM;
+ 
+-#ifndef OPENSSL_NO_SCRYPT
++typedef struct {
++    X509_ALGOR *keyDerivationFunc;
++    X509_ALGOR *messageAuthScheme;
++} PBMAC1PARAM;
++
++# ifndef OPENSSL_NO_SCRYPT
+ typedef struct SCRYPT_PARAMS_st {
+     ASN1_OCTET_STRING *salt;
+     ASN1_INTEGER *costParameter;
+@@ -287,7 +292,7 @@ typedef struct SCRYPT_PARAMS_st {
+     ASN1_INTEGER *parallelizationParameter;
+     ASN1_INTEGER *keyLength;
+ } SCRYPT_PARAMS;
+-#endif
++# endif
+ 
+ #ifdef  __cplusplus
+ }
+@@ -1023,9 +1028,10 @@ X509 *X509_find_by_subject(STACK_OF(X509) *sk, const X509_NAME *name);
+ DECLARE_ASN1_FUNCTIONS(PBEPARAM)
+ DECLARE_ASN1_FUNCTIONS(PBE2PARAM)
+ DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM)
+-#ifndef OPENSSL_NO_SCRYPT
++DECLARE_ASN1_FUNCTIONS(PBMAC1PARAM)
++# ifndef OPENSSL_NO_SCRYPT
+ DECLARE_ASN1_FUNCTIONS(SCRYPT_PARAMS)
+-#endif
++# endif
+ 
+ int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter,
+                          const unsigned char *salt, int saltlen);
+@@ -1062,6 +1068,7 @@ X509_ALGOR *PKCS5_pbkdf2_set_ex(int iter, unsigned char *salt, int saltlen,
+                                 int prf_nid, int keylen,
+                                 OSSL_LIB_CTX *libctx);
+ 
++PBKDF2PARAM *PBMAC1_get1_pbkdf2_param(const X509_ALGOR *macalg);
+ /* PKCS#8 utilities */
+ 
+ DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
+
+From 29d98a8287d217b2232344056934d3cd2c6f44a3 Mon Sep 17 00:00:00 2001
+From: Dmitry Belyavskiy <beldmit@gmail.com>
+Date: Fri, 7 Jun 2024 14:38:40 +0200
+Subject: [PATCH 2/4] Implementation of the RFC 9579, PBMAC1 in PKCS#12 -
+ documentation
+
+---
+ doc/man1/openssl-pkcs12.pod.in        | 11 +++++++
+ doc/man3/PBMAC1_get1_pbkdf2_param.pod | 46 +++++++++++++++++++++++++++
+ doc/man3/PKCS12_gen_mac.pod           | 37 ++++++++++++++++-----
+ doc/man3/X509_dup.pod                 |  3 ++
+ doc/man3/d2i_X509.pod                 |  2 ++
+ util/missingcrypto.txt                |  1 -
+ util/missingcrypto111.txt             |  1 -
+ 7 files changed, 91 insertions(+), 10 deletions(-)
+ create mode 100644 doc/man3/PBMAC1_get1_pbkdf2_param.pod
+
+diff --git a/doc/man1/openssl-pkcs12.pod.in b/doc/man1/openssl-pkcs12.pod.in
+index 665b22bb644ac..020543cd5c895 100644
+--- a/doc/man1/openssl-pkcs12.pod.in
++++ b/doc/man1/openssl-pkcs12.pod.in
+@@ -62,6 +62,8 @@ PKCS#12 output (export) options:
+ [B<-certpbe> I<cipher>]
+ [B<-descert>]
+ [B<-macalg> I<digest>]
++[B<-pbmac1_pbkdf2>]
++[B<-pbmac1_pbkdf2_md> I<digest>]
+ [B<-iter> I<count>]
+ [B<-noiter>]
+ [B<-nomaciter>]
+@@ -345,6 +347,15 @@ then both, the private key and the certificates are encrypted using triple DES.
+ 
+ Specify the MAC digest algorithm. If not included SHA256 will be used.
+ 
++=item B<-pbmac1_pbkdf2>
++
++Use PBMAC1 with PBKDF2 for MAC protection of the PKCS#12 file.
++
++=item B<-pbmac1_pbkdf2_md> I<digest>
++
++Specify the PBKDF2 KDF digest algorithm. If not specified, SHA256 will be used.
++Unless C<-pbmac1_pbkdf2> is specified, this parameter is ignored.
++
+ =item B<-iter> I<count>
+ 
+ This option specifies the iteration count for the encryption key and MAC. The
+diff --git a/doc/man3/PBMAC1_get1_pbkdf2_param.pod b/doc/man3/PBMAC1_get1_pbkdf2_param.pod
+new file mode 100644
+index 0000000000000..415c3cd214a2e
+--- /dev/null
++++ b/doc/man3/PBMAC1_get1_pbkdf2_param.pod
+@@ -0,0 +1,46 @@
++=pod
++
++=head1 NAME
++
++PBMAC1_get1_pbkdf2_param - Function to manipulate a PBMAC1
++MAC structure
++
++=head1 SYNOPSIS
++
++ #include <openssl/x509.h>
++
++ PBKDF2PARAM *PBMAC1_get1_pbkdf2_param(const X509_ALGOR *macalg);
++
++=head1 DESCRIPTION
++
++PBMAC1_get1_pbkdf2_param() retrieves a B<PBKDF2PARAM> structure from an
++I<X509_ALGOR> structure.
++
++=head1 RETURN VALUES
++
++PBMAC1_get1_pbkdf2_param() returns NULL in case when PBMAC1 uses an algorithm
++apart from B<PBKDF2> or when passed incorrect parameters and a pointer to
++B<PBKDF2PARAM> structure otherwise.
++
++=head1 CONFORMING TO
++
++IETF RFC 9579 (L<https://tools.ietf.org/html/rfc9579>)
++
++=head1 SEE ALSO
++
++L<openssl-pkcs12(1)>
++
++=head1 HISTORY
++
++The I<PBMAC1_get1_pbkdf2_param> function was added in OpenSSL 3.4.
++
++=head1 COPYRIGHT
++
++Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved.
++
++Licensed under the Apache License 2.0 (the "License").  You may not use
++this file except in compliance with the License.  You can obtain a copy
++in the file LICENSE in the source distribution or at
++L<https://www.openssl.org/source/license.html>.
++
++=cut
+diff --git a/doc/man3/PKCS12_gen_mac.pod b/doc/man3/PKCS12_gen_mac.pod
+index a72df145fedd7..ebeee98f04e68 100644
+--- a/doc/man3/PKCS12_gen_mac.pod
++++ b/doc/man3/PKCS12_gen_mac.pod
+@@ -3,7 +3,8 @@
+ =head1 NAME
+ 
+ PKCS12_gen_mac, PKCS12_setup_mac, PKCS12_set_mac,
+-PKCS12_verify_mac - Functions to create and manipulate a PKCS#12 structure
++PKCS12_set_pbmac1_pbkdf2, PKCS12_verify_mac, PKCS12_get0_mac -
++Functions to create and manipulate a PKCS#12 MAC structure
+ 
+ =head1 SYNOPSIS
+ 
+@@ -15,9 +16,19 @@ PKCS12_verify_mac - Functions to create and manipulate a PKCS#12 structure
+  int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
+                     unsigned char *salt, int saltlen, int iter,
+                     const EVP_MD *md_type);
++ int PKCS12_set_pbmac1_pbkdf2(PKCS12 *p12, const char *pass, int passlen,
++                                   unsigned char *salt, int saltlen, int iter,
++                                   const EVP_MD *md_type,
++                                   const char *prf_md_name);
+  int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt,
+                       int saltlen, const EVP_MD *md_type);
+ 
++ void PKCS12_get0_mac(const ASN1_OCTET_STRING **pmac,
++                      const X509_ALGOR **pmacalg,
++                      const ASN1_OCTET_STRING **psalt,
++                      const ASN1_INTEGER **piter,
++                      const PKCS12 *p12);
++
+ =head1 DESCRIPTION
+ 
+ PKCS12_gen_mac() generates an HMAC over the entire PKCS#12 object using the
+@@ -31,10 +42,15 @@ PKCS12_setup_mac() sets the MAC part of the PKCS#12 structure with the supplied
+ parameters.
+ 
+ PKCS12_set_mac() sets the MAC and MAC parameters into the PKCS#12 object.
++PKCS12_set_pbmac1_pbkdf2() sets the MAC and MAC parameters into the PKCS#12
++object when B<PBMAC1> with PBKDF2 is used for protection of the PKCS#12 object.
+ 
+ I<pass> is the passphrase to use in the HMAC. I<salt> is the salt value to use,
+-I<iter> is the iteration count and I<md_type> is the message digest
+-function to use.
++I<iter> is the iteration count and I<md_type> is the message digest function to
++use. I<prf_md_name> specifies the digest used for the PBKDF2 in PBMAC1 KDF.
++
++PKCS12_get0_mac() retrieves any included MAC value, B<X509_ALGOR> object,
++I<salt>, and I<iter> count from the PKCS12 object.
+ 
+ =head1 NOTES
+ 
+@@ -43,17 +59,18 @@ If I<salt> is NULL then a suitable salt will be generated and used.
+ If I<iter> is 1 then an iteration count will be omitted from the PKCS#12
+ structure.
+ 
+-PKCS12_gen_mac(), PKCS12_verify_mac() and PKCS12_set_mac() make assumptions
+-regarding the encoding of the given passphrase. See L<passphrase-encoding(7)>
+-for more information.
++PKCS12_gen_mac(), PKCS12_verify_mac(), PKCS12_set_mac() and
++PKCS12_set_pbmac1_pbkdf2() make assumptions regarding the encoding of the
++given passphrase. See L<passphrase-encoding(7)> for more information.
+ 
+ =head1 RETURN VALUES
+ 
+-All functions return 1 on success and 0 if an error occurred.
++All functions returning an integer return 1 on success and 0 if an error occurred.
+ 
+ =head1 CONFORMING TO
+ 
+ IETF RFC 7292 (L<https://tools.ietf.org/html/rfc7292>)
++IETF RFC 9579 (L<https://tools.ietf.org/html/rfc9579>)
+ 
+ =head1 SEE ALSO
+ 
+@@ -62,9 +79,13 @@ L<EVP_KDF-PKCS12KDF(7)>,
+ L<PKCS12_create(3)>,
+ L<passphrase-encoding(7)>
+ 
++=head1 HISTORY
++
++The I<PKCS12_set_pbmac1_pbkdf2> function was added in OpenSSL 3.4.
++
+ =head1 COPYRIGHT
+ 
+-Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved.
++Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved.
+ 
+ Licensed under the Apache License 2.0 (the "License").  You may not use
+ this file except in compliance with the License.  You can obtain a copy
+diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod
+index fc93494a76617..81ea2275d7414 100644
+--- a/doc/man3/X509_dup.pod
++++ b/doc/man3/X509_dup.pod
+@@ -218,6 +218,9 @@ PBEPARAM_free,
+ PBEPARAM_new,
+ PBKDF2PARAM_free,
+ PBKDF2PARAM_new,
++PBMAC1PARAM_free,
++PBMAC1PARAM_it,
++PBMAC1PARAM_new,
+ PKCS12_BAGS_free,
+ PKCS12_BAGS_new,
+ PKCS12_MAC_DATA_free,
+diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod
+index 75b37e5544396..3615bcaafe7c0 100644
+--- a/doc/man3/d2i_X509.pod
++++ b/doc/man3/d2i_X509.pod
+@@ -115,6 +115,7 @@ d2i_OTHERNAME,
+ d2i_PBE2PARAM,
+ d2i_PBEPARAM,
+ d2i_PBKDF2PARAM,
++d2i_PBMAC1PARAM,
+ d2i_PKCS12,
+ d2i_PKCS12_BAGS,
+ d2i_PKCS12_MAC_DATA,
+@@ -300,6 +301,7 @@ i2d_OTHERNAME,
+ i2d_PBE2PARAM,
+ i2d_PBEPARAM,
+ i2d_PBKDF2PARAM,
++i2d_PBMAC1PARAM,
+ i2d_PKCS12,
+ i2d_PKCS12_BAGS,
+ i2d_PKCS12_MAC_DATA,
+diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt
+index b7d5091b31912..a56491d0f8b94 100644
+--- a/util/missingcrypto.txt
++++ b/util/missingcrypto.txt
+@@ -749,7 +749,6 @@ PKCS12_MAC_DATA_it(3)
+ PKCS12_PBE_add(3)
+ PKCS12_SAFEBAGS_it(3)
+ PKCS12_SAFEBAG_it(3)
+-PKCS12_get0_mac(3)
+ PKCS12_get_attr(3)
+ PKCS12_it(3)
+ PKCS12_item_pack_safebag(3)
+diff --git a/util/missingcrypto111.txt b/util/missingcrypto111.txt
+index 0386701ad1e32..f3402ada7e60f 100644
+--- a/util/missingcrypto111.txt
++++ b/util/missingcrypto111.txt
+@@ -1027,7 +1027,6 @@ PKCS12_add_safe(3)
+ PKCS12_add_safes(3)
+ PKCS12_decrypt_skey(3)
+ PKCS12_gen_mac(3)
+-PKCS12_get0_mac(3)
+ PKCS12_get_attr(3)
+ PKCS12_get_attr_gen(3)
+ PKCS12_get_friendlyname(3)
+
+From 7257898633703d5841aefa7fb4f9d192430fdad8 Mon Sep 17 00:00:00 2001
+From: Dmitry Belyavskiy <beldmit@gmail.com>
+Date: Thu, 6 Jun 2024 13:07:48 +0200
+Subject: [PATCH 3/4] Make update
+
+---
+ doc/build.info     | 6 ++++++
+ util/libcrypto.num | 7 +++++++
+ 2 files changed, 13 insertions(+)
+
+diff --git a/doc/build.info b/doc/build.info
+index d47371e88aa9f..60a5d9b86bd5c 100644
+--- a/doc/build.info
++++ b/doc/build.info
+@@ -1847,6 +1847,10 @@ DEPEND[html/man3/OpenSSL_version.html]=man3/OpenSSL_version.pod
+ GENERATE[html/man3/OpenSSL_version.html]=man3/OpenSSL_version.pod
+ DEPEND[man/man3/OpenSSL_version.3]=man3/OpenSSL_version.pod
+ GENERATE[man/man3/OpenSSL_version.3]=man3/OpenSSL_version.pod
++DEPEND[html/man3/PBMAC1_get1_pbkdf2_param.html]=man3/PBMAC1_get1_pbkdf2_param.pod
++GENERATE[html/man3/PBMAC1_get1_pbkdf2_param.html]=man3/PBMAC1_get1_pbkdf2_param.pod
++DEPEND[man/man3/PBMAC1_get1_pbkdf2_param.3]=man3/PBMAC1_get1_pbkdf2_param.pod
++GENERATE[man/man3/PBMAC1_get1_pbkdf2_param.3]=man3/PBMAC1_get1_pbkdf2_param.pod
+ DEPEND[html/man3/PEM_X509_INFO_read_bio_ex.html]=man3/PEM_X509_INFO_read_bio_ex.pod
+ GENERATE[html/man3/PEM_X509_INFO_read_bio_ex.html]=man3/PEM_X509_INFO_read_bio_ex.pod
+ DEPEND[man/man3/PEM_X509_INFO_read_bio_ex.3]=man3/PEM_X509_INFO_read_bio_ex.pod
+@@ -3453,6 +3457,7 @@ html/man3/OSSL_trace_get_category_num.html \
+ html/man3/OSSL_trace_set_channel.html \
+ html/man3/OpenSSL_add_all_algorithms.html \
+ html/man3/OpenSSL_version.html \
++html/man3/PBMAC1_get1_pbkdf2_param.html \
+ html/man3/PEM_X509_INFO_read_bio_ex.html \
+ html/man3/PEM_bytes_read_bio.html \
+ html/man3/PEM_read.html \
+@@ -4113,6 +4118,7 @@ man/man3/OSSL_trace_get_category_num.3 \
+ man/man3/OSSL_trace_set_channel.3 \
+ man/man3/OpenSSL_add_all_algorithms.3 \
+ man/man3/OpenSSL_version.3 \
++man/man3/PBMAC1_get1_pbkdf2_param.3 \
+ man/man3/PEM_X509_INFO_read_bio_ex.3 \
+ man/man3/PEM_bytes_read_bio.3 \
+ man/man3/PEM_read.3 \
+diff --git a/util/libcrypto.num b/util/libcrypto.num
+index 7f958a4fa31db..ef11c0302e396 100644
+--- a/util/libcrypto.num
++++ b/util/libcrypto.num
+@@ -5664,3 +5664,10 @@ OSSL_IETF_ATTR_SYNTAX_get_value_num     ?	3_4_0	EXIST::FUNCTION:
+ OPENSSL_strncasecmp                     ? 	3_0_1	EXIST::FUNCTION:
+ ossl_ctx_legacy_digest_signatures_allowed ?	3_0_1	EXIST::FUNCTION:
+ ossl_ctx_legacy_digest_signatures_allowed_set ?	3_0_1	EXIST::FUNCTION:
++PKCS12_set_pbmac1_pbkdf2                ?	3_4_0	EXIST::FUNCTION:
++PBMAC1_get1_pbkdf2_param                ?	3_4_0	EXIST::FUNCTION:
++d2i_PBMAC1PARAM                         ?	3_4_0	EXIST::FUNCTION:
++i2d_PBMAC1PARAM                         ?	3_4_0	EXIST::FUNCTION:
++PBMAC1PARAM_free                        ?	3_4_0	EXIST::FUNCTION:
++PBMAC1PARAM_new                         ?	3_4_0	EXIST::FUNCTION:
++PBMAC1PARAM_it                          ?	3_4_0	EXIST::FUNCTION:
+
+From 97fbb9437163fb5114da40250b7ace83748a2e81 Mon Sep 17 00:00:00 2001
+From: Dmitry Belyavskiy <beldmit@gmail.com>
+Date: Thu, 6 Jun 2024 17:01:45 +0200
+Subject: [PATCH 4/4] Test vectors from rfc9579 and creation tests
+
+---
+ test/recipes/80-test_pkcs12.t                 |  55 +++++++++++++++++-
+ .../pbmac1_256_256.bad-iter.p12               | Bin 0 -> 2703 bytes
+ .../pbmac1_256_256.bad-salt.p12               | Bin 0 -> 2702 bytes
+ .../pbmac1_256_256.good.p12                   | Bin 0 -> 2702 bytes
+ .../pbmac1_256_256.no-len.p12                 | Bin 0 -> 2700 bytes
+ .../pbmac1_512_256.good.p12                   | Bin 0 -> 2702 bytes
+ .../pbmac1_512_512.good.p12                   | Bin 0 -> 2736 bytes
+ 7 files changed, 54 insertions(+), 1 deletion(-)
+ create mode 100644 test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-iter.p12
+ create mode 100644 test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-salt.p12
+ create mode 100644 test/recipes/80-test_pkcs12_data/pbmac1_256_256.good.p12
+ create mode 100644 test/recipes/80-test_pkcs12_data/pbmac1_256_256.no-len.p12
+ create mode 100644 test/recipes/80-test_pkcs12_data/pbmac1_512_256.good.p12
+ create mode 100644 test/recipes/80-test_pkcs12_data/pbmac1_512_512.good.p12
+
+diff --git a/test/recipes/80-test_pkcs12.t b/test/recipes/80-test_pkcs12.t
+index 999129a03074d..c14ef94998cde 100644
+--- a/test/recipes/80-test_pkcs12.t
++++ b/test/recipes/80-test_pkcs12.t
+@@ -9,7 +9,7 @@
+ use strict;
+ use warnings;
+ 
+-use OpenSSL::Test qw/:DEFAULT srctop_file with/;
++use OpenSSL::Test qw/:DEFAULT srctop_file bldtop_dir with/;
+ use OpenSSL::Test::Utils;
+ 
+ use Encode;
+@@ -54,7 +54,9 @@ if (eval { require Win32::API; 1; }) {
+ }
+ $ENV{OPENSSL_WIN32_UTF8}=1;
+ 
+-plan tests => 31;
++my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
++
++plan tests => $no_fips ? 45 : 51;
+ 
+ # Test different PKCS#12 formats
+ ok(run(test(["pkcs12_format_test"])), "test pkcs12 formats");
+@@ -170,6 +170,80 @@ ok(grep(/Trusted key usage (Oracle)/, @pkcs12info) == 0,
+     ok(scalar @match > 0 ? 0 : 1, "test_export_pkcs12_outerr6_empty");
+ }
+ 
++my %pbmac1_tests = (
++    pbmac1_defaults => {args => [], lookup => "hmacWithSHA256"},
++    pbmac1_nondefaults => {args => ["-pbmac1_pbkdf2_md", "sha512", "-macalg", "sha384"], lookup => "hmacWithSHA512"},
++);
++
++for my $instance (sort keys %pbmac1_tests) {
++    my $extra_args = $pbmac1_tests{$instance}{args};
++    my $lookup     = $pbmac1_tests{$instance}{lookup};
++    # Test export of PEM file with both cert and key, with password.
++    {
++        my $pbmac1_id = $instance;
++        ok(run(app(["openssl", "pkcs12", "-export", "-pbmac1_pbkdf2",
++                "-inkey", srctop_file(@path, "cert-key-cert.pem"),
++                "-in", srctop_file(@path, "cert-key-cert.pem"),
++                "-passout", "pass:1234",
++                @$extra_args,
++                "-out", "$pbmac1_id.p12"], stderr => "${pbmac1_id}_err.txt")),
++        "test_export_pkcs12_${pbmac1_id}");
++        open DATA, "${pbmac1_id}_err.txt";
++        my @match = grep /:error:/, <DATA>;
++        close DATA;
++        ok(scalar @match > 0 ? 0 : 1, "test_export_pkcs12_${pbmac1_id}_err.empty");
++
++        ok(run(app(["openssl", "pkcs12", "-in", "$pbmac1_id.p12", "-info", "-noout",
++                "-passin", "pass:1234"], stderr => "${pbmac1_id}_info.txt")),
++        "test_export_pkcs12_${pbmac1_id}_info");
++        open DATA, "${pbmac1_id}_info.txt";
++        my @match = grep /$lookup/, <DATA>;
++        close DATA;
++        ok(scalar @match > 0 ? 1 : 0, "test_export_pkcs12_${pbmac1_id}_info");
++    }
++}
++
++# Test pbmac1 pkcs12 good files, RFC 9579
++for my $file ("pbmac1_256_256.good.p12", "pbmac1_512_256.good.p12", "pbmac1_512_512.good.p12")
++{
++    my $path = srctop_file("test", "recipes", "80-test_pkcs12_data", $file);
++    ok(run(app(["openssl", "pkcs12", "-in", $path, "-password", "pass:1234", "-noenc"])),
++      "test pbmac1 pkcs12 file $file");
++}
++
++unless ($no_fips) {
++    my $provpath = bldtop_dir("providers");
++    my $provconf = srctop_file("test", "fips-and-base.cnf");
++    my $provname = 'fips';
++    my @prov = ("-provider-path", $provpath,
++                "-provider", $provname);
++    local $ENV{OPENSSL_CONF} = $provconf;
++
++# Test pbmac1 pkcs12 good files, RFC 9579
++    for my $file ("pbmac1_256_256.good.p12", "pbmac1_512_256.good.p12", "pbmac1_512_512.good.p12")
++    {
++        my $path = srctop_file("test", "recipes", "80-test_pkcs12_data", $file);
++        ok(run(app(["openssl", "pkcs12", @prov, "-in", $path, "-password", "pass:1234", "-noenc"])),
++           "test pbmac1 pkcs12 file $file");
++
++        ok(run(app(["openssl", "pkcs12", @prov, "-in", $path, "-info", "-noout",
++                    "-passin", "pass:1234"], stderr => "${file}_info.txt")),
++           "test_export_pkcs12_${file}_info");
++    }
++}
++
++# Test pbmac1 pkcs12 bad files, RFC 9579
++for my $file ("pbmac1_256_256.bad-iter.p12", "pbmac1_256_256.bad-salt.p12", "pbmac1_256_256.no-len.p12")
++{
++    my $path = srctop_file("test", "recipes", "80-test_pkcs12_data", $file);
++    with({ exit_checker => sub { return shift == 1; } },
++        sub {
++            ok(run(app(["openssl", "pkcs12", "-in", $path, "-password", "pass:1234", "-noenc"])),
++            "test pbmac1 pkcs12 bad file $file");
++            }
++        );
++}
++
+ # Test some bad pkcs12 files
+ my $bad1 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad1.p12");
+ my $bad2 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad2.p12");
+diff --git a/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-iter.p12 b/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-iter.p12
+new file mode 100644
+index 0000000000000000000000000000000000000000..9957d473c433bc9fb9572ecf51332a7f325fe36f
+GIT binary patch
+literal 2703
+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
+QZf;>CWNWRj_YbE31}omyrT_o{
+
+literal 0
+HcmV?d00001
+
+diff --git a/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-salt.p12 b/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-salt.p12
+new file mode 100644
+index 0000000000000000000000000000000000000000..fef1e51f71c94240b8d5e375b3e5273a7cb54be5
+GIT binary patch
+literal 2702
+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
+QJitKh*G5^nATS8@Hz^a=n*aa+
+
+literal 0
+HcmV?d00001
+
+diff --git a/test/recipes/80-test_pkcs12_data/pbmac1_256_256.good.p12 b/test/recipes/80-test_pkcs12_data/pbmac1_256_256.good.p12
+new file mode 100644
+index 0000000000000000000000000000000000000000..b8c8c2d7759c66db30d791389a498418fd9cf2bd
+GIT binary patch
+literal 2702
+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
+Ob8A5xD?ME>2=q5e$<~_y
+
+literal 0
+HcmV?d00001
+
+diff --git a/test/recipes/80-test_pkcs12_data/pbmac1_256_256.no-len.p12 b/test/recipes/80-test_pkcs12_data/pbmac1_256_256.no-len.p12
+new file mode 100644
+index 0000000000000000000000000000000000000000..35ebe05d177f7d745251e2fce3ebb4f23e0ebd09
+GIT binary patch
+literal 2700
+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
+
+literal 0
+HcmV?d00001
+
+diff --git a/test/recipes/80-test_pkcs12_data/pbmac1_512_256.good.p12 b/test/recipes/80-test_pkcs12_data/pbmac1_512_256.good.p12
+new file mode 100644
+index 0000000000000000000000000000000000000000..e8d4899691bfec94614bf1614c0e9d45b902cf24
+GIT binary patch
+literal 2702
+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
+VW!Nl&SdEOYi{CK0av2B!{0(@<()a)X
+
+literal 0
+HcmV?d00001
+
+diff --git a/test/recipes/80-test_pkcs12_data/pbmac1_512_512.good.p12 b/test/recipes/80-test_pkcs12_data/pbmac1_512_512.good.p12
+new file mode 100644
+index 0000000000000000000000000000000000000000..64e14341a10d04e7e98cf83dbb2b6409ae1fd72f
+GIT binary patch
+literal 2736
+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
+D?Q7k<
+
+literal 0
+HcmV?d00001
+

diff --git a/0125-PBMAC1-PKCS12-FIPS-default.patch b/0125-PBMAC1-PKCS12-FIPS-default.patch
new file mode 100644
index 0000000..f7257ea
--- /dev/null
+++ b/0125-PBMAC1-PKCS12-FIPS-default.patch
@@ -0,0 +1,21 @@
+diff -up openssl-3.2.2/apps/pkcs12.c.xxx openssl-3.2.2/apps/pkcs12.c
+--- openssl-3.2.2/apps/pkcs12.c.xxx	2024-08-14 11:24:41.164589397 +0200
++++ openssl-3.2.2/apps/pkcs12.c	2024-08-14 11:28:21.071004221 +0200
+@@ -17,6 +17,7 @@
+ #include <openssl/asn1.h>
+ #include <openssl/crypto.h>
+ #include <openssl/err.h>
++#include <openssl/evp.h>
+ #include <openssl/pem.h>
+ #include <openssl/pkcs12.h>
+ #include <openssl/provider.h>
+@@ -708,6 +709,9 @@ int pkcs12_main(int argc, char **argv)
+         }
+ 
+         if (maciter != -1) {
++            if (EVP_default_properties_is_fips_enabled(NULL))
++                pbmac1_pbkdf2 = 1;
++
+             if (pbmac1_pbkdf2 == 1) {
+                 if (!PKCS12_set_pbmac1_pbkdf2(p12, mpass, -1, NULL,
+                                               macsaltlen, maciter,

diff --git a/0126-pkeyutl-encap.patch b/0126-pkeyutl-encap.patch
new file mode 100644
index 0000000..8f82cce
--- /dev/null
+++ b/0126-pkeyutl-encap.patch
@@ -0,0 +1,430 @@
+From 77a0eabe15b9c8c0fb5fde27f6ce1c593c278e20 Mon Sep 17 00:00:00 2001
+From: Dmitry Belyavskiy <beldmit@gmail.com>
+Date: Wed, 7 Aug 2024 17:17:18 +0200
+Subject: [PATCH 1/3] Support of en/decapsulation in the pkeyutl command
+
+---
+ apps/pkeyutl.c | 83 +++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 69 insertions(+), 14 deletions(-)
+
+diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c
+index b5390c64c2a81..a14ad88217823 100644
+--- a/apps/pkeyutl.c
++++ b/apps/pkeyutl.c
+@@ -24,7 +24,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize,
+                               const char *keyfile, int keyform, int key_type,
+                               char *passinarg, int pkey_op, ENGINE *e,
+                               const int impl, int rawin, EVP_PKEY **ppkey,
+-                              EVP_MD_CTX *mctx, const char *digestname,
++                              EVP_MD_CTX *mctx, const char *digestname, const char *kemop,
+                               OSSL_LIB_CTX *libctx, const char *propq);
+ 
+ static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file,
+@@ -32,7 +32,8 @@ static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file,
+ 
+ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op,
+                     unsigned char *out, size_t *poutlen,
+-                    const unsigned char *in, size_t inlen);
++                    const unsigned char *in, size_t inlen,
++                    unsigned char *secret, size_t *psecretlen);
+ 
+ static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx,
+                         EVP_PKEY *pkey, BIO *in,
+@@ -47,6 +48,7 @@ typedef enum OPTION_choice {
+     OPT_DERIVE, OPT_SIGFILE, OPT_INKEY, OPT_PEERKEY, OPT_PASSIN,
+     OPT_PEERFORM, OPT_KEYFORM, OPT_PKEYOPT, OPT_PKEYOPT_PASSIN, OPT_KDF,
+     OPT_KDFLEN, OPT_R_ENUM, OPT_PROV_ENUM,
++    OPT_DECAP, OPT_ENCAP, OPT_SECOUT, OPT_KEMOP,
+     OPT_CONFIG,
+     OPT_RAWIN, OPT_DIGEST
+ } OPTION_CHOICE;
+@@ -64,6 +66,8 @@ const OPTIONS pkeyutl_options[] = {
+     {"encrypt", OPT_ENCRYPT, '-', "Encrypt input data with public key"},
+     {"decrypt", OPT_DECRYPT, '-', "Decrypt input data with private key"},
+     {"derive", OPT_DERIVE, '-', "Derive shared secret"},
++    {"decap", OPT_DECAP, '-', "Decapsulate shared secret"},
++    {"encap", OPT_ENCAP, '-', "Encapsulate shared secret"},
+     OPT_CONFIG_OPTION,
+ 
+     OPT_SECTION("Input"),
+@@ -81,12 +85,13 @@ const OPTIONS pkeyutl_options[] = {
+ 
+     OPT_SECTION("Output"),
+     {"out", OPT_OUT, '>', "Output file - default stdout"},
++    {"secret", OPT_SECOUT, '>', "File to store secret on encapsulation"},
+     {"asn1parse", OPT_ASN1PARSE, '-', "asn1parse the output data"},
+     {"hexdump", OPT_HEXDUMP, '-', "Hex dump output"},
+     {"verifyrecover", OPT_VERIFYRECOVER, '-',
+      "Verify with public key, recover original data"},
+ 
+-    OPT_SECTION("Signing/Derivation"),
++    OPT_SECTION("Signing/Derivation/Encapsulation"),
+     {"digest", OPT_DIGEST, 's',
+      "Specify the digest algorithm when signing the raw input data"},
+     {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"},
+@@ -94,6 +99,7 @@ const OPTIONS pkeyutl_options[] = {
+      "Public key option that is read as a passphrase argument opt:passphrase"},
+     {"kdf", OPT_KDF, 's', "Use KDF algorithm"},
+     {"kdflen", OPT_KDFLEN, 'p', "KDF algorithm output length"},
++    {"kemop", OPT_KEMOP, 's', "KEM operation specific to the key algorithm"},
+ 
+     OPT_R_OPTIONS,
+     OPT_PROV_OPTIONS,
+@@ -103,23 +109,23 @@ const OPTIONS pkeyutl_options[] = {
+ int pkeyutl_main(int argc, char **argv)
+ {
+     CONF *conf = NULL;
+-    BIO *in = NULL, *out = NULL;
++    BIO *in = NULL, *out = NULL, *secout = NULL;
+     ENGINE *e = NULL;
+     EVP_PKEY_CTX *ctx = NULL;
+     EVP_PKEY *pkey = NULL;
+-    char *infile = NULL, *outfile = NULL, *sigfile = NULL, *passinarg = NULL;
++    char *infile = NULL, *outfile = NULL, *secoutfile = NULL, *sigfile = NULL, *passinarg = NULL;
+     char hexdump = 0, asn1parse = 0, rev = 0, *prog;
+-    unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL;
++    unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL, *secret = NULL;
+     OPTION_CHOICE o;
+     int buf_inlen = 0, siglen = -1;
+     int keyform = FORMAT_UNDEF, peerform = FORMAT_UNDEF;
+     int keysize = -1, pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY;
+     int engine_impl = 0;
+     int ret = 1, rv = -1;
+-    size_t buf_outlen;
++    size_t buf_outlen = 0, secretlen = 0;
+     const char *inkey = NULL;
+     const char *peerkey = NULL;
+-    const char *kdfalg = NULL, *digestname = NULL;
++    const char *kdfalg = NULL, *digestname = NULL, *kemop = NULL;
+     int kdflen = 0;
+     STACK_OF(OPENSSL_STRING) *pkeyopts = NULL;
+     STACK_OF(OPENSSL_STRING) *pkeyopts_passin = NULL;
+@@ -147,6 +153,9 @@ int pkeyutl_main(int argc, char **argv)
+         case OPT_OUT:
+             outfile = opt_arg();
+             break;
++        case OPT_SECOUT:
++            secoutfile = opt_arg();
++            break;
+         case OPT_SIGFILE:
+             sigfile = opt_arg();
+             break;
+@@ -216,6 +225,15 @@ int pkeyutl_main(int argc, char **argv)
+         case OPT_DERIVE:
+             pkey_op = EVP_PKEY_OP_DERIVE;
+             break;
++        case OPT_DECAP:
++            pkey_op = EVP_PKEY_OP_DECAPSULATE;
++            break;
++        case OPT_ENCAP:
++            pkey_op = EVP_PKEY_OP_ENCAPSULATE;
++            break;
++        case OPT_KEMOP:
++            kemop = opt_arg();
++            break;
+         case OPT_KDF:
+             pkey_op = EVP_PKEY_OP_DERIVE;
+             key_type = KEY_NONE;
+@@ -303,7 +321,7 @@ int pkeyutl_main(int argc, char **argv)
+     }
+     ctx = init_ctx(kdfalg, &keysize, inkey, keyform, key_type,
+                    passinarg, pkey_op, e, engine_impl, rawin, &pkey,
+-                   mctx, digestname, libctx, app_get0_propq());
++                   mctx, digestname, kemop, libctx, app_get0_propq());
+     if (ctx == NULL) {
+         BIO_printf(bio_err, "%s: Error initializing context\n", prog);
+         goto end;
+@@ -387,7 +405,7 @@ int pkeyutl_main(int argc, char **argv)
+         goto end;
+     }
+ 
+-    if (pkey_op != EVP_PKEY_OP_DERIVE) {
++    if (pkey_op != EVP_PKEY_OP_DERIVE && pkey_op != EVP_PKEY_OP_ENCAPSULATE) {
+         in = bio_open_default(infile, 'r', FORMAT_BINARY);
+         if (infile != NULL) {
+             struct stat st;
+@@ -402,6 +420,16 @@ int pkeyutl_main(int argc, char **argv)
+     if (out == NULL)
+         goto end;
+ 
++    if (pkey_op == EVP_PKEY_OP_ENCAPSULATE) {
++        if (secoutfile == NULL) {
++            BIO_printf(bio_err, "Encapsulation requires '-secret' argument\n");
++            goto end;
++        }
++        secout = bio_open_default(secoutfile, 'w', FORMAT_BINARY);
++        if (secout == NULL)
++            goto end;
++    }
++
+     if (sigfile != NULL) {
+         BIO *sigbio = BIO_new_file(sigfile, "rb");
+ 
+@@ -473,13 +501,15 @@ int pkeyutl_main(int argc, char **argv)
+             rv = 1;
+         } else {
+             rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen,
+-                          buf_in, (size_t)buf_inlen);
++                          buf_in, (size_t)buf_inlen, NULL, (size_t *)&secretlen);
+         }
+         if (rv > 0 && buf_outlen != 0) {
+             buf_out = app_malloc(buf_outlen, "buffer output");
++            if (secretlen > 0)
++                secret = app_malloc(secretlen, "secret output");
+             rv = do_keyop(ctx, pkey_op,
+                           buf_out, (size_t *)&buf_outlen,
+-                          buf_in, (size_t)buf_inlen);
++                          buf_in, (size_t)buf_inlen, secret, (size_t *)&secretlen);
+         }
+     }
+     if (rv <= 0) {
+@@ -500,6 +530,8 @@ int pkeyutl_main(int argc, char **argv)
+     } else {
+         BIO_write(out, buf_out, buf_outlen);
+     }
++    if (secretlen > 0)
++        BIO_write(secout, secret, secretlen);
+ 
+  end:
+     if (ret != 0)
+@@ -510,9 +542,11 @@ int pkeyutl_main(int argc, char **argv)
+     release_engine(e);
+     BIO_free(in);
+     BIO_free_all(out);
++    BIO_free_all(secout);
+     OPENSSL_free(buf_in);
+     OPENSSL_free(buf_out);
+     OPENSSL_free(sig);
++    OPENSSL_free(secret);
+     sk_OPENSSL_STRING_free(pkeyopts);
+     sk_OPENSSL_STRING_free(pkeyopts_passin);
+     NCONF_free(conf);
+@@ -524,7 +558,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize,
+                               char *passinarg, int pkey_op, ENGINE *e,
+                               const int engine_impl, int rawin,
+                               EVP_PKEY **ppkey, EVP_MD_CTX *mctx, const char *digestname,
+-                              OSSL_LIB_CTX *libctx, const char *propq)
++                              const char *kemop, OSSL_LIB_CTX *libctx, const char *propq)
+ {
+     EVP_PKEY *pkey = NULL;
+     EVP_PKEY_CTX *ctx = NULL;
+@@ -642,6 +676,18 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize,
+         case EVP_PKEY_OP_DERIVE:
+             rv = EVP_PKEY_derive_init(ctx);
+             break;
++
++        case EVP_PKEY_OP_ENCAPSULATE:
++            rv = EVP_PKEY_encapsulate_init(ctx, NULL);
++            if (rv > 0 && kemop != NULL)
++                rv = EVP_PKEY_CTX_set_kem_op(ctx, kemop);
++            break;
++
++        case EVP_PKEY_OP_DECAPSULATE:
++            rv = EVP_PKEY_decapsulate_init(ctx, NULL);
++            if (rv > 0 && kemop != NULL)
++                rv = EVP_PKEY_CTX_set_kem_op(ctx, kemop);
++            break;
+         }
+     }
+ 
+@@ -679,7 +725,8 @@ static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file,
+ 
+ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op,
+                     unsigned char *out, size_t *poutlen,
+-                    const unsigned char *in, size_t inlen)
++                    const unsigned char *in, size_t inlen,
++                    unsigned char *secret, size_t *pseclen)
+ {
+     int rv = 0;
+     switch (pkey_op) {
+@@ -703,6 +750,14 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op,
+         rv = EVP_PKEY_derive(ctx, out, poutlen);
+         break;
+ 
++    case EVP_PKEY_OP_ENCAPSULATE:
++        rv = EVP_PKEY_encapsulate(ctx, out, poutlen, secret, pseclen);
++        break;
++
++    case EVP_PKEY_OP_DECAPSULATE:
++        rv = EVP_PKEY_decapsulate(ctx, out, poutlen, in, inlen);
++        break;
++
+     }
+     return rv;
+ }
+
+From 1598da873df55887c2d878549f74b7aaed6d5fde Mon Sep 17 00:00:00 2001
+From: Dmitry Belyavskiy <beldmit@gmail.com>
+Date: Wed, 7 Aug 2024 17:50:51 +0200
+Subject: [PATCH 2/3] Encap/decap in pkeyutl - documentation
+
+---
+ doc/man1/openssl-pkeyutl.pod.in | 33 +++++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in
+index 50c2030aa353c..9de50dd6cee8f 100644
+--- a/doc/man1/openssl-pkeyutl.pod.in
++++ b/doc/man1/openssl-pkeyutl.pod.in
+@@ -13,6 +13,7 @@ B<openssl> B<pkeyutl>
+ [B<-rawin>]
+ [B<-digest> I<algorithm>]
+ [B<-out> I<file>]
++[B<-secret> I<file>]
+ [B<-sigfile> I<file>]
+ [B<-inkey> I<filename>|I<uri>]
+ [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
+@@ -28,8 +29,11 @@ B<openssl> B<pkeyutl>
+ [B<-encrypt>]
+ [B<-decrypt>]
+ [B<-derive>]
++[B<-encap>]
++[B<-decap>]
+ [B<-kdf> I<algorithm>]
+ [B<-kdflen> I<length>]
++[B<-kemop> I<operation>]
+ [B<-pkeyopt> I<opt>:I<value>]
+ [B<-pkeyopt_passin> I<opt>[:I<passarg>]]
+ [B<-hexdump>]
+@@ -79,6 +83,10 @@ then the B<-rawin> option must be also specified.
+ Specifies the output filename to write to or standard output by
+ default.
+ 
++=item B<-secret> I<filename>
++
++Specifies the output filename to write the secret to on I<-encap>.
++
+ =item B<-sigfile> I<file>
+ 
+ Signature file, required for B<-verify> operations only
+@@ -147,6 +155,31 @@ Decrypt the input data using a private key.
+ 
+ Derive a shared secret using the peer key.
+ 
++=item B<-encap>
++
++Encapsulate a generated secret using a private key.
++The encapsulated result (binary data) is written to standard output by default,
++or else to the file specified with I<-out>.
++The I<-secret> option must also be provided to specify the output file for the
++secret value generated in the encapsulation process.
++
++=item B<-decap>
++
++Decapsulate the secret using a private key.
++The result (binary data) is written to standard output by default, or else to
++the file specified with I<-out>.
++
++=item B<-kemop> I<operation>
++
++This option is used for I<-encap>/I<-decap> commands and specifies the KEM
++operation specific for the key algorithm when there is no default KEM
++operation.
++If the algorithm has the default KEM operation, this option can be omitted.
++
++See L<EVP_PKEY_CTX_set_kem_op(3)> and algorithm-specific KEM documentation e.g.
++L<EVP_KEM-RSA(7)>, L<EVP_KEM-EC(7)>, L<EVP_KEM-X25519(7)>, and
++L<EVP_KEM-X448(7)>.
++
+ =item B<-kdf> I<algorithm>
+ 
+ Use key derivation function I<algorithm>.  The supported algorithms are
+
+From 1fe7d5b3d96e2ce1e822a4e6e042959af55b0145 Mon Sep 17 00:00:00 2001
+From: Dmitry Belyavskiy <beldmit@gmail.com>
+Date: Thu, 8 Aug 2024 13:45:19 +0200
+Subject: [PATCH 3/3] Encap/decap in pkeyutl - tests
+
+---
+ test/decap_out.bin             |  3 +++
+ test/encap_out.bin             |  4 ++++
+ test/encap_secret.bin          |  3 +++
+ test/recipes/20-test_pkeyutl.t | 34 ++++++++++++++++++++++++++++++++--
+ 4 files changed, 42 insertions(+), 2 deletions(-)
+ create mode 100644 test/decap_out.bin
+ create mode 100644 test/encap_out.bin
+ create mode 100644 test/encap_secret.bin
+
+diff --git a/test/decap_out.bin b/test/decap_out.bin
+new file mode 100644
+index 0000000000000..b94441ed1c002
+--- /dev/null
++++ b/test/decap_out.bin
+@@ -0,0 +1,3 @@
++6�W�\x06����n���;��^[����m� ĥ�B\x18[H^[���#�Ӈ(��h�]\f:\�\x14P��\x13x�e���b��)G�f��"��˭f�	\b��J�\x03)���\x02��\v{�H\x03m�\P\fú�+�P޸%��/j\x15ϙ\x06%�؆�<_�~^[�
++K�JEh����lEa�:�(�\x10�\a/\Ѯ�b��î�\x10�\v\x0e\x18�\x19\x11�-g,A\x14Y��4�
++l�\x14�t�N�)~\�HU4\x01y\x1c\x16�	\x13}qJ�\b�\f�t#\f��}.��T���?��ϊ��cD=�\aL�\x13�n\x16mv�{�\x16�ſԋȣ�
+\ No newline at end of file
+diff --git a/test/encap_out.bin b/test/encap_out.bin
+new file mode 100644
+index 0000000000000..024fc40550f15
+--- /dev/null
++++ b/test/encap_out.bin
+@@ -0,0 +1,4 @@
++�\a:��y�Đ�\x055�\x11���[�2�<��?��qժ1�������>Y�M寬3P�
++��O�2r�ي��Ad"\vG�m�2m��7x��h�7-\x7f�\a@:\x0e?N�\x1c�rSꋜK��\x05\x13��`�t�ɟ��xi�头'	M\x12h\x1e��3\x02\x02r�\x1f��ڃ�^[Sd��O���HT�F\x0e��
++��kZ\x12'x�F�K�x�q"\x1c���l@04E�����;c�iA}U��\x7f�\fP6�k\x7f\x020��\x0f�%D��L\x19\x16�.U��aO�(L�I��Q���A
++�[�uԞ�4s$���%t�B
+\ No newline at end of file
+diff --git a/test/encap_secret.bin b/test/encap_secret.bin
+new file mode 100644
+index 0000000000000..b94441ed1c002
+--- /dev/null
++++ b/test/encap_secret.bin
+@@ -0,0 +1,3 @@
++6�W�\x06����n���;��^[����m� ĥ�B\x18[H^[���#�Ӈ(��h�]\f:\�\x14P��\x13x�e���b��)G�f��"��˭f�	\b��J�\x03)���\x02��\v{�H\x03m�\P\fú�+�P޸%��/j\x15ϙ\x06%�؆�<_�~^[�
++K�JEh����lEa�:�(�\x10�\a/\Ѯ�b��î�\x10�\v\x0e\x18�\x19\x11�-g,A\x14Y��4�
++l�\x14�t�N�)~\�HU4\x01y\x1c\x16�	\x13}qJ�\b�\f�t#\f��}.��T���?��ϊ��cD=�\aL�\x13�n\x16mv�{�\x16�ſԋȣ�
+\ No newline at end of file
+diff --git a/test/recipes/20-test_pkeyutl.t b/test/recipes/20-test_pkeyutl.t
+index 76e4f0a869459..e9472a21352e2 100644
+--- a/test/recipes/20-test_pkeyutl.t
++++ b/test/recipes/20-test_pkeyutl.t
+@@ -13,11 +13,11 @@ use File::Spec;
+ use File::Basename;
+ use OpenSSL::Test qw/:DEFAULT srctop_file ok_nofips/;
+ use OpenSSL::Test::Utils;
+-use File::Compare qw/compare_text/;
++use File::Compare qw/compare_text compare/;
+ 
+ setup("test_pkeyutl");
+ 
+-plan tests => 14;
++plan tests => 19;
+ 
+ # For the tests below we use the cert itself as the TBS file
+ 
+@@ -200,3 +200,33 @@ SKIP: {
+                     "-rawin");
+     };
+ }
++
++#Encap/decap tests
++# openssl pkeyutl -encap -pubin -inkey rsa_pub.pem -secret secret.bin -out encap_out.bin
++# openssl pkeyutl -decap -inkey rsa_priv.pem -in encap_out.bin -out decap_out.bin
++# decap_out is equal to secret
++SKIP: {
++    skip "RSA is not supported by this OpenSSL build", 3
++        if disabled("rsa");
++
++    # Self-compat
++    ok(run(app(([ 'openssl', 'pkeyutl', '-encap', '-pubin', '-kemop', 'RSASVE',
++                  '-inkey', srctop_file('test', 'testrsa2048pub.pem'),
++                  '-out', 'encap_out.bin', '-secret', 'secret.bin']))),
++                  "RSA pubkey encapsulation");
++    ok(run(app(([ 'openssl', 'pkeyutl', '-decap', '-kemop', 'RSASVE',
++                  '-inkey', srctop_file('test', 'testrsa2048.pem'),
++                  '-in', 'encap_out.bin', '-out', 'decap_out.bin']))),
++                  "RSA pubkey decapsulation");
++    is(compare("secret.bin", "decap_out.bin"), 0, "Secret is correctly decapsulated");
++
++    # Pregenerated
++    ok(run(app(([ 'openssl', 'pkeyutl', '-decap', '-kemop', 'RSASVE',
++                  '-inkey', srctop_file('test', 'testrsa2048.pem'),
++                  '-in', srctop_file('test', 'encap_out.bin'), '-out', 'decap_out_etl.bin']))),
++                  "RSA pubkey decapsulation - pregenerated");
++
++    is(compare(srctop_file('test', 'encap_secret.bin'), "decap_out_etl.bin"), 0,
++               "Secret is correctly decapsulated - pregenerated");
++}
++

diff --git a/0127-speedup-SSL_add_cert_subjects_to_stack.patch b/0127-speedup-SSL_add_cert_subjects_to_stack.patch
new file mode 100644
index 0000000..a6bd503
--- /dev/null
+++ b/0127-speedup-SSL_add_cert_subjects_to_stack.patch
@@ -0,0 +1,201 @@
+From e2e469593a15681983d16e36d856bf8fb7de8589 Mon Sep 17 00:00:00 2001
+From: Clemens Lang <cllang@redhat.com>
+Date: Wed, 31 Jul 2024 12:45:11 +0200
+Subject: [PATCH] Speed up SSL_add_{file,dir}_cert_subjects_to_stack
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The X509_NAME comparison function converts its arguments to DER using
+i2d_X509_NAME before comparing the results using memcmp(). For every
+invocation of the comparison function (of which there are many when
+loading many certificates), it allocates two buffers of the appropriate
+size for the DER encoding.
+
+Switching to static buffers (possibly of X509_NAME_MAX size as defined
+in crypto/x509/x_name.c) would not work with multithreaded use, e.g.,
+when two threads sort two separate STACK_OF(X509_NAME)s at the same
+time. A suitable re-usable buffer could have been added to the
+STACK_OF(X509_NAME) if sk_X509_NAME_compfunc did have a void* argument,
+or a pointer to the STACK_OF(X509_NAME) – but it does not.
+
+Instead, copy the solution chosen in SSL_load_client_CA_file() by
+filling an LHASH_OF(X509_NAME) with all existing names in the stack and
+using that to deduplicate, rather than relying on sk_X509_NAME_find(),
+which ends up being very slow.
+
+Adjust SSL_add_dir_cert_subjects_to_stack() to keep a local
+LHASH_OF(X509_NAME)s over the complete directory it is processing.
+
+In a small benchmark that calls SSL_add_dir_cert_subjects_to_stack()
+twice, once on a directory with one entry, and once with a directory
+with 1000 certificates, and repeats this in a loop 10 times, this change
+yields a speed-up of 5.32:
+
+| Benchmark 1: ./bench 10 dir-1 dir-1000
+|   Time (mean ± σ):      6.685 s ±  0.017 s    [User: 6.402 s, System: 0.231 s]
+|   Range (min … max):    6.658 s …  6.711 s    10 runs
+|
+| Benchmark 2: LD_LIBRARY_PATH=. ./bench 10 dir-1 dir-1000
+|   Time (mean ± σ):      1.256 s ±  0.013 s    [User: 1.034 s, System: 0.212 s]
+|   Range (min … max):    1.244 s …  1.286 s    10 runs
+|
+| Summary
+|   LD_LIBRARY_PATH=. ./bench 10 dir-1 dir-1000 ran
+|    5.32 ± 0.06 times faster than ./bench 10 dir-1 dir-1000
+
+In the worst case scenario where many entries are added to a stack that
+is then repeatedly used to add more certificates, and with a larger test
+size, the speedup is still very significant. With 15000 certificates,
+a single pass to load them, followed by attempting to load a subset of
+1000 of these 15000 certificates, followed by a single certificate, the
+new approach is ~85 times faster:
+
+| Benchmark 1: ./bench 1 dir-15000 dir-1000 dir-1
+|   Time (mean ± σ):     176.295 s ±  4.147 s    [User: 174.593 s, System: 0.448 s]
+|   Range (min … max):   173.774 s … 185.594 s    10 runs
+|
+| Benchmark 2: LD_LIBRARY_PATH=. ./bench 1 dir-15000 dir-1000 dir-1
+|   Time (mean ± σ):      2.087 s ±  0.034 s    [User: 1.679 s, System: 0.393 s]
+|   Range (min … max):    2.057 s …  2.167 s    10 runs
+|
+| Summary
+|   LD_LIBRARY_PATH=. ./bench 1 dir-15000 dir-1000 dir-1 ran
+|    84.48 ± 2.42 times faster than ./bench 1 dir-15000 dir-1000 dir-1
+
+Signed-off-by: Clemens Lang <cllang@redhat.com>
+---
+ ssl/ssl_cert.c | 74 ++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 65 insertions(+), 9 deletions(-)
+
+diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
+index 0ff407bf55edc..5e5ffe39d0655 100644
+--- a/ssl/ssl_cert.c
++++ b/ssl/ssl_cert.c
+@@ -813,16 +813,14 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file)
+     return SSL_load_client_CA_file_ex(file, NULL, NULL);
+ }
+ 
+-int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+-                                        const char *file)
++static int add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
++                                           const char *file,
++                                           LHASH_OF(X509_NAME) *name_hash)
+ {
+     BIO *in;
+     X509 *x = NULL;
+     X509_NAME *xn = NULL;
+     int ret = 1;
+-    int (*oldcmp) (const X509_NAME *const *a, const X509_NAME *const *b);
+-
+-    oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_sk_cmp);
+ 
+     in = BIO_new(BIO_s_file());
+ 
+@@ -842,12 +840,15 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+         xn = X509_NAME_dup(xn);
+         if (xn == NULL)
+             goto err;
+-        if (sk_X509_NAME_find(stack, xn) >= 0) {
++        if (lh_X509_NAME_retrieve(name_hash, xn) != NULL) {
+             /* Duplicate. */
+             X509_NAME_free(xn);
+         } else if (!sk_X509_NAME_push(stack, xn)) {
+             X509_NAME_free(xn);
+             goto err;
++        } else {
++            /* Successful insert, add to hash table */
++            lh_X509_NAME_insert(name_hash, xn);
+         }
+     }
+ 
+@@ -859,7 +860,42 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+  done:
+     BIO_free(in);
+     X509_free(x);
+-    (void)sk_X509_NAME_set_cmp_func(stack, oldcmp);
++    return ret;
++}
++
++int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
++                                        const char *file)
++{
++    X509_NAME *xn = NULL;
++    int ret = 1;
++    int idx = 0;
++    int num = 0;
++    LHASH_OF(X509_NAME) *name_hash = lh_X509_NAME_new(xname_hash, xname_cmp);
++
++    if (name_hash == NULL) {
++        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
++        goto err;
++    }
++
++    /*
++     * Pre-populate the lhash with the existing entries of the stack, since
++     * using the LHASH_OF is much faster for duplicate checking. That's because
++     * xname_cmp converts the X509_NAMEs to DER involving a memory allocation
++     * for every single invocation of the comparison function.
++     */
++    num = sk_X509_NAME_num(stack);
++    for (idx = 0; idx < num; idx++) {
++        xn = sk_X509_NAME_value(stack, idx);
++        lh_X509_NAME_insert(name_hash, xn);
++    }
++
++    ret = add_file_cert_subjects_to_stack(stack, file, name_hash);
++    goto done;
++
++ err:
++    ret = 0;
++ done:
++    lh_X509_NAME_free(name_hash);
+     return ret;
+ }
+ 
+@@ -869,8 +905,27 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+     OPENSSL_DIR_CTX *d = NULL;
+     const char *filename;
+     int ret = 0;
++    X509_NAME *xn = NULL;
++    int idx = 0;
++    int num = 0;
++    LHASH_OF(X509_NAME) *name_hash = lh_X509_NAME_new(xname_hash, xname_cmp);
++
++    if (name_hash == NULL) {
++        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
++        goto err;
++    }
+ 
+-    /* Note that a side effect is that the CAs will be sorted by name */
++    /*
++     * Pre-populate the lhash with the existing entries of the stack, since
++     * using the LHASH_OF is much faster for duplicate checking. That's because
++     * xname_cmp converts the X509_NAMEs to DER involving a memory allocation
++     * for every single invocation of the comparison function.
++     */
++    num = sk_X509_NAME_num(stack);
++    for (idx = 0; idx < num; idx++) {
++        xn = sk_X509_NAME_value(stack, idx);
++        lh_X509_NAME_insert(name_hash, xn);
++    }
+ 
+     while ((filename = OPENSSL_DIR_read(&d, dir))) {
+         char buf[1024];
+@@ -899,7 +954,7 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ #endif
+         if (r <= 0 || r >= (int)sizeof(buf))
+             goto err;
+-        if (!SSL_add_file_cert_subjects_to_stack(stack, buf))
++        if (!add_file_cert_subjects_to_stack(stack, buf, name_hash))
+             goto err;
+     }
+ 
+@@ -915,6 +970,7 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+  err:
+     if (d)
+         OPENSSL_DIR_end(&d);
++    lh_X509_NAME_free(name_hash);
+ 
+     return ret;
+ }

diff --git a/0128-SAST-findings.patch b/0128-SAST-findings.patch
new file mode 100644
index 0000000..77cb8e9
--- /dev/null
+++ b/0128-SAST-findings.patch
@@ -0,0 +1,24 @@
+diff -up openssl-3.2.2/crypto/rsa/rsa_oaep.c.xxx openssl-3.2.2/crypto/rsa/rsa_oaep.c
+--- openssl-3.2.2/crypto/rsa/rsa_oaep.c.xxx	2024-08-14 14:22:48.733407808 +0200
++++ openssl-3.2.2/crypto/rsa/rsa_oaep.c	2024-08-14 14:23:32.994483135 +0200
+@@ -233,7 +233,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(un
+ 
+     mdlen = EVP_MD_get_size(md);
+ 
+-    if (tlen <= 0 || flen <= 0)
++    if (tlen <= 0 || flen <= 0 || mdlen <= 0)
+         return -1;
+     /*
+      * |num| is the length of the modulus; |flen| is the length of the
+diff -up openssl-3.2.2/crypto/x509/pcy_tree.c.xxx openssl-3.2.2/crypto/x509/pcy_tree.c
+--- openssl-3.2.2/crypto/x509/pcy_tree.c.xxx	2024-08-14 14:14:13.144850097 +0200
++++ openssl-3.2.2/crypto/x509/pcy_tree.c	2024-08-14 14:14:53.213826481 +0200
+@@ -110,6 +110,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
+ 
+     *ptree = NULL;
+ 
++    if (n < 0)
++        return X509_PCY_TREE_INTERNAL;
+     /* Can't do anything with just a trust anchor */
+     if (n == 0)
+         return X509_PCY_TREE_EMPTY;

diff --git a/0129-Fix-SSL_select_next_proto.patch b/0129-Fix-SSL_select_next_proto.patch
new file mode 100644
index 0000000..6458067
--- /dev/null
+++ b/0129-Fix-SSL_select_next_proto.patch
@@ -0,0 +1,109 @@
+From 99fb785a5f85315b95288921a321a935ea29a51e Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 31 May 2024 11:14:33 +0100
+Subject: [PATCH 01/10] Fix SSL_select_next_proto
+
+Ensure that the provided client list is non-NULL and starts with a valid
+entry. When called from the ALPN callback the client list should already
+have been validated by OpenSSL so this should not cause a problem. When
+called from the NPN callback the client list is locally configured and
+will not have already been validated. Therefore SSL_select_next_proto
+should not assume that it is correctly formatted.
+
+We implement stricter checking of the client protocol list. We also do the
+same for the server list while we are about it.
+
+CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ ssl/ssl_lib.c | 63 ++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 40 insertions(+), 23 deletions(-)
+
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index 016135fe18..cf52b317cf 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -3518,37 +3518,54 @@ int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
+                           unsigned int server_len,
+                           const unsigned char *client, unsigned int client_len)
+ {
+-    unsigned int i, j;
+-    const unsigned char *result;
+-    int status = OPENSSL_NPN_UNSUPPORTED;
++    PACKET cpkt, csubpkt, spkt, ssubpkt;
++
++    if (!PACKET_buf_init(&cpkt, client, client_len)
++            || !PACKET_get_length_prefixed_1(&cpkt, &csubpkt)
++            || PACKET_remaining(&csubpkt) == 0) {
++        *out = NULL;
++        *outlen = 0;
++        return OPENSSL_NPN_NO_OVERLAP;
++    }
++
++    /*
++     * Set the default opportunistic protocol. Will be overwritten if we find
++     * a match.
++     */
++    *out = (unsigned char *)PACKET_data(&csubpkt);
++    *outlen = (unsigned char)PACKET_remaining(&csubpkt);
+ 
+     /*
+      * For each protocol in server preference order, see if we support it.
+      */
+-    for (i = 0; i < server_len;) {
+-        for (j = 0; j < client_len;) {
+-            if (server[i] == client[j] &&
+-                memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) {
+-                /* We found a match */
+-                result = &server[i];
+-                status = OPENSSL_NPN_NEGOTIATED;
+-                goto found;
++    if (PACKET_buf_init(&spkt, server, server_len)) {
++        while (PACKET_get_length_prefixed_1(&spkt, &ssubpkt)) {
++            if (PACKET_remaining(&ssubpkt) == 0)
++                continue; /* Invalid - ignore it */
++            if (PACKET_buf_init(&cpkt, client, client_len)) {
++                while (PACKET_get_length_prefixed_1(&cpkt, &csubpkt)) {
++                    if (PACKET_equal(&csubpkt, PACKET_data(&ssubpkt),
++                                     PACKET_remaining(&ssubpkt))) {
++                        /* We found a match */
++                        *out = (unsigned char *)PACKET_data(&ssubpkt);
++                        *outlen = (unsigned char)PACKET_remaining(&ssubpkt);
++                        return OPENSSL_NPN_NEGOTIATED;
++                    }
++                }
++                /* Ignore spurious trailing bytes in the client list */
++            } else {
++                /* This should never happen */
++                return OPENSSL_NPN_NO_OVERLAP;
+             }
+-            j += client[j];
+-            j++;
+         }
+-        i += server[i];
+-        i++;
++        /* Ignore spurious trailing bytes in the server list */
+     }
+ 
+-    /* There's no overlap between our protocols and the server's list. */
+-    result = client;
+-    status = OPENSSL_NPN_NO_OVERLAP;
+-
+- found:
+-    *out = (unsigned char *)result + 1;
+-    *outlen = result[0];
+-    return status;
++    /*
++     * There's no overlap between our protocols and the server's list. We use
++     * the default opportunistic protocol selected earlier
++     */
++    return OPENSSL_NPN_NO_OVERLAP;
+ }
+ 
+ #ifndef OPENSSL_NO_NEXTPROTONEG
+-- 
+2.46.0
+

diff --git a/0130-More-correctly-handle-a-selected_len-of-0-when-proce.patch b/0130-More-correctly-handle-a-selected_len-of-0-when-proce.patch
new file mode 100644
index 0000000..29d22c6
--- /dev/null
+++ b/0130-More-correctly-handle-a-selected_len-of-0-when-proce.patch
@@ -0,0 +1,39 @@
+From 015255851371757d54c2560643eb3b3a88123cf1 Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 31 May 2024 11:18:27 +0100
+Subject: [PATCH 02/10] More correctly handle a selected_len of 0 when
+ processing NPN
+
+In the case where the NPN callback returns with SSL_TLEXT_ERR_OK, but
+the selected_len is 0 we should fail. Previously this would fail with an
+internal_error alert because calling OPENSSL_malloc(selected_len) will
+return NULL when selected_len is 0. We make this error detection more
+explicit and return a handshake failure alert.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ ssl/statem/extensions_clnt.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 381a6c9d7b..1ab3c13d57 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1560,8 +1560,8 @@ int tls_parse_stoc_npn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+     if (sctx->ext.npn_select_cb(SSL_CONNECTION_GET_SSL(s),
+                                 &selected, &selected_len,
+                                 PACKET_data(pkt), PACKET_remaining(pkt),
+-                                sctx->ext.npn_select_cb_arg) !=
+-             SSL_TLSEXT_ERR_OK) {
++                                sctx->ext.npn_select_cb_arg) != SSL_TLSEXT_ERR_OK
++            || selected_len == 0) {
+         SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_EXTENSION);
+         return 0;
+     }
+-- 
+2.46.0
+

diff --git a/0131-Use-correctly-formatted-ALPN-data-in-tserver.patch b/0131-Use-correctly-formatted-ALPN-data-in-tserver.patch
new file mode 100644
index 0000000..028732f
--- /dev/null
+++ b/0131-Use-correctly-formatted-ALPN-data-in-tserver.patch
@@ -0,0 +1,34 @@
+From 6cc511826f09e513b4ec066d9b95acaf4f86d991 Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 31 May 2024 11:22:13 +0100
+Subject: [PATCH 03/10] Use correctly formatted ALPN data in tserver
+
+The QUIC test server was using incorrectly formatted ALPN data. With the
+previous implementation of SSL_select_next_proto this went unnoticed. With
+the new stricter implemenation it was failing.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ ssl/quic/quic_tserver.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c
+index 86187d06ff..15694e723f 100644
+--- a/ssl/quic/quic_tserver.c
++++ b/ssl/quic/quic_tserver.c
+@@ -58,7 +58,7 @@ static int alpn_select_cb(SSL *ssl, const unsigned char **out,
+ 
+     if (srv->args.alpn == NULL) {
+         alpn = alpndeflt;
+-        alpnlen = sizeof(alpn);
++        alpnlen = sizeof(alpndeflt);
+     } else {
+         alpn = srv->args.alpn;
+         alpnlen = srv->args.alpnlen;
+-- 
+2.46.0
+

diff --git a/0132-Clarify-the-SSL_select_next_proto-documentation.patch b/0132-Clarify-the-SSL_select_next_proto-documentation.patch
new file mode 100644
index 0000000..34e6261
--- /dev/null
+++ b/0132-Clarify-the-SSL_select_next_proto-documentation.patch
@@ -0,0 +1,78 @@
+From 8e81c57adbbf703dfb63955f65599765fdacc741 Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 31 May 2024 11:46:38 +0100
+Subject: [PATCH 04/10] Clarify the SSL_select_next_proto() documentation
+
+We clarify the input preconditions and the expected behaviour in the event
+of no overlap.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ doc/man3/SSL_CTX_set_alpn_select_cb.pod | 26 +++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_alpn_select_cb.pod b/doc/man3/SSL_CTX_set_alpn_select_cb.pod
+index 05fee2fbec..79e1a252f6 100644
+--- a/doc/man3/SSL_CTX_set_alpn_select_cb.pod
++++ b/doc/man3/SSL_CTX_set_alpn_select_cb.pod
+@@ -52,7 +52,8 @@ SSL_select_next_proto, SSL_get0_alpn_selected, SSL_get0_next_proto_negotiated
+ SSL_CTX_set_alpn_protos() and SSL_set_alpn_protos() are used by the client to
+ set the list of protocols available to be negotiated. The B<protos> must be in
+ protocol-list format, described below. The length of B<protos> is specified in
+-B<protos_len>.
++B<protos_len>. Setting B<protos_len> to 0 clears any existing list of ALPN
++protocols and no ALPN extension will be sent to the server.
+ 
+ SSL_CTX_set_alpn_select_cb() sets the application callback B<cb> used by a
+ server to select which protocol to use for the incoming connection. When B<cb>
+@@ -73,9 +74,16 @@ B<server_len> and B<client>, B<client_len> must be in the protocol-list format
+ described below. The first item in the B<server>, B<server_len> list that
+ matches an item in the B<client>, B<client_len> list is selected, and returned
+ in B<out>, B<outlen>. The B<out> value will point into either B<server> or
+-B<client>, so it should be copied immediately. If no match is found, the first
+-item in B<client>, B<client_len> is returned in B<out>, B<outlen>. This
+-function can also be used in the NPN callback.
++B<client>, so it should be copied immediately. The client list must include at
++least one valid (nonempty) protocol entry in the list.
++
++The SSL_select_next_proto() helper function can be useful from either the ALPN
++callback or the NPN callback (described below). If no match is found, the first
++item in B<client>, B<client_len> is returned in B<out>, B<outlen> and
++B<OPENSSL_NPN_NO_OVERLAP> is returned. This can be useful when implementating
++the NPN callback. In the ALPN case, the value returned in B<out> and B<outlen>
++must be ignored if B<OPENSSL_NPN_NO_OVERLAP> has been returned from
++SSL_select_next_proto().
+ 
+ SSL_CTX_set_next_proto_select_cb() sets a callback B<cb> that is called when a
+ client needs to select a protocol from the server's provided list, and a
+@@ -85,9 +93,10 @@ must be set to point to the selected protocol (which may be within B<in>).
+ The length of the protocol name must be written into B<outlen>. The
+ server's advertised protocols are provided in B<in> and B<inlen>. The
+ callback can assume that B<in> is syntactically valid. The client must
+-select a protocol. It is fatal to the connection if this callback returns
+-a value other than B<SSL_TLSEXT_ERR_OK>. The B<arg> parameter is the pointer
+-set via SSL_CTX_set_next_proto_select_cb().
++select a protocol (although it may be an empty, zero length protocol). It is
++fatal to the connection if this callback returns a value other than
++B<SSL_TLSEXT_ERR_OK> or if the zero length protocol is selected. The B<arg>
++parameter is the pointer set via SSL_CTX_set_next_proto_select_cb().
+ 
+ SSL_CTX_set_next_protos_advertised_cb() sets a callback B<cb> that is called
+ when a TLS server needs a list of supported protocols for Next Protocol
+@@ -154,7 +163,8 @@ A match was found and is returned in B<out>, B<outlen>.
+ =item OPENSSL_NPN_NO_OVERLAP
+ 
+ No match was found. The first item in B<client>, B<client_len> is returned in
+-B<out>, B<outlen>.
++B<out>, B<outlen> (or B<NULL> and 0 in the case where the first entry in
++B<client> is invalid).
+ 
+ =back
+ 
+-- 
+2.46.0
+

diff --git a/0133-Add-a-test-for-SSL_select_next_proto.patch b/0133-Add-a-test-for-SSL_select_next_proto.patch
new file mode 100644
index 0000000..ccf1577
--- /dev/null
+++ b/0133-Add-a-test-for-SSL_select_next_proto.patch
@@ -0,0 +1,172 @@
+From add5c52a25c549cec4a730cdf96e2252f0a1862d Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 31 May 2024 16:35:16 +0100
+Subject: [PATCH 05/10] Add a test for SSL_select_next_proto
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ test/sslapitest.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 137 insertions(+)
+
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index ce163322cd..15cb9060cb 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -11741,6 +11741,142 @@ static int test_multi_resume(int idx)
+     return testresult;
+ }
+ 
++static struct next_proto_st {
++    int serverlen;
++    unsigned char server[40];
++    int clientlen;
++    unsigned char client[40];
++    int expected_ret;
++    size_t selectedlen;
++    unsigned char selected[40];
++} next_proto_tests[] = {
++    {
++        4, { 3, 'a', 'b', 'c' },
++        4, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NEGOTIATED,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        7, { 3, 'a', 'b', 'c', 2, 'a', 'b' },
++        4, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NEGOTIATED,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        7, { 2, 'a', 'b', 3, 'a', 'b', 'c', },
++        4, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NEGOTIATED,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        4, { 3, 'a', 'b', 'c' },
++        7, { 3, 'a', 'b', 'c', 2, 'a', 'b', },
++        OPENSSL_NPN_NEGOTIATED,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        4, { 3, 'a', 'b', 'c' },
++        7, { 2, 'a', 'b', 3, 'a', 'b', 'c'},
++        OPENSSL_NPN_NEGOTIATED,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        7, { 2, 'b', 'c', 3, 'a', 'b', 'c' },
++        7, { 2, 'a', 'b', 3, 'a', 'b', 'c'},
++        OPENSSL_NPN_NEGOTIATED,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        10, { 2, 'b', 'c', 3, 'a', 'b', 'c', 2, 'a', 'b' },
++        7, { 2, 'a', 'b', 3, 'a', 'b', 'c'},
++        OPENSSL_NPN_NEGOTIATED,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        4, { 3, 'b', 'c', 'd' },
++        4, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NO_OVERLAP,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        0, { 0 },
++        4, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NO_OVERLAP,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        -1, { 0 },
++        4, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NO_OVERLAP,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        4, { 3, 'a', 'b', 'c' },
++        0, { 0 },
++        OPENSSL_NPN_NO_OVERLAP,
++        0, { 0 }
++    },
++    {
++        4, { 3, 'a', 'b', 'c' },
++        -1, { 0 },
++        OPENSSL_NPN_NO_OVERLAP,
++        0, { 0 }
++    },
++    {
++        3, { 3, 'a', 'b', 'c' },
++        4, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NO_OVERLAP,
++        3, { 'a', 'b', 'c' }
++    },
++    {
++        4, { 3, 'a', 'b', 'c' },
++        3, { 3, 'a', 'b', 'c' },
++        OPENSSL_NPN_NO_OVERLAP,
++        0, { 0 }
++    }
++};
++
++static int test_select_next_proto(int idx)
++{
++    struct next_proto_st *np = &next_proto_tests[idx];
++    int ret = 0;
++    unsigned char *out, *client, *server;
++    unsigned char outlen;
++    unsigned int clientlen, serverlen;
++
++    if (np->clientlen == -1) {
++        client = NULL;
++        clientlen = 0;
++    } else {
++        client = np->client;
++        clientlen = (unsigned int)np->clientlen;
++    }
++    if (np->serverlen == -1) {
++        server = NULL;
++        serverlen = 0;
++    } else {
++        server = np->server;
++        serverlen = (unsigned int)np->serverlen;
++    }
++
++    if (!TEST_int_eq(SSL_select_next_proto(&out, &outlen, server, serverlen,
++                                           client, clientlen),
++                     np->expected_ret))
++        goto err;
++
++    if (np->selectedlen == 0) {
++        if (!TEST_ptr_null(out) || !TEST_uchar_eq(outlen, 0))
++            goto err;
++    } else {
++        if (!TEST_mem_eq(out, outlen, np->selected, np->selectedlen))
++            goto err;
++    }
++
++    ret = 1;
++ err:
++    return ret;
++}
++
+ OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n")
+ 
+ int setup_tests(void)
+@@ -12053,6 +12189,7 @@ int setup_tests(void)
+     ADD_ALL_TESTS(test_handshake_retry, 16);
+     ADD_TEST(test_data_retry);
+     ADD_ALL_TESTS(test_multi_resume, 5);
++    ADD_ALL_TESTS(test_select_next_proto, OSSL_NELEM(next_proto_tests));
+     return 1;
+ 
+  err:
+-- 
+2.46.0
+

diff --git a/0134-Allow-an-empty-NPN-ALPN-protocol-list-in-the-tests.patch b/0134-Allow-an-empty-NPN-ALPN-protocol-list-in-the-tests.patch
new file mode 100644
index 0000000..ae383c8
--- /dev/null
+++ b/0134-Allow-an-empty-NPN-ALPN-protocol-list-in-the-tests.patch
@@ -0,0 +1,1169 @@
+From 7ea1f6a85b299b976cb3f756b2a7f0153f31b2b6 Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Tue, 4 Jun 2024 15:47:32 +0100
+Subject: [PATCH 06/10] Allow an empty NPN/ALPN protocol list in the tests
+
+Allow ourselves to configure an empty NPN/ALPN protocol list and test what
+happens if we do.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ test/helpers/handshake.c      |   6 +
+ test/ssl-tests/08-npn.cnf     | 553 +++++++++++++++++++---------------
+ test/ssl-tests/08-npn.cnf.in  |  35 +++
+ test/ssl-tests/09-alpn.cnf    |  66 +++-
+ test/ssl-tests/09-alpn.cnf.in |  33 ++
+ 5 files changed, 449 insertions(+), 244 deletions(-)
+
+diff --git a/test/helpers/handshake.c b/test/helpers/handshake.c
+index e0422469e4..6b1629b942 100644
+--- a/test/helpers/handshake.c
++++ b/test/helpers/handshake.c
+@@ -348,6 +348,12 @@ static int parse_protos(const char *protos, unsigned char **out, size_t *outlen)
+ 
+     len = strlen(protos);
+ 
++    if (len == 0) {
++        *out = NULL;
++        *outlen = 0;
++        return 1;
++    }
++
+     /* Should never have reuse. */
+     if (!TEST_ptr_null(*out)
+             /* Test values are small, so we omit length limit checks. */
+diff --git a/test/ssl-tests/08-npn.cnf b/test/ssl-tests/08-npn.cnf
+index f38b3f6975..1931d02de4 100644
+--- a/test/ssl-tests/08-npn.cnf
++++ b/test/ssl-tests/08-npn.cnf
+@@ -1,6 +1,6 @@
+ # Generated with generate_ssl_tests.pl
+ 
+-num_tests = 20
++num_tests = 22
+ 
+ test-0 = 0-npn-simple
+ test-1 = 1-npn-client-finds-match
+@@ -8,20 +8,22 @@ test-2 = 2-npn-client-honours-server-pref
+ test-3 = 3-npn-client-first-pref-on-mismatch
+ test-4 = 4-npn-no-server-support
+ test-5 = 5-npn-no-client-support
+-test-6 = 6-npn-with-sni-no-context-switch
+-test-7 = 7-npn-with-sni-context-switch
+-test-8 = 8-npn-selected-sni-server-supports-npn
+-test-9 = 9-npn-selected-sni-server-does-not-support-npn
+-test-10 = 10-alpn-preferred-over-npn
+-test-11 = 11-sni-npn-preferred-over-alpn
+-test-12 = 12-npn-simple-resumption
+-test-13 = 13-npn-server-switch-resumption
+-test-14 = 14-npn-client-switch-resumption
+-test-15 = 15-npn-client-first-pref-on-mismatch-resumption
+-test-16 = 16-npn-no-server-support-resumption
+-test-17 = 17-npn-no-client-support-resumption
+-test-18 = 18-alpn-preferred-over-npn-resumption
+-test-19 = 19-npn-used-if-alpn-not-supported-resumption
++test-6 = 6-npn-empty-client-list
++test-7 = 7-npn-empty-server-list
++test-8 = 8-npn-with-sni-no-context-switch
++test-9 = 9-npn-with-sni-context-switch
++test-10 = 10-npn-selected-sni-server-supports-npn
++test-11 = 11-npn-selected-sni-server-does-not-support-npn
++test-12 = 12-alpn-preferred-over-npn
++test-13 = 13-sni-npn-preferred-over-alpn
++test-14 = 14-npn-simple-resumption
++test-15 = 15-npn-server-switch-resumption
++test-16 = 16-npn-client-switch-resumption
++test-17 = 17-npn-client-first-pref-on-mismatch-resumption
++test-18 = 18-npn-no-server-support-resumption
++test-19 = 19-npn-no-client-support-resumption
++test-20 = 20-alpn-preferred-over-npn-resumption
++test-21 = 21-npn-used-if-alpn-not-supported-resumption
+ # ===========================================================
+ 
+ [0-npn-simple]
+@@ -206,253 +208,318 @@ NPNProtocols = foo
+ 
+ # ===========================================================
+ 
+-[6-npn-with-sni-no-context-switch]
+-ssl_conf = 6-npn-with-sni-no-context-switch-ssl
++[6-npn-empty-client-list]
++ssl_conf = 6-npn-empty-client-list-ssl
+ 
+-[6-npn-with-sni-no-context-switch-ssl]
+-server = 6-npn-with-sni-no-context-switch-server
+-client = 6-npn-with-sni-no-context-switch-client
+-server2 = 6-npn-with-sni-no-context-switch-server2
++[6-npn-empty-client-list-ssl]
++server = 6-npn-empty-client-list-server
++client = 6-npn-empty-client-list-client
+ 
+-[6-npn-with-sni-no-context-switch-server]
++[6-npn-empty-client-list-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[6-npn-with-sni-no-context-switch-server2]
++[6-npn-empty-client-list-client]
++CipherString = DEFAULT
++MaxProtocol = TLSv1.2
++VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
++VerifyMode = Peer
++
++[test-6]
++ExpectedClientAlert = HandshakeFailure
++ExpectedResult = ClientFail
++server = 6-npn-empty-client-list-server-extra
++client = 6-npn-empty-client-list-client-extra
++
++[6-npn-empty-client-list-server-extra]
++NPNProtocols = foo
++
++[6-npn-empty-client-list-client-extra]
++NPNProtocols = 
++
++
++# ===========================================================
++
++[7-npn-empty-server-list]
++ssl_conf = 7-npn-empty-server-list-ssl
++
++[7-npn-empty-server-list-ssl]
++server = 7-npn-empty-server-list-server
++client = 7-npn-empty-server-list-client
++
++[7-npn-empty-server-list-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[6-npn-with-sni-no-context-switch-client]
++[7-npn-empty-server-list-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-6]
++[test-7]
++ExpectedNPNProtocol = foo
++server = 7-npn-empty-server-list-server-extra
++client = 7-npn-empty-server-list-client-extra
++
++[7-npn-empty-server-list-server-extra]
++NPNProtocols = 
++
++[7-npn-empty-server-list-client-extra]
++NPNProtocols = foo
++
++
++# ===========================================================
++
++[8-npn-with-sni-no-context-switch]
++ssl_conf = 8-npn-with-sni-no-context-switch-ssl
++
++[8-npn-with-sni-no-context-switch-ssl]
++server = 8-npn-with-sni-no-context-switch-server
++client = 8-npn-with-sni-no-context-switch-client
++server2 = 8-npn-with-sni-no-context-switch-server2
++
++[8-npn-with-sni-no-context-switch-server]
++Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
++CipherString = DEFAULT
++PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
++
++[8-npn-with-sni-no-context-switch-server2]
++Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
++CipherString = DEFAULT
++PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
++
++[8-npn-with-sni-no-context-switch-client]
++CipherString = DEFAULT
++MaxProtocol = TLSv1.2
++VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
++VerifyMode = Peer
++
++[test-8]
+ ExpectedNPNProtocol = foo
+ ExpectedServerName = server1
+-server = 6-npn-with-sni-no-context-switch-server-extra
+-server2 = 6-npn-with-sni-no-context-switch-server2-extra
+-client = 6-npn-with-sni-no-context-switch-client-extra
++server = 8-npn-with-sni-no-context-switch-server-extra
++server2 = 8-npn-with-sni-no-context-switch-server2-extra
++client = 8-npn-with-sni-no-context-switch-client-extra
+ 
+-[6-npn-with-sni-no-context-switch-server-extra]
++[8-npn-with-sni-no-context-switch-server-extra]
+ NPNProtocols = foo
+ ServerNameCallback = IgnoreMismatch
+ 
+-[6-npn-with-sni-no-context-switch-server2-extra]
++[8-npn-with-sni-no-context-switch-server2-extra]
+ NPNProtocols = bar
+ 
+-[6-npn-with-sni-no-context-switch-client-extra]
++[8-npn-with-sni-no-context-switch-client-extra]
+ NPNProtocols = foo,bar
+ ServerName = server1
+ 
+ 
+ # ===========================================================
+ 
+-[7-npn-with-sni-context-switch]
+-ssl_conf = 7-npn-with-sni-context-switch-ssl
++[9-npn-with-sni-context-switch]
++ssl_conf = 9-npn-with-sni-context-switch-ssl
+ 
+-[7-npn-with-sni-context-switch-ssl]
+-server = 7-npn-with-sni-context-switch-server
+-client = 7-npn-with-sni-context-switch-client
+-server2 = 7-npn-with-sni-context-switch-server2
++[9-npn-with-sni-context-switch-ssl]
++server = 9-npn-with-sni-context-switch-server
++client = 9-npn-with-sni-context-switch-client
++server2 = 9-npn-with-sni-context-switch-server2
+ 
+-[7-npn-with-sni-context-switch-server]
++[9-npn-with-sni-context-switch-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[7-npn-with-sni-context-switch-server2]
++[9-npn-with-sni-context-switch-server2]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[7-npn-with-sni-context-switch-client]
++[9-npn-with-sni-context-switch-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-7]
++[test-9]
+ ExpectedNPNProtocol = bar
+ ExpectedServerName = server2
+-server = 7-npn-with-sni-context-switch-server-extra
+-server2 = 7-npn-with-sni-context-switch-server2-extra
+-client = 7-npn-with-sni-context-switch-client-extra
++server = 9-npn-with-sni-context-switch-server-extra
++server2 = 9-npn-with-sni-context-switch-server2-extra
++client = 9-npn-with-sni-context-switch-client-extra
+ 
+-[7-npn-with-sni-context-switch-server-extra]
++[9-npn-with-sni-context-switch-server-extra]
+ NPNProtocols = foo
+ ServerNameCallback = IgnoreMismatch
+ 
+-[7-npn-with-sni-context-switch-server2-extra]
++[9-npn-with-sni-context-switch-server2-extra]
+ NPNProtocols = bar
+ 
+-[7-npn-with-sni-context-switch-client-extra]
++[9-npn-with-sni-context-switch-client-extra]
+ NPNProtocols = foo,bar
+ ServerName = server2
+ 
+ 
+ # ===========================================================
+ 
+-[8-npn-selected-sni-server-supports-npn]
+-ssl_conf = 8-npn-selected-sni-server-supports-npn-ssl
++[10-npn-selected-sni-server-supports-npn]
++ssl_conf = 10-npn-selected-sni-server-supports-npn-ssl
+ 
+-[8-npn-selected-sni-server-supports-npn-ssl]
+-server = 8-npn-selected-sni-server-supports-npn-server
+-client = 8-npn-selected-sni-server-supports-npn-client
+-server2 = 8-npn-selected-sni-server-supports-npn-server2
++[10-npn-selected-sni-server-supports-npn-ssl]
++server = 10-npn-selected-sni-server-supports-npn-server
++client = 10-npn-selected-sni-server-supports-npn-client
++server2 = 10-npn-selected-sni-server-supports-npn-server2
+ 
+-[8-npn-selected-sni-server-supports-npn-server]
++[10-npn-selected-sni-server-supports-npn-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[8-npn-selected-sni-server-supports-npn-server2]
++[10-npn-selected-sni-server-supports-npn-server2]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[8-npn-selected-sni-server-supports-npn-client]
++[10-npn-selected-sni-server-supports-npn-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-8]
++[test-10]
+ ExpectedNPNProtocol = bar
+ ExpectedServerName = server2
+-server = 8-npn-selected-sni-server-supports-npn-server-extra
+-server2 = 8-npn-selected-sni-server-supports-npn-server2-extra
+-client = 8-npn-selected-sni-server-supports-npn-client-extra
++server = 10-npn-selected-sni-server-supports-npn-server-extra
++server2 = 10-npn-selected-sni-server-supports-npn-server2-extra
++client = 10-npn-selected-sni-server-supports-npn-client-extra
+ 
+-[8-npn-selected-sni-server-supports-npn-server-extra]
++[10-npn-selected-sni-server-supports-npn-server-extra]
+ ServerNameCallback = IgnoreMismatch
+ 
+-[8-npn-selected-sni-server-supports-npn-server2-extra]
++[10-npn-selected-sni-server-supports-npn-server2-extra]
+ NPNProtocols = bar
+ 
+-[8-npn-selected-sni-server-supports-npn-client-extra]
++[10-npn-selected-sni-server-supports-npn-client-extra]
+ NPNProtocols = foo,bar
+ ServerName = server2
+ 
+ 
+ # ===========================================================
+ 
+-[9-npn-selected-sni-server-does-not-support-npn]
+-ssl_conf = 9-npn-selected-sni-server-does-not-support-npn-ssl
++[11-npn-selected-sni-server-does-not-support-npn]
++ssl_conf = 11-npn-selected-sni-server-does-not-support-npn-ssl
+ 
+-[9-npn-selected-sni-server-does-not-support-npn-ssl]
+-server = 9-npn-selected-sni-server-does-not-support-npn-server
+-client = 9-npn-selected-sni-server-does-not-support-npn-client
+-server2 = 9-npn-selected-sni-server-does-not-support-npn-server2
++[11-npn-selected-sni-server-does-not-support-npn-ssl]
++server = 11-npn-selected-sni-server-does-not-support-npn-server
++client = 11-npn-selected-sni-server-does-not-support-npn-client
++server2 = 11-npn-selected-sni-server-does-not-support-npn-server2
+ 
+-[9-npn-selected-sni-server-does-not-support-npn-server]
++[11-npn-selected-sni-server-does-not-support-npn-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[9-npn-selected-sni-server-does-not-support-npn-server2]
++[11-npn-selected-sni-server-does-not-support-npn-server2]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[9-npn-selected-sni-server-does-not-support-npn-client]
++[11-npn-selected-sni-server-does-not-support-npn-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-9]
++[test-11]
+ ExpectedServerName = server2
+-server = 9-npn-selected-sni-server-does-not-support-npn-server-extra
+-client = 9-npn-selected-sni-server-does-not-support-npn-client-extra
++server = 11-npn-selected-sni-server-does-not-support-npn-server-extra
++client = 11-npn-selected-sni-server-does-not-support-npn-client-extra
+ 
+-[9-npn-selected-sni-server-does-not-support-npn-server-extra]
++[11-npn-selected-sni-server-does-not-support-npn-server-extra]
+ NPNProtocols = bar
+ ServerNameCallback = IgnoreMismatch
+ 
+-[9-npn-selected-sni-server-does-not-support-npn-client-extra]
++[11-npn-selected-sni-server-does-not-support-npn-client-extra]
+ NPNProtocols = foo,bar
+ ServerName = server2
+ 
+ 
+ # ===========================================================
+ 
+-[10-alpn-preferred-over-npn]
+-ssl_conf = 10-alpn-preferred-over-npn-ssl
++[12-alpn-preferred-over-npn]
++ssl_conf = 12-alpn-preferred-over-npn-ssl
+ 
+-[10-alpn-preferred-over-npn-ssl]
+-server = 10-alpn-preferred-over-npn-server
+-client = 10-alpn-preferred-over-npn-client
++[12-alpn-preferred-over-npn-ssl]
++server = 12-alpn-preferred-over-npn-server
++client = 12-alpn-preferred-over-npn-client
+ 
+-[10-alpn-preferred-over-npn-server]
++[12-alpn-preferred-over-npn-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[10-alpn-preferred-over-npn-client]
++[12-alpn-preferred-over-npn-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-10]
++[test-12]
+ ExpectedALPNProtocol = foo
+-server = 10-alpn-preferred-over-npn-server-extra
+-client = 10-alpn-preferred-over-npn-client-extra
++server = 12-alpn-preferred-over-npn-server-extra
++client = 12-alpn-preferred-over-npn-client-extra
+ 
+-[10-alpn-preferred-over-npn-server-extra]
++[12-alpn-preferred-over-npn-server-extra]
+ ALPNProtocols = foo
+ NPNProtocols = bar
+ 
+-[10-alpn-preferred-over-npn-client-extra]
++[12-alpn-preferred-over-npn-client-extra]
+ ALPNProtocols = foo
+ NPNProtocols = bar
+ 
+ 
+ # ===========================================================
+ 
+-[11-sni-npn-preferred-over-alpn]
+-ssl_conf = 11-sni-npn-preferred-over-alpn-ssl
++[13-sni-npn-preferred-over-alpn]
++ssl_conf = 13-sni-npn-preferred-over-alpn-ssl
+ 
+-[11-sni-npn-preferred-over-alpn-ssl]
+-server = 11-sni-npn-preferred-over-alpn-server
+-client = 11-sni-npn-preferred-over-alpn-client
+-server2 = 11-sni-npn-preferred-over-alpn-server2
++[13-sni-npn-preferred-over-alpn-ssl]
++server = 13-sni-npn-preferred-over-alpn-server
++client = 13-sni-npn-preferred-over-alpn-client
++server2 = 13-sni-npn-preferred-over-alpn-server2
+ 
+-[11-sni-npn-preferred-over-alpn-server]
++[13-sni-npn-preferred-over-alpn-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[11-sni-npn-preferred-over-alpn-server2]
++[13-sni-npn-preferred-over-alpn-server2]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[11-sni-npn-preferred-over-alpn-client]
++[13-sni-npn-preferred-over-alpn-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-11]
++[test-13]
+ ExpectedNPNProtocol = bar
+ ExpectedServerName = server2
+-server = 11-sni-npn-preferred-over-alpn-server-extra
+-server2 = 11-sni-npn-preferred-over-alpn-server2-extra
+-client = 11-sni-npn-preferred-over-alpn-client-extra
++server = 13-sni-npn-preferred-over-alpn-server-extra
++server2 = 13-sni-npn-preferred-over-alpn-server2-extra
++client = 13-sni-npn-preferred-over-alpn-client-extra
+ 
+-[11-sni-npn-preferred-over-alpn-server-extra]
++[13-sni-npn-preferred-over-alpn-server-extra]
+ ALPNProtocols = foo
+ ServerNameCallback = IgnoreMismatch
+ 
+-[11-sni-npn-preferred-over-alpn-server2-extra]
++[13-sni-npn-preferred-over-alpn-server2-extra]
+ NPNProtocols = bar
+ 
+-[11-sni-npn-preferred-over-alpn-client-extra]
++[13-sni-npn-preferred-over-alpn-client-extra]
+ ALPNProtocols = foo
+ NPNProtocols = bar
+ ServerName = server2
+@@ -460,356 +527,356 @@ ServerName = server2
+ 
+ # ===========================================================
+ 
+-[12-npn-simple-resumption]
+-ssl_conf = 12-npn-simple-resumption-ssl
++[14-npn-simple-resumption]
++ssl_conf = 14-npn-simple-resumption-ssl
+ 
+-[12-npn-simple-resumption-ssl]
+-server = 12-npn-simple-resumption-server
+-client = 12-npn-simple-resumption-client
+-resume-server = 12-npn-simple-resumption-server
+-resume-client = 12-npn-simple-resumption-client
++[14-npn-simple-resumption-ssl]
++server = 14-npn-simple-resumption-server
++client = 14-npn-simple-resumption-client
++resume-server = 14-npn-simple-resumption-server
++resume-client = 14-npn-simple-resumption-client
+ 
+-[12-npn-simple-resumption-server]
++[14-npn-simple-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[12-npn-simple-resumption-client]
++[14-npn-simple-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-12]
++[test-14]
+ ExpectedNPNProtocol = foo
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 12-npn-simple-resumption-server-extra
+-resume-server = 12-npn-simple-resumption-server-extra
+-client = 12-npn-simple-resumption-client-extra
+-resume-client = 12-npn-simple-resumption-client-extra
++server = 14-npn-simple-resumption-server-extra
++resume-server = 14-npn-simple-resumption-server-extra
++client = 14-npn-simple-resumption-client-extra
++resume-client = 14-npn-simple-resumption-client-extra
+ 
+-[12-npn-simple-resumption-server-extra]
++[14-npn-simple-resumption-server-extra]
+ NPNProtocols = foo
+ 
+-[12-npn-simple-resumption-client-extra]
++[14-npn-simple-resumption-client-extra]
+ NPNProtocols = foo
+ 
+ 
+ # ===========================================================
+ 
+-[13-npn-server-switch-resumption]
+-ssl_conf = 13-npn-server-switch-resumption-ssl
++[15-npn-server-switch-resumption]
++ssl_conf = 15-npn-server-switch-resumption-ssl
+ 
+-[13-npn-server-switch-resumption-ssl]
+-server = 13-npn-server-switch-resumption-server
+-client = 13-npn-server-switch-resumption-client
+-resume-server = 13-npn-server-switch-resumption-resume-server
+-resume-client = 13-npn-server-switch-resumption-client
++[15-npn-server-switch-resumption-ssl]
++server = 15-npn-server-switch-resumption-server
++client = 15-npn-server-switch-resumption-client
++resume-server = 15-npn-server-switch-resumption-resume-server
++resume-client = 15-npn-server-switch-resumption-client
+ 
+-[13-npn-server-switch-resumption-server]
++[15-npn-server-switch-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[13-npn-server-switch-resumption-resume-server]
++[15-npn-server-switch-resumption-resume-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[13-npn-server-switch-resumption-client]
++[15-npn-server-switch-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-13]
++[test-15]
+ ExpectedNPNProtocol = baz
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 13-npn-server-switch-resumption-server-extra
+-resume-server = 13-npn-server-switch-resumption-resume-server-extra
+-client = 13-npn-server-switch-resumption-client-extra
+-resume-client = 13-npn-server-switch-resumption-client-extra
++server = 15-npn-server-switch-resumption-server-extra
++resume-server = 15-npn-server-switch-resumption-resume-server-extra
++client = 15-npn-server-switch-resumption-client-extra
++resume-client = 15-npn-server-switch-resumption-client-extra
+ 
+-[13-npn-server-switch-resumption-server-extra]
++[15-npn-server-switch-resumption-server-extra]
+ NPNProtocols = bar,foo
+ 
+-[13-npn-server-switch-resumption-resume-server-extra]
++[15-npn-server-switch-resumption-resume-server-extra]
+ NPNProtocols = baz,foo
+ 
+-[13-npn-server-switch-resumption-client-extra]
++[15-npn-server-switch-resumption-client-extra]
+ NPNProtocols = foo,bar,baz
+ 
+ 
+ # ===========================================================
+ 
+-[14-npn-client-switch-resumption]
+-ssl_conf = 14-npn-client-switch-resumption-ssl
++[16-npn-client-switch-resumption]
++ssl_conf = 16-npn-client-switch-resumption-ssl
+ 
+-[14-npn-client-switch-resumption-ssl]
+-server = 14-npn-client-switch-resumption-server
+-client = 14-npn-client-switch-resumption-client
+-resume-server = 14-npn-client-switch-resumption-server
+-resume-client = 14-npn-client-switch-resumption-resume-client
++[16-npn-client-switch-resumption-ssl]
++server = 16-npn-client-switch-resumption-server
++client = 16-npn-client-switch-resumption-client
++resume-server = 16-npn-client-switch-resumption-server
++resume-client = 16-npn-client-switch-resumption-resume-client
+ 
+-[14-npn-client-switch-resumption-server]
++[16-npn-client-switch-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[14-npn-client-switch-resumption-client]
++[16-npn-client-switch-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[14-npn-client-switch-resumption-resume-client]
++[16-npn-client-switch-resumption-resume-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-14]
++[test-16]
+ ExpectedNPNProtocol = bar
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 14-npn-client-switch-resumption-server-extra
+-resume-server = 14-npn-client-switch-resumption-server-extra
+-client = 14-npn-client-switch-resumption-client-extra
+-resume-client = 14-npn-client-switch-resumption-resume-client-extra
++server = 16-npn-client-switch-resumption-server-extra
++resume-server = 16-npn-client-switch-resumption-server-extra
++client = 16-npn-client-switch-resumption-client-extra
++resume-client = 16-npn-client-switch-resumption-resume-client-extra
+ 
+-[14-npn-client-switch-resumption-server-extra]
++[16-npn-client-switch-resumption-server-extra]
+ NPNProtocols = foo,bar,baz
+ 
+-[14-npn-client-switch-resumption-client-extra]
++[16-npn-client-switch-resumption-client-extra]
+ NPNProtocols = foo,baz
+ 
+-[14-npn-client-switch-resumption-resume-client-extra]
++[16-npn-client-switch-resumption-resume-client-extra]
+ NPNProtocols = bar,baz
+ 
+ 
+ # ===========================================================
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption]
+-ssl_conf = 15-npn-client-first-pref-on-mismatch-resumption-ssl
++[17-npn-client-first-pref-on-mismatch-resumption]
++ssl_conf = 17-npn-client-first-pref-on-mismatch-resumption-ssl
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption-ssl]
+-server = 15-npn-client-first-pref-on-mismatch-resumption-server
+-client = 15-npn-client-first-pref-on-mismatch-resumption-client
+-resume-server = 15-npn-client-first-pref-on-mismatch-resumption-resume-server
+-resume-client = 15-npn-client-first-pref-on-mismatch-resumption-client
++[17-npn-client-first-pref-on-mismatch-resumption-ssl]
++server = 17-npn-client-first-pref-on-mismatch-resumption-server
++client = 17-npn-client-first-pref-on-mismatch-resumption-client
++resume-server = 17-npn-client-first-pref-on-mismatch-resumption-resume-server
++resume-client = 17-npn-client-first-pref-on-mismatch-resumption-client
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption-server]
++[17-npn-client-first-pref-on-mismatch-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption-resume-server]
++[17-npn-client-first-pref-on-mismatch-resumption-resume-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption-client]
++[17-npn-client-first-pref-on-mismatch-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-15]
++[test-17]
+ ExpectedNPNProtocol = foo
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 15-npn-client-first-pref-on-mismatch-resumption-server-extra
+-resume-server = 15-npn-client-first-pref-on-mismatch-resumption-resume-server-extra
+-client = 15-npn-client-first-pref-on-mismatch-resumption-client-extra
+-resume-client = 15-npn-client-first-pref-on-mismatch-resumption-client-extra
++server = 17-npn-client-first-pref-on-mismatch-resumption-server-extra
++resume-server = 17-npn-client-first-pref-on-mismatch-resumption-resume-server-extra
++client = 17-npn-client-first-pref-on-mismatch-resumption-client-extra
++resume-client = 17-npn-client-first-pref-on-mismatch-resumption-client-extra
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption-server-extra]
++[17-npn-client-first-pref-on-mismatch-resumption-server-extra]
+ NPNProtocols = bar
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption-resume-server-extra]
++[17-npn-client-first-pref-on-mismatch-resumption-resume-server-extra]
+ NPNProtocols = baz
+ 
+-[15-npn-client-first-pref-on-mismatch-resumption-client-extra]
++[17-npn-client-first-pref-on-mismatch-resumption-client-extra]
+ NPNProtocols = foo,bar
+ 
+ 
+ # ===========================================================
+ 
+-[16-npn-no-server-support-resumption]
+-ssl_conf = 16-npn-no-server-support-resumption-ssl
++[18-npn-no-server-support-resumption]
++ssl_conf = 18-npn-no-server-support-resumption-ssl
+ 
+-[16-npn-no-server-support-resumption-ssl]
+-server = 16-npn-no-server-support-resumption-server
+-client = 16-npn-no-server-support-resumption-client
+-resume-server = 16-npn-no-server-support-resumption-resume-server
+-resume-client = 16-npn-no-server-support-resumption-client
++[18-npn-no-server-support-resumption-ssl]
++server = 18-npn-no-server-support-resumption-server
++client = 18-npn-no-server-support-resumption-client
++resume-server = 18-npn-no-server-support-resumption-resume-server
++resume-client = 18-npn-no-server-support-resumption-client
+ 
+-[16-npn-no-server-support-resumption-server]
++[18-npn-no-server-support-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[16-npn-no-server-support-resumption-resume-server]
++[18-npn-no-server-support-resumption-resume-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[16-npn-no-server-support-resumption-client]
++[18-npn-no-server-support-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-16]
++[test-18]
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 16-npn-no-server-support-resumption-server-extra
+-client = 16-npn-no-server-support-resumption-client-extra
+-resume-client = 16-npn-no-server-support-resumption-client-extra
++server = 18-npn-no-server-support-resumption-server-extra
++client = 18-npn-no-server-support-resumption-client-extra
++resume-client = 18-npn-no-server-support-resumption-client-extra
+ 
+-[16-npn-no-server-support-resumption-server-extra]
++[18-npn-no-server-support-resumption-server-extra]
+ NPNProtocols = foo
+ 
+-[16-npn-no-server-support-resumption-client-extra]
++[18-npn-no-server-support-resumption-client-extra]
+ NPNProtocols = foo
+ 
+ 
+ # ===========================================================
+ 
+-[17-npn-no-client-support-resumption]
+-ssl_conf = 17-npn-no-client-support-resumption-ssl
++[19-npn-no-client-support-resumption]
++ssl_conf = 19-npn-no-client-support-resumption-ssl
+ 
+-[17-npn-no-client-support-resumption-ssl]
+-server = 17-npn-no-client-support-resumption-server
+-client = 17-npn-no-client-support-resumption-client
+-resume-server = 17-npn-no-client-support-resumption-server
+-resume-client = 17-npn-no-client-support-resumption-resume-client
++[19-npn-no-client-support-resumption-ssl]
++server = 19-npn-no-client-support-resumption-server
++client = 19-npn-no-client-support-resumption-client
++resume-server = 19-npn-no-client-support-resumption-server
++resume-client = 19-npn-no-client-support-resumption-resume-client
+ 
+-[17-npn-no-client-support-resumption-server]
++[19-npn-no-client-support-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[17-npn-no-client-support-resumption-client]
++[19-npn-no-client-support-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[17-npn-no-client-support-resumption-resume-client]
++[19-npn-no-client-support-resumption-resume-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-17]
++[test-19]
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 17-npn-no-client-support-resumption-server-extra
+-resume-server = 17-npn-no-client-support-resumption-server-extra
+-client = 17-npn-no-client-support-resumption-client-extra
++server = 19-npn-no-client-support-resumption-server-extra
++resume-server = 19-npn-no-client-support-resumption-server-extra
++client = 19-npn-no-client-support-resumption-client-extra
+ 
+-[17-npn-no-client-support-resumption-server-extra]
++[19-npn-no-client-support-resumption-server-extra]
+ NPNProtocols = foo
+ 
+-[17-npn-no-client-support-resumption-client-extra]
++[19-npn-no-client-support-resumption-client-extra]
+ NPNProtocols = foo
+ 
+ 
+ # ===========================================================
+ 
+-[18-alpn-preferred-over-npn-resumption]
+-ssl_conf = 18-alpn-preferred-over-npn-resumption-ssl
++[20-alpn-preferred-over-npn-resumption]
++ssl_conf = 20-alpn-preferred-over-npn-resumption-ssl
+ 
+-[18-alpn-preferred-over-npn-resumption-ssl]
+-server = 18-alpn-preferred-over-npn-resumption-server
+-client = 18-alpn-preferred-over-npn-resumption-client
+-resume-server = 18-alpn-preferred-over-npn-resumption-resume-server
+-resume-client = 18-alpn-preferred-over-npn-resumption-client
++[20-alpn-preferred-over-npn-resumption-ssl]
++server = 20-alpn-preferred-over-npn-resumption-server
++client = 20-alpn-preferred-over-npn-resumption-client
++resume-server = 20-alpn-preferred-over-npn-resumption-resume-server
++resume-client = 20-alpn-preferred-over-npn-resumption-client
+ 
+-[18-alpn-preferred-over-npn-resumption-server]
++[20-alpn-preferred-over-npn-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[18-alpn-preferred-over-npn-resumption-resume-server]
++[20-alpn-preferred-over-npn-resumption-resume-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[18-alpn-preferred-over-npn-resumption-client]
++[20-alpn-preferred-over-npn-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-18]
++[test-20]
+ ExpectedALPNProtocol = foo
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 18-alpn-preferred-over-npn-resumption-server-extra
+-resume-server = 18-alpn-preferred-over-npn-resumption-resume-server-extra
+-client = 18-alpn-preferred-over-npn-resumption-client-extra
+-resume-client = 18-alpn-preferred-over-npn-resumption-client-extra
++server = 20-alpn-preferred-over-npn-resumption-server-extra
++resume-server = 20-alpn-preferred-over-npn-resumption-resume-server-extra
++client = 20-alpn-preferred-over-npn-resumption-client-extra
++resume-client = 20-alpn-preferred-over-npn-resumption-client-extra
+ 
+-[18-alpn-preferred-over-npn-resumption-server-extra]
++[20-alpn-preferred-over-npn-resumption-server-extra]
+ NPNProtocols = bar
+ 
+-[18-alpn-preferred-over-npn-resumption-resume-server-extra]
++[20-alpn-preferred-over-npn-resumption-resume-server-extra]
+ ALPNProtocols = foo
+ NPNProtocols = baz
+ 
+-[18-alpn-preferred-over-npn-resumption-client-extra]
++[20-alpn-preferred-over-npn-resumption-client-extra]
+ ALPNProtocols = foo
+ NPNProtocols = bar,baz
+ 
+ 
+ # ===========================================================
+ 
+-[19-npn-used-if-alpn-not-supported-resumption]
+-ssl_conf = 19-npn-used-if-alpn-not-supported-resumption-ssl
++[21-npn-used-if-alpn-not-supported-resumption]
++ssl_conf = 21-npn-used-if-alpn-not-supported-resumption-ssl
+ 
+-[19-npn-used-if-alpn-not-supported-resumption-ssl]
+-server = 19-npn-used-if-alpn-not-supported-resumption-server
+-client = 19-npn-used-if-alpn-not-supported-resumption-client
+-resume-server = 19-npn-used-if-alpn-not-supported-resumption-resume-server
+-resume-client = 19-npn-used-if-alpn-not-supported-resumption-client
++[21-npn-used-if-alpn-not-supported-resumption-ssl]
++server = 21-npn-used-if-alpn-not-supported-resumption-server
++client = 21-npn-used-if-alpn-not-supported-resumption-client
++resume-server = 21-npn-used-if-alpn-not-supported-resumption-resume-server
++resume-client = 21-npn-used-if-alpn-not-supported-resumption-client
+ 
+-[19-npn-used-if-alpn-not-supported-resumption-server]
++[21-npn-used-if-alpn-not-supported-resumption-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[19-npn-used-if-alpn-not-supported-resumption-resume-server]
++[21-npn-used-if-alpn-not-supported-resumption-resume-server]
+ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+ CipherString = DEFAULT
+ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+ 
+-[19-npn-used-if-alpn-not-supported-resumption-client]
++[21-npn-used-if-alpn-not-supported-resumption-client]
+ CipherString = DEFAULT
+ MaxProtocol = TLSv1.2
+ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+ VerifyMode = Peer
+ 
+-[test-19]
++[test-21]
+ ExpectedNPNProtocol = baz
+ HandshakeMode = Resume
+ ResumptionExpected = Yes
+-server = 19-npn-used-if-alpn-not-supported-resumption-server-extra
+-resume-server = 19-npn-used-if-alpn-not-supported-resumption-resume-server-extra
+-client = 19-npn-used-if-alpn-not-supported-resumption-client-extra
+-resume-client = 19-npn-used-if-alpn-not-supported-resumption-client-extra
++server = 21-npn-used-if-alpn-not-supported-resumption-server-extra
++resume-server = 21-npn-used-if-alpn-not-supported-resumption-resume-server-extra
++client = 21-npn-used-if-alpn-not-supported-resumption-client-extra
++resume-client = 21-npn-used-if-alpn-not-supported-resumption-client-extra
+ 
+-[19-npn-used-if-alpn-not-supported-resumption-server-extra]
++[21-npn-used-if-alpn-not-supported-resumption-server-extra]
+ ALPNProtocols = foo
+ NPNProtocols = bar
+ 
+-[19-npn-used-if-alpn-not-supported-resumption-resume-server-extra]
++[21-npn-used-if-alpn-not-supported-resumption-resume-server-extra]
+ NPNProtocols = baz
+ 
+-[19-npn-used-if-alpn-not-supported-resumption-client-extra]
++[21-npn-used-if-alpn-not-supported-resumption-client-extra]
+ ALPNProtocols = foo
+ NPNProtocols = bar,baz
+ 
+diff --git a/test/ssl-tests/08-npn.cnf.in b/test/ssl-tests/08-npn.cnf.in
+index 30783e45eb..1dc2704bdb 100644
+--- a/test/ssl-tests/08-npn.cnf.in
++++ b/test/ssl-tests/08-npn.cnf.in
+@@ -110,6 +110,41 @@ our @tests = (
+             "ExpectedNPNProtocol" => undef,
+         },
+     },
++    {
++        name => "npn-empty-client-list",
++        server => {
++            extra => {
++                "NPNProtocols" => "foo",
++            },
++        },
++        client => {
++            extra => {
++                "NPNProtocols" => "",
++            },
++            "MaxProtocol" => "TLSv1.2"
++        },
++        test => {
++            "ExpectedResult" => "ClientFail",
++            "ExpectedClientAlert" => "HandshakeFailure"
++        },
++    },
++    {
++        name => "npn-empty-server-list",
++        server => {
++            extra => {
++                "NPNProtocols" => "",
++            },
++        },
++        client => {
++            extra => {
++                "NPNProtocols" => "foo",
++            },
++            "MaxProtocol" => "TLSv1.2"
++        },
++        test => {
++            "ExpectedNPNProtocol" => "foo"
++        },
++    },
+     {
+         name => "npn-with-sni-no-context-switch",
+         server => {
+diff --git a/test/ssl-tests/09-alpn.cnf b/test/ssl-tests/09-alpn.cnf
+index e7e6cb9534..dd668739ab 100644
+--- a/test/ssl-tests/09-alpn.cnf
++++ b/test/ssl-tests/09-alpn.cnf
+@@ -1,6 +1,6 @@
+ # Generated with generate_ssl_tests.pl
+ 
+-num_tests = 16
++num_tests = 18
+ 
+ test-0 = 0-alpn-simple
+ test-1 = 1-alpn-server-finds-match
+@@ -18,6 +18,8 @@ test-12 = 12-alpn-client-switch-resumption
+ test-13 = 13-alpn-alert-on-mismatch-resumption
+ test-14 = 14-alpn-no-server-support-resumption
+ test-15 = 15-alpn-no-client-support-resumption
++test-16 = 16-alpn-empty-client-list
++test-17 = 17-alpn-empty-server-list
+ # ===========================================================
+ 
+ [0-alpn-simple]
+@@ -617,3 +619,65 @@ ALPNProtocols = foo
+ ALPNProtocols = foo
+ 
+ 
++# ===========================================================
++
++[16-alpn-empty-client-list]
++ssl_conf = 16-alpn-empty-client-list-ssl
++
++[16-alpn-empty-client-list-ssl]
++server = 16-alpn-empty-client-list-server
++client = 16-alpn-empty-client-list-client
++
++[16-alpn-empty-client-list-server]
++Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
++CipherString = DEFAULT
++PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
++
++[16-alpn-empty-client-list-client]
++CipherString = DEFAULT
++VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
++VerifyMode = Peer
++
++[test-16]
++server = 16-alpn-empty-client-list-server-extra
++client = 16-alpn-empty-client-list-client-extra
++
++[16-alpn-empty-client-list-server-extra]
++ALPNProtocols = foo
++
++[16-alpn-empty-client-list-client-extra]
++ALPNProtocols = 
++
++
++# ===========================================================
++
++[17-alpn-empty-server-list]
++ssl_conf = 17-alpn-empty-server-list-ssl
++
++[17-alpn-empty-server-list-ssl]
++server = 17-alpn-empty-server-list-server
++client = 17-alpn-empty-server-list-client
++
++[17-alpn-empty-server-list-server]
++Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
++CipherString = DEFAULT
++PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
++
++[17-alpn-empty-server-list-client]
++CipherString = DEFAULT
++VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
++VerifyMode = Peer
++
++[test-17]
++ExpectedResult = ServerFail
++ExpectedServerAlert = NoApplicationProtocol
++server = 17-alpn-empty-server-list-server-extra
++client = 17-alpn-empty-server-list-client-extra
++
++[17-alpn-empty-server-list-server-extra]
++ALPNProtocols = 
++
++[17-alpn-empty-server-list-client-extra]
++ALPNProtocols = foo
++
++
+diff --git a/test/ssl-tests/09-alpn.cnf.in b/test/ssl-tests/09-alpn.cnf.in
+index 81330756c6..322b7096a6 100644
+--- a/test/ssl-tests/09-alpn.cnf.in
++++ b/test/ssl-tests/09-alpn.cnf.in
+@@ -322,4 +322,37 @@ our @tests = (
+             "ExpectedALPNProtocol" => undef,
+         },
+     },
++    {
++        name => "alpn-empty-client-list",
++        server => {
++            extra => {
++                "ALPNProtocols" => "foo",
++            },
++        },
++        client => {
++            extra => {
++                "ALPNProtocols" => "",
++            },
++        },
++        test => {
++            "ExpectedALPNProtocol" => undef,
++        },
++    },
++    {
++        name => "alpn-empty-server-list",
++        server => {
++            extra => {
++                "ALPNProtocols" => "",
++            },
++        },
++        client => {
++            extra => {
++                "ALPNProtocols" => "foo",
++            },
++        },
++        test => {
++            "ExpectedResult" => "ServerFail",
++            "ExpectedServerAlert" => "NoApplicationProtocol",
++        },
++    },
+ );
+-- 
+2.46.0
+

diff --git a/0135-Correct-return-values-for-tls_construct_stoc_next_pr.patch b/0135-Correct-return-values-for-tls_construct_stoc_next_pr.patch
new file mode 100644
index 0000000..97c28ee
--- /dev/null
+++ b/0135-Correct-return-values-for-tls_construct_stoc_next_pr.patch
@@ -0,0 +1,39 @@
+From 53f5677f358c4a4f69830d944ea40e71950673b8 Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 21 Jun 2024 10:41:55 +0100
+Subject: [PATCH 07/10] Correct return values for
+ tls_construct_stoc_next_proto_neg
+
+Return EXT_RETURN_NOT_SENT in the event that we don't send the extension,
+rather than EXT_RETURN_SENT. This actually makes no difference at all to
+the current control flow since this return value is ignored in this case
+anyway. But lets make it correct anyway.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ ssl/statem/extensions_srvr.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index 800654450e..66ed7dacf2 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1501,9 +1501,10 @@ EXT_RETURN tls_construct_stoc_next_proto_neg(SSL_CONNECTION *s, WPACKET *pkt,
+             return EXT_RETURN_FAIL;
+         }
+         s->s3.npn_seen = 1;
++        return EXT_RETURN_SENT;
+     }
+ 
+-    return EXT_RETURN_SENT;
++    return EXT_RETURN_NOT_SENT;
+ }
+ #endif
+ 
+-- 
+2.46.0
+

diff --git a/0136-Add-ALPN-validation-in-the-client.patch b/0136-Add-ALPN-validation-in-the-client.patch
new file mode 100644
index 0000000..1406860
--- /dev/null
+++ b/0136-Add-ALPN-validation-in-the-client.patch
@@ -0,0 +1,62 @@
+From 195e15421df113d7283aab2ccff8b8fb06df5465 Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 21 Jun 2024 11:51:54 +0100
+Subject: [PATCH 08/10] Add ALPN validation in the client
+
+The ALPN protocol selected by the server must be one that we originally
+advertised. We should verify that it is.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ ssl/statem/extensions_clnt.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 1ab3c13d57..ff9c009ee5 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1590,6 +1590,8 @@ int tls_parse_stoc_alpn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+                         X509 *x, size_t chainidx)
+ {
+     size_t len;
++    PACKET confpkt, protpkt;
++    int valid = 0;
+ 
+     /* We must have requested it. */
+     if (!s->s3.alpn_sent) {
+@@ -1608,6 +1610,28 @@ int tls_parse_stoc_alpn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+         return 0;
+     }
++
++    /* It must be a protocol that we sent */
++    if (!PACKET_buf_init(&confpkt, s->ext.alpn, s->ext.alpn_len)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++    while (PACKET_get_length_prefixed_1(&confpkt, &protpkt)) {
++        if (PACKET_remaining(&protpkt) != len)
++            continue;
++        if (memcmp(PACKET_data(pkt), PACKET_data(&protpkt), len) == 0) {
++            /* Valid protocol found */
++            valid = 1;
++            break;
++        }
++    }
++
++    if (!valid) {
++        /* The protocol sent from the server does not match one we advertised */
++        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
++        return 0;
++    }
++
+     OPENSSL_free(s->s3.alpn_selected);
+     s->s3.alpn_selected = OPENSSL_malloc(len);
+     if (s->s3.alpn_selected == NULL) {
+-- 
+2.46.0
+

diff --git a/0136-CVE-2024-6119.patch b/0136-CVE-2024-6119.patch
deleted file mode 100644
index a39106a..0000000
--- a/0136-CVE-2024-6119.patch
+++ /dev/null
@@ -1,233 +0,0 @@
-diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c
-index 1a18174995..a09414c972 100644
---- a/crypto/x509/v3_utl.c
-+++ b/crypto/x509/v3_utl.c
-@@ -916,36 +916,64 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen,
-             ASN1_STRING *cstr;
- 
-             gen = sk_GENERAL_NAME_value(gens, i);
--            if ((gen->type == GEN_OTHERNAME) && (check_type == GEN_EMAIL)) {
--                if (OBJ_obj2nid(gen->d.otherName->type_id) ==
--                    NID_id_on_SmtpUTF8Mailbox) {
--                    san_present = 1;
--
--                    /*
--                     * If it is not a UTF8String then that is unexpected and we
--                     * treat it as no match
--                     */
--                    if (gen->d.otherName->value->type == V_ASN1_UTF8STRING) {
--                        cstr = gen->d.otherName->value->value.utf8string;
--
--                        /* Positive on success, negative on error! */
--                        if ((rv = do_check_string(cstr, 0, equal, flags,
--                                                chk, chklen, peername)) != 0)
--                            break;
--                    }
--                } else
-+            switch (gen->type) {
-+            default:
-+                continue;
-+            case GEN_OTHERNAME:
-+		switch (OBJ_obj2nid(gen->d.otherName->type_id)) {
-+                default:
-                     continue;
--            } else {
--                if ((gen->type != check_type) && (gen->type != GEN_OTHERNAME))
-+                case NID_id_on_SmtpUTF8Mailbox:
-+                    /*-
-+                     * https://datatracker.ietf.org/doc/html/rfc8398#section-3
-+                     *
-+                     *   Due to name constraint compatibility reasons described
-+                     *   in Section 6, SmtpUTF8Mailbox subjectAltName MUST NOT
-+                     *   be used unless the local-part of the email address
-+                     *   contains non-ASCII characters. When the local-part is
-+                     *   ASCII, rfc822Name subjectAltName MUST be used instead
-+                     *   of SmtpUTF8Mailbox. This is compatible with legacy
-+                     *   software that supports only rfc822Name (and not
-+                     *   SmtpUTF8Mailbox). [...]
-+                     *
-+                     *   SmtpUTF8Mailbox is encoded as UTF8String.
-+                     *
-+                     * If it is not a UTF8String then that is unexpected, and
-+                     * we ignore the invalid SAN (neither set san_present nor
-+                     * consider it a candidate for equality).  This does mean
-+                     * that the subject CN may be considered, as would be the
-+                     * case when the malformed SmtpUtf8Mailbox SAN is instead
-+                     * simply absent.
-+                     *
-+                     * When CN-ID matching is not desirable, applications can
-+                     * choose to turn it off, doing so is at this time a best
-+                     * practice.
-+                     */
-+                    if (check_type != GEN_EMAIL
-+                        || gen->d.otherName->value->type != V_ASN1_UTF8STRING)
-+                        continue;
-+                    alt_type = 0;
-+                    cstr = gen->d.otherName->value->value.utf8string;
-+                    break;
-+                }
-+                break;
-+            case GEN_EMAIL:
-+                if (check_type != GEN_EMAIL)
-                     continue;
--            }
--            san_present = 1;
--            if (check_type == GEN_EMAIL)
-                 cstr = gen->d.rfc822Name;
--            else if (check_type == GEN_DNS)
-+                break;
-+            case GEN_DNS:
-+                if (check_type != GEN_DNS)
-+                    continue;
-                 cstr = gen->d.dNSName;
--            else
-+                break;
-+            case GEN_IPADD:
-+                if (check_type != GEN_IPADD)
-+                    continue;
-                 cstr = gen->d.iPAddress;
-+                break;
-+            }
-+            san_present = 1;
-             /* Positive on success, negative on error! */
-             if ((rv = do_check_string(cstr, alt_type, equal, flags,
-                                       chk, chklen, peername)) != 0)
-diff --git a/test/recipes/25-test_eai_data.t b/test/recipes/25-test_eai_data.t
-index 522982ddfb..e18735d89a 100644
---- a/test/recipes/25-test_eai_data.t
-+++ b/test/recipes/25-test_eai_data.t
-@@ -21,16 +21,18 @@ setup("test_eai_data");
- #./util/wrap.pl apps/openssl verify -nameopt utf8 -no_check_time -CAfile test/recipes/25-test_eai_data/utf8_chain.pem test/recipes/25-test_eai_data/ascii_leaf.pem
- #./util/wrap.pl apps/openssl verify -nameopt utf8 -no_check_time -CAfile test/recipes/25-test_eai_data/ascii_chain.pem test/recipes/25-test_eai_data/utf8_leaf.pem
- 
--plan tests => 12;
-+plan tests => 16;
- 
- require_ok(srctop_file('test','recipes','tconversion.pl'));
- my $folder = "test/recipes/25-test_eai_data";
- 
- my $ascii_pem = srctop_file($folder, "ascii_leaf.pem");
- my $utf8_pem  = srctop_file($folder, "utf8_leaf.pem");
-+my $kdc_pem   = srctop_file($folder, "kdc-cert.pem");
- 
- my $ascii_chain_pem = srctop_file($folder, "ascii_chain.pem");
- my $utf8_chain_pem  = srctop_file($folder, "utf8_chain.pem");
-+my $kdc_chain_pem  = srctop_file($folder, "kdc-root-cert.pem");
- 
- my $out;
- my $outcnt = 0;
-@@ -56,10 +58,18 @@ SKIP: {
- 
- ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $ascii_chain_pem, $ascii_pem])));
- ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $utf8_chain_pem, $utf8_pem])));
-+ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $kdc_chain_pem, $kdc_pem])));
- 
- ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $ascii_chain_pem, $utf8_pem])));
- ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $utf8_chain_pem,  $ascii_pem])));
- 
-+# Check an otherName does not get misparsed as an DNS name, (should trigger ASAN errors if violated).
-+ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_hostname", 'mx1.example.com', "-CAfile", $kdc_chain_pem,  $kdc_pem])));
-+# Check an otherName does not get misparsed as an email address, (should trigger ASAN errors if violated).
-+ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_email", 'joe@example.com', "-CAfile", $kdc_chain_pem,  $kdc_pem])));
-+# We expect SmtpUTF8Mailbox to be a UTF8 String, not an IA5String.
-+ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_email", 'moe@example.com', "-CAfile", $kdc_chain_pem,  $kdc_pem])));
-+
- #Check that we get the expected failure return code
- with({ exit_checker => sub { return shift == 2; } },
-      sub {
-diff --git a/test/recipes/25-test_eai_data/kdc-cert.pem b/test/recipes/25-test_eai_data/kdc-cert.pem
-new file mode 100644
-index 0000000000..e8a2c6f55d
---- /dev/null
-+++ b/test/recipes/25-test_eai_data/kdc-cert.pem
-@@ -0,0 +1,21 @@
-+-----BEGIN CERTIFICATE-----
-+MIIDbDCCAlSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-+MCAXDTI0MDYyMDA2MTQxNVoYDzIxMjQwNjIwMDYxNDE1WjAXMRUwEwYDVQQDDAxU
-+RVNULkVYQU1QTEUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6wfP+
-+6go79dkpo/dGLMlPZ7Gw/Q6gUYrCWZWUEgEeRVHCrqOlgUEyA+PcWas/XDPUxXry
-+BQlJHLvlqamAQn8gs4QPBARFYWKNiTVGyaRkgNA1N5gqyZdrP9UE+ZJmdqxRAAe8
-+vvpGZWSgevPhLUiSCFYDiD0Rtji2Hm3rGUrReQFBQDEw2pNGwz9zIaxUs08kQZcx
-+Yzyiplz5Oau+R/6sAgUwDlrD9xOlUxx/tA/MSDIfkK8qioU11uUZtO5VjkNQy/bT
-+7zQMmXxWgm2MIgOs1u4YN7YGOtgqHE9v9iPHHfgrkbQDtVDGQsa8AQEhkUDSCtW9
-+3VFAKx6dGNXYzFwfAgMBAAGjgcgwgcUwHQYDVR0OBBYEFFR5tZycW19DmtbL4Zqj
-+te1c2vZLMAkGA1UdIwQCMAAwCQYDVR0TBAIwADCBjQYDVR0RBIGFMIGCoD8GBisG
-+AQUCAqA1MDOgDhsMVEVTVC5FWEFNUExFoSEwH6ADAgEBoRgwFhsGa3JidGd0GwxU
-+RVNULkVYQU1QTEWgHQYIKwYBBQUHCAmgERYPbW9lQGV4YW1wbGUuY29tgQ9qb2VA
-+ZXhhbXBsZS5jb22CD214MS5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA
-+T0xzVtVpRtaOzIhgzw7XQUdzWD5UEGSJJ1cBCOmKUWwDLTAouCYLFB4TbEE7MMUb
-+iuMy60bjmVtvfJIXorGUgSadRe5RWJ5DamJWvPA0Q9x7blnEcXqEF+9Td+ypevgU
-+UYHFmg83OYwxOsFXZ5cRuXMk3WCsDHQIBi6D1L6oDDZ2pfArs5mqm3thQKVlqyl1
-+El3XRYEdqAz/5eCOFNfwxF0ALxjxVr/Z50StUZU8I7Zfev6+kHhyrR7dqzYJImv9
-+0fTCOBEMjIETDsrA70OxAMu4V16nrWZdJdvzblS2qrt97Omkj+2kiPAJFB76RpwI
-+oDQ9fKfUOAmUFth2/R/eGA==
-+-----END CERTIFICATE-----
-diff --git a/test/recipes/25-test_eai_data/kdc-root-cert.pem b/test/recipes/25-test_eai_data/kdc-root-cert.pem
-new file mode 100644
-index 0000000000..a74c96bf31
---- /dev/null
-+++ b/test/recipes/25-test_eai_data/kdc-root-cert.pem
-@@ -0,0 +1,16 @@
-+-----BEGIN CERTIFICATE-----
-+MIICnDCCAYQCCQCBswYcrlZSHjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARS
-+b290MCAXDTI0MDYyMDA2MTQxNVoYDzIxMjQwNjIwMDYxNDE1WjAPMQ0wCwYDVQQD
-+DARSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqRj8S4kBbIUj
-+61kZfi6nE35Q38U140+qt4uAiwAhKumfVHlBM0zQ98WFt5zMHIBQwIb3yjc2zj+0
-+qzUnQfwm1r/RfcMmBPEti9Ge+aEMSsds2gMXziOFM8wd2aAFPy7UVE0XpEWofsRK
-+MGi61MKVdPSbGIxBwY9VW38/7D/wf1HtJe7y0xpuecR7GB2XAs+qST59NjuF+7wS
-+dLM8Hb3TATgeYbXXWsRJgwz+SPzExg5WmLnU+7y4brZ32dHtdSmkRVSgSlaIf7Xj
-+3Tc6Zi7I+W/JYk7hy1zUexVdWCak4PHcoWrXe0gNNN/t8VfLfMExt5z/HIylXnU7
-+pGUyqZlTGQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAHpLF1UCRy7b6Hk0rLokxI
-+lgwiH9BU9mktigAGASvkbllpt+YbUbWnuYAvpHBGiP1qZtfX2r96UrSJaGO9BEzT
-+Gp9ThnSjoj4Srul0+s/NArU22irFLmDzbalgevAmm9gMGkdqkiIm/mXbwrPj0ncl
-+KGicevXryVpvaP62eZ8cc3C4p97frMmXxRX8sTdQpD/gRI7prdEILRSKveqT+AEW
-+7rFGM5AOevb4U8ddop8A3D/kX0wcCAIBF6jCNk3uEJ57jVcagL04kPnVfdRiedTS
-+vfq1DRNcD29d1H/9u0fHdSn1/+8Ep3X+afQ3C6//5NvOEaXcIGO4QSwkprQydfv8
-+-----END CERTIFICATE-----
-diff --git a/test/recipes/25-test_eai_data/kdc.sh b/test/recipes/25-test_eai_data/kdc.sh
-new file mode 100755
-index 0000000000..7a8dbc719f
---- /dev/null
-+++ b/test/recipes/25-test_eai_data/kdc.sh
-@@ -0,0 +1,41 @@
-+#! /usr/bin/env bash
-+
-+# Create a root CA, signing a leaf cert with a KDC principal otherName SAN, and
-+# also a non-UTF8 smtpUtf8Mailbox SAN followed by an rfc822Name SAN and a DNS
-+# name SAN.  In the vulnerable EAI code, the KDC principal `otherName` should
-+# trigger ASAN errors in DNS name checks, while the non-UTF8 `smtpUtf8Mailbox`
-+# should likewise lead to ASAN issues with email name checks.
-+
-+rm -f root-key.pem root-cert.pem
-+openssl req -nodes -new -newkey rsa:2048 -keyout kdc-root-key.pem \
-+        -x509 -subj /CN=Root -days 36524 -out kdc-root-cert.pem
-+
-+exts=$(
-+    printf "%s\n%s\n%s\n%s = " \
-+        "subjectKeyIdentifier = hash" \
-+        "authorityKeyIdentifier = keyid" \
-+        "basicConstraints = CA:false" \
-+        "subjectAltName"
-+    printf "%s, " "otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name"
-+    printf "%s, " "otherName:1.3.6.1.5.5.7.8.9;IA5:moe@example.com"
-+    printf "%s, " "email:joe@example.com"
-+    printf "%s\n" "DNS:mx1.example.com"
-+    printf "[kdc_princ_name]\n"
-+    printf "realm = EXP:0, GeneralString:TEST.EXAMPLE\n"
-+    printf "principal_name = EXP:1, SEQUENCE:kdc_principal_seq\n"
-+    printf "[kdc_principal_seq]\n"
-+    printf "name_type = EXP:0, INTEGER:1\n"
-+    printf "name_string = EXP:1, SEQUENCE:kdc_principal_components\n"
-+    printf "[kdc_principal_components]\n"
-+    printf "princ1 = GeneralString:krbtgt\n"
-+    printf "princ2 = GeneralString:TEST.EXAMPLE\n"
-+    )
-+
-+printf "%s\n" "$exts"
-+
-+openssl req -nodes -new -newkey rsa:2048 -keyout kdc-key.pem \
-+    -subj "/CN=TEST.EXAMPLE" |
-+    openssl x509 -req -out kdc-cert.pem \
-+        -CA "kdc-root-cert.pem" -CAkey "kdc-root-key.pem" \
-+        -set_serial 2 -days 36524 \
-+        -extfile <(printf "%s\n" "$exts")

diff --git a/0137-Add-explicit-testing-of-ALN-and-NPN-in-sslapitest.patch b/0137-Add-explicit-testing-of-ALN-and-NPN-in-sslapitest.patch
new file mode 100644
index 0000000..135fa25
--- /dev/null
+++ b/0137-Add-explicit-testing-of-ALN-and-NPN-in-sslapitest.patch
@@ -0,0 +1,267 @@
+From 7c95191434415d1c9b7fe9b130df13cce630b6b5 Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 21 Jun 2024 10:09:41 +0100
+Subject: [PATCH 09/10] Add explicit testing of ALN and NPN in sslapitest
+
+We already had some tests elsewhere - but this extends that testing with
+additional tests.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ test/sslapitest.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 229 insertions(+)
+
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index 15cb9060cb..7a55a2b721 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -11877,6 +11877,231 @@ static int test_select_next_proto(int idx)
+     return ret;
+ }
+ 
++static const unsigned char fooprot[] = {3, 'f', 'o', 'o' };
++static const unsigned char barprot[] = {3, 'b', 'a', 'r' };
++
++#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_NEXTPROTONEG)
++static int npn_advert_cb(SSL *ssl, const unsigned char **out,
++                         unsigned int *outlen, void *arg)
++{
++    int *idx = (int *)arg;
++
++    switch (*idx) {
++    default:
++    case 0:
++        *out = fooprot;
++        *outlen = sizeof(fooprot);
++        return SSL_TLSEXT_ERR_OK;
++
++    case 1:
++        *outlen = 0;
++        return SSL_TLSEXT_ERR_OK;
++
++    case 2:
++        return SSL_TLSEXT_ERR_NOACK;
++    }
++}
++
++static int npn_select_cb(SSL *s, unsigned char **out, unsigned char *outlen,
++                         const unsigned char *in, unsigned int inlen, void *arg)
++{
++    int *idx = (int *)arg;
++
++    switch (*idx) {
++    case 0:
++    case 1:
++        *out = (unsigned char *)(fooprot + 1);
++        *outlen = *fooprot;
++        return SSL_TLSEXT_ERR_OK;
++
++    case 3:
++        *out = (unsigned char *)(barprot + 1);
++        *outlen = *barprot;
++        return SSL_TLSEXT_ERR_OK;
++
++    case 4:
++        *outlen = 0;
++        return SSL_TLSEXT_ERR_OK;
++
++    default:
++    case 2:
++        return SSL_TLSEXT_ERR_ALERT_FATAL;
++    }
++}
++
++/*
++ * Test the NPN callbacks
++ * Test 0: advert = foo, select = foo
++ * Test 1: advert = <empty>, select = foo
++ * Test 2: no advert
++ * Test 3: advert = foo, select = bar
++ * Test 4: advert = foo, select = <empty> (should fail)
++ */
++static int test_npn(int idx)
++{
++    SSL_CTX *sctx = NULL, *cctx = NULL;
++    SSL *serverssl = NULL, *clientssl = NULL;
++    int testresult = 0;
++
++    if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
++                                       TLS_client_method(), 0, TLS1_2_VERSION,
++                                       &sctx, &cctx, cert, privkey)))
++        goto end;
++
++    SSL_CTX_set_next_protos_advertised_cb(sctx, npn_advert_cb, &idx);
++    SSL_CTX_set_next_proto_select_cb(cctx, npn_select_cb, &idx);
++
++    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL,
++                                      NULL)))
++        goto end;
++
++    if (idx == 4) {
++        /* We don't allow empty selection of NPN, so this should fail */
++        if (!TEST_false(create_ssl_connection(serverssl, clientssl,
++                                              SSL_ERROR_NONE)))
++            goto end;
++    } else {
++        const unsigned char *prot;
++        unsigned int protlen;
++
++        if (!TEST_true(create_ssl_connection(serverssl, clientssl,
++                                             SSL_ERROR_NONE)))
++            goto end;
++
++        SSL_get0_next_proto_negotiated(serverssl, &prot, &protlen);
++        switch (idx) {
++        case 0:
++        case 1:
++            if (!TEST_mem_eq(prot, protlen, fooprot + 1, *fooprot))
++                goto end;
++            break;
++        case 2:
++            if (!TEST_uint_eq(protlen, 0))
++                goto end;
++            break;
++        case 3:
++            if (!TEST_mem_eq(prot, protlen, barprot + 1, *barprot))
++                goto end;
++            break;
++        default:
++            TEST_error("Should not get here");
++            goto end;
++        }
++    }
++
++    testresult = 1;
++ end:
++    SSL_free(serverssl);
++    SSL_free(clientssl);
++    SSL_CTX_free(sctx);
++    SSL_CTX_free(cctx);
++
++    return testresult;
++}
++#endif /* !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_NEXTPROTONEG) */
++
++static int alpn_select_cb2(SSL *ssl, const unsigned char **out,
++                           unsigned char *outlen, const unsigned char *in,
++                           unsigned int inlen, void *arg)
++{
++    int *idx = (int *)arg;
++
++    switch (*idx) {
++    case 0:
++        *out = (unsigned char *)(fooprot + 1);
++        *outlen = *fooprot;
++        return SSL_TLSEXT_ERR_OK;
++
++    case 2:
++        *out = (unsigned char *)(barprot + 1);
++        *outlen = *barprot;
++        return SSL_TLSEXT_ERR_OK;
++
++    case 3:
++        *outlen = 0;
++        return SSL_TLSEXT_ERR_OK;
++
++    default:
++    case 1:
++        return SSL_TLSEXT_ERR_ALERT_FATAL;
++    }
++    return 0;
++}
++
++/*
++ * Test the ALPN callbacks
++ * Test 0: client = foo, select = foo
++ * Test 1: client = <empty>, select = none
++ * Test 2: client = foo, select = bar (should fail)
++ * Test 3: client = foo, select = <empty> (should fail)
++ */
++static int test_alpn(int idx)
++{
++    SSL_CTX *sctx = NULL, *cctx = NULL;
++    SSL *serverssl = NULL, *clientssl = NULL;
++    int testresult = 0;
++    const unsigned char *prots = fooprot;
++    unsigned int protslen = sizeof(fooprot);
++
++    if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
++                                       TLS_client_method(), 0, 0,
++                                       &sctx, &cctx, cert, privkey)))
++        goto end;
++
++    SSL_CTX_set_alpn_select_cb(sctx, alpn_select_cb2, &idx);
++
++    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL,
++                                      NULL)))
++        goto end;
++
++    if (idx == 1) {
++        prots = NULL;
++        protslen = 0;
++    }
++
++    /* SSL_set_alpn_protos returns 0 for success! */
++    if (!TEST_false(SSL_set_alpn_protos(clientssl, prots, protslen)))
++        goto end;
++
++    if (idx == 2 || idx == 3) {
++        /* We don't allow empty selection of NPN, so this should fail */
++        if (!TEST_false(create_ssl_connection(serverssl, clientssl,
++                                              SSL_ERROR_NONE)))
++            goto end;
++    } else {
++        const unsigned char *prot;
++        unsigned int protlen;
++
++        if (!TEST_true(create_ssl_connection(serverssl, clientssl,
++                                             SSL_ERROR_NONE)))
++            goto end;
++
++        SSL_get0_alpn_selected(clientssl, &prot, &protlen);
++        switch (idx) {
++        case 0:
++            if (!TEST_mem_eq(prot, protlen, fooprot + 1, *fooprot))
++                goto end;
++            break;
++        case 1:
++            if (!TEST_uint_eq(protlen, 0))
++                goto end;
++            break;
++        default:
++            TEST_error("Should not get here");
++            goto end;
++        }
++    }
++
++    testresult = 1;
++ end:
++    SSL_free(serverssl);
++    SSL_free(clientssl);
++    SSL_CTX_free(sctx);
++    SSL_CTX_free(cctx);
++
++    return testresult;
++}
++
+ OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n")
+ 
+ int setup_tests(void)
+@@ -12190,6 +12415,10 @@ int setup_tests(void)
+     ADD_TEST(test_data_retry);
+     ADD_ALL_TESTS(test_multi_resume, 5);
+     ADD_ALL_TESTS(test_select_next_proto, OSSL_NELEM(next_proto_tests));
++#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_NEXTPROTONEG)
++    ADD_ALL_TESTS(test_npn, 5);
++#endif
++    ADD_ALL_TESTS(test_alpn, 4);
+     return 1;
+ 
+  err:
+-- 
+2.46.0
+

diff --git a/0138-Add-a-test-for-an-empty-NextProto-message.patch b/0138-Add-a-test-for-an-empty-NextProto-message.patch
new file mode 100644
index 0000000..923ec66
--- /dev/null
+++ b/0138-Add-a-test-for-an-empty-NextProto-message.patch
@@ -0,0 +1,199 @@
+From 301b870546d1c7b2d8f0d66e04a2596142f0399f Mon Sep 17 00:00:00 2001
+From: Matt Caswell <matt@openssl.org>
+Date: Fri, 21 Jun 2024 14:29:26 +0100
+Subject: [PATCH 10/10] Add a test for an empty NextProto message
+
+It is valid according to the spec for a NextProto message to have no
+protocols listed in it. The OpenSSL implementation however does not allow
+us to create such a message. In order to check that we work as expected
+when communicating with a client that does generate such messages we have
+to use a TLSProxy test.
+
+Follow on from CVE-2024-5535
+
+Reviewed-by: Neil Horman <nhorman@openssl.org>
+Reviewed-by: Tomas Mraz <tomas@openssl.org>
+(Merged from https://github.com/openssl/openssl/pull/24717)
+---
+ test/recipes/70-test_npn.t      | 73 +++++++++++++++++++++++++++++++++
+ util/perl/TLSProxy/Message.pm   |  9 ++++
+ util/perl/TLSProxy/NextProto.pm | 54 ++++++++++++++++++++++++
+ util/perl/TLSProxy/Proxy.pm     |  1 +
+ 4 files changed, 137 insertions(+)
+ create mode 100644 test/recipes/70-test_npn.t
+ create mode 100644 util/perl/TLSProxy/NextProto.pm
+
+diff --git a/test/recipes/70-test_npn.t b/test/recipes/70-test_npn.t
+new file mode 100644
+index 0000000000..f82e71af6a
+--- /dev/null
++++ b/test/recipes/70-test_npn.t
+@@ -0,0 +1,73 @@
++#! /usr/bin/env perl
++# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
++#
++# Licensed under the Apache License 2.0 (the "License").  You may not use
++# this file except in compliance with the License.  You can obtain a copy
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++use strict;
++use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file/;
++use OpenSSL::Test::Utils;
++
++use TLSProxy::Proxy;
++
++my $test_name = "test_npn";
++setup($test_name);
++
++plan skip_all => "TLSProxy isn't usable on $^O"
++    if $^O =~ /^(VMS)$/;
++
++plan skip_all => "$test_name needs the dynamic engine feature enabled"
++    if disabled("engine") || disabled("dynamic-engine");
++
++plan skip_all => "$test_name needs the sock feature enabled"
++    if disabled("sock");
++
++plan skip_all => "$test_name needs NPN enabled"
++    if disabled("nextprotoneg");
++
++plan skip_all => "$test_name needs TLSv1.2 enabled"
++    if disabled("tls1_2");
++
++my $proxy = TLSProxy::Proxy->new(
++    undef,
++    cmdstr(app(["openssl"]), display => 1),
++    srctop_file("apps", "server.pem"),
++    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
++);
++
++$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
++plan tests => 1;
++
++my $npnseen = 0;
++
++# Test 1: Check sending an empty NextProto message from the client works. This is
++#         valid as per the spec, but OpenSSL does not allow you to send it.
++#         Therefore we must be prepared to receive such a message but we cannot
++#         generate it except via TLSProxy
++$proxy->clear();
++$proxy->filter(\&npn_filter);
++$proxy->clientflags("-nextprotoneg foo -no_tls1_3");
++$proxy->serverflags("-nextprotoneg foo");
++$proxy->start();
++ok($npnseen && TLSProxy::Message->success(), "Empty NPN message");
++
++sub npn_filter
++{
++    my $proxy = shift;
++    my $message;
++
++    # The NextProto message always appears in flight 2
++    return if $proxy->flight != 2;
++
++    foreach my $message (@{$proxy->message_list}) {
++        if ($message->mt == TLSProxy::Message::MT_NEXT_PROTO) {
++            # Our TLSproxy NextProto message support doesn't support parsing of
++            # the message. If we repack it just creates an empty NextProto
++            # message - which is exactly the scenario we want to test here.
++            $message->repack();
++            $npnseen = 1;
++        }
++    }
++}
+diff --git a/util/perl/TLSProxy/Message.pm b/util/perl/TLSProxy/Message.pm
+index ce22187569..fb41b2ffc8 100644
+--- a/util/perl/TLSProxy/Message.pm
++++ b/util/perl/TLSProxy/Message.pm
+@@ -384,6 +384,15 @@ sub create_message
+             [@message_frag_lens]
+         );
+         $message->parse();
++    }  elsif ($mt == MT_NEXT_PROTO) {
++        $message = TLSProxy::NextProto->new(
++            $server,
++            $data,
++            [@message_rec_list],
++            $startoffset,
++            [@message_frag_lens]
++        );
++        $message->parse();
+     } else {
+         #Unknown message type
+         $message = TLSProxy::Message->new(
+diff --git a/util/perl/TLSProxy/NextProto.pm b/util/perl/TLSProxy/NextProto.pm
+new file mode 100644
+index 0000000000..0e18347546
+--- /dev/null
++++ b/util/perl/TLSProxy/NextProto.pm
+@@ -0,0 +1,54 @@
++# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
++#
++# Licensed under the Apache License 2.0 (the "License").  You may not use
++# this file except in compliance with the License.  You can obtain a copy
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++use strict;
++
++package TLSProxy::NextProto;
++
++use vars '@ISA';
++push @ISA, 'TLSProxy::Message';
++
++sub new
++{
++    my $class = shift;
++    my ($server,
++        $data,
++        $records,
++        $startoffset,
++        $message_frag_lens) = @_;
++
++    my $self = $class->SUPER::new(
++        $server,
++        TLSProxy::Message::MT_NEXT_PROTO,
++        $data,
++        $records,
++        $startoffset,
++        $message_frag_lens);
++
++    return $self;
++}
++
++sub parse
++{
++    # We don't support parsing at the moment
++}
++
++# This is supposed to reconstruct the on-the-wire message data following changes.
++# For now though since we don't support parsing we just create an empty NextProto
++# message - this capability is used in test_npn
++sub set_message_contents
++{
++    my $self = shift;
++    my $data;
++
++    $data = pack("C32", 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                 0x00, 0x00, 0x00);
++    $self->data($data);
++}
++1;
+diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm
+index 3de10eccb9..b707722b6b 100644
+--- a/util/perl/TLSProxy/Proxy.pm
++++ b/util/perl/TLSProxy/Proxy.pm
+@@ -23,6 +23,7 @@ use TLSProxy::CertificateRequest;
+ use TLSProxy::CertificateVerify;
+ use TLSProxy::ServerKeyExchange;
+ use TLSProxy::NewSessionTicket;
++use TLSProxy::NextProto;
+ 
+ my $have_IPv6;
+ my $IP_factory;
+-- 
+2.46.0
+

diff --git a/0139-CVE-2024-6119.patch b/0139-CVE-2024-6119.patch
new file mode 100644
index 0000000..a39106a
--- /dev/null
+++ b/0139-CVE-2024-6119.patch
@@ -0,0 +1,233 @@
+diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c
+index 1a18174995..a09414c972 100644
+--- a/crypto/x509/v3_utl.c
++++ b/crypto/x509/v3_utl.c
+@@ -916,36 +916,64 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen,
+             ASN1_STRING *cstr;
+ 
+             gen = sk_GENERAL_NAME_value(gens, i);
+-            if ((gen->type == GEN_OTHERNAME) && (check_type == GEN_EMAIL)) {
+-                if (OBJ_obj2nid(gen->d.otherName->type_id) ==
+-                    NID_id_on_SmtpUTF8Mailbox) {
+-                    san_present = 1;
+-
+-                    /*
+-                     * If it is not a UTF8String then that is unexpected and we
+-                     * treat it as no match
+-                     */
+-                    if (gen->d.otherName->value->type == V_ASN1_UTF8STRING) {
+-                        cstr = gen->d.otherName->value->value.utf8string;
+-
+-                        /* Positive on success, negative on error! */
+-                        if ((rv = do_check_string(cstr, 0, equal, flags,
+-                                                chk, chklen, peername)) != 0)
+-                            break;
+-                    }
+-                } else
++            switch (gen->type) {
++            default:
++                continue;
++            case GEN_OTHERNAME:
++		switch (OBJ_obj2nid(gen->d.otherName->type_id)) {
++                default:
+                     continue;
+-            } else {
+-                if ((gen->type != check_type) && (gen->type != GEN_OTHERNAME))
++                case NID_id_on_SmtpUTF8Mailbox:
++                    /*-
++                     * https://datatracker.ietf.org/doc/html/rfc8398#section-3
++                     *
++                     *   Due to name constraint compatibility reasons described
++                     *   in Section 6, SmtpUTF8Mailbox subjectAltName MUST NOT
++                     *   be used unless the local-part of the email address
++                     *   contains non-ASCII characters. When the local-part is
++                     *   ASCII, rfc822Name subjectAltName MUST be used instead
++                     *   of SmtpUTF8Mailbox. This is compatible with legacy
++                     *   software that supports only rfc822Name (and not
++                     *   SmtpUTF8Mailbox). [...]
++                     *
++                     *   SmtpUTF8Mailbox is encoded as UTF8String.
++                     *
++                     * If it is not a UTF8String then that is unexpected, and
++                     * we ignore the invalid SAN (neither set san_present nor
++                     * consider it a candidate for equality).  This does mean
++                     * that the subject CN may be considered, as would be the
++                     * case when the malformed SmtpUtf8Mailbox SAN is instead
++                     * simply absent.
++                     *
++                     * When CN-ID matching is not desirable, applications can
++                     * choose to turn it off, doing so is at this time a best
++                     * practice.
++                     */
++                    if (check_type != GEN_EMAIL
++                        || gen->d.otherName->value->type != V_ASN1_UTF8STRING)
++                        continue;
++                    alt_type = 0;
++                    cstr = gen->d.otherName->value->value.utf8string;
++                    break;
++                }
++                break;
++            case GEN_EMAIL:
++                if (check_type != GEN_EMAIL)
+                     continue;
+-            }
+-            san_present = 1;
+-            if (check_type == GEN_EMAIL)
+                 cstr = gen->d.rfc822Name;
+-            else if (check_type == GEN_DNS)
++                break;
++            case GEN_DNS:
++                if (check_type != GEN_DNS)
++                    continue;
+                 cstr = gen->d.dNSName;
+-            else
++                break;
++            case GEN_IPADD:
++                if (check_type != GEN_IPADD)
++                    continue;
+                 cstr = gen->d.iPAddress;
++                break;
++            }
++            san_present = 1;
+             /* Positive on success, negative on error! */
+             if ((rv = do_check_string(cstr, alt_type, equal, flags,
+                                       chk, chklen, peername)) != 0)
+diff --git a/test/recipes/25-test_eai_data.t b/test/recipes/25-test_eai_data.t
+index 522982ddfb..e18735d89a 100644
+--- a/test/recipes/25-test_eai_data.t
++++ b/test/recipes/25-test_eai_data.t
+@@ -21,16 +21,18 @@ setup("test_eai_data");
+ #./util/wrap.pl apps/openssl verify -nameopt utf8 -no_check_time -CAfile test/recipes/25-test_eai_data/utf8_chain.pem test/recipes/25-test_eai_data/ascii_leaf.pem
+ #./util/wrap.pl apps/openssl verify -nameopt utf8 -no_check_time -CAfile test/recipes/25-test_eai_data/ascii_chain.pem test/recipes/25-test_eai_data/utf8_leaf.pem
+ 
+-plan tests => 12;
++plan tests => 16;
+ 
+ require_ok(srctop_file('test','recipes','tconversion.pl'));
+ my $folder = "test/recipes/25-test_eai_data";
+ 
+ my $ascii_pem = srctop_file($folder, "ascii_leaf.pem");
+ my $utf8_pem  = srctop_file($folder, "utf8_leaf.pem");
++my $kdc_pem   = srctop_file($folder, "kdc-cert.pem");
+ 
+ my $ascii_chain_pem = srctop_file($folder, "ascii_chain.pem");
+ my $utf8_chain_pem  = srctop_file($folder, "utf8_chain.pem");
++my $kdc_chain_pem  = srctop_file($folder, "kdc-root-cert.pem");
+ 
+ my $out;
+ my $outcnt = 0;
+@@ -56,10 +58,18 @@ SKIP: {
+ 
+ ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $ascii_chain_pem, $ascii_pem])));
+ ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $utf8_chain_pem, $utf8_pem])));
++ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $kdc_chain_pem, $kdc_pem])));
+ 
+ ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $ascii_chain_pem, $utf8_pem])));
+ ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $utf8_chain_pem,  $ascii_pem])));
+ 
++# Check an otherName does not get misparsed as an DNS name, (should trigger ASAN errors if violated).
++ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_hostname", 'mx1.example.com', "-CAfile", $kdc_chain_pem,  $kdc_pem])));
++# Check an otherName does not get misparsed as an email address, (should trigger ASAN errors if violated).
++ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_email", 'joe@example.com', "-CAfile", $kdc_chain_pem,  $kdc_pem])));
++# We expect SmtpUTF8Mailbox to be a UTF8 String, not an IA5String.
++ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_email", 'moe@example.com', "-CAfile", $kdc_chain_pem,  $kdc_pem])));
++
+ #Check that we get the expected failure return code
+ with({ exit_checker => sub { return shift == 2; } },
+      sub {
+diff --git a/test/recipes/25-test_eai_data/kdc-cert.pem b/test/recipes/25-test_eai_data/kdc-cert.pem
+new file mode 100644
+index 0000000000..e8a2c6f55d
+--- /dev/null
++++ b/test/recipes/25-test_eai_data/kdc-cert.pem
+@@ -0,0 +1,21 @@
++-----BEGIN CERTIFICATE-----
++MIIDbDCCAlSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
++MCAXDTI0MDYyMDA2MTQxNVoYDzIxMjQwNjIwMDYxNDE1WjAXMRUwEwYDVQQDDAxU
++RVNULkVYQU1QTEUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6wfP+
++6go79dkpo/dGLMlPZ7Gw/Q6gUYrCWZWUEgEeRVHCrqOlgUEyA+PcWas/XDPUxXry
++BQlJHLvlqamAQn8gs4QPBARFYWKNiTVGyaRkgNA1N5gqyZdrP9UE+ZJmdqxRAAe8
++vvpGZWSgevPhLUiSCFYDiD0Rtji2Hm3rGUrReQFBQDEw2pNGwz9zIaxUs08kQZcx
++Yzyiplz5Oau+R/6sAgUwDlrD9xOlUxx/tA/MSDIfkK8qioU11uUZtO5VjkNQy/bT
++7zQMmXxWgm2MIgOs1u4YN7YGOtgqHE9v9iPHHfgrkbQDtVDGQsa8AQEhkUDSCtW9
++3VFAKx6dGNXYzFwfAgMBAAGjgcgwgcUwHQYDVR0OBBYEFFR5tZycW19DmtbL4Zqj
++te1c2vZLMAkGA1UdIwQCMAAwCQYDVR0TBAIwADCBjQYDVR0RBIGFMIGCoD8GBisG
++AQUCAqA1MDOgDhsMVEVTVC5FWEFNUExFoSEwH6ADAgEBoRgwFhsGa3JidGd0GwxU
++RVNULkVYQU1QTEWgHQYIKwYBBQUHCAmgERYPbW9lQGV4YW1wbGUuY29tgQ9qb2VA
++ZXhhbXBsZS5jb22CD214MS5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA
++T0xzVtVpRtaOzIhgzw7XQUdzWD5UEGSJJ1cBCOmKUWwDLTAouCYLFB4TbEE7MMUb
++iuMy60bjmVtvfJIXorGUgSadRe5RWJ5DamJWvPA0Q9x7blnEcXqEF+9Td+ypevgU
++UYHFmg83OYwxOsFXZ5cRuXMk3WCsDHQIBi6D1L6oDDZ2pfArs5mqm3thQKVlqyl1
++El3XRYEdqAz/5eCOFNfwxF0ALxjxVr/Z50StUZU8I7Zfev6+kHhyrR7dqzYJImv9
++0fTCOBEMjIETDsrA70OxAMu4V16nrWZdJdvzblS2qrt97Omkj+2kiPAJFB76RpwI
++oDQ9fKfUOAmUFth2/R/eGA==
++-----END CERTIFICATE-----
+diff --git a/test/recipes/25-test_eai_data/kdc-root-cert.pem b/test/recipes/25-test_eai_data/kdc-root-cert.pem
+new file mode 100644
+index 0000000000..a74c96bf31
+--- /dev/null
++++ b/test/recipes/25-test_eai_data/kdc-root-cert.pem
+@@ -0,0 +1,16 @@
++-----BEGIN CERTIFICATE-----
++MIICnDCCAYQCCQCBswYcrlZSHjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARS
++b290MCAXDTI0MDYyMDA2MTQxNVoYDzIxMjQwNjIwMDYxNDE1WjAPMQ0wCwYDVQQD
++DARSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqRj8S4kBbIUj
++61kZfi6nE35Q38U140+qt4uAiwAhKumfVHlBM0zQ98WFt5zMHIBQwIb3yjc2zj+0
++qzUnQfwm1r/RfcMmBPEti9Ge+aEMSsds2gMXziOFM8wd2aAFPy7UVE0XpEWofsRK
++MGi61MKVdPSbGIxBwY9VW38/7D/wf1HtJe7y0xpuecR7GB2XAs+qST59NjuF+7wS
++dLM8Hb3TATgeYbXXWsRJgwz+SPzExg5WmLnU+7y4brZ32dHtdSmkRVSgSlaIf7Xj
++3Tc6Zi7I+W/JYk7hy1zUexVdWCak4PHcoWrXe0gNNN/t8VfLfMExt5z/HIylXnU7
++pGUyqZlTGQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAHpLF1UCRy7b6Hk0rLokxI
++lgwiH9BU9mktigAGASvkbllpt+YbUbWnuYAvpHBGiP1qZtfX2r96UrSJaGO9BEzT
++Gp9ThnSjoj4Srul0+s/NArU22irFLmDzbalgevAmm9gMGkdqkiIm/mXbwrPj0ncl
++KGicevXryVpvaP62eZ8cc3C4p97frMmXxRX8sTdQpD/gRI7prdEILRSKveqT+AEW
++7rFGM5AOevb4U8ddop8A3D/kX0wcCAIBF6jCNk3uEJ57jVcagL04kPnVfdRiedTS
++vfq1DRNcD29d1H/9u0fHdSn1/+8Ep3X+afQ3C6//5NvOEaXcIGO4QSwkprQydfv8
++-----END CERTIFICATE-----
+diff --git a/test/recipes/25-test_eai_data/kdc.sh b/test/recipes/25-test_eai_data/kdc.sh
+new file mode 100755
+index 0000000000..7a8dbc719f
+--- /dev/null
++++ b/test/recipes/25-test_eai_data/kdc.sh
+@@ -0,0 +1,41 @@
++#! /usr/bin/env bash
++
++# Create a root CA, signing a leaf cert with a KDC principal otherName SAN, and
++# also a non-UTF8 smtpUtf8Mailbox SAN followed by an rfc822Name SAN and a DNS
++# name SAN.  In the vulnerable EAI code, the KDC principal `otherName` should
++# trigger ASAN errors in DNS name checks, while the non-UTF8 `smtpUtf8Mailbox`
++# should likewise lead to ASAN issues with email name checks.
++
++rm -f root-key.pem root-cert.pem
++openssl req -nodes -new -newkey rsa:2048 -keyout kdc-root-key.pem \
++        -x509 -subj /CN=Root -days 36524 -out kdc-root-cert.pem
++
++exts=$(
++    printf "%s\n%s\n%s\n%s = " \
++        "subjectKeyIdentifier = hash" \
++        "authorityKeyIdentifier = keyid" \
++        "basicConstraints = CA:false" \
++        "subjectAltName"
++    printf "%s, " "otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name"
++    printf "%s, " "otherName:1.3.6.1.5.5.7.8.9;IA5:moe@example.com"
++    printf "%s, " "email:joe@example.com"
++    printf "%s\n" "DNS:mx1.example.com"
++    printf "[kdc_princ_name]\n"
++    printf "realm = EXP:0, GeneralString:TEST.EXAMPLE\n"
++    printf "principal_name = EXP:1, SEQUENCE:kdc_principal_seq\n"
++    printf "[kdc_principal_seq]\n"
++    printf "name_type = EXP:0, INTEGER:1\n"
++    printf "name_string = EXP:1, SEQUENCE:kdc_principal_components\n"
++    printf "[kdc_principal_components]\n"
++    printf "princ1 = GeneralString:krbtgt\n"
++    printf "princ2 = GeneralString:TEST.EXAMPLE\n"
++    )
++
++printf "%s\n" "$exts"
++
++openssl req -nodes -new -newkey rsa:2048 -keyout kdc-key.pem \
++    -subj "/CN=TEST.EXAMPLE" |
++    openssl x509 -req -out kdc-cert.pem \
++        -CA "kdc-root-cert.pem" -CAkey "kdc-root-key.pem" \
++        -set_serial 2 -days 36524 \
++        -extfile <(printf "%s\n" "$exts")

diff --git a/openssl.spec b/openssl.spec
index bdbe887..5f73667 100644
--- a/openssl.spec
+++ b/openssl.spec
@@ -29,7 +29,7 @@ print(string.sub(hash, 0, 16))
 Summary: Utilities from the general purpose cryptography library with TLS implementation
 Name: openssl
 Version: 3.2.2
-Release: 7%{?dist}
+Release: 8%{?dist}
 Epoch: 1
 Source: openssl-%{version}.tar.gz
 Source2: Makefile.certificate
@@ -154,8 +154,30 @@ Patch121: 0121-FIPS-cms-defaults.patch
 # [PATCH 50/50] Assign IANA numbers for hybrid PQ KEX Porting the fix
 #  in https://github.com/openssl/openssl/pull/22803
 Patch122: 0122-Assign-IANA-numbers-for-hybrid-PQ-KEX.patch
+# HKDF regression with older provider implementations
+Patch123: 0123-kdf-Preserve-backward-compatibility-with-older-provi.patch
+# https://github.com/openssl/openssl/issues/24577
+Patch124: 0124-PBMAC1-PKCS12-FIPS-support.patch
+# Downstream patch: enforce PBMAC1 in FIPS mode
+Patch125: 0125-PBMAC1-PKCS12-FIPS-default.patch
+# https://github.com/openssl/openssl/issues/25127
+Patch126: 0126-pkeyutl-encap.patch
+# https://github.com/openssl/openssl/issues/25056
+Patch127: 0127-speedup-SSL_add_cert_subjects_to_stack.patch
+Patch128: 0128-SAST-findings.patch
+# https://github.com/openssl/openssl/pull/24717
+Patch129: 0129-Fix-SSL_select_next_proto.patch
+Patch130: 0130-More-correctly-handle-a-selected_len-of-0-when-proce.patch
+Patch131: 0131-Use-correctly-formatted-ALPN-data-in-tserver.patch
+Patch132: 0132-Clarify-the-SSL_select_next_proto-documentation.patch
+Patch133: 0133-Add-a-test-for-SSL_select_next_proto.patch
+Patch134: 0134-Allow-an-empty-NPN-ALPN-protocol-list-in-the-tests.patch
+Patch135: 0135-Correct-return-values-for-tls_construct_stoc_next_pr.patch
+Patch136: 0136-Add-ALPN-validation-in-the-client.patch
+Patch137: 0137-Add-explicit-testing-of-ALN-and-NPN-in-sslapitest.patch
+Patch138: 0138-Add-a-test-for-an-empty-NextProto-message.patch
 # https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f
-Patch136: 0136-CVE-2024-6119.patch
+Patch139: 0139-CVE-2024-6119.patch
 
 License: Apache-2.0
 URL: http://www.openssl.org/
@@ -525,6 +547,17 @@ ln -s /etc/crypto-policies/back-ends/openssl_fips.config $RPM_BUILD_ROOT%{_sysco
 %ldconfig_scriptlets libs
 
 %changelog
+* Thu Sep 12 2024 Sahana Prasad <sahana@redhat.com> - 1:3.2.2-8
+- Synchorize patches in CentOS10 and Fedora with the following changes
+- Fix CVE-2024-5535: SSL_select_next_proto buffer overread
+- Use PBMAC1 by default when creating PKCS#12 files in FIPS mode
+- Support key encapsulation/decapsulation in openssl pkeyutl command
+- Fix typo in the patch numeration
+- Enable KTLS, temporary disable KTLS tests
+- Speedup SSL_add_{file,dir}_cert_subjects_to_stack
+- Resolve SAST package scan results
+- An interface to create PKCS #12 files in FIPS compliant way
+
 * Fri Sep 06 2024 Sahana Prasad <sahana@redhat.com> - 1:3.2.2-7
 - Patch for CVE-2024-6119
 

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-06-09 12:45 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-09 12:45 [rpms/openssl] rebase_40beta: - Synchorize patches in CentOS 10 and Fedora with the following changes Sahana Prasad

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox