From: Richard Levitte Date: Thu, 9 Jul 2020 17:07:12 +0000 (+0200) Subject: PROV: Implement DER to RSA deserializer X-Git-Tag: openssl-3.0.0-alpha6~63 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1017b8e4a161682c909a98ebf3f7a21b38d6c677;p=thirdparty%2Fopenssl.git PROV: Implement DER to RSA deserializer Reviewed-by: Matt Caswell Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/12410) --- diff --git a/providers/defltprov.c b/providers/defltprov.c index d404585afd1..7d8681bb16d 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -530,6 +530,14 @@ static const OSSL_ALGORITHM deflt_serializer[] = { { "EC", "provider=default,fips=yes,format=pem,type=parameters", ec_param_pem_serializer_functions }, #endif + + { NULL, NULL, NULL } +}; + +static const OSSL_ALGORITHM deflt_deserializer[] = { + { "RSA", "provider=default,fips=yes,input=der", + der_to_rsa_deserializer_functions }, + { NULL, NULL, NULL } }; @@ -559,6 +567,8 @@ static const OSSL_ALGORITHM *deflt_query(void *provctx, int operation_id, return deflt_asym_cipher; case OSSL_OP_SERIALIZER: return deflt_serializer; + case OSSL_OP_DESERIALIZER: + return deflt_deserializer; } return NULL; } diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 0b32f3727c2..07452a372e9 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -358,3 +358,5 @@ extern const OSSL_DISPATCH ec_param_der_serializer_functions[]; extern const OSSL_DISPATCH ec_priv_pem_serializer_functions[]; extern const OSSL_DISPATCH ec_pub_pem_serializer_functions[]; extern const OSSL_DISPATCH ec_param_pem_serializer_functions[]; + +extern const OSSL_DISPATCH der_to_rsa_deserializer_functions[]; diff --git a/providers/implementations/keymgmt/rsa_kmgmt.c b/providers/implementations/keymgmt/rsa_kmgmt.c index 5c6b52efaf5..3231c020c96 100644 --- a/providers/implementations/keymgmt/rsa_kmgmt.c +++ b/providers/implementations/keymgmt/rsa_kmgmt.c @@ -23,6 +23,7 @@ #include "prov/providercommon.h" #include "prov/provider_ctx.h" #include "crypto/rsa.h" +#include "crypto/cryptlib.h" #include "internal/param_build_set.h" static OSSL_FUNC_keymgmt_new_fn rsa_newdata; @@ -34,6 +35,7 @@ static OSSL_FUNC_keymgmt_gen_settable_params_fn rsa_gen_settable_params; static OSSL_FUNC_keymgmt_gen_settable_params_fn rsapss_gen_settable_params; static OSSL_FUNC_keymgmt_gen_fn rsa_gen; static OSSL_FUNC_keymgmt_gen_cleanup_fn rsa_gen_cleanup; +static OSSL_FUNC_keymgmt_load_fn rsa_load; static OSSL_FUNC_keymgmt_free_fn rsa_freedata; static OSSL_FUNC_keymgmt_get_params_fn rsa_get_params; static OSSL_FUNC_keymgmt_gettable_params_fn rsa_gettable_params; @@ -575,6 +577,20 @@ static void rsa_gen_cleanup(void *genctx) OPENSSL_free(gctx); } +void *rsa_load(const void *reference, size_t reference_sz) +{ + RSA *rsa = NULL; + + if (reference_sz == sizeof(rsa)) { + /* The contents of the reference is the address to our object */ + rsa = *(RSA **)reference; + /* We grabbed, so we detach it */ + *(RSA **)reference = NULL; + return rsa; + } + return NULL; +} + /* For any RSA key, we use the "RSA" algorithms regardless of sub-type. */ static const char *rsapss_query_operation_name(int operation_id) { @@ -590,6 +606,7 @@ const OSSL_DISPATCH rsa_keymgmt_functions[] = { (void (*)(void))rsa_gen_settable_params }, { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))rsa_gen }, { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))rsa_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))rsa_load }, { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))rsa_freedata }, { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))rsa_get_params }, { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))rsa_gettable_params }, diff --git a/providers/implementations/serializers/build.info b/providers/implementations/serializers/build.info index ffafbe38e50..5eaa1683641 100644 --- a/providers/implementations/serializers/build.info +++ b/providers/implementations/serializers/build.info @@ -9,8 +9,9 @@ $DSA_GOAL=../../libimplementations.a $ECX_GOAL=../../libimplementations.a $EC_GOAL=../../libimplementations.a -SOURCE[$SERIALIZER_GOAL]=serializer_common.c +SOURCE[$SERIALIZER_GOAL]=serializer_common.c deserialize_common.c +SOURCE[$RSA_GOAL]=deserialize_der2rsa.c SOURCE[$RSA_GOAL]=serializer_rsa.c serializer_rsa_priv.c serializer_rsa_pub.c DEPEND[serializer_rsa.o]=../../common/include/prov/der_rsa.h diff --git a/providers/implementations/serializers/deserialize_common.c b/providers/implementations/serializers/deserialize_common.c new file mode 100644 index 00000000000..17362f2270c --- /dev/null +++ b/providers/implementations/serializers/deserialize_common.c @@ -0,0 +1,31 @@ +/* + * Copyright 2020 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 "crypto/asn1.h" +#include "prov/bio.h" +#include "serializer_local.h" + +int ossl_prov_read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin, + unsigned char **data, long *len) +{ + BUF_MEM *mem = NULL; + BIO *in = 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/serializers/deserialize_der2rsa.c b/providers/implementations/serializers/deserialize_der2rsa.c new file mode 100644 index 00000000000..9b586324757 --- /dev/null +++ b/providers/implementations/serializers/deserialize_der2rsa.c @@ -0,0 +1,179 @@ +/* + * Copyright 2020 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 + */ + +/* + * RSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include +#include +#include +#include +#include +#include "prov/bio.h" +#include "prov/implementations.h" +#include "serializer_local.h" + +static OSSL_FUNC_deserializer_newctx_fn der2rsa_newctx; +static OSSL_FUNC_deserializer_freectx_fn der2rsa_freectx; +static OSSL_FUNC_deserializer_gettable_params_fn der2rsa_gettable_params; +static OSSL_FUNC_deserializer_get_params_fn der2rsa_get_params; +static OSSL_FUNC_deserializer_deserialize_fn der2rsa_deserialize; +static OSSL_FUNC_deserializer_export_object_fn der2rsa_export_object; + +/* + * Context used for DER to RSA key deserialization. + */ +struct der2rsa_ctx_st { + PROV_CTX *provctx; + +#if 0 + struct pkcs8_encrypt_ctx_st sc; +#endif +}; + +static void *der2rsa_newctx(void *provctx) +{ + struct der2rsa_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + } + return ctx; +} + +static void der2rsa_freectx(void *vctx) +{ + struct der2rsa_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static const OSSL_PARAM *der2rsa_gettable_params(void) +{ + static const OSSL_PARAM gettables[] = { + { OSSL_DESERIALIZER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 }, + OSSL_PARAM_END, + }; + + return gettables; +} + +static int der2rsa_get_params(OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_DESERIALIZER_PARAM_INPUT_TYPE); + if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, "DER")) + return 0; + + return 1; +} + +static int der2rsa_deserialize(void *vctx, OSSL_CORE_BIO *cin, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct der2rsa_ctx_st *ctx = vctx; + void *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx); + RSA *rsa = NULL; + unsigned char *der = NULL; + const unsigned char *derp; + long der_len = 0; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if (!ossl_prov_read_der(ctx->provctx, cin, &der, &der_len)) + return 0; + + derp = der; +#if 0 /* PKCS#8 decryption coming soon */ + X509_SIG *p8 = NULL; + if ((p8 = d2i_X509_SIG(NULL, &derp, der_len)) != NULL) { + const X509_ALGOR *dalg = NULL; + const ASN1_OCTET_STRING *doct = NULL; + unsigned char *new_data = NULL; + int new_data_len; + + /* passphrase fetching code TBA */ + X509_SIG_get0(p8, &dalg, &doct); + if (!PKCS12_pbe_crypt(dalg, pass, strlen(pass), + doct->data, doct->length, + &new_data, &new_data_len, 0)) + goto nop8; + OPENSSL_free(der); + der = new_data; + der_len = new_data_len; + } + X509_SIG_free(p8); + nop8: +#endif + + derp = der; + if ((pkey = d2i_PrivateKey_ex(EVP_PKEY_RSA, NULL, &derp, der_len, + libctx, NULL)) != NULL) { + /* Tear out the RSA pointer from the pkey */ + rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + } + + OPENSSL_free(der); + + if (rsa != NULL) { + OSSL_PARAM params[3]; + + params[0] = + OSSL_PARAM_construct_utf8_string(OSSL_DESERIALIZER_PARAM_DATA_TYPE, + "RSA", 0); + /* The address of the key becomes the octet string */ + params[1] = + OSSL_PARAM_construct_octet_string(OSSL_DESERIALIZER_PARAM_REFERENCE, + &rsa, sizeof(rsa)); + params[2] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + RSA_free(rsa); + + return ok; +} + +static int der2rsa_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + OSSL_FUNC_keymgmt_export_fn *rsa_export = + ossl_prov_get_keymgmt_rsa_export(); + void *keydata; + + if (reference_sz == sizeof(keydata) && rsa_export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(RSA **)reference; + + return rsa_export(keydata, OSSL_KEYMGMT_SELECT_ALL, + export_cb, export_cbarg); + } + return 0; +} + +const OSSL_DISPATCH der_to_rsa_deserializer_functions[] = { + { OSSL_FUNC_DESERIALIZER_NEWCTX, (void (*)(void))der2rsa_newctx }, + { OSSL_FUNC_DESERIALIZER_FREECTX, (void (*)(void))der2rsa_freectx }, + { OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS, + (void (*)(void))der2rsa_gettable_params }, + { OSSL_FUNC_DESERIALIZER_GET_PARAMS, + (void (*)(void))der2rsa_get_params }, + { OSSL_FUNC_DESERIALIZER_DESERIALIZE, + (void (*)(void))der2rsa_deserialize }, + { OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT, + (void (*)(void))der2rsa_export_object }, + { 0, NULL } +}; diff --git a/providers/implementations/serializers/serializer_common.c b/providers/implementations/serializers/serializer_common.c index 7bf0ce941ae..58d7a27e601 100644 --- a/providers/implementations/serializers/serializer_common.c +++ b/providers/implementations/serializers/serializer_common.c @@ -144,6 +144,16 @@ OSSL_FUNC_keymgmt_import_fn *ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *f return NULL; } +OSSL_FUNC_keymgmt_export_fn *ossl_prov_get_keymgmt_export(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_EXPORT) + return OSSL_FUNC_keymgmt_export(fns); + + return NULL; +} + # ifdef SIXTY_FOUR_BIT_LONG # define BN_FMTu "%lu" # define BN_FMTx "%lx" diff --git a/providers/implementations/serializers/serializer_local.h b/providers/implementations/serializers/serializer_local.h index 5378bf1c84c..3d163209381 100644 --- a/providers/implementations/serializers/serializer_local.h +++ b/providers/implementations/serializers/serializer_local.h @@ -35,10 +35,12 @@ struct pkcs8_encrypt_ctx_st { OSSL_FUNC_keymgmt_new_fn *ossl_prov_get_keymgmt_new(const OSSL_DISPATCH *fns); OSSL_FUNC_keymgmt_free_fn *ossl_prov_get_keymgmt_free(const OSSL_DISPATCH *fns); OSSL_FUNC_keymgmt_import_fn *ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_export_fn *ossl_prov_get_keymgmt_export(const OSSL_DISPATCH *fns); OSSL_FUNC_keymgmt_new_fn *ossl_prov_get_keymgmt_rsa_new(void); OSSL_FUNC_keymgmt_free_fn *ossl_prov_get_keymgmt_rsa_free(void); OSSL_FUNC_keymgmt_import_fn *ossl_prov_get_keymgmt_rsa_import(void); +OSSL_FUNC_keymgmt_export_fn *ossl_prov_get_keymgmt_rsa_export(void); OSSL_FUNC_keymgmt_new_fn *ossl_prov_get_keymgmt_dh_new(void); OSSL_FUNC_keymgmt_free_fn *ossl_prov_get_keymgmt_dh_free(void); OSSL_FUNC_keymgmt_import_fn *ossl_prov_get_keymgmt_dh_import(void); @@ -157,3 +159,6 @@ int ossl_prov_write_pub_pem_from_obj(BIO *out, const void *obj, int obj_nid, int *strtype), int (*k2d)(const void *obj, unsigned char **pder)); + +int ossl_prov_read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin, + unsigned char **data, long *len); diff --git a/providers/implementations/serializers/serializer_rsa.c b/providers/implementations/serializers/serializer_rsa.c index e936a672123..d0cea458d12 100644 --- a/providers/implementations/serializers/serializer_rsa.c +++ b/providers/implementations/serializers/serializer_rsa.c @@ -37,6 +37,11 @@ OSSL_FUNC_keymgmt_import_fn *ossl_prov_get_keymgmt_rsa_import(void) return ossl_prov_get_keymgmt_import(rsa_keymgmt_functions); } +OSSL_FUNC_keymgmt_export_fn *ossl_prov_get_keymgmt_rsa_export(void) +{ + return ossl_prov_get_keymgmt_export(rsa_keymgmt_functions); +} + int ossl_prov_print_rsa(BIO *out, RSA *rsa, int priv) { const char *modulus_label;