summaryrefslogtreecommitdiffstats
path: root/providers/implementations/encode_decode
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2021-06-08 11:49:06 +0100
committerMatt Caswell <matt@openssl.org>2021-06-14 09:43:01 +0100
commit8c7c1c84cbaa38a4053404883d666ea8dff81b3a (patch)
treee775c97857d6cf816b94573bcbad11e68ed691fb /providers/implementations/encode_decode
parent1c49be8673713d2ceb03a63be03531d9b28a46bd (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/implementations/encode_decode')
-rw-r--r--providers/implementations/encode_decode/build.info3
-rw-r--r--providers/implementations/encode_decode/decode_der2key.c18
-rw-r--r--providers/implementations/encode_decode/decode_spki2typespki.c124
-rw-r--r--providers/implementations/encode_decode/endecoder_common.c19
-rw-r--r--providers/implementations/encode_decode/endecoder_local.h2
5 files changed, 147 insertions, 19 deletions
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);