{
struct import_data_st *data = arg;
+ /*
+ * It's fine if there was no data to transfer, we just end up with an
+ * empty destination key.
+ */
+ if (params[0].key == NULL)
+ return 1;
+
+ /* Just in time creation of keydata, if needed */
+ if (data->keydata == NULL
+ && (data->keydata = evp_keymgmt_newdata(data->keymgmt)) == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
return evp_keymgmt_import(data->keymgmt, data->keydata, data->selection,
params);
}
void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
{
- void *keydata = NULL;
struct import_data_st import_data;
size_t i = 0;
return NULL;
/* If we have an unassigned key, give up */
- if (pk->keymgmt == NULL)
+ if (pk->keydata == NULL)
return NULL;
/* If |keymgmt| matches the "origin" |keymgmt|, no more to do */
if (!ossl_assert(match_type(pk->keymgmt, keymgmt)))
return NULL;
- /* Create space to import data into */
- if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL)
- return NULL;
-
/*
* We look at the already cached provider keys, and import from the
* first that supports it (i.e. use its export function), and export
*/
/* Setup for the export callback */
- import_data.keydata = keydata;
+ import_data.keydata = NULL; /* try_import will create it */
import_data.keymgmt = keymgmt;
import_data.selection = OSSL_KEYMGMT_SELECT_ALL;
if (!evp_keymgmt_export(pk->keymgmt, pk->keydata, OSSL_KEYMGMT_SELECT_ALL,
&try_import, &import_data)) {
/* If there was an error, bail out */
- evp_keymgmt_freedata(keymgmt, keydata);
+ evp_keymgmt_freedata(keymgmt, import_data.keydata);
return NULL;
}
/* Add the new export to the operation cache */
- if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, keydata)) {
- evp_keymgmt_freedata(keymgmt, keydata);
+ if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, import_data.keydata)) {
+ evp_keymgmt_freedata(keymgmt, import_data.keydata);
return NULL;
}
- return keydata;
+ return import_data.keydata;
}
void evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk)
*
* This services functions like EVP_PKEY_size, EVP_PKEY_bits, etc
*/
- if (pk->keymgmt != NULL) {
+ if (pk->keydata != NULL) {
int bits = 0;
int security_bits = 0;
int size = 0;
keydata2 = pk2->keydata;
if (keymgmt1 != keymgmt2) {
- void *tmp_keydata = NULL;
+ /*
+ * The condition for a successful cross export is that the
+ * keydata to be exported is NULL (typed, but otherwise empty
+ * EVP_PKEY), or that it was possible to export it with
+ * evp_keymgmt_util_export_to_provider().
+ *
+ * We use |ok| to determine if it's ok to cross export one way,
+ * but also to determine if we should attempt a cross export
+ * the other way. There's no point doing it both ways.
+ */
+ int ok = 1;
/* Complex case, where the keymgmt differ */
if (keymgmt1 != NULL
*/
if (keymgmt2 != NULL
&& keymgmt2->match != NULL) {
- tmp_keydata = evp_keymgmt_util_export_to_provider(pk1, keymgmt2);
- if (tmp_keydata != NULL) {
+ void *tmp_keydata = NULL;
+
+ ok = 1;
+ if (keydata1 != NULL) {
+ tmp_keydata =
+ evp_keymgmt_util_export_to_provider(pk1, keymgmt2);
+ ok = (tmp_keydata != NULL);
+ }
+ if (ok) {
keymgmt1 = keymgmt2;
keydata1 = tmp_keydata;
}
}
- if (tmp_keydata == NULL
+ /*
+ * If we've successfully cross exported one way, there's not point
+ * doing it the other way, hence the |!ok| check.
+ */
+ if (!ok
&& keymgmt1 != NULL
&& keymgmt1->match != NULL) {
- tmp_keydata = evp_keymgmt_util_export_to_provider(pk2, keymgmt1);
- if (tmp_keydata != NULL) {
+ void *tmp_keydata = NULL;
+
+ ok = 1;
+ if (keydata2 != NULL) {
+ tmp_keydata =
+ evp_keymgmt_util_export_to_provider(pk2, keymgmt1);
+ ok = (tmp_keydata != NULL);
+ }
+ if (ok) {
keymgmt2 = keymgmt1;
keydata2 = tmp_keydata;
}
if (keymgmt1 != keymgmt2)
return -2;
+ /* If both keydata are NULL, then they're the same key */
+ if (keydata1 == NULL && keydata2 == NULL)
+ return 1;
+ /* If only one of the keydata is NULL, then they're different keys */
+ if (keydata1 == NULL || keydata2 == NULL)
+ return 0;
+ /* If both keydata are non-NULL, we let the backend decide */
return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
}
void *to_keydata = to->keydata, *alloc_keydata = NULL;
/* An unassigned key can't be copied */
- if (from == NULL || from->keymgmt == NULL)
- return 0;
-
- /* If |from| doesn't support copying, we fail */
- if (from->keymgmt->copy == NULL)
+ if (from == NULL || from->keydata == NULL)
return 0;
- /* If |to| doesn't have a provider side "origin" yet, create one */
- if (to_keymgmt == NULL) {
- to_keydata = alloc_keydata = evp_keymgmt_newdata(from->keymgmt);
- if (to_keydata == NULL)
+ if (to_keymgmt == from->keymgmt && to_keymgmt->copy != NULL) {
+ /* Make sure there's somewhere to copy to */
+ if (to_keydata == NULL
+ && (to_keydata = evp_keymgmt_newdata(to_keymgmt)) == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
return 0;
- to_keymgmt = from->keymgmt;
- }
+ }
- if (to_keymgmt == from->keymgmt) {
- /* |to| and |from| have the same keymgmt, just copy and be done */
+ /*
+ * |to| and |from| have the same keymgmt, and the copy function is
+ * implemented, so just copy and be done
+ */
if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata,
selection))
return 0;
evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
return 0;
}
+
+ /*
+ * In this case to_keydata was previously unallocated, try_import()
+ * may have created it for us.
+ */
+ to_keydata = import_data.keydata;
} else {
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
return 0;
int EVP_PKEY_size(const EVP_PKEY *pkey)
{
+ int size = 0;
+
if (pkey != NULL) {
- if (pkey->ameth == NULL)
- return pkey->cache.size;
- else if (pkey->ameth->pkey_size != NULL)
- return pkey->ameth->pkey_size(pkey);
+ size = pkey->cache.size;
+#ifndef FIPS_MODE
+ if (pkey->ameth != NULL && pkey->ameth->pkey_size != NULL)
+ size = pkey->ameth->pkey_size(pkey);
+#endif
}
- return 0;
+ return size;
}
void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
EVP_KEYMGMT *allocated_keymgmt = NULL;
EVP_KEYMGMT *tmp_keymgmt = NULL;
void *keydata = NULL;
+ int check;
if (pk == NULL)
return NULL;
+ /* No key data => nothing to export */
+ check = 1;
+#ifndef FIPS_MODE
+ check = check && pk->pkey.ptr == NULL;
+#endif
+ check = check && pk->keydata == NULL;
+ if (check)
+ return NULL;
+
#ifndef FIPS_MODE
if (pk->pkey.ptr != NULL) {
/*
return evp_keymgmt_validate(keymgmt, key,
OSSL_KEYMGMT_SELECT_PUBLIC_KEY);
+ if (pkey->type == EVP_PKEY_NONE)
+ goto not_supported;
+
+#ifndef FIPS_MODE
/* legacy */
/* call customized public key check function first */
if (ctx->pmeth->public_check != NULL)
return ctx->pmeth->public_check(pkey);
/* use default public key check function in ameth */
- if (pkey->ameth == NULL || pkey->ameth->pkey_public_check == NULL) {
- EVPerr(EVP_F_EVP_PKEY_PUBLIC_CHECK,
- EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
- return -2;
- }
+ if (pkey->ameth == NULL || pkey->ameth->pkey_public_check == NULL)
+ goto not_supported;
return pkey->ameth->pkey_public_check(pkey);
+#endif
+ not_supported:
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
}
int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx)
return evp_keymgmt_validate(keymgmt, key,
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
+ if (pkey->type == EVP_PKEY_NONE)
+ goto not_supported;
+
+#ifndef FIPS_MODE
+ /* legacy */
/* call customized param check function first */
if (ctx->pmeth->param_check != NULL)
return ctx->pmeth->param_check(pkey);
- /* legacy */
/* use default param check function in ameth */
- if (pkey->ameth == NULL || pkey->ameth->pkey_param_check == NULL) {
- EVPerr(EVP_F_EVP_PKEY_PARAM_CHECK,
- EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
- return -2;
- }
+ if (pkey->ameth == NULL || pkey->ameth->pkey_param_check == NULL)
+ goto not_supported;
return pkey->ameth->pkey_param_check(pkey);
+#endif
+ not_supported:
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
}
int EVP_PKEY_private_check(EVP_PKEY_CTX *ctx)
return evp_keymgmt_validate(keymgmt, key,
OSSL_KEYMGMT_SELECT_PRIVATE_KEY);
/* not supported for legacy keys */
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return -2;
}
if (key != NULL && keymgmt != NULL)
return evp_keymgmt_validate(keymgmt, key, OSSL_KEYMGMT_SELECT_KEYPAIR);
/* not supported for legacy keys */
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return -2;
}
if (key != NULL && keymgmt != NULL)
return evp_keymgmt_validate(keymgmt, key, OSSL_KEYMGMT_SELECT_ALL);
+ if (pkey->type == EVP_PKEY_NONE)
+ goto not_supported;
+
+#ifndef FIPS_MODE
/* legacy */
/* call customized check function first */
if (ctx->pmeth->check != NULL)
return ctx->pmeth->check(pkey);
/* use default check function in ameth */
- if (pkey->ameth == NULL || pkey->ameth->pkey_check == NULL) {
- EVPerr(EVP_F_EVP_PKEY_CHECK,
- EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
- return -2;
- }
+ if (pkey->ameth == NULL || pkey->ameth->pkey_check == NULL)
+ goto not_supported;
return pkey->ameth->pkey_check(pkey);
+#endif
+ not_supported:
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
}
* If the key doesn't contain anything legacy, then it must be provided,
* so we extract the necessary information and use that.
*/
- if (pkey != NULL && pkey->ameth == NULL) {
+ if (pkey != NULL && pkey->type == EVP_PKEY_NONE) {
/* If we have an engine, something went wrong somewhere... */
if (!ossl_assert(e == NULL))
return NULL;
cipher##_init_key, NULL, NULL, NULL, NULL)
/*
- * Type needs to be a bit field Sub-type needs to be for variations on the
- * method, as in, can it do arbitrary encryption....
+ * An EVP_PKEY can have the following states:
+ *
+ * untyped & empty:
+ *
+ * type == EVP_PKEY_NONE && keymgmt == NULL
+ *
+ * typed & empty:
+ *
+ * (type != EVP_PKEY_NONE && pkey.ptr == NULL) ## legacy (libcrypto only)
+ * || (keymgmt != NULL && keydata == NULL) ## provider side
+ *
+ * fully assigned:
+ *
+ * (type != EVP_PKEY_NONE && pkey.ptr != NULL) ## legacy (libcrypto only)
+ * || (keymgmt != NULL && keydata != NULL) ## provider side
+ *
+ * The easiest way to detect a legacy key is: type != EVP_PKEY_NONE
+ * The easiest way to detect a provider side key is: keymgmt != NULL
*/
struct evp_pkey_st {
/* == Legacy attributes == */
int type;
int save_type;
+# ifndef FIPS_MODE
/*
* Legacy key "origin" is composed of a pointer to an EVP_PKEY_ASN1_METHOD,
* a pointer to a low level key and possibly a pointer to an engine.
ENGINE *pmeth_engine; /* If not NULL public key ENGINE to use */
union {
void *ptr;
-# ifndef OPENSSL_NO_RSA
+# ifndef OPENSSL_NO_RSA
struct rsa_st *rsa; /* RSA */
-# endif
-# ifndef OPENSSL_NO_DSA
+# endif
+# ifndef OPENSSL_NO_DSA
struct dsa_st *dsa; /* DSA */
-# endif
-# ifndef OPENSSL_NO_DH
+# endif
+# ifndef OPENSSL_NO_DH
struct dh_st *dh; /* DH */
-# endif
-# ifndef OPENSSL_NO_EC
+# endif
+# ifndef OPENSSL_NO_EC
struct ec_key_st *ec; /* ECC */
ECX_KEY *ecx; /* X25519, X448, Ed25519, Ed448 */
-# endif
+# endif
} pkey;
+# endif
/* == Common attributes == */
CRYPTO_REF_COUNT references;
DH *dh = keydata;
int ok = 0;
- if ((selection & DH_POSSIBLE_SELECTIONS) != 0)
- ok = 1;
-
- if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
- ok = ok && (DH_get0_pub_key(dh) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
- ok = ok && (DH_get0_priv_key(dh) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
- ok = ok && (DH_get0_p(dh) != NULL && DH_get0_g(dh) != NULL);
+ if (dh != NULL) {
+ if ((selection & DH_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && (DH_get0_pub_key(dh) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && (DH_get0_priv_key(dh) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+ ok = ok && (DH_get0_p(dh) != NULL && DH_get0_g(dh) != NULL);
+ }
return ok;
}
DSA *dsa = keydata;
int ok = 0;
- if ((selection & DSA_POSSIBLE_SELECTIONS) != 0)
- ok = 1;
-
- if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
- ok = ok && (DSA_get0_pub_key(dsa) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
- ok = ok && (DSA_get0_priv_key(dsa) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
- ok = ok && (DSA_get0_p(dsa) != NULL && DSA_get0_g(dsa) != NULL);
+ if (dsa != NULL) {
+ if ((selection & DSA_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && (DSA_get0_pub_key(dsa) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && (DSA_get0_priv_key(dsa) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+ ok = ok && (DSA_get0_p(dsa) != NULL && DSA_get0_g(dsa) != NULL);
+ }
return ok;
}
EC_KEY *ec = keydata;
int ok = 0;
- if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
- ok = 1;
-
- if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
- ok = ok && (EC_KEY_get0_public_key(ec) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
- ok = ok && (EC_KEY_get0_private_key(ec) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
- ok = ok && (EC_KEY_get0_group(ec) != NULL);
- /*
- * We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be available,
- * so no extra check is needed other than the previous one against
- * EC_POSSIBLE_SELECTIONS.
- */
-
+ if (ec != NULL) {
+ if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && (EC_KEY_get0_public_key(ec) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && (EC_KEY_get0_private_key(ec) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+ ok = ok && (EC_KEY_get0_group(ec) != NULL);
+ /*
+ * We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be
+ * available, so no extra check is needed other than the previous one
+ * against EC_POSSIBLE_SELECTIONS.
+ */
+ }
return ok;
}
static int ecx_has(void *keydata, int selection)
{
ECX_KEY *key = keydata;
- int ok = 1;
+ int ok = 0;
- if ((selection & ECX_POSSIBLE_SELECTIONS) == 0)
- return 0;
-
- if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
- ok = ok && key->haspubkey;
+ if (key != NULL) {
+ if ((selection & ECX_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
- ok = ok && key->privkey != NULL;
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && key->haspubkey;
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && key->privkey != NULL;
+ }
return ok;
}
RSA *rsa = keydata;
int ok = 0;
- if ((selection & RSA_POSSIBLE_SELECTIONS) != 0)
- ok = 1;
-
- ok = ok && (RSA_get0_e(rsa) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
- ok = ok && (RSA_get0_n(rsa) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
- ok = ok && (RSA_get0_d(rsa) != NULL);
+ if (rsa != NULL) {
+ if ((selection & RSA_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
+ ok = ok && 0; /* This will change with PSS and OAEP */
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
+ ok = ok && (RSA_get0_e(rsa) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && (RSA_get0_n(rsa) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && (RSA_get0_d(rsa) != NULL);
+ }
return ok;
}