summaryrefslogtreecommitdiffstats
path: root/providers
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2021-03-18 10:41:53 +0100
committerRichard Levitte <levitte@openssl.org>2021-03-19 16:46:39 +0100
commitcf333799979755dd46193b49c15db0afd262c6a0 (patch)
tree77e5ab82979b1b8a9a64fcb2e0500af5361a57d0 /providers
parente0be34beee9ef8ebab49c51581f796e013600b77 (diff)
PROV: Add type specific PKCS#8 decoding to the DER->key decoders
This required refactoring a number of functions from the diverse EVP_PKEY_ASN1_METHOD implementations to become shared backend functions. It also meant modifying a few of them to return pointers to our internal RSA / DSA/ DH / EC_KEY, ... structures instead of manipulating an EVP_PKEY pointer directly, letting the caller do the latter. Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14314)
Diffstat (limited to 'providers')
-rw-r--r--providers/implementations/encode_decode/decode_der2key.c289
1 files changed, 140 insertions, 149 deletions
diff --git a/providers/implementations/encode_decode/decode_der2key.c b/providers/implementations/encode_decode/decode_der2key.c
index 74f462794a..f50fca3896 100644
--- a/providers/implementations/encode_decode/decode_der2key.c
+++ b/providers/implementations/encode_decode/decode_der2key.c
@@ -56,68 +56,13 @@
SET_ERR_MARK(); \
} while(0)
-static int read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin,
- unsigned char **data, long *len)
-{
- BUF_MEM *mem = NULL;
- BIO *in = ossl_bio_new_from_core_bio(provctx, 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;
-}
-
-static int der_from_p8(unsigned char **new_der, long *new_der_len,
- unsigned char *input_der, long input_der_len,
- OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
-{
- const unsigned char *derp;
- X509_SIG *p8 = NULL;
- int ok = 0;
-
- if (!ossl_assert(new_der != NULL && *new_der == NULL)
- || !ossl_assert(new_der_len != NULL))
- return 0;
-
- derp = input_der;
- if ((p8 = d2i_X509_SIG(NULL, &derp, input_der_len)) != NULL) {
- char pbuf[PEM_BUFSIZE];
- size_t plen = 0;
-
- if (!pw_cb(pbuf, sizeof(pbuf), &plen, NULL, pw_cbarg)) {
- ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE);
- } else {
- const X509_ALGOR *alg = NULL;
- const ASN1_OCTET_STRING *oct = NULL;
- int len = 0;
-
- X509_SIG_get0(p8, &alg, &oct);
- if (PKCS12_pbe_crypt(alg, pbuf, plen, oct->data, oct->length,
- new_der, &len, 0) != NULL)
- ok = 1;
- *new_der_len = len;
- }
- }
- X509_SIG_free(p8);
- return ok;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static OSSL_FUNC_decoder_freectx_fn der2key_freectx;
-static OSSL_FUNC_decoder_decode_fn der2key_decode;
-static OSSL_FUNC_decoder_export_object_fn der2key_export_object;
-
struct der2key_ctx_st; /* Forward declaration */
-typedef void *extract_key_fn(EVP_PKEY *);
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 *,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg);
struct keytype_desc_st {
const char *keytype_name;
const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */
@@ -140,14 +85,10 @@ struct keytype_desc_st {
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 PKCS#8, possibly encrypted */
d2i_of_void *d2i_PUBKEY; /* Wrapped in a SubjectPublicKeyInfo */
/*
- * For PKCS#8 decoders, we use EVP_PKEY extractors, EVP_PKEY_get1_{TYPE}()
- */
- extract_key_fn *extract_key;
-
- /*
* 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.
@@ -169,8 +110,67 @@ struct keytype_desc_st {
struct der2key_ctx_st {
PROV_CTX *provctx;
const struct keytype_desc_st *desc;
+ /* Flag used to signal that a failure is fatal */
+ unsigned int flag_fatal : 1;
};
+static int read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin,
+ unsigned char **data, long *len)
+{
+ BUF_MEM *mem = NULL;
+ BIO *in = ossl_bio_new_from_core_bio(provctx, 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 *der2key_decode_p8(const unsigned char **input_der,
+ long input_der_len, struct der2key_ctx_st *ctx,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg,
+ key_from_pkcs8_t *key_from_pkcs8)
+{
+ X509_SIG *p8 = NULL;
+ PKCS8_PRIV_KEY_INFO *p8inf = NULL;
+ const X509_ALGOR *alg = NULL;
+ void *key = NULL;
+
+ ctx->flag_fatal = 0;
+ if ((p8 = d2i_X509_SIG(NULL, input_der, input_der_len)) != NULL) {
+ char pbuf[PEM_BUFSIZE];
+ size_t plen = 0;
+
+ if (!pw_cb(pbuf, sizeof(pbuf), &plen, NULL, pw_cbarg))
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE);
+ else
+ p8inf = PKCS8_decrypt(p8, pbuf, plen);
+ if (p8inf == NULL)
+ ctx->flag_fatal = 1;
+ X509_SIG_free(p8);
+ } else {
+ p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, input_der, input_der_len);
+ }
+ if (p8inf != NULL
+ && PKCS8_pkey_get0(NULL, NULL, NULL, &alg, p8inf)
+ && OBJ_obj2nid(alg->algorithm) == ctx->desc->evp_type)
+ key = key_from_pkcs8(p8inf, PROV_LIBCTX_OF(ctx->provctx), NULL);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ return key;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static OSSL_FUNC_decoder_freectx_fn der2key_freectx;
+static OSSL_FUNC_decoder_decode_fn der2key_decode;
+static OSSL_FUNC_decoder_export_object_fn der2key_export_object;
+
static struct der2key_ctx_st *
der2key_newctx(void *provctx, const struct keytype_desc_st *desc)
{
@@ -262,13 +262,9 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
struct der2key_ctx_st *ctx = vctx;
- void *libctx = PROV_LIBCTX_OF(ctx->provctx);
unsigned char *der = NULL;
const unsigned char *derp;
long der_len = 0;
- unsigned char *new_der = NULL;
- long new_der_len;
- EVP_PKEY *pkey = NULL;
void *key = NULL;
int orig_selection = selection;
int ok = 0;
@@ -292,18 +288,21 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
if (!read_der(ctx->provctx, cin, &der, &der_len))
goto next;
- /* We try the typs specific functions first, if available */
- if (ctx->desc->d2i_private_key != NULL
- && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
RESET_ERR_MARK();
derp = der;
- key = ctx->desc->d2i_private_key(NULL, &derp, der_len);
+ if (ctx->desc->d2i_PKCS8 != NULL) {
+ key = ctx->desc->d2i_PKCS8(NULL, &derp, der_len, ctx,
+ pw_cb, pw_cbarg);
+ 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 && orig_selection != 0)
goto next;
}
- if (key == NULL
- && (ctx->desc->d2i_PUBKEY != NULL || ctx->desc->d2i_public_key != NULL)
- && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+ if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
RESET_ERR_MARK();
derp = der;
if (ctx->desc->d2i_PUBKEY != NULL)
@@ -313,71 +312,15 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
if (key == NULL && orig_selection != 0)
goto next;
}
- if (key == NULL
- && ctx->desc->d2i_key_params != NULL
- && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) {
+ if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) {
RESET_ERR_MARK();
derp = der;
- key = ctx->desc->d2i_key_params(NULL, &derp, der_len);
- }
- if (key == NULL
- && ctx->desc->extract_key != NULL) {
- /*
- * There is a EVP_PKEY extractor, so we use the more generic
- * EVP_PKEY functions, since they know how to unpack PKCS#8 and
- * SubjectPublicKeyInfo.
- */
-
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
- /*
- * Opportunistic attempt to decrypt. If it doesn't work, we try
- * to decode our input unencrypted.
- */
- if (der_from_p8(&new_der, &new_der_len, der, der_len,
- pw_cb, pw_cbarg)) {
- OPENSSL_free(der);
- der = new_der;
- der_len = new_der_len;
- }
- RESET_ERR_MARK();
-
- derp = der;
- pkey = evp_privatekey_from_binary(ctx->desc->evp_type, NULL,
- &derp, der_len, libctx, NULL);
- }
-
- /*
- * As long as we have algos without a specific d2i_<TYPE>_PUBKEY,
- * this code must remain...
- */
- if (pkey == NULL
- && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
- RESET_ERR_MARK();
- derp = der;
- pkey = ossl_d2i_PUBKEY_legacy(NULL, &derp, der_len);
- }
-
- if (pkey != NULL) {
- /*
- * Tear out the low-level key pointer from the pkey,
- * but only if it matches the expected key type.
- *
- * The check should be done with EVP_PKEY_is_a(), but
- * as long as we still have #legacy internal keys, it's safer
- * to use the type numbers inside the provider.
- */
- if (EVP_PKEY_id(pkey) == ctx->desc->evp_type)
- key = ctx->desc->extract_key(pkey);
-
- /*
- * ctx->desc->extract_key() is expected to have incremented
- * |key|'s reference count, so it should be safe to free |pkey|
- * now.
- */
- EVP_PKEY_free(pkey);
- }
+ if (ctx->desc->d2i_key_params != NULL)
+ key = ctx->desc->d2i_key_params(NULL, &derp, der_len);
+ if (key == NULL && orig_selection != 0)
+ goto next;
}
-
+ RESET_ERR_MARK();
if (key != NULL
&& ctx->desc->check_key != NULL
&& !ctx->desc->check_key(key, ctx)) {
@@ -453,10 +396,18 @@ static int der2key_export_object(void *vctx,
#ifndef OPENSSL_NO_DH
# define dh_evp_type EVP_PKEY_DH
-# define dh_evp_extract (extract_key_fn *)EVP_PKEY_get1_DH
# define dh_d2i_private_key NULL
# define dh_d2i_public_key NULL
# define dh_d2i_key_params (d2i_of_void *)d2i_DHparams
+
+static void *dh_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
+ struct der2key_ctx_st *ctx,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+ return der2key_decode_p8(der, der_len, ctx, pw_cb, pw_cbarg,
+ (key_from_pkcs8_t *)ossl_dh_key_from_pkcs8);
+}
+
# define dh_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DH_PUBKEY
# define dh_free (free_key_fn *)DH_free
# define dh_check NULL
@@ -467,10 +418,10 @@ static void dh_adjust(void *key, struct der2key_ctx_st *ctx)
}
# define dhx_evp_type EVP_PKEY_DHX
-# define dhx_evp_extract (extract_key_fn *)EVP_PKEY_get1_DH
# define dhx_d2i_private_key NULL
# define dhx_d2i_public_key NULL
# define dhx_d2i_key_params (d2i_of_void *)d2i_DHxparams
+# define dhx_d2i_PKCS8 dh_d2i_PKCS8
# define dhx_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DHx_PUBKEY
# define dhx_free (free_key_fn *)DH_free
# define dhx_check NULL
@@ -481,10 +432,18 @@ static void dh_adjust(void *key, struct der2key_ctx_st *ctx)
#ifndef OPENSSL_NO_DSA
# define dsa_evp_type EVP_PKEY_DSA
-# define dsa_evp_extract (extract_key_fn *)EVP_PKEY_get1_DSA
# define dsa_d2i_private_key (d2i_of_void *)d2i_DSAPrivateKey
# define dsa_d2i_public_key (d2i_of_void *)d2i_DSAPublicKey
# define dsa_d2i_key_params (d2i_of_void *)d2i_DSAparams
+
+static void *dsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
+ struct der2key_ctx_st *ctx,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+ return der2key_decode_p8(der, der_len, ctx, pw_cb, pw_cbarg,
+ (key_from_pkcs8_t *)ossl_dsa_key_from_pkcs8);
+}
+
# define dsa_d2i_PUBKEY (d2i_of_void *)d2i_DSA_PUBKEY
# define dsa_free (free_key_fn *)DSA_free
# define dsa_check NULL
@@ -499,10 +458,18 @@ static void dsa_adjust(void *key, struct der2key_ctx_st *ctx)
#ifndef OPENSSL_NO_EC
# define ec_evp_type EVP_PKEY_EC
-# define ec_evp_extract (extract_key_fn *)EVP_PKEY_get1_EC_KEY
# define ec_d2i_private_key (d2i_of_void *)d2i_ECPrivateKey
# define ec_d2i_public_key NULL
# define ec_d2i_key_params (d2i_of_void *)d2i_ECParameters
+
+static void *ec_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
+ struct der2key_ctx_st *ctx,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+ return der2key_decode_p8(der, der_len, ctx, pw_cb, pw_cbarg,
+ (key_from_pkcs8_t *)ossl_ec_key_from_pkcs8);
+}
+
# define ec_d2i_PUBKEY (d2i_of_void *)d2i_EC_PUBKEY
# define ec_free (free_key_fn *)EC_KEY_free
@@ -525,46 +492,54 @@ static void ec_adjust(void *key, struct der2key_ctx_st *ctx)
* so no d2i functions to be had.
*/
+static void *ecx_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
+ struct der2key_ctx_st *ctx,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+ return der2key_decode_p8(der, der_len, ctx, pw_cb, pw_cbarg,
+ (key_from_pkcs8_t *)ossl_ecx_key_from_pkcs8);
+}
+
static void ecx_key_adjust(void *key, struct der2key_ctx_st *ctx)
{
ossl_ecx_key_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx));
}
# define ed25519_evp_type EVP_PKEY_ED25519
-# define ed25519_evp_extract (extract_key_fn *)ossl_evp_pkey_get1_ED25519
# define ed25519_d2i_private_key NULL
# define ed25519_d2i_public_key NULL
# define ed25519_d2i_key_params NULL
+# define ed25519_d2i_PKCS8 ecx_d2i_PKCS8
# define ed25519_d2i_PUBKEY (d2i_of_void *)ossl_d2i_ED25519_PUBKEY
# define ed25519_free (free_key_fn *)ossl_ecx_key_free
# define ed25519_check NULL
# define ed25519_adjust ecx_key_adjust
# define ed448_evp_type EVP_PKEY_ED448
-# define ed448_evp_extract (extract_key_fn *)ossl_evp_pkey_get1_ED448
# define ed448_d2i_private_key NULL
# define ed448_d2i_public_key NULL
# define ed448_d2i_key_params NULL
+# define ed448_d2i_PKCS8 ecx_d2i_PKCS8
# define ed448_d2i_PUBKEY (d2i_of_void *)ossl_d2i_ED448_PUBKEY
# define ed448_free (free_key_fn *)ossl_ecx_key_free
# define ed448_check NULL
# define ed448_adjust ecx_key_adjust
# define x25519_evp_type EVP_PKEY_X25519
-# define x25519_evp_extract (extract_key_fn *)ossl_evp_pkey_get1_X25519
# define x25519_d2i_private_key NULL
# define x25519_d2i_public_key NULL
# define x25519_d2i_key_params NULL
+# define x25519_d2i_PKCS8 ecx_d2i_PKCS8
# define x25519_d2i_PUBKEY (d2i_of_void *)ossl_d2i_X25519_PUBKEY
# define x25519_free (free_key_fn *)ossl_ecx_key_free
# define x25519_check NULL
# define x25519_adjust ecx_key_adjust
# define x448_evp_type EVP_PKEY_X448
-# define x448_evp_extract (extract_key_fn *)ossl_evp_pkey_get1_X448
# define x448_d2i_private_key NULL
# define x448_d2i_public_key NULL
# define x448_d2i_key_params NULL
+# define x448_d2i_PKCS8 ecx_d2i_PKCS8
# define x448_d2i_PUBKEY (d2i_of_void *)ossl_d2i_X448_PUBKEY
# define x448_free (free_key_fn *)ossl_ecx_key_free
# define x448_check NULL
@@ -572,10 +547,18 @@ static void ecx_key_adjust(void *key, struct der2key_ctx_st *ctx)
# ifndef OPENSSL_NO_SM2
# define sm2_evp_type EVP_PKEY_SM2
-# define sm2_evp_extract (extract_key_fn *)EVP_PKEY_get1_EC_KEY
# define sm2_d2i_private_key (d2i_of_void *)d2i_ECPrivateKey
# define sm2_d2i_public_key NULL
# define sm2_d2i_key_params (d2i_of_void *)d2i_ECParameters
+
+static void *sm2_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
+ struct der2key_ctx_st *ctx,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+ return der2key_decode_p8(der, der_len, ctx, pw_cb, pw_cbarg,
+ (key_from_pkcs8_t *)ossl_ec_key_from_pkcs8);
+}
+
# define sm2_d2i_PUBKEY (d2i_of_void *)d2i_EC_PUBKEY
# define sm2_free (free_key_fn *)EC_KEY_free
# define sm2_check ec_check
@@ -586,10 +569,18 @@ static void ecx_key_adjust(void *key, struct der2key_ctx_st *ctx)
/* ---------------------------------------------------------------------- */
#define rsa_evp_type EVP_PKEY_RSA
-#define rsa_evp_extract (extract_key_fn *)EVP_PKEY_get1_RSA
#define rsa_d2i_private_key (d2i_of_void *)d2i_RSAPrivateKey
#define rsa_d2i_public_key (d2i_of_void *)d2i_RSAPublicKey
#define rsa_d2i_key_params NULL
+
+static void *rsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
+ struct der2key_ctx_st *ctx,
+ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+ return der2key_decode_p8(der, der_len, ctx, pw_cb, pw_cbarg,
+ (key_from_pkcs8_t *)ossl_rsa_key_from_pkcs8);
+}
+
#define rsa_d2i_PUBKEY (d2i_of_void *)d2i_RSA_PUBKEY
#define rsa_free (free_key_fn *)RSA_free
@@ -612,10 +603,10 @@ static void rsa_adjust(void *key, struct der2key_ctx_st *ctx)
}
#define rsapss_evp_type EVP_PKEY_RSA_PSS
-#define rsapss_evp_extract (extract_key_fn *)EVP_PKEY_get1_RSA
#define rsapss_d2i_private_key (d2i_of_void *)d2i_RSAPrivateKey
#define rsapss_d2i_public_key (d2i_of_void *)d2i_RSAPublicKey
#define rsapss_d2i_key_params NULL
+#define rsapss_d2i_PKCS8 rsa_d2i_PKCS8
#define rsapss_d2i_PUBKEY (d2i_of_void *)d2i_RSA_PUBKEY
#define rsapss_free (free_key_fn *)RSA_free
#define rsapss_check rsa_check
@@ -706,8 +697,8 @@ static void rsa_adjust(void *key, struct der2key_ctx_st *ctx)
NULL, \
NULL, \
NULL, \
+ keytype##_d2i_PKCS8, \
NULL, \
- keytype##_evp_extract, \
keytype##_check, \
keytype##_adjust, \
keytype##_free
@@ -718,8 +709,8 @@ static void rsa_adjust(void *key, struct der2key_ctx_st *ctx)
NULL, \
NULL, \
NULL, \
+ NULL, \
keytype##_d2i_PUBKEY, \
- keytype##_evp_extract, \
keytype##_check, \
keytype##_adjust, \
keytype##_free