Rename OSSL_SERIALIZER / OSSL_DESERIALIZER to OSSL_ENCODE / OSSL_DECODE

Fixes #12455

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12660)
master
Richard Levitte 3 years ago
parent f650993f1d
commit ece9304c96

@ -612,22 +612,22 @@ OpenSSL 3.0
*Rich Salz*
* Introduced a new method type and API, OSSL_SERIALIZER, to
represent generic serializers. An implementation is expected to
be able to serialize an object associated with a given name (such
* Introduced a new method type and API, OSSL_ENCODER, to
represent generic encoders. An implementation is expected to
be able to encode an object associated with a given name (such
as an algorithm name for an asymmetric key) into forms given by
implementation properties.
Serializers are primarily used from inside libcrypto, through
Encoders are primarily used from inside libcrypto, through
calls to functions like EVP_PKEY_print_private(),
PEM_write_bio_PrivateKey() and similar.
Serializers are specified in such a way that they can be made to
Encoders are specified in such a way that they can be made to
directly handle the provider side portion of an object, if this
provider side part comes from the same provider as the serializer
provider side part comes from the same provider as the encoder
itself, but can also be made to handle objects in parametrized
form (as an OSSL_PARAM array of data). This allows a provider to
offer generic serializers as a service for any other provider.
offer generic encoders as a service for any other provider.
*Richard Levitte*
@ -769,13 +769,13 @@ OpenSSL 3.0
*Richard Levitte*
* For built-in EC curves, ensure an EC_GROUP built from the curve name is
used even when parsing explicit parameters, when loading a serialized key
used even when parsing explicit parameters, when loading a encoded key
or calling `EC_GROUP_new_from_ecpkparameters()`/
`EC_GROUP_new_from_ecparameters()`.
This prevents bypass of security hardening and performance gains,
especially for curves with specialized EC_METHODs.
By default, if a key encoded with explicit parameters is loaded and later
serialized, the output is still encoded with explicit parameters, even if
encoded, the output is still encoded with explicit parameters, even if
internally a "named" EC_GROUP is used for computation.
*Nicola Tuveri*
@ -1255,13 +1255,13 @@ OpenSSL 1.1.1
*Matthias St. Pierre*
* For built-in EC curves, ensure an EC_GROUP built from the curve name is
used even when parsing explicit parameters, when loading a serialized key
used even when parsing explicit parameters, when loading a encoded key
or calling `EC_GROUP_new_from_ecpkparameters()`/
`EC_GROUP_new_from_ecparameters()`.
This prevents bypass of security hardening and performance gains,
especially for curves with specialized EC_METHODs.
By default, if a key encoded with explicit parameters is loaded and later
serialized, the output is still encoded with explicit parameters, even if
encoded, the output is still encoded with explicit parameters, even if
internally a "named" EC_GROUP is used for computation.
*Nicola Tuveri*
@ -2025,13 +2025,13 @@ OpenSSL 1.1.0
### Changes between 1.1.0k and 1.1.0l [10 Sep 2019]
* For built-in EC curves, ensure an EC_GROUP built from the curve name is
used even when parsing explicit parameters, when loading a serialized key
used even when parsing explicit parameters, when loading a encoded key
or calling `EC_GROUP_new_from_ecpkparameters()`/
`EC_GROUP_new_from_ecparameters()`.
This prevents bypass of security hardening and performance gains,
especially for curves with specialized EC_METHODs.
By default, if a key encoded with explicit parameters is loaded and later
serialized, the output is still encoded with explicit parameters, even if
encoded, the output is still encoded with explicit parameters, even if
internally a "named" EC_GROUP is used for computation.
*Nicola Tuveri*
@ -3822,13 +3822,13 @@ OpenSSL 1.0.2
### Changes between 1.0.2s and 1.0.2t [10 Sep 2019]
* For built-in EC curves, ensure an EC_GROUP built from the curve name is
used even when parsing explicit parameters, when loading a serialized key
used even when parsing explicit parameters, when loading a encoded key
or calling `EC_GROUP_new_from_ecpkparameters()`/
`EC_GROUP_new_from_ecparameters()`.
This prevents bypass of security hardening and performance gains,
especially for curves with specialized EC_METHODs.
By default, if a key encoded with explicit parameters is loaded and later
serialized, the output is still encoded with explicit parameters, even if
encoded, the output is still encoded with explicit parameters, even if
internally a "named" EC_GROUP is used for computation.
*Nicola Tuveri*

@ -43,7 +43,7 @@ OpenSSL 3.0
* Added a proper HTTP(S) client to libcrypto supporting GET and POST,
redirection, plain and ASN.1-encoded contents, proxies, and timeouts.
* Added util/check-format.pl for checking adherence to the coding guidelines.
* Added OSSL_SERIALIZER, a generic serializer API.
* Added OSSL_ENCODER, a generic encoder API.
* Added OSSL_PARAM_BLD, an easier to use API to OSSL_PARAM.
* Added error raising macros, ERR_raise() and ERR_raise_data().
* Deprecated ERR_put_error().

@ -16,8 +16,8 @@
#include <openssl/provider.h>
#include <openssl/safestack.h>
#include <openssl/kdf.h>
#include <openssl/serializer.h>
#include <openssl/deserializer.h>
#include <openssl/encoder.h>
#include <openssl/decoder.h>
#include <openssl/core_names.h>
#include "apps.h"
#include "app_params.h"
@ -355,124 +355,124 @@ static void list_random_generators(void)
}
/*
* Serializers
* Encoders
*/
DEFINE_STACK_OF(OSSL_SERIALIZER)
static int serializer_cmp(const OSSL_SERIALIZER * const *a,
const OSSL_SERIALIZER * const *b)
DEFINE_STACK_OF(OSSL_ENCODER)
static int encoder_cmp(const OSSL_ENCODER * const *a,
const OSSL_ENCODER * const *b)
{
int ret = OSSL_SERIALIZER_number(*a) - OSSL_SERIALIZER_number(*b);
int ret = OSSL_ENCODER_number(*a) - OSSL_ENCODER_number(*b);
if (ret == 0)
ret = strcmp(OSSL_PROVIDER_name(OSSL_SERIALIZER_provider(*a)),
OSSL_PROVIDER_name(OSSL_SERIALIZER_provider(*b)));
ret = strcmp(OSSL_PROVIDER_name(OSSL_ENCODER_provider(*a)),
OSSL_PROVIDER_name(OSSL_ENCODER_provider(*b)));
return ret;
}
static void collect_serializers(OSSL_SERIALIZER *serializer, void *stack)
static void collect_encoders(OSSL_ENCODER *encoder, void *stack)
{
STACK_OF(OSSL_SERIALIZER) *serializer_stack = stack;
STACK_OF(OSSL_ENCODER) *encoder_stack = stack;
sk_OSSL_SERIALIZER_push(serializer_stack, serializer);
OSSL_SERIALIZER_up_ref(serializer);
sk_OSSL_ENCODER_push(encoder_stack, encoder);
OSSL_ENCODER_up_ref(encoder);
}
static void list_serializers(void)
static void list_encoders(void)
{
STACK_OF(OSSL_SERIALIZER) *serializers;
STACK_OF(OSSL_ENCODER) *encoders;
int i;
serializers = sk_OSSL_SERIALIZER_new(serializer_cmp);
if (serializers == NULL) {
encoders = sk_OSSL_ENCODER_new(encoder_cmp);
if (encoders == NULL) {
BIO_printf(bio_err, "ERROR: Memory allocation\n");
return;
}
BIO_printf(bio_out, "Provided SERIALIZERs:\n");
OSSL_SERIALIZER_do_all_provided(NULL, collect_serializers, serializers);
sk_OSSL_SERIALIZER_sort(serializers);
BIO_printf(bio_out, "Provided ENCODERs:\n");
OSSL_ENCODER_do_all_provided(NULL, collect_encoders, encoders);
sk_OSSL_ENCODER_sort(encoders);
for (i = 0; i < sk_OSSL_SERIALIZER_num(serializers); i++) {
OSSL_SERIALIZER *k = sk_OSSL_SERIALIZER_value(serializers, i);
for (i = 0; i < sk_OSSL_ENCODER_num(encoders); i++) {
OSSL_ENCODER *k = sk_OSSL_ENCODER_value(encoders, i);
STACK_OF(OPENSSL_CSTRING) *names =
sk_OPENSSL_CSTRING_new(name_cmp);
OSSL_SERIALIZER_names_do_all(k, collect_names, names);
OSSL_ENCODER_names_do_all(k, collect_names, names);
BIO_printf(bio_out, " ");
print_names(bio_out, names);
BIO_printf(bio_out, " @ %s (%s)\n",
OSSL_PROVIDER_name(OSSL_SERIALIZER_provider(k)),
OSSL_SERIALIZER_properties(k));
OSSL_PROVIDER_name(OSSL_ENCODER_provider(k)),
OSSL_ENCODER_properties(k));
sk_OPENSSL_CSTRING_free(names);
if (verbose) {
print_param_types("settable operation parameters",
OSSL_SERIALIZER_settable_ctx_params(k), 4);
OSSL_ENCODER_settable_ctx_params(k), 4);
}
}
sk_OSSL_SERIALIZER_pop_free(serializers, OSSL_SERIALIZER_free);
sk_OSSL_ENCODER_pop_free(encoders, OSSL_ENCODER_free);
}
/*
* Deserializers
* Decoders
*/
DEFINE_STACK_OF(OSSL_DESERIALIZER)
static int deserializer_cmp(const OSSL_DESERIALIZER * const *a,
const OSSL_DESERIALIZER * const *b)
DEFINE_STACK_OF(OSSL_DECODER)
static int decoder_cmp(const OSSL_DECODER * const *a,
const OSSL_DECODER * const *b)
{
int ret = OSSL_DESERIALIZER_number(*a) - OSSL_DESERIALIZER_number(*b);
int ret = OSSL_DECODER_number(*a) - OSSL_DECODER_number(*b);
if (ret == 0)
ret = strcmp(OSSL_PROVIDER_name(OSSL_DESERIALIZER_provider(*a)),
OSSL_PROVIDER_name(OSSL_DESERIALIZER_provider(*b)));
ret = strcmp(OSSL_PROVIDER_name(OSSL_DECODER_provider(*a)),
OSSL_PROVIDER_name(OSSL_DECODER_provider(*b)));
return ret;
}
static void collect_deserializers(OSSL_DESERIALIZER *deserializer, void *stack)
static void collect_decoders(OSSL_DECODER *decoder, void *stack)
{
STACK_OF(OSSL_DESERIALIZER) *deserializer_stack = stack;
STACK_OF(OSSL_DECODER) *decoder_stack = stack;
sk_OSSL_DESERIALIZER_push(deserializer_stack, deserializer);
OSSL_DESERIALIZER_up_ref(deserializer);
sk_OSSL_DECODER_push(decoder_stack, decoder);
OSSL_DECODER_up_ref(decoder);
}
static void list_deserializers(void)
static void list_decoders(void)
{
STACK_OF(OSSL_DESERIALIZER) *deserializers;
STACK_OF(OSSL_DECODER) *decoders;
int i;
deserializers = sk_OSSL_DESERIALIZER_new(deserializer_cmp);
if (deserializers == NULL) {
decoders = sk_OSSL_DECODER_new(decoder_cmp);
if (decoders == NULL) {
BIO_printf(bio_err, "ERROR: Memory allocation\n");
return;
}
BIO_printf(bio_out, "Provided DESERIALIZERs:\n");
OSSL_DESERIALIZER_do_all_provided(NULL, collect_deserializers,
deserializers);
sk_OSSL_DESERIALIZER_sort(deserializers);
BIO_printf(bio_out, "Provided DECODERs:\n");
OSSL_DECODER_do_all_provided(NULL, collect_decoders,
decoders);
sk_OSSL_DECODER_sort(decoders);
for (i = 0; i < sk_OSSL_DESERIALIZER_num(deserializers); i++) {
OSSL_DESERIALIZER *k = sk_OSSL_DESERIALIZER_value(deserializers, i);
for (i = 0; i < sk_OSSL_DECODER_num(decoders); i++) {
OSSL_DECODER *k = sk_OSSL_DECODER_value(decoders, i);
STACK_OF(OPENSSL_CSTRING) *names =
sk_OPENSSL_CSTRING_new(name_cmp);
OSSL_DESERIALIZER_names_do_all(k, collect_names, names);
OSSL_DECODER_names_do_all(k, collect_names, names);
BIO_printf(bio_out, " ");
print_names(bio_out, names);
BIO_printf(bio_out, " @ %s (%s)\n",
OSSL_PROVIDER_name(OSSL_DESERIALIZER_provider(k)),
OSSL_DESERIALIZER_properties(k));
OSSL_PROVIDER_name(OSSL_DECODER_provider(k)),
OSSL_DECODER_properties(k));
sk_OPENSSL_CSTRING_free(names);
if (verbose) {
print_param_types("settable operation parameters",
OSSL_DESERIALIZER_settable_ctx_params(k), 4);
OSSL_DECODER_settable_ctx_params(k), 4);
}
}
sk_OSSL_DESERIALIZER_pop_free(deserializers, OSSL_DESERIALIZER_free);
sk_OSSL_DECODER_pop_free(decoders, OSSL_DECODER_free);
}
static void list_missing_help(void)
@ -554,7 +554,7 @@ static void list_options_for_command(const char *command)
break;
if (fp->name == NULL) {
BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
command);
command);
return;
}
@ -821,8 +821,8 @@ typedef enum HELPLIST_CHOICE {
OPT_COMMANDS, OPT_DIGEST_COMMANDS, OPT_MAC_ALGORITHMS, OPT_OPTIONS,
OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS,
OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_DISABLED,
OPT_KDF_ALGORITHMS, OPT_RANDOM_GENERATORS, OPT_SERIALIZERS,
OPT_DESERIALIZERS,
OPT_KDF_ALGORITHMS, OPT_RANDOM_GENERATORS, OPT_ENCODERS,
OPT_DECODERS,
OPT_MISSING_HELP, OPT_OBJECTS,
#ifndef OPENSSL_NO_DEPRECATED_3_0
OPT_ENGINES,
@ -847,15 +847,14 @@ const OPTIONS list_options[] = {
{"kdf-algorithms", OPT_KDF_ALGORITHMS, '-',
"List of key derivation and pseudo random function algorithms"},
{"random-generators", OPT_RANDOM_GENERATORS, '-',
"List of random number generators"},
"List of random number generators"},
{"mac-algorithms", OPT_MAC_ALGORITHMS, '-',
"List of message authentication code algorithms"},
{"cipher-commands", OPT_CIPHER_COMMANDS, '-', "List of cipher commands"},
{"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-',
"List of cipher algorithms"},
{"serializers", OPT_SERIALIZERS, '-', "List of serialization methods" },
{"deserializers", OPT_DESERIALIZERS, '-',
"List of deserialization methods" },
{"encoders", OPT_ENCODERS, '-', "List of encoding methods" },
{"decoders", OPT_DECODERS, '-', "List of decoding methods" },
{"public-key-algorithms", OPT_PK_ALGORITHMS, '-',
"List of public key algorithms"},
#ifndef OPENSSL_NO_DEPRECATED_3_0
@ -890,8 +889,8 @@ int list_main(int argc, char **argv)
unsigned int mac_algorithms:1;
unsigned int cipher_commands:1;
unsigned int cipher_algorithms:1;
unsigned int serializer_algorithms:1;
unsigned int deserializer_algorithms:1;
unsigned int encoder_algorithms:1;
unsigned int decoder_algorithms:1;
unsigned int pk_algorithms:1;
unsigned int pk_method:1;
#ifndef OPENSSL_NO_DEPRECATED_3_0
@ -943,11 +942,11 @@ opthelp:
case OPT_CIPHER_ALGORITHMS:
todo.cipher_algorithms = 1;
break;
case OPT_SERIALIZERS:
todo.serializer_algorithms = 1;
case OPT_ENCODERS:
todo.encoder_algorithms = 1;
break;
case OPT_DESERIALIZERS:
todo.deserializer_algorithms = 1;
case OPT_DECODERS:
todo.decoder_algorithms = 1;
break;
case OPT_PK_ALGORITHMS:
todo.pk_algorithms = 1;
@ -1003,10 +1002,10 @@ opthelp:
list_type(FT_cipher, one);
if (todo.cipher_algorithms)
list_ciphers();
if (todo.serializer_algorithms)
list_serializers();
if (todo.deserializer_algorithms)
list_deserializers();
if (todo.encoder_algorithms)
list_encoders();
if (todo.decoder_algorithms)
list_decoders();
if (todo.pk_algorithms)
list_pkey();
#ifndef OPENSSL_NO_DEPRECATED_3_0

@ -10,7 +10,7 @@
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/evp.h>
#include <openssl/serializer.h>
#include <openssl/encoder.h>
#include <openssl/buffer.h>
#include <openssl/x509.h>
#include "crypto/asn1.h"
@ -31,17 +31,17 @@ int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp)
return ret;
}
if (a->keymgmt != NULL) {
const char *serprop = OSSL_SERIALIZER_PrivateKey_TO_DER_PQ;
OSSL_SERIALIZER_CTX *ctx =
OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(a, serprop);
const char *encprop = OSSL_ENCODER_PrivateKey_TO_DER_PQ;
OSSL_ENCODER_CTX *ctx =
OSSL_ENCODER_CTX_new_by_EVP_PKEY(a, encprop);
BIO *out = BIO_new(BIO_s_mem());
BUF_MEM *buf = NULL;
int ret = -1;
if (ctx != NULL
&& out != NULL
&& OSSL_SERIALIZER_CTX_get_serializer(ctx) != NULL
&& OSSL_SERIALIZER_to_bio(ctx, out)
&& OSSL_ENCODER_CTX_get_encoder(ctx) != NULL
&& OSSL_ENCODER_to_bio(ctx, out)
&& BIO_get_mem_ptr(out, &buf) > 0) {
ret = buf->length;
@ -57,7 +57,7 @@ int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp)
}
}
BIO_free(out);
OSSL_SERIALIZER_CTX_free(ctx);
OSSL_ENCODER_CTX_free(ctx);
return ret;
}
ASN1err(ASN1_F_I2D_PRIVATEKEY, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);

@ -5,7 +5,7 @@ SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 conf \
md2 md4 md5 sha mdc2 hmac ripemd whrlpool poly1305 \
siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \
seed sm4 chacha modes bn ec rsa dsa dh sm2 dso engine \
err comp http ocsp cms ts srp cmac ct async ess crmf cmp serializer \
err comp http ocsp cms ts srp cmac ct async ess crmf cmp encode_decode \
ffc
LIBS=../libcrypto

@ -0,0 +1,8 @@
SOURCE[../../libcrypto]=endecode_pass.c
SOURCE[../../libcrypto]=encoder_meth.c encoder_lib.c encoder_pkey.c
SOURCE[../../libcrypto]=decoder_meth.c decoder_lib.c \
decoder_pkey.c
SOURCE[../../libcrypto]=encoder_err.c
SOURCE[../../libcrypto]=decoder_err.c

@ -9,23 +9,23 @@
*/
#include <openssl/err.h>
#include <openssl/deserializererr.h>
#include <openssl/decodererr.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"},
static const ERR_STRING_DATA OSSL_DECODER_str_reasons[] = {
{ERR_PACK(ERR_LIB_OSSL_DECODER, 0, OSSL_DECODER_R_MISSING_GET_PARAMS),
"missing get params"},
{0, NULL}
};
#endif
int ERR_load_OSSL_DESERIALIZER_strings(void)
int ERR_load_OSSL_DECODER_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);
if (ERR_reason_error_string(OSSL_DECODER_str_reasons[0].error) == NULL)
ERR_load_strings_const(OSSL_DECODER_str_reasons);
#endif
return 1;
}

