*Ryan Hooper*
+ * Added `OSSL_[EN|DE]CODER_CTX_[set|get]_finalized()` functions.
+ `OSSL_[EN|DE]CODER_CTX_set_*()` and `OSSL_[EN|DE]CODER_CTX_add_*()`
+ functions return 0 if the context is already finalised.
+
+ *Igor Ustinov*
+
OpenSSL 3.6
-----------
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
/*
* 0 is a valid selection, and means that the caller leaves
* it to code to discover what the selection is.
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ 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.
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
/*
* NULL is a valid starting input structure, and means that the caller
* leaves it to code to discover what the starting input structure is.
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
prov = OSSL_DECODER_get0_provider(decoder);
provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
/*
* If there is no stack of OSSL_DECODER_INSTANCE, we have nothing
* more to add. That's fine.
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
+
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->construct = construct;
return 1;
}
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
+
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->construct_data = construct_data;
return 1;
}
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
+
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->cleanup = cleanup;
return 1;
}
+int OSSL_DECODER_CTX_set_finalized(OSSL_DECODER_CTX *ctx)
+{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ ctx->finalized = 1;
+ return 1;
+}
+
+int OSSL_DECODER_CTX_get_finalized(OSSL_DECODER_CTX *ctx)
+{
+ if (ctx == NULL)
+ return 0;
+
+ return ctx->finalized;
+}
+
OSSL_DECODER_CONSTRUCT *
OSSL_DECODER_CTX_get_construct(OSSL_DECODER_CTX *ctx)
{
&& OSSL_DECODER_CTX_set_selection(ctx, selection)
&& ossl_decoder_ctx_setup_for_pkey(ctx, keytype, libctx, propquery)
&& OSSL_DECODER_CTX_add_extra(ctx, libctx, propquery)
+ && OSSL_DECODER_CTX_set_finalized(ctx)
&& (propquery == NULL
|| OSSL_DECODER_CTX_set_params(ctx, decoder_params))) {
OSSL_TRACE_BEGIN(DECODER) {
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
if (!ossl_assert(selection != 0)) {
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->output_type = output_type;
return 1;
}
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->output_structure = output_structure;
return 1;
}
return 0;
}
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
prov = OSSL_ENCODER_get0_provider(encoder);
provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
OSSL_LIB_CTX *libctx, const char *propq)
{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
return 1;
}
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
+
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->construct = construct;
return 1;
}
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
+
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->construct_data = construct_data;
return 1;
}
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
+
+ if (ctx->finalized != 0) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
ctx->cleanup = cleanup;
return 1;
}
+int OSSL_ENCODER_CTX_set_finalized(OSSL_ENCODER_CTX *ctx)
+{
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ ctx->finalized = 1;
+ return 1;
+}
+
+int OSSL_ENCODER_CTX_get_finalized(OSSL_ENCODER_CTX *ctx)
+{
+ if (ctx == NULL)
+ return 0;
+
+ return ctx->finalized;
+}
+
OSSL_ENCODER *
OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
{
/* For any function that needs a passphrase reader */
struct ossl_passphrase_data_st pwdata;
+
+ /* Flag that the structure is ready for use */
+ int finalized;
};
struct ossl_decoder_instance_st {
/* Signal that further processing should not continue. */
int harderr;
+
+ /* Flag that the structure is ready for use */
+ int finalized;
};
const OSSL_PROPERTY_LIST *
|| OSSL_ENCODER_CTX_set_output_structure(ctx, output_struct))
&& OSSL_ENCODER_CTX_set_selection(ctx, selection)
&& ossl_encoder_ctx_setup_for_pkey(ctx, pkey, selection, propquery)
- && OSSL_ENCODER_CTX_add_extra(ctx, libctx, propquery)) {
+ && OSSL_ENCODER_CTX_add_extra(ctx, libctx, propquery)
+ && OSSL_ENCODER_CTX_set_finalized(ctx)) {
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
int save_parameters = pkey->save_parameters;
OSSL_DECODER_CTX_set_construct,
OSSL_DECODER_CTX_set_construct_data,
OSSL_DECODER_CTX_set_cleanup,
+OSSL_DECODER_CTX_set_finalized,
OSSL_DECODER_CTX_get_construct,
OSSL_DECODER_CTX_get_construct_data,
OSSL_DECODER_CTX_get_cleanup,
+OSSL_DECODER_CTX_get_finalized,
OSSL_DECODER_export,
OSSL_DECODER_INSTANCE_get_decoder,
OSSL_DECODER_INSTANCE_get_decoder_ctx,
void *OSSL_DECODER_CTX_get_construct_data(OSSL_DECODER_CTX *ctx);
OSSL_DECODER_CLEANUP *OSSL_DECODER_CTX_get_cleanup(OSSL_DECODER_CTX *ctx);
+ int OSSL_DECODER_CTX_set_finalized(OSSL_DECODER_CTX *ctx);
+ int OSSL_DECODER_CTX_get_finalized(OSSL_DECODER_CTX *ctx);
+
int OSSL_DECODER_export(OSSL_DECODER_INSTANCE *decoder_inst,
void *reference, size_t reference_sz,
OSSL_CALLBACK *export_cb, void *export_cbarg);
added decoders, and adds them as well. This is used to build decoder
chains.
+OSSL_DECODER_CTX_set_selection() sets what the input is expected to contain.
+
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_construct(), OSSL_DECODER_CTX_set_construct_data() and
OSSL_DECODER_CTX_set_cleanup() respectively.
+OSSL_DECODER_CTX_set_finalized() finalises the context. Functions
+OSSL_DECODER_CTX_set_selection(), OSSL_DECODER_CTX_set_output_type(),
+OSSL_DECODER_CTX_set_output_structure(), OSSL_DECODER_CTX_add_encoder(),
+OSSL_DECODER_CTX_add_extra(), OSSL_DECODER_CTX_set_construct(),
+OSSL_DECODER_CTX_set_construct_data() and OSSL_DECODER_CTX_set_cleanup()
+can't be used after the context is finalised.
+
+OSSL_DECODER_CTX_get_finalized() indicates if the context was finalised.
+
OSSL_DECODER_export() is a fallback function for constructors that cannot
use the data they get directly for diverse reasons. It takes the same
decode instance I<decoder_inst> that the constructor got and an object
valid, or 0 if one of them was invalid or caused some other failure in the
implementation.
+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_set_construct(), OSSL_DECODER_CTX_set_construct_data() and
-OSSL_DECODER_CTX_set_cleanup() return 1 on success, or 0 on failure.
+OSSL_DECODER_CTX_set_construct(), OSSL_DECODER_CTX_set_construct_data(),
+OSSL_DECODER_CTX_set_cleanup() and OSSL_DECODER_CTX_set_finalized()
+return 1 on success, or 0 on failure.
OSSL_DECODER_CTX_get_construct(), OSSL_DECODER_CTX_get_construct_data() and
OSSL_DECODER_CTX_get_cleanup() return the current pointers to the
constructor, the constructor data and the cleanup functions, respectively.
+OSSL_DECODER_CTX_get_finalized() returns 1 if I<ctx> was finalised,
+0 otherwise. It also returns 0 if I<ctx> is NULL.
+
OSSL_DECODER_CTX_num_decoders() returns the current number of decoders. It
returns 0 if I<ctx> is NULL.
The functions described here were added in OpenSSL 3.0.
+OSSL_DECODER_CTX_set_finalized() and OSSL_DECODER_CTX_get_finalized()
+were added in OpenSSL 4.0.
+
=head1 COPYRIGHT
Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
the B<OSSL_ENCODER_CTX> and missing encoder implementation, and allows it to
act accordingly.
+Note that OSSL_DECODER_CTX_new_for_pkey() finalises the OSSL_DECODER_CTX;
+after that the B<OSSL_DECODER_CTX_set_*()> and B<OSSL_DECODER_CTX_add_*()>
+functions described in L<OSSL_DECODER_CTX(3)> shouldn't be called.
+
OSSL_DECODER_CTX_set_passphrase() gives the implementation a pass phrase to
use when decrypting the encoded private key. Alternatively, a pass phrase
callback may be specified with the following functions.
OSSL_ENCODER_CLEANUP,
OSSL_ENCODER_CTX_set_construct,
OSSL_ENCODER_CTX_set_construct_data,
-OSSL_ENCODER_CTX_set_cleanup
+OSSL_ENCODER_CTX_set_cleanup,
+OSSL_ENCODER_CTX_set_finalized,
+OSSL_ENCODER_CTX_get_finalized
- Encoder context routines
=head1 SYNOPSIS
int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
OSSL_ENCODER_CLEANUP *cleanup);
+ int OSSL_ENCODER_CTX_set_finalized(OSSL_ENCODER_CTX *ctx);
+ int OSSL_ENCODER_CTX_get_finalized(OSSL_ENCODER_CTX *ctx);
+
=head1 DESCRIPTION
Encoding an input object to the desired encoding may be done with a chain of
from already added encoders, and adds them as well. This is used to build
encoder chains.
+OSSL_ENCODER_CTX_set_selection() sets what should be included in the output.
+
OSSL_ENCODER_CTX_set_output_type() sets the ending output type. This must
be specified, and determines if a complete encoder chain is available.
OSSL_ENCODER_CTX_set_cleanup() sets the constructor data I<cleanup>
function. This is called by L<OSSL_ENCODER_CTX_free(3)>.
+OSSL_ENCODER_CTX_set_finalized() finalises the context. Functions
+OSSL_ENCODER_CTX_set_selection(),
+OSSL_ENCODER_CTX_set_output_type(), OSSL_ENCODER_CTX_set_output_structure(),
+OSSL_ENCODER_CTX_add_encoder(), OSSL_ENCODER_CTX_add_extra(),
+OSSL_ENCODER_CTX_set_construct(), OSSL_ENCODER_CTX_set_construct_data() and
+OSSL_ENCODER_CTX_set_cleanup() can't be used after the context is finalised.
+
+OSSL_ENCODER_CTX_get_finalized() indicates if the context was finalised.
+
=head2 Constructor
A B<OSSL_ENCODER_CONSTRUCT> gets the following arguments:
valid, or 0 if one of them was invalid or caused some other failure in the
implementation.
+OSSL_ENCODER_CTX_set_selection(),
+OSSL_ENCODER_CTX_set_output_type(), OSSL_ENCODER_CTX_set_output_structure(),
OSSL_ENCODER_CTX_add_encoder(), OSSL_ENCODER_CTX_add_extra(),
-OSSL_ENCODER_CTX_set_construct(), OSSL_ENCODER_CTX_set_construct_data() and
-OSSL_ENCODER_CTX_set_cleanup() return 1 on success, or 0 on failure.
+OSSL_ENCODER_CTX_set_construct(), OSSL_ENCODER_CTX_set_construct_data(),
+OSSL_ENCODER_CTX_set_cleanup() and OSSL_ENCODER_CTX_set_finalized()
+return 1 on success, or 0 on failure.
+
+OSSL_ENCODER_CTX_get_finalized() returns 1 if I<ctx> was finalised,
+0 otherwise. It also returns 0 if I<ctx> is NULL.
OSSL_ENCODER_CTX_get_num_encoders() returns the current number of encoders.
It returns 0 if I<ctx> is NULL.
OSSL_ENCODER_INSTANCE_get_output_structure() returns a string with the name
of the output structure.
+=head1 NOTES AND BUGS
+
+The chain mechanism in ENCODE is not yet completely implemented.
+It affects functions such as OSSL_ENCODER_CTX_add_extra and the
+inner processing loop.
+
=head1 SEE ALSO
L<provider(7)>, L<OSSL_ENCODER(3)>
The functions described here were added in OpenSSL 3.0.
+OSSL_ENCODER_CTX_set_finalized() and OSSL_ENCODER_CTX_get_finalized()
+were added in OpenSSL 4.0.
+
=head1 COPYRIGHT
Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
the B<OSSL_ENCODER_CTX> and missing encoder implementation, and allows it to
act accordingly.
+Note that OSSL_ENCODER_CTX_new_for_pkey() finalises the OSSL_ENCODER_CTX;
+after that the B<OSSL_ENCODER_CTX_set_*()> and B<OSSL_ENCODER_CTX_add_*()>
+functions described in L<OSSL_ENCODER_CTX(3)> shouldn't be called.
+
OSSL_ENCODER_CTX_set_cipher() tells the implementation what cipher
should be used to encrypt encoded keys. The cipher is given by
name I<cipher_name>. The interpretation of that I<cipher_name> is
int OSSL_DECODER_CTX_set_passphrase_ui(OSSL_DECODER_CTX *ctx,
const UI_METHOD *ui_method,
void *ui_data);
+int OSSL_DECODER_CTX_set_finalized(OSSL_DECODER_CTX *ctx);
+int OSSL_DECODER_CTX_get_finalized(OSSL_DECODER_CTX *ctx);
/*
* Utilities to read the object to decode, with the result sent to cb.
const char *output_type);
int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
const char *output_structure);
+int OSSL_ENCODER_CTX_set_finalized(OSSL_ENCODER_CTX *ctx);
+int OSSL_ENCODER_CTX_get_finalized(OSSL_ENCODER_CTX *ctx);
/* Utilities to add encoders */
int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder);
}
#endif /* OPENSSL_NO_EC */
+/*
+ * Test that OSSL_ENCODER_CTX setters return 0 after finalising the context
+ */
+static int encoder_ctx_setters(void)
+{
+ int ret;
+ OSSL_ENCODER_CTX *ectx = NULL;
+
+ ret = TEST_ptr(ectx = OSSL_ENCODER_CTX_new())
+ && TEST_int_eq(OSSL_ENCODER_CTX_get_finalized(ectx), 0)
+ && TEST_int_eq(OSSL_ENCODER_CTX_set_selection(ectx,
+ EVP_PKEY_KEYPAIR), 1)
+ && TEST_int_eq(OSSL_ENCODER_CTX_set_output_type(ectx, "DER"), 1)
+ && TEST_int_eq(OSSL_ENCODER_CTX_set_output_structure(ectx, "PKCS8"), 1)
+ && TEST_int_eq(OSSL_ENCODER_CTX_set_finalized(ectx), 1)
+ && TEST_int_eq(OSSL_ENCODER_CTX_set_selection(ectx,
+ EVP_PKEY_PUBLIC_KEY), 0)
+ && TEST_int_eq(OSSL_ENCODER_CTX_set_output_type(ectx, "PEM"), 0)
+ && TEST_int_eq(OSSL_ENCODER_CTX_set_output_structure(ectx, "PKCS8"), 0)
+ && TEST_int_eq(OSSL_ENCODER_CTX_add_extra(ectx, NULL, NULL), 0)
+ && TEST_int_eq(OSSL_ENCODER_CTX_get_finalized(ectx), 1);
+ OSSL_ENCODER_CTX_free(ectx);
+ return ret;
+}
+
+/*
+ * Test that OSSL_DECODER_CTX setters return 0 after finalising the context
+ */
+static int decoder_ctx_setters(void)
+{
+ int ret;
+ OSSL_DECODER_CTX *dctx = NULL;
+
+ ret = TEST_ptr(dctx = OSSL_DECODER_CTX_new())
+ && TEST_int_eq(OSSL_DECODER_CTX_get_finalized(dctx), 0)
+ && TEST_int_eq(OSSL_DECODER_CTX_set_selection(dctx,
+ EVP_PKEY_KEYPAIR), 1)
+ && TEST_int_eq(OSSL_DECODER_CTX_set_input_type(dctx, "DER"), 1)
+ && TEST_int_eq(OSSL_DECODER_CTX_set_input_structure(dctx, "PKCS8"), 1)
+ && TEST_int_eq(OSSL_DECODER_CTX_set_finalized(dctx), 1)
+ && TEST_int_eq(OSSL_DECODER_CTX_set_selection(dctx,
+ EVP_PKEY_PUBLIC_KEY), 0)
+ && TEST_int_eq(OSSL_DECODER_CTX_set_input_type(dctx, "PEM"), 0)
+ && TEST_int_eq(OSSL_DECODER_CTX_set_input_structure(dctx, "PKCS8"), 0)
+ && TEST_int_eq(OSSL_DECODER_CTX_add_extra(dctx, NULL, NULL), 0)
+ && TEST_int_eq(OSSL_DECODER_CTX_get_finalized(dctx), 1);
+ OSSL_DECODER_CTX_free(dctx);
+ return ret;
+}
+
typedef enum OPTION_choice {
OPT_ERR = -1,
OPT_EOF = 0,
ADD_TEST_SUITE(SLH_DSA_SHAKE_256f);
}
#endif /* OPENSSL_NO_SLH_DSA */
+
+ ADD_TEST(encoder_ctx_setters);
+ ADD_TEST(decoder_ctx_setters);
}
return 1;
CMS_dataFinal_ex ? 4_0_0 EXIST::FUNCTION:CMS
CMS_SignerInfo_verify_ex ? 4_0_0 EXIST::FUNCTION:CMS
EVP_SIGNATURE_has_message_update ? 4_0_0 EXIST::FUNCTION:
+OSSL_DECODER_CTX_set_finalized ? 4_0_0 EXIST::FUNCTION:
+OSSL_DECODER_CTX_get_finalized ? 4_0_0 EXIST::FUNCTION:
+OSSL_ENCODER_CTX_set_finalized ? 4_0_0 EXIST::FUNCTION:
+OSSL_ENCODER_CTX_get_finalized ? 4_0_0 EXIST::FUNCTION: