/* Skip the CVE-2025-11187 fix in case the version being livepatched already have a fix for it.  */

#ifndef _DISABLE_CVE_2025_11187

#define OSSL_DEPRECATED(since)                extern
#define OSSL_DEPRECATEDIN_3_0                OSSL_DEPRECATED(3.0)
#define OPENSSL_FILE __FILE__
#define OPENSSL_LINE __LINE__
#define OPENSSL_FUNC __func__

#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#define STACK_OF(type) struct stack_st_##type
/** clang-extract: from include/openssl/types.h:63:1 */
typedef struct asn1_string_st ASN1_INTEGER;

/** clang-extract: from include/openssl/types.h:64:1 */
typedef struct asn1_string_st ASN1_ENUMERATED;

/** clang-extract: from include/openssl/types.h:65:1 */
typedef struct asn1_string_st ASN1_BIT_STRING;

/** clang-extract: from include/openssl/types.h:66:1 */
typedef struct asn1_string_st ASN1_OCTET_STRING;

/** clang-extract: from include/openssl/types.h:67:1 */
typedef struct asn1_string_st ASN1_PRINTABLESTRING;

/** clang-extract: from include/openssl/types.h:68:1 */
typedef struct asn1_string_st ASN1_T61STRING;

/** clang-extract: from include/openssl/types.h:69:1 */
typedef struct asn1_string_st ASN1_IA5STRING;

/** clang-extract: from include/openssl/types.h:70:1 */
typedef struct asn1_string_st ASN1_GENERALSTRING;

/** clang-extract: from include/openssl/types.h:71:1 */
typedef struct asn1_string_st ASN1_UNIVERSALSTRING;

/** clang-extract: from include/openssl/types.h:72:1 */
typedef struct asn1_string_st ASN1_BMPSTRING;

/** clang-extract: from include/openssl/types.h:73:1 */
typedef struct asn1_string_st ASN1_UTCTIME;

/** clang-extract: from include/openssl/types.h:75:1 */
typedef struct asn1_string_st ASN1_GENERALIZEDTIME;

/** clang-extract: from include/openssl/types.h:76:1 */
typedef struct asn1_string_st ASN1_VISIBLESTRING;

/** clang-extract: from include/openssl/types.h:77:1 */
typedef struct asn1_string_st ASN1_UTF8STRING;

/** clang-extract: from include/openssl/types.h:78:1 */
typedef struct asn1_string_st ASN1_STRING;

/** clang-extract: from include/openssl/types.h:79:1 */
typedef int ASN1_BOOLEAN;

/** clang-extract: from include/openssl/types.h:83:1 */
typedef struct asn1_type_st ASN1_TYPE;

/** clang-extract: from include/openssl/types.h:84:1 */
typedef struct asn1_object_st ASN1_OBJECT;

/** clang-extract: from include/openssl/types.h:110:1 */
typedef struct evp_cipher_st EVP_CIPHER;

/** clang-extract: from include/openssl/types.h:112:1 */
typedef struct evp_md_st EVP_MD;

/** clang-extract: from include/openssl/types.h:144:1 */
typedef struct hmac_ctx_st HMAC_CTX;

/** clang-extract: from include/openssl/types.h:170:1 */
typedef struct X509_algor_st X509_ALGOR;

/** clang-extract: from include/openssl/types.h:195:1 */
typedef struct engine_st ENGINE;

/** clang-extract: from include/openssl/types.h:227:1 */
typedef struct ossl_lib_ctx_st OSSL_LIB_CTX;

/** clang-extract: from include/openssl/crypto.h:382:1 */
void OPENSSL_cleanse(void *ptr, size_t len);

/** clang-extract: from include/openssl/asn1.h:132:1 */
struct stack_st_X509_ALGOR;/* Full definition was removed.  */

/** clang-extract: from include/openssl/asn1.h:186:1 */
struct asn1_string_st {
    int length;
    int type;
    unsigned char *data;
    /*
     * The value of the following field depends on the type being held.  It
     * is mostly being used for BIT_STRING so if the input data has a
     * non-zero 'unused bits' value, it will be handled correctly
     */
    long flags;
};

/** clang-extract: from include/openssl/asn1.h:279:1 */
typedef struct ASN1_VALUE_st ASN1_VALUE;

/** clang-extract: from include/openssl/asn1.h:524:1 */
struct asn1_type_st {
    int type;
    union {
        char *ptr;
        ASN1_BOOLEAN boolean;
        ASN1_STRING *asn1_string;
        ASN1_OBJECT *object;
        ASN1_INTEGER *integer;
        ASN1_ENUMERATED *enumerated;
        ASN1_BIT_STRING *bit_string;
        ASN1_OCTET_STRING *octet_string;
        ASN1_PRINTABLESTRING *printablestring;
        ASN1_T61STRING *t61string;
        ASN1_IA5STRING *ia5string;
        ASN1_GENERALSTRING *generalstring;
        ASN1_BMPSTRING *bmpstring;
        ASN1_UNIVERSALSTRING *universalstring;
        ASN1_UTCTIME *utctime;
        ASN1_GENERALIZEDTIME *generalizedtime;
        ASN1_VISIBLESTRING *visiblestring;
        ASN1_UTF8STRING *utf8string;
        /*
         * set and sequence are left complete and still contain the set or
         * sequence bytes
         */
        ASN1_STRING *set;
        ASN1_STRING *sequence;
        ASN1_VALUE *asn1_value;
    } value;
};

/** clang-extract: from include/openssl/asn1.h:878:1 */
long ASN1_INTEGER_get(const ASN1_INTEGER *a);


# define V_ASN1_OCTET_STRING             4
# define PKCS12_R_PARSE_ERROR          114

#define ERR_LIB_PKCS12          35
#define ERR_RFLAGS_OFFSET              18L
#define ERR_RFLAG_FATAL                (0x1 << ERR_RFLAGS_OFFSET)
#define ERR_RFLAG_COMMON               (0x2 << ERR_RFLAGS_OFFSET)
#define ERR_R_FATAL                             (ERR_RFLAG_FATAL|ERR_RFLAG_COMMON)
#define ERR_R_INTERNAL_ERROR                    (259|ERR_R_FATAL)
#define ERR_R_UNSUPPORTED                       (268|ERR_RFLAG_COMMON)
#define ERR_R_FETCH_FAILED                      (269|ERR_RFLAG_COMMON)
/** clang-extract: from include/openssl/err.h:395:1 */
void ERR_new(void);

/** clang-extract: from include/openssl/err.h:396:1 */
void ERR_set_debug(const char *file, int line, const char *func);

/** clang-extract: from include/openssl/err.h:397:1 */
void ERR_set_error(int lib, int reason, const char *fmt, ...);

#define ERR_raise(lib, reason) ERR_raise_data((lib),(reason),NULL)
#define ERR_raise_data                                         \
    (ERR_new(),                                                 \
     ERR_set_debug(OPENSSL_FILE,OPENSSL_LINE,OPENSSL_FUNC),     \
     ERR_set_error)
/** clang-extract: from include/openssl/err.h:496:1 */
int ERR_set_mark(void);

/** clang-extract: from include/openssl/err.h:497:1 */
int ERR_pop_to_mark(void);

/** clang-extract: from include/openssl/err.h:498:1 */
int ERR_clear_last_mark(void);

/** clang-extract: from include/internal/cryptlib.h:49:1 */
char *ossl_safe_getenv(const char *name);

#define EVP_MAX_MD_SIZE                 64
#define NID_undef                       0
#define NID_pbmac1              162
#define NID_pkcs7_data          21
#define NID_hmacWithSHA1                163
#define NID_id_GostR3411_94             809
#define NID_id_GostR3411_2012_256               982
#define NID_id_GostR3411_2012_512               983
/** clang-extract: from include/openssl/objects.h:67:1 */
ASN1_OBJECT *OBJ_nid2obj(int n);

/** clang-extract: from include/openssl/objects.h:69:1 */
const char *OBJ_nid2sn(int n);

/** clang-extract: from include/openssl/objects.h:70:1 */
int OBJ_obj2nid(const ASN1_OBJECT *o);

/** clang-extract: from include/openssl/objects.h:72:1 */
int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name);

#define EVP_get_digestbynid(a) EVP_get_digestbyname(OBJ_nid2sn(a))
/** clang-extract: from include/openssl/evp.h:556:1 */
int EVP_MD_get_type(const EVP_MD *md);

/** clang-extract: from include/openssl/evp.h:569:1 */
int EVP_MD_get_size(const EVP_MD *md);

/** clang-extract: from include/openssl/evp.h:761:8 */
EVP_MD *EVP_MD_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
                            const char *properties);

/** clang-extract: from include/openssl/evp.h:765:1 */
void EVP_MD_free(EVP_MD *md);

/** clang-extract: from include/openssl/evp.h:1229:1 */
const EVP_MD *EVP_get_digestbyname(const char *name);

