From: Matt Caswell Date: Sat, 13 Feb 2021 14:24:15 +0000 (+0000) Subject: Pass the object type and data structure from the pem2der decoder X-Git-Tag: openssl-3.0.0-alpha13~262 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=70793dbbb983b0f95da30b79e8c8744289062499;p=thirdparty%2Fopenssl.git Pass the object type and data structure from the pem2der decoder The pem2der decoder can infer certain information about the endoded der data based on the PEM headers. This information should be passed to the next decoders in the chain to ensure we end up loading the correct type of thing. Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/14191) --- diff --git a/crypto/store/store_result.c b/crypto/store/store_result.c index b79126e1cbb..64b0e814b34 100644 --- a/crypto/store/store_result.c +++ b/crypto/store/store_result.c @@ -62,6 +62,7 @@ struct extracted_param_data_st { int object_type; const char *data_type; + const char *data_structure; const char *utf8_data; const void *octet_data; size_t octet_data_size; @@ -128,6 +129,10 @@ int ossl_store_handle_load_result(const OSSL_PARAM params[], void *arg) &helper_data.octet_data_size) && !OSSL_PARAM_get_utf8_string_ptr(p, &helper_data.utf8_data)) return 0; + p = OSSL_PARAM_locate_const(params, OSSL_OBJECT_PARAM_DATA_STRUCTURE); + if (p != NULL + && !OSSL_PARAM_get_utf8_string_ptr(p, &helper_data.data_structure)) + return 0; p = OSSL_PARAM_locate_const(params, OSSL_OBJECT_PARAM_REFERENCE); if (p != NULL && !OSSL_PARAM_get_octet_string_ptr(p, &helper_data.ref, &helper_data.ref_size)) @@ -274,8 +279,9 @@ static EVP_PKEY *try_key_value(struct extracted_param_data_st *data, } decoderctx = - OSSL_DECODER_CTX_new_for_pkey(&pk, "DER", NULL, data->data_type, - selection, libctx, propq); + OSSL_DECODER_CTX_new_for_pkey(&pk, "DER", data->data_structure, + data->data_type, selection, libctx, + propq); (void)OSSL_DECODER_CTX_set_passphrase_cb(decoderctx, cb, cbarg); /* No error if this couldn't be decoded */ diff --git a/providers/implementations/encode_decode/decode_pem2der.c b/providers/implementations/encode_decode/decode_pem2der.c index 73973e13ffc..895015a56ba 100644 --- a/providers/implementations/encode_decode/decode_pem2der.c +++ b/providers/implementations/encode_decode/decode_pem2der.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -114,20 +115,23 @@ static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, OSSL_CALLBACK *data_cb, void *data_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { - /* Strings to peal off the pem name */ - static const char *pealable_pem_name_endings[] = { + /* Strings to peel off the pem name */ + static struct peelablee_pem_name_endings_st { + const char *ending; + const char *data_structure; + } peelable_pem_name_endings[] = { /* * These entries should be in longest to shortest order to avoid * mixups. */ - "ENCRYPTED PRIVATE KEY", - "PRIVATE KEY", - "PUBLIC KEY", - "PARAMETERS" + { "ENCRYPTED PRIVATE KEY", "pkcs8" }, + { "PRIVATE KEY", "pkcs8" }, + { "PUBLIC KEY", "SubjectPublicKeyInfo" }, + { "PARAMETERS", NULL } /* * Libcrypto currently only supports decoding keys with provider side - * decoders, so we don't try to peal any other PEM name. That's an + * decoders, so we don't try to peel any other PEM name. That's an * exercise for when libcrypto starts to treat other types of objects * via providers. */ @@ -138,6 +142,8 @@ static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, unsigned char *der = NULL; long der_len = 0; int ok = 0; + int objtype = OSSL_OBJECT_UNKNOWN; + const char *data_structure = NULL; if (read_pem(ctx->provctx, cin, &pem_name, &pem_header, &der, &der_len) <= 0) @@ -166,15 +172,15 @@ static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, * no further purpose. */ for (i = 0, pem_name_len = strlen(pem_name); - i < OSSL_NELEM(pealable_pem_name_endings); + i < OSSL_NELEM(peelable_pem_name_endings); i++) { - size_t peal_len = strlen(pealable_pem_name_endings[i]); + size_t peel_len = strlen(peelable_pem_name_endings[i].ending); size_t pem_name_offset; - if (peal_len <= pem_name_len) { - pem_name_offset = pem_name_len - peal_len; + if (peel_len <= pem_name_len) { + pem_name_offset = pem_name_len - peel_len; if (strcmp(pem_name + pem_name_offset, - pealable_pem_name_endings[i]) == 0) { + peelable_pem_name_endings[i].ending) == 0) { do { pem_name[pem_name_offset] = '\0'; @@ -185,21 +191,53 @@ static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, OPENSSL_free(pem_name); pem_name = NULL; } + /* All of these peelable endings are for EVP_PKEYs */ + objtype = OSSL_OBJECT_PKEY; + if (pem_name == NULL) { + data_structure = peelable_pem_name_endings[i].data_structure; + if (data_structure == NULL) + goto end; + } else { + /* + * If there is an algorithm name prefix then it is a + * type-specific data structure + */ + data_structure = "type-specific"; + } break; } } } + /* If we don't know the object type yet check if it's one we know about */ + if (objtype == OSSL_OBJECT_UNKNOWN) { + if (strcmp(pem_name, PEM_STRING_X509) == 0 + || strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0 + || strcmp(pem_name, PEM_STRING_X509_OLD) == 0) + objtype = OSSL_OBJECT_CERT; + else if (strcmp(pem_name, PEM_STRING_X509_CRL) == 0) + objtype = OSSL_OBJECT_CRL; + } + { - OSSL_PARAM params[3], *p = params; + OSSL_PARAM params[5], *p = params; if (pem_name != NULL) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, pem_name, 0); + + /* We expect this to be read only so casting away the const is ok */ + if (data_structure != NULL) + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + (char *)data_structure, 0); *p++ = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, der, der_len); + *p++ = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + *p = OSSL_PARAM_construct_end(); ok = data_cb(params, data_cbarg);