DESERIALIZER: Add foundation for deserializers
authorRichard Levitte <levitte@openssl.org>
Wed, 8 Jul 2020 21:04:08 +0000 (23:04 +0200)
committerRichard Levitte <levitte@openssl.org>
Fri, 24 Jul 2020 14:32:00 +0000 (16:32 +0200)
This adds a method OSSL_DESERIALIZER, a deserializer context and basic
support to use a set of serializers to get a desired type of data, as
well as deserializer chains.

The idea is that the caller can call OSSL_DESERIALIZER_CTX_add_serializer()
to set up the set of desired results, and to add possible chains, call
OSSL_DESERIALIZER_CTX_add_extra().  All these deserializers are pushed
on an internal stack.

The actual deserialization is then performed using functions like
OSSL_DESERIALIZER_from_bio().  When performing deserialization, the
inernal stack is walked backwards, keeping track of the deserialized
data and its type along the way, until the data kan be processed into
the desired type of data.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12410)

24 files changed:
crypto/err/err.c
crypto/err/openssl.ec
crypto/err/openssl.txt
crypto/property/property_parse.c
crypto/serializer/build.info
crypto/serializer/deserializer_err.c [new file with mode: 0644]
crypto/serializer/deserializer_lib.c [new file with mode: 0644]
crypto/serializer/deserializer_meth.c [new file with mode: 0644]
crypto/serializer/serializer_local.h
crypto/serializer/serializer_meth.c
doc/man3/OSSL_DESERIALIZER.pod [new file with mode: 0644]
doc/man3/OSSL_DESERIALIZER_CTX.pod [new file with mode: 0644]
doc/man3/OSSL_DESERIALIZER_from_bio.pod [new file with mode: 0644]
include/crypto/serializer.h
include/internal/cryptlib.h
include/openssl/core_dispatch.h
include/openssl/core_names.h
include/openssl/deserializer.h [new file with mode: 0644]
include/openssl/deserializererr.h [new file with mode: 0644]
include/openssl/err.h
include/openssl/types.h
util/libcrypto.num
util/missingcrypto.txt
util/other.syms

index 26cf2b0b9d3e4e2e9a887d0a2e340265cd0869d1..e2d70d7a58ed92aa979a55b456c6bd190fc86993 100644 (file)
@@ -76,6 +76,7 @@ static ERR_STRING_DATA ERR_str_libraries[] = {
     {ERR_PACK(ERR_LIB_ESS, 0, 0), "ESS routines"},
     {ERR_PACK(ERR_LIB_PROV, 0, 0), "Provider routines"},
     {ERR_PACK(ERR_LIB_OSSL_SERIALIZER, 0, 0), "SERIALIZER routines"},
+    {ERR_PACK(ERR_LIB_OSSL_DESERIALIZER, 0, 0), "DESERIALIZER routines"},
     {ERR_PACK(ERR_LIB_HTTP, 0, 0), "HTTP routines"},
     {0, NULL},
 };
index 1ec7bb1162e9725366a59df1c5b7b4af94a04a21..f1bed1279588aff69b43948a815338cff9b3ed48 100644 (file)
@@ -41,6 +41,7 @@ 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_SERIALIZER include/openssl/serializer.h  crypto/serializer/serializer_err.c
+L OSSL_DESERIALIZER include/openssl/deserializer.h  crypto/serializer/deserializer_err.c
 L HTTP          include/openssl/http.h          crypto/http/http_err.c
 
 # additional header files to be scanned for function names
index fcc4fb5c1cc487137f785c6d1f466020f4116127..e5ed28bce1e20295da15579fe7106326244ed2e0 100644 (file)
@@ -2693,6 +2693,7 @@ OCSP_R_STATUS_TOO_OLD:127:status too old
 OCSP_R_UNKNOWN_MESSAGE_DIGEST:119:unknown message digest
 OCSP_R_UNKNOWN_NID:120:unknown nid
 OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type
+OSSL_DESERIALIZER_R_MISSING_GET_PARAMS:100:missing get params
 OSSL_SERIALIZER_R_INCORRECT_PROPERTY_QUERY:100:incorrect property query
 OSSL_SERIALIZER_R_SERIALIZER_NOT_FOUND:101:serializer not found
 OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type
index 41a5a059c5c9aeec22842cc637d668ee7201efed..91b830c2e5a05f165ff146f9f6372e669d40ddb5 100644 (file)
@@ -598,6 +598,7 @@ int ossl_property_parse_init(OPENSSL_CTX *ctx)
         "fips",         /* FIPS validated or FIPS supporting algorithm */
         "format",       /* output format for serializers */
         "type",         /* output type for serializers */
+        "input",        /* input type for deserializers */
     };
     size_t i;
 
index 551319ed59b72ddfd11b82851bdbf6639f0f9a92..066eec5cdd6eb5eee9558307995463f871479b06 100644 (file)
@@ -1,2 +1,5 @@
-SOURCE[../../libcrypto]=serializer_meth.c serializer_lib.c serializer_pkey.c \
-        serializer_err.c
+SOURCE[../../libcrypto]=serializer_meth.c serializer_lib.c serializer_pkey.c
+SOURCE[../../libcrypto]=deserializer_meth.c deserializer_lib.c
+
+SOURCE[../../libcrypto]=serializer_err.c
+SOURCE[../../libcrypto]=deserializer_err.c
diff --git a/crypto/serializer/deserializer_err.c b/crypto/serializer/deserializer_err.c
new file mode 100644 (file)
index 0000000..2cc2459
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include <openssl/deserializererr.h>
+
+#ifndef OPENSSL_NO_ERR
+
+static const ERR_STRING_DATA OSSL_DESERIALIZER_str_reasons[] = {
+    {ERR_PACK(ERR_LIB_OSSL_DESERIALIZER, 0, OSSL_DESERIALIZER_R_MISSING_GET_PARAMS),
+    "missing get params"},
+    {0, NULL}
+};
+
+#endif
+
+int ERR_load_OSSL_DESERIALIZER_strings(void)
+{
+#ifndef OPENSSL_NO_ERR
+    if (ERR_reason_error_string(OSSL_DESERIALIZER_str_reasons[0].error) == NULL)
+        ERR_load_strings_const(OSSL_DESERIALIZER_str_reasons);
+#endif
+    return 1;
+}
diff --git a/crypto/serializer/deserializer_lib.c b/crypto/serializer/deserializer_lib.c
new file mode 100644 (file)
index 0000000..2d2b1b7
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_names.h>
+#include <openssl/bio.h>
+#include <openssl/params.h>
+#include <openssl/provider.h>
+#include "serializer_local.h"
+#include "e_os.h"
+
+struct deser_process_data_st {
+    OSSL_DESERIALIZER_CTX *ctx;
+
+    /* Current BIO */
+    BIO *bio;
+
+    /* Index of the current deserializer instance to be processed */
+    size_t current_deser_inst_index;
+};
+
+static int deser_process(const OSSL_PARAM params[], void *arg);
+
+int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in)
+{
+    struct deser_process_data_st data;
+
+    memset(&data, 0, sizeof(data));
+    data.ctx = ctx;
+    data.bio = in;
+
+    return deser_process(NULL, &data);
+}
+
+#ifndef OPENSSL_NO_STDIO
+static BIO *bio_from_file(FILE *fp)
+{
+    BIO *b;
+
+    if ((b = BIO_new(BIO_s_file())) == NULL) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_BIO_LIB);
+        return NULL;
+    }
+    BIO_set_fp(b, fp, BIO_NOCLOSE);
+    return b;
+}
+
+int OSSL_DESERIALIZER_from_fp(OSSL_DESERIALIZER_CTX *ctx, FILE *fp)
+{
+    BIO *b = bio_from_file(fp);
+    int ret = 0;
+
+    if (b != NULL)
+        ret = OSSL_DESERIALIZER_from_bio(ctx, b);
+
+    BIO_free(b);
+    return ret;
+}
+#endif
+
+int OSSL_DESERIALIZER_CTX_set_input_type(OSSL_DESERIALIZER_CTX *ctx,
+                                         const char *input_type)
+{
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    /*
+     * NULL is a valid starting input type, and means that the caller leaves
+     * it to code to discover what the starting input type is.
+     */
+    ctx->start_input_type = input_type;
+    return 1;
+}
+
+int OSSL_DESERIALIZER_CTX_add_deserializer(OSSL_DESERIALIZER_CTX *ctx,
+                                           OSSL_DESERIALIZER *deser)
+{
+    OSSL_DESERIALIZER_INSTANCE *deser_inst = NULL;
+    const OSSL_PROVIDER *prov = NULL;
+    OSSL_PARAM params[2];
+    void *provctx = NULL;
+
+    if (!ossl_assert(ctx != NULL) || !ossl_assert(deser != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if (deser->get_params == NULL) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER,
+                  OSSL_DESERIALIZER_R_MISSING_GET_PARAMS);
+        return 0;
+    }
+
+    if (ctx->deser_insts == NULL
+        && (ctx->deser_insts =
+            sk_OSSL_DESERIALIZER_INSTANCE_new_null()) == NULL) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    if ((deser_inst = OPENSSL_zalloc(sizeof(*deser_inst))) == NULL) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    if (!OSSL_DESERIALIZER_up_ref(deser)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    deser_inst->deser = deser;
+
+    prov = OSSL_DESERIALIZER_provider(deser_inst->deser);
+    provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
+
+    /* Cache the input type for this serializer */
+    params[0] =
+        OSSL_PARAM_construct_utf8_ptr(OSSL_DESERIALIZER_PARAM_INPUT_TYPE,
+                                      (char **)&deser_inst->input_type, 0);
+    params[1] = OSSL_PARAM_construct_end();
+
+    if (!deser_inst->deser->get_params(params)
+        || !OSSL_PARAM_modified(&params[0]))
+        goto err;
+
+    if ((deser_inst->deserctx = deser_inst->deser->newctx(provctx))
+        == NULL)
+        goto err;
+
+    if (sk_OSSL_DESERIALIZER_INSTANCE_push(ctx->deser_insts, deser_inst) <= 0)
+        goto err;
+
+    return 1;
+ err:
+    if (deser_inst != NULL) {
+        if (deser_inst->deser != NULL)
+            deser_inst->deser->freectx(deser_inst->deserctx);
+        OSSL_DESERIALIZER_free(deser_inst->deser);
+        OPENSSL_free(deser_inst);
+    }
+    return 0;
+}
+
+int OSSL_DESERIALIZER_CTX_add_extra(OSSL_DESERIALIZER_CTX *ctx,
+                                    OPENSSL_CTX *libctx, const char *propq)
+{
+    /*
+     * This function goes through existing deserializer methods in
+     * |ctx->deser_insts|, and tries to fetch new deserializers that produce
+     * what the existing ones want as input, and push those newly fetched
+     * deserializers on top of the same stack.
+     * Then it does the same again, but looping over the newly fetched
+     * deserializers, until there are no more serializers to be fetched, or
+     * when we have done this 10 times.
+     *
+     * we do this with sliding windows on the stack by keeping track of indexes
+     * and of the end.
+     *
+     * +----------------+
+     * |   DER to RSA   | <--- w_prev_start
+     * +----------------+
+     * |   DER to DSA   |
+     * +----------------+
+     * |   DER to DH    |
+     * +----------------+
+     * |   PEM to DER   | <--- w_prev_end, w_new_start
+     * +----------------+
+     *                    <--- w_new_end
+     */
+    size_t w_prev_start, w_prev_end; /* "previous" deserializers */
+    size_t w_new_start, w_new_end;   /* "new" deserializers */
+    size_t count = 0; /* Calculates how many were added in each iteration */
+    size_t depth = 0; /* Counts the number of iterations */
+
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    /*
+     * If there is no stack of OSSL_DESERIALIZER_INSTANCE, we have nothing
+     * more to add.  That's fine.
+     */
+    if (ctx->deser_insts == NULL)
+        return 1;
+
+    w_prev_start = 0;
+    w_prev_end = sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
+    do {
+        size_t i;
+
+        w_new_start = w_new_end = w_prev_end;
+
+        for (i = w_prev_start; i < w_prev_end; i++) {
+            OSSL_DESERIALIZER_INSTANCE *deser_inst =
+                sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, i);
+            const char *name = deser_inst->input_type;
+            OSSL_DESERIALIZER *deser = NULL;
+
+            /*
+             * If the caller has specified what the initial input should be,
+             * and the deserializer implementation we're looking at has that
+             * input type, there's no point adding on more implementations
+             * on top of this one, so we don't.
+             */
+            if (ctx->start_input_type != NULL
+                && strcasecmp(ctx->start_input_type,
+                              deser_inst->input_type) != 0)
+                continue;
+
+            ERR_set_mark();
+            deser = OSSL_DESERIALIZER_fetch(libctx, name, propq);
+            ERR_pop_to_mark();
+
+            if (deser != NULL) {
+                size_t j;
+
+                /*
+                 * Check that we don't already have this deserializer in our
+                 * stack We only need to check among the newly added ones.
+                 */
+                for (j = w_new_start; j < w_new_end; j++) {
+                    OSSL_DESERIALIZER_INSTANCE *check_inst =
+                        sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, j);
+
+                    if (deser == check_inst->deser) {
+                        /* We found it, so drop the new fetch */
+                        OSSL_DESERIALIZER_free(deser);
+                        deser = NULL;
+                        break;
+                    }
+                }
+            }
+
+            if (deser == NULL)
+                continue;
+
+            /*
+             * Apart from keeping w_new_end up to date, We don't care about
+             * errors here.  If it doesn't collect, then it doesn't...
+             */
+            if (OSSL_DESERIALIZER_CTX_add_deserializer(ctx, deser)) /* ref++ */
+                w_new_end++;
+            OSSL_DESERIALIZER_free(deser); /* ref-- */
+        }
+        /* How many were added in this iteration */
+        count = w_new_end - w_new_start;
+
+        /* Slide the "previous deserializer" windows */
+        w_prev_start = w_new_start;
+        w_prev_end = w_new_end;
+
+        depth++;
+    } while (count != 0 && depth <= 10);
+
+    return 1;
+}
+
+int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx)
+{
+    if (ctx == NULL || ctx->deser_insts == NULL)
+        return 0;
+    return sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
+}
+
+int OSSL_DESERIALIZER_CTX_set_finalizer(OSSL_DESERIALIZER_CTX *ctx,
+                                        OSSL_DESERIALIZER_FINALIZER *finalizer,
+                                        OSSL_DESERIALIZER_CLEANER *cleaner,
+                                        void *finalize_arg)
+{
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    ctx->finalizer = finalizer;
+    ctx->cleaner = cleaner;
+    ctx->finalize_arg = finalize_arg;
+    return 1;
+}
+
+int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
+                             void *reference, size_t reference_sz,
+                             OSSL_CALLBACK *export_cb, void *export_cbarg)
+{
+    if (!(ossl_assert(deser_inst != NULL)
+          && ossl_assert(reference != NULL)
+          && ossl_assert(export_cb != NULL)
+          && ossl_assert(export_cbarg != NULL))) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    return deser_inst->deser->export_object(deser_inst->deserctx,
+                                            reference, reference_sz,
+                                            export_cb, export_cbarg);
+}
+
+OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst)
+{
+    if (deser_inst == NULL)
+        return NULL;
+    return deser_inst->deser;
+}
+
+void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst)
+{
+    if (deser_inst == NULL)
+        return NULL;
+    return deser_inst->deserctx;
+}
+
+static int deser_process(const OSSL_PARAM params[], void *arg)
+{
+    struct deser_process_data_st *data = arg;
+    OSSL_DESERIALIZER_CTX *ctx = data->ctx;
+    OSSL_DESERIALIZER_INSTANCE *deser_inst = NULL;
+    OSSL_DESERIALIZER *deser = NULL;
+    BIO *bio = data->bio;
+    long loc;
+    size_t i;
+    int ok = 0;
+    /* For recursions */
+    struct deser_process_data_st new_data;
+
+    memset(&new_data, 0, sizeof(new_data));
+    new_data.ctx = data->ctx;
+
+    if (params == NULL) {
+        /* First iteration, where we prepare for what is to come */
+
+        data->current_deser_inst_index =
+            OSSL_DESERIALIZER_CTX_num_deserializers(ctx);
+
+        bio = data->bio;
+    } else {
+        const OSSL_PARAM *p;
+
+        deser_inst =
+            sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts,
+                                                data->current_deser_inst_index);
+        deser = OSSL_DESERIALIZER_INSTANCE_deserializer(deser_inst);
+
+        if (ctx->finalizer(deser_inst, params, ctx->finalize_arg)) {
+            ok = 1;
+            goto end;
+        }
+
+        /* The finalizer didn't return success */
+
+        /*
+         * so we try to use the object we got and feed it to any next
+         * deserializer that will take it.  Object references are not
+         * allowed for this.
+         * If this data isn't present, deserialization has failed.
+         */
+
+        p = OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_DATA);
+        if (p == NULL || p->data_type != OSSL_PARAM_OCTET_STRING)
+            goto end;
+        new_data.bio = BIO_new_mem_buf(p->data, (int)p->data_size);
+        if (new_data.bio == NULL)
+            goto end;
+        bio = new_data.bio;
+    }
+
+    /*
+     * If we have no more deserializers to look through at this point,
+     * we failed
+     */
+    if (data->current_deser_inst_index == 0)
+        goto end;
+
+    if ((loc = BIO_tell(bio)) < 0) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_BIO_LIB);
+        goto end;
+    }
+
+    for (i = data->current_deser_inst_index; i-- > 0;) {
+        OSSL_DESERIALIZER_INSTANCE *new_deser_inst =
+            sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, i);
+        OSSL_DESERIALIZER *new_deser =
+            OSSL_DESERIALIZER_INSTANCE_deserializer(new_deser_inst);
+
+        /*
+         * If |deser| is NULL, it means we've just started, and the caller
+         * may have specified what it expects the initial input to be.  If
+         * that's the case, we do this extra check.
+         */
+        if (deser == NULL && ctx->start_input_type != NULL
+            && strcasecmp(ctx->start_input_type, deser_inst->input_type) != 0)
+            continue;
+
+        /*
+         * If we have a previous deserializer, we check that the input type
+         * of the next to be used matches the type of this previous one.
+         * deser_inst->input_type is a cache of the parameter "input-type"
+         * value for that deserializer.
+         */
+        if (deser != NULL
+            && !OSSL_DESERIALIZER_is_a(deser, new_deser_inst->input_type))
+            continue;
+
+        if (loc == 0) {
+            if (BIO_reset(bio) <= 0)
+                goto end;
+        } else {
+            if (BIO_seek(bio, loc) <= 0)
+                goto end;
+        }
+
+        /* Recurse */
+        new_data.current_deser_inst_index = i;
+        ok = new_deser->deserialize(new_deser_inst->deserctx,
+                                    (OSSL_CORE_BIO *)bio,
+                                    deser_process, &new_data,
+                                    NULL /* ossl_deserializer_passphrase_in_cb */,
+                                    new_data.ctx);
+        if (ok)
+            break;
+    }
+
+ end:
+    BIO_free(new_data.bio);
+    return ok;
+}
diff --git a/crypto/serializer/deserializer_meth.c b/crypto/serializer/deserializer_meth.c
new file mode 100644 (file)
index 0000000..5450071
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/deserializer.h>
+#include <openssl/ui.h>
+#include "internal/core.h"
+#include "internal/namemap.h"
+#include "internal/property.h"
+#include "internal/provider.h"
+#include "crypto/serializer.h"
+#include "serializer_local.h"
+
+static void OSSL_DESERIALIZER_INSTANCE_free(OSSL_DESERIALIZER_INSTANCE *instance);
+
+/*
+ * Deserializer can have multiple names, separated with colons in a name string
+ */
+#define NAME_SEPARATOR ':'
+
+/* Simple method structure constructor and destructor */
+static OSSL_DESERIALIZER *ossl_deserializer_new(void)
+{
+    OSSL_DESERIALIZER *deser = NULL;
+
+    if ((deser = OPENSSL_zalloc(sizeof(*deser))) == NULL
+        || (deser->base.lock = CRYPTO_THREAD_lock_new()) == NULL) {
+        OSSL_DESERIALIZER_free(deser);
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    deser->base.refcnt = 1;
+
+    return deser;
+}
+
+int OSSL_DESERIALIZER_up_ref(OSSL_DESERIALIZER *deser)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&deser->base.refcnt, &ref, deser->base.lock);
+    return 1;
+}
+
+void OSSL_DESERIALIZER_free(OSSL_DESERIALIZER *deser)
+{
+    int ref = 0;
+
+    if (deser == NULL)
+        return;
+
+    CRYPTO_DOWN_REF(&deser->base.refcnt, &ref, deser->base.lock);
+    if (ref > 0)
+        return;
+    ossl_provider_free(deser->base.prov);
+    CRYPTO_THREAD_lock_free(deser->base.lock);
+    OPENSSL_free(deser);
+}
+
+/* Permanent deserializer method store, constructor and destructor */
+static void deserializer_store_free(void *vstore)
+{
+    ossl_method_store_free(vstore);
+}
+
+static void *deserializer_store_new(OPENSSL_CTX *ctx)
+{
+    return ossl_method_store_new(ctx);
+}
+
+
+static const OPENSSL_CTX_METHOD deserializer_store_method = {
+    deserializer_store_new,
+    deserializer_store_free,
+};
+
+/* Data to be passed through ossl_method_construct() */
+struct deserializer_data_st {
+    OPENSSL_CTX *libctx;
+    OSSL_METHOD_CONSTRUCT_METHOD *mcm;
+    int id;                      /* For get_deserializer_from_store() */
+    const char *names;           /* For get_deserializer_from_store() */
+    const char *propquery;       /* For get_deserializer_from_store() */
+};
+
+/*
+ * Generic routines to fetch / create DESERIALIZER methods with
+ * ossl_method_construct()
+ */
+
+/* Temporary deserializer method store, constructor and destructor */
+static void *alloc_tmp_deserializer_store(OPENSSL_CTX *ctx)
+{
+    return ossl_method_store_new(ctx);
+}
+
+ static void dealloc_tmp_deserializer_store(void *store)
+{
+    if (store != NULL)
+        ossl_method_store_free(store);
+}
+
+/* Get the permanent deserializer store */
+static OSSL_METHOD_STORE *get_deserializer_store(OPENSSL_CTX *libctx)
+{
+    return openssl_ctx_get_data(libctx, OPENSSL_CTX_DESERIALIZER_STORE_INDEX,
+                                &deserializer_store_method);
+}
+
+/* Get deserializer methods from a store, or put one in */
+static void *get_deserializer_from_store(OPENSSL_CTX *libctx, void *store,
+                                         void *data)
+{
+    struct deserializer_data_st *methdata = data;
+    void *method = NULL;
+    int id;
+
+    if ((id = methdata->id) == 0) {
+        OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+
+        id = ossl_namemap_name2num(namemap, methdata->names);
+    }
+
+    if (store == NULL
+        && (store = get_deserializer_store(libctx)) == NULL)
+        return NULL;
+
+    if (!ossl_method_store_fetch(store, id, methdata->propquery, &method))
+        return NULL;
+    return method;
+}
+
+static int put_deserializer_in_store(OPENSSL_CTX *libctx, void *store,
+                                     void *method, const OSSL_PROVIDER *prov,
+                                     int operation_id, const char *names,
+                                     const char *propdef, void *unused)
+{
+    OSSL_NAMEMAP *namemap;
+    int id;
+
+    if ((namemap = ossl_namemap_stored(libctx)) == NULL
+        || (id = ossl_namemap_name2num(namemap, names)) == 0)
+        return 0;
+
+    if (store == NULL && (store = get_deserializer_store(libctx)) == NULL)
+        return 0;
+
+    return ossl_method_store_add(store, prov, id, propdef, method,
+                                 (int (*)(void *))OSSL_DESERIALIZER_up_ref,
+                                 (void (*)(void *))OSSL_DESERIALIZER_free);
+}
+
+/* Create and populate a deserializer method */
+static void *deserializer_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
+                                        OSSL_PROVIDER *prov)
+{
+    OSSL_DESERIALIZER *deser = NULL;
+    const OSSL_DISPATCH *fns = algodef->implementation;
+
+    if ((deser = ossl_deserializer_new()) == NULL)
+        return NULL;
+    deser->base.id = id;
+    deser->base.propdef = algodef->property_definition;
+
+    for (; fns->function_id != 0; fns++) {
+        switch (fns->function_id) {
+        case OSSL_FUNC_DESERIALIZER_NEWCTX:
+            if (deser->newctx == NULL)
+                deser->newctx = OSSL_FUNC_deserializer_newctx(fns);
+            break;
+        case OSSL_FUNC_DESERIALIZER_FREECTX:
+            if (deser->freectx == NULL)
+                deser->freectx = OSSL_FUNC_deserializer_freectx(fns);
+            break;
+        case OSSL_FUNC_DESERIALIZER_GET_PARAMS:
+            if (deser->get_params == NULL)
+                deser->get_params =
+                    OSSL_FUNC_deserializer_get_params(fns);
+            break;
+        case OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS:
+            if (deser->gettable_params == NULL)
+                deser->gettable_params =
+                    OSSL_FUNC_deserializer_gettable_params(fns);
+            break;
+        case OSSL_FUNC_DESERIALIZER_SET_CTX_PARAMS:
+            if (deser->set_ctx_params == NULL)
+                deser->set_ctx_params =
+                    OSSL_FUNC_deserializer_set_ctx_params(fns);
+            break;
+        case OSSL_FUNC_DESERIALIZER_SETTABLE_CTX_PARAMS:
+            if (deser->settable_ctx_params == NULL)
+                deser->settable_ctx_params =
+                    OSSL_FUNC_deserializer_settable_ctx_params(fns);
+            break;
+        case OSSL_FUNC_DESERIALIZER_DESERIALIZE:
+            if (deser->deserialize == NULL)
+                deser->deserialize = OSSL_FUNC_deserializer_deserialize(fns);
+            break;
+        case OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT:
+            if (deser->export_object == NULL)
+                deser->export_object = OSSL_FUNC_deserializer_export_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 serializing driver functions.
+     */
+    if (!((deser->newctx == NULL && deser->freectx == NULL)
+          || (deser->newctx != NULL && deser->freectx != NULL))
+        || (deser->deserialize == NULL && deser->export_object == NULL)) {
+        OSSL_DESERIALIZER_free(deser);
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
+        return NULL;
+    }
+
+    if (prov != NULL && !ossl_provider_up_ref(prov)) {
+        OSSL_DESERIALIZER_free(deser);
+        return NULL;
+    }
+
+    deser->base.prov = prov;
+    return deser;
+}
+
+
+/*
+ * The core fetching functionality passes the names of the implementation.
+ * This function is responsible to getting an identity number for them,
+ * then call deserializer_from_dispatch() with that identity number.
+ */
+static void *construct_deserializer(const OSSL_ALGORITHM *algodef,
+                                    OSSL_PROVIDER *prov, void *unused)
+{
+    /*
+     * This function is only called if get_deserializer_from_store() returned
+     * NULL, so it's safe to say that of all the spots to create a new
+     * namemap entry, this is it.  Should the name already exist there, we
+     * know that ossl_namemap_add() will return its corresponding number.
+     */
+    OPENSSL_CTX *libctx = ossl_provider_library_context(prov);
+    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+    const char *names = algodef->algorithm_names;
+    int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
+    void *method = NULL;
+
+    if (id != 0)
+        method = deserializer_from_dispatch(id, algodef, prov);
+
+    return method;
+}
+
+/* Intermediary function to avoid ugly casts, used below */
+static void destruct_deserializer(void *method, void *data)
+{
+    OSSL_DESERIALIZER_free(method);
+}
+
+static int up_ref_deserializer(void *method)
+{
+    return OSSL_DESERIALIZER_up_ref(method);
+}
+
+static void free_deserializer(void *method)
+{
+    OSSL_DESERIALIZER_free(method);
+}
+
+/* Fetching support.  Can fetch by numeric identity or by name */
+static OSSL_DESERIALIZER *inner_ossl_deserializer_fetch(OPENSSL_CTX *libctx,
+                                                        int id,
+                                                        const char *name,
+                                                        const char *properties)
+{
+    OSSL_METHOD_STORE *store = get_deserializer_store(libctx);
+    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+    void *method = NULL;
+
+    if (store == NULL || namemap == NULL)
+        return NULL;
+
+    /*
+     * If we have been passed neither a name_id or a name, we have an
+     * internal programming error.
+     */
+    if (!ossl_assert(id != 0 || name != NULL))
+        return NULL;
+
+    if (id == 0)
+        id = ossl_namemap_name2num(namemap, name);
+
+    if (id == 0
+        || !ossl_method_store_cache_get(store, id, properties, &method)) {
+        OSSL_METHOD_CONSTRUCT_METHOD mcm = {
+            alloc_tmp_deserializer_store,
+            dealloc_tmp_deserializer_store,
+            get_deserializer_from_store,
+            put_deserializer_in_store,
+            construct_deserializer,
+            destruct_deserializer
+        };
+        struct deserializer_data_st mcmdata;
+
+        mcmdata.libctx = libctx;
+        mcmdata.mcm = &mcm;
+        mcmdata.id = id;
+        mcmdata.names = name;
+        mcmdata.propquery = properties;
+        if ((method = ossl_method_construct(libctx, OSSL_OP_DESERIALIZER,
+                                            0 /* !force_cache */,
+                                            &mcm, &mcmdata)) != NULL) {
+            /*
+             * If construction did create a method for us, we know that
+             * there is a correct name_id and meth_id, since those have
+             * already been calculated in get_deserializer_from_store() and
+             * put_deserializer_in_store() above.
+             */
+            if (id == 0)
+                id = ossl_namemap_name2num(namemap, name);
+            ossl_method_store_cache_set(store, id, properties, method,
+                                        up_ref_deserializer, free_deserializer);
+        }
+    }
+
+    return method;
+}
+
+OSSL_DESERIALIZER *OSSL_DESERIALIZER_fetch(OPENSSL_CTX *libctx,
+                                           const char *name,
+                                           const char *properties)
+{
+    return inner_ossl_deserializer_fetch(libctx, 0, name, properties);
+}
+
+OSSL_DESERIALIZER *ossl_deserializer_fetch_by_number(OPENSSL_CTX *libctx,
+                                                     int id,
+                                                     const char *properties)
+{
+    return inner_ossl_deserializer_fetch(libctx, id, NULL, properties);
+}
+
+/*
+ * Library of basic method functions
+ */
+
+const OSSL_PROVIDER *OSSL_DESERIALIZER_provider(const OSSL_DESERIALIZER *deser)
+{
+    if (!ossl_assert(deser != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    return deser->base.prov;
+}
+
+const char *OSSL_DESERIALIZER_properties(const OSSL_DESERIALIZER *deser)
+{
+    if (!ossl_assert(deser != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    return deser->base.propdef;
+}
+
+int OSSL_DESERIALIZER_number(const OSSL_DESERIALIZER *deser)
+{
+    if (!ossl_assert(deser != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    return deser->base.id;
+}
+
+int OSSL_DESERIALIZER_is_a(const OSSL_DESERIALIZER *deser, const char *name)
+{
+    if (deser->base.prov != NULL) {
+        OPENSSL_CTX *libctx = ossl_provider_library_context(deser->base.prov);
+        OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+
+        return ossl_namemap_name2num(namemap, name) == deser->base.id;
+    }
+    return 0;
+}
+
+struct deserializer_do_all_data_st {
+    void (*user_fn)(void *method, void *arg);
+    void *user_arg;
+};
+
+static void deserializer_do_one(OSSL_PROVIDER *provider,
+                                const OSSL_ALGORITHM *algodef,
+                                int no_store, void *vdata)
+{
+    struct deserializer_do_all_data_st *data = vdata;
+    OPENSSL_CTX *libctx = ossl_provider_library_context(provider);
+    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+    const char *names = algodef->algorithm_names;
+    int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
+    void *method = NULL;
+
+    if (id != 0)
+        method =
+            deserializer_from_dispatch(id, algodef, provider);
+
+    if (method != NULL) {
+        data->user_fn(method, data->user_arg);
+        OSSL_DESERIALIZER_free(method);
+    }
+}
+
+void OSSL_DESERIALIZER_do_all_provided(OPENSSL_CTX *libctx,
+                                       void (*fn)(OSSL_DESERIALIZER *deser,
+                                                  void *arg),
+                                       void *arg)
+{
+    struct deserializer_do_all_data_st data;
+
+    data.user_fn = (void (*)(void *, void *))fn;
+    data.user_arg = arg;
+    ossl_algorithm_do_all(libctx, OSSL_OP_DESERIALIZER, NULL,
+                          NULL, deserializer_do_one, NULL,
+                          &data);
+}
+
+void OSSL_DESERIALIZER_names_do_all(const OSSL_DESERIALIZER *deser,
+                                    void (*fn)(const char *name, void *data),
+                                    void *data)
+{
+    if (deser == NULL)
+        return;
+
+    if (deser->base.prov != NULL) {
+        OPENSSL_CTX *libctx = ossl_provider_library_context(deser->base.prov);
+        OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+
+        ossl_namemap_doall_names(namemap, deser->base.id, fn, data);
+    }
+}
+
+const OSSL_PARAM *
+OSSL_DESERIALIZER_gettable_params(OSSL_DESERIALIZER *deser)
+{
+    if (deser != NULL && deser->gettable_params != NULL)
+        return deser->gettable_params();
+    return NULL;
+}
+
+int OSSL_DESERIALIZER_get_params(OSSL_DESERIALIZER *deser, OSSL_PARAM params[])
+{
+    if (deser != NULL && deser->get_params != NULL)
+        return deser->get_params(params);
+    return 0;
+}
+
+const OSSL_PARAM *
+OSSL_DESERIALIZER_settable_ctx_params(OSSL_DESERIALIZER *deser)
+{
+    if (deser != NULL && deser->settable_ctx_params != NULL)
+        return deser->settable_ctx_params();
+    return NULL;
+}
+
+/*
+ * Deserializer context support
+ */
+
+/*
+ * |ser| value NULL is valid, and signifies that there is no deserializer.
+ * This is useful to provide fallback mechanisms.
+ *  Functions that want to verify if there is a deserializer can do so with
+ * OSSL_DESERIALIZER_CTX_get_deserializer()
+ */
+OSSL_DESERIALIZER_CTX *OSSL_DESERIALIZER_CTX_new(void)
+{
+    OSSL_DESERIALIZER_CTX *ctx;
+
+    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    return ctx;
+}
+
+int OSSL_DESERIALIZER_CTX_set_params(OSSL_DESERIALIZER_CTX *ctx,
+                                     const OSSL_PARAM params[])
+{
+    size_t i;
+    size_t l;
+
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if (ctx->deser_insts == NULL)
+        return 1;
+
+    l = (size_t)sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
+    for (i = 0; i < l; i++) {
+        OSSL_DESERIALIZER_INSTANCE *deser_inst =
+            sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, i);
+
+        if (deser_inst->deserctx == NULL
+            || deser_inst->deser->set_ctx_params == NULL)
+            continue;
+        if (!deser_inst->deser->set_ctx_params(deser_inst->deserctx, params))
+            return 0;
+    }
+    return 1;
+}
+
+static void
+OSSL_DESERIALIZER_INSTANCE_free(OSSL_DESERIALIZER_INSTANCE *deser_inst)
+{
+    if (deser_inst != NULL) {
+        if (deser_inst->deser->freectx != NULL)
+            deser_inst->deser->freectx(deser_inst->deserctx);
+        deser_inst->deserctx = NULL;
+        OSSL_DESERIALIZER_free(deser_inst->deser);
+        deser_inst->deser = NULL;
+        OPENSSL_free(deser_inst);
+        deser_inst = NULL;
+    }
+}
+
+void OSSL_DESERIALIZER_CTX_free(OSSL_DESERIALIZER_CTX *ctx)
+{
+    if (ctx != NULL) {
+        if (ctx->cleaner != NULL)
+            ctx->cleaner(ctx->finalize_arg);
+        sk_OSSL_DESERIALIZER_INSTANCE_pop_free(ctx->deser_insts,
+                                               OSSL_DESERIALIZER_INSTANCE_free);
+        UI_destroy_method(ctx->allocated_ui_method);
+        OPENSSL_free(ctx);
+    }
+}
index 970c7c55852932e4090fd334d7dbffb4bb5a9c95..46ff84cc7a53df158f80e548787f92c1f5ed9d09 100644 (file)
@@ -9,17 +9,23 @@
 
 #include <openssl/core_dispatch.h>
 #include <openssl/types.h>
+#include <openssl/safestack.h>
+#include <openssl/serializer.h>
+#include <openssl/deserializer.h>
 #include "internal/cryptlib.h"
 #include "internal/refcount.h"
 
-struct ossl_serializer_st {
+struct ossl_serdes_base_st {
     OSSL_PROVIDER *prov;
     int id;
     const char *propdef;
 
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
+};
 
+struct ossl_serializer_st {
+    struct ossl_serdes_base_st base;
     OSSL_FUNC_serializer_newctx_fn *newctx;
     OSSL_FUNC_serializer_freectx_fn *freectx;
     OSSL_FUNC_serializer_set_ctx_params_fn *set_ctx_params;
@@ -28,15 +34,31 @@ struct ossl_serializer_st {
     OSSL_FUNC_serializer_serialize_object_fn *serialize_object;
 };
 
+struct ossl_deserializer_st {
+    struct ossl_serdes_base_st base;
+    OSSL_FUNC_deserializer_newctx_fn *newctx;
+    OSSL_FUNC_deserializer_freectx_fn *freectx;
+    OSSL_FUNC_deserializer_get_params_fn *get_params;
+    OSSL_FUNC_deserializer_gettable_params_fn *gettable_params;
+    OSSL_FUNC_deserializer_set_ctx_params_fn *set_ctx_params;
+    OSSL_FUNC_deserializer_settable_ctx_params_fn *settable_ctx_params;
+    OSSL_FUNC_deserializer_deserialize_fn *deserialize;
+    OSSL_FUNC_deserializer_export_object_fn *export_object;
+};
+
 struct ossl_serializer_ctx_st {
     OSSL_SERIALIZER *ser;
     void *serctx;
 
     int selection;
 
-    /*
-     * |object| is the libcrypto object to handle.
-     * |do_output| must have intimate knowledge of this object.
+    /*-
+     * Output / serializing data, used by OSSL_SERIALIZER_to_{bio,fp}
+     *
+     * |object|         is the libcrypto object to handle.
+     * |do_output|      performs the actual serialization.
+     *
+     * |do_output| must have intimate knowledge of |object|.
      */
     const void *object;
     int (*do_output)(OSSL_SERIALIZER_CTX *ctx, BIO *out);
@@ -50,3 +72,42 @@ struct ossl_serializer_ctx_st {
      */
     UI_METHOD *allocated_ui_method;
 };
+
+struct ossl_deserializer_instance_st {
+    OSSL_DESERIALIZER *deser;    /* Never NULL */
+    void *deserctx;              /* Never NULL */
+    const char *input_type;      /* Never NULL */
+};
+
+DEFINE_STACK_OF(OSSL_DESERIALIZER_INSTANCE)
+
+struct ossl_deserializer_ctx_st {
+    /*
+     * The caller may know the input type of the data they pass.  If not,
+     * this will remain NULL and the deserializing functionality will start
+     * with trying to deserialize with any desserializer in |deser_insts|,
+     * regardless of their respective input type.
+     */
+    const char *start_input_type;
+
+    /*
+     * Deserializers that are components of any current deserialization path.
+     */
+    STACK_OF(OSSL_DESERIALIZER_INSTANCE) *deser_insts;
+
+    /*
+     * The finalizer of a deserialization, and its caller argument.
+     */
+    OSSL_DESERIALIZER_FINALIZER *finalizer;
+    OSSL_DESERIALIZER_CLEANER *cleaner;
+    void *finalize_arg;
+
+    /* For any function that needs a passphrase reader */
+    const UI_METHOD *ui_method;
+    void *ui_data;
+    /*
+     * if caller used OSSL_SERIALIZER_CTX_set_passphrase_cb(), we need
+     * intermediary storage.
+     */
+    UI_METHOD *allocated_ui_method;
+};
index d7c98891e40f4d9e87144f251828fb5b1a2a9de1..c2ff1c0dcac3220c8db731f719af343e1e82dd23 100644 (file)
@@ -29,13 +29,13 @@ static OSSL_SERIALIZER *ossl_serializer_new(void)
     OSSL_SERIALIZER *ser = NULL;
 
     if ((ser = OPENSSL_zalloc(sizeof(*ser))) == NULL
-        || (ser->lock = CRYPTO_THREAD_lock_new()) == NULL) {
+        || (ser->base.lock = CRYPTO_THREAD_lock_new()) == NULL) {
         OSSL_SERIALIZER_free(ser);
         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
 
-    ser->refcnt = 1;
+    ser->base.refcnt = 1;
 
     return ser;
 }
@@ -44,7 +44,7 @@ int OSSL_SERIALIZER_up_ref(OSSL_SERIALIZER *ser)
 {
     int ref = 0;
 
-    CRYPTO_UP_REF(&ser->refcnt, &ref, ser->lock);
+    CRYPTO_UP_REF(&ser->base.refcnt, &ref, ser->base.lock);
     return 1;
 }
 
@@ -55,11 +55,11 @@ void OSSL_SERIALIZER_free(OSSL_SERIALIZER *ser)
     if (ser == NULL)
         return;
 
-    CRYPTO_DOWN_REF(&ser->refcnt, &ref, ser->lock);
+    CRYPTO_DOWN_REF(&ser->base.refcnt, &ref, ser->base.lock);
     if (ref > 0)
         return;
-    ossl_provider_free(ser->prov);
-    CRYPTO_THREAD_lock_free(ser->lock);
+    ossl_provider_free(ser->base.prov);
+    CRYPTO_THREAD_lock_free(ser->base.lock);
     OPENSSL_free(ser);
 }
 
@@ -165,8 +165,8 @@ static void *serializer_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
 
     if ((ser = ossl_serializer_new()) == NULL)
         return NULL;
-    ser->id = id;
-    ser->propdef = algodef->property_definition;
+    ser->base.id = id;
+    ser->base.propdef = algodef->property_definition;
 
     for (; fns->function_id != 0; fns++) {
         switch (fns->function_id) {
@@ -220,7 +220,7 @@ static void *serializer_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
         return NULL;
     }
 
-    ser->prov = prov;
+    ser->base.prov = prov;
     return ser;
 }
 
@@ -348,7 +348,7 @@ const OSSL_PROVIDER *OSSL_SERIALIZER_provider(const OSSL_SERIALIZER *ser)
         return 0;
     }
 
-    return ser->prov;
+    return ser->base.prov;
 }
 
 const char *OSSL_SERIALIZER_properties(const OSSL_SERIALIZER *ser)
@@ -358,7 +358,7 @@ const char *OSSL_SERIALIZER_properties(const OSSL_SERIALIZER *ser)
         return 0;
     }
 
-    return ser->propdef;
+    return ser->base.propdef;
 }
 
 int OSSL_SERIALIZER_number(const OSSL_SERIALIZER *ser)
@@ -368,16 +368,16 @@ int OSSL_SERIALIZER_number(const OSSL_SERIALIZER *ser)
         return 0;
     }
 
-    return ser->id;
+    return ser->base.id;
 }
 
 int OSSL_SERIALIZER_is_a(const OSSL_SERIALIZER *ser, const char *name)
 {
-    if (ser->prov != NULL) {
-        OPENSSL_CTX *libctx = ossl_provider_library_context(ser->prov);
+    if (ser->base.prov != NULL) {
+        OPENSSL_CTX *libctx = ossl_provider_library_context(ser->base.prov);
         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
 
-        return ossl_namemap_name2num(namemap, name) == ser->id;
+        return ossl_namemap_name2num(namemap, name) == ser->base.id;
     }
     return 0;
 }
@@ -433,11 +433,11 @@ void OSSL_SERIALIZER_names_do_all(const OSSL_SERIALIZER *ser,
     if (ser == NULL)
         return;
 
-    if (ser->prov != NULL) {
-        OPENSSL_CTX *libctx = ossl_provider_library_context(ser->prov);
+    if (ser->base.prov != NULL) {
+        OPENSSL_CTX *libctx = ossl_provider_library_context(ser->base.prov);
         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
 
-        ossl_namemap_doall_names(namemap, ser->id, fn, data);
+        ossl_namemap_doall_names(namemap, ser->base.id, fn, data);
     }
 }
 
diff --git a/doc/man3/OSSL_DESERIALIZER.pod b/doc/man3/OSSL_DESERIALIZER.pod
new file mode 100644 (file)
index 0000000..5562a81
--- /dev/null
@@ -0,0 +1,146 @@
+=pod
+
+=head1 NAME
+
+OSSL_DESERIALIZER,
+OSSL_DESERIALIZER_fetch,
+OSSL_DESERIALIZER_up_ref,
+OSSL_DESERIALIZER_free,
+OSSL_DESERIALIZER_provider,
+OSSL_DESERIALIZER_properties,
+OSSL_DESERIALIZER_is_a,
+OSSL_DESERIALIZER_number,
+OSSL_DESERIALIZER_do_all_provided,
+OSSL_DESERIALIZER_names_do_all,
+OSSL_DESERIALIZER_gettable_params,
+OSSL_DESERIALIZER_get_params
+- Deserializer method routines
+
+=head1 SYNOPSIS
+
+ #include <openssl/deserializer.h>
+
+ typedef struct ossl_deserializer_st OSSL_DESERIALIZER;
+
+ OSSL_DESERIALIZER *OSSL_DESERIALIZER_fetch(OPENSSL_CTX *ctx, const char *name,
+                                            const char *properties);
+ int OSSL_DESERIALIZER_up_ref(OSSL_DESERIALIZER *deserializer);
+ void OSSL_DESERIALIZER_free(OSSL_DESERIALIZER *deserializer);
+ const OSSL_PROVIDER *OSSL_DESERIALIZER_provider(const OSSL_DESERIALIZER
+                                                 *deserializer);
+ const char *OSSL_DESERIALIZER_properties(const OSSL_DESERIALIZER *deser);
+ int OSSL_DESERIALIZER_is_a(const OSSL_DESERIALIZER *deserializer,
+                            const char *name);
+ int OSSL_DESERIALIZER_number(const OSSL_DESERIALIZER *deserializer);
+ void OSSL_DESERIALIZER_do_all_provided(OPENSSL_CTX *libctx,
+                                        void (*fn)(OSSL_DESERIALIZER *deserializer,
+                                                   void *arg),
+                                        void *arg);
+ void OSSL_DESERIALIZER_names_do_all(const OSSL_DESERIALIZER *deserializer,
+                                     void (*fn)(const char *name, void *data),
+                                     void *data);
+ const OSSL_PARAM *OSSL_DESERIALIZER_gettable_params(OSSL_DESERIALIZER *deser);
+ int OSSL_DESERIALIZER_get_params(OSSL_DESERIALIZER_CTX *ctx,
+                                  const OSSL_PARAM params[]);
+
+=head1 DESCRIPTION
+
+B<OSSL_DESERIALIZER> is a method for deserializers, which know how to
+deserialize serialized data into an object of some type that the rest
+of OpenSSL knows how to handle.
+
+OSSL_DESERIALIZER_fetch() looks for an algorithm within the provider that
+has been loaded into the B<OPENSSL_CTX> given by I<ctx>, having the
+name given by I<name> and the properties given by I<properties>.
+The I<name> determines what type of object the fetched deserializer
+method is expected to be able to deserialize, and the properties are
+used to determine the expected output type.
+For known properties and the values they may have, please have a look
+in L<provider-serializer(7)/Names and properties>.
+
+OSSL_DESERIALIZER_up_ref() increments the reference count for the given
+I<deserializer>.
+
+OSSL_DESERIALIZER_free() decrements the reference count for the given
+I<deserializer>, and when the count reaches zero, frees it.
+
+OSSL_DESERIALIZER_provider() returns the provider of the given
+I<deserializer>.
+
+OSSL_DESERIALIZER_properties() returns the property definition associated
+with the given I<deserializer>.
+
+OSSL_DESERIALIZER_is_a() checks if I<deserializer> is an implementation
+of an algorithm that's identifiable with I<name>.
+
+OSSL_DESERIALIZER_number() returns the internal dynamic number assigned
+to the given I<deserializer>.
+
+OSSL_DESERIALIZER_names_do_all() traverses all names for the given
+I<deserializer>, and calls I<fn> with each name and I<data>.
+
+OSSL_DESERIALIZER_do_all_provided() traverses all serializer
+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_DESERIALIZER_gettable_params() returns an L<OSSL_PARAM(3)>
+array of parameter descriptors.
+
+OSSL_DESERIALIZER_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 RETURN VALUES
+
+OSSL_DESERIALIZER_fetch() returns a pointer to an OSSL_DESERIALIZER object,
+or NULL on error.
+
+OSSL_DESERIALIZER_up_ref() returns 1 on success, or 0 on error.
+
+OSSL_DESERIALIZER_free() doesn't return any value.
+
+OSSL_DESERIALIZER_provider() returns a pointer to a provider object, or
+NULL on error.
+
+OSSL_DESERIALIZER_properties() returns a pointer to a property
+definition string, or NULL on error.
+
+OSSL_DESERIALIZER_is_a() returns 1 if I<deserializer> was identifiable,
+otherwise 0.
+
+OSSL_DESERIALIZER_number() returns an integer.
+
+=head1 NOTES
+
+OSSL_DESERIALIZER_fetch() may be called implicitly by other fetching
+functions, using the same library context and properties.
+Any other API that uses keys will typically do this.
+
+=begin comment TODO(3.0) Add examples!
+
+=head1 EXAMPLES
+
+Text, because pod2xxx doesn't like empty sections
+
+=end comment
+
+=head1 SEE ALSO
+
+L<provider(7)>, L<OSSL_DESERIALIZER_CTX(3)>, L<OSSL_DESERIALIZER_from_bio(3)>,
+L<OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY(3)>, L<OPENSSL_CTX(3)>
+
+=head1 HISTORY
+
+The functions described here were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 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
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/OSSL_DESERIALIZER_CTX.pod b/doc/man3/OSSL_DESERIALIZER_CTX.pod
new file mode 100644 (file)
index 0000000..413584f
--- /dev/null
@@ -0,0 +1,74 @@
+=pod
+
+=head1 NAME
+
+OSSL_DESERIALIZER_CTX,
+OSSL_DESERIALIZER_CTX_new,
+OSSL_DESERIALIZER_settable_ctx_params,
+OSSL_DESERIALIZER_CTX_set_params,
+OSSL_DESERIALIZER_CTX_free
+- Serializer context routines
+
+=head1 SYNOPSIS
+
+ #include <openssl/deserializer.h>
+
+ typedef struct ossl_deserializer_ctx_st OSSL_DESERIALIZER_CTX;
+
+ OSSL_DESERIALIZER_CTX *OSSL_DESERIALIZER_CTX_new(OPENSSL_CTX *libctx);
+ const OSSL_PARAM *OSSL_DESERIALIZER_settable_ctx_params(OSSL_DESERIALIZER *deser);
+ int OSSL_DESERIALIZER_CTX_set_params(OSSL_DESERIALIZER_CTX *ctx,
+                                      const OSSL_PARAM params[]);
+ void OSSL_DESERIALIZER_CTX_free(OSSL_DESERIALIZER_CTX *ctx);
+
+=head1 DESCRIPTION
+
+B<OSSL_DESERIALIZER_CTX> is a context with which B<OSSL_DESERIALIZER>
+operations are performed.  The context typically holds values, both
+internal and supplied by the application, which are useful for the
+implementations supplied by providers.
+
+OSSL_DESERIALIZER_CTX_new() creates a new empty B<OSSL_DESERIALIZER_CTX>.
+
+OSSL_DESERIALIZER_settable_ctx_params() returns an L<OSSL_PARAM(3)>
+array of parameter descriptors.
+
+OSSL_DESERIALIZER_CTX_set_params() attempts to set parameters specified
+with an L<OSSL_PARAM(3)> array I<params>.  These parameters are passed
+to all deserializers that have been added to the I<ctx> so far.
+Parameters that an implementation doesn't recognise should be ignored
+by it.
+
+OSSL_DESERIALIZER_CTX_free() frees the given context I<ctx>.
+
+=head1 RETURN VALUES
+
+OSSL_DESERIALIZER_CTX_new() returns a pointer to a
+B<OSSL_DESERIALIZER_CTX>, or NULL if the context structure couldn't be
+allocated.
+
+OSSL_DESERIALIZER_settable_ctx_params() returns an L<OSSL_PARAM(3)>
+array, or NULL if none is available.
+
+OSSL_DESERIALIZER_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.
+
+=head1 SEE ALSO
+
+L<provider(7)>, L<OSSL_DESERIALIZER(3)>, L<OSSL_DESERIALIZER_from_bio(3)>
+
+=head1 HISTORY
+
+The functions described here were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 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
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/OSSL_DESERIALIZER_from_bio.pod b/doc/man3/OSSL_DESERIALIZER_from_bio.pod
new file mode 100644 (file)
index 0000000..8c372a6
--- /dev/null
@@ -0,0 +1,253 @@
+=pod
+
+=head1 NAME
+
+OSSL_DESERIALIZER_from_bio,
+OSSL_DESERIALIZER_from_fp,
+OSSL_DESERIALIZER_CTX_set_input_type,
+OSSL_DESERIALIZER_CTX_add_deserializer,
+OSSL_DESERIALIZER_CTX_add_extra,
+OSSL_DESERIALIZER_CTX_num_deserializers,
+OSSL_DESERIALIZER_INSTANCE,
+OSSL_DESERIALIZER_FINALIZER,
+OSSL_DESERIALIZER_CLEANER,
+OSSL_DESERIALIZER_CTX_set_finalizer,
+OSSL_DESERIALIZER_export,
+OSSL_DESERIALIZER_INSTANCE_deserializer,
+OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
+- Routines to perform a deserialization
+
+=head1 SYNOPSIS
+
+ #include <openssl/deserializer.h>
+
+ int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in);
+ int OSSL_DESERIALIZER_from_fp(OSSL_DESERIALIZER_CTX *ctx, FILE *fp);
+
+ int OSSL_DESERIALIZER_CTX_set_input_type(OSSL_DESERIALIZER_CTX *ctx,
+                                          const char *input_type);
+ int OSSL_DESERIALIZER_CTX_add_deserializer(OSSL_DESERIALIZER_CTX *ctx,
+                                            OSSL_DESERIALIZER *deser);
+ int OSSL_DESERIALIZER_CTX_add_extra(OSSL_DESERIALIZER_CTX *ctx);
+ int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx);
+
+ typedef struct ossl_deserializer_instance_st OSSL_DESERIALIZER_INSTANCE;
+ typedef int (OSSL_DESERIALIZER_FINALIZER)
+     (OSSL_DESERIALIZER_INSTANCE *deser_inst,
+      const OSSL_PARAM *params, void *finalize_arg);
+ typedef void (OSSL_DESERIALIZER_CLEANER)(void *finalize_arg);
+
+ int OSSL_DESERIALIZER_CTX_set_finalizer(OSSL_DESERIALIZER_CTX *ctx,
+                                         OSSL_DESRIALIZER_FINALIZER *finalizer,
+                                         OSSL_DESERIALIZER_CLEANER *cleaner,
+                                         void *finalize_arg);
+
+ int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
+                              void *reference, size_t reference_sz,
+                              OSSL_CALLBACK *export_cb, void *export_cbarg);
+
+ OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
+     (OSSL_DESERIALIZER_INSTANCE *deser_inst);
+ void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
+     (OSSL_DESERIALIZER_INSTANCE *deser_inst);
+
+Feature availability macros:
+
+=over 4
+
+=item OSSL_DESERIALIZER_from_fp() is only available when B<OPENSSL_NO_STDIO>
+is undefined.
+
+=back
+
+=head1 DESCRIPTION
+
+The B<OSSL_DESERIALIZER_CTX> holds data about multiple deserializers, as
+needed to figure out what the input data is and to attempt to unpack it into
+one of several possible related results.  This also includes chaining
+deserializers, so the output from one can become the input for another.
+This allows having generic format deserializers such as PEM to DER, as well
+as more specialized deserializers like DER to RSA.
+
+The chains may be limited by specifying an input type, which is considered a
+starting point.
+This is both considered by OSSL_DESERIALIZER_CTX_add_extra(), which will
+stop adding on more deserializer implementations when it has already added
+those that take the specified input type, and OSSL_DESERIALIZER_from_bio(),
+which will only start the deserializing process with the deserializer
+implementations that take that input type.  For example, if the input type
+is set to C<DER>, a PEM to DER deserializer will be ignored.
+
+The input type can also be NULL, which means that the caller doesn't know
+what type of input they have.  In this case, OSSL_DESERIALIZER_from_bio()
+will simply try with one deserializer implementation after the other, and
+thereby discover what kind of input the caller gave it.
+
+For every deserialization done, even intermediary, a I<finalizer>
+provided by the caller is used to attempt to "finalize" the current
+deserialization output, which is always a provider side object of some
+sort, by "wrapping" it into some appropriate type or structure that
+the caller knows how to handle.  Exactly what this "wrapping" consists
+of is entirely at the discretion of the I<finalizer>.
+
+B<OSSL_DESERIALIZER_INSTANCE> is an opaque structure that contains
+data about the deserializer that was just used, and that may be
+useful for the I<finalizer>.  There are some functions to extract data
+from this type, described further down.
+
+=head2 Functions
+
+OSSL_DESERIALIZER_from_bio() runs the deserialization process for the
+context I<ctx>, with the input coming from the B<BIO> I<in>.  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 deserializer!
+
+OSSL_DESERIALIZER_from_fp() does the same thing as OSSL_DESERIALIZER_from_bio(),
+except that the input is coming from the B<FILE> I<fp>.
+
+OSSL_DESERIALIZER_CTX_add_deserializer() populates the B<OSSL_DESERIALIZER_CTX>
+I<ctx> with a deserializer, to be used to attempt to deserialize some
+serialized input.
+
+OSSL_DESERIALIZER_CTX_add_extra() finds deserializers that generate
+input for already added deserializers, and adds them as well.  This is
+used to build deserializer chains.
+
+OSSL_DESERIALIZER_CTX_set_input_type() sets the starting input type.  This
+limits the deserializer chains to be considered, as explained in the general
+description above.
+
+OSSL_DESERIALIZER_CTX_num_deserializers() gets the number of
+deserializers currently added to the context I<ctx>.
+
+OSSL_DESERIALIZER_CTX_set_finalizer() sets the I<finalizer> function
+together with the caller argument for the finalizer, I<finalize_arg>,
+as well as I<cleaner>, the function to clean up I<finalize_arg> when
+the deserialization has concluded.
+
+OSSL_DESERIALIZER_export() is a fallback function for I<finalizers>
+that can't use the data they get directly for diverse reasons.  It
+takes the same deserialize instance I<deser_inst> that the
+I<finalizer> got and an object I<reference>, unpacks the object that
+refers to, and exports it by creating an L<OSSL_PARAM(3)> array that
+it then passes to I<export_cb>, along with I<export_arg>.
+
+OSSL_DESERIALIZER_INSTANCE_deserializer() can be used to get the
+deserializer method from a deserializer instance I<deser_inst>.
+
+OSSL_DESERIALIZER_INSTANCE_deserializer-ctx() can be used to get the
+deserializer method's provider context from a deserializer instance
+I<deser_inst>.
+
+=head2 Finalizer
+
+The I<finalizer> gets the following arguments:
+
+=over 4
+
+=item I<deser_inst>
+
+The B<OSSL_DESERIALIZER_INSTANCE> for the deserializer from which
+I<finalizer> gets its data.
+
+=item I<params>
+
+The data produced by the deserializer, further described below.
+
+=item I<finalize_arg>
+
+The pointer that was set with OSSL_DESERIALIZE_CTX_set_finalizer() as
+I<finalize_arg>.
+
+=back
+
+The I<finalizer> is expected to return 1 when the data it receives can
+be "finalized", otherwise 0.
+
+The globally known parameters that I<finalize> can get in I<params>
+are:
+
+=over 4
+
+=item "data-type" (B<OSSL_DESERIALIZER_PARAM_DATA_TYPE>) <UTF8 string>
+
+This is a detected content type that some deserializers may provide.
+For example, PEM input sometimes has a type specified in its header,
+and some deserializers may add that information as this parameter.
+This is an optional parameter, but may be useful for extra checks in
+the I<finalizer>.
+
+=item "data" (B<OSSL_DESERIALIZER_PARAM_DATA>) <octet string>
+
+The deserialized data itself, as an octet string.  This is produced by
+deserializers when it's possible to pass an object in this form.  Most
+often, this is simply meant to be passed to the next deserializer in a
+chain, but could be considered final data as well, at the discretion
+of the I<finalizer>.
+
+=item "reference" (B<OSSL_DESERIALIZER_PARAM_DATA>) <octet string>
+
+The deserialized data itself, as a reference to an object.  The
+reference itself is an octet string, and can be passed to other
+operations and functions within the same provider as the one that
+provides I<deser>.
+
+=back
+
+At least one of "data" or "reference" must be present, and it's
+possible that both can be.  A I<finalizer> should choose to use the
+"reference" parameter if possible, otherwise the "data" parameter.
+
+If it's not possible to use the "reference" parameter, but that's
+still what a I<finalizer> wants to do, it is possible to use
+OSSL_DESERIALIZER_export() as a fallback.
+
+=head1 RETURN VALUES
+
+OSSL_DESERIALIZER_from_bio() and OSSL_DESERIALIZER_from_fp() return 1 on
+success, or 0 on failure.
+
+OSSL_DESERIALIZER_CTX_add_deserializer(),
+OSSL_DESERIALIZER_CTX_add_extra(), and
+OSSL_DESERIALIZER_CTX_set_finalizer() return 1 on success, or 0 on
+failure.
+
+OSSL_DESERIALIZER_CTX_num_deserializers() returns the current
+number of deserializers.  It returns 0 if I<ctx> is NULL.
+
+OSSL_DESERIALIZER_export() returns 1 on success, or 0 on failure.
+
+OSSL_DESERIALIZER_INSTANCE_deserializer() returns an
+B<OSSL_DESERIALIZER> pointer on success, or NULL on failure.
+
+OSSL_DESERIALIZER_INSTANCE_deserializer_ctx() returns a provider
+context pointer on success, or NULL on failure.>
+
+=begin comment TODO(3.0) Add examples!
+
+=head1 EXAMPLES
+
+Text, because pod2xxx doesn't like empty sections
+
+=end comment
+
+=head1 SEE ALSO
+
+L<provider(7)>, L<OSSL_DESERIALIZER_CTX(3)>
+
+=head1 HISTORY
+
+The functions described here were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 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
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
index c40788f78b766ddca48afe57292bb85fbaf50267..df4953994f8842a19669eb910b4fff183b5fd18b 100644 (file)
@@ -11,3 +11,5 @@
 
 OSSL_SERIALIZER *ossl_serializer_fetch_by_number(OPENSSL_CTX *libctx, int id,
                                                  const char *properties);
+OSSL_DESERIALIZER *ossl_deserializer_fetch_by_number(OPENSSL_CTX *libctx, int id,
+                                                     const char *properties);
index fba1d5643fead9723c0beaa64dc1e9de9a1344b7..d0dd6fe2b5e97938f4ebd13b203d1f4e2e60b04f 100644 (file)
@@ -156,10 +156,11 @@ typedef struct ossl_ex_data_global_st {
 # define OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX     8
 # define OPENSSL_CTX_FIPS_PROV_INDEX                9
 # define OPENSSL_CTX_SERIALIZER_STORE_INDEX        10
-# define OPENSSL_CTX_SELF_TEST_CB_INDEX            11
-# define OPENSSL_CTX_BIO_PROV_INDEX                12
-# define OPENSSL_CTX_GLOBAL_PROPERTIES             13
-# define OPENSSL_CTX_MAX_INDEXES                   14
+# define OPENSSL_CTX_DESERIALIZER_STORE_INDEX      11
+# define OPENSSL_CTX_SELF_TEST_CB_INDEX            12
+# define OPENSSL_CTX_BIO_PROV_INDEX                13
+# define OPENSSL_CTX_GLOBAL_PROPERTIES             14
+# define OPENSSL_CTX_MAX_INDEXES                   15
 
 typedef struct openssl_ctx_method {
     void *(*new_func)(OPENSSL_CTX *ctx);
index efb05d404b44f4465df3499e2a093bba8b5fbfe0..8dba65b5560030f3a4bf6d10de7611a4fe6f88d1 100644 (file)
@@ -185,8 +185,9 @@ OSSL_CORE_MAKE_FUNC(int, provider_get_capabilities, (void *provctx,
 # define OSSL_OP_ASYM_CIPHER                        13
 /* New section for non-EVP operations */
 # define OSSL_OP_SERIALIZER                         20
+# define OSSL_OP_DESERIALIZER                       21
 /* Highest known operation number */
-# define OSSL_OP__HIGHEST                           20
+# define OSSL_OP__HIGHEST                           21
 
 /* Digests */
 
@@ -694,7 +695,7 @@ OSSL_CORE_MAKE_FUNC(int, asym_cipher_set_ctx_params,
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, asym_cipher_settable_ctx_params,
                     (void))
 
-/* Serializers */
+/* Serializers and deserializers */
 # define OSSL_FUNC_SERIALIZER_NEWCTX                1
 # define OSSL_FUNC_SERIALIZER_FREECTX               2
 # define OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS        3
@@ -715,6 +716,31 @@ OSSL_CORE_MAKE_FUNC(int, serializer_serialize_object,
                     (void *ctx, void *obj, OSSL_CORE_BIO *out,
                      OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg))
 
+# define OSSL_FUNC_DESERIALIZER_NEWCTX              1
+# define OSSL_FUNC_DESERIALIZER_FREECTX             2
+# define OSSL_FUNC_DESERIALIZER_GET_PARAMS          3
+# define OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS     4
+# define OSSL_FUNC_DESERIALIZER_SET_CTX_PARAMS      5
+# define OSSL_FUNC_DESERIALIZER_SETTABLE_CTX_PARAMS 6
+# define OSSL_FUNC_DESERIALIZER_DESERIALIZE        10
+# define OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT      11
+OSSL_CORE_MAKE_FUNC(void *, deserializer_newctx, (void *provctx))
+OSSL_CORE_MAKE_FUNC(void, deserializer_freectx, (void *ctx))
+OSSL_CORE_MAKE_FUNC(int, deserializer_get_params, (OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, deserializer_gettable_params, (void))
+OSSL_CORE_MAKE_FUNC(int, deserializer_set_ctx_params,
+                    (void *ctx, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, deserializer_settable_ctx_params,
+                    (void))
+
+OSSL_CORE_MAKE_FUNC(int, deserializer_deserialize,
+                    (void *ctx, OSSL_CORE_BIO *in,
+                     OSSL_CALLBACK *metadata_cb, void *metadata_cbarg,
+                     OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg))
+OSSL_CORE_MAKE_FUNC(int, deserializer_export_object,
+                    (void *ctx, const void *objref, size_t objref_sz,
+                     OSSL_CALLBACK *export_cb, void *export_cbarg))
+
 # ifdef __cplusplus
 }
 # endif
index 702ee6a6ed432a6167ccd2e41d3bfb07d68824af..c380b45fbbaa139a1341355147c3a416c86f8669 100644 (file)
@@ -397,13 +397,18 @@ extern "C" {
 #define OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION   "tls-negotiated-version"
 
 /*
- * Serializer parameters
+ * Serializer / deserializer parameters
  */
 /* The passphrase may be passed as a utf8 string or an octet string */
 #define OSSL_SERIALIZER_PARAM_CIPHER            OSSL_ALG_PARAM_CIPHER
 #define OSSL_SERIALIZER_PARAM_PROPERTIES        OSSL_ALG_PARAM_PROPERTIES
 #define OSSL_SERIALIZER_PARAM_PASS              "passphrase"
 
+#define OSSL_DESERIALIZER_PARAM_INPUT_TYPE      "input-type"
+#define OSSL_DESERIALIZER_PARAM_DATA_TYPE       "data-type"
+#define OSSL_DESERIALIZER_PARAM_DATA            "data"
+#define OSSL_DESERIALIZER_PARAM_REFERENCE       "reference"
+
 /* Passphrase callback parameters */
 #define OSSL_PASSPHRASE_PARAM_INFO              "info"
 
diff --git a/include/openssl/deserializer.h b/include/openssl/deserializer.h
new file mode 100644 (file)
index 0000000..89a230c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_DESERIALIZER_H
+# define OPENSSL_DESERIALIZER_H
+# pragma once
+
+# include <openssl/opensslconf.h>
+
+# ifndef OPENSSL_NO_STDIO
+#  include <stdio.h>
+# endif
+# include <stdarg.h>
+# include <stddef.h>
+# include <openssl/deserializererr.h>
+# include <openssl/types.h>
+# include <openssl/core.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+OSSL_DESERIALIZER *OSSL_DESERIALIZER_fetch(OPENSSL_CTX *libctx,
+                                           const char *name,
+                                           const char *properties);
+int OSSL_DESERIALIZER_up_ref(OSSL_DESERIALIZER *ser);
+void OSSL_DESERIALIZER_free(OSSL_DESERIALIZER *ser);
+
+const OSSL_PROVIDER *OSSL_DESERIALIZER_provider(const OSSL_DESERIALIZER *ser);
+const char *OSSL_DESERIALIZER_properties(const OSSL_DESERIALIZER *ser);
+int OSSL_DESERIALIZER_number(const OSSL_DESERIALIZER *ser);
+int OSSL_DESERIALIZER_is_a(const OSSL_DESERIALIZER *ser,
+                           const char *name);
+
+void OSSL_DESERIALIZER_do_all_provided(OPENSSL_CTX *libctx,
+                                       void (*fn)(OSSL_DESERIALIZER *ser,
+                                                  void *arg),
+                                       void *arg);
+void OSSL_DESERIALIZER_names_do_all(const OSSL_DESERIALIZER *ser,
+                                    void (*fn)(const char *name, void *data),
+                                    void *data);
+const OSSL_PARAM *OSSL_DESERIALIZER_gettable_params(OSSL_DESERIALIZER *deser);
+int OSSL_DESERIALIZER_get_params(OSSL_DESERIALIZER *deser, OSSL_PARAM params[]);
+
+const OSSL_PARAM *OSSL_DESERIALIZER_settable_ctx_params(OSSL_DESERIALIZER *ser);
+OSSL_DESERIALIZER_CTX *OSSL_DESERIALIZER_CTX_new(void);
+int OSSL_DESERIALIZER_CTX_set_params(OSSL_DESERIALIZER_CTX *ctx,
+                                     const OSSL_PARAM params[]);
+void OSSL_DESERIALIZER_CTX_free(OSSL_DESERIALIZER_CTX *ctx);
+
+/* Utilities that help set specific parameters */
+int OSSL_DESERIALIZER_CTX_set_cipher(OSSL_DESERIALIZER_CTX *ctx,
+                                     const char *cipher_name,
+                                     const char *propquery);
+int OSSL_DESERIALIZER_CTX_set_passphrase(OSSL_DESERIALIZER_CTX *ctx,
+                                         const unsigned char *kstr,
+                                         size_t klen);
+int OSSL_DESERIALIZER_CTX_set_passphrase_cb(OSSL_DESERIALIZER_CTX *ctx, int enc,
+                                            pem_password_cb *cb, void *cbarg);
+int OSSL_DESERIALIZER_CTX_set_passphrase_ui(OSSL_DESERIALIZER_CTX *ctx,
+                                            const UI_METHOD *ui_method,
+                                            void *ui_data);
+
+/*
+ * Utilities to read the object to deserialize, with the result sent to cb.
+ * These will discover all provided methods
+ */
+
+int OSSL_DESERIALIZER_CTX_set_input_type(OSSL_DESERIALIZER_CTX *ctx,
+                                         const char *input_type);
+int OSSL_DESERIALIZER_CTX_add_deserializer(OSSL_DESERIALIZER_CTX *ctx,
+                                           OSSL_DESERIALIZER *deser);
+int OSSL_DESERIALIZER_CTX_add_extra(OSSL_DESERIALIZER_CTX *ctx,
+                                    OPENSSL_CTX *libctx, const char *propq);
+int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx);
+
+typedef struct ossl_deserializer_instance_st OSSL_DESERIALIZER_INSTANCE;
+typedef int (OSSL_DESERIALIZER_FINALIZER)
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst,
+     const OSSL_PARAM *params, void *finalize_arg);
+typedef void (OSSL_DESERIALIZER_CLEANER)(void *finalize_arg);
+
+int OSSL_DESERIALIZER_CTX_set_finalizer(OSSL_DESERIALIZER_CTX *ctx,
+                                        OSSL_DESERIALIZER_FINALIZER *finalizer,
+                                        OSSL_DESERIALIZER_CLEANER *cleaner,
+                                        void *finalize_arg);
+
+int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
+                             void *reference, size_t reference_sz,
+                             OSSL_CALLBACK *export_cb, void *export_cbarg);
+
+OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst);
+void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst);
+
+int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in);
+#ifndef OPENSSL_NO_STDIO
+int OSSL_DESERIALIZER_from_fp(OSSL_DESERIALIZER_CTX *ctx, FILE *in);
+#endif
+
+# ifdef __cplusplus
+}
+# endif
+#endif
diff --git a/include/openssl/deserializererr.h b/include/openssl/deserializererr.h
new file mode 100644 (file)
index 0000000..1c6573a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_OSSL_DESERIALIZERERR_H
+# define OPENSSL_OSSL_DESERIALIZERERR_H
+# pragma once
+
+# include <openssl/opensslconf.h>
+# include <openssl/symhacks.h>
+
+
+# ifdef  __cplusplus
+extern "C"
+# endif
+int ERR_load_OSSL_DESERIALIZER_strings(void);
+
+/*
+ * OSSL_DESERIALIZER function codes.
+ */
+# ifndef OPENSSL_NO_DEPRECATED_3_0
+# endif
+
+/*
+ * OSSL_DESERIALIZER reason codes.
+ */
+# define OSSL_DESERIALIZER_R_MISSING_GET_PARAMS           100
+
+#endif
index a40d231ea098944ea549dec42bf9802675e1c8e9..fd3b93aa47de7a25cf415b7136e249764701a1c3 100644 (file)
@@ -114,7 +114,8 @@ struct err_state_st {
 # define ERR_LIB_PROV            57
 # define ERR_LIB_CMP             58
 # define ERR_LIB_OSSL_SERIALIZER 59
-# define ERR_LIB_HTTP            60
+# define ERR_LIB_OSSL_DESERIALIZER 60
+# define ERR_LIB_HTTP            61
 
 # define ERR_LIB_USER            128
 
index d43950a8097cbf2682e6b9e1a8e88a0bd78be55a..496f42a101bd741d2240778373ade8f0eb8d3214 100644 (file)
@@ -214,6 +214,8 @@ typedef int pem_password_cb (char *buf, int size, int rwflag, void *userdata);
 
 typedef struct ossl_serializer_st OSSL_SERIALIZER;
 typedef struct ossl_serializer_ctx_st OSSL_SERIALIZER_CTX;
+typedef struct ossl_deserializer_st OSSL_DESERIALIZER;
+typedef struct ossl_deserializer_ctx_st OSSL_DESERIALIZER_CTX;
 
 typedef struct ossl_self_test_st OSSL_SELF_TEST;
 
index 5aff5d5c4468b8efab72a0651e837ac083faa2dd..30d500f18f1b789b69842afc660c5eefa2f817ab 100644 (file)
@@ -5149,3 +5149,33 @@ X509_STORE_load_store_with_libctx       ?        3_0_0   EXIST::FUNCTION:
 X509_STORE_load_locations_with_libctx   ?      3_0_0   EXIST::FUNCTION:
 X509_STORE_set_default_paths_with_libctx ?     3_0_0   EXIST::FUNCTION:
 OSSL_STORE_open_with_libctx             ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_fetch                 ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_up_ref                ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_free                  ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_provider              ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_properties            ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_number                ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_is_a                  ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_do_all_provided       ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_names_do_all          ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_settable_ctx_params   ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_new               ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_params        ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_free              ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_cipher        ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_passphrase    ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_passphrase_cb ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_passphrase_ui ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_from_bio              ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_from_fp               ?      3_0_0   EXIST::FUNCTION:STDIO
+OSSL_DESERIALIZER_CTX_add_deserializer  ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_add_extra         ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_num_deserializers ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_finalizer     ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_input_type    ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_export                ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_INSTANCE_deserializer ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_INSTANCE_deserializer_ctx ?  3_0_0   EXIST::FUNCTION:
+ERR_load_OSSL_DESERIALIZER_strings      ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_gettable_params       ?      3_0_0   EXIST::FUNCTION:
+OSSL_DESERIALIZER_get_params            ?      3_0_0   EXIST::FUNCTION:
index 0034a711d1d6f75d3c071bf5a401f194ad8d515f..0e5bb35878fd51adcb466d49f7efb078e7498f27 100644 (file)
@@ -636,6 +636,7 @@ ERR_load_KDF_strings(3)
 ERR_load_OBJ_strings(3)
 ERR_load_OCSP_strings(3)
 ERR_load_OSSL_SERIALIZER_strings(3)
+ERR_load_OSSL_DESERIALIZER_strings(3)
 ERR_load_OSSL_STORE_strings(3)
 ERR_load_PEM_strings(3)
 ERR_load_PKCS12_strings(3)
index 54a2b71abb5729b01284f9608f5b008708168220..a623ff5e775f41a735a1385fcd16d0b47571eb81 100644 (file)
@@ -41,6 +41,12 @@ GEN_SESSION_CB                          datatype
 OPENSSL_Applink                         external
 OPENSSL_CTX                             datatype
 NAMING_AUTHORITY                        datatype
+OSSL_DESERIALIZER                       datatype
+OSSL_DESERIALIZER_CTX                   datatype
+OSSL_DESERIALIZER_FINALIZER             datatype
+OSSL_DESERIALIZER_CLEANER               datatype
+OSSL_DESERIALIZER_INSTANCE              datatype
+OSSL_DESERIALIZER_CTX                   datatype
 OSSL_HTTP_bio_cb_t                      datatype
 OSSL_PARAM                              datatype
 OSSL_PROVIDER                           datatype