DECODER: Add input structure support for EVP_PKEY decoding

OSSL_DECODER_CTX_new_by_EVP_PKEY() takes one more argument to express
the desired outermost structure for the input.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/13248)
This commit is contained in:
Richard Levitte 2020-10-26 13:17:42 +01:00
parent 67c91ca23e
commit df65c06b59
3 changed files with 86 additions and 10 deletions

View File

@ -9,6 +9,7 @@
#include <openssl/core_names.h>
#include <openssl/core_object.h>
#include <openssl/provider.h>
#include <openssl/evp.h>
#include <openssl/ui.h>
#include <openssl/decoder.h>
@ -16,6 +17,7 @@
#include "crypto/evp.h"
#include "crypto/decoder.h"
#include "encoder_local.h"
#include "e_os.h" /* strcasecmp on Windows */
int OSSL_DECODER_CTX_set_passphrase(OSSL_DECODER_CTX *ctx,
const unsigned char *kstr,
@ -231,10 +233,40 @@ static void collect_name(const char *name, void *arg)
data->error_occured = 0; /* All is good now */
}
/*
* The input structure check is only done on the initial decoder
* implementations.
*/
static int collect_decoder_check_input_structure(OSSL_DECODER_CTX *ctx,
OSSL_DECODER_INSTANCE *di)
{
int di_is_was_set = 0;
const char *di_is =
OSSL_DECODER_INSTANCE_get_input_structure(di, &di_is_was_set);
/*
* If caller didn't give an input structure name, the decoder is accepted
* unconditionally with regards to the input structure.
*/
if (ctx->input_structure == NULL)
return 1;
/*
* If the caller did give an input structure name, the decoder must have
* a matching input structure to be accepted.
*/
if (di_is != NULL
&& strcasecmp(ctx->input_structure, di_is) == 0)
return 1;
return 0;
}
static void collect_decoder(OSSL_DECODER *decoder, void *arg)
{
struct collected_data_st *data = arg;
size_t i, end_i;
const OSSL_PROVIDER *prov = OSSL_DECODER_provider(decoder);
void *provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
void *decoderctx = NULL;
if (data->error_occured)
return;
@ -246,10 +278,30 @@ static void collect_decoder(OSSL_DECODER *decoder, void *arg)
end_i = sk_OPENSSL_CSTRING_num(data->names);
for (i = 0; i < end_i; i++) {
const char *name = sk_OPENSSL_CSTRING_value(data->names, i);
OSSL_DECODER_INSTANCE *di = NULL;
if (!OSSL_DECODER_is_a(decoder, name))
continue;
(void)OSSL_DECODER_CTX_add_decoder(data->ctx, decoder);
if (OSSL_DECODER_is_a(decoder, name)
/*
* Either the caller didn't give a selection, or if they did,
* the decoder must tell us if it supports that selection to
* be accepted. If the decoder doesn't have |does_selection|,
* it's seen as taking anything.
*/
&& (decoder->does_selection == NULL
|| decoder->does_selection(provctx, data->ctx->selection))
&& (decoderctx = decoder->newctx(provctx)) != NULL
&& (di = ossl_decoder_instance_new(decoder, decoderctx)) != NULL) {
/* If successful so far, don't free these directly */
decoderctx = NULL;
if (collect_decoder_check_input_structure(data->ctx, di)
&& ossl_decoder_ctx_add_decoder_inst(data->ctx, di))
di = NULL; /* If successfully added, don't free it */
}
/* Free what can be freed */
ossl_decoder_instance_free(di);
decoder->freectx(decoderctx);
}
data->error_occured = 0; /* All is good now */
@ -325,7 +377,9 @@ int ossl_decoder_ctx_setup_for_EVP_PKEY(OSSL_DECODER_CTX *ctx,
OSSL_DECODER_CTX *
OSSL_DECODER_CTX_new_by_EVP_PKEY(EVP_PKEY **pkey,
const char *input_type, const char *keytype,
const char *input_type,
const char *input_structure,
const char *keytype, int selection,
OSSL_LIB_CTX *libctx, const char *propquery)
{
OSSL_DECODER_CTX *ctx = NULL;
@ -335,6 +389,8 @@ OSSL_DECODER_CTX_new_by_EVP_PKEY(EVP_PKEY **pkey,
return NULL;
}
if (OSSL_DECODER_CTX_set_input_type(ctx, input_type)
&& OSSL_DECODER_CTX_set_input_structure(ctx, input_structure)
&& OSSL_DECODER_CTX_set_selection(ctx, selection)
&& ossl_decoder_ctx_setup_for_EVP_PKEY(ctx, pkey, keytype,
libctx, propquery)
&& OSSL_DECODER_CTX_add_extra(ctx, libctx, propquery))

View File

@ -7,7 +7,9 @@ OSSL_DECODER_CTX_new,
OSSL_DECODER_settable_ctx_params,
OSSL_DECODER_CTX_set_params,
OSSL_DECODER_CTX_free,
OSSL_DECODER_CTX_set_selection,
OSSL_DECODER_CTX_set_input_type,
OSSL_DECODER_CTX_set_input_structure,
OSSL_DECODER_CTX_add_decoder,
OSSL_DECODER_CTX_add_extra,
OSSL_DECODER_CTX_get_num_decoders,
@ -23,7 +25,8 @@ OSSL_DECODER_CTX_get_cleanup,
OSSL_DECODER_export,
OSSL_DECODER_INSTANCE_get_decoder,
OSSL_DECODER_INSTANCE_get_decoder_ctx,
OSSL_DECODER_INSTANCE_get_input_type
OSSL_DECODER_INSTANCE_get_input_type,
OSSL_DECODER_INSTANCE_get_input_structure
- Decoder context routines
=head1 SYNOPSIS
@ -38,8 +41,11 @@ OSSL_DECODER_INSTANCE_get_input_type
const OSSL_PARAM params[]);
void OSSL_DECODER_CTX_free(OSSL_DECODER_CTX *ctx);
int OSSL_DECODER_CTX_set_selection(OSSL_DECODER_CTX *ctx, int selection);
int OSSL_DECODER_CTX_set_input_type(OSSL_DECODER_CTX *ctx,
const char *input_type);
int OSSL_DECODER_CTX_set_input_structure(OSSL_DECODER_CTX *ctx,
const char *input_structure);
int OSSL_DECODER_CTX_add_decoder(OSSL_DECODER_CTX *ctx, OSSL_DECODER *decoder);
int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx);
int OSSL_DECODER_CTX_get_num_decoders(OSSL_DECODER_CTX *ctx);
@ -51,6 +57,8 @@ OSSL_DECODER_INSTANCE_get_input_type
OSSL_DECODER_INSTANCE_get_decoder_ctx(OSSL_DECODER_INSTANCE *decoder_inst);
const char *
OSSL_DECODER_INSTANCE_get_input_type(OSSL_DECODER_INSTANCE *decoder_inst);
OSSL_DECODER_INSTANCE_get_input_structure(OSSL_DECODER_INSTANCE *decoder_inst,
int *was_set);
typedef int OSSL_DECODER_CONSTRUCT(OSSL_DECODER_INSTANCE *decoder_inst,
const OSSL_PARAM *object,
@ -128,6 +136,11 @@ OSSL_DECODER_CTX_set_input_type() sets the starting input type. This limits
the decoder chains to be considered, as explained in the general description
above.
OSSL_DECODER_CTX_set_input_structure() sets the name of the structure that
the input is expected to have. This may be used to determines what decoder
implementations may be used. NULL is a valid input structure, when it's not
relevant, or when the decoder implementations are expected to figure it out.
OSSL_DECODER_CTX_get_num_decoders() gets the number of decoders currently
added to the context I<ctx>.
@ -179,14 +192,19 @@ constructed, otherwise 0.
These utility functions may be used by a constructor:
OSSL_DECODER_INSTANCE_get_decoder() can be used to get the decoder method
from a decoder instance I<decoder_inst>.
OSSL_DECODER_INSTANCE_get_decoder() can be used to get the decoder
implementation from a decoder instance I<decoder_inst>.
OSSL_DECODER_INSTANCE_get_decoder_ctx() can be used to get the decoder
method's provider context from a decoder instance I<decoder_inst>.
implementation's provider context from a decoder instance I<decoder_inst>.
OSSL_DECODER_INSTANCE_get_input_type() can be used to get the decoder
method's input type from a decoder instance I<decoder_inst>.
implementation's input type from a decoder instance I<decoder_inst>.
OSSL_DECODER_INSTANCE_get_input_structure() can be used to get the input
structure for the decoder implementation from a decoder instance
I<decoder_inst>.
This may be NULL.
=head1 RETURN VALUES

View File

@ -121,7 +121,9 @@ int OSSL_DECODER_from_data(OSSL_DECODER_CTX *ctx, const unsigned char **pdata,
*/
OSSL_DECODER_CTX *
OSSL_DECODER_CTX_new_by_EVP_PKEY(EVP_PKEY **pkey,
const char *input_type, const char *keytype,
const char *input_type,
const char *input_struct,
const char *keytype, int selection,
OSSL_LIB_CTX *libctx, const char *propquery);
# ifdef __cplusplus