/*
- * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2021 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
#include <openssl/pkcs12err.h>
#include <openssl/x509err.h>
#include <openssl/trace.h>
-#include "internal/passphrase.h"
#include "internal/bio.h"
+#include "internal/provider.h"
#include "crypto/decoder.h"
#include "encoder_local.h"
#include "e_os.h"
size_t current_decoder_inst_index;
/* For tracing, count recursion level */
size_t recursion;
+
+ /*-
+ * Flags
+ */
+ unsigned int flag_next_level_called : 1;
+ unsigned int flag_construct_called : 1;
};
static int decoder_process(const OSSL_PARAM params[], void *arg);
int ok = 0;
BIO *new_bio = NULL;
+ if (OSSL_DECODER_CTX_get_num_decoders(ctx) == 0) {
+ ERR_raise_data(ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_DECODER_NOT_FOUND,
+ "No decoders were found. For standard decoders you need "
+ "at least one of the default or base providers "
+ "available. Did you forget to load them?");
+ return 0;
+ }
+
if (BIO_tell(in) < 0) {
new_bio = BIO_new(BIO_f_readbuffer());
if (new_bio == NULL)
ok = decoder_process(NULL, &data);
+ if (!data.flag_construct_called) {
+ const char *spaces
+ = ctx->start_input_type != NULL && ctx->input_structure != NULL
+ ? " " : "";
+ const char *input_type_label
+ = ctx->start_input_type != NULL ? "Input type: " : "";
+ const char *input_structure_label
+ = ctx->input_structure != NULL ? "Input structure: " : "";
+ const char *comma
+ = ctx->start_input_type != NULL && ctx->input_structure != NULL
+ ? ", " : "";
+ const char *input_type
+ = ctx->start_input_type != NULL ? ctx->start_input_type : "";
+ const char *input_structure
+ = ctx->input_structure != NULL ? ctx->input_structure : "";
+
+ if (BIO_eof(in) == 0 || ERR_peek_error() == 0)
+ /* Prevent spurious decoding error */
+ ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_UNSUPPORTED,
+ "No supported data to decode. %s%s%s%s%s%s",
+ spaces, input_type_label, input_type, comma,
+ input_structure_label, input_structure);
+ ok = 0;
+ }
+
/* Clear any internally cached passphrase */
(void)ossl_pw_clear_passphrase_cache(&ctx->pwdata);
}
/*
- * NULL is a valid starting input type, and means that the caller leaves
- * it to code to discover what the starting input type is.
+ * NULL is a valid starting input structure, and means that the caller
+ * leaves it to code to discover what the starting input structure is.
*/
ctx->input_structure = input_structure;
return 1;
void *decoderctx)
{
OSSL_DECODER_INSTANCE *decoder_inst = NULL;
- OSSL_PARAM params[3];
+ const OSSL_PROVIDER *prov;
+ OSSL_LIB_CTX *libctx;
+ const OSSL_PROPERTY_LIST *props;
+ const OSSL_PROPERTY_DEFINITION *prop;
if (!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 ((decoder_inst = OPENSSL_zalloc(sizeof(*decoder_inst))) == NULL) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
return 0;
goto err;
}
- /* Cache the input type for this decoder */
- params[0] =
- OSSL_PARAM_construct_utf8_ptr(OSSL_DECODER_PARAM_INPUT_TYPE,
- (char **)&decoder_inst->input_type, 0);
- params[1] =
- OSSL_PARAM_construct_utf8_ptr(OSSL_DECODER_PARAM_INPUT_STRUCTURE,
- (char **)&decoder_inst->input_structure,
- 0);
- params[2] = OSSL_PARAM_construct_end();
-
- if (!decoder->get_params(params)
- || !OSSL_PARAM_modified(¶ms[0]))
+ prov = OSSL_DECODER_get0_provider(decoder);
+ libctx = ossl_provider_libctx(prov);
+ props = ossl_decoder_parsed_properties(decoder);
+ if (props == NULL) {
+ ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION,
+ "there are no property definitions with decoder %s",
+ OSSL_DECODER_get0_name(decoder));
goto err;
+ }
+
+ /* The "input" property is mandatory */
+ prop = ossl_property_find_property(props, libctx, "input");
+ decoder_inst->input_type = ossl_property_get_string_value(libctx, prop);
+ if (decoder_inst->input_type == NULL) {
+ ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION,
+ "the mandatory 'input' property is missing "
+ "for decoder %s (properties: %s)",
+ OSSL_DECODER_get0_name(decoder),
+ OSSL_DECODER_get0_properties(decoder));
+ goto err;
+ }
+
+ /* The "structure" property is optional */
+ prop = ossl_property_find_property(props, libctx, "structure");
+ if (prop != NULL) {
+ decoder_inst->input_structure
+ = ossl_property_get_string_value(libctx, prop);
+ }
- decoder_inst->flag_input_structure_was_set =
- OSSL_PARAM_modified(¶ms[1]);
decoder_inst->decoder = decoder;
decoder_inst->decoderctx = decoderctx;
return decoder_inst;
return 0;
}
- prov = OSSL_DECODER_provider(decoder);
+ prov = OSSL_DECODER_get0_provider(decoder);
provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
if ((decoderctx = decoder->newctx(provctx)) == NULL
BIO *bio = data->bio;
long loc;
size_t i;
- int err, lib, reason, ok = 0;
+ int ok = 0;
/* For recursions */
struct decoder_process_data_st new_data;
const char *data_type = NULL;
const char *data_structure = NULL;
+ /*
+ * This is an indicator up the call stack that something was indeed
+ * decoded, leading to a recursive call of this function.
+ */
+ data->flag_next_level_called = 1;
+
memset(&new_data, 0, sizeof(new_data));
new_data.ctx = data->ctx;
new_data.recursion = data->recursion + 1;
data->current_decoder_inst_index);
decoder = OSSL_DECODER_INSTANCE_get_decoder(decoder_inst);
- if (ctx->construct != NULL
- && ctx->construct(decoder_inst, params, ctx->construct_data)) {
- ok = 1;
- goto end;
+ data->flag_construct_called = 0;
+ if (ctx->construct != NULL) {
+ int rv = ctx->construct(decoder_inst, params, ctx->construct_data);
+
+ data->flag_construct_called = 1;
+ ok = (rv > 0);
+ if (ok)
+ goto end;
}
/* The constructor didn't return success */
* too special knowledge.
*/
trace_data_structure = data_structure;
- if (data_type != NULL
+ if (data_type != NULL && data_structure != NULL
&& strcasecmp(data_structure, "type-specific") == 0)
data_structure = NULL;
(void *)new_decoder_inst);
} OSSL_TRACE_END(DECODER);
+ /*
+ * We only care about errors reported from decoder implementations
+ * if it returns false (i.e. there was a fatal error).
+ */
+ ERR_set_mark();
+
new_data.current_decoder_inst_index = i;
ok = new_decoder->decode(new_decoderctx, cbio,
new_data.ctx->selection,
OSSL_TRACE_BEGIN(DECODER) {
BIO_printf(trc_out,
- "(ctx %p) %s [%u] Running decoder instance %p => %d\n",
+ "(ctx %p) %s [%u] Running decoder instance %p => %d"
+ " (recursed further: %s, construct called: %s)\n",
(void *)new_data.ctx, LEVEL, (unsigned int)i,
- (void *)new_decoder_inst, ok);
+ (void *)new_decoder_inst, ok,
+ new_data.flag_next_level_called ? "yes" : "no",
+ new_data.flag_construct_called ? "yes" : "no");
} OSSL_TRACE_END(DECODER);
- if (ok)
+ data->flag_construct_called = new_data.flag_construct_called;
+
+ /* Break on error or if we tried to construct an object already */
+ if (!ok || data->flag_construct_called) {
+ ERR_clear_last_mark();
break;
+ }
+ ERR_pop_to_mark();
/*
- * These errors are assumed to come from ossl_store_handle_load_result()
- * in crypto/store/store_result.c. They are currently considered fatal
- * errors, so we preserve them in the error queue and stop.
+ * Break if the decoder implementation that we called recursed, since
+ * that indicates that it successfully decoded something.
*/
- err = ERR_peek_last_error();
- lib = ERR_GET_LIB(err);
- reason = ERR_GET_REASON(err);
- if ((lib == ERR_LIB_EVP
- && reason == EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM)
-#ifndef OPENSSL_NO_EC
- || (lib == ERR_LIB_EC && reason == EC_R_UNKNOWN_GROUP)
-#endif
- || (lib == ERR_LIB_X509 && reason == X509_R_UNSUPPORTED_ALGORITHM)
- || (lib == ERR_LIB_PKCS12
- && reason == PKCS12_R_PKCS12_CIPHERFINAL_ERROR))
- goto end;
+ if (new_data.flag_next_level_called)
+ break;
}
end: