mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 05:21:51 +08:00
ENCODER: Refactor the OSSL_ENCODER API to be more like OSSL_DECODER
OSSL_ENCODER was developed before OSSL_DECODER, so the idea of chaining and the resulting API came later. This series of changes brings the same sort of API and functionality back to OSSL_ENCODER, making the two APIs more consistent with each other. Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12873)
This commit is contained in:
parent
5a6d6fe666
commit
b8975c68b1
@ -14,10 +14,12 @@
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
|
||||
static const ERR_STRING_DATA OSSL_ENCODER_str_reasons[] = {
|
||||
{ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY),
|
||||
"incorrect property query"},
|
||||
{ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_ENCODER_NOT_FOUND),
|
||||
"encoder not found"},
|
||||
"encoder not found"},
|
||||
{ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY),
|
||||
"incorrect property query"},
|
||||
{ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_MISSING_GET_PARAMS),
|
||||
"missing get params"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
@ -7,13 +7,20 @@
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "e_os.h" /* strcasecmp on Windows */
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/encoder.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/params.h>
|
||||
#include <openssl/provider.h>
|
||||
#include "encoder_local.h"
|
||||
|
||||
static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out);
|
||||
|
||||
int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
|
||||
{
|
||||
return ctx->do_output(ctx, out);
|
||||
return encoder_process(ctx, out);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
@ -41,3 +48,336 @@ int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp)
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
|
||||
const char *output_type)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->output_type = output_type;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ossl_assert(selection != 0)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->selection = selection;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
|
||||
void *encoderctx)
|
||||
{
|
||||
OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
|
||||
OSSL_PARAM params[3];
|
||||
|
||||
if (!ossl_assert(encoder != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (encoder->get_params == NULL) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER,
|
||||
OSSL_ENCODER_R_MISSING_GET_PARAMS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache the input and output types for this encoder. The output type
|
||||
* is mandatory.
|
||||
*/
|
||||
params[0] =
|
||||
OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
|
||||
(char **)&encoder_inst->output_type, 0);
|
||||
params[1] =
|
||||
OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_INPUT_TYPE,
|
||||
(char **)&encoder_inst->input_type, 0);
|
||||
params[2] = OSSL_PARAM_construct_end();
|
||||
|
||||
if (!encoder->get_params(params)
|
||||
|| !OSSL_PARAM_modified(¶ms[1]))
|
||||
goto err;
|
||||
|
||||
if (!OSSL_ENCODER_up_ref(encoder)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
encoder_inst->encoder = encoder;
|
||||
encoder_inst->encoderctx = encoderctx;
|
||||
return encoder_inst;
|
||||
err:
|
||||
ossl_encoder_instance_free(encoder_inst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
|
||||
{
|
||||
if (encoder_inst != NULL) {
|
||||
if (encoder_inst->encoder != NULL)
|
||||
encoder_inst->encoder->freectx(encoder_inst->encoderctx);
|
||||
encoder_inst->encoderctx = NULL;
|
||||
OSSL_ENCODER_free(encoder_inst->encoder);
|
||||
encoder_inst->encoder = NULL;
|
||||
OPENSSL_free(encoder_inst);
|
||||
}
|
||||
}
|
||||
|
||||
static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_ENCODER_INSTANCE *ei)
|
||||
{
|
||||
if (ctx->encoder_insts == NULL
|
||||
&& (ctx->encoder_insts =
|
||||
sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
|
||||
{
|
||||
OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
|
||||
const OSSL_PROVIDER *prov = NULL;
|
||||
void *encoderctx = NULL;
|
||||
void *provctx = NULL;
|
||||
|
||||
if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
prov = OSSL_ENCODER_provider(encoder);
|
||||
provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
|
||||
|
||||
if ((encoderctx = encoder->newctx(provctx)) == NULL
|
||||
|| (encoder_inst =
|
||||
ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
|
||||
goto err;
|
||||
/* Avoid double free of encoderctx on further errors */
|
||||
encoderctx = NULL;
|
||||
|
||||
if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
|
||||
goto err;
|
||||
|
||||
return 1;
|
||||
err:
|
||||
ossl_encoder_instance_free(encoder_inst);
|
||||
if (encoderctx != NULL)
|
||||
encoder->freectx(encoderctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
|
||||
OPENSSL_CTX *libctx, const char *propq)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL || ctx->encoder_insts == NULL)
|
||||
return 0;
|
||||
return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_ENCODER_CONSTRUCT *construct)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
ctx->construct = construct;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
|
||||
void *construct_data)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
ctx->construct_data = construct_data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_ENCODER_CLEANUP *cleanup)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
ctx->cleanup = cleanup;
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSSL_ENCODER *
|
||||
OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
|
||||
{
|
||||
if (encoder_inst == NULL)
|
||||
return NULL;
|
||||
return encoder_inst->encoder;
|
||||
}
|
||||
|
||||
void *
|
||||
OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
|
||||
{
|
||||
if (encoder_inst == NULL)
|
||||
return NULL;
|
||||
return encoder_inst->encoderctx;
|
||||
}
|
||||
|
||||
const char *
|
||||
OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst)
|
||||
{
|
||||
if (encoder_inst == NULL)
|
||||
return NULL;
|
||||
return encoder_inst->input_type;
|
||||
}
|
||||
|
||||
const char *
|
||||
OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
|
||||
{
|
||||
if (encoder_inst == NULL)
|
||||
return NULL;
|
||||
return encoder_inst->output_type;
|
||||
}
|
||||
|
||||
static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
|
||||
{
|
||||
size_t i, end;
|
||||
void *latest_output = NULL;
|
||||
size_t latest_output_length = 0;
|
||||
const char *latest_output_type = NULL;
|
||||
const char *last_input_type = NULL;
|
||||
int ok = 0;
|
||||
|
||||
end = OSSL_ENCODER_CTX_get_num_encoders(ctx);
|
||||
for (i = 0; i < end; i++) {
|
||||
OSSL_ENCODER_INSTANCE *encoder_inst =
|
||||
sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
|
||||
OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
|
||||
void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
|
||||
const char *current_input_type =
|
||||
OSSL_ENCODER_INSTANCE_get_input_type(encoder_inst);
|
||||
const char *current_output_type =
|
||||
OSSL_ENCODER_INSTANCE_get_output_type(encoder_inst);
|
||||
BIO *current_out;
|
||||
BIO *allocated_out = NULL;
|
||||
const void *current_data = NULL;
|
||||
OSSL_PARAM abstract[3];
|
||||
OSSL_PARAM *abstract_p;
|
||||
const OSSL_PARAM *current_abstract = NULL;
|
||||
|
||||
if (latest_output_type == NULL) {
|
||||
/*
|
||||
* This is the first iteration, so we prepare the object to be
|
||||
* encoded
|
||||
*/
|
||||
|
||||
current_data = ctx->construct(encoder_inst, ctx->construct_data);
|
||||
|
||||
/* Assume that the constructor recorded an error */
|
||||
if (current_data == NULL)
|
||||
goto loop_end;
|
||||
} else {
|
||||
/*
|
||||
* Check that the latest output type matches the currently
|
||||
* considered encoder
|
||||
*/
|
||||
if (!OSSL_ENCODER_is_a(encoder, latest_output_type))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If there is a latest output type, there should be a latest output
|
||||
*/
|
||||
if (!ossl_assert(latest_output != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
|
||||
goto loop_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an object abstraction from the latest output, which was
|
||||
* stolen from the previous round.
|
||||
*/
|
||||
abstract_p = abstract;
|
||||
if (last_input_type != NULL)
|
||||
*abstract_p++ =
|
||||
OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
|
||||
(char *)last_input_type, 0);
|
||||
*abstract_p++ =
|
||||
OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
|
||||
latest_output,
|
||||
latest_output_length);
|
||||
*abstract_p = OSSL_PARAM_construct_end();
|
||||
current_abstract = abstract;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the desired output type matches the output type of the currently
|
||||
* considered encoder, we're setting up final output. Otherwise, set
|
||||
* up an intermediary memory output.
|
||||
*/
|
||||
if (strcasecmp(ctx->output_type, current_output_type) == 0)
|
||||
current_out = out;
|
||||
else if ((current_out = allocated_out = BIO_new(BIO_s_mem())) == NULL)
|
||||
goto loop_end; /* Assume BIO_new() recorded an error */
|
||||
|
||||
ok = encoder->encode(encoderctx, (OSSL_CORE_BIO *)current_out,
|
||||
current_data, current_abstract, ctx->selection,
|
||||
ossl_pw_passphrase_callback_enc, &ctx->pwdata);
|
||||
|
||||
if (current_input_type != NULL)
|
||||
last_input_type = current_input_type;
|
||||
|
||||
if (!ok)
|
||||
goto loop_end;
|
||||
|
||||
OPENSSL_free(latest_output);
|
||||
|
||||
/*
|
||||
* Steal the output from the BIO_s_mem, if we did allocate one.
|
||||
* That'll be the data for an object abstraction in the next round.
|
||||
*/
|
||||
if (allocated_out != NULL) {
|
||||
BUF_MEM *buf;
|
||||
|
||||
BIO_get_mem_ptr(allocated_out, &buf);
|
||||
latest_output = buf->data;
|
||||
latest_output_length = buf->length;
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
BIO_free(allocated_out);
|
||||
}
|
||||
|
||||
loop_end:
|
||||
if (current_data != NULL)
|
||||
ctx->cleanup(ctx->construct_data);
|
||||
|
||||
if (ok)
|
||||
break;
|
||||
}
|
||||
|
||||
OPENSSL_free(latest_output);
|
||||
return ok;
|
||||
}
|
||||
|
@ -29,10 +29,13 @@ struct ossl_encoder_st {
|
||||
struct ossl_endecode_base_st base;
|
||||
OSSL_FUNC_encoder_newctx_fn *newctx;
|
||||
OSSL_FUNC_encoder_freectx_fn *freectx;
|
||||
OSSL_FUNC_encoder_get_params_fn *get_params;
|
||||
OSSL_FUNC_encoder_gettable_params_fn *gettable_params;
|
||||
OSSL_FUNC_encoder_set_ctx_params_fn *set_ctx_params;
|
||||
OSSL_FUNC_encoder_settable_ctx_params_fn *settable_ctx_params;
|
||||
OSSL_FUNC_encoder_encode_data_fn *encode_data;
|
||||
OSSL_FUNC_encoder_encode_object_fn *encode_object;
|
||||
OSSL_FUNC_encoder_encode_fn *encode;
|
||||
OSSL_FUNC_encoder_import_object_fn *import_object;
|
||||
OSSL_FUNC_encoder_free_object_fn *free_object;
|
||||
};
|
||||
|
||||
struct ossl_decoder_st {
|
||||
@ -47,22 +50,43 @@ struct ossl_decoder_st {
|
||||
OSSL_FUNC_decoder_export_object_fn *export_object;
|
||||
};
|
||||
|
||||
struct ossl_encoder_ctx_st {
|
||||
OSSL_ENCODER *encoder;
|
||||
void *encoderctx;
|
||||
struct ossl_encoder_instance_st {
|
||||
OSSL_ENCODER *encoder; /* Never NULL */
|
||||
void *encoderctx; /* Never NULL */
|
||||
const char *input_type; /* May be NULL */
|
||||
const char *output_type; /* Never NULL */
|
||||
};
|
||||
|
||||
DEFINE_STACK_OF(OSSL_ENCODER_INSTANCE)
|
||||
|
||||
void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
|
||||
struct ossl_encoder_ctx_st {
|
||||
/*
|
||||
* The desired output type. The encoder implementation have a gettable
|
||||
* "output-type" parameter that this will match against.
|
||||
*/
|
||||
const char *output_type;
|
||||
/*
|
||||
* Select what parts of an object will be encoded. This selection is
|
||||
* bit encoded, and the bits correspond to selection bits available with
|
||||
* the provider side operation. For example, when encoding an EVP_PKEY,
|
||||
* the OSSL_KEYMGMT_SELECT_ macros are used for this.
|
||||
*/
|
||||
int selection;
|
||||
|
||||
/*-
|
||||
* Output / encoding data, used by OSSL_ENCODER_to_{bio,fp}
|
||||
*
|
||||
* |object| is the libcrypto object to handle.
|
||||
* |do_output| performs the actual encoding.
|
||||
*
|
||||
* |do_output| must have intimate knowledge of |object|.
|
||||
/*
|
||||
* Decoders that are components of any current decoding path.
|
||||
*/
|
||||
const void *object;
|
||||
int (*do_output)(OSSL_ENCODER_CTX *ctx, BIO *out);
|
||||
STACK_OF(OSSL_ENCODER_INSTANCE) *encoder_insts;
|
||||
|
||||
/*
|
||||
* The constructor and destructor of an object to pass to the first
|
||||
* encoder in a chain.
|
||||
*/
|
||||
OSSL_ENCODER_CONSTRUCT *construct;
|
||||
OSSL_ENCODER_CLEANUP *cleanup;
|
||||
void *construct_data;
|
||||
|
||||
/* For any function that needs a passphrase reader */
|
||||
struct ossl_passphrase_data_st pwdata;
|
||||
|
@ -180,6 +180,16 @@ static void *encoder_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
|
||||
encoder->freectx =
|
||||
OSSL_FUNC_encoder_freectx(fns);
|
||||
break;
|
||||
case OSSL_FUNC_ENCODER_GET_PARAMS:
|
||||
if (encoder->get_params == NULL)
|
||||
encoder->get_params =
|
||||
OSSL_FUNC_encoder_get_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_ENCODER_GETTABLE_PARAMS:
|
||||
if (encoder->gettable_params == NULL)
|
||||
encoder->gettable_params =
|
||||
OSSL_FUNC_encoder_gettable_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_ENCODER_SET_CTX_PARAMS:
|
||||
if (encoder->set_ctx_params == NULL)
|
||||
encoder->set_ctx_params =
|
||||
@ -190,26 +200,34 @@ static void *encoder_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
|
||||
encoder->settable_ctx_params =
|
||||
OSSL_FUNC_encoder_settable_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_ENCODER_ENCODE_DATA:
|
||||
if (encoder->encode_data == NULL)
|
||||
encoder->encode_data =
|
||||
OSSL_FUNC_encoder_encode_data(fns);
|
||||
case OSSL_FUNC_ENCODER_ENCODE:
|
||||
if (encoder->encode == NULL)
|
||||
encoder->encode = OSSL_FUNC_encoder_encode(fns);
|
||||
break;
|
||||
case OSSL_FUNC_ENCODER_ENCODE_OBJECT:
|
||||
if (encoder->encode_object == NULL)
|
||||
encoder->encode_object =
|
||||
OSSL_FUNC_encoder_encode_object(fns);
|
||||
case OSSL_FUNC_ENCODER_IMPORT_OBJECT:
|
||||
if (encoder->import_object == NULL)
|
||||
encoder->import_object =
|
||||
OSSL_FUNC_encoder_import_object(fns);
|
||||
break;
|
||||
case OSSL_FUNC_ENCODER_FREE_OBJECT:
|
||||
if (encoder->free_object == NULL)
|
||||
encoder->free_object =
|
||||
OSSL_FUNC_encoder_free_object(fns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Try to check that the method is sensible.
|
||||
* If you have a constructor, you must have a destructor and vice versa.
|
||||
* You must have at least one of the encoding driver functions.
|
||||
* You must have the encoding driver functions.
|
||||
*/
|
||||
if (!((encoder->newctx == NULL && encoder->freectx == NULL)
|
||||
|| (encoder->newctx != NULL && encoder->freectx != NULL))
|
||||
|| (encoder->encode_data == NULL && encoder->encode_object == NULL)) {
|
||||
|| (encoder->newctx != NULL && encoder->freectx != NULL)
|
||||
|| (encoder->import_object != NULL && encoder->free_object != NULL)
|
||||
|| (encoder->import_object == NULL && encoder->free_object == NULL))
|
||||
|| encoder->encode == NULL
|
||||
|| encoder->gettable_params == NULL
|
||||
|| encoder->get_params == NULL) {
|
||||
OSSL_ENCODER_free(encoder);
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
return NULL;
|
||||
@ -440,6 +458,24 @@ void OSSL_ENCODER_names_do_all(const OSSL_ENCODER *encoder,
|
||||
}
|
||||
}
|
||||
|
||||
const OSSL_PARAM *
|
||||
OSSL_ENCODER_gettable_params(OSSL_ENCODER *encoder)
|
||||
{
|
||||
if (encoder != NULL && encoder->gettable_params != NULL) {
|
||||
void *provctx = ossl_provider_ctx(OSSL_ENCODER_provider(encoder));
|
||||
|
||||
return encoder->gettable_params(provctx);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_get_params(OSSL_ENCODER *encoder, OSSL_PARAM params[])
|
||||
{
|
||||
if (encoder != NULL && encoder->get_params != NULL)
|
||||
return encoder->get_params(params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder)
|
||||
{
|
||||
if (encoder != NULL && encoder->settable_ctx_params != NULL) {
|
||||
@ -454,69 +490,51 @@ const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder)
|
||||
* Encoder context support
|
||||
*/
|
||||
|
||||
/*
|
||||
* |encoder| value NULL is valid, and signifies that there is no encoder.
|
||||
* This is useful to provide fallback mechanisms.
|
||||
* Functions that want to verify if there is a encoder can do so with
|
||||
* OSSL_ENCODER_CTX_get_encoder()
|
||||
*/
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(OSSL_ENCODER *encoder)
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(void)
|
||||
{
|
||||
OSSL_ENCODER_CTX *ctx;
|
||||
|
||||
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
|
||||
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->encoder = encoder;
|
||||
if (encoder != NULL && encoder->newctx != NULL) {
|
||||
const OSSL_PROVIDER *prov = OSSL_ENCODER_provider(encoder);
|
||||
void *provctx = ossl_provider_ctx(prov);
|
||||
|
||||
if (OSSL_ENCODER_up_ref(encoder)) {
|
||||
ctx->encoderctx = encoder->newctx(provctx);
|
||||
} else {
|
||||
OSSL_ENCODER_free(encoder);
|
||||
OPENSSL_free(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
const OSSL_ENCODER *
|
||||
OSSL_ENCODER_CTX_get_encoder(OSSL_ENCODER_CTX *ctx)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctx->encoder;
|
||||
}
|
||||
|
||||
|
||||
int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
size_t i;
|
||||
size_t l;
|
||||
|
||||
if (!ossl_assert(ctx != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->encoder != NULL && ctx->encoder->set_ctx_params != NULL)
|
||||
return ctx->encoder->set_ctx_params(ctx->encoderctx, params);
|
||||
return 0;
|
||||
if (ctx->encoder_insts == NULL)
|
||||
return 1;
|
||||
|
||||
l = OSSL_ENCODER_CTX_get_num_encoders(ctx);
|
||||
for (i = 0; i < l; i++) {
|
||||
OSSL_ENCODER_INSTANCE *encoder_inst =
|
||||
sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
|
||||
OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
|
||||
void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
|
||||
|
||||
if (encoderctx == NULL || encoder->set_ctx_params == NULL)
|
||||
continue;
|
||||
if (!encoder->set_ctx_params(encoderctx, params))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx)
|
||||
{
|
||||
if (ctx != NULL) {
|
||||
if (ctx->encoder != NULL && ctx->encoder->freectx != NULL)
|
||||
ctx->encoder->freectx(ctx->encoderctx);
|
||||
OSSL_ENCODER_free(ctx->encoder);
|
||||
sk_OSSL_ENCODER_INSTANCE_pop_free(ctx->encoder_insts,
|
||||
ossl_encoder_instance_free);
|
||||
OPENSSL_free(ctx->construct_data);
|
||||
ossl_pw_clear_passphrase_data(&ctx->pwdata);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "e_os.h" /* strcasecmp on Windows */
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ui.h>
|
||||
#include <openssl/params.h>
|
||||
@ -18,6 +19,8 @@
|
||||
#include "crypto/evp.h"
|
||||
#include "encoder_local.h"
|
||||
|
||||
DEFINE_STACK_OF(OSSL_ENCODER)
|
||||
|
||||
int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
|
||||
const char *cipher_name,
|
||||
const char *propquery)
|
||||
@ -48,28 +51,82 @@ int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
|
||||
return ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data);
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
|
||||
pem_password_cb *cb, void *cbarg)
|
||||
int OSSL_ENCODER_CTX_set_pem_password_cb(OSSL_ENCODER_CTX *ctx,
|
||||
pem_password_cb *cb, void *cbarg)
|
||||
{
|
||||
return ossl_pw_set_pem_password_cb(&ctx->pwdata, cb, cbarg);
|
||||
}
|
||||
|
||||
int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_PASSPHRASE_CALLBACK *cb,
|
||||
void *cbarg)
|
||||
{
|
||||
return ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, cb, cbarg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for OSSL_ENCODER_CTX_new_by_TYPE:
|
||||
* finding a suitable encoder
|
||||
*/
|
||||
|
||||
struct selected_encoder_st {
|
||||
STACK_OF(OPENSSL_CSTRING) *names;
|
||||
int error;
|
||||
struct collected_encoder_st {
|
||||
const char *output_type;
|
||||
STACK_OF(OSSL_ENCODER) *encoders;
|
||||
int error_occured;
|
||||
};
|
||||
|
||||
static void cache_encoders(const char *name, void *data)
|
||||
static void collect_encoder(OSSL_ENCODER *encoder, void *arg)
|
||||
{
|
||||
struct selected_encoder_st *d = data;
|
||||
struct collected_encoder_st *data = arg;
|
||||
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
const char *output_type = NULL;
|
||||
|
||||
if (sk_OPENSSL_CSTRING_push(d->names, name) <= 0)
|
||||
d->error = 1;
|
||||
if (data->error_occured)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Ask for the output type. If the encoder doesn't answer to that,
|
||||
* we refuse it.
|
||||
*/
|
||||
params[0] =
|
||||
OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
|
||||
(char **)&output_type, 0);
|
||||
if (!encoder->get_params(params)
|
||||
|| !OSSL_PARAM_modified(¶ms[0])
|
||||
|| output_type == NULL
|
||||
|| strcasecmp(output_type, data->output_type) != 0)
|
||||
return;
|
||||
|
||||
data->error_occured = 1; /* Assume the worst */
|
||||
|
||||
if (!OSSL_ENCODER_up_ref(encoder) /* ref++ */)
|
||||
return;
|
||||
if (sk_OSSL_ENCODER_push(data->encoders, encoder) <= 0) {
|
||||
OSSL_ENCODER_free(encoder); /* ref-- */
|
||||
return;
|
||||
}
|
||||
|
||||
data->error_occured = 0; /* All is good now */
|
||||
}
|
||||
|
||||
struct collected_names_st {
|
||||
STACK_OF(OPENSSL_CSTRING) *names;
|
||||
unsigned int error_occured:1;
|
||||
};
|
||||
|
||||
static void collect_name(const char *name, void *arg)
|
||||
{
|
||||
struct collected_names_st *data = arg;
|
||||
|
||||
if (data->error_occured)
|
||||
return;
|
||||
|
||||
data->error_occured = 1; /* Assume the worst */
|
||||
|
||||
if (sk_OPENSSL_CSTRING_push(data->names, name) <= 0)
|
||||
return;
|
||||
|
||||
data->error_occured = 0; /* All is good now */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -78,167 +135,224 @@ static void cache_encoders(const char *name, void *data)
|
||||
* intimate knowledge of the provider side object)
|
||||
*/
|
||||
|
||||
struct encoder_write_data_st {
|
||||
OSSL_ENCODER_CTX *ctx;
|
||||
BIO *out;
|
||||
struct construct_data_st {
|
||||
const EVP_PKEY *pk;
|
||||
int selection;
|
||||
|
||||
OSSL_ENCODER_INSTANCE *encoder_inst;
|
||||
const void *obj;
|
||||
void *constructed_obj;
|
||||
};
|
||||
|
||||
static int encoder_write_cb(const OSSL_PARAM params[], void *arg)
|
||||
static int encoder_import_cb(const OSSL_PARAM params[], void *arg)
|
||||
{
|
||||
struct encoder_write_data_st *write_data = arg;
|
||||
OSSL_ENCODER_CTX *ctx = write_data->ctx;
|
||||
BIO *out = write_data->out;
|
||||
struct construct_data_st *construct_data = arg;
|
||||
OSSL_ENCODER_INSTANCE *encoder_inst = construct_data->encoder_inst;
|
||||
OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
|
||||
void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
|
||||
|
||||
return ctx->encoder->encode_data(ctx->encoderctx, params,
|
||||
(OSSL_CORE_BIO *)out,
|
||||
ossl_pw_passphrase_callback_enc,
|
||||
&ctx->pwdata);
|
||||
construct_data->constructed_obj =
|
||||
encoder->import_object(encoderctx, construct_data->selection, params);
|
||||
|
||||
return (construct_data->constructed_obj != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for OSSL_ENCODER_to_bio:
|
||||
* Perform the actual output.
|
||||
*/
|
||||
|
||||
static int encoder_EVP_PKEY_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
|
||||
static const void *
|
||||
encoder_construct_EVP_PKEY(OSSL_ENCODER_INSTANCE *encoder_inst, void *arg)
|
||||
{
|
||||
const EVP_PKEY *pkey = ctx->object;
|
||||
void *keydata = pkey->keydata;
|
||||
EVP_KEYMGMT *keymgmt = pkey->keymgmt;
|
||||
struct construct_data_st *data = arg;
|
||||
|
||||
/*
|
||||
* OSSL_ENCODER_CTX_new() creates a context, even when the
|
||||
* encoder it's given is NULL. Callers can detect the lack
|
||||
* of encoder with OSSL_ENCODER_CTX_get_encoder() and
|
||||
* should take precautions, possibly call a fallback instead of
|
||||
* OSSL_ENCODER_to_bio() / OSSL_ENCODER_to_fp(). If it's
|
||||
* come this far, we return an error.
|
||||
*/
|
||||
if (ctx->encoder == NULL)
|
||||
return 0;
|
||||
if (data->obj == NULL) {
|
||||
OSSL_ENCODER *encoder =
|
||||
OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
|
||||
const EVP_PKEY *pk = data->pk;
|
||||
const OSSL_PROVIDER *k_prov = EVP_KEYMGMT_provider(pk->keymgmt);
|
||||
const OSSL_PROVIDER *e_prov = OSSL_ENCODER_provider(encoder);
|
||||
|
||||
if (ctx->encoder->encode_object == NULL
|
||||
|| (OSSL_ENCODER_provider(ctx->encoder)
|
||||
!= EVP_KEYMGMT_provider(keymgmt))) {
|
||||
struct encoder_write_data_st write_data;
|
||||
if (k_prov != e_prov) {
|
||||
data->encoder_inst = encoder_inst;
|
||||
|
||||
write_data.ctx = ctx;
|
||||
write_data.out = out;
|
||||
|
||||
return evp_keymgmt_export(keymgmt, keydata, ctx->selection,
|
||||
&encoder_write_cb, &write_data);
|
||||
if (!evp_keymgmt_export(pk->keymgmt, pk->keydata, data->selection,
|
||||
&encoder_import_cb, data))
|
||||
return NULL;
|
||||
data->obj = data->constructed_obj;
|
||||
} else {
|
||||
data->obj = pk->keydata;
|
||||
}
|
||||
}
|
||||
|
||||
return ctx->encoder->encode_object(ctx->encoderctx, keydata,
|
||||
(OSSL_CORE_BIO *)out,
|
||||
ossl_pw_passphrase_callback_enc,
|
||||
&ctx->pwdata);
|
||||
return data->obj;
|
||||
}
|
||||
|
||||
static void encoder_destruct_EVP_PKEY(void *arg)
|
||||
{
|
||||
struct construct_data_st *data = arg;
|
||||
|
||||
if (data->encoder_inst != NULL) {
|
||||
OSSL_ENCODER *encoder =
|
||||
OSSL_ENCODER_INSTANCE_get_encoder(data->encoder_inst);
|
||||
|
||||
encoder->free_object(data->constructed_obj);
|
||||
}
|
||||
data->constructed_obj = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* OSSL_ENCODER_CTX_new_by_EVP_PKEY() returns a ctx with no encoder if
|
||||
* it couldn't find a suitable encoder. This allows a caller to detect if
|
||||
* a suitable encoder was found, with OSSL_ENCODER_CTX_get_encoder(),
|
||||
* a suitable encoder was found, with OSSL_ENCODER_CTX_get_num_encoder(),
|
||||
* and to use fallback methods if the result is NULL.
|
||||
*/
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
|
||||
const char *propquery)
|
||||
static int ossl_encoder_ctx_setup_for_EVP_PKEY(OSSL_ENCODER_CTX *ctx,
|
||||
const EVP_PKEY *pkey,
|
||||
int selection,
|
||||
OPENSSL_CTX *libctx,
|
||||
const char *propquery)
|
||||
{
|
||||
OSSL_ENCODER_CTX *ctx = NULL;
|
||||
OSSL_ENCODER *encoder = NULL;
|
||||
EVP_KEYMGMT *keymgmt = pkey->keymgmt;
|
||||
int selection = OSSL_KEYMGMT_SELECT_ALL;
|
||||
struct construct_data_st *data = NULL;
|
||||
int ok = 0;
|
||||
|
||||
if (!ossl_assert(pkey != NULL && propquery != NULL)) {
|
||||
if (!ossl_assert(ctx != NULL) || !ossl_assert(pkey != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (keymgmt != NULL) {
|
||||
const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(keymgmt);
|
||||
OPENSSL_CTX *libctx = ossl_provider_library_context(desired_prov);
|
||||
struct selected_encoder_st sel_data;
|
||||
OSSL_ENCODER *first = NULL;
|
||||
const char *name;
|
||||
if (pkey->keymgmt != NULL) {
|
||||
OSSL_ENCODER *found = NULL;
|
||||
const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(pkey->keymgmt);
|
||||
struct collected_encoder_st encoder_data;
|
||||
struct collected_names_st keymgmt_data;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Select the encoder in two steps. First, get the names of all of
|
||||
* the encoders. Then determine which is the best one to use.
|
||||
* This has to be broken because it isn't possible to fetch the
|
||||
* encoders inside EVP_KEYMGMT_names_do_all() due to locking order
|
||||
* inversions with the store lock.
|
||||
*/
|
||||
sel_data.error = 0;
|
||||
sel_data.names = sk_OPENSSL_CSTRING_new_null();
|
||||
if (sel_data.names == NULL)
|
||||
return NULL;
|
||||
EVP_KEYMGMT_names_do_all(keymgmt, cache_encoders, &sel_data);
|
||||
/*
|
||||
* Ignore memory allocation errors that are indicated in sel_data.error
|
||||
* in case a suitable provider does get found regardless.
|
||||
*/
|
||||
if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encoders offer two functions, one that handles object data in
|
||||
* the form of a OSSL_PARAM array, and one that directly handles a
|
||||
* provider side object. The latter requires that the encoder
|
||||
* is offered by the same provider that holds that object, but is
|
||||
* more desirable because it usually provides faster encoding.
|
||||
*
|
||||
* When looking up possible encoders, we save the first that can
|
||||
* handle an OSSL_PARAM array in |first| and use that if nothing
|
||||
* better turns up.
|
||||
* Select the encoder in two steps. First, collect all encoders
|
||||
* that have the correct output type, as well as all keymgmt names.
|
||||
*/
|
||||
for (i = 0; i < sk_OPENSSL_CSTRING_num(sel_data.names); i++) {
|
||||
name = sk_OPENSSL_CSTRING_value(sel_data.names, i);
|
||||
encoder = OSSL_ENCODER_fetch(libctx, name, propquery);
|
||||
if (encoder != NULL) {
|
||||
if (OSSL_ENCODER_provider(encoder) == desired_prov
|
||||
&& encoder->encode_object != NULL) {
|
||||
OSSL_ENCODER_free(first);
|
||||
encoder_data.output_type = ctx->output_type;
|
||||
encoder_data.encoders = sk_OSSL_ENCODER_new_null();
|
||||
encoder_data.error_occured = 0;
|
||||
keymgmt_data.names = sk_OPENSSL_CSTRING_new_null();
|
||||
keymgmt_data.error_occured = 0;
|
||||
if (encoder_data.encoders == NULL || keymgmt_data.names == NULL) {
|
||||
sk_OSSL_ENCODER_free(encoder_data.encoders);
|
||||
sk_OPENSSL_CSTRING_free(keymgmt_data.names);
|
||||
return 0;
|
||||
}
|
||||
OSSL_ENCODER_do_all_provided(libctx, collect_encoder, &encoder_data);
|
||||
EVP_KEYMGMT_names_do_all(pkey->keymgmt, collect_name, &keymgmt_data);
|
||||
|
||||
/*-
|
||||
* Now we look for the most desirable encoder for our |pkey|.
|
||||
*
|
||||
* Encoders offer two functions:
|
||||
*
|
||||
* - one ('encode') that encodes a given provider-native object that
|
||||
* it knows intimately, so it must be from the same provider.
|
||||
* - one ('import_object') that imports the parameters of an object
|
||||
* of the same type from a different provider, which is used to
|
||||
* create a temporary object that 'encode' can handle.
|
||||
*
|
||||
* It is, of course, more desirable to be able to use 'encode'
|
||||
* directly without having to go through an export/import maneuver,
|
||||
* but the latter allows us to have generic encoders.
|
||||
*
|
||||
* Of course, if |libctx| is different from |pkey|'s library context,
|
||||
* we're going to have to do an export/import maneuvre no matter what.
|
||||
*/
|
||||
for (i = 0; i < sk_OSSL_ENCODER_num(encoder_data.encoders); i++) {
|
||||
OSSL_ENCODER *encoder =
|
||||
sk_OSSL_ENCODER_value(encoder_data.encoders, i);
|
||||
int j;
|
||||
|
||||
/* Check that any of the |keymgmt| names match */
|
||||
for (j = 0; j < sk_OPENSSL_CSTRING_num(keymgmt_data.names); j++) {
|
||||
const char *name =
|
||||
sk_OPENSSL_CSTRING_value(keymgmt_data.names, j);
|
||||
|
||||
if (OSSL_ENCODER_is_a(encoder, name))
|
||||
break;
|
||||
}
|
||||
if (first == NULL && encoder->encode_data != NULL)
|
||||
first = encoder;
|
||||
else
|
||||
OSSL_ENCODER_free(encoder);
|
||||
encoder = NULL;
|
||||
}
|
||||
|
||||
if (j == sk_OPENSSL_CSTRING_num(keymgmt_data.names))
|
||||
continue;
|
||||
|
||||
/* We found one! Process it */
|
||||
if (OSSL_ENCODER_provider(encoder) == desired_prov) {
|
||||
/*
|
||||
* We found one in the same provider as the keymgmt. Choose
|
||||
* it and stop looking.
|
||||
*/
|
||||
found = encoder;
|
||||
break;
|
||||
}
|
||||
if (found == NULL && encoder->import_object != NULL) {
|
||||
/*
|
||||
* We found one that's good enough. Choose it for now, but
|
||||
* keep looking.
|
||||
*/
|
||||
found = encoder;
|
||||
}
|
||||
}
|
||||
sk_OPENSSL_CSTRING_free(sel_data.names);
|
||||
if (encoder == NULL)
|
||||
encoder = first;
|
||||
|
||||
if (encoder != NULL) {
|
||||
OSSL_PROPERTY_LIST *check = NULL, *current_props = NULL;
|
||||
|
||||
check = ossl_parse_query(libctx, "type=parameters");
|
||||
current_props =
|
||||
ossl_parse_property(libctx, OSSL_ENCODER_properties(encoder));
|
||||
if (ossl_property_match_count(check, current_props) > 0)
|
||||
selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS;
|
||||
ossl_property_free(current_props);
|
||||
ossl_property_free(check);
|
||||
if (found != NULL) {
|
||||
(void)OSSL_ENCODER_CTX_add_encoder(ctx, found);
|
||||
} else {
|
||||
if (sel_data.error)
|
||||
if (encoder_data.error_occured)
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
||||
else
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER,
|
||||
OSSL_ENCODER_R_ENCODER_NOT_FOUND);
|
||||
}
|
||||
|
||||
sk_OPENSSL_CSTRING_free(keymgmt_data.names);
|
||||
sk_OSSL_ENCODER_pop_free(encoder_data.encoders, OSSL_ENCODER_free);
|
||||
}
|
||||
|
||||
ctx = OSSL_ENCODER_CTX_new(encoder); /* refcnt(encoder)++ */
|
||||
OSSL_ENCODER_free(encoder); /* refcnt(encoder)-- */
|
||||
if (OSSL_ENCODER_CTX_get_num_encoders(ctx) != 0) {
|
||||
if (!OSSL_ENCODER_CTX_set_construct(ctx, encoder_construct_EVP_PKEY)
|
||||
|| !OSSL_ENCODER_CTX_set_construct_data(ctx, data)
|
||||
|| !OSSL_ENCODER_CTX_set_cleanup(ctx, encoder_destruct_EVP_PKEY))
|
||||
goto err;
|
||||
|
||||
if (ctx != NULL) {
|
||||
/* Setup for OSSL_ENCODE_to_bio() */
|
||||
ctx->selection = selection;
|
||||
ctx->object = pkey;
|
||||
ctx->do_output = encoder_EVP_PKEY_to_bio;
|
||||
data->pk = pkey;
|
||||
data->selection = selection;
|
||||
|
||||
data = NULL; /* Avoid it being freed */
|
||||
}
|
||||
|
||||
return ctx;
|
||||
ok = 1;
|
||||
err:
|
||||
if (data != NULL) {
|
||||
OSSL_ENCODER_CTX_set_construct_data(ctx, NULL);
|
||||
OPENSSL_free(data);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
|
||||
const char *output_type,
|
||||
int selection,
|
||||
OPENSSL_CTX *libctx,
|
||||
const char *propquery)
|
||||
{
|
||||
OSSL_ENCODER_CTX *ctx = NULL;
|
||||
|
||||
if ((ctx = OSSL_ENCODER_CTX_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
if (OSSL_ENCODER_CTX_set_output_type(ctx, output_type)
|
||||
&& OSSL_ENCODER_CTX_set_selection(ctx, selection)
|
||||
&& ossl_encoder_ctx_setup_for_EVP_PKEY(ctx, pkey, selection,
|
||||
libctx, propquery)
|
||||
&& OSSL_ENCODER_CTX_add_extra(ctx, libctx, propquery))
|
||||
return ctx;
|
||||
|
||||
OSSL_ENCODER_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ L OSSL_STORE include/openssl/store.h crypto/store/store_err.c
|
||||
L ESS include/openssl/ess.h crypto/ess/ess_err.c
|
||||
L PROP include/internal/property.h crypto/property/property_err.c
|
||||
L PROV providers/common/include/prov/providercommon.h providers/common/provider_err.c
|
||||
L OSSL_ENCODER include/openssl/encoder.h crypto/encoder/encoder_err.c
|
||||
L OSSL_DECODER include/openssl/decoder.h crypto/encoder/decoder_err.c
|
||||
L OSSL_ENCODER include/openssl/encoder.h crypto/encode_decode/encoder_err.c
|
||||
L OSSL_DECODER include/openssl/decoder.h crypto/encode_decode/decoder_err.c
|
||||
L HTTP include/openssl/http.h crypto/http/http_err.c
|
||||
|
||||
# additional header files to be scanned for function names
|
||||
|
@ -2712,6 +2712,7 @@ OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type
|
||||
OSSL_DECODER_R_MISSING_GET_PARAMS:100:missing get params
|
||||
OSSL_ENCODER_R_ENCODER_NOT_FOUND:101:encoder not found
|
||||
OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY:100:incorrect property query
|
||||
OSSL_ENCODER_R_MISSING_GET_PARAMS:102:missing get params
|
||||
OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type
|
||||
OSSL_STORE_R_BAD_PASSWORD_READ:115:bad password read
|
||||
OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC:113:error verifying pkcs12 mac
|
||||
|
@ -11,7 +11,9 @@ OSSL_ENCODER_properties,
|
||||
OSSL_ENCODER_is_a,
|
||||
OSSL_ENCODER_number,
|
||||
OSSL_ENCODER_do_all_provided,
|
||||
OSSL_ENCODER_names_do_all
|
||||
OSSL_ENCODER_names_do_all,
|
||||
OSSL_ENCODER_gettable_params,
|
||||
OSSL_ENCODER_get_params
|
||||
- Encoder method routines
|
||||
|
||||
=head1 SYNOPSIS
|
||||
@ -34,11 +36,11 @@ OSSL_ENCODER_names_do_all
|
||||
void OSSL_ENCODER_names_do_all(const OSSL_ENCODER *encoder,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data);
|
||||
const OSSL_PARAM *OSSL_ENCODER_gettable_params(OSSL_ENCODER *encoder);
|
||||
int OSSL_ENCODER_get_params(OSSL_ENCODER_CTX *ctx, const OSSL_PARAM params[]);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
=for comment Future development should also talk about decoding
|
||||
|
||||
B<OSSL_ENCODER> is a method for encoders, which know how to
|
||||
encode an object of some kind to a encoded form, such as PEM,
|
||||
DER, or even human readable text.
|
||||
@ -78,6 +80,13 @@ implementations by all activated providers in the library context
|
||||
I<libctx>, and for each of the implementations, calls I<fn> with the
|
||||
implementation method and I<data> as arguments.
|
||||
|
||||
OSSL_ENCODER_gettable_params() returns an L<OSSL_PARAM(3)>
|
||||
array of parameter descriptors.
|
||||
|
||||
OSSL_ENCODER_get_params() attempts to get parameters specified
|
||||
with an L<OSSL_PARAM(3)> array I<params>. Parameters that the
|
||||
implementation doesn't recognise should be ignored.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
OSSL_ENCODER_fetch() may be called implicitly by other fetching
|
||||
|
@ -4,10 +4,24 @@
|
||||
|
||||
OSSL_ENCODER_CTX,
|
||||
OSSL_ENCODER_CTX_new,
|
||||
OSSL_ENCODER_CTX_get_encoder,
|
||||
OSSL_ENCODER_settable_ctx_params,
|
||||
OSSL_ENCODER_CTX_set_params,
|
||||
OSSL_ENCODER_CTX_free
|
||||
OSSL_ENCODER_CTX_free,
|
||||
OSSL_ENCODER_CTX_set_output_type,
|
||||
OSSL_ENCODER_CTX_set_selection,
|
||||
OSSL_ENCODER_CTX_add_encoder,
|
||||
OSSL_ENCODER_CTX_add_extra,
|
||||
OSSL_ENCODER_CTX_get_num_encoders,
|
||||
OSSL_ENCODER_INSTANCE,
|
||||
OSSL_ENCODER_INSTANCE_get_encoder,
|
||||
OSSL_ENCODER_INSTANCE_get_encoder_ctx,
|
||||
OSSL_ENCODER_INSTANCE_get_input_type,
|
||||
OSSL_ENCODER_INSTANCE_get_output_type,
|
||||
OSSL_ENCODER_CONSTRUCT,
|
||||
OSSL_ENCODER_CLEANUP,
|
||||
OSSL_ENCODER_CTX_set_construct,
|
||||
OSSL_ENCODER_CTX_set_construct_data,
|
||||
OSSL_ENCODER_CTX_set_cleanup
|
||||
- Encoder context routines
|
||||
|
||||
=head1 SYNOPSIS
|
||||
@ -16,36 +30,66 @@ OSSL_ENCODER_CTX_free
|
||||
|
||||
typedef struct ossl_encoder_ctx_st OSSL_ENCODER_CTX;
|
||||
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(OSSL_ENCODER *encoder);
|
||||
const OSSL_ENCODER *OSSL_ENCODER_CTX_get_encoder(OSSL_ENCODER_CTX *ctx);
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new();
|
||||
const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder);
|
||||
int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
|
||||
const OSSL_PARAM params[]);
|
||||
void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx);
|
||||
|
||||
int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
|
||||
const char *output_type);
|
||||
int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection);
|
||||
|
||||
int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder);
|
||||
int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
|
||||
OPENSSL_CTX *libctx, const char *propq);
|
||||
int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx);
|
||||
|
||||
typedef struct ossl_encoder_instance_st OSSL_ENCODER_INSTANCE;
|
||||
OSSL_ENCODER *
|
||||
OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
void *
|
||||
OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
const char *
|
||||
OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
const char *
|
||||
OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
|
||||
typedef const void *OSSL_ENCODER_CONSTRUCT(OSSL_ENCODER_INSTANCE *encoder_inst,
|
||||
void *construct_data);
|
||||
typedef void OSSL_ENCODER_CLEANUP(void *construct_data);
|
||||
|
||||
int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_ENCODER_CONSTRUCT *construct);
|
||||
int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
|
||||
void *construct_data);
|
||||
int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_ENCODER_CLEANUP *cleanup);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<OSSL_ENCODER_CTX> is a context with which B<OSSL_ENCODER>
|
||||
operations are performed. The context typically holds values, both
|
||||
internal and supplied by the application, which are useful for the
|
||||
implementations supplied by providers.
|
||||
Encoding an input object to the desired encoding may be done with a chain of
|
||||
encoder implementations, which means that the output from one encoder may be
|
||||
the input for the next in the chain. The B<OSSL_ENCODER_CTX> holds all the
|
||||
data about these encoders. This allows having generic format encoders such
|
||||
as DER to PEM, as well as more specialized encoders like RSA to DER.
|
||||
|
||||
OSSL_ENCODER_CTX_new() creates a B<OSSL_ENCODER_CTX> associated
|
||||
with the encoder I<encoder>. NULL is a valid I<encoder>, the context will
|
||||
be created anyway, it's just not very useful. This is intentional, to
|
||||
distinguish between errors in allocating the context or assigning it
|
||||
values on one hand, and the lack of encoder support on the other.
|
||||
The final output type must be given, and a chain of encoders must end with
|
||||
an implementation that produces that output type.
|
||||
|
||||
=begin comment
|
||||
At the beginning of the encoding process, a contructor provided by the
|
||||
caller is called to ensure that there is an appropriate provider-side object
|
||||
to start with.
|
||||
The constructor is set with OSSL_ENCODER_CTX_set_construct().
|
||||
|
||||
The above distinction makes it possible for other routines to sense if
|
||||
they need to report an error or fall back on other methods to
|
||||
encode.
|
||||
B<OSSL_ENCODER_INSTANCE> is an opaque structure that contains data about the
|
||||
encoder that is going to be used, and that may be useful for the
|
||||
constructor. There are some functions to extract data from this type,
|
||||
described in L</Constructor> below.
|
||||
|
||||
=end comment
|
||||
=head2 Functions
|
||||
|
||||
OSSL_ENCODER_CTX_get_encoder() gets the encoder method
|
||||
currently associated with the context I<ctx>.
|
||||
OSSL_ENCODER_CTX_new() creates a B<OSSL_ENCODER_CTX>.
|
||||
|
||||
OSSL_ENCODER_settable_ctx_params() returns an L<OSSL_PARAM(3)>
|
||||
array of parameter descriptors.
|
||||
@ -56,22 +100,93 @@ implementation doesn't recognise should be ignored.
|
||||
|
||||
OSSL_ENCODER_CTX_free() frees the given context I<ctx>.
|
||||
|
||||
OSSL_ENCODER_CTX_add_encoder() populates the B<OSSL_ENCODER_CTX>
|
||||
I<ctx> with a encoder, to be used to encode an input object.
|
||||
|
||||
OSSL_ENCODER_CTX_add_extra() finds encoders that further encodes output
|
||||
from already added encoders, and adds them as well. This is used to build
|
||||
encoder chains.
|
||||
|
||||
OSSL_ENCODER_CTX_set_output_type() sets the ending output type. This must
|
||||
be specified, and determines if a complete encoder chain is available.
|
||||
|
||||
OSSL_ENCODER_CTX_num_encoders() gets the number of encoders currently added
|
||||
to the context I<ctx>.
|
||||
|
||||
OSSL_ENCODER_CTX_set_construct() sets the constructor I<construct>.
|
||||
|
||||
OSSL_ENCODER_CTX_set_construct_data() sets the constructor data that is
|
||||
passed to the constructor every time it's called.
|
||||
|
||||
OSSL_ENCODER_CTX_set_cleanup() sets the constructor data I<cleanup>
|
||||
function. This is called by L<OSSL_ENCODER_CTX_free(3)>.
|
||||
|
||||
=head2 Constructor
|
||||
|
||||
A B<OSSL_ENCODER_CONSTRUCT> gets the following arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
=item I<encoder_inst>
|
||||
|
||||
The B<OSSL_ENCODER_INSTANCE> for the encoder from which the constructor gets
|
||||
its data.
|
||||
|
||||
=item I<construct_data>
|
||||
|
||||
The pointer that was set with OSSL_ENCODE_CTX_set_construct_data().
|
||||
|
||||
=back
|
||||
|
||||
The constructor is expected to return a valid (non-NULL) pointer to a
|
||||
provider-native object that can be used as first input of an encoding chain,
|
||||
or NULL to indicate that an error has occured.
|
||||
|
||||
These utility functions may be used by a constructor:
|
||||
|
||||
OSSL_ENCODER_INSTANCE_encoder() can be used to get the encoder method from a
|
||||
encoder instance I<encoder_inst>.
|
||||
|
||||
OSSL_ENCODER_INSTANCE_encoder_ctx() can be used to get the encoder method's
|
||||
provider context from a encoder instance I<encoder_inst>.
|
||||
|
||||
OSSL_ENCODER_INSTANCE_input_type() can be used to get the input type for
|
||||
encoder method from a encoder instance I<encoder_inst>. This may be NULL.
|
||||
|
||||
OSSL_ENCODER_INSTANCE_output_type() can be used to get the output type for
|
||||
encoder method from a encoder instance I<encoder_inst>. This will never be
|
||||
NULL.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
OSSL_ENCODER_CTX_new() returns a pointer to a
|
||||
B<OSSL_ENCODER_CTX>, or NULL if the context structure couldn't be
|
||||
allocated.
|
||||
OSSL_ENCODER_CTX_new() returns a pointer to a B<OSSL_ENCODER_CTX>, or NULL
|
||||
if the context structure couldn't be allocated.
|
||||
|
||||
OSSL_ENCODER_CTX_get_encoder() returns a pointer to the
|
||||
encoder method associated with I<ctx>. NULL is a valid return
|
||||
value and signifies that there is no associated encoder method.
|
||||
OSSL_ENCODER_settable_ctx_params() returns an L<OSSL_PARAM(3)> array, or
|
||||
NULL if none is available.
|
||||
|
||||
OSSL_ENCODER_settable_ctx_params() returns an L<OSSL_PARAM(3)>
|
||||
array, or NULL if none is available.
|
||||
OSSL_ENCODER_CTX_set_params() returns 1 if all recognised parameters were
|
||||
valid, or 0 if one of them was invalid or caused some other failure in the
|
||||
implementation.
|
||||
|
||||
OSSL_ENCODER_CTX_set_params() returns 1 if all recognised
|
||||
parameters were valid, or 0 if one of them was invalid or caused some
|
||||
other failure in the implementation.
|
||||
OSSL_DECODER_CTX_add_decoder(), OSSL_DECODER_CTX_add_extra(),
|
||||
OSSL_DECODER_CTX_set_construct(), OSSL_DECODER_CTX_set_construct_data() and
|
||||
OSSL_DECODER_CTX_set_cleanup() return 1 on success, or 0 on failure.
|
||||
|
||||
OSSL_DECODER_CTX_num_decoders() returns the current number of decoders. It
|
||||
returns 0 if I<ctx> is NULL.
|
||||
|
||||
OSSL_DECODER_INSTANCE_decoder() returns an B<OSSL_DECODER> pointer on
|
||||
success, or NULL on failure.
|
||||
|
||||
OSSL_DECODER_INSTANCE_decoder_ctx() returns a provider context pointer on
|
||||
success, or NULL on failure.
|
||||
|
||||
OSSL_ENCODER_INSTANCE_input_type() returns a string with the name of the
|
||||
input type, if relevant. NULL is a valid returned value.
|
||||
|
||||
OSSL_ENCODER_INSTANCE_output_type() returns a string with the name of the
|
||||
output type.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@ -5,25 +5,19 @@
|
||||
OSSL_ENCODER_CTX_new_by_EVP_PKEY,
|
||||
OSSL_ENCODER_CTX_set_cipher,
|
||||
OSSL_ENCODER_CTX_set_passphrase,
|
||||
OSSL_ENCODER_CTX_set_pem_password_cb,
|
||||
OSSL_ENCODER_CTX_set_passphrase_cb,
|
||||
OSSL_ENCODER_CTX_set_passphrase_ui,
|
||||
OSSL_ENCODER_PUBKEY_TO_PEM_PQ,
|
||||
OSSL_ENCODER_PrivateKey_TO_PEM_PQ,
|
||||
OSSL_ENCODER_Parameters_TO_PEM_PQ,
|
||||
OSSL_ENCODER_PUBKEY_TO_DER_PQ,
|
||||
OSSL_ENCODER_PrivateKey_TO_DER_PQ,
|
||||
OSSL_ENCODER_Parameters_TO_DER_PQ,
|
||||
OSSL_ENCODER_PUBKEY_TO_TEXT_PQ,
|
||||
OSSL_ENCODER_PrivateKey_TO_TEXT_PQ,
|
||||
OSSL_ENCODER_Parameters_TO_TEXT_PQ
|
||||
OSSL_ENCODER_CTX_set_passphrase_ui
|
||||
- Encoder routines to encode EVP_PKEYs
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
#include <openssl/encoder.h>
|
||||
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
|
||||
const char *propquery);
|
||||
OSSL_ENCODER_CTX *
|
||||
OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
|
||||
const char *output_type, int selection,
|
||||
OPENSSL_CTX *libctx, const char *propquery);
|
||||
|
||||
int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
|
||||
const char *cipher_name,
|
||||
@ -31,45 +25,39 @@ OSSL_ENCODER_Parameters_TO_TEXT_PQ
|
||||
int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX *ctx,
|
||||
const unsigned char *kstr,
|
||||
size_t klen);
|
||||
int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
|
||||
pem_password_cb *cb, void *cbarg);
|
||||
int OSSL_ENCODER_CTX_set_pem_password_cb(OSSL_ENCODER_CTX *ctx,
|
||||
pem_password_cb *cb, void *cbarg);
|
||||
int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data);
|
||||
|
||||
#define OSSL_ENCODER_PUBKEY_TO_PEM_PQ "format=pem,type=public"
|
||||
#define OSSL_ENCODER_PrivateKey_TO_PEM_PQ "format=pem,type=private"
|
||||
#define OSSL_ENCODER_Parameters_TO_PEM_PQ "format=pem,type=parameters"
|
||||
|
||||
#define OSSL_ENCODER_PUBKEY_TO_DER_PQ "format=der,type=public"
|
||||
#define OSSL_ENCODER_PrivateKey_TO_DER_PQ "format=der,type=private"
|
||||
#define OSSL_ENCODER_Parameters_TO_DER_PQ "format=der,type=parameters"
|
||||
|
||||
#define OSSL_ENCODER_PUBKEY_TO_TEXT_PQ "format=text,type=public"
|
||||
#define OSSL_ENCODER_PrivateKey_TO_TEXT_PQ "format=text,type=private"
|
||||
#define OSSL_ENCODER_Parameters_TO_TEXT_PQ "format=text,type=parameters"
|
||||
int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_PASSPHRASE_CALLBACK *cb,
|
||||
void *cbarg);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
OSSL_ENCODER_CTX_new_by_EVP_PKEY() creates a B<OSSL_ENCODER_CTX>
|
||||
with a suitable attached output routine for B<EVP_PKEY>s. It will
|
||||
search for a encoder implementation that matches the algorithm of
|
||||
the B<EVP_PKEY> and the property query given with I<propquery>. It
|
||||
will prefer to find a encoder from the same provider as the key
|
||||
data of the B<EVP_PKEY> itself, but failing that, it will choose the
|
||||
first encoder that supplies a generic encoding function.
|
||||
OSSL_ENCODER_CTX_new_by_EVP_PKEY() is a utility function that creates a
|
||||
B<OSSL_ENCODER_CTX>, finds all applicable encoder implementations and sets
|
||||
them up, so almost all the caller has to do next is call functions like
|
||||
L<OSSL_ENCODER_to_bio(3)>.
|
||||
|
||||
If no suitable encoder was found, OSSL_ENCODER_CTX_new_by_EVP_PKEY()
|
||||
still creates a B<OSSL_ENCODER_CTX>, but with no associated
|
||||
encoder (L<OSSL_ENCODER_CTX_get_encoder(3)> returns NULL).
|
||||
This helps the caller distinguish between an error when creating
|
||||
the B<OSSL_ENCODER_CTX>, and the lack the encoder support and
|
||||
Internally, OSSL_ENCODER_CTX_new_by_EVP_PKEY() uses the names from the
|
||||
L<EVP_KEYMGMT(3)> implementation associated with I<pkey> to build a list of
|
||||
applicable encoder implementations that are used to process the I<pkey> into
|
||||
the encoding named by I<output_type>. All these implementations are
|
||||
implicitly fetched using I<libctx> and I<propquery>.
|
||||
|
||||
If no suitable encoder implementation is found,
|
||||
OSSL_ENCODER_CTX_new_by_EVP_PKEY() still creates a B<OSSL_ENCODER_CTX>, but
|
||||
with no associated encoder (L<OSSL_ENCODER_CTX_get_num_encoders(3)> returns
|
||||
zero). This helps the caller to distinguish between an error when creating
|
||||
the B<OSSL_ENCODER_CTX> and missing encoder implementation, and allows it to
|
||||
act accordingly.
|
||||
|
||||
OSSL_ENCODER_CTX_set_cipher() tells the implementation what cipher
|
||||
should be used to encrypt encoded keys. The cipher is given by
|
||||
name I<cipher_name>. The interpretation of that I<cipher_name> is
|
||||
implementation dependent. The implementation may implement the digest
|
||||
implementation dependent. The implementation may implement the cipher
|
||||
directly itself or by other implementations, or it may choose to fetch
|
||||
it. If the implementation supports fetching the cipher, then it may
|
||||
use I<propquery> as properties to be queried for when fetching.
|
||||
@ -81,48 +69,30 @@ pass phrase to use when encrypting the encoded private key.
|
||||
Alternatively, a pass phrase callback may be specified with the
|
||||
following functions.
|
||||
|
||||
OSSL_ENCODER_CTX_set_passphrase_cb() and
|
||||
OSSL_ENCODER_CTX_set_passphrase_ui() sets up a callback method that
|
||||
the implementation can use to prompt for a pass phrase.
|
||||
|
||||
=for comment Note that the callback method is called indirectly,
|
||||
OSSL_ENCODER_CTX_set_pem_password_cb(), OSSL_ENCODER_CTX_set_passphrase_ui()
|
||||
and OSSL_ENCODER_CTX_set_passphrase_cb() sets up a callback method that the
|
||||
implementation can use to prompt for a pass phrase, giving the caller the
|
||||
choice of prefered pass phrase callback form. These are called indirectly,
|
||||
through an internal B<OSSL_PASSPHRASE_CALLBACK> function.
|
||||
|
||||
The macros B<OSSL_ENCODER_PUBKEY_TO_PEM_PQ>,
|
||||
B<OSSL_ENCODER_PrivateKey_TO_PEM_PQ>,
|
||||
B<OSSL_ENCODER_Parameters_TO_PEM_PQ>,
|
||||
B<OSSL_ENCODER_PUBKEY_TO_DER_PQ>,
|
||||
B<OSSL_ENCODER_PrivateKey_TO_DER_PQ>,
|
||||
B<OSSL_ENCODER_Parameters_TO_DER_PQ>,
|
||||
B<OSSL_ENCODER_PUBKEY_TO_TEXT_PQ>,
|
||||
B<OSSL_ENCODER_PrivateKey_TO_TEXT_PQ>,
|
||||
B<OSSL_ENCODER_Parameters_TO_TEXT_PQ> are convenience macros with
|
||||
property queries to encode the B<EVP_PKEY> as a public key, private
|
||||
key or parameters to B<PEM>, to B<DER>, or to text.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
OSSL_ENCODER_CTX_new_by_EVP_PKEY() returns a pointer to a
|
||||
B<OSSL_ENCODER_CTX>, or NULL if it couldn't be created.
|
||||
|
||||
OSSL_ENCODER_CTX_set_cipher(),
|
||||
OSSL_ENCODER_CTX_set_passphrase(),
|
||||
OSSL_ENCODER_CTX_set_passphrase_cb(), and
|
||||
OSSL_ENCODER_CTX_set_passphrase_ui() all return 1 on success, or 0
|
||||
on failure.
|
||||
OSSL_ENCODER_CTX_set_cipher(), OSSL_ENCODER_CTX_set_passphrase(),
|
||||
OSSL_ENCODER_CTX_set_pem_password_cb(), OSSL_ENCODER_CTX_set_passphrase_ui()
|
||||
and OSSL_ENCODER_CTX_set_passphrase_cb() all return 1 on success, or 0 on
|
||||
failure.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
Parts of the function and macro names are made to match already
|
||||
existing OpenSSL names.
|
||||
Parts of the function names are made to match already existing OpenSSL
|
||||
names.
|
||||
|
||||
B<EVP_PKEY> in OSSL_ENCODER_CTX_new_by_EVP_PKEY() matches the type
|
||||
name, thus making for the naming pattern
|
||||
B<OSSL_ENCODER_CTX_new_by_I<TYPE>>() when new types are handled.
|
||||
|
||||
B<PUBKEY>, B<PrivateKey> and B<Parameters> in the macro names match
|
||||
the B<I<TYPE>> part of B<PEM_write_bio_I<TYPE>> functions as well
|
||||
as B<i2d_I<TYPE>_bio> functions.
|
||||
B<EVP_PKEY> in OSSL_ENCODER_CTX_new_by_EVP_PKEY() matches the type name,
|
||||
thus making for the naming pattern B<OSSL_ENCODER_CTX_new_by_I<TYPE>>() when
|
||||
new types are handled.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
OSSL_ENCODER_to_bio,
|
||||
OSSL_ENCODER_to_fp
|
||||
- Encoder file output routines
|
||||
- Routines to perform an encoding
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@ -24,10 +24,10 @@ is undefined.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
OSSL_ENCODER_to_bio() runs the encoding process for the
|
||||
context I<ctx>, with the output going to the B<BIO> I<out>. The
|
||||
application is required to set up the B<BIO> properly, for example to
|
||||
have it in text or binary mode if that's appropriate.
|
||||
OSSL_ENCODER_to_bio() runs the encoding process for the context I<ctx>, with
|
||||
the output going to the B<BIO> I<out>. The application is required to set
|
||||
up the B<BIO> properly, for example to have it in text or binary mode if
|
||||
that's appropriate.
|
||||
|
||||
=for comment Know your encoder!
|
||||
|
||||
@ -36,8 +36,16 @@ except that the output is going to the B<FILE> I<fp>.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
OSSL_ENCODER_to_bio() and OSSL_ENCODER_to_fp() return 1 on
|
||||
success, or 0 on failure.
|
||||
OSSL_ENCODER_to_bio() and OSSL_ENCODER_to_fp() return 1 on success, or 0 on
|
||||
failure.
|
||||
|
||||
=begin comment TODO(3.0) Add examples!
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Text, because pod2xxx doesn't like empty sections
|
||||
|
||||
=end comment
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
@ -49,7 +57,7 @@ The functions described here were added in OpenSSL 3.0.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
|
||||
Copyright 2019-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
|
||||
|
@ -11,5 +11,3 @@
|
||||
|
||||
OSSL_ENCODER *ossl_encoder_fetch_by_number(OPENSSL_CTX *libctx, int id,
|
||||
const char *properties);
|
||||
OSSL_DECODER *ossl_decoder_fetch_by_number(OPENSSL_CTX *libctx, int id,
|
||||
const char *properties);
|
||||
|
@ -42,26 +42,59 @@ void OSSL_ENCODER_do_all_provided(OPENSSL_CTX *libctx,
|
||||
void OSSL_ENCODER_names_do_all(const OSSL_ENCODER *encoder,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data);
|
||||
const OSSL_PARAM *OSSL_ENCODER_gettable_params(OSSL_ENCODER *encoder);
|
||||
int OSSL_ENCODER_get_params(OSSL_ENCODER *encoder, OSSL_PARAM params[]);
|
||||
|
||||
const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder);
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(OSSL_ENCODER *encoder);
|
||||
const OSSL_ENCODER *OSSL_ENCODER_CTX_get_encoder(OSSL_ENCODER_CTX *ctx);
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(void);
|
||||
int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
|
||||
const OSSL_PARAM params[]);
|
||||
void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx);
|
||||
|
||||
/* Utilities that help set specific parameters */
|
||||
int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
|
||||
const char *cipher_name,
|
||||
const char *propquery);
|
||||
int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX *ctx,
|
||||
const unsigned char *kstr,
|
||||
size_t klen);
|
||||
const unsigned char *kstr, size_t klen);
|
||||
int OSSL_ENCODER_CTX_set_pem_password_cb(OSSL_ENCODER_CTX *ctx,
|
||||
pem_password_cb *cb, void *cbarg);
|
||||
int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
|
||||
pem_password_cb *cb, void *cbarg);
|
||||
OSSL_PASSPHRASE_CALLBACK *cb,
|
||||
void *cbarg);
|
||||
int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data);
|
||||
int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
|
||||
const char *cipher_name,
|
||||
const char *propquery);
|
||||
int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
|
||||
const char *output_type);
|
||||
int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection);
|
||||
|
||||
/* Utilities to add encoders */
|
||||
int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder);
|
||||
int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
|
||||
OPENSSL_CTX *libctx, const char *propq);
|
||||
int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx);
|
||||
|
||||
typedef struct ossl_encoder_instance_st OSSL_ENCODER_INSTANCE;
|
||||
OSSL_ENCODER *
|
||||
OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
void *
|
||||
OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
const char *
|
||||
OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
const char *
|
||||
OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst);
|
||||
|
||||
typedef const void *OSSL_ENCODER_CONSTRUCT(OSSL_ENCODER_INSTANCE *encoder_inst,
|
||||
void *construct_data);
|
||||
typedef void OSSL_ENCODER_CLEANUP(void *construct_data);
|
||||
|
||||
int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_ENCODER_CONSTRUCT *construct);
|
||||
int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
|
||||
void *construct_data);
|
||||
int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
|
||||
OSSL_ENCODER_CLEANUP *cleanup);
|
||||
|
||||
/* Utilities to output the object to encode */
|
||||
int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out);
|
||||
@ -75,25 +108,11 @@ int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp);
|
||||
* This is more useful than calling OSSL_ENCODER_CTX_new().
|
||||
*/
|
||||
OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
|
||||
const char *output_type,
|
||||
int selection,
|
||||
OPENSSL_CTX *libctx,
|
||||
const char *propquery);
|
||||
|
||||
/*
|
||||
* These macros define the last argument to pass to
|
||||
* OSSL_ENCODER_CTX_new_by_TYPE().
|
||||
*/
|
||||
# define OSSL_ENCODER_PUBKEY_TO_PEM_PQ "format=pem,type=public"
|
||||
# define OSSL_ENCODER_PrivateKey_TO_PEM_PQ "format=pem,type=private"
|
||||
# define OSSL_ENCODER_Parameters_TO_PEM_PQ "format=pem,type=parameters"
|
||||
|
||||
# define OSSL_ENCODER_PUBKEY_TO_DER_PQ "format=der,type=public"
|
||||
# define OSSL_ENCODER_PrivateKey_TO_DER_PQ "format=der,type=private"
|
||||
# define OSSL_ENCODER_Parameters_TO_DER_PQ "format=der,type=parameters"
|
||||
|
||||
/* Corresponding macros for text output */
|
||||
# define OSSL_ENCODER_PUBKEY_TO_TEXT_PQ "format=text,type=public"
|
||||
# define OSSL_ENCODER_PrivateKey_TO_TEXT_PQ "format=text,type=private"
|
||||
# define OSSL_ENCODER_Parameters_TO_TEXT_PQ "format=text,type=parameters"
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
@ -30,7 +30,8 @@ int ERR_load_OSSL_ENCODER_strings(void);
|
||||
/*
|
||||
* OSSL_ENCODER reason codes.
|
||||
*/
|
||||
# define OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY 100
|
||||
# define OSSL_ENCODER_R_ENCODER_NOT_FOUND 101
|
||||
# define OSSL_ENCODER_R_ENCODER_NOT_FOUND 101
|
||||
# define OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY 100
|
||||
# define OSSL_ENCODER_R_MISSING_GET_PARAMS 102
|
||||
|
||||
#endif
|
||||
|
@ -4865,7 +4865,6 @@ OSSL_ENCODER_do_all_provided ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_names_do_all ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_settable_ctx_params ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_new ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_get_encoder ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_params ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_free ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_properties ? 3_0_0 EXIST::FUNCTION:
|
||||
@ -4874,7 +4873,7 @@ OSSL_ENCODER_to_fp ? 3_0_0 EXIST::FUNCTION:STDIO
|
||||
OSSL_ENCODER_CTX_new_by_EVP_PKEY ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_cipher ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_passphrase ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_passphrase_cb ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_pem_password_cb ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_passphrase_ui ? 3_0_0 EXIST::FUNCTION:
|
||||
ERR_load_OSSL_ENCODER_strings ? 3_0_0 EXIST::FUNCTION:
|
||||
PEM_read_X509_PUBKEY ? 3_0_0 EXIST::FUNCTION:STDIO
|
||||
@ -5296,3 +5295,19 @@ EVP_PKEY_encapsulate ? 3_0_0 EXIST::FUNCTION:
|
||||
EVP_PKEY_decapsulate_init ? 3_0_0 EXIST::FUNCTION:
|
||||
EVP_PKEY_decapsulate ? 3_0_0 EXIST::FUNCTION:
|
||||
EVP_PKEY_CTX_set_kem_op ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_gettable_params ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_get_params ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_output_type ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_add_encoder ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_add_extra ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_get_num_encoders ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_selection ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_INSTANCE_get_encoder ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_INSTANCE_get_encoder_ctx ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_INSTANCE_get_input_type ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_INSTANCE_get_output_type ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_construct ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_construct_data ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_cleanup ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_DECODER_INSTANCE_get_input_type ? 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_ENCODER_CTX_set_passphrase_cb ? 3_0_0 EXIST::FUNCTION:
|
||||
|
@ -52,6 +52,9 @@ OSSL_PARAM datatype
|
||||
OSSL_PROVIDER datatype
|
||||
OSSL_ENCODER datatype
|
||||
OSSL_ENCODER_CTX datatype
|
||||
OSSL_ENCODER_CONSTRUCT datatype
|
||||
OSSL_ENCODER_CLEANUP datatype
|
||||
OSSL_ENCODER_INSTANCE datatype
|
||||
OSSL_STORE_CTX datatype
|
||||
OSSL_STORE_INFO datatype
|
||||
OSSL_STORE_LOADER datatype
|
||||
|
Loading…
Reference in New Issue
Block a user