/** clang-extract: from include/openssl/evp.h:1543:1 */
int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
                      const unsigned char *salt, int saltlen, int iter,
                      const EVP_MD *digest, int keylen, unsigned char *out);

/** clang-extract: from include/crypto/evp.h:997:1 */
int (*klpe_ossl_hmac2mdnid)(int);

/** clang-extract: from include/openssl/hmac.h:33:1 */
OSSL_DEPRECATEDIN_3_0 HMAC_CTX *HMAC_CTX_new(void);

/** clang-extract: from include/openssl/hmac.h:35:1 */
OSSL_DEPRECATEDIN_3_0 void HMAC_CTX_free(HMAC_CTX *ctx);

/** clang-extract: from include/openssl/hmac.h:43:1 */
OSSL_DEPRECATEDIN_3_0 int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
                                       const EVP_MD *md, ENGINE *impl);

/** clang-extract: from include/openssl/hmac.h:45:1 */
OSSL_DEPRECATEDIN_3_0 int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data,
                                      size_t len);

/** clang-extract: from include/openssl/hmac.h:47:1 */
OSSL_DEPRECATEDIN_3_0 int HMAC_Final(HMAC_CTX *ctx, unsigned char *md,
                                     unsigned int *len);

/** clang-extract: from include/openssl/x509.h:78:1 */
struct stack_st_X509;/* Full definition was removed.  */

/** clang-extract: from include/openssl/x509.h:130:1 */
struct stack_st_X509_CRL;/* Full definition was removed.  */

/** clang-extract: from include/openssl/x509.h:187:1 */
struct X509_algor_st;/* Full definition was removed.  */

/** clang-extract: from include/openssl/x509.h:199:1 */
typedef struct X509_sig_st X509_SIG;

/** clang-extract: from include/openssl/x509.h:468:1 */
typedef struct PBKDF2PARAM_st {
/* Usually OCTET STRING but could be anything */
    ASN1_TYPE *salt;
    ASN1_INTEGER *iter;
    ASN1_INTEGER *keylength;
    X509_ALGOR *prf;
} PBKDF2PARAM;

/** clang-extract: from include/openssl/pkcs7.h:47:1 */
typedef struct PKCS7_CTX_st {
    OSSL_LIB_CTX *libctx;
    char *propq;
} PKCS7_CTX;

/** clang-extract: from include/openssl/pkcs7.h:69:1 */
struct stack_st_PKCS7_SIGNER_INFO;/* Full definition was removed.  */

/** clang-extract: from include/openssl/pkcs7.h:105:1 */
struct stack_st_PKCS7_RECIP_INFO;/* Full definition was removed.  */

/** clang-extract: from include/openssl/pkcs7.h:134:1 */
typedef struct pkcs7_signed_st {
    ASN1_INTEGER *version;      /* version 1 */
    STACK_OF(X509_ALGOR) *md_algs; /* md used */
    STACK_OF(X509) *cert;       /* [ 0 ] */ /* name should be 'certificates' */
    STACK_OF(X509_CRL) *crl;    /* [ 1 ] */ /* name should be 'crls' */
    STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
    struct pkcs7_st *contents;
} PKCS7_SIGNED;

/** clang-extract: from include/openssl/pkcs7.h:147:1 */
typedef struct pkcs7_enc_content_st {
    ASN1_OBJECT *content_type;
    X509_ALGOR *algorithm;
    ASN1_OCTET_STRING *enc_data; /* [ 0 ] */
    const EVP_CIPHER *cipher;
    const PKCS7_CTX *ctx;
} PKCS7_ENC_CONTENT;

/** clang-extract: from include/openssl/pkcs7.h:155:1 */
typedef struct pkcs7_enveloped_st {
    ASN1_INTEGER *version;      /* version 0 */
    STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
    PKCS7_ENC_CONTENT *enc_data;
} PKCS7_ENVELOPE;

/** clang-extract: from include/openssl/pkcs7.h:161:1 */
typedef struct pkcs7_signedandenveloped_st {
    ASN1_INTEGER *version;      /* version 1 */
    STACK_OF(X509_ALGOR) *md_algs; /* md used */
    STACK_OF(X509) *cert;       /* [ 0 ] */ /* name should be 'certificates' */
    STACK_OF(X509_CRL) *crl;    /* [ 1 ] */ /* name should be 'crls' */
    STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
    PKCS7_ENC_CONTENT *enc_data;
    STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
} PKCS7_SIGN_ENVELOPE;

