ENCODER: Refactor the OSSL_ENCODER API to be more like OSSL_DECODER
authorRichard Levitte <levitte@openssl.org>
Mon, 14 Sep 2020 07:20:41 +0000 (09:20 +0200)
committerRichard Levitte <levitte@openssl.org>
Sun, 20 Sep 2020 15:31:22 +0000 (17:31 +0200)
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)

16 files changed:
crypto/encode_decode/encoder_err.c
crypto/encode_decode/encoder_lib.c
crypto/encode_decode/encoder_local.h
crypto/encode_decode/encoder_meth.c
crypto/encode_decode/encoder_pkey.c
crypto/err/openssl.ec
crypto/err/openssl.txt
doc/man3/OSSL_ENCODER.pod
doc/man3/OSSL_ENCODER_CTX.pod
doc/man3/OSSL_ENCODER_CTX_new_by_EVP_PKEY.pod
doc/man3/OSSL_ENCODER_to_bio.pod
include/crypto/encoder.h
include/openssl/encoder.h
include/openssl/encodererr.h
util/libcrypto.num
util/other.syms

index 5416f8390ecaf9859745e70250717915520057e6..2c95a2a20ebd7d1b7d3439ed0734c9cc16e55596 100644 (file)
 #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}
 };
 
index b083fa2d4c47d4048f0bc43c4149a341b502e225..179c6d3dc371ffb9be2e93c6b8b3eb2821b13c51 100644 (file)
@@ -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;
+}
index e707be19ffc26ff703f88b88d6dd3305a2cc6939..a57d0cd16c50b900448473bc7ecc612535740e05 100644 (file)
@@ -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;
index 62342f511a79ebd220c05252201fbd87072afc07..93929b5360d52266285e48a349db65ae40437671 100644 (file)
@@ -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);
     }
index 7c63a76adbb85344b18ec09574a7df6bf5cb32f5..6e1a80da9f63767f34fe3672dd10b805744894c6 100644 (file)
@@ -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;
 
+        if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) {
+            ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
         /*
-         * 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.
+         * Select the encoder in two steps.  First, collect all encoders
+         * that have the correct output type, as well as all keymgmt names.
          */
+        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);
 
-        /*
-         * 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.
+        /*-
+         * 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.
          *
-         * 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.
+         * 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_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);
+        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;
+}
index 037611d759a111bfb0d86c7190811e19b10b2014..589ff1094c05b201e993a6e361ab57d300adf32f 100644 (file)
@@ -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
index f26d07835f5c54f738014b7a5e8728c28ca53ab8..3c2fa4a4e76a4388fa4e8ece787e54b3c6391978 100644 (file)
@@ -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
index d8998310bda34efad0cd7979220560bdf27a5989..a1b7c4b76cd5117f6403aecd1a85255813a78cff 100644 (file)
@@ -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
index bf339c6a4f6c35e534e496f865ef86cec1443ef3..ccf847db477eaa99abb0f71b12a42d862ee710b9 100644 (file)
@@ -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_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_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_INSTANCE_output_type() returns a string with the name of the
+output type.
 
 =head1 SEE ALSO
 
index 2aa103fd143509e621629058898d4e5b28cf9a60..a97208cbe3ad7eb704665f815f692788a833db76 100644 (file)
@@ -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.
-
-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
+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)>.
+
+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.
-
-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.
+Parts of the function names are made to match already existing OpenSSL
+names.
 
-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
 
index ee9998b2eb5a0da4d6e1f3f44114aa09062f26db..6f75f592e44301708685ba3a83a2293119654cfe 100644 (file)
@@ -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
index f75a031c326b4ed63e40293091423d41a757052a..2f036456a250911db9bb605b237a376005b42e19 100644 (file)
@@ -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);
index 10b2bc9188e4d4b25d72950c4e0ecd203b0e3304..6698769e24d9d498f27abd407d91efec39b1e0f3 100644 (file)
@@ -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
index 007070e0c02b22cbb3fd00a4c87041c0e0686409..e146d6ec923df4d7f1747f3b58b4f1219372abcd 100644 (file)
@@ -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
index 96fd637ba0613d7b8d162f486ad4ae892009beee..f9045e021ac43c1e118482eb75596685cac57a7c 100644 (file)
@@ -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:
index 0925d726d81da7b65863f1b89d09808344978cf2..b4acae2952ae3bc714e158ccd9341ea18c8f1036 100644 (file)
@@ -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