1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
/*
* Copyright 2021-2023 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 <openssl/core.h>
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/params.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#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;
if (out == NULL)
return 0;
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 void *key2blob_newctx(void *provctx)
{
return provctx;
}
static void key2blob_freectx(void *vctx)
{
}
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_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 }, \
OSSL_DISPATCH_END \
}
#ifndef OPENSSL_NO_EC
MAKE_BLOB_ENCODER(ec, ec, PUBLIC_KEY);
#ifndef OPENSSL_NO_SM2
MAKE_BLOB_ENCODER(sm2, ec, PUBLIC_KEY);
#endif
#endif
|