/** clang-extract: from include/openssl/pkcs7.h:171:1 */
typedef struct pkcs7_digest_st {
    ASN1_INTEGER *version;      /* version 0 */
    X509_ALGOR *md;             /* md used */
    struct pkcs7_st *contents;
    ASN1_OCTET_STRING *digest;
} PKCS7_DIGEST;

/** clang-extract: from include/openssl/pkcs7.h:178:1 */
typedef struct pkcs7_encrypted_st {
    ASN1_INTEGER *version;      /* version 0 */
    PKCS7_ENC_CONTENT *enc_data;
} PKCS7_ENCRYPT;

/** clang-extract: from include/openssl/pkcs7.h:183:1 */
typedef struct pkcs7_st {
    /*
     * The following is non NULL if it contains ASN1 encoding of this
     * structure
     */
    unsigned char *asn1;
    long length;
# define PKCS7_S_HEADER  0
# define PKCS7_S_BODY    1
# define PKCS7_S_TAIL    2
    int state;                  /* used during processing */
    int detached;
    ASN1_OBJECT *type;
    /* content as defined by the type */
    /*
     * all encryption/message digests are applied to the 'contents', leaving
     * out the 'type' field.
     */
    union {
        char *ptr;
        /* NID_pkcs7_data */
        ASN1_OCTET_STRING *data;
        /* NID_pkcs7_signed */
        PKCS7_SIGNED *sign; /* field name 'signed' would clash with C keyword */
        /* NID_pkcs7_enveloped */
        PKCS7_ENVELOPE *enveloped;
        /* NID_pkcs7_signedAndEnveloped */
        PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
        /* NID_pkcs7_digest */
        PKCS7_DIGEST *digest;
        /* NID_pkcs7_encrypted */
        PKCS7_ENCRYPT *encrypted;
        /* Anything else */
        ASN1_TYPE *other;
    } d;
    PKCS7_CTX ctx;
} PKCS7;

#define PKCS7_type_is_data(a)   (OBJ_obj2nid((a)->type) == NID_pkcs7_data)
/** clang-extract: from include/openssl/x509.h:686:1 */
void X509_ALGOR_get0(const ASN1_OBJECT **paobj, int *pptype,
                     const void **ppval, const X509_ALGOR *algor);

/** clang-extract: from include/openssl/x509.h:744:1 */
void X509_SIG_get0(const X509_SIG *sig, const X509_ALGOR **palg,
                   const ASN1_OCTET_STRING **pdigest);

/** clang-extract: from include/openssl/x509.h:1223:1 */
extern void PBKDF2PARAM_free(PBKDF2PARAM *a);

/** clang-extract: from include/openssl/x509.h:1264:1 */
PBKDF2PARAM *PBMAC1_get1_pbkdf2_param(const X509_ALGOR *macalg);

#define PKCS12_R_CONTENT_TYPE_NOT_DATA                   121
#define PKCS12_R_DECODE_ERROR                            101
#define PKCS12_R_KEY_GEN_ERROR                           107
#define PKCS12_R_UNKNOWN_DIGEST_ALGORITHM                118
#define PKCS12_MAC_ID   3
/** clang-extract: from include/openssl/pkcs12.h:59:1 */
typedef struct PKCS12_MAC_DATA_st PKCS12_MAC_DATA;

/** clang-extract: from include/openssl/pkcs12.h:61:1 */
typedef struct PKCS12_st PKCS12;

/** clang-extract: from include/openssl/pkcs12.h:277:1 */
int PKCS12_key_gen_utf8_ex(const char *pass, int passlen, unsigned char *salt,
                           int saltlen, int id, int iter, int n,
                           unsigned char *out, const EVP_MD *md_type,
                           OSSL_LIB_CTX *ctx, const char *propq);

/** clang-extract: from crypto/pkcs12/p12_local.h:10:1 */
struct PKCS12_MAC_DATA_st {
    X509_SIG *dinfo;
    ASN1_OCTET_STRING *salt;
    ASN1_INTEGER *iter;         /* defaults to 1 */
};

/** clang-extract: from crypto/pkcs12/p12_local.h:16:1 */
struct PKCS12_st {
    ASN1_INTEGER *version;
    PKCS12_MAC_DATA *mac;
    PKCS7 *authsafes;
};

