forked from rpms/openssl
299b43d420
Related: RHEL-36659
1526 lines
66 KiB
Diff
1526 lines
66 KiB
Diff
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
|
|
zcmai$c{J1u8^_I<8ABNB4Pk6UgnstR*kkNVmbleK_MOQV5{B$bZuZ@TE(Q%DI~6Sy
|
|
za_>;K?Awg&gK)d&eNUbD{pbGioacPM-{+j?zt8ysc%~FEh#tT*L1Bzi@rLpHEFcC@
|
|
z37&Bef@j<U@QhRd4{`b#!AkHD>+hBY7)1Ad8U9Q_fZY!PWdV!<$)A!L;D^99D!DhE
|
|
zeQE;1U^pGX41@pY8<-JF2ME9z9peo_uJjO)6ojpI>t?AXtBj{Jv>|^u>h6bVJpBw;
|
|
z+#a^-mWMrkMYg}Jfxic~-vQC^Kt6wiU3a5|Vneevb2UJ$z)2qnB(3bX+ki6$-vZY@
|
|
z_jNXQZTo6cC8;EgG@yE-_xV79ZGQJ%I{69AF&s=P;{7m`BV^eD>hi8QDGbWW=k(N~
|
|
z?rwAx=6c3#F>pv2L4VOaP$r$r8H)wPkN!jmp#f9wlbG_*(`oK#@rheWABcv-oOfog
|
|
zZYz%aTa??GYAh^>vo?%Ytn1k}?VQgy3?$BA43ITPmqN=#z7%|ZuMyYTsb!MrPNefm
|
|
zZqFRZBncUQLYTJFRO5#Vm}Abxr(6e>cmXMQ`{e6;(W1HbvJy+6ch6Ew4a%-^T)$S!
|
|
zZ-KnuFs_#(<>qmAQHUMRgA=lor{8J5+lgi3=XMhrn{rQ)Q8o{i>As;dbVXX%-pF_*
|
|
zZzgS@b5K1fKeg-SDJdp=IfDL64sDgQcs97g>-}r5xM&}z?CAJ5DfWlrG{Vclzf>dn
|
|
zo{V*Ewz$6%Lf?^0e0Q>3DIInhuW#>Yl@qx8n7!wUPXuV11Kb@ccR{%DDS;0qHY>mu
|
|
zu-vr2t#J+HN=T``{Vnn9R#VlV+Ii{wMEM1hhXQ^ve5Zr$o3Kq}n^%2LkRM1kp&yyN
|
|
zAIuV?4KWFhmGbLG$uK=egKjkyGTp!b68!4=amq-$qDri1b;qV9YFJH~WOizc9I_%J
|
|
z44_J>+hGh!f}QMW!}Tr^@1zS%n5t6Ov;=QmkAqZ|PFXjGT~H>*Zg3m@=;#5|xjVXa
|
|
z=7!*1ZMuW<p*@7H5oMY-q~cIV6E9V=(v+!_8YNdAYFwU+&l^kII>{7jRvPZEBWku=
|
|
z>pX3o*5O*R8WWG=%h|0czJp%Kpab&Azs(Zn5^hkb3c)52sAW^j`(JBf2EO(<zljE%
|
|
z`bi_rlEW)C-u$2HsN?jtYmd~<cJ4GQS4)`TCW?cOn=TEPF122)|1vGe8ah>u;};5!
|
|
zJ78c=pipR;Q`}}oNj`E?>xmo1c;h+<V}gzDnZ+p8=J_*ePr-hDAF;AiEb1=>*jm-F
|
|
zvGHxT@3QKop@A(X%GI?VH>66GGkfm!BX8F_RG=h|*OTP)9Z`1b7<0OAi@nQHs^*85
|
|
zy*k?D(T_YY`YGM_^c@Sl@gz6Yg;Gw|Vky;(_%~Rln$h^CvdyVE;n0ScW(%D_2ZaT(
|
|
z<3JvG*k_Ou-4q$NEa0%}?T(4#q1{(hydmIOYF_cub5Cw@>J!^KG*=9kyF|@s=|27Q
|
|
zk5EesrnuH`ef-b#>n}vJP!(M)-5U9(H%wuaT-Hq#?`FZSaO8=JSxam?LFa7UX-&BK
|
|
zIDm)7{outv0D=ZX@KD@$+xPo;!p{7cP0UOn@b^&eyD9T;z_IRE*SwPN?f9?2sdG23
|
|
zR1)>R-S`UQdvhgZ6oQ8g4M@YO8nkG!jk}taE%TK@@R2z0qnt?s#hH5~A7!4`<Uiy-
|
|
zb+GHKYuerkq4us>E7*MW!m9T778sjy_p@|)v(>Z)=gcJcZLp?ECAhRQ*>te0UgO>T
|
|
z2!WGkqg5>=c`{x<y^wuFhT|FSRC)e#d8*!A)0WOPv$p(8edh&jY<hdM$Q&~rw8j`-
|
|
z*r^;@e}^G0>YLI9e=7GvIPcLnpC&fKx}N>j5dT@r0A!A+m^|pCwV%3}UgTlK*(`F{
|
|
zPE_J;HRlt|ru*VW!Bh<_#<*>;Jv5N5(AdP?(m~9_6tWxOYfDd`22P^04U&R2Zr$>-
|
|
z+S}&in23Z+TUPeaSFchSdhOE0HWRA57_5a4k<9K1n4QJ6@Ttyv(<|-^FIfAs){oKH
|
|
zqoB1uud(vU?4o(Mh)@Yne2`GvO5mxWbYq0!lNT2Fo9>2DjQiZ<u66N`Wbqiqa<6fk
|
|
zE_2~baBzC$s*~+S&NA`?*0A#;Lq~EhFPt0)_lar&I+|CWtU+F@bLr+zEp#zuOs}tB
|
|
z3X=ZaT}#ABufyaPp|I}B$x8CW#=SQ0Prry0_@67B_|^33<=mYJSm5GUc2<i_s`Q`v
|
|
zBW7&ii}A>4nM|rNda1}rV7|GK^jbT#JYRA%BE6nLJBS9BEd(yLu>AqCaWH~S=o;Yl
|
|
zic31awmQ<DYZCX+(SgP8=Nx(U0%C&fC(A~OqX!EaCBNh3YzW&a4~0Y0`PxXv@xRx<
|
|
zu2KLOzn64osnaYiZEKQyzRNI6w`T0)h}(P{;8_1~gW@9Yn|KE)Tr3Fn_drOxh)ebJ
|
|
ztjH=R5s@I+hQU5BX9B4_f#*V4$VKw!=$p?3_H+3ONT<QdaGQhWPLP%VTt%qt12MV>
|
|
z51!~>BfRljLJY^Qp!I#PjtaOIPDWYp+$&mbuVGcU)QqmMx@9N@lGwtF9@~Xn-;x*U
|
|
zRR}CmP}b3UWSLQx=yn#R!-^im4P0K}(>&NwVZrb@W~U1o6fNJ0i`^IUgM;lg5T9HE
|
|
zUp?nq!(DFHFFOZ^v`yg@3Tp0oG-OAq7r%L2@%9|U=R!)c$gbRS?~&Uuhq2aMJ4bF)
|
|
zf9njx1D3ZECBTEZrI0V={tmq_rW~!5r`TA@z92xfYOR#%H)xcyAYVzqvpW-~s7ggZ
|
|
zV|Wf(Fi+sk3X;)Gv!LJ@2C>OTp;CMfZI^QGP_q1}y?ib7d!@%IEYg|Tz27j)$Y$y3
|
|
z`4@4b-II|shmwgiM~Bgiiypp>)Nf4n-UjRgh-0>@+qtPVBd)8s%)CyCu8_8O6#0mT
|
|
zf%CXFZHEb(A-2~HXCGkoY3Frim&%;~856h40r_N$o~%%u3OU(#^nHpCJf&869MoR0
|
|
zqP7On(hy;EhPkfH46;KSkjHL35~I4ooaATVlj8K4mFeX(d6hS_vW^&Q1gR$l#1FOJ
|
|
zP3WkyRW%X8xE`;1+p8FC`VJL(1*uzfeD%;{Gp$p1BKOFmMcJo#Y&Mx?ruFQNH{1^7
|
|
zOHZfkTqNCL8+mP1emzme1_TNP`D>}n-%12coa(BwP0IT9FXEZ1t{DyZoYPX;<Rqs!
|
|
zj;fk4g%}xwq@Go(-peNk60uKX9|sp9Zr0gpU~t#3l(@a+n85m2cSX|hw$>)PLp^dR
|
|
zK=cP-8M)<tfpGOWKW9zeuyun@a6ignRwU~1rAYvhfG=S5;}FUUr~}eJB{P78!2J!>
|
|
zf3265`=`i(z#yUj>vI3o>>xtn<-Ye+$zWwI^q_2ul78QG*>lf;C9Y5z5p$iWB-kVb
|
|
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
|
|
|