int total; /* number of matching results */
char error_occurred;
char keytype_resolved;
+ OSSL_PROPERTY_LIST *pq;
STACK_OF(EVP_KEYMGMT) *keymgmts;
};
-static void collect_decoder_keymgmt(EVP_KEYMGMT *keymgmt, OSSL_DECODER *decoder,
- void *provctx, struct collect_data_st *data)
+/*
+ * Add decoder instance to the decoder context if it is compatible. Returns 1
+ * if a decoder was added, 0 otherwise.
+ */
+static int collect_decoder_keymgmt(EVP_KEYMGMT *keymgmt, OSSL_DECODER *decoder,
+ void *provctx, struct collect_data_st *data)
{
void *decoderctx = NULL;
OSSL_DECODER_INSTANCE *di = NULL;
+ const OSSL_PROPERTY_LIST *props;
/*
* We already checked the EVP_KEYMGMT is applicable in check_keymgmt so we
if (keymgmt->name_id != decoder->base.id)
/* Mismatch is not an error, continue. */
- return;
+ return 0;
if ((decoderctx = decoder->newctx(provctx)) == NULL) {
data->error_occurred = 1;
- return;
+ return 0;
}
if ((di = ossl_decoder_instance_new(decoder, decoderctx)) == NULL) {
decoder->freectx(decoderctx);
data->error_occurred = 1;
- return;
+ return 0;
}
/*
|| OPENSSL_strcasecmp(data->ctx->start_input_type, "PEM") != 0)) {
/* Mismatch is not an error, continue. */
ossl_decoder_instance_free(di);
- return;
+ return 0;
}
OSSL_TRACE_BEGIN(DECODER) {
OSSL_DECODER_get0_properties(decoder));
} OSSL_TRACE_END(DECODER);
+ /*
+ * Get the property match score so the decoders can be prioritized later.
+ */
+ props = ossl_decoder_parsed_properties(decoder);
+ if (data->pq != NULL && props != NULL) {
+ di->score = ossl_property_match_count(data->pq, props);
+ /*
+ * Mismatch of mandatory properties is not an error, the decoder is just
+ * ignored, continue.
+ */
+ if (di->score < 0) {
+ ossl_decoder_instance_free(di);
+ return 0;
+ }
+ }
+
if (!ossl_decoder_ctx_add_decoder_inst(data->ctx, di)) {
ossl_decoder_instance_free(di);
data->error_occurred = 1;
- return;
+ return 0;
}
++data->total;
+ return 1;
}
static void collect_decoder(OSSL_DECODER *decoder, void *arg)
for (i = 0; i < end_i; ++i) {
keymgmt = sk_EVP_KEYMGMT_value(keymgmts, i);
- collect_decoder_keymgmt(keymgmt, decoder, provctx, data);
+ /* Only add this decoder once */
+ if (collect_decoder_keymgmt(keymgmt, decoder, provctx, data))
+ break;
if (data->error_occurred)
return;
}
struct decoder_pkey_data_st *process_data = NULL;
struct collect_data_st collect_data = { NULL };
STACK_OF(EVP_KEYMGMT) *keymgmts = NULL;
+ OSSL_PROPERTY_LIST **plp;
+ OSSL_PROPERTY_LIST *pq = NULL, *p2 = NULL;
OSSL_TRACE_BEGIN(DECODER) {
const char *input_type = ctx->start_input_type;
process_data->selection = ctx->selection;
process_data->keymgmts = keymgmts;
+ /*
+ * Collect passed and default properties to prioritize the decoders.
+ */
+ if (propquery != NULL)
+ p2 = pq = ossl_parse_query(libctx, propquery, 1);
+
+ plp = ossl_ctx_global_properties(libctx, 0);
+ if (plp != NULL && *plp != NULL) {
+ if (pq == NULL) {
+ pq = *plp;
+ } else {
+ p2 = ossl_property_merge(pq, *plp);
+ ossl_property_free(pq);
+ if (p2 == NULL)
+ goto err;
+ pq = p2;
+ }
+ }
+
/*
* Enumerate all keymgmts into a stack.
*
* upfront, as this ensures that the names for all loaded providers have
* been registered by the time we try to resolve the keytype string.
*/
- collect_data.ctx = ctx;
- collect_data.libctx = libctx;
- collect_data.keymgmts = keymgmts;
- collect_data.keytype = keytype;
+ collect_data.ctx = ctx;
+ collect_data.libctx = libctx;
+ collect_data.keymgmts = keymgmts;
+ collect_data.keytype = keytype;
+ collect_data.pq = pq;
EVP_KEYMGMT_do_all_provided(libctx, collect_keymgmt, &collect_data);
if (collect_data.error_occurred)
ok = 1;
err:
decoder_clean_pkey_construct_arg(process_data);
+ ossl_property_free(p2);
return ok;
}
/*
- * Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2021-2025 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.
*/
#include <string.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
#include <openssl/core_names.h>
#include <openssl/core_object.h>
#include <openssl/rand.h>
#include <openssl/provider.h>
#include "testutil.h"
#include "fake_rsaprov.h"
+#include "internal/asn1.h"
static OSSL_FUNC_keymgmt_new_fn fake_rsa_keymgmt_new;
static OSSL_FUNC_keymgmt_free_fn fake_rsa_keymgmt_free;
static int query_id;
static int key_deleted;
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+} PROV_FAKE_RSA_CTX;
+
+#define PROV_FAKE_RSA_LIBCTX_OF(provctx) (((PROV_FAKE_RSA_CTX *)provctx)->libctx)
+
+#define FAKE_RSA_STATUS_IMPORTED 1
+#define FAKE_RSA_STATUS_GENERATED 2
+#define FAKE_RSA_STATUS_DECODED 3
+
struct fake_rsa_keydata {
int selection;
int status;
struct fake_rsa_keydata *fake_rsa_key = keydata;
/* key was imported */
- fake_rsa_key->status = 1;
+ fake_rsa_key->status = FAKE_RSA_STATUS_IMPORTED;
return 1;
}
{
struct fake_rsa_keydata *key = NULL;
- if (reference_sz != sizeof(*key))
+ if (reference_sz != sizeof(key))
return NULL;
key = *(struct fake_rsa_keydata **)reference;
- if (key->status != 1)
+ if (key->status != FAKE_RSA_STATUS_IMPORTED && key->status != FAKE_RSA_STATUS_DECODED)
return NULL;
/* detach the reference */
if (!TEST_ptr(keydata = fake_rsa_keymgmt_new(NULL)))
return NULL;
- keydata->status = 2;
+ keydata->status = FAKE_RSA_STATUS_GENERATED;
return keydata;
}
/* The address of the key becomes the octet string */
params[2] =
OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,
- &key, sizeof(*key));
+ &key, sizeof(key));
params[3] = OSSL_PARAM_construct_end();
rv = object_cb(params, object_cbarg);
*storectx = 1;
{ NULL, NULL, NULL }
};
+struct der2key_ctx_st; /* Forward declaration */
+typedef int check_key_fn(void *, struct der2key_ctx_st *ctx);
+typedef void adjust_key_fn(void *, struct der2key_ctx_st *ctx);
+typedef void free_key_fn(void *);
+typedef void *d2i_PKCS8_fn(void **, const unsigned char **, long,
+ struct der2key_ctx_st *);
+struct keytype_desc_st {
+ const char *keytype_name;
+ const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */
+
+ /* The input structure name */
+ const char *structure_name;
+
+ /*
+ * The EVP_PKEY_xxx type macro. Should be zero for type specific
+ * structures, non-zero when the outermost structure is PKCS#8 or
+ * SubjectPublicKeyInfo. This determines which of the function
+ * pointers below will be used.
+ */
+ int evp_type;
+
+ /* The selection mask for OSSL_FUNC_decoder_does_selection() */
+ int selection_mask;
+
+ /* For type specific decoders, we use the corresponding d2i */
+ d2i_of_void *d2i_private_key; /* From type-specific DER */
+ d2i_of_void *d2i_public_key; /* From type-specific DER */
+ d2i_of_void *d2i_key_params; /* From type-specific DER */
+ d2i_PKCS8_fn *d2i_PKCS8; /* Wrapped in a PrivateKeyInfo */
+ d2i_of_void *d2i_PUBKEY; /* Wrapped in a SubjectPublicKeyInfo */
+
+ /*
+ * For any key, we may need to check that the key meets expectations.
+ * This is useful when the same functions can decode several variants
+ * of a key.
+ */
+ check_key_fn *check_key;
+
+ /*
+ * For any key, we may need to make provider specific adjustments, such
+ * as ensure the key carries the correct library context.
+ */
+ adjust_key_fn *adjust_key;
+ /* {type}_free() */
+ free_key_fn *free_key;
+};
+
+/*
+ * Start blatant code steal. Alternative: Open up d2i_X509_PUBKEY_INTERNAL
+ * as per https://github.com/openssl/openssl/issues/16697 (TBD)
+ * Code from openssl/crypto/x509/x_pubkey.c as
+ * ossl_d2i_X509_PUBKEY_INTERNAL is presently not public
+ */
+struct X509_pubkey_st {
+ X509_ALGOR *algor;
+ ASN1_BIT_STRING *public_key;
+
+ EVP_PKEY *pkey;
+
+ /* extra data for the callback, used by d2i_PUBKEY_ex */
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+};
+
+ASN1_SEQUENCE(X509_PUBKEY_INTERNAL) = {
+ ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR),
+ ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING)
+} static_ASN1_SEQUENCE_END_name(X509_PUBKEY, X509_PUBKEY_INTERNAL)
+
+static X509_PUBKEY *fake_rsa_d2i_X509_PUBKEY_INTERNAL(const unsigned char **pp,
+ long len, OSSL_LIB_CTX *libctx)
+{
+ X509_PUBKEY *xpub = OPENSSL_zalloc(sizeof(*xpub));
+
+ if (xpub == NULL)
+ return NULL;
+ return (X509_PUBKEY *)ASN1_item_d2i_ex((ASN1_VALUE **)&xpub, pp, len,
+ ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL),
+ libctx, NULL);
+}
+/* end steal https://github.com/openssl/openssl/issues/16697 */
+
+/*
+ * Context used for DER to key decoding.
+ */
+struct der2key_ctx_st {
+ PROV_FAKE_RSA_CTX *provctx;
+ struct keytype_desc_st *desc;
+ /* The selection that is passed to fake_rsa_der2key_decode() */
+ int selection;
+ /* Flag used to signal that a failure is fatal */
+ unsigned int flag_fatal : 1;
+};
+
+static int fake_rsa_read_der(PROV_FAKE_RSA_CTX *provctx, OSSL_CORE_BIO *cin,
+ unsigned char **data, long *len)
+{
+ BUF_MEM *mem = NULL;
+ BIO *in = BIO_new_from_core_bio(provctx->libctx, cin);
+ int ok = (asn1_d2i_read_bio(in, &mem) >= 0);
+
+ if (ok) {
+ *data = (unsigned char *)mem->data;
+ *len = (long)mem->length;
+ OPENSSL_free(mem);
+ }
+ BIO_free(in);
+ return ok;
+}
+
+typedef void *key_from_pkcs8_t(const PKCS8_PRIV_KEY_INFO *p8inf,
+ OSSL_LIB_CTX *libctx, const char *propq);
+static void *fake_rsa_der2key_decode_p8(const unsigned char **input_der,
+ long input_der_len, struct der2key_ctx_st *ctx,
+ key_from_pkcs8_t *key_from_pkcs8)
+{
+ PKCS8_PRIV_KEY_INFO *p8inf = NULL;
+ const X509_ALGOR *alg = NULL;
+ void *key = NULL;
+
+ if ((p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, input_der, input_der_len)) != NULL
+ && PKCS8_pkey_get0(NULL, NULL, NULL, &alg, p8inf)
+ && OBJ_obj2nid(alg->algorithm) == ctx->desc->evp_type)
+ key = key_from_pkcs8(p8inf, PROV_FAKE_RSA_LIBCTX_OF(ctx->provctx), NULL);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+
+ return key;
+}
+
+static struct fake_rsa_keydata *fake_rsa_d2i_PUBKEY(struct fake_rsa_keydata **a,
+ const unsigned char **pp, long length)
+{
+ struct fake_rsa_keydata *key = NULL;
+ X509_PUBKEY *xpk;
+
+ xpk = fake_rsa_d2i_X509_PUBKEY_INTERNAL(pp, length, NULL);
+ if (xpk == NULL)
+ goto err_exit;
+
+ key = fake_rsa_keymgmt_new(NULL);
+ if (key == NULL)
+ goto err_exit;
+
+ key->status = FAKE_RSA_STATUS_DECODED;
+
+ if (a != NULL) {
+ fake_rsa_keymgmt_free(*a);
+ *a = key;
+ }
+
+err_exit:
+ X509_PUBKEY_free(xpk);
+ return key;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static OSSL_FUNC_decoder_freectx_fn der2key_freectx;
+static OSSL_FUNC_decoder_decode_fn fake_rsa_der2key_decode;
+static OSSL_FUNC_decoder_export_object_fn der2key_export_object;
+
+static struct der2key_ctx_st *
+der2key_newctx(void *provctx, struct keytype_desc_st *desc, const char *tls_name)
+{
+ struct der2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL) {
+ ctx->provctx = provctx;
+ ctx->desc = desc;
+ if (desc->evp_type == 0)
+ ctx->desc->evp_type = OBJ_sn2nid(tls_name);
+ }
+ return ctx;
+}
+
+static void der2key_freectx(void *vctx)
+{
+ struct der2key_ctx_st *ctx = vctx;
+
+ OPENSSL_free(ctx);
+}
+
+static int der2key_check_selection(int selection,
+ const struct keytype_desc_st *desc)
+{
+ /*
+ * The selections are kinda sorta "levels", i.e. each selection given
+ * here is assumed to include those following.
+ */
+ int checks[] = {
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
+ OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
+ };
+ size_t i;
+
+ /* The decoder implementations made here support guessing */
+ if (selection == 0)
+ return 1;
+
+ for (i = 0; i < OSSL_NELEM(checks); i++) {
+ int check1 = (selection & checks[i]) != 0;
+ int check2 = (desc->selection_mask & checks[i]) != 0;
+
+ /*
+ * If the caller asked for the currently checked bit(s), return
+ * whether the decoder description says it's supported.
+ */
+ if (check1)
+ return check2;
+ }
+
+ /* This should be dead code, but just to be safe... */
+ return 0;
+}
+
+static int fake_rsa_der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
+ OSSL_CALLBACK *data_cb, void *data_cbarg,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+ struct der2key_ctx_st *ctx = vctx;
+ unsigned char *der = NULL;
+ const unsigned char *derp;
+ long der_len = 0;
+ void *key = NULL;
+ int ok = 0;
+
+ ctx->selection = selection;
+ /*
+ * The caller is allowed to specify 0 as a selection mark, to have the
+ * structure and key type guessed. For type-specific structures, this
+ * is not recommended, as some structures are very similar.
+ * Note that 0 isn't the same as OSSL_KEYMGMT_SELECT_ALL, as the latter
+ * signifies a private key structure, where everything else is assumed
+ * to be present as well.
+ */
+ if (selection == 0)
+ selection = ctx->desc->selection_mask;
+ if ((selection & ctx->desc->selection_mask) == 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ ok = fake_rsa_read_der(ctx->provctx, cin, &der, &der_len);
+ if (!ok)
+ goto next;
+
+ ok = 0; /* Assume that we fail */
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+ derp = der;
+ if (ctx->desc->d2i_PKCS8 != NULL) {
+ key = ctx->desc->d2i_PKCS8(NULL, &derp, der_len, ctx);
+ if (ctx->flag_fatal)
+ goto end;
+ } else if (ctx->desc->d2i_private_key != NULL) {
+ key = ctx->desc->d2i_private_key(NULL, &derp, der_len);
+ }
+ if (key == NULL && ctx->selection != 0)
+ goto next;
+ }
+ if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+ derp = der;
+ if (ctx->desc->d2i_PUBKEY != NULL)
+ key = ctx->desc->d2i_PUBKEY(NULL, &derp, der_len);
+ else
+ key = ctx->desc->d2i_public_key(NULL, &derp, der_len);
+ if (key == NULL && ctx->selection != 0)
+ goto next;
+ }
+ if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) {
+ derp = der;
+ if (ctx->desc->d2i_key_params != NULL)
+ key = ctx->desc->d2i_key_params(NULL, &derp, der_len);
+ if (key == NULL && ctx->selection != 0)
+ goto next;
+ }
+
+ /*
+ * Last minute check to see if this was the correct type of key. This
+ * should never lead to a fatal error, i.e. the decoding itself was
+ * correct, it was just an unexpected key type. This is generally for
+ * classes of key types that have subtle variants, like RSA-PSS keys as
+ * opposed to plain RSA keys.
+ */
+ if (key != NULL
+ && ctx->desc->check_key != NULL
+ && !ctx->desc->check_key(key, ctx)) {
+ ctx->desc->free_key(key);
+ key = NULL;
+ }
+
+ if (key != NULL && ctx->desc->adjust_key != NULL)
+ ctx->desc->adjust_key(key, ctx);
+
+ next:
+ /*
+ * Indicated that we successfully decoded something, or not at all.
+ * Ending up "empty handed" is not an error.
+ */
+ ok = 1;
+
+ /*
+ * We free memory here so it's not held up during the callback, because
+ * we know the process is recursive and the allocated chunks of memory
+ * add up.
+ */
+ OPENSSL_free(der);
+ der = NULL;
+
+ if (key != NULL) {
+ OSSL_PARAM params[4];
+ int object_type = OSSL_OBJECT_PKEY;
+
+ params[0] =
+ OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type);
+ params[1] =
+ OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
+ (char *)ctx->desc->keytype_name,
+ 0);
+ /* The address of the key becomes the octet string */
+ params[2] =
+ OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,
+ &key, sizeof(key));
+ params[3] = OSSL_PARAM_construct_end();
+
+ ok = data_cb(params, data_cbarg);
+ }
+
+ end:
+ ctx->desc->free_key(key);
+ OPENSSL_free(der);
+
+ return ok;
+}
+
+static OSSL_FUNC_keymgmt_export_fn *
+fake_rsa_prov_get_keymgmt_export(const OSSL_DISPATCH *fns)
+{
+ /* Pilfer the keymgmt dispatch table */
+ for (; fns->function_id != 0; fns++)
+ if (fns->function_id == OSSL_FUNC_KEYMGMT_EXPORT)
+ return OSSL_FUNC_keymgmt_export(fns);
+
+ return NULL;
+}
+
+static int der2key_export_object(void *vctx,
+ const void *reference, size_t reference_sz,
+ OSSL_CALLBACK *export_cb, void *export_cbarg)
+{
+ struct der2key_ctx_st *ctx = vctx;
+ OSSL_FUNC_keymgmt_export_fn *export = fake_rsa_prov_get_keymgmt_export(ctx->desc->fns);
+ void *keydata;
+
+ if (reference_sz == sizeof(keydata) && export != NULL) {
+ /* The contents of the reference is the address to our object */
+ keydata = *(void **)reference;
+
+ return export(keydata, ctx->selection, export_cb, export_cbarg);
+ }
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct fake_rsa_keydata *fake_rsa_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf,
+ OSSL_LIB_CTX *libctx, const char *propq)
+{
+ struct fake_rsa_keydata *key = fake_rsa_keymgmt_new(NULL);
+
+ if (key)
+ key->status = FAKE_RSA_STATUS_DECODED;
+ return key;
+}
+
+#define rsa_evp_type EVP_PKEY_RSA
+
+static void *fake_rsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
+ struct der2key_ctx_st *ctx)
+{
+ return fake_rsa_der2key_decode_p8(der, der_len, ctx,
+ (key_from_pkcs8_t *)fake_rsa_key_from_pkcs8);
+}
+
+static void fake_rsa_key_adjust(void *key, struct der2key_ctx_st *ctx)
+{
+}
+
+/* ---------------------------------------------------------------------- */
+
+#define DO_PrivateKeyInfo(keytype) \
+ "PrivateKeyInfo", keytype##_evp_type, \
+ (OSSL_KEYMGMT_SELECT_PRIVATE_KEY), \
+ NULL, \
+ NULL, \
+ NULL, \
+ fake_rsa_d2i_PKCS8, \
+ NULL, \
+ NULL, \
+ fake_rsa_key_adjust, \
+ (free_key_fn *)fake_rsa_keymgmt_free
+
+#define DO_SubjectPublicKeyInfo(keytype) \
+ "SubjectPublicKeyInfo", keytype##_evp_type, \
+ (OSSL_KEYMGMT_SELECT_PUBLIC_KEY), \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ (d2i_of_void *)fake_rsa_d2i_PUBKEY, \
+ NULL, \
+ fake_rsa_key_adjust, \
+ (free_key_fn *)fake_rsa_keymgmt_free
+
+/*
+ * MAKE_DECODER is the single driver for creating OSSL_DISPATCH tables.
+ * It takes the following arguments:
+ *
+ * keytype_name The implementation key type as a string.
+ * keytype The implementation key type. This must correspond exactly
+ * to our existing keymgmt keytype names... in other words,
+ * there must exist an ossl_##keytype##_keymgmt_functions.
+ * type The type name for the set of functions that implement the
+ * decoder for the key type. This isn't necessarily the same
+ * as keytype. For example, the key types ed25519, ed448,
+ * x25519 and x448 are all handled by the same functions with
+ * the common type name ecx.
+ * kind The kind of support to implement. This translates into
+ * the DO_##kind macros above, to populate the keytype_desc_st
+ * structure.
+ */
+#define MAKE_DECODER(keytype_name, keytype, type, kind) \
+ static struct keytype_desc_st kind##_##keytype##_desc = \
+ { keytype_name, fake_rsa_keymgmt_funcs, \
+ DO_##kind(keytype) }; \
+ \
+ static OSSL_FUNC_decoder_newctx_fn kind##_der2##keytype##_newctx; \
+ \
+ static void *kind##_der2##keytype##_newctx(void *provctx) \
+ { \
+ return der2key_newctx(provctx, &kind##_##keytype##_desc, keytype_name);\
+ } \
+ static int kind##_der2##keytype##_does_selection(void *provctx, \
+ int selection) \
+ { \
+ return der2key_check_selection(selection, \
+ &kind##_##keytype##_desc); \
+ } \
+ static const OSSL_DISPATCH \
+ fake_rsa_##kind##_der_to_##keytype##_decoder_functions[] = { \
+ { OSSL_FUNC_DECODER_NEWCTX, \
+ (void (*)(void))kind##_der2##keytype##_newctx }, \
+ { OSSL_FUNC_DECODER_FREECTX, \
+ (void (*)(void))der2key_freectx }, \
+ { OSSL_FUNC_DECODER_DOES_SELECTION, \
+ (void (*)(void))kind##_der2##keytype##_does_selection }, \
+ { OSSL_FUNC_DECODER_DECODE, \
+ (void (*)(void))fake_rsa_der2key_decode }, \
+ { OSSL_FUNC_DECODER_EXPORT_OBJECT, \
+ (void (*)(void))der2key_export_object }, \
+ OSSL_DISPATCH_END \
+ }
+
+MAKE_DECODER("RSA", rsa, rsa, PrivateKeyInfo);
+MAKE_DECODER("RSA", rsa, rsa, SubjectPublicKeyInfo);
+
+static const OSSL_ALGORITHM fake_rsa_decoder_algs[] = {
+#define DECODER_PROVIDER "fake-rsa"
+#define DECODER_STRUCTURE_SubjectPublicKeyInfo "SubjectPublicKeyInfo"
+#define DECODER_STRUCTURE_PrivateKeyInfo "PrivateKeyInfo"
+
+/* Arguments are prefixed with '_' to avoid build breaks on certain platforms */
+/*
+ * Obviously this is not FIPS approved, but in order to test in conjunction
+ * with the FIPS provider we pretend that it is.
+ */
+
+#define DECODER(_name, _input, _output) \
+ { _name, \
+ "provider=" DECODER_PROVIDER ",fips=yes,input=" #_input, \
+ (fake_rsa_##_input##_to_##_output##_decoder_functions) \
+ }
+#define DECODER_w_structure(_name, _input, _structure, _output) \
+ { _name, \
+ "provider=" DECODER_PROVIDER ",fips=yes,input=" #_input \
+ ",structure=" DECODER_STRUCTURE_##_structure, \
+ (fake_rsa_##_structure##_##_input##_to_##_output##_decoder_functions) \
+ }
+
+DECODER_w_structure("RSA:rsaEncryption", der, PrivateKeyInfo, rsa),
+DECODER_w_structure("RSA:rsaEncryption", der, SubjectPublicKeyInfo, rsa),
+#undef DECODER_PROVIDER
+ { NULL, NULL, NULL }
+};
+
static const OSSL_ALGORITHM *fake_rsa_query(void *provctx,
int operation_id,
int *no_cache)
case OSSL_OP_STORE:
return fake_rsa_store_algs;
+
+ case OSSL_OP_DECODER:
+ return fake_rsa_decoder_algs;
}
return NULL;
}
+static void fake_rsa_prov_teardown(void *provctx)
+{
+ PROV_FAKE_RSA_CTX *pctx = (PROV_FAKE_RSA_CTX *)provctx;
+
+ OSSL_LIB_CTX_free(pctx->libctx);
+ OPENSSL_free(pctx);
+}
+
/* Functions we provide to the core */
static const OSSL_DISPATCH fake_rsa_method[] = {
- { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))OSSL_LIB_CTX_free },
+ { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))fake_rsa_prov_teardown },
{ OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))fake_rsa_query },
OSSL_DISPATCH_END
};
const OSSL_DISPATCH *in,
const OSSL_DISPATCH **out, void **provctx)
{
- if (!TEST_ptr(*provctx = OSSL_LIB_CTX_new()))
+ OSSL_LIB_CTX *libctx;
+ PROV_FAKE_RSA_CTX *prov_ctx;
+
+ if (!TEST_ptr(libctx = OSSL_LIB_CTX_new_from_dispatch(handle, in)))
+ return 0;
+
+ if (!TEST_ptr(prov_ctx = OPENSSL_malloc(sizeof(*prov_ctx)))) {
+ OSSL_LIB_CTX_free(libctx);
return 0;
+ }
+
+ prov_ctx->libctx = libctx;
+
+ *provctx = prov_ctx;
*out = fake_rsa_method;
return 1;
}
/*
- * Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2021-2025 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
return ret;
}
+#define DEFAULT_PROVIDER_IDX 0
+#define FAKE_RSA_PROVIDER_IDX 1
+
+static int reset_ctx_providers(OSSL_LIB_CTX **ctx, OSSL_PROVIDER *providers[2], const char *prop)
+{
+ OSSL_PROVIDER_unload(providers[DEFAULT_PROVIDER_IDX]);
+ providers[DEFAULT_PROVIDER_IDX] = NULL;
+ fake_rsa_finish(providers[FAKE_RSA_PROVIDER_IDX]);
+ providers[FAKE_RSA_PROVIDER_IDX] = NULL;
+ OSSL_LIB_CTX_free(*ctx);
+ *ctx = NULL;
+
+ if (!TEST_ptr(*ctx = OSSL_LIB_CTX_new())
+ || !TEST_ptr(providers[DEFAULT_PROVIDER_IDX] = OSSL_PROVIDER_load(*ctx, "default"))
+ || !TEST_ptr(providers[FAKE_RSA_PROVIDER_IDX] = fake_rsa_start(*ctx))
+ || !TEST_true(EVP_set_default_properties(*ctx, prop)))
+ return 0;
+ return 1;
+}
+
+struct test_pkey_decoder_properties_t {
+ const char *provider_props;
+ const char *explicit_props;
+ int curr_provider_idx;
+};
+
+static int test_pkey_provider_decoder_props(void)
+{
+ OSSL_LIB_CTX *my_libctx = NULL;
+ OSSL_PROVIDER *providers[2] = { NULL };
+ struct test_pkey_decoder_properties_t properties_test[] = {
+ { "?provider=fake-rsa", NULL, FAKE_RSA_PROVIDER_IDX },
+ { "?provider=default", NULL, DEFAULT_PROVIDER_IDX },
+ { NULL, "?provider=fake-rsa", FAKE_RSA_PROVIDER_IDX },
+ { NULL, "?provider=default", DEFAULT_PROVIDER_IDX },
+ { NULL, "provider=fake-rsa", FAKE_RSA_PROVIDER_IDX },
+ { NULL, "provider=default", DEFAULT_PROVIDER_IDX },
+ };
+ EVP_PKEY *pkey = NULL;
+ BIO *bio_priv = NULL;
+ unsigned char *encoded_pub = NULL;
+ int len_pub;
+ const unsigned char *p;
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
+ size_t i;
+ int ret = 0;
+ const char pem_rsa_priv_key[] =
+ "-----BEGIN PRIVATE KEY-----\n"
+ "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEkC4ZWv3ucFbU\n"
+ "F8YwlUrmQlLCZwAgr4DPUAFVHl+wFcXypVgScVY4K7QmdWKsYqb8tpOxqw0NwZWX\n"
+ "O+ta4+y27COufoOhRTMwNyN2LwSNTPN3eEk4ee5QnppEyDrqoCgvTlAAdToFaXvj\n"
+ "x13Ybj7jfhwN74qKdqsSEtPWyggeotiQSPy6KyBIuWtIxPAA8jAvfAnQj1eXhghF\n"
+ "N2NxkqgxvBYdNy1m3+jXACPLRzc11ZbNHKiwhCY1/HiSBkwHlIK+/VLj2smCKdUQ\n"
+ "gvLXSnnVgQulHioD6UgY8xA2a4M1rhYuTV8BrPRZ4BFx2o0jYWvGbA/Hlp7fTOy+\n"
+ "F5OkiHS7AgMBAAECggEAYgCu81ZiQBVDvWiDGKr+1pIf2CxprGJEm1h86ZcEx3L7\n"
+ "qFDW+g8HGWd04S3qvh9LublAJzetAPxRXL9zx3PXjJZs7e3HLEuny3TaWez0XI0O\n"
+ "4LSY8S8d6pVBPmUEtwGWN4vYqHnKLXOb4QQAXs4MzfkM/Me/b+zdu1umwjMl3Dud\n"
+ "5rVhkgvt8uhDUG3XSHeoJYBMbT9ikJDVMJ51rre/1Riddgxp8SktVkvGmMl9kQR8\n"
+ "8dv3Px/kTN94EuRg0CkXBhHpoGo4qnM3Q3B5PlmSK5gkuPvWy9l8L/TVt8Lb6/zL\n"
+ "ByQW+g02wxeNGhw1fkD+XFH7KkSeWl+QnrLcePM0hQKBgQDxoqUk0PLOY5WgOkgr\n"
+ "umgie/K1WKs+izTtApjzcM76sza63b5R9w+P+NssMV4aeV9epEGZO68IUmi0QjvQ\n"
+ "npluQoadFYweFwSQ11BXHoeQBA4nNpkrV58hgzZN3m9JLR7JxyrIqXsRnUzl13Kj\n"
+ "GzZBCJxCpJjfTze/yme8d3pa5QKBgQDQP5mB4jI+g3XH3MuLyBjMoTIvoy7CYMhZ\n"
+ "6/+Kkpw132J16mqkLrwUOZfT0e1rJBsCUkEoBmgKNtRkHo3/SjUI/9fHj3uStPHV\n"
+ "oPcfXj/gFRUkDDzY+auB3dHONF1U1z06EANkkPCC3a538UANBIaPjwpRdBzNw1xl\n"
+ "bvn5aCt3HwKBgBfOl4jGEXYmN6K+u0ebqRDkt2gIoW6bFo7Xd6xci/gFWjoVCOBY\n"
+ "gC8GLMnw3z2qgav4cQIg8EDYpbpE4FHQnntPkKW/bru0Nt3yaNb8igy1aZORfIvZ\n"
+ "qTMLE3melcZW7LaiqeN1V0vH/MCUdpX9Y14K9CJYxzsROgPqdEgMWYDFAoGAAe9l\n"
+ "XMieUOhl0sqhdZYRbO1eiwTILXQ6yGMiB8ae/v0pbBEWlpn8k2+JkqVTwHggbCAZ\n"
+ "jOaqVtX1mUyTYzjsTz4ZYjhaHJ3j1WlegoMcstdfT+txMU74ogdOqMzhxSUO45g8\n"
+ "f9W89mpa8bBjOPu+yFy66tDaZ6sWE7c5SXEHXl8CgYEAtAWwFPoDSTdzoXAwRof0\n"
+ "QMO08+PnQGoPbMJTqrgxrHYCS8u4cYSHdDMJDCOMo5gFXyC+5FfTiGwBhy58z5b7\n"
+ "gBwFKI9RgRfV1D/NimxPrlj3WHyec1/Cs+Br+/vekMVFg5gekeHr4aGSF4bk0AjV\n"
+ "Tv/pQjyRuZAt66IbRZdl2II=\n"
+ "-----END PRIVATE KEY-----";
+
+ /* Load private key BIO, DER-encoded public key and PKCS#8 private key for testing */
+ if (!TEST_ptr(bio_priv = BIO_new(BIO_s_mem()))
+ || !TEST_int_gt(BIO_write(bio_priv, pem_rsa_priv_key, sizeof(pem_rsa_priv_key)), 0)
+ || !TEST_ptr(pkey = PEM_read_bio_PrivateKey_ex(bio_priv, NULL, NULL, NULL, NULL, NULL))
+ || !TEST_int_ge(BIO_seek(bio_priv, 0), 0)
+ || !TEST_int_gt((len_pub = i2d_PUBKEY(pkey, &encoded_pub)), 0)
+ || !TEST_ptr(p8 = EVP_PKEY2PKCS8(pkey)))
+ goto end;
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+
+ for (i = 0; i < OSSL_NELEM(properties_test); i++) {
+ const char *libctx_prop = properties_test[i].provider_props;
+ const char *explicit_prop = properties_test[i].explicit_props;
+ /* *curr_provider will be updated in reset_ctx_providers */
+ OSSL_PROVIDER **curr_provider = &providers[properties_test[i].curr_provider_idx];
+
+ /*
+ * Decoding a PEM-encoded key uses the properties to select the right provider.
+ * Using a PEM-encoding adds an extra decoder before the key is created.
+ */
+ if (!TEST_int_eq(reset_ctx_providers(&my_libctx, providers, libctx_prop), 1))
+ goto end;
+ if (!TEST_int_ge(BIO_seek(bio_priv, 0), 0)
+ || !TEST_ptr(pkey = PEM_read_bio_PrivateKey_ex(bio_priv, NULL, NULL, NULL, my_libctx,
+ explicit_prop))
+ || !TEST_ptr_eq(EVP_PKEY_get0_provider(pkey), *curr_provider))
+ goto end;
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+
+ /* Decoding a DER-encoded X509_PUBKEY uses the properties to select the right provider */
+ if (!TEST_int_eq(reset_ctx_providers(&my_libctx, providers, libctx_prop), 1))
+ goto end;
+ p = encoded_pub;
+ if (!TEST_ptr(pkey = d2i_PUBKEY_ex(NULL, &p, len_pub, my_libctx, explicit_prop))
+ || !TEST_ptr_eq(EVP_PKEY_get0_provider(pkey), *curr_provider))
+ goto end;
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+
+ /* Decoding a PKCS8_PRIV_KEY_INFO uses the properties to select the right provider */
+ if (!TEST_int_eq(reset_ctx_providers(&my_libctx, providers, libctx_prop), 1))
+ goto end;
+ if (!TEST_ptr(pkey = EVP_PKCS82PKEY_ex(p8, my_libctx, explicit_prop))
+ || !TEST_ptr_eq(EVP_PKEY_get0_provider(pkey), *curr_provider))
+ goto end;
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+
+ ret = 1;
+
+end:
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ BIO_free(bio_priv);
+ OPENSSL_free(encoded_pub);
+ EVP_PKEY_free(pkey);
+ OSSL_PROVIDER_unload(providers[DEFAULT_PROVIDER_IDX]);
+ fake_rsa_finish(providers[FAKE_RSA_PROVIDER_IDX]);
+ OSSL_LIB_CTX_free(my_libctx);
+ return ret;
+}
+
int setup_tests(void)
{
libctx = OSSL_LIB_CTX_new();
ADD_ALL_TESTS(test_pkey_store, 2);
ADD_TEST(test_pkey_delete);
ADD_TEST(test_pkey_store_open_ex);
+ ADD_TEST(test_pkey_provider_decoder_props);
return 1;
}