#define TK26_MAC_KEY_LEN 32
/** clang-extract: from crypto/pkcs12/p12_mutl.c:62:1 */
static int pkcs12_gen_gost_mac_key(const char *pass, int passlen,
                                   const unsigned char *salt, int saltlen,
                                   int iter, int keylen, unsigned char *key,
                                   const EVP_MD *digest)
{
    unsigned char out[96];

    if (keylen != TK26_MAC_KEY_LEN) {
        return 0;
    }

    if (!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter,
                           digest, sizeof(out), out)) {
        return 0;
    }
    memcpy(key, out + sizeof(out) - TK26_MAC_KEY_LEN, TK26_MAC_KEY_LEN);
    OPENSSL_cleanse(out, sizeof(out));
    return 1;
}

/** clang-extract: from crypto/pkcs12/p12_mutl.c:108:1 */
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 kdf_hmac_nid;
    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;
    }

    if (pbkdf2_param->prf == NULL) {
        kdf_hmac_nid = NID_hmacWithSHA1;
    } else {
        X509_ALGOR_get0(&kdf_hmac_oid, NULL, NULL, pbkdf2_param->prf);
        kdf_hmac_nid = OBJ_obj2nid(kdf_hmac_oid);
    }

    kdf_md = EVP_MD_fetch(ctx, OBJ_nid2sn((*klpe_ossl_hmac2mdnid)(kdf_hmac_nid)), propq);
    if (kdf_md == NULL) {
        ERR_raise(ERR_LIB_PKCS12, ERR_R_FETCH_FAILED);
        goto err;
    }

    /* Validate salt is an OCTET STRING choice */
    if (pbkdf2_param->salt == NULL
        || pbkdf2_param->salt->type != V_ASN1_OCTET_STRING) {
        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR);
        goto err;
    }
    pbkdf2_salt = pbkdf2_param->salt->value.octet_string;

    /* RFC 9579 specifies missing key length as invalid */
    if (pbkdf2_param->keylength != NULL)
        keylen = ASN1_INTEGER_get(pbkdf2_param->keylength);
    if (keylen <= 0 || keylen > EVP_MAX_MD_SIZE) {
        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR);
        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;
}

/** clang-extract: from crypto/pkcs12/p12_mutl.c:156:1 */
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,
                                                unsigned char *out,
                                                const EVP_MD *md_type))
{
    int ret = 0;
    const EVP_MD *md;
    EVP_MD *md_fetch;
    HMAC_CTX *hmac = NULL;
    unsigned char key[EVP_MAX_MD_SIZE], *salt;
    int saltlen, iter;
    char md_name[80];
    int keylen = 0;
    int md_nid = NID_undef;
    const X509_ALGOR *macalg;
    const ASN1_OBJECT *macoid;

    if (!PKCS7_type_is_data(p12->authsafes)) {
        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA);
        return 0;
    }

    if (p12->authsafes->d.data == NULL) {
        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR);
        return 0;
    }

    salt = p12->mac->salt->data;
    saltlen = p12->mac->salt->length;
    if (p12->mac->iter == NULL)
        iter = 1;
    else
        iter = ASN1_INTEGER_get(p12->mac->iter);
    X509_SIG_get0(p12->mac->dinfo, &macalg, NULL);
    X509_ALGOR_get0(&macoid, NULL, NULL, macalg);
    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);
    if (md == NULL)
        md = EVP_get_digestbynid(OBJ_obj2nid(macoid));

    if (md == NULL) {
        (void)ERR_clear_last_mark();
        ERR_raise(ERR_LIB_PKCS12, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM);
        return 0;
    }
    (void)ERR_pop_to_mark();

    keylen = EVP_MD_get_size(md);
    md_nid = EVP_MD_get_type(md);
    if (keylen <= 0)
        goto err;

    /* 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,
                                     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);
            if (hmac_md == NULL)
                goto err;
            fetched = 1;
        }
        if (pkcs12_key_gen != NULL) {
            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 {
            if (fetched)
                EVP_MD_free(hmac_md);
            /* Default to UTF-8 password */
            if (!PKCS12_key_gen_utf8_ex(pass, passlen, salt, saltlen, PKCS12_MAC_ID,
                                        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, keylen, md, NULL)
        || !HMAC_Update(hmac, p12->authsafes->d.data->data,
                        p12->authsafes->d.data->length)
        || !HMAC_Final(hmac, mac, maclen)) {
        goto err;
    }
    ret = 1;

err:
    OPENSSL_cleanse(key, sizeof(key));
    HMAC_CTX_free(hmac);
    EVP_MD_free(md_fetch);
    return ret;
}

/* Added manually. Its a public function and its usually better than livepatching
   local functions.  */
__attribute__((visibility("default")))
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, NID_undef, NID_undef, NULL);
}

#endif
