summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/encode_decode/encoder_err.c8
-rw-r--r--crypto/encode_decode/encoder_lib.c342
-rw-r--r--crypto/encode_decode/encoder_local.h52
-rw-r--r--crypto/encode_decode/encoder_meth.c122
-rw-r--r--crypto/encode_decode/encoder_pkey.c366
-rw-r--r--crypto/err/openssl.ec4
-rw-r--r--crypto/err/openssl.txt1
-rw-r--r--doc/man3/OSSL_ENCODER.pod15
-rw-r--r--doc/man3/OSSL_ENCODER_CTX.pod177
-rw-r--r--doc/man3/OSSL_ENCODER_CTX_new_by_EVP_PKEY.pod112
-rw-r--r--doc/man3/OSSL_ENCODER_to_bio.pod24
-rw-r--r--include/crypto/encoder.h2
-rw-r--r--include/openssl/encoder.h69
-rw-r--r--include/openssl/encodererr.h5
-rw-r--r--util/libcrypto.num19
-rw-r--r--util/other.syms3
16 files changed, 979 insertions, 342 deletions
diff --git a/crypto/encode_decode/encoder_err.c b/crypto/encode_decode/encoder_err.c
index 5416f8390e..2c95a2a20e 100644
--- a/crypto/encode_decode/encoder_err.c
+++ b/crypto/encode_decode/encoder_err.c
@@ -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}
};
diff --git a/crypto/encode_decode/encoder_lib.c b/crypto/encode_decode/encoder_lib.c
index b083fa2d4c..179c6d3dc3 100644
--- a/crypto/encode_decode/encoder_lib.c
+++ b/crypto/encode_decode/encoder_lib.c
@@ -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(&params[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;
+}
diff --git a/crypto/encode_decode/encoder_local.h b/crypto/encode_decode/encoder_local.h
index e707be19ff..a57d0cd16c 100644
--- a/crypto/encode_decode/encoder_local.h
+++ b/crypto/encode_decode/encoder_local.h
@@ -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;
diff --git a/crypto/encode_decode/encoder_meth.c b/crypto/encode_decode/encoder_meth.c
index 62342f511a..93929b5360 100644
--- a/crypto/encode_decode/encoder_meth.c
+++ b/crypto/encode_decode/encoder_meth.c
@@ -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_IMPORT_OBJECT:
+ if (encoder->import_object == NULL)
+ encoder->import_object =
+ OSSL_FUNC_encoder_import_object(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_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)
+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;
}
- return ctx->encoder;
-}
+ 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);
-int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
- const OSSL_PARAM params[])
-{
- if (!ossl_assert(ctx != NULL)) {
- ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
+ if (encoderctx == NULL || encoder->set_ctx_params == NULL)
+ continue;
+ if (!encoder->set_ctx_params(encoderctx, params))
+ return 0;
}
-
- if (ctx->encoder != NULL && ctx->encoder->set_ctx_params != NULL)
- return ctx->encoder->set_ctx_params(ctx->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);
}
diff --git a/crypto/encode_decode/encoder_pkey.c b/crypto/encode_decode/encoder_pkey.c
index 7c63a76adb..6e1a80da9f 100644
--- a/crypto/encode_decode/encoder_pkey.c
+++ b/crypto/encode_decode/encoder_pkey.c
@@ -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 {
+struct collected_encoder_st {
+ const char *output_type;
+ STACK_OF(OSSL_ENCODER) *encoders;
+ int error_occured;
+};
+
+static void collect_encoder(OSSL_ENCODER *encoder, void *arg)
+{
+ struct collected_encoder_st *data = arg;
+ OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+ const char *output_type = NULL;
+
+ 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(&params[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;
- int error;
+ unsigned int error_occured:1;
};
-static void cache_encoders(const char *name, void *data)
+static void collect_name(const char *name, void *arg)
{
- struct selected_encoder_st *d = data;
+ struct collected_names_st *data = arg;
+
+ if (data->error_occured)
+ return;
+
+ data->error_occured = 1; /* Assume the worst */
- if (sk_OPENSSL_CSTRING_push(d->names, name) <= 0)
- d->error = 1;
+ 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;
-
- return ctx->encoder->encode_data(ctx->encoderctx, params,
- (OSSL_CORE_BIO *)out,
- ossl_pw_passphrase_callback_enc,
- &ctx->pwdata);
-}
+ 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);
-/*
- * Support for OSSL_ENCODER_to_bio:
- * Perform the actual output.
- */
+ construct_data->constructed_obj =
+ encoder->import_object(encoderctx, construct_data->selection, params);
-static int encoder_EVP_PKEY_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
+ return (construct_data->constructed_obj != NULL);
+}
+
+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;
+
+ 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 (k_prov != e_prov) {
+ data->encoder_inst = encoder_inst;
+
+ 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;
+ }
+ }
- /*
- * 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;
+ return data->obj;
+}
- if (ctx->encoder->encode_object == NULL
- || (OSSL_ENCODER_provider(ctx->encoder)
- != EVP_KEYMGMT_provider(keymgmt))) {
- struct encoder_write_data_st write_data;
+static void encoder_destruct_EVP_PKEY(void *arg)
+{
+ struct construct_data_st *data = arg;
- write_data.ctx = ctx;
- write_data.out = out;
+ if (data->encoder_inst != NULL) {
+ OSSL_ENCODER *encoder =
+ OSSL_ENCODER_INSTANCE_get_encoder(data->encoder_inst);
- return evp_keymgmt_export(keymgmt, keydata, ctx->selection,
- &encoder_write_cb, &write_data);
+ encoder->free_object(data->constructed_obj);
}
-
- return ctx->encoder->encode_object(ctx->encoderctx, keydata,
- (OSSL_CORE_BIO *)out,
- ossl_pw_passphrase_callback_enc,
- &ctx->pwdata);
+ 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