@ -0,0 +1,483 @@
/*
* 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 "encoder_local.h"
#include "e_os.h"
struct decoder_process_data_st {
OSSL_DECODER_CTX *ctx;
/* Current BIO */
BIO *bio;
/* Index of the current decoder instance to be processed */
size_t current_deser_inst_index;
};
static int decoder_process(const OSSL_PARAM params[], void *arg);
int OSSL_DECODER_from_bio(OSSL_DECODER_CTX *ctx, BIO *in)
{
struct decoder_process_data_st data;
int ok = 0;
memset(&data, 0, sizeof(data));
data.ctx = ctx;
data.bio = in;
ok = decoder_process(NULL, &data);
/* Clear any internally cached passphrase */
if (!ctx->flag_user_passphrase) {
OSSL_DECODER_CTX_set_passphrase(ctx, NULL, 0);
ctx->flag_user_passphrase = 0;
}
return ok;
}
#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_DECODER, ERR_R_BIO_LIB);
return NULL;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
return b;
}
int OSSL_DECODER_from_fp(OSSL_DECODER_CTX *ctx, FILE *fp)
{
BIO *b = bio_from_file(fp);
int ret = 0;
if (b != NULL)
ret = OSSL_DECODER_from_bio(ctx, b);
BIO_free(b);
return ret;
}
#endif
int OSSL_DECODER_CTX_set_input_type(OSSL_DECODER_CTX *ctx,
const char *input_type)
{
if (!ossl_assert(ctx != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, 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_DECODER_CTX_add_decoder(OSSL_DECODER_CTX *ctx, OSSL_DECODER *decoder)
{
OSSL_DECODER_INSTANCE *decoder_inst = NULL;
const OSSL_PROVIDER *prov = NULL;
OSSL_PARAM params[2];
void *provctx = NULL;
if (!ossl_assert(ctx != NULL) || !ossl_assert(decoder != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (decoder->get_params == NULL) {
ERR_raise(ERR_LIB_OSSL_DECODER,
OSSL_DECODER_R_MISSING_GET_PARAMS);
return 0;
}
if (ctx->decoder_insts == NULL
&& (ctx->decoder_insts =
sk_OSSL_DECODER_INSTANCE_new_null()) == NULL) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
return 0;
}
if ((decoder_inst = OPENSSL_zalloc(sizeof(*decoder_inst))) == NULL) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
return 0;
}
if (!OSSL_DECODER_up_ref(decoder)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INTERNAL_ERROR);
goto err;
}
decoder_inst->decoder = decoder;
prov = OSSL_DECODER_provider(decoder_inst->decoder);
provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
/* Cache the input type for this encoder */
params[0] =
OSSL_PARAM_construct_utf8_ptr(OSSL_DECODER_PARAM_INPUT_TYPE,
(char **)&decoder_inst->input_type, 0);
params[1] = OSSL_PARAM_construct_end();
if (!decoder_inst->decoder->get_params(params)
|| !OSSL_PARAM_modified(&params[0]))
goto err;
if ((decoder_inst->deserctx = decoder_inst->decoder->newctx(provctx))
== NULL)
goto err;
if (sk_OSSL_DECODER_INSTANCE_push(ctx->decoder_insts, decoder_inst) <= 0)
goto err;
return 1;
err:
if (decoder_inst != NULL) {
if (decoder_inst->decoder != NULL)
decoder_inst->decoder->freectx(decoder_inst->deserctx);
OSSL_DECODER_free(decoder_inst->decoder);
OPENSSL_free(decoder_inst);
}
return 0;
}
int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx,
OPENSSL_CTX *libctx, const char *propq)
{
/*
* This function goes through existing decoder methods in
* |ctx->decoder_insts|, and tries to fetch new decoders that produce
* what the existing ones want as input, and push those newly fetched
* decoders on top of the same stack.
* Then it does the same again, but looping over the newly fetched
* decoders, until there are no more encoders 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" decoders */
size_t w_new_start, w_new_end; /* "new" decoders */
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_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
/*
* If there is no stack of OSSL_DECODER_INSTANCE, we have nothing
* more to add. That's fine.
*/
if (ctx->decoder_insts == NULL)
return 1;
w_prev_start = 0;
w_prev_end = sk_OSSL_DECODER_INSTANCE_num(ctx->decoder_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_DECODER_INSTANCE *decoder_inst =
sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts, i);
const char *name = decoder_inst->input_type;
OSSL_DECODER *decoder = NULL;
/*
* If the caller has specified what the initial input should be,
* and the decoder 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,
decoder_inst->input_type) != 0)
continue;
ERR_set_mark();
decoder = OSSL_DECODER_fetch(libctx, name, propq);
ERR_pop_to_mark();
if (decoder != NULL) {
size_t j;
/*
* Check that we don't already have this decoder in our
* stack We only need to check among the newly added ones.
*/
for (j = w_new_start; j < w_new_end; j++) {
OSSL_DECODER_INSTANCE *check_inst =
sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts, j);
if (decoder == check_inst->decoder) {
/* We found it, so drop the new fetch */
OSSL_DECODER_free(decoder);
decoder = NULL;
break;
}
}
}
if (decoder == 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_DECODER_CTX_add_decoder(ctx, decoder)) /* ref++ */
w_new_end++;
OSSL_DECODER_free(decoder); /* ref-- */
}
/* How many were added in this iteration */
count = w_new_end - w_new_start;
/* Slide the "previous decoder" windows */
w_prev_start = w_new_start;
w_prev_end = w_new_end;
depth++;
} while (count != 0 && depth <= 10);
return 1;
}
int OSSL_DECODER_CTX_num_decoders(OSSL_DECODER_CTX *ctx)
{
if (ctx == NULL || ctx->decoder_insts == NULL)
return 0;
return sk_OSSL_DECODER_INSTANCE_num(ctx->decoder_insts);
}
int OSSL_DECODER_CTX_set_construct(OSSL_DECODER_CTX *ctx,
OSSL_DECODER_CONSTRUCT *construct)
{
if (!ossl_assert(ctx != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
ctx->construct = construct;
return 1;
}
int OSSL_DECODER_CTX_set_construct_data(OSSL_DECODER_CTX *ctx,
void *construct_data)
{
if (!ossl_assert(ctx != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
ctx->construct_data = construct_data;
return 1;
}
int OSSL_DECODER_CTX_set_cleanup(OSSL_DECODER_CTX *ctx,
OSSL_DECODER_CLEANUP *cleanup)
{
if (!ossl_assert(ctx != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
ctx->cleanup = cleanup;
return 1;
}
OSSL_DECODER_CONSTRUCT *
OSSL_DECODER_CTX_get_construct(OSSL_DECODER_CTX *ctx)
{
if (ctx == NULL)
return NULL;
return ctx->construct;
}
void *OSSL_DECODER_CTX_get_construct_data(OSSL_DECODER_CTX *ctx)
{
if (ctx == NULL)
return NULL;
return ctx->construct_data;
}
OSSL_DECODER_CLEANUP *
OSSL_DECODER_CTX_get_cleanup(OSSL_DECODER_CTX *ctx)
{
if (ctx == NULL)
return NULL;
return ctx->cleanup;
}
int OSSL_DECODER_export(OSSL_DECODER_INSTANCE *decoder_inst,
void *reference, size_t reference_sz,
OSSL_CALLBACK *export_cb, void *export_cbarg)
{
if (!(ossl_assert(decoder_inst != NULL)
&& ossl_assert(reference != NULL)
&& ossl_assert(export_cb != NULL)
&& ossl_assert(export_cbarg != NULL))) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return decoder_inst->decoder->export_object(decoder_inst->deserctx,
reference, reference_sz,
export_cb, export_cbarg);
}
OSSL_DECODER *OSSL_DECODER_INSTANCE_decoder(OSSL_DECODER_INSTANCE *decoder_inst)
{
if (decoder_inst == NULL)
return NULL;
return decoder_inst->decoder;
}
void *OSSL_DECODER_INSTANCE_decoder_ctx(OSSL_DECODER_INSTANCE *decoder_inst)
{
if (decoder_inst == NULL)
return NULL;
return decoder_inst->deserctx;
}
static int decoder_process(const OSSL_PARAM params[], void *arg)
{
struct decoder_process_data_st *data = arg;
OSSL_DECODER_CTX *ctx = data->ctx;
OSSL_DECODER_INSTANCE *decoder_inst = NULL;
OSSL_DECODER *decoder = NULL;
BIO *bio = data->bio;
long loc;
size_t i;
int ok = 0;
/* For recursions */
struct decoder_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_DECODER_CTX_num_decoders(ctx);
bio = data->bio;
} else {
const OSSL_PARAM *p;
decoder_inst =
sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts,
data->current_deser_inst_index);
decoder = OSSL_DECODER_INSTANCE_decoder(decoder_inst);
if (ctx->construct != NULL
&& ctx->construct(decoder_inst, params, ctx->construct_data)) {
ok = 1;
goto end;
}
/* The constructor didn't return success */
/*
* so we try to use the object we got and feed it to any next
* decoder that will take it. Object references are not
* allowed for this.
* If this data isn't present, decoding has failed.
*/
p = OSSL_PARAM_locate_const(params, OSSL_DECODER_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 decoders 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_DECODER, ERR_R_BIO_LIB);
goto end;
}
for (i = data->current_deser_inst_index; i-- > 0;) {
OSSL_DECODER_INSTANCE *new_deser_inst =
sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts, i);
OSSL_DECODER *new_deser =
OSSL_DECODER_INSTANCE_decoder(new_deser_inst);
/*
* If |decoder| 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 (decoder == NULL && ctx->start_input_type != NULL
&& strcasecmp(ctx->start_input_type,
new_deser_inst->input_type) != 0)
continue;
/*
* If we have a previous decoder, we check that the input type
* of the next to be used matches the type of this previous one.
* decoder_inst->input_type is a cache of the parameter "input-type"
* value for that decoder.
*/
if (decoder != NULL
&& !OSSL_DECODER_is_a(decoder, new_deser_inst->input_type))
continue;
/*
* Checking the return value of BIO_reset() or BIO_seek() is unsafe.
* Furthermore, BIO_reset() is unsafe to use if the source BIO happens
* to be a BIO_s_mem(), because the earlier BIO_tell() gives us zero
* no matter where we are in the underlying buffer we're reading from.
*
* So, we simply do a BIO_seek(), and use BIO_tell() that we're back
* at the same position. This is a best effort attempt, but BIO_seek()
* and BIO_tell() should come as a pair...
*/
(void)BIO_seek(bio, loc);
if (BIO_tell(bio) != loc)
goto end;
/* Recurse */
new_data.current_deser_inst_index = i;
ok = new_deser->decode(new_deser_inst->deserctx, (OSSL_CORE_BIO *)bio,
decoder_process, &new_data,
ctx->passphrase_cb, new_data.ctx);
if (ok)
break;
}
end:
BIO_free(new_data.bio);
return ok;
}

@ -0,0 +1,552 @@
/*
* 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/decoder.h>
#include <openssl/ui.h>
#include "internal/core.h"
#include "internal/namemap.h"
#include "internal/property.h"
#include "internal/provider.h"
#include "crypto/encoder.h"
#include "encoder_local.h"
static void OSSL_DECODER_INSTANCE_free(OSSL_DECODER_INSTANCE *instance);
/*
* Decoder can have multiple names, separated with colons in a name string
*/
#define NAME_SEPARATOR ':'
/* Simple method structure constructor and destructor */
static OSSL_DECODER *ossl_decoder_new(void)
{
OSSL_DECODER *decoder = NULL;
if ((decoder = OPENSSL_zalloc(sizeof(*decoder))) == NULL
|| (decoder->base.lock = CRYPTO_THREAD_lock_new()) == NULL) {
OSSL_DECODER_free(decoder);
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
return NULL;
}
decoder->base.refcnt = 1;
return decoder;
}
int OSSL_DECODER_up_ref(OSSL_DECODER *decoder)
{
int ref = 0;
CRYPTO_UP_REF(&decoder->base.refcnt, &ref, decoder->base.lock);
return 1;
}
void OSSL_DECODER_free(OSSL_DECODER *decoder)
{
int ref = 0;
if (decoder == NULL)
return;
CRYPTO_DOWN_REF(&decoder->base.refcnt, &ref, decoder->base.lock);
if (ref > 0)
return;
ossl_provider_free(decoder->base.prov);
CRYPTO_THREAD_lock_free(decoder->base.lock);
OPENSSL_free(decoder);
}
/* Permanent decoder method store, constructor and destructor */
static void decoder_store_free(void *vstore)
{
ossl_method_store_free(vstore);
}
static void *decoder_store_new(OPENSSL_CTX *ctx)
{
return ossl_method_store_new(ctx);
}
static const OPENSSL_CTX_METHOD decoder_store_method = {
decoder_store_new,
decoder_store_free,
};
/* Data to be passed through ossl_method_construct() */
struct decoder_data_st {
OPENSSL_CTX *libctx;
OSSL_METHOD_CONSTRUCT_METHOD *mcm;
int id; /* For get_decoder_from_store() */
const char *names; /* For get_decoder_from_store() */
const char *propquery; /* For get_decoder_from_store() */
};
/*
* Generic routines to fetch / create DECODER methods with
* ossl_method_construct()
*/
/* Temporary decoder method store, constructor and destructor */
static void *alloc_tmp_decoder_store(OPENSSL_CTX *ctx)
{
return ossl_method_store_new(ctx);
}
static void dealloc_tmp_decoder_store(void *store)
{
if (store != NULL)
ossl_method_store_free(store);
}
/* Get the permanent decoder store */
static OSSL_METHOD_STORE *get_decoder_store(OPENSSL_CTX *libctx)
{
return openssl_ctx_get_data(libctx, OPENSSL_CTX_DECODER_STORE_INDEX,
&decoder_store_method);
}
/* Get decoder methods from a store, or put one in */
static void *get_decoder_from_store(OPENSSL_CTX *libctx, void *store,
void *data)
{
struct decoder_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_decoder_store(libctx)) == NULL)
return NULL;
if (!ossl_method_store_fetch(store, id, methdata->propquery, &method))
return NULL;
return method;
}
static int put_decoder_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_decoder_store(libctx)) == NULL)
return 0;
return ossl_method_store_add(store, prov, id, propdef, method,
(int (*)(void *))OSSL_DECODER_up_ref,
(void (*)(void *))OSSL_DECODER_free);
}
/* Create and populate a decoder method */
static void *decoder_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
OSSL_PROVIDER *prov)
{
OSSL_DECODER *decoder = NULL;
const OSSL_DISPATCH *fns = algodef->implementation;
if ((decoder = ossl_decoder_new()) == NULL)
return NULL;
decoder->base.id = id;
decoder->base.propdef = algodef->property_definition;
for (; fns->function_id != 0; fns++) {
switch (fns->function_id) {
case OSSL_FUNC_DECODER_NEWCTX:
if (decoder->newctx == NULL)
decoder->newctx = OSSL_FUNC_decoder_newctx(fns);
break;
case OSSL_FUNC_DECODER_FREECTX:
if (decoder->freectx == NULL)
decoder->freectx = OSSL_FUNC_decoder_freectx(fns);
break;
case OSSL_FUNC_DECODER_GET_PARAMS:
if (decoder->get_params == NULL)
decoder->get_params =
OSSL_FUNC_decoder_get_params(fns);
break;
case OSSL_FUNC_DECODER_GETTABLE_PARAMS:
if (decoder->gettable_params == NULL)
decoder->gettable_params =
OSSL_FUNC_decoder_gettable_params(fns);
break;
case OSSL_FUNC_DECODER_SET_CTX_PARAMS:
if (decoder->set_ctx_params == NULL)
decoder->set_ctx_params =
OSSL_FUNC_decoder_set_ctx_params(fns);
break;
case OSSL_FUNC_DECODER_SETTABLE_CTX_PARAMS:
if (decoder->settable_ctx_params == NULL)
decoder->settable_ctx_params =
OSSL_FUNC_decoder_settable_ctx_params(fns);
break;
case OSSL_FUNC_DECODER_DECODE:
if (decoder->decode == NULL)
decoder->decode = OSSL_FUNC_decoder_decode(fns);
break;
case OSSL_FUNC_DECODER_EXPORT_OBJECT:
if (decoder->export_object == NULL)
decoder->export_object = OSSL_FUNC_decoder_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 encoding driver functions.
*/
if (!((decoder->newctx == NULL && decoder->freectx == NULL)
|| (decoder->newctx != NULL && decoder->freectx != NULL))
|| (decoder->decode == NULL && decoder->export_object == NULL)) {
OSSL_DECODER_free(decoder);
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
return NULL;
}
if (prov != NULL && !ossl_provider_up_ref(prov)) {
OSSL_DECODER_free(decoder);
return NULL;
}
decoder->base.prov = prov;
return decoder;
}
/*
* The core fetching functionality passes the names of the implementation.
* This function is responsible to getting an identity number for them,
* then call decoder_from_dispatch() with that identity number.
*/
static void *construct_decoder(const OSSL_ALGORITHM *algodef,
OSSL_PROVIDER *prov, void *unused)
{
/*
* This function is only called if get_decoder_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 = decoder_from_dispatch(id, algodef, prov);
return method;
}
/* Intermediary function to avoid ugly casts, used below */
static void destruct_decoder(void *method, void *data)
{
OSSL_DECODER_free(method);
}
static int up_ref_decoder(void *method)
{
return OSSL_DECODER_up_ref(method);
}
static void free_decoder(void *method)
{
OSSL_DECODER_free(method);
}
/* Fetching support. Can fetch by numeric identity or by name */
static OSSL_DECODER *inner_ossl_decoder_fetch(OPENSSL_CTX *libctx, int id,
const char *name,
const char *properties)
{
OSSL_METHOD_STORE *store = get_decoder_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_decoder_store,
dealloc_tmp_decoder_store,
get_decoder_from_store,
put_decoder_in_store,
construct_decoder,
destruct_decoder
};
struct decoder_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_DECODER,
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_decoder_from_store() and
* put_decoder_in_store() above.
*/
if (id == 0)
id = ossl_namemap_name2num(namemap, name);
ossl_method_store_cache_set(store, id, properties, method,
up_ref_decoder, free_decoder);
}
}
return method;
}
OSSL_DECODER *OSSL_DECODER_fetch(OPENSSL_CTX *libctx, const char *name,
const char *properties)
{
return inner_ossl_decoder_fetch(libctx, 0, name, properties);
}
OSSL_DECODER *ossl_decoder_fetch_by_number(OPENSSL_CTX *libctx, int id,
const char *properties)
{
return inner_ossl_decoder_fetch(libctx, id, NULL, properties);
}
/*
* Library of basic method functions
*/
const OSSL_PROVIDER *OSSL_DECODER_provider(const OSSL_DECODER *decoder)
{
if (!ossl_assert(decoder != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return decoder->base.prov;
}
const char *OSSL_DECODER_properties(const OSSL_DECODER *decoder)
{
if (!ossl_assert(decoder != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return decoder->base.propdef;
}
int OSSL_DECODER_number(const OSSL_DECODER *decoder)
{
if (!ossl_assert(decoder != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return decoder->base.id;
}
int OSSL_DECODER_is_a(const OSSL_DECODER *decoder, const char *name)
{
if (decoder->base.prov != NULL) {
OPENSSL_CTX *libctx = ossl_provider_library_context(decoder->base.prov);
OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
return ossl_namemap_name2num(namemap, name) == decoder->base.id;
}
return 0;
}
struct decoder_do_all_data_st {
void (*user_fn)(void *method, void *arg);
void *user_arg;
};
static void decoder_do_one(OSSL_PROVIDER *provider,
const OSSL_ALGORITHM *algodef,
int no_store, void *vdata)
{
struct decoder_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 =
decoder_from_dispatch(id, algodef, provider);
if (method != NULL) {
data->user_fn(method, data->user_arg);
OSSL_DECODER_free(method);
}
}
void OSSL_DECODER_do_all_provided(OPENSSL_CTX *libctx,
void (*fn)(OSSL_DECODER *decoder, void *arg),
void *arg)
{
struct decoder_do_all_data_st data;
data.user_fn = (void (*)(void *, void *))fn;
data.user_arg = arg;
ossl_algorithm_do_all(libctx, OSSL_OP_DECODER, NULL,
NULL, decoder_do_one, NULL,
&data);
}
void OSSL_DECODER_names_do_all(const OSSL_DECODER *decoder,
void (*fn)(const char *name, void *data),
void *data)
{
if (decoder == NULL)
return;
if (decoder->base.prov != NULL) {
OPENSSL_CTX *libctx = ossl_provider_library_context(decoder->base.prov);
OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
ossl_namemap_doall_names(namemap, decoder->base.id, fn, data);
}
}
const OSSL_PARAM *
OSSL_DECODER_gettable_params(OSSL_DECODER *decoder)
{
if (decoder != NULL && decoder->gettable_params != NULL) {
void *provctx = ossl_provider_ctx(OSSL_DECODER_provider(decoder));
return decoder->gettable_params(provctx);
}
return NULL;
}
int OSSL_DECODER_get_params(OSSL_DECODER *decoder, OSSL_PARAM params[])
{
if (decoder != NULL && decoder->get_params != NULL)
return decoder->get_params(params);
return 0;