diff --git a/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch b/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch index 425c158..5189459 100644 --- a/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch +++ b/0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch @@ -1,30 +1,29 @@ -From 66b728801f141c9db8e647ab02421c83694ade79 Mon Sep 17 00:00:00 2001 +From 8be4ef77c64fcada41041c00e02c34b07658ba66 Mon Sep 17 00:00:00 2001 From: rpm-build -Date: Mon, 31 Jul 2023 09:41:27 +0200 -Subject: [PATCH 07/35] +Date: Wed, 6 Mar 2024 19:17:14 +0100 +Subject: [PATCH 07/49] 0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch Patch-name: 0007-Add-support-for-PROFILE-SYSTEM-system-default-cipher.patch Patch-id: 7 Patch-status: | - # Add support for PROFILE=SYSTEM system default cipherlist -From-dist-git-commit: 9409bc7044cf4b5773639cce20f51399888c45fd + # # Add support for PROFILE=SYSTEM system default cipherlist +From-dist-git-commit: 4334bc837fbc64d14890fdc51679a80770d498ce --- Configurations/unix-Makefile.tmpl | 5 ++ Configure | 11 +++- doc/man1/openssl-ciphers.pod.in | 9 ++++ include/openssl/ssl.h.in | 5 ++ - ssl/ssl_ciph.c | 87 +++++++++++++++++++++++++++---- + ssl/ssl_ciph.c | 86 +++++++++++++++++++++++++++---- ssl/ssl_lib.c | 4 +- test/cipherlist_test.c | 2 + - util/libcrypto.num | 1 + - 8 files changed, 110 insertions(+), 14 deletions(-) + 7 files changed, 109 insertions(+), 13 deletions(-) diff --git a/Configurations/unix-Makefile.tmpl b/Configurations/unix-Makefile.tmpl -index f29cdc7f38..c0df026de3 100644 +index 5d61ce9550..e9fba957f1 100644 --- a/Configurations/unix-Makefile.tmpl +++ b/Configurations/unix-Makefile.tmpl -@@ -315,6 +315,10 @@ MANDIR=$(INSTALLTOP)/share/man +@@ -324,6 +324,10 @@ MANDIR=$(INSTALLTOP)/share/man DOCDIR=$(INSTALLTOP)/share/doc/$(BASENAME) HTMLDIR=$(DOCDIR)/html @@ -35,7 +34,7 @@ index f29cdc7f38..c0df026de3 100644 # MANSUFFIX is for the benefit of anyone who may want to have a suffix # appended after the manpage file section number. "ssl" is popular, # resulting in files such as config.5ssl rather than config.5. -@@ -338,6 +342,7 @@ CC=$(CROSS_COMPILE){- $config{CC} -} +@@ -347,6 +351,7 @@ CC=$(CROSS_COMPILE){- $config{CC} -} CXX={- $config{CXX} ? "\$(CROSS_COMPILE)$config{CXX}" : '' -} CPPFLAGS={- our $cppflags1 = join(" ", (map { "-D".$_} @{$config{CPPDEFINES}}), @@ -44,7 +43,7 @@ index f29cdc7f38..c0df026de3 100644 @{$config{CPPFLAGS}}) -} CFLAGS={- join(' ', @{$config{CFLAGS}}) -} diff --git a/Configure b/Configure -index 456995240b..93be83be94 100755 +index cca1ac8d16..2ae1cd0bc2 100755 --- a/Configure +++ b/Configure @@ -27,7 +27,7 @@ use OpenSSL::config; @@ -67,7 +66,7 @@ index 456995240b..93be83be94 100755 # --banner=".." Output specified text instead of default completion banner # # -w Don't wait after showing a Configure warning -@@ -387,6 +391,7 @@ $config{prefix}=""; +@@ -394,6 +398,7 @@ $config{prefix}=""; $config{openssldir}=""; $config{processor}=""; $config{libdir}=""; @@ -75,7 +74,7 @@ index 456995240b..93be83be94 100755 my $auto_threads=1; # enable threads automatically? true by default my $default_ranlib; -@@ -989,6 +994,10 @@ while (@argvcopy) +@@ -1047,6 +1052,10 @@ while (@argvcopy) die "FIPS key too long (64 bytes max)\n" if length $1 > 64; } @@ -87,10 +86,10 @@ index 456995240b..93be83be94 100755 { $banner = $1 . "\n"; diff --git a/doc/man1/openssl-ciphers.pod.in b/doc/man1/openssl-ciphers.pod.in -index 658730ec53..04e66bcebe 100644 +index d4df30686f..cec4835268 100644 --- a/doc/man1/openssl-ciphers.pod.in +++ b/doc/man1/openssl-ciphers.pod.in -@@ -186,6 +186,15 @@ As of OpenSSL 1.0.0, the B cipher suites are sensibly ordered by default. +@@ -190,6 +190,15 @@ As of OpenSSL 1.0.0, the B cipher suites are sensibly ordered by default. The cipher suites not enabled by B, currently B. @@ -107,10 +106,10 @@ index 658730ec53..04e66bcebe 100644 "High" encryption cipher suites. This currently means those with key lengths diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in -index f03f52fbd8..0b6de603e2 100644 +index 9f91039f8a..fc34d4ca61 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in -@@ -208,6 +208,11 @@ extern "C" { +@@ -209,6 +209,11 @@ extern "C" { * throwing out anonymous and unencrypted ciphersuites! (The latter are not * actually enabled by ALL, but "ALL:RSA" would enable some of them.) */ @@ -123,10 +122,10 @@ index f03f52fbd8..0b6de603e2 100644 /* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ # define SSL_SENT_SHUTDOWN 1 diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c -index 93de9cf8fd..a5e60e8839 100644 +index 8360991ce4..33c23efb0d 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c -@@ -1443,6 +1443,53 @@ int SSL_set_ciphersuites(SSL *s, const char *str) +@@ -1455,6 +1455,53 @@ int SSL_set_ciphersuites(SSL *s, const char *str) return ret; } @@ -180,7 +179,7 @@ index 93de9cf8fd..a5e60e8839 100644 STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, STACK_OF(SSL_CIPHER) *tls13_ciphersuites, STACK_OF(SSL_CIPHER) **cipher_list, -@@ -1457,15 +1504,25 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, +@@ -1469,15 +1516,25 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; const SSL_CIPHER **ca_list = NULL; const SSL_METHOD *ssl_method = ctx->method; @@ -208,7 +207,16 @@ index 93de9cf8fd..a5e60e8839 100644 /* * To reduce the work to do we only want to process the compiled -@@ -1553,8 +1610,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, +@@ -1499,7 +1556,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, + if (num_of_ciphers > 0) { + co_list = OPENSSL_malloc(sizeof(*co_list) * num_of_ciphers); + if (co_list == NULL) +- return NULL; /* Failure */ ++ goto err; + } + + ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers, +@@ -1565,8 +1622,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, * in force within each class */ if (!ssl_cipher_strength_sort(&head, &tail)) { @@ -218,7 +226,17 @@ index 93de9cf8fd..a5e60e8839 100644 } /* -@@ -1626,8 +1681,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, +@@ -1611,8 +1667,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, + num_of_alias_max = num_of_ciphers + num_of_group_aliases + 1; + ca_list = OPENSSL_malloc(sizeof(*ca_list) * num_of_alias_max); + if (ca_list == NULL) { +- OPENSSL_free(co_list); +- return NULL; /* Failure */ ++ goto err; + } + ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, + disabled_mkey, disabled_auth, disabled_enc, +@@ -1637,8 +1693,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, OPENSSL_free(ca_list); /* Not needed anymore */ if (!ok) { /* Rule processing failure */ @@ -228,7 +246,7 @@ index 93de9cf8fd..a5e60e8839 100644 } /* -@@ -1635,10 +1689,13 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, +@@ -1646,10 +1701,13 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, * if we cannot get one. */ if ((cipherstack = sk_SSL_CIPHER_new_null()) == NULL) { @@ -244,7 +262,7 @@ index 93de9cf8fd..a5e60e8839 100644 /* Add TLSv1.3 ciphers first - we always prefer those if possible */ for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++) { const SSL_CIPHER *sslc = sk_SSL_CIPHER_value(tls13_ciphersuites, i); -@@ -1690,6 +1747,14 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, +@@ -1701,6 +1759,14 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx, *cipher_list = cipherstack; return cipherstack; @@ -260,10 +278,10 @@ index 93de9cf8fd..a5e60e8839 100644 char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c -index f12ad6d034..a059bcd83b 100644 +index cf59d2dfa5..1329841aaf 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c -@@ -661,7 +661,7 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) +@@ -700,7 +700,7 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) ctx->tls13_ciphersuites, &(ctx->cipher_list), &(ctx->cipher_list_by_id), @@ -272,7 +290,7 @@ index f12ad6d034..a059bcd83b 100644 if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0)) { ERR_raise(ERR_LIB_SSL, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS); return 0; -@@ -3286,7 +3286,7 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq, +@@ -3966,7 +3966,7 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq, if (!ssl_create_cipher_list(ret, ret->tls13_ciphersuites, &ret->cipher_list, &ret->cipher_list_by_id, @@ -282,10 +300,10 @@ index f12ad6d034..a059bcd83b 100644 ERR_raise(ERR_LIB_SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS); goto err; diff --git a/test/cipherlist_test.c b/test/cipherlist_test.c -index 2d166e2b46..4ff2aa12d6 100644 +index c46e431b00..19d05e860b 100644 --- a/test/cipherlist_test.c +++ b/test/cipherlist_test.c -@@ -246,7 +246,9 @@ end: +@@ -261,7 +261,9 @@ end: int setup_tests(void) { @@ -296,26 +314,5 @@ index 2d166e2b46..4ff2aa12d6 100644 ADD_TEST(test_default_cipherlist_clear); ADD_TEST(test_stdname_cipherlist); -- -2.41.0 +2.44.0 -diff -up openssl-3.2.0/ssl/ssl_ciph.c.7patch openssl-3.2.0/ssl/ssl_ciph.c ---- openssl-3.2.0/ssl/ssl_ciph.c.7patch 2023-11-30 13:43:03.510620566 +0100 -+++ openssl-3.2.0/ssl/ssl_ciph.c 2023-11-30 13:44:21.275313230 +0100 -@@ -1556,7 +1556,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_ - if (num_of_ciphers > 0) { - co_list = OPENSSL_malloc(sizeof(*co_list) * num_of_ciphers); - if (co_list == NULL) -- return NULL; /* Failure */ -+ goto err; - } - - ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers, -@@ -1667,7 +1667,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_ - ca_list = OPENSSL_malloc(sizeof(*ca_list) * num_of_alias_max); - if (ca_list == NULL) { - OPENSSL_free(co_list); -- return NULL; /* Failure */ -+ goto err; - } - ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, - disabled_mkey, disabled_auth, disabled_enc, diff --git a/0122-TMP-KTLS-test-skip.patch b/0122-TMP-KTLS-test-skip.patch new file mode 100644 index 0000000..f037ee3 --- /dev/null +++ b/0122-TMP-KTLS-test-skip.patch @@ -0,0 +1,16 @@ +diff -up openssl-3.2.1/test/sslapitest.c.xxx openssl-3.2.1/test/sslapitest.c +--- openssl-3.2.1/test/sslapitest.c.xxx 2024-04-15 10:14:47.292448045 +0200 ++++ openssl-3.2.1/test/sslapitest.c 2024-04-15 10:15:23.428396994 +0200 +@@ -1020,9 +1020,10 @@ static int execute_test_large_message(co + /* sock must be connected */ + static int ktls_chk_platform(int sock) + { +- if (!ktls_enable(sock)) ++/* if (!ktls_enable(sock)) + return 0; +- return 1; ++ return 1; */ ++ return 0; + } + + static int ping_pong_query(SSL *clientssl, SSL *serverssl) diff --git a/0124-PBMAC1-PKCS12-FIPS-support.patch b/0124-PBMAC1-PKCS12-FIPS-support.patch new file mode 100644 index 0000000..6e1cc96 --- /dev/null +++ b/0124-PBMAC1-PKCS12-FIPS-support.patch @@ -0,0 +1,1525 @@ +From d959252c47af0eb0dd55bc032606901fedaf029b Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +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 + #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 +@@ -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:/, ; ++ 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"); ++} ++ ++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+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{7jRvPZEBWku= +z>pX3o*5O*R8WWG=%h|0czJp%Kpab&Azs(Zn5^hkb3c)52sAW^j`(JBf2EO(u;};5! +zJ78c=pipR;Q`}}oNj`E?>xmo1c;h+*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`E7*MW!m9T778sjy_p@|)v(>Z)=gcJcZLp?ECAhRQ*>te0UgO>T +z2!WGkqg5>=c`{xYLI9e=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>2DjQiZ4nM|rNda1}rV7|GK^jbT#JYRA%BE6nLJBS9BEd(yLu>AqCaWH~S=o;Yl +zic31awmQ +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;)PLp^dR +zK=cP-8M) +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 +zcmai$cQo4z8^xrY#+` +zsC%QWRa;5aj(vO2`=0i^??3mC=RD{8{XXYB|9#FEz%!(PL9_s#0Scp+OfXE?X9CfI +zO7Zl25Ip@BfTyPbc!Q@&82E%CpMi~4*-@x=x8h{^0@0?%=a;JrWBq6NzTQ|xqnPt3Pp-qLOF?ZhM@U*k% +z8S;f2Y&sjIWE-ljnY#hYDxCPff~cAMW*cxt}-Y;CpLL2`8~mKlp|`+ +zVO#NIfJLR9srurg7<1Ej)w-T-%g)6@!yv*e+5k~^q#IT){H5sgJN5YPZcURUPXdi! +zN@w;^Hc`;<6N_m(RV87hh%xp;Lh5x;sSl8PXF$HOA0?7+FDt$bdiyl3%%I$X{ra_f +zJ`2RXrjL55k{(`MOM+~0Zmgi4Jnc^Foo);RAE$@##I$FsjIw!{Ot0hRk*m@=_D065 +z1+(e<9K&kCg=sx6&WN!QE0MHc@~B@qO6EeUeBQnCiO2c5Fw!CwRHFuyuQ7&RbJ5UBeuS)evzOVc5rXBoRm=UlL}s>=o~+5 +z;7ZH>w)!=YdqryP?c=0xTP-zzY87Pe6XX|(UJCf7h@CFhVn7Q`eZPV#0iQikCX3UsTbnBm^N7vPuIPg2J^6)(qm*LH1MB1ct~iDqZEh!HCS +zivd(AZ9AM!NuZkzWw_oW?3*mbfUYTXPfzsK@j6Jm+%4-tw+qTf+YN7{9vo#rU3+n5 +zvyK9Hv}g`0NA_53jmR_9k;_gERIxH8D-D?j$#GKkq575igo26mtuVg~ +zGDsY2l^9*E^X2>0K>0{pzxF_tt9z$axmMf^J6RHZ(xN+Bw%mTH@ym<=bJ%nxmQOGw +z{(z1#kxZs$Pji|XCHu)qt|x7j;Efv~^oce)=aynrS{KfxKLOty_<)g}W>R~>&)Tkv +ziA(6PeVfxD4Gn5DQLe4`a+EAp&hEQAh`3$vRD~2jSx=TPbVk~#q0MP}E%vU&sF)vG +z_G@dA#y@aBA0+qQ)psuP#S=Y{Qe_;>C6X#x39m5>b>j&w<(t#cf0>fi)_eBn +zA7Pdj4Ds#91AI^Q8>Mhe6h${nk7nMP4O197pLr9>vstt&6n$!9))v=Uq0QBBRu^IZ +z5x_&^fAHcT06{|_cqsO}?f-qeVdwtKCPoGj_L8EU{nVCi;PV<2bp?&S?k(E@@7*8Hki{T6W!VwY`WM~uJLSs +zfWV1!I28*C?yOf&q;ef)*q>6*lozg4rs>VMY-wLJ>nPM6xF}#_)8C&%VxR4zHplY7 +z&g4k?J9OzW$4XKG6wbv6o}**G7S@V&J$r}HfH})RM4pJKJm`bM)Nz}^}vK#1cOG}#$PNuO9mV`BL-SV;8 +z+va7TjD|~FR`=1?ekIfO+og+cCf4@QSqmK^7(ElwJ4@*i)7_1xS3MV>GY{mfpP(>D +z!D|CP6O~iB4;MTl!^FMu!GayDL1zNe&5?$WpIhK>cpApg?{j{1Z%B9`i$^O~`h2A7 +zFc!~-gk(m4b+Ns~QBKNW4!}#U6&Nne}zu +zVCmmIHHD4zx=e0W6gNCRT}`>)yw~CT=@+pIzGn)jH|qxU^6pFqE}rL8c2$i|t`3;} +zBX(lwi}BcaxlEcdYWblN|3Ygq@s(CsWue4oWM(6sRxlMTTMX#7vHk(EaWaBU>KNel +zN=m!FwL4RvX%O~MxS$fx3(h=xfw95%Q|04?@q@*z(%-RiHWk~c_k}_;c{_;43BNbK +zs!;%!ypwQcYS1Vv>u8aCwo5lhvu5n)jNN<_=-haJgX|{epA>}Ly4r>qeI-%l9zuo<(Q$-*MMz^<%G57c79sjnEO|3c0spzPiV(mvV3II +z&_!&AmeVBF5YumlwGXuVwDYRE=kk2OITMfSA^8-GzML@ZWm1a&_`6g;cxt`SM^IynL8BdRfNvN6Nf{u&Gc@a$^0XWHf6t(iMbS}*>*0+*PKoy +z-6t~*ZW5lbje-sepPq_JHyvuU>)D(vp +zmZFk4%`!FtN#jzg-76#o5in2U9)&z)xzS*!j>cZUTI%tJeG=nm-4jj4+gh9GjP%JN +z0g)eorRS9U1#-U6^%--@hOGy5lJh|xqas0@H(eZv0{j7^ABRw8Kn;-oDH#C-1a59& +zBWP=_ulEmE!63o^>vI3o>>z>>mHu~CNML16)Ua%ulK#L<`7`gp9+tpJq5r+oPI{IQar@!yJZdr(R^P9KNApO`$IsP03$%+r(^{9AaFGT*QT>i +zZ2%YyrvVsY@c(=R(?e+hei*%DyaC9S76L*+SnIZKmRT@MdpbiK3r3>uzK_P!&Tz)< +zVXJR@*wI$y_{r$|d0+<|SQ^vi3O3lZH%iy7sWzsr`YbDO()$XMM$VgUz!`&Yg==2; +zHXFOTZJ$ISm4=cAl}~j)AIP)L@4n3-KZZGmfl0+Y?}u{*EjmHn-c_eXf!PHdo*I!4CEAmwhqTtgpPB+pJpd@SOz{WH{tOq_Y`R*vk>W?8<&T#N@?2}8m;8d +zr0sJIsRkCLcE30y#e^+~(|*aNe&r~c4XW~b_sT0S+Q%s;I=&sn_CSnU@nYyNFn +z5V)&Jb5J?F$6{l+K206I>`+e?D^s*om##;RkqL)tSLWjL$J4e>vjkfdM|$ds>K#^E +zPnxE+IF~HP#iDp~cdJSw&m(cJp(*V>rDZ@td1qXDM@ +z(rAms$V#m@-=})YN7}m8hbrg0c3PBb#7%J%C4nc+IwNIEZI>FpObalFOjY9e1cTxZ +z=ok~$*Qr@kT&9LeKC-B_#ElZXQ9Xn{!CL#=Vw7^r{JFFz;9LD4urgCjsxSCi+f=Zz +z@$EKmv+Jdx0jpl1M91FeiBsZjF83%I-N;xzBHI|`vEWWvXb81c~r16F6LKo1v&cw3g +zKpuS1ub&d#92vUI@9@>z9TUe*y|18fgWt2vtm=j5p6ue(C)PD+o+vDDiIUmcbN1&S +zAr|Hgac#%_d{6ZnB%_%q3N99IO}x_^Cb0E9=1nBeX5p?-KzE1OGjXTEwOnR7#${VDZKY5q!Os_tC#mew`X_5z*$ivrfxeSO(v_L)vQWe#WJPbddO%C0O +zO1z`ue2Uq0U%Vucs)ofFwGVZK1h5tv8M|9Jh_?NVt>*p_jJi>pESZZJOw2LQOZFmCzxA(LDjPvzQh()zx5f)qUYPbAR^Q2^xD8 +zxZ3YEUOAalJnt4BBJPO~6l`A!I1`X+3O9KC+#G+?-5`p7pX;M*ef&ciJVv3?>mya0 +zv1leJC?oQ#lg%ZLa&kIz=tbe-BUzW{PL4zSL=}H6^{bCpA+J<9wezMHx*0O3*Vc3b +zrG9tU5H{59G`?L?RR8#NCHXjIqk&E{kP4P50(4qg|A1IK7{VsB_3^qT +zrJdi}9I4OLiF@eifD-o$jy$^lF@biI +zvEH?c*SD5fMq*dcdcO8!{H{flQC2(miobT$GOJpsM^{}~5$u(1;Tfq+Q$Y8k_C&?qGV-ctXk5ff)ff&!p6 +zGKVOfui(iJlvYnOU&ql6VUrC*P`nQ9I(fE889wA*fd=}W;-eHMsjQs7W6Uz5MQVEf +zd7MbkWaP}DMB>cRVf5mnhi?<*n4!U2pKXxkgthukUTW>A>sMS>ewTQ6aQoYJx$wrp +zi@0`8hY6|yw$Bu2=WqFG=M|y*@|@o}V>iN}T(Ws@b_nh=IoWsYU5XDprB3K0sH1R2 +zWfh{KCQR=Pb6uGkVuLgyPTaV~$Fzeu$WOtiB^fa*)63`b2{*H|kLYU!D5r(Q_jTUQ +z=&16qD#8MBycVynG#2dDFkA(R2=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 +zcmai$cQ71^7RK$`T}$+Gm0-0cYF59jURE#BuVfLuv(bVGmgqv<=$){+SY-*KlY|r! +z#Jx+RMXxLRB6xZ8-X!nMdo%ZsGiT2CojK>f-+TxxO%f15iNMl;A=F|C`U%H$04hKk +zmih>UrQSnesYwVd$oZ!QDZ_#+ze{F70LAyF|I+~=Y<~=3I)ouY^yf&6;08feacsLT +zzI8!BAd~_@3xWRY8;}}If#88qJ0<7?+$cc+F%V<@-tBU8dPy%AaC6~U^!*PpSju_U +z_#<@99Zx&T>f8V+y#P=2kRwBLhD_lOlh#hzwiVgh#7&Q39ZL96Nl?#yyN_@|VcVe^ +zSHCXAZSLDA;|OKpgkhx%ozEw-j7x{_GKo(iP7y#t3Fn8=JU;VoK(9~rMR9OWA&Zwf +z>2RmJINvLFkBV8u0Q`&Ei2~tj-eep?`0P&xJ|x1J?IN}+>~fARMtJ&8@&~;B7|Xo{ +z`+d2o0JADvW7XwlVfyBY>Mb4X)`M$>`a$@4lpd_^OgpSX;7ifx_p0$dJ?chD9(W4h +zl&y;$ytw7Nd?m|$vy|gQ5y*@I|IY@ +zg8B4gmJyZU!nEF(mxS1ewMfb@dE^b2(uI&}@At30<70fCb7K-Z#h4xmlPh12{G}Ad +z^>ng#x836vAM&1P(z}Z_oJ9BytgfAtMPAV16Q+I}-$=k5Gq5j8TAaVQsgesWw7|m{ +zxYl~SuX+>UR+(CR_gm7}z1EsPH3~A1@iNN4`pCo+oLFJyPyehk$I9?Z`gz@mU7gr7xy@ +z-hubN2E|F$=n;dp!S)<^RMD}4EL<*cp(fcNHbKOls@_;kD40y&yU6BilOOAAz^ipx +zYBsgZX|k?bObSPHHyO?E8D=X1TZA(|un}Ggz(MUs3bpl~4q{~r+5HcOV0Y^stKlN&TgftoPH?g)8aJ~>Ef0dNg-go)u +zA7SQZH1QqZ2DzWp&>-CMZkc8nq0`SiPR&fTIz{-_HhllHi-N=^2L%en~D +zDFhZA|AQC*1Q0j`gau>1%YNU>3v%V(Y@($B0Kc2k-$lv41CHg8ikeNKkJH}*r@_Mz +zCokx8x8)Ve@Ai7=1PBWn9hQKSRLL86c}HDJ_Z +z_Tkz%l(qWkjaC{OC^9r=8=~v=VXW&2$(v6Z+@VhwOLXm^vFc`0y2-iw +z5d{ +z(LNXRbQDy=9M?}-yRl6*V4E(qn^@aRWyyaEqxDEc9jv5B%=R=I+juO$pdZZHI!B_< +zf;R`fC#z<1OP1Ut!$iEW!F-+TL6^J|Es^?9UzlNUd+0|~AG1xlH6%Qi!lLA=yr;-o +zw8irwA(>Gd&eqpiDu@~M;nxI4&!k;nI6I9T +zOZ@JkE?}V3ZFHxyxZ&x=ddj1gqfVbszX(@yKbO7muN&0KyFVSc%*w6cq8ycs3z+{S +zc5?WO;rK*_WSSvzwZwpDsjZmsS|hBgP;@skvyn<8m<*IEMrgM){sFRbG=NNN>0xzB +z%eudIIFX;L;g66pL8Ts7oj7#@V}tExDkks~C(Bu7zhk7WD)&<#@rPz|brK8{es6qT +zBMU5jFX}?qpjKYq*(&|~kZOTq)6mxmv->vCsqxXywyUsT(mfb|DK9v{lR?x~SZs)6 +zT}mz)4+B7U^o}`M5(!m_9OB`j*NLBFZa?EW&gZU#Igj8XtWMT?02Tp@)nQT@LKGPp +zPjzorzVTmW7>ip+>iXGF@VFJvL|Yy_DB0+$qgOFki>bD_qb~*!*~1E++lJoSlMxt@ +z4JwmW&{ThHo>h_L&JNe4M^0jfZ!B}Eog66Ap}3rKGx_vN*6zi}9rO7^fp)44pIn1p +zJ!jp-+-TFSxC#Yz&SGSX>K=GD=SHiPzIjsp_A1rq;_Xs_L+Q1FGxsrOL-n_|PHe^j +zmRb5IbZc&2pOGz|ji4TxEgJ?oD69adHUN +zu|-(XQYB|ju%ueL**1o11f60KCdTF1shw{Nm*R#W6{;iO%Rfn_lgQ2;_=Z}8wMon^ +zy@(g=n~9n~6-}ByJB?Xc@$_pUeWPjg(PJ8BIA^T6o1a!U?zVx+F6a^I4efllEfd*1 +zd=1m7;W$m!M-P}_>;f%59lXZ%DlP_GF>=QZ%cPj~=Y(Mti79>)?^AuDsrCF*fUcr- +z`@I{j?NR8=0}|KH*m)=p=FL2+B1xz~P|3Rx1K51d#aI-Wu!VoL~RKU#aPxSA{M*ucpt;un1#F +zN{O=! +wg4}<_IuKt(mEQv;B2YmcIU?0AuRAzb@!TtLl{HLKz*I9j88QQc{^zZK0K6{N*8l(j + +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 +zcmai$c{J3I8pdbF48|5&vqjlrhOaf*e~6LnON7GM*TRf3A}0Gbexk{eEm_A}b`r8> +zuMmwr#kJMgD&qQ`dr#f}?jP@Y&+|O*Iq!d;^8f?}G6YNm5Ex*zaLE`{%mFi)4xCSb +z??VZ2DnNj50R*V?pNKY}0JS)^Odw#;=|cTUz`%{)0>%tn11|lMOaMQWo?KOURPZ9w +z69S?|M>=i!$5!lE!;5%1$L!@f+eA>5>rmGyl-<5gfLWQhjpo01c7G3*uvx%W?sgue{9RT|s4#R>C6J%Edk<=-uq-d@r!ROUg)X-ILGkK7})ZpGl# +z6-*+R=UWkb{1Uk*#E0!_e;YnW&+pQ^eq4sI$Ww|Hv(}0#a +zKlQ^+B%Z=t5EUDbniPw$^O<*tICAC6KObyy_!1pUMJP=_w3MQ_L}_KLa~I$j`nTT} +zHKwJ_EiYl2+#BDc^{A=46L)q=)y5g6&!p^&Vq?l?HW_g0&*yWG8)~BcGLmG2_zkpD +zuJoXL67oBKU=FvPnif~prLZ59aGj)q&F+Tb8c-j#f&RP0OKAu!zYnC!R&k()qJN1D +zH)n{YHF**!la_j>+`ZaK*3+)|hY9ao;2E{SU;60toCXNT@qDh`ml?gc_3=eV{?51F +z=U0+nWJ9&68P5wsaB~Oh{Ml7-lZyT?nz7-@3_Pa$cFyfOH{VqUHj`A%$91}J$gqD1T>EH^|xG)1&ISL#*ZFlj`&Q|`X@`eO}%)v57KM?!MyKQ +zXc{9i<$mE}VxakYPTQpB%tY3V*Dl{DW5lfc_V}%EtVn1p7nY~{N*8NuoyQ_$)ws86do%hBVb(F1bVEvsA9>F&O +zRQs=KLrclFky%8f;cM0HkAnqrG!8bmFh0|w6SSh^JAOInR!2Krmr4GHh^F&q&BF29 +z*|eckw27|l!`5RThgUd3i2XeIHB||T+HmQF1 +zPDP#z=8kjer&j+4rM{T~`6CS-p+%{%^hoip*Obdm#BNa17XnqR4f#}AZEEru&#GzO +zS(|OatP(Y7WaOUxEG~h6fN5pGvEXc-|1Te>L%`F|$k|~yrON}$Q~GV(GItZZR5rtq +zx@@Va4Xu+B1WTkJN6(5zi^HOIP318BM~CGBgDH4 +zLaK$Ks@QD9D>chzYe`t>NjjE`cuObjo}66SL50g8p9$Sm^^tns +z;0_RAQNMZd4}f48C;@i&)b>3cPg=(RvWbZS3^@&DPfg_i15SP5i)Nv}TDSi%aONt8 +z`B0c7FBPnYhe9LB8cKkUDN;BJQl}W&QaCv2Pc-)0f6CFEbAOdK&Ob3`Zm!y`U3A_z +zODU+hSBxYWL41$n&+28lD!q0TwRAFBNsli%CnzuIPE_J$DjM&>bE7k^auH?~miFK) +zIqaBwg7QmEwp)ZSN6kj5jefLN-FgZBcH76~>AGKHJauJBXEOUCn_uh{(n3he>JRLQ +zR|B-g%xs4l(>}LpgECD!Tqrr!Vx|{2qiD6Sg)V5%4}U+mVekZjH08N`i}}Fy*3^0# +zKz&<(b0knfLr)75aA8X|3pbq_oeCq8e7yiN*S+Qd)>ig&jMwh9R+b7e+Im__SSes+ +zMDA};&vN=jlrY*Ehga$F@lBOSQ_Yyhk>Pz>=S5R8vmJc)scR +z=#Y@?kRW+Jndd2|TkldK}))zdux@RmaSl_TDG0?o5 +zMMh%2IT4G9~=#_+fE&WM@d6`gnk`K +z4ZAPu-T)R`7#!}|D~Z^i8YP*nzuQ&$t^)ex^SI)5bkOl@$Ch5et(hmU_H$6{=rd(= +zH*9Taf@8>5lz@Cc`s0rbN|)&x9;{@sX6g>J>@7D0-tggLsaChE +zzWcuCVOajxbVG+ly{x;j!jR)mBkL?no4>)=YitX8aX)SOTr(yPVoxrI*RR#up7#Q5 +z!0saXlgee#J^Ms>kaU^#^Pe+9Tw>CWyg)zG{L3(N9jlQ$s~q?b%j!`e#kFy^z8iAp +zQ|IfPf8O6EM%?ua$)DxW{I#W1QaAd&_M^8%JCiVwCzS=o!;k(}DaOl#W09 +zSk4>aZ7zFHy<|Igb>#!~?A4PQWj>6QxLJ@Kj1CZPTN_dw)mu~-BUvZrsoc9C#w#ld +zT>K4KIHxQZl%o^f%#yHeHs^H6%z +z8T%F9D?MlaAu9x|^*?Qn@wCnT>2{|Isuci|f7PzcNM|bXivb;s8AAv{)-jC$Rb~R?lGFsEHIm`3Psh-q4iM{;+CGg!1m8_f06hv5BRSmBm$E2pIft +D?Q7k< + +literal 0 +HcmV?d00001 + diff --git a/0125-PBMAC1-PKCS12-FIPS-default.patch b/0125-PBMAC1-PKCS12-FIPS-default.patch new file mode 100644 index 0000000..f7257ea --- /dev/null +++ b/0125-PBMAC1-PKCS12-FIPS-default.patch @@ -0,0 +1,21 @@ +diff -up openssl-3.2.2/apps/pkcs12.c.xxx openssl-3.2.2/apps/pkcs12.c +--- openssl-3.2.2/apps/pkcs12.c.xxx 2024-08-14 11:24:41.164589397 +0200 ++++ openssl-3.2.2/apps/pkcs12.c 2024-08-14 11:28:21.071004221 +0200 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -708,6 +709,9 @@ int pkcs12_main(int argc, char **argv) + } + + if (maciter != -1) { ++ if (EVP_default_properties_is_fips_enabled(NULL)) ++ pbmac1_pbkdf2 = 1; ++ + if (pbmac1_pbkdf2 == 1) { + if (!PKCS12_set_pbmac1_pbkdf2(p12, mpass, -1, NULL, + macsaltlen, maciter, diff --git a/0126-pkeyutl-encap.patch b/0126-pkeyutl-encap.patch new file mode 100644 index 0000000..8f82cce --- /dev/null +++ b/0126-pkeyutl-encap.patch @@ -0,0 +1,430 @@ +From 77a0eabe15b9c8c0fb5fde27f6ce1c593c278e20 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Wed, 7 Aug 2024 17:17:18 +0200 +Subject: [PATCH 1/3] Support of en/decapsulation in the pkeyutl command + +--- + apps/pkeyutl.c | 83 +++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 69 insertions(+), 14 deletions(-) + +diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c +index b5390c64c2a81..a14ad88217823 100644 +--- a/apps/pkeyutl.c ++++ b/apps/pkeyutl.c +@@ -24,7 +24,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, + const char *keyfile, int keyform, int key_type, + char *passinarg, int pkey_op, ENGINE *e, + const int impl, int rawin, EVP_PKEY **ppkey, +- EVP_MD_CTX *mctx, const char *digestname, ++ EVP_MD_CTX *mctx, const char *digestname, const char *kemop, + OSSL_LIB_CTX *libctx, const char *propq); + + static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, +@@ -32,7 +32,8 @@ static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, + + static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, + unsigned char *out, size_t *poutlen, +- const unsigned char *in, size_t inlen); ++ const unsigned char *in, size_t inlen, ++ unsigned char *secret, size_t *psecretlen); + + static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx, + EVP_PKEY *pkey, BIO *in, +@@ -47,6 +48,7 @@ typedef enum OPTION_choice { + OPT_DERIVE, OPT_SIGFILE, OPT_INKEY, OPT_PEERKEY, OPT_PASSIN, + OPT_PEERFORM, OPT_KEYFORM, OPT_PKEYOPT, OPT_PKEYOPT_PASSIN, OPT_KDF, + OPT_KDFLEN, OPT_R_ENUM, OPT_PROV_ENUM, ++ OPT_DECAP, OPT_ENCAP, OPT_SECOUT, OPT_KEMOP, + OPT_CONFIG, + OPT_RAWIN, OPT_DIGEST + } OPTION_CHOICE; +@@ -64,6 +66,8 @@ const OPTIONS pkeyutl_options[] = { + {"encrypt", OPT_ENCRYPT, '-', "Encrypt input data with public key"}, + {"decrypt", OPT_DECRYPT, '-', "Decrypt input data with private key"}, + {"derive", OPT_DERIVE, '-', "Derive shared secret"}, ++ {"decap", OPT_DECAP, '-', "Decapsulate shared secret"}, ++ {"encap", OPT_ENCAP, '-', "Encapsulate shared secret"}, + OPT_CONFIG_OPTION, + + OPT_SECTION("Input"), +@@ -81,12 +85,13 @@ const OPTIONS pkeyutl_options[] = { + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file - default stdout"}, ++ {"secret", OPT_SECOUT, '>', "File to store secret on encapsulation"}, + {"asn1parse", OPT_ASN1PARSE, '-', "asn1parse the output data"}, + {"hexdump", OPT_HEXDUMP, '-', "Hex dump output"}, + {"verifyrecover", OPT_VERIFYRECOVER, '-', + "Verify with public key, recover original data"}, + +- OPT_SECTION("Signing/Derivation"), ++ OPT_SECTION("Signing/Derivation/Encapsulation"), + {"digest", OPT_DIGEST, 's', + "Specify the digest algorithm when signing the raw input data"}, + {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, +@@ -94,6 +99,7 @@ const OPTIONS pkeyutl_options[] = { + "Public key option that is read as a passphrase argument opt:passphrase"}, + {"kdf", OPT_KDF, 's', "Use KDF algorithm"}, + {"kdflen", OPT_KDFLEN, 'p', "KDF algorithm output length"}, ++ {"kemop", OPT_KEMOP, 's', "KEM operation specific to the key algorithm"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, +@@ -103,23 +109,23 @@ const OPTIONS pkeyutl_options[] = { + int pkeyutl_main(int argc, char **argv) + { + CONF *conf = NULL; +- BIO *in = NULL, *out = NULL; ++ BIO *in = NULL, *out = NULL, *secout = NULL; + ENGINE *e = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; +- char *infile = NULL, *outfile = NULL, *sigfile = NULL, *passinarg = NULL; ++ char *infile = NULL, *outfile = NULL, *secoutfile = NULL, *sigfile = NULL, *passinarg = NULL; + char hexdump = 0, asn1parse = 0, rev = 0, *prog; +- unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL; ++ unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL, *secret = NULL; + OPTION_CHOICE o; + int buf_inlen = 0, siglen = -1; + int keyform = FORMAT_UNDEF, peerform = FORMAT_UNDEF; + int keysize = -1, pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY; + int engine_impl = 0; + int ret = 1, rv = -1; +- size_t buf_outlen; ++ size_t buf_outlen = 0, secretlen = 0; + const char *inkey = NULL; + const char *peerkey = NULL; +- const char *kdfalg = NULL, *digestname = NULL; ++ const char *kdfalg = NULL, *digestname = NULL, *kemop = NULL; + int kdflen = 0; + STACK_OF(OPENSSL_STRING) *pkeyopts = NULL; + STACK_OF(OPENSSL_STRING) *pkeyopts_passin = NULL; +@@ -147,6 +153,9 @@ int pkeyutl_main(int argc, char **argv) + case OPT_OUT: + outfile = opt_arg(); + break; ++ case OPT_SECOUT: ++ secoutfile = opt_arg(); ++ break; + case OPT_SIGFILE: + sigfile = opt_arg(); + break; +@@ -216,6 +225,15 @@ int pkeyutl_main(int argc, char **argv) + case OPT_DERIVE: + pkey_op = EVP_PKEY_OP_DERIVE; + break; ++ case OPT_DECAP: ++ pkey_op = EVP_PKEY_OP_DECAPSULATE; ++ break; ++ case OPT_ENCAP: ++ pkey_op = EVP_PKEY_OP_ENCAPSULATE; ++ break; ++ case OPT_KEMOP: ++ kemop = opt_arg(); ++ break; + case OPT_KDF: + pkey_op = EVP_PKEY_OP_DERIVE; + key_type = KEY_NONE; +@@ -303,7 +321,7 @@ int pkeyutl_main(int argc, char **argv) + } + ctx = init_ctx(kdfalg, &keysize, inkey, keyform, key_type, + passinarg, pkey_op, e, engine_impl, rawin, &pkey, +- mctx, digestname, libctx, app_get0_propq()); ++ mctx, digestname, kemop, libctx, app_get0_propq()); + if (ctx == NULL) { + BIO_printf(bio_err, "%s: Error initializing context\n", prog); + goto end; +@@ -387,7 +405,7 @@ int pkeyutl_main(int argc, char **argv) + goto end; + } + +- if (pkey_op != EVP_PKEY_OP_DERIVE) { ++ if (pkey_op != EVP_PKEY_OP_DERIVE && pkey_op != EVP_PKEY_OP_ENCAPSULATE) { + in = bio_open_default(infile, 'r', FORMAT_BINARY); + if (infile != NULL) { + struct stat st; +@@ -402,6 +420,16 @@ int pkeyutl_main(int argc, char **argv) + if (out == NULL) + goto end; + ++ if (pkey_op == EVP_PKEY_OP_ENCAPSULATE) { ++ if (secoutfile == NULL) { ++ BIO_printf(bio_err, "Encapsulation requires '-secret' argument\n"); ++ goto end; ++ } ++ secout = bio_open_default(secoutfile, 'w', FORMAT_BINARY); ++ if (secout == NULL) ++ goto end; ++ } ++ + if (sigfile != NULL) { + BIO *sigbio = BIO_new_file(sigfile, "rb"); + +@@ -473,13 +501,15 @@ int pkeyutl_main(int argc, char **argv) + rv = 1; + } else { + rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, +- buf_in, (size_t)buf_inlen); ++ buf_in, (size_t)buf_inlen, NULL, (size_t *)&secretlen); + } + if (rv > 0 && buf_outlen != 0) { + buf_out = app_malloc(buf_outlen, "buffer output"); ++ if (secretlen > 0) ++ secret = app_malloc(secretlen, "secret output"); + rv = do_keyop(ctx, pkey_op, + buf_out, (size_t *)&buf_outlen, +- buf_in, (size_t)buf_inlen); ++ buf_in, (size_t)buf_inlen, secret, (size_t *)&secretlen); + } + } + if (rv <= 0) { +@@ -500,6 +530,8 @@ int pkeyutl_main(int argc, char **argv) + } else { + BIO_write(out, buf_out, buf_outlen); + } ++ if (secretlen > 0) ++ BIO_write(secout, secret, secretlen); + + end: + if (ret != 0) +@@ -510,9 +542,11 @@ int pkeyutl_main(int argc, char **argv) + release_engine(e); + BIO_free(in); + BIO_free_all(out); ++ BIO_free_all(secout); + OPENSSL_free(buf_in); + OPENSSL_free(buf_out); + OPENSSL_free(sig); ++ OPENSSL_free(secret); + sk_OPENSSL_STRING_free(pkeyopts); + sk_OPENSSL_STRING_free(pkeyopts_passin); + NCONF_free(conf); +@@ -524,7 +558,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, + char *passinarg, int pkey_op, ENGINE *e, + const int engine_impl, int rawin, + EVP_PKEY **ppkey, EVP_MD_CTX *mctx, const char *digestname, +- OSSL_LIB_CTX *libctx, const char *propq) ++ const char *kemop, OSSL_LIB_CTX *libctx, const char *propq) + { + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; +@@ -642,6 +676,18 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, + case EVP_PKEY_OP_DERIVE: + rv = EVP_PKEY_derive_init(ctx); + break; ++ ++ case EVP_PKEY_OP_ENCAPSULATE: ++ rv = EVP_PKEY_encapsulate_init(ctx, NULL); ++ if (rv > 0 && kemop != NULL) ++ rv = EVP_PKEY_CTX_set_kem_op(ctx, kemop); ++ break; ++ ++ case EVP_PKEY_OP_DECAPSULATE: ++ rv = EVP_PKEY_decapsulate_init(ctx, NULL); ++ if (rv > 0 && kemop != NULL) ++ rv = EVP_PKEY_CTX_set_kem_op(ctx, kemop); ++ break; + } + } + +@@ -679,7 +725,8 @@ static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, + + static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, + unsigned char *out, size_t *poutlen, +- const unsigned char *in, size_t inlen) ++ const unsigned char *in, size_t inlen, ++ unsigned char *secret, size_t *pseclen) + { + int rv = 0; + switch (pkey_op) { +@@ -703,6 +750,14 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, + rv = EVP_PKEY_derive(ctx, out, poutlen); + break; + ++ case EVP_PKEY_OP_ENCAPSULATE: ++ rv = EVP_PKEY_encapsulate(ctx, out, poutlen, secret, pseclen); ++ break; ++ ++ case EVP_PKEY_OP_DECAPSULATE: ++ rv = EVP_PKEY_decapsulate(ctx, out, poutlen, in, inlen); ++ break; ++ + } + return rv; + } + +From 1598da873df55887c2d878549f74b7aaed6d5fde Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Wed, 7 Aug 2024 17:50:51 +0200 +Subject: [PATCH 2/3] Encap/decap in pkeyutl - documentation + +--- + doc/man1/openssl-pkeyutl.pod.in | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in +index 50c2030aa353c..9de50dd6cee8f 100644 +--- a/doc/man1/openssl-pkeyutl.pod.in ++++ b/doc/man1/openssl-pkeyutl.pod.in +@@ -13,6 +13,7 @@ B B + [B<-rawin>] + [B<-digest> I] + [B<-out> I] ++[B<-secret> I] + [B<-sigfile> I] + [B<-inkey> I|I] + [B<-keyform> B|B|B|B] +@@ -28,8 +29,11 @@ B B + [B<-encrypt>] + [B<-decrypt>] + [B<-derive>] ++[B<-encap>] ++[B<-decap>] + [B<-kdf> I] + [B<-kdflen> I] ++[B<-kemop> I] + [B<-pkeyopt> I:I] + [B<-pkeyopt_passin> I[:I]] + [B<-hexdump>] +@@ -79,6 +83,10 @@ then the B<-rawin> option must be also specified. + Specifies the output filename to write to or standard output by + default. + ++=item B<-secret> I ++ ++Specifies the output filename to write the secret to on I<-encap>. ++ + =item B<-sigfile> I + + Signature file, required for B<-verify> operations only +@@ -147,6 +155,31 @@ Decrypt the input data using a private key. + + Derive a shared secret using the peer key. + ++=item B<-encap> ++ ++Encapsulate a generated secret using a private key. ++The encapsulated result (binary data) is written to standard output by default, ++or else to the file specified with I<-out>. ++The I<-secret> option must also be provided to specify the output file for the ++secret value generated in the encapsulation process. ++ ++=item B<-decap> ++ ++Decapsulate the secret using a private key. ++The result (binary data) is written to standard output by default, or else to ++the file specified with I<-out>. ++ ++=item B<-kemop> I ++ ++This option is used for I<-encap>/I<-decap> commands and specifies the KEM ++operation specific for the key algorithm when there is no default KEM ++operation. ++If the algorithm has the default KEM operation, this option can be omitted. ++ ++See L and algorithm-specific KEM documentation e.g. ++L, L, L, and ++L. ++ + =item B<-kdf> I + + Use key derivation function I. The supported algorithms are + +From 1fe7d5b3d96e2ce1e822a4e6e042959af55b0145 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 8 Aug 2024 13:45:19 +0200 +Subject: [PATCH 3/3] Encap/decap in pkeyutl - tests + +--- + test/decap_out.bin | 3 +++ + test/encap_out.bin | 4 ++++ + test/encap_secret.bin | 3 +++ + test/recipes/20-test_pkeyutl.t | 34 ++++++++++++++++++++++++++++++++-- + 4 files changed, 42 insertions(+), 2 deletions(-) + create mode 100644 test/decap_out.bin + create mode 100644 test/encap_out.bin + create mode 100644 test/encap_secret.bin + +diff --git a/test/decap_out.bin b/test/decap_out.bin +new file mode 100644 +index 0000000000000..b94441ed1c002 +--- /dev/null ++++ b/test/decap_out.bin +@@ -0,0 +1,3 @@ ++6Wn;m ĥB[H#Ӈ(h] :\Pxeb)Gf"˭f J) {Hm\P ú+P޸%/jϙ%؆<_~ ++KJEhlEa:(/\Ѯbî -g,AY4 ++ltN)~\HU4y }qJ t# }.T?ϊcD=Lnmv{ſԋȣ +\ No newline at end of file +diff --git a/test/encap_out.bin b/test/encap_out.bin +new file mode 100644 +index 0000000000000..024fc40550f15 +--- /dev/null ++++ b/test/encap_out.bin +@@ -0,0 +1,4 @@ ++:yĐ5[2YM寬3P ++O2rيAd" Gm2m7xh7-@:?NrSꋜK`tɟxi头' Mh3rڃSdOHTF ++kZ'xFKxq"l@04E;ciA}U P6k0%DL.UaO(LIQA ++[uԞ4s$%tB +\ No newline at end of file +diff --git a/test/encap_secret.bin b/test/encap_secret.bin +new file mode 100644 +index 0000000000000..b94441ed1c002 +--- /dev/null ++++ b/test/encap_secret.bin +@@ -0,0 +1,3 @@ ++6Wn;m ĥB[H#Ӈ(h] :\Pxeb)Gf"˭f J) {Hm\P ú+P޸%/jϙ%؆<_~ ++KJEhlEa:(/\Ѯbî -g,AY4 ++ltN)~\HU4y }qJ t# }.T?ϊcD=Lnmv{ſԋȣ +\ No newline at end of file +diff --git a/test/recipes/20-test_pkeyutl.t b/test/recipes/20-test_pkeyutl.t +index 76e4f0a869459..e9472a21352e2 100644 +--- a/test/recipes/20-test_pkeyutl.t ++++ b/test/recipes/20-test_pkeyutl.t +@@ -13,11 +13,11 @@ use File::Spec; + use File::Basename; + use OpenSSL::Test qw/:DEFAULT srctop_file ok_nofips/; + use OpenSSL::Test::Utils; +-use File::Compare qw/compare_text/; ++use File::Compare qw/compare_text compare/; + + setup("test_pkeyutl"); + +-plan tests => 14; ++plan tests => 19; + + # For the tests below we use the cert itself as the TBS file + +@@ -200,3 +200,33 @@ SKIP: { + "-rawin"); + }; + } ++ ++#Encap/decap tests ++# openssl pkeyutl -encap -pubin -inkey rsa_pub.pem -secret secret.bin -out encap_out.bin ++# openssl pkeyutl -decap -inkey rsa_priv.pem -in encap_out.bin -out decap_out.bin ++# decap_out is equal to secret ++SKIP: { ++ skip "RSA is not supported by this OpenSSL build", 3 ++ if disabled("rsa"); ++ ++ # Self-compat ++ ok(run(app(([ 'openssl', 'pkeyutl', '-encap', '-pubin', '-kemop', 'RSASVE', ++ '-inkey', srctop_file('test', 'testrsa2048pub.pem'), ++ '-out', 'encap_out.bin', '-secret', 'secret.bin']))), ++ "RSA pubkey encapsulation"); ++ ok(run(app(([ 'openssl', 'pkeyutl', '-decap', '-kemop', 'RSASVE', ++ '-inkey', srctop_file('test', 'testrsa2048.pem'), ++ '-in', 'encap_out.bin', '-out', 'decap_out.bin']))), ++ "RSA pubkey decapsulation"); ++ is(compare("secret.bin", "decap_out.bin"), 0, "Secret is correctly decapsulated"); ++ ++ # Pregenerated ++ ok(run(app(([ 'openssl', 'pkeyutl', '-decap', '-kemop', 'RSASVE', ++ '-inkey', srctop_file('test', 'testrsa2048.pem'), ++ '-in', srctop_file('test', 'encap_out.bin'), '-out', 'decap_out_etl.bin']))), ++ "RSA pubkey decapsulation - pregenerated"); ++ ++ is(compare(srctop_file('test', 'encap_secret.bin'), "decap_out_etl.bin"), 0, ++ "Secret is correctly decapsulated - pregenerated"); ++} ++ diff --git a/0127-speedup-SSL_add_cert_subjects_to_stack.patch b/0127-speedup-SSL_add_cert_subjects_to_stack.patch new file mode 100644 index 0000000..a6bd503 --- /dev/null +++ b/0127-speedup-SSL_add_cert_subjects_to_stack.patch @@ -0,0 +1,201 @@ +From e2e469593a15681983d16e36d856bf8fb7de8589 Mon Sep 17 00:00:00 2001 +From: Clemens Lang +Date: Wed, 31 Jul 2024 12:45:11 +0200 +Subject: [PATCH] Speed up SSL_add_{file,dir}_cert_subjects_to_stack +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The X509_NAME comparison function converts its arguments to DER using +i2d_X509_NAME before comparing the results using memcmp(). For every +invocation of the comparison function (of which there are many when +loading many certificates), it allocates two buffers of the appropriate +size for the DER encoding. + +Switching to static buffers (possibly of X509_NAME_MAX size as defined +in crypto/x509/x_name.c) would not work with multithreaded use, e.g., +when two threads sort two separate STACK_OF(X509_NAME)s at the same +time. A suitable re-usable buffer could have been added to the +STACK_OF(X509_NAME) if sk_X509_NAME_compfunc did have a void* argument, +or a pointer to the STACK_OF(X509_NAME) – but it does not. + +Instead, copy the solution chosen in SSL_load_client_CA_file() by +filling an LHASH_OF(X509_NAME) with all existing names in the stack and +using that to deduplicate, rather than relying on sk_X509_NAME_find(), +which ends up being very slow. + +Adjust SSL_add_dir_cert_subjects_to_stack() to keep a local +LHASH_OF(X509_NAME)s over the complete directory it is processing. + +In a small benchmark that calls SSL_add_dir_cert_subjects_to_stack() +twice, once on a directory with one entry, and once with a directory +with 1000 certificates, and repeats this in a loop 10 times, this change +yields a speed-up of 5.32: + +| Benchmark 1: ./bench 10 dir-1 dir-1000 +| Time (mean ± σ): 6.685 s ± 0.017 s [User: 6.402 s, System: 0.231 s] +| Range (min … max): 6.658 s … 6.711 s 10 runs +| +| Benchmark 2: LD_LIBRARY_PATH=. ./bench 10 dir-1 dir-1000 +| Time (mean ± σ): 1.256 s ± 0.013 s [User: 1.034 s, System: 0.212 s] +| Range (min … max): 1.244 s … 1.286 s 10 runs +| +| Summary +| LD_LIBRARY_PATH=. ./bench 10 dir-1 dir-1000 ran +| 5.32 ± 0.06 times faster than ./bench 10 dir-1 dir-1000 + +In the worst case scenario where many entries are added to a stack that +is then repeatedly used to add more certificates, and with a larger test +size, the speedup is still very significant. With 15000 certificates, +a single pass to load them, followed by attempting to load a subset of +1000 of these 15000 certificates, followed by a single certificate, the +new approach is ~85 times faster: + +| Benchmark 1: ./bench 1 dir-15000 dir-1000 dir-1 +| Time (mean ± σ): 176.295 s ± 4.147 s [User: 174.593 s, System: 0.448 s] +| Range (min … max): 173.774 s … 185.594 s 10 runs +| +| Benchmark 2: LD_LIBRARY_PATH=. ./bench 1 dir-15000 dir-1000 dir-1 +| Time (mean ± σ): 2.087 s ± 0.034 s [User: 1.679 s, System: 0.393 s] +| Range (min … max): 2.057 s … 2.167 s 10 runs +| +| Summary +| LD_LIBRARY_PATH=. ./bench 1 dir-15000 dir-1000 dir-1 ran +| 84.48 ± 2.42 times faster than ./bench 1 dir-15000 dir-1000 dir-1 + +Signed-off-by: Clemens Lang +--- + ssl/ssl_cert.c | 74 ++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 65 insertions(+), 9 deletions(-) + +diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c +index 0ff407bf55edc..5e5ffe39d0655 100644 +--- a/ssl/ssl_cert.c ++++ b/ssl/ssl_cert.c +@@ -813,16 +813,14 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) + return SSL_load_client_CA_file_ex(file, NULL, NULL); + } + +-int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, +- const char *file) ++static int add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, ++ const char *file, ++ LHASH_OF(X509_NAME) *name_hash) + { + BIO *in; + X509 *x = NULL; + X509_NAME *xn = NULL; + int ret = 1; +- int (*oldcmp) (const X509_NAME *const *a, const X509_NAME *const *b); +- +- oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_sk_cmp); + + in = BIO_new(BIO_s_file()); + +@@ -842,12 +840,15 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + xn = X509_NAME_dup(xn); + if (xn == NULL) + goto err; +- if (sk_X509_NAME_find(stack, xn) >= 0) { ++ if (lh_X509_NAME_retrieve(name_hash, xn) != NULL) { + /* Duplicate. */ + X509_NAME_free(xn); + } else if (!sk_X509_NAME_push(stack, xn)) { + X509_NAME_free(xn); + goto err; ++ } else { ++ /* Successful insert, add to hash table */ ++ lh_X509_NAME_insert(name_hash, xn); + } + } + +@@ -859,7 +860,42 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + done: + BIO_free(in); + X509_free(x); +- (void)sk_X509_NAME_set_cmp_func(stack, oldcmp); ++ return ret; ++} ++ ++int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, ++ const char *file) ++{ ++ X509_NAME *xn = NULL; ++ int ret = 1; ++ int idx = 0; ++ int num = 0; ++ LHASH_OF(X509_NAME) *name_hash = lh_X509_NAME_new(xname_hash, xname_cmp); ++ ++ if (name_hash == NULL) { ++ ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB); ++ goto err; ++ } ++ ++ /* ++ * Pre-populate the lhash with the existing entries of the stack, since ++ * using the LHASH_OF is much faster for duplicate checking. That's because ++ * xname_cmp converts the X509_NAMEs to DER involving a memory allocation ++ * for every single invocation of the comparison function. ++ */ ++ num = sk_X509_NAME_num(stack); ++ for (idx = 0; idx < num; idx++) { ++ xn = sk_X509_NAME_value(stack, idx); ++ lh_X509_NAME_insert(name_hash, xn); ++ } ++ ++ ret = add_file_cert_subjects_to_stack(stack, file, name_hash); ++ goto done; ++ ++ err: ++ ret = 0; ++ done: ++ lh_X509_NAME_free(name_hash); + return ret; + } + +@@ -869,8 +905,27 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + OPENSSL_DIR_CTX *d = NULL; + const char *filename; + int ret = 0; ++ X509_NAME *xn = NULL; ++ int idx = 0; ++ int num = 0; ++ LHASH_OF(X509_NAME) *name_hash = lh_X509_NAME_new(xname_hash, xname_cmp); ++ ++ if (name_hash == NULL) { ++ ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB); ++ goto err; ++ } + +- /* Note that a side effect is that the CAs will be sorted by name */ ++ /* ++ * Pre-populate the lhash with the existing entries of the stack, since ++ * using the LHASH_OF is much faster for duplicate checking. That's because ++ * xname_cmp converts the X509_NAMEs to DER involving a memory allocation ++ * for every single invocation of the comparison function. ++ */ ++ num = sk_X509_NAME_num(stack); ++ for (idx = 0; idx < num; idx++) { ++ xn = sk_X509_NAME_value(stack, idx); ++ lh_X509_NAME_insert(name_hash, xn); ++ } + + while ((filename = OPENSSL_DIR_read(&d, dir))) { + char buf[1024]; +@@ -899,7 +954,7 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + #endif + if (r <= 0 || r >= (int)sizeof(buf)) + goto err; +- if (!SSL_add_file_cert_subjects_to_stack(stack, buf)) ++ if (!add_file_cert_subjects_to_stack(stack, buf, name_hash)) + goto err; + } + +@@ -915,6 +970,7 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + err: + if (d) + OPENSSL_DIR_end(&d); ++ lh_X509_NAME_free(name_hash); + + return ret; + } diff --git a/0128-SAST-findings.patch b/0128-SAST-findings.patch new file mode 100644 index 0000000..77cb8e9 --- /dev/null +++ b/0128-SAST-findings.patch @@ -0,0 +1,24 @@ +diff -up openssl-3.2.2/crypto/rsa/rsa_oaep.c.xxx openssl-3.2.2/crypto/rsa/rsa_oaep.c +--- openssl-3.2.2/crypto/rsa/rsa_oaep.c.xxx 2024-08-14 14:22:48.733407808 +0200 ++++ openssl-3.2.2/crypto/rsa/rsa_oaep.c 2024-08-14 14:23:32.994483135 +0200 +@@ -233,7 +233,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(un + + mdlen = EVP_MD_get_size(md); + +- if (tlen <= 0 || flen <= 0) ++ if (tlen <= 0 || flen <= 0 || mdlen <= 0) + return -1; + /* + * |num| is the length of the modulus; |flen| is the length of the +diff -up openssl-3.2.2/crypto/x509/pcy_tree.c.xxx openssl-3.2.2/crypto/x509/pcy_tree.c +--- openssl-3.2.2/crypto/x509/pcy_tree.c.xxx 2024-08-14 14:14:13.144850097 +0200 ++++ openssl-3.2.2/crypto/x509/pcy_tree.c 2024-08-14 14:14:53.213826481 +0200 +@@ -110,6 +110,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + + *ptree = NULL; + ++ if (n < 0) ++ return X509_PCY_TREE_INTERNAL; + /* Can't do anything with just a trust anchor */ + if (n == 0) + return X509_PCY_TREE_EMPTY; diff --git a/gating.yaml b/gating.yaml index 27a7838..9da38fe 100644 --- a/gating.yaml +++ b/gating.yaml @@ -3,10 +3,10 @@ product_versions: - rhel-10 decision_context: osci_compose_gate rules: - - !PassingTestCaseRule {test_case_name: osci.brew-build./Plan/ci/fips-disabled-tier1.functional} - - !PassingTestCaseRule {test_case_name: osci.brew-build./Plan/ci/fips-disabled-tier2.functional} - - !PassingTestCaseRule {test_case_name: osci.brew-build./Plan/ci/fips-disabled-explicitCI.functional} - - !PassingTestCaseRule {test_case_name: osci.brew-build./Plan/ci/fips-enabled-tier1.functional} - - !PassingTestCaseRule {test_case_name: osci.brew-build./Plan/ci/fips-enabled-tier2.functional} - - !PassingTestCaseRule {test_case_name: osci.brew-build./Plan/ci/fips-enabled-explicitCI.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/ci/fips-disabled-tier1.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/ci/fips-disabled-tier2.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/ci/fips-disabled-explicitCI.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/ci/fips-enabled-tier1.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/ci/fips-enabled-tier2.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/ci/fips-enabled-explicitCI.functional} # - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tedude.validation} \ No newline at end of file diff --git a/openssl.spec b/openssl.spec index 0425717..1ad0b79 100644 --- a/openssl.spec +++ b/openssl.spec @@ -29,7 +29,7 @@ print(string.sub(hash, 0, 16)) Summary: Utilities from the general purpose cryptography library with TLS implementation Name: openssl Version: 3.2.2 -Release: 7%{?dist}.alma.1 +Release: 10%{?dist}.alma.1 Epoch: 1 Source: openssl-%{version}.tar.gz Source2: Makefile.certificate @@ -156,8 +156,19 @@ Patch116: 0116-version-aliasing.patch Patch117: 0117-ignore-unknown-sigalgorithms-groups.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2160797 Patch121: 0121-FIPS-cms-defaults.patch +# skip KTLS tests on infrastructure +Patch122: 0122-TMP-KTLS-test-skip.patch # HKDF regression with older provider implementations -Patch122: 0123-kdf-Preserve-backward-compatibility-with-older-provi.patch +Patch123: 0123-kdf-Preserve-backward-compatibility-with-older-provi.patch +# https://github.com/openssl/openssl/issues/24577 +Patch124: 0124-PBMAC1-PKCS12-FIPS-support.patch +# Downstream patch: enforce PBMAC1 in FIPS mode +Patch125: 0125-PBMAC1-PKCS12-FIPS-default.patch +# https://github.com/openssl/openssl/issues/25127 +Patch126: 0126-pkeyutl-encap.patch +# https://github.com/openssl/openssl/issues/25056 +Patch127: 0127-speedup-SSL_add_cert_subjects_to_stack.patch +Patch128: 0128-SAST-findings.patch License: Apache-2.0 URL: http://www.openssl.org/ @@ -278,7 +289,7 @@ sslflags=enable-ec_nistp_64_gcc_128 sslarch=linux-generic64 %endif #temporarily disable ktls to unblock c10s builds -ktlsopt=disable-ktls +ktlsopt=enable-ktls %ifarch armv7hl ktlsopt=disable-ktls %endif @@ -506,9 +517,31 @@ ln -s /etc/crypto-policies/back-ends/openssl_fips.config $RPM_BUILD_ROOT%{_sysco %ldconfig_scriptlets libs %changelog -* Fri Jul 26 2024 Eduard Abdullin - 1:3.2.2-7.alma.1 +* Mon Sep 02 2024 Eduard Abdullin - 1:3.2.2-10.alma.1 - Redefine sslarch for x86_64_v2 arch +* Wed Aug 14 2024 Dmitry Belyavskiy - 1:3.2.2-10 +- Use PBMAC1 by default when creating PKCS#12 files in FIPS mode + Related: RHEL-36659 +- Support key encapsulation/decapsulation in openssl pkeyutl command + Resolves: RHEL-54156 +- Fix typo in the patch numeration + Related: RHEL-41261 +- Enable KTLS, temporary disable KTLS tests + Related: RHEL-47335 +- Speedup SSL_add_{file,dir}_cert_subjects_to_stack + Resolves: RHEL-54232 +- Resolve SAST package scan results + Resolves: RHEL-37561 + +* Fri Aug 09 2024 Dmitry Belyavskiy - 1:3.2.2-9 +- An interface to create PKCS #12 files in FIPS compliant way + Related: RHEL-36659 + +* Wed Aug 07 2024 Dmitry Belyavskiy - 1:3.2.2-8 +- An interface to create PKCS #12 files in FIPS compliant way + Resolves: RHEL-36659 + * Wed Jul 10 2024 Dmitry Belyavskiy - 1:3.2.2-7 - Disallow SHA1 at SECLEVEL2 in OpenSSL Resolves: RHEL-39962