diff options
author | Matt Caswell <matt@openssl.org> | 2021-06-08 11:49:06 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2021-06-14 09:43:01 +0100 |
commit | 8c7c1c84cbaa38a4053404883d666ea8dff81b3a (patch) | |
tree | e775c97857d6cf816b94573bcbad11e68ed691fb /providers | |
parent | 1c49be8673713d2ceb03a63be03531d9b28a46bd (diff) |
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 <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15662)
Diffstat (limited to 'providers')
7 files changed, 153 insertions, 19 deletions
diff --git a/providers/decoders.inc b/providers/decoders.inc index 02b2b32c3f..b562a45ee9 100644 --- a/providers/decoders.inc +++ b/providers/decoders.inc @@ -80,6 +80,11 @@ DECODER_w_structure("RSA-PSS", der, SubjectPublicKeyInfo, rsapss, yes), DECODER("RSA", msblob, rsa, yes), DECODER("RSA", pvk, rsa, yes), +/* + * A decoder that takes a SubjectPublicKeyInfo and figures out the types of key + * that it contains. The output is the same SubjectPublicKeyInfo + */ +DECODER_w_structure("DER", der, SubjectPublicKeyInfo, der, yes), DECODER("DER", pem, der, yes), /* * A decoder that recognises PKCS#8 EncryptedPrivateKeyInfo structure 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 <string.h> +#include <openssl/asn1t.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/params.h> +#include <openssl/x509.h> +#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 <openssl/core.h> - +#include <openssl/buffer.h> +#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); diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 7b59e7308d..855bd90919 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -484,6 +484,7 @@ extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_rsapss_decoder_functions[] extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_rsapss_decoder_functions[]; extern const OSSL_DISPATCH ossl_EncryptedPrivateKeyInfo_der_to_der_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_der_decoder_functions[]; extern const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[]; extern const OSSL_DISPATCH ossl_file_store_functions[]; |