From d959252c47af0eb0dd55bc032606901fedaf029b Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy 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,11 +792,32 @@ 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; 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 #include #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 #include "internal/cryptlib.h" +#include "crypto/evp.h" #include #include #include #include #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 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] [B<-descert>] [B<-macalg> I] +[B<-pbmac1_pbkdf2>] +[B<-pbmac1_pbkdf2_md> I] [B<-iter> I] [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 + +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 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 + + PBKDF2PARAM *PBMAC1_get1_pbkdf2_param(const X509_ALGOR *macalg); + +=head1 DESCRIPTION + +PBMAC1_get1_pbkdf2_param() retrieves a B structure from an +I structure. + +=head1 RETURN VALUES + +PBMAC1_get1_pbkdf2_param() returns NULL in case when PBMAC1 uses an algorithm +apart from B or when passed incorrect parameters and a pointer to +B structure otherwise. + +=head1 CONFORMING TO + +IETF RFC 9579 (L) + +=head1 SEE ALSO + +L + +=head1 HISTORY + +The I 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. + +=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 with PBKDF2 is used for protection of the PKCS#12 object. I is the passphrase to use in the HMAC. I is the salt value to use, -I is the iteration count and I is the message digest -function to use. +I is the iteration count and I is the message digest function to +use. I specifies the digest used for the PBKDF2 in PBMAC1 KDF. + +PKCS12_get0_mac() retrieves any included MAC value, B object, +I, and I count from the PKCS12 object. =head1 NOTES @@ -43,17 +59,18 @@ If I is NULL then a suitable salt will be generated and used. If I 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 -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 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) +IETF RFC 9579 (L) =head1 SEE ALSO @@ -62,9 +79,13 @@ L, L, L +=head1 HISTORY + +The I 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 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 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 @@ -54,7 +54,7 @@ if (eval { require Win32::API; 1; }) { } $ENV{OPENSSL_WIN32_UTF8}=1; -plan tests => 31; +plan tests => 45; # Test different PKCS#12 formats ok(run(test(["pkcs12_format_test"])), "test pkcs12 formats"); @@ -170,6 +170,59 @@ 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:/, ; + 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/, ; + 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"); +} + +# 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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 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 zcmai$XHXM}7KKSjLJPg9krp5dtO*HCK!hMlfKXgfI#LZaQi2reL5lP$MT%7EC6I^; zC`DLA7DP4z(iA~@4~T#+JMWFY_iKOLxpU6BGxy&&2Tf*=0|J=QWOguwO*UFLdXE#p z0(eAb+Xa!?w$Nm@H8dII@GF8mB7;nhEn^^n>3He>N&slHp90K@)wmrh*}zO_5eS=Iv@YNlGYB9H;<3c(p-6ScN9EXskqoP5qi{0w z47G^^7Gd+bc<}~Fgv7UOY||$9Vx7GWFqBwZz(2@Li=v*KZ6RzFhbL%5y>@HX*g|fK zCFqY*(F=sh(a;N)GHI#~25yMcT_{*a)IDT;VNko2^?scCxtKjyLprQ(YXAh}L#%n( zTQrhNI76$_g!lGcpUJy)#$0n;G6ZQ#gO>#8w>!LU{(S-z=WV6_Pg zU*q$mxw1C5Ex$SI=B3N?jdOchd{4fgVv=pT4ZoVk9Z8}FNHUvYc4BhvoTUsI8L^sL zopiZ;y2XdHfUO!V-Ar5BROQO(-K1jGZ7ZwQ!@L!*8;l#mKUQ?Yzp@bGbDg|ELDX}Q&X!Y4%3b*7*VHf%9yZv!SWi>t>qm6DRrsYEr;&BPo!3}4V@ zk?AMeU*?oAW{xGA$SE*L7`tfRwiT#@v9gqOtDkqwN;#{ly0J}Nt?hZV1xAlN*4&`O zo9da~^}MoxyT7Vk-92 z`Y3n;E-oE~9xR#>@)u0sn#CVfstkUtzoh@2+a05kV*_uuuYEzSeI1hbS)7*QO!P~C zUpz75Z=$s3)O#=QnbMzDER&L`hq$60tR+pC63&E_?TS#3G2b&kyp{F7S&&35;>&M5 zoi(MtRe^Tbu7XhXI68w9sOH1As}p-duSoG*Qkw>vkUeG2mDftlHA~m$ge}onp(n8m zjgL*GaTIZ6RA)2QALINZPma#jy)Ibw&1Y%$yleTJY&G+3C7q8dc)f9RLJ&!BHfys` zaK2_A6@J2!er@{0=ws8BH6wK-N)Zh+u50iiFvMOD3ykZI*xk+il9(tg0csxxoP57w znjV%tW3PLyr zEqvBZD*alJHx#UUSUudi^LW71U$8h1Dw(>yN;V%GV;T|#h&eWq{{|fGcn3K57F4v8+{vgq3Oh~ZrmcEST-O8z4%K1s}M;tPIc zvuMYpV5W+0Rp}Q}bxD!pJEs=sD=OV!n^Ee3qTtk`$Aw(zo%z>QnV?T|U!r)o;7w81 zU8CuN( zJMm~CzxWw161M$eue=Jp=M_L1i0#Y2MGA8K()rh?vW>%30k;T}1? z73pvY=|4vmbzqOSv-E$-F!*{oNrwn~$f41DUk0TThvqA(==BjI2KmgHnSx1=#&OijuHpX8vmIu1PgNf;+T-W%LX3WP z&{M@dfCZ%)WLtc}A*y(c^jYJ2tcE(uY+ewf71epylo^X+N#8rQb|Ue`>HI&+qd)mi zId1=z#p>EI>l<)+iMA|za=3;zliQfPg_;_ezGxi5rM!wx@zl36fR6R;pK9|{zggX* zI6Wwgv1upQj4OReh2&+=-Pn==w3ffs-CqWjKex5G188Rqb`XY6^RUk$`=4$`8sPh}=d zv}X!M)}HY<>H3J5M?xOCT|9W&eD}BTmWQhLCqxa48DSh-kzZRxQ+j6ECqPlX{Qmc^GC9chTwY@c+_gztryy>w&dM=$U8i>Kpbf+D} z?Vt}#Da&gwKZZJZ)>~u*r}KQ-=}o7F^3P&hdJSmW%72t?l7+Ayu%T4Lc{nj}7&S;y zz22p-cu4Wo2I^8oDFG?Hj(rdN$71iy?jf1LKBnw%CeB1cCTX{@H=Qu31p;5@G-X&J z1vYRNT{O^EkvCH4zO*k_)-C*YZk?&YXgTvRv&{EHw)K<0LYMb)dxsMdr7y};se-ZX zj`eRLC6ZHm$aFaJ&TF0w;}^q&d-N7Xu0&R=9n)a$X>W)J+jk6IL8~=YwI;Vo$o%nPP#DS zOsjaY(w>~gaR7Bor+MVily= 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