From 8c7c1c84cbaa38a4053404883d666ea8dff81b3a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 8 Jun 2021 11:49:06 +0100 Subject: Add a generic SubjectPublicKeyInfo decoder Previously all the SubjectPublicKeyInfo decoders were specific to a key type. We would iterate over all them until a match was found for the correct key type. Each one would fully decode the key before then testing whether it was a match or not - throwing it away if not. This was very inefficient. Instead we introduce a generic SubjectPublicKeyInfo decoder which figures out what type of key is contained within it, before subsequently passing on the data to a key type specific SubjectPublicKeyInfo decoder. Fixes #15646 Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/15662) --- providers/implementations/encode_decode/build.info | 3 +- .../implementations/encode_decode/decode_der2key.c | 18 +-- .../encode_decode/decode_spki2typespki.c | 124 +++++++++++++++++++++ .../encode_decode/endecoder_common.c | 19 +++- .../encode_decode/endecoder_local.h | 2 + 5 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 providers/implementations/encode_decode/decode_spki2typespki.c (limited to 'providers/implementations/encode_decode') diff --git a/providers/implementations/encode_decode/build.info b/providers/implementations/encode_decode/build.info index 22f11cbceb..d3f6ca4abd 100644 --- a/providers/implementations/encode_decode/build.info +++ b/providers/implementations/encode_decode/build.info @@ -7,7 +7,8 @@ $DECODER_GOAL=../../libdefault.a SOURCE[$ENCODER_GOAL]=endecoder_common.c SOURCE[$DECODER_GOAL]=decode_der2key.c decode_epki2pki.c decode_pem2der.c \ - decode_msblob2key.c decode_pvk2key.c + decode_msblob2key.c decode_pvk2key.c \ + decode_spki2typespki.c SOURCE[$ENCODER_GOAL]=encode_key2any.c encode_key2text.c encode_key2ms.c # encode_key2blob.c is only being included when EC is enabled, because we diff --git a/providers/implementations/encode_decode/decode_der2key.c b/providers/implementations/encode_decode/decode_der2key.c index 7de44ed75d..fd4a7c6e2a 100644 --- a/providers/implementations/encode_decode/decode_der2key.c +++ b/providers/implementations/encode_decode/decode_der2key.c @@ -93,22 +93,6 @@ struct der2key_ctx_st { 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, @@ -214,7 +198,7 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, return 0; } - ok = read_der(ctx->provctx, cin, &der, &der_len); + ok = ossl_read_der(ctx->provctx, cin, &der, &der_len); if (!ok) goto next; diff --git a/providers/implementations/encode_decode/decode_spki2typespki.c b/providers/implementations/encode_decode/decode_spki2typespki.c new file mode 100644 index 0000000000..3a4c83e8b5 --- /dev/null +++ b/providers/implementations/encode_decode/decode_spki2typespki.c @@ -0,0 +1,124 @@ +/* + * Copyright 2020-2021 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include "internal/sizes.h" +#include "crypto/x509.h" +#include "crypto/ec.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +static OSSL_FUNC_decoder_newctx_fn spki2typespki_newctx; +static OSSL_FUNC_decoder_freectx_fn spki2typespki_freectx; +static OSSL_FUNC_decoder_decode_fn spki2typespki_decode; + +/* + * Context used for SubjectPublicKeyInfo to Type specific SubjectPublicKeyInfo + * decoding. + */ +struct spki2typespki_ctx_st { + PROV_CTX *provctx; +}; + +static void *spki2typespki_newctx(void *provctx) +{ + struct spki2typespki_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void spki2typespki_freectx(void *vctx) +{ + struct spki2typespki_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int spki2typespki_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 spki2typespki_ctx_st *ctx = vctx; + unsigned char *der, *derp; + long len; + int ok = 0; + int objtype = OSSL_OBJECT_PKEY; + X509_PUBKEY *xpub = NULL; + X509_ALGOR *algor = NULL; + const ASN1_OBJECT *oid = NULL; + char dataname[OSSL_MAX_NAME_SIZE]; + OSSL_PARAM params[5], *p = params; + + if (!ossl_read_der(ctx->provctx, cin, &der, &len)) + return 1; + derp = der; + xpub = ossl_d2i_X509_PUBKEY_INTERNAL((const unsigned char **)&derp, len, + PROV_LIBCTX_OF(ctx->provctx)); + + + if (xpub == NULL) { + /* We return "empty handed". This is not an error. */ + ok = 1; + goto end; + } + + if (!X509_PUBKEY_get0_param(NULL, NULL, NULL, &algor, xpub)) + goto end; + X509_ALGOR_get0(&oid, NULL, NULL, algor); + +#ifndef OPENSSL_NO_EC + /* SM2 abuses the EC oid, so this could actually be SM2 */ + if (OBJ_obj2nid(oid) == NID_X9_62_id_ecPublicKey + && ossl_x509_algor_is_sm2(algor)) + strcpy(dataname, "SM2"); + else +#endif + if (!OBJ_obj2txt(dataname, sizeof(dataname), oid, 0)) + goto end; + + ossl_X509_PUBKEY_INTERNAL_free(xpub); + xpub = NULL; + + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + dataname, 0); + + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + "SubjectPublicKeyInfo", + 0); + *p++ = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, der, len); + *p++ = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + + *p = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + + end: + ossl_X509_PUBKEY_INTERNAL_free(xpub); + OPENSSL_free(der); + return ok; +} + +const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_der_decoder_functions[] = { + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))spki2typespki_newctx }, + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))spki2typespki_freectx }, + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))spki2typespki_decode }, + { 0, NULL } +}; diff --git a/providers/implementations/encode_decode/endecoder_common.c b/providers/implementations/encode_decode/endecoder_common.c index c85fe915ac..7d26e2a340 100644 --- a/providers/implementations/encode_decode/endecoder_common.c +++ b/providers/implementations/encode_decode/endecoder_common.c @@ -8,7 +8,9 @@ */ #include - +#include +#include "internal/asn1.h" +#include "prov/bio.h" #include "endecoder_local.h" OSSL_FUNC_keymgmt_new_fn * @@ -82,3 +84,18 @@ void ossl_prov_free_key(const OSSL_DISPATCH *fns, void *key) kmgmt_free(key); } +int ossl_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; +} diff --git a/providers/implementations/encode_decode/endecoder_local.h b/providers/implementations/encode_decode/endecoder_local.h index ab431b8086..96941e4d16 100644 --- a/providers/implementations/encode_decode/endecoder_local.h +++ b/providers/implementations/encode_decode/endecoder_local.h @@ -24,3 +24,5 @@ int ossl_prov_der_from_p8(unsigned char **new_der, long *new_der_len, void *ossl_prov_import_key(const OSSL_DISPATCH *fns, void *provctx, int selection, const OSSL_PARAM params[]); void ossl_prov_free_key(const OSSL_DISPATCH *fns, void *key); +int ossl_read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len); -- cgit v1.2.3