Commit 90bf314b0b for openssl.org
commit 90bf314b0b5cbd9705e3b1862f633c2679c19e78
Author: Dmitry Belyavskiy <beldmit@gmail.com>
Date: Mon Sep 21 16:50:08 2026 +0200
Provide metadata for symmetric keys when parsing pkcs#12 files
Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
Reviewed-by: Simo Sorce <simo@redhat.com>
MergeDate: Thu Sep 24 07:34:27 2026
(Merged from https://github.com/openssl/openssl/pull/30937)
diff --git a/crypto/pkcs12/p12_kiss.c b/crypto/pkcs12/p12_kiss.c
index 55f2ca2b60..5b7ee063c2 100644
--- a/crypto/pkcs12/p12_kiss.c
+++ b/crypto/pkcs12/p12_kiss.c
@@ -10,6 +10,7 @@
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/pkcs12.h>
+#include <openssl/core_names.h>
#include "crypto/pkcs7/pk7_local.h"
#include "p12_local.h"
#include "crypto/x509.h" /* for ossl_x509_add_cert_new() */
@@ -368,12 +369,33 @@ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen,
return 1;
{
EVP_SKEY *skey;
+ OSSL_PARAM extra[3];
+ int nparams = 0;
+ unsigned char *fname_utf8 = NULL;
+ int fname_utf8_len = 0;
PKCS8_PRIV_KEY_INFO *p8sb = PKCS12_decrypt_secretbag(bag, pass,
passlen, libctx, propq);
+
if (p8sb == NULL)
return 0;
- skey = PKCS8_PRIV_KEY_INFO_get1_skey(p8sb, libctx, propq);
+
+ if (fname) {
+ fname_utf8_len = ASN1_STRING_to_UTF8(&fname_utf8, fname);
+ if (fname_utf8_len >= 0)
+ extra[nparams++] = OSSL_PARAM_construct_utf8_string(
+ OSSL_SKEY_PARAM_ALIAS,
+ (char *)fname_utf8, (size_t)fname_utf8_len);
+ }
+ if (lkid)
+ extra[nparams++] = OSSL_PARAM_construct_octet_string(
+ OSSL_SKEY_PARAM_LOCAL_KEYID,
+ lkid->data, (size_t)lkid->length);
+ extra[nparams] = OSSL_PARAM_construct_end();
+
+ skey = PKCS8_PRIV_KEY_INFO_get1_skey(p8sb, libctx, propq,
+ extra, 1);
PKCS8_PRIV_KEY_INFO_free(p8sb);
+ OPENSSL_free(fname_utf8);
if (skey == NULL) {
ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR);
return 0;
diff --git a/crypto/pkcs12/p12_sbag.c b/crypto/pkcs12/p12_sbag.c
index 40f53a71fa..860553162f 100644
--- a/crypto/pkcs12/p12_sbag.c
+++ b/crypto/pkcs12/p12_sbag.c
@@ -12,6 +12,7 @@
#include <openssl/pkcs12.h>
#include <openssl/core_names.h>
#include <openssl/objects.h>
+#include <openssl/param_build.h>
#include "p12_local.h"
#include "crypto/x509.h"
@@ -150,17 +151,26 @@ X509_CRL *PKCS12_SAFEBAG_get1_crl_ex(const PKCS12_SAFEBAG *bag,
}
EVP_SKEY *PKCS8_PRIV_KEY_INFO_get1_skey(const PKCS8_PRIV_KEY_INFO *p8inf,
- OSSL_LIB_CTX *libctx, const char *propq)
+ OSSL_LIB_CTX *libctx, const char *propq,
+ const OSSL_PARAM *extra_params, int strict)
{
const ASN1_OBJECT *algoid = NULL;
+ const X509_ALGOR *algor = NULL;
const unsigned char *raw_key = NULL;
int raw_key_len = 0;
const char *skey_type = OSSL_SKEY_TYPE_GENERIC;
+ unsigned char *oid_der = NULL;
+ int oid_der_len = 0;
+ unsigned char *params_der = NULL;
+ int params_der_len = 0;
+ OSSL_PARAM_BLD *bld = NULL;
+ OSSL_PARAM *params = NULL;
+ EVP_SKEY *skey = NULL;
if (p8inf == NULL)
return NULL;
- if (!PKCS8_pkey_get0(&algoid, &raw_key, &raw_key_len, NULL, p8inf)
+ if (!PKCS8_pkey_get0(&algoid, &raw_key, &raw_key_len, &algor, p8inf)
|| raw_key == NULL || raw_key_len <= 0)
return NULL;
@@ -198,12 +208,73 @@ EVP_SKEY *PKCS8_PRIV_KEY_INFO_get1_skey(const PKCS8_PRIV_KEY_INFO *p8inf,
skey_type = OSSL_SKEY_TYPE_AES;
break;
default:
+ if (strict != 0)
+ return NULL;
break;
}
}
- return EVP_SKEY_import_raw_key(libctx, skey_type,
- (unsigned char *)raw_key, raw_key_len, propq);
+ bld = OSSL_PARAM_BLD_new();
+ if (bld == NULL)
+ return NULL;
+
+ if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_SKEY_PARAM_RAW_BYTES,
+ raw_key, (size_t)raw_key_len))
+ goto err;
+
+ if (algoid != NULL) {
+ oid_der_len = i2d_ASN1_OBJECT(algoid, &oid_der);
+ if (oid_der_len > 0
+ && !OSSL_PARAM_BLD_push_octet_string(bld,
+ OSSL_SKEY_PARAM_ALGORITHM_OID,
+ oid_der, (size_t)oid_der_len))
+ goto err;
+ }
+
+ if (algor != NULL && algor->parameter != NULL
+ && algor->parameter->type != V_ASN1_UNDEF) {
+ params_der_len = i2d_ASN1_TYPE(algor->parameter, ¶ms_der);
+ if (params_der_len > 0
+ && !OSSL_PARAM_BLD_push_octet_string(bld,
+ OSSL_SKEY_PARAM_ALGORITHM_PARAMS,
+ params_der, (size_t)params_der_len))
+ goto err;
+ }
+
+ if (extra_params != NULL) {
+ const OSSL_PARAM *p;
+
+ for (p = extra_params; p->key != NULL; p++) {
+ switch (p->data_type) {
+ case OSSL_PARAM_UTF8_STRING:
+ if (!OSSL_PARAM_BLD_push_utf8_string(bld,
+ p->key, p->data, p->data_size))
+ goto err;
+ break;
+ case OSSL_PARAM_OCTET_STRING:
+ if (!OSSL_PARAM_BLD_push_octet_string(bld,
+ p->key, p->data, p->data_size))
+ goto err;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ params = OSSL_PARAM_BLD_to_param(bld);
+ if (params == NULL)
+ goto err;
+
+ skey = EVP_SKEY_import(libctx, skey_type, propq,
+ OSSL_SKEYMGMT_SELECT_ALL, params);
+
+err:
+ OSSL_PARAM_BLD_free(bld);
+ OSSL_PARAM_clear_free(params);
+ OPENSSL_free(oid_der);
+ OPENSSL_free(params_der);
+ return skey;
}
PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_cert(X509 *x509)
diff --git a/doc/designs/evp_skey_metadata.md b/doc/designs/evp_skey_metadata.md
index fa8e09470b..59479a15c1 100644
--- a/doc/designs/evp_skey_metadata.md
+++ b/doc/designs/evp_skey_metadata.md
@@ -131,3 +131,79 @@ The implementation is in general provider-dependent. If the corresponding
callback is not implemented for the EVP_SKEYMGMT, 0 is returned. However, as
metadata is completely optional, the success doesn't indicate that the data is
available.
+
+PKCS8_PRIV_KEY_INFO_get1_skey changes
+--------------------------------------
+
+The function gains two new parameters:
+
+```c
+EVP_SKEY *PKCS8_PRIV_KEY_INFO_get1_skey(const PKCS8_PRIV_KEY_INFO *p8inf,
+ OSSL_LIB_CTX *libctx,
+ const char *propq,
+ const OSSL_PARAM *extra_params,
+ int strict);
+```
+
+- **`extra_params`**: caller-built `OSSL_PARAM` array containing metadata
+ from bag attributes (local key ID and friendly name). May be NULL.
+ The function merges these with the params it builds from the PKCS8
+ structure (raw key bytes, algorithm identifier, algorithm parameters).
+
+- **`strict`**: controls how unrecognized algorithm OIDs are handled.
+ The function always attempts to match an algorithm-specific SKEYMGMT
+ based on the AlgorithmIdentifier OID (e.g. `OSSL_SKEY_TYPE_AES` for
+ AES NIDs).
+ - `0` (permissive, default): unrecognized OIDs fall back to
+ `OSSL_SKEY_TYPE_GENERIC`.
+ - non-zero (strict): unrecognized OIDs cause the function to return
+ NULL.
+
+The function now also:
+1. Extracts the full `X509_ALGOR` from the PKCS8 structure (via `PKCS8_pkey_get0`).
+2. DER-encodes the algorithm OID and adds it as
+ `OSSL_SKEY_PARAM_ALGORITHM_OID`.
+3. DER-encodes the algorithm parameters (if present) and adds them as
+ `OSSL_SKEY_PARAM_ALGORITHM_PARAMS`.
+4. Merges with `extra_params` (lkid, fname from caller).
+5. Calls `EVP_SKEY_import()` with the combined parameter set.
+
+Caller changes in p12_kiss.c
+-----------------------------
+
+In the `NID_secretBag` case in `parse_bag()`, the caller builds an
+`OSSL_PARAM` array with the friendly name and local key ID extracted
+from bag attributes, and passes it to `PKCS8_PRIV_KEY_INFO_get1_skey`
+via `extra_params`:
+
+```c
+case NID_secretBag:
+{
+ OSSL_PARAM extra[3];
+ int nparams = 0;
+ unsigned char *fname_utf8 = NULL;
+ int fname_utf8_len = 0;
+
+ if (fname) {
+ fname_utf8_len = ASN1_STRING_to_UTF8(&fname_utf8, fname);
+ if (fname_utf8_len >= 0) {
+ extra[nparams++] = OSSL_PARAM_construct_utf8_string(
+ OSSL_SKEY_PARAM_ALIAS,
+ (char *)fname_utf8, fname_utf8_len);
+ }
+ }
+ if (lkid) {
+ extra[nparams++] = OSSL_PARAM_construct_octet_string(
+ OSSL_SKEY_PARAM_LOCAL_KEYID,
+ lkid->data, lkid->length);
+ }
+ extra[nparams] = OSSL_PARAM_construct_end();
+
+ skey = PKCS8_PRIV_KEY_INFO_get1_skey(p8, ctx, propq, extra, 0);
+ OPENSSL_free(fname_utf8);
+ if (skey == NULL)
+ goto err;
+
+ /* push skey to stack ... */
+}
+```
diff --git a/doc/man3/PKCS12_SAFEBAG_get1_cert.pod b/doc/man3/PKCS12_SAFEBAG_get1_cert.pod
index 97ea4a51ae..d9a8b18557 100644
--- a/doc/man3/PKCS12_SAFEBAG_get1_cert.pod
+++ b/doc/man3/PKCS12_SAFEBAG_get1_cert.pod
@@ -33,7 +33,8 @@ PKCS8_PRIV_KEY_INFO_get1_skey - Get objects from a PKCS#12 safeBag
const X509_SIG *PKCS12_SAFEBAG_get0_pkcs8(const PKCS12_SAFEBAG *bag);
EVP_SKEY *PKCS8_PRIV_KEY_INFO_get1_skey(const PKCS8_PRIV_KEY_INFO *p8inf,
- OSSL_LIB_CTX *libctx, const char *propq);
+ OSSL_LIB_CTX *libctx, const char *propq,
+ const OSSL_PARAM *extra_params, int strict);
=head1 DESCRIPTION
@@ -66,11 +67,21 @@ safeContentsBag.
PKCS8_PRIV_KEY_INFO_get1_skey() converts a decrypted B<PKCS8_PRIV_KEY_INFO> (as
returned by L<PKCS12_decrypt_secretbag(3)>) into an B<EVP_SKEY> symmetric key
-object if it holds a symmetric key inside. The algorithm OID in I<p8inf> is
-used to determine the key type (e.g., AES). If the algorithm OID is not
-recognized by current implementation as matching the known key type, a generic
-symmetric key type will be used. The caller can use L<EVP_SKEY_get0_algorithm(3)>
-to retrieve the original AlgorithmIdentifier.
+object if it holds a symmetric key inside. The algorithm OID and parameters
+from the PKCS8 AlgorithmIdentifier are stored as metadata on the key and can be
+retrieved via L<EVP_SKEY_get0_algorithm_id(3)>.
+
+The I<strict> parameter controls how unrecognized algorithm OIDs are handled.
+In permissive mode (I<strict> is 0), recognized OIDs select an algorithm-specific
+SKEYMGMT (e.g., B<OSSL_SKEY_TYPE_AES> for AES NIDs) and unrecognized OIDs
+fall back to a generic key type.
+In strict mode (I<strict> is nonzero), only recognized OIDs are accepted and
+unrecognized OIDs cause the function to return NULL.
+
+I<extra_params> is an optional caller-built L<OSSL_PARAM(3)> array containing
+additional metadata to attach to the key (e.g., B<OSSL_SKEY_PARAM_ALIAS> for the
+friendly name and B<OSSL_SKEY_PARAM_LOCAL_KEYID> for the local key ID from
+PKCS#12 bag attributes). May be NULL.
=head1 RETURN VALUES
@@ -84,7 +95,7 @@ L<PKCS12_create(3)>,
L<PKCS12_add_safe(3)>,
L<PKCS12_add_safes(3)>,
L<PKCS12_decrypt_secretbag(3)>,
-L<EVP_SKEY_get0_algorithm(3)>
+L<EVP_SKEY_get0_algorithm_id(3)>
=head1 HISTORY
diff --git a/include/openssl/pkcs12.h.in b/include/openssl/pkcs12.h.in
index e966228ea9..1c470f15e0 100644
--- a/include/openssl/pkcs12.h.in
+++ b/include/openssl/pkcs12.h.in
@@ -127,7 +127,8 @@ X509 *PKCS12_SAFEBAG_get1_cert(const PKCS12_SAFEBAG *bag);
X509_CRL *PKCS12_SAFEBAG_get1_crl_ex(const PKCS12_SAFEBAG *bag, OSSL_LIB_CTX *libctx, const char *propq);
X509_CRL *PKCS12_SAFEBAG_get1_crl(const PKCS12_SAFEBAG *bag);
EVP_SKEY *PKCS8_PRIV_KEY_INFO_get1_skey(const PKCS8_PRIV_KEY_INFO *p8inf,
- OSSL_LIB_CTX *libctx, const char *propq);
+ OSSL_LIB_CTX *libctx, const char *propq,
+ const OSSL_PARAM *extra_params, int strict);
const STACK_OF(PKCS12_SAFEBAG) *
PKCS12_SAFEBAG_get0_safes(const PKCS12_SAFEBAG *bag);
const PKCS8_PRIV_KEY_INFO *PKCS12_SAFEBAG_get0_p8inf(const PKCS12_SAFEBAG *bag);