/* * Copyright 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 */ /* * Low level APIs are deprecated for public use, but still ok for internal use. */ #include "internal/deprecated.h" #include #include #include #include #include #include #include #include "internal/passphrase.h" #include "internal/nelem.h" #include "prov/implementations.h" #include "prov/bio.h" #include "prov/provider_ctx.h" #include "endecoder_local.h" static int write_blob(void *provctx, OSSL_CORE_BIO *cout, void *data, int len) { BIO *out = ossl_bio_new_from_core_bio(provctx, cout); int ret = BIO_write(out, data, len); BIO_free(out); return ret; } static OSSL_FUNC_encoder_newctx_fn key2blob_newctx; static OSSL_FUNC_encoder_freectx_fn key2blob_freectx; static OSSL_FUNC_encoder_gettable_params_fn key2blob_gettable_params; static OSSL_FUNC_encoder_get_params_fn key2blob_get_params; static void *key2blob_newctx(void *provctx) { return provctx; } static void key2blob_freectx(void *vctx) { } static const OSSL_PARAM *key2blob_gettable_params(ossl_unused void *provctx) { static const OSSL_PARAM gettables[] = { { OSSL_ENCODER_PARAM_OUTPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 }, OSSL_PARAM_END, }; return gettables; } static int key2blob_get_params(OSSL_PARAM params[]) { OSSL_PARAM *p; p = OSSL_PARAM_locate(params, OSSL_ENCODER_PARAM_OUTPUT_TYPE); if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, "blob")) return 0; return 1; } static int key2blob_check_selection(int selection, int selection_mask) { /* * The selections are kinda sorta "levels", i.e. each selection given * here is assumed to include those following. */ int checks[] = { OSSL_KEYMGMT_SELECT_PRIVATE_KEY, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, OSSL_KEYMGMT_SELECT_ALL_PARAMETERS }; size_t i; /* The decoder implementations made here support guessing */ if (selection == 0) return 1; for (i = 0; i < OSSL_NELEM(checks); i++) { int check1 = (selection & checks[i]) != 0; int check2 = (selection_mask & checks[i]) != 0; /* * If the caller asked for the currently checked bit(s), return * whether the decoder description says it's supported. */ if (check1) return check2; } /* This should be dead code, but just to be safe... */ return 0; } static int key2blob_encode(void *vctx, const void *key, int selection, OSSL_CORE_BIO *cout) { int pubkey_len = 0, ok = 0; unsigned char *pubkey = NULL; pubkey_len = i2o_ECPublicKey(key, &pubkey); if (pubkey_len > 0 && pubkey != NULL) ok = write_blob(vctx, cout, pubkey, pubkey_len); OPENSSL_free(pubkey); return ok; } /* * MAKE_BLOB_ENCODER() Makes an OSSL_DISPATCH table for a particular key->blob * encoder * * impl: The keytype to encode * type: The C structure type holding the key data * selection_name: The acceptable selections. This translates into * the macro EVP_PKEY_##selection_name. * * The selection is understood as a "level" rather than an exact set of * requests from the caller. The encoder has to decide what contents fit * the encoded format. For example, the EC public key blob will only contain * the encoded public key itself, no matter if the selection bits include * OSSL_KEYMGMT_SELECT_PARAMETERS or not. However, if the selection includes * OSSL_KEYMGMT_SELECT_PRIVATE_KEY, the same encoder will simply refuse to * cooperate, because it cannot output the private key. * * EVP_PKEY_##selection_name are convenience macros that combine "typical" * OSSL_KEYMGMT_SELECT_ macros for a certain type of EVP_PKEY content. */ #define MAKE_BLOB_ENCODER(impl, type, selection_name) \ static OSSL_FUNC_encoder_import_object_fn \ impl##2blob_import_object; \ static OSSL_FUNC_encoder_free_object_fn impl##2blob_free_object; \ static OSSL_FUNC_encoder_does_selection_fn \ impl##2blob_does_selection; \ static OSSL_FUNC_encoder_encode_fn impl##2blob_encode; \ \ static void *impl##2blob_import_object(void *ctx, int selection, \ const OSSL_PARAM params[]) \ { \ return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ ctx, selection, params); \ } \ static void impl##2blob_free_object(void *key) \ { \ ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ } \ static int impl##2blob_does_selection(void *ctx, int selection) \ { \ return key2blob_check_selection(selection, \ EVP_PKEY_##selection_name); \ } \ static int impl##2blob_encode(void *vctx, OSSL_CORE_BIO *cout, \ const void *key, \ const OSSL_PARAM key_abstract[], \ int selection, \ OSSL_PASSPHRASE_CALLBACK *cb, \ void *cbarg) \ { \ /* We don't deal with abstract objects */ \ if (key_abstract != NULL) { \ ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \ return 0; \ } \ return key2blob_encode(vctx, key, selection, cout); \ } \ const OSSL_DISPATCH ossl_##impl##_to_blob_encoder_functions[] = { \ { OSSL_FUNC_ENCODER_NEWCTX, \ (void (*)(void))key2blob_newctx }, \ { OSSL_FUNC_ENCODER_FREECTX, \ (void (*)(void))key2blob_freectx }, \ { OSSL_FUNC_ENCODER_GETTABLE_PARAMS, \ (void (*)(void))key2blob_gettable_params }, \ { OSSL_FUNC_ENCODER_GET_PARAMS, \ (void (*)(void))key2blob_get_params }, \ { OSSL_FUNC_ENCODER_DOES_SELECTION, \ (void (*)(void))impl##2blob_does_selection }, \ { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ (void (*)(void))impl##2blob_import_object }, \ { OSSL_FUNC_ENCODER_FREE_OBJECT, \ (void (*)(void))impl##2blob_free_object }, \ { OSSL_FUNC_ENCODER_ENCODE, \ (void (*)(void))impl##2blob_encode }, \ { 0, NULL } \ } #ifndef OPENSSL_NO_EC MAKE_BLOB_ENCODER(ec, ec, PUBLIC_KEY); # ifndef OPENSSL_NO_SM2 MAKE_BLOB_ENCODER(sm2, ec, PUBLIC_KEY); # endif #endif