]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Added finalized flag to the OSSL_ENCODER/DECODER_CTX structures
authorIgor Ustinov <igus68@gmail.com>
Tue, 11 Nov 2025 10:23:35 +0000 (11:23 +0100)
committerTomas Mraz <tomas@openssl.org>
Tue, 18 Nov 2025 18:35:01 +0000 (19:35 +0100)
After this flag is set, the generic OSSL_ENCODER/DECODER_CTX_set_*()
functions shouldn't be called anymore, so they return error in this case.

Fixes #28249

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/29120)

14 files changed:
CHANGES.md
crypto/encode_decode/decoder_lib.c
crypto/encode_decode/decoder_pkey.c
crypto/encode_decode/encoder_lib.c
crypto/encode_decode/encoder_local.h
crypto/encode_decode/encoder_pkey.c
doc/man3/OSSL_DECODER_CTX.pod
doc/man3/OSSL_DECODER_CTX_new_for_pkey.pod
doc/man3/OSSL_ENCODER_CTX.pod
doc/man3/OSSL_ENCODER_CTX_new_for_pkey.pod
include/openssl/decoder.h
include/openssl/encoder.h
test/endecode_test.c
util/libcrypto.num

index 73c1e9d3221aef9f1e0ee6c1fc8d67b877aecab1..6ac08a2ca464ee83d7bf1d9db4622fec567790fb 100644 (file)
@@ -46,6 +46,12 @@ OpenSSL 4.0
 
    *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
 -----------
 
index f0e29c1608e3715e62bdbc1c134c93d1f0003896..54fc3519901bc136c7e0b569a1858c88c14e90cf 100644 (file)
@@ -170,6 +170,11 @@ int OSSL_DECODER_CTX_set_selection(OSSL_DECODER_CTX *ctx, int selection)
         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.
@@ -186,6 +191,11 @@ int OSSL_DECODER_CTX_set_input_type(OSSL_DECODER_CTX *ctx,
         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.
@@ -202,6 +212,11 @@ int OSSL_DECODER_CTX_set_input_structure(OSSL_DECODER_CTX *ctx,
         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.
@@ -388,6 +403,11 @@ int OSSL_DECODER_CTX_add_decoder(OSSL_DECODER_CTX *ctx, OSSL_DECODER *decoder)
         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);
 
@@ -582,6 +602,11 @@ int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx,
         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.
@@ -684,6 +709,12 @@ int OSSL_DECODER_CTX_set_construct(OSSL_DECODER_CTX *ctx,
         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;
 }
@@ -695,6 +726,12 @@ int OSSL_DECODER_CTX_set_construct_data(OSSL_DECODER_CTX *ctx,
         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;
 }
@@ -706,10 +743,35 @@ int OSSL_DECODER_CTX_set_cleanup(OSSL_DECODER_CTX *ctx,
         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)
 {
index 5f08536bff12bf02e44effc039675c31dbde5cda..4e795a640e8e28623d79fa3bf9dbc774479d0dc9 100644 (file)
@@ -877,6 +877,7 @@ OSSL_DECODER_CTX_new_for_pkey(EVP_PKEY **pkey,
             && 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) {
index 59d0c885a3e4c6bce2b148bf68dc8c9644673e2b..d22b1184d2ab62c8a12c31e000277066bd92d1db 100644 (file)
@@ -174,6 +174,11 @@ int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
         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;
@@ -191,6 +196,11 @@ int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
         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;
 }
@@ -203,6 +213,11 @@ int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
         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;
 }
@@ -315,6 +330,11 @@ int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
         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);
 
@@ -339,6 +359,16 @@ int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
 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;
 }
 
@@ -356,6 +386,12 @@ int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
         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;
 }
@@ -367,6 +403,12 @@ int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
         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;
 }
@@ -378,10 +420,35 @@ int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
         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)
 {
index 11e52cfeec75d4effff5e1d483387f0fa8dcc854..e43259e8649727a814345e31decf888ad34a2798 100644 (file)
@@ -101,6 +101,9 @@ struct ossl_encoder_ctx_st {
 
     /* 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 {
@@ -162,6 +165,9 @@ struct ossl_decoder_ctx_st {
 
     /* Signal that further processing should not continue. */
     int harderr;
+
+    /* Flag that the structure is ready for use */
+    int finalized;
 };
 
 const OSSL_PROPERTY_LIST *
index 414859d1e4651def6f762a958a5627c1e610eba5..7fe7318a3e4152b6fb24de6f4d1df444091a1129 100644 (file)
@@ -388,7 +388,8 @@ OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_for_pkey(const EVP_PKEY *pkey,
             || 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;
 
index 33b09c836db867df8b2cce977332bd42c27b2759..0ccbd62c11bb7f30cc753848f5d3a47beda8c268 100644 (file)
@@ -19,9 +19,11 @@ OSSL_DECODER_CLEANUP,
 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,
@@ -77,6 +79,9 @@ OSSL_DECODER_INSTANCE_get_input_structure
  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);
@@ -135,6 +140,8 @@ OSSL_DECODER_CTX_add_extra() finds decoders that generate input for already
 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.
@@ -160,6 +167,15 @@ OSSL_DECODER_CTX_get_cleanup() return the values that have been set by
 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
@@ -221,14 +237,20 @@ OSSL_DECODER_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.
 
+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.
 
@@ -248,6 +270,9 @@ L<provider(7)>, L<OSSL_DECODER(3)>, L<OSSL_DECODER_from_bio(3)>
 
 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.
index e55212ad554b9ebc6ab5e5b71a601d43be53a28b..2836d0e18a71d44657f7a964f505352d1733ea1f 100644 (file)
@@ -71,6 +71,10 @@ zero).  This helps the caller to distinguish between an error when creating
 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.
index e9248c356a055149105151883dce54b70cac76ee..6266f6ac3a091a00e10fa88cfe709ff2278b3de3 100644 (file)
@@ -22,7 +22,9 @@ OSSL_ENCODER_CONSTRUCT,
 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
@@ -69,6 +71,9 @@ OSSL_ENCODER_CTX_set_cleanup
  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
@@ -111,6 +116,8 @@ OSSL_ENCODER_CTX_add_extra() finds encoders that further encodes output
 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.
 
@@ -130,6 +137,15 @@ passed to the constructor every time it's called.
 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:
@@ -180,9 +196,15 @@ OSSL_ENCODER_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.
 
+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.
@@ -202,6 +224,12 @@ output type.
 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)>
@@ -210,6 +238,9 @@ 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.
index 3bf9c10e374e551719c3295ac299b1398f1e6ef5..5fb7a036813e56d52c492e0f6273a4dcb6350066 100644 (file)
@@ -60,6 +60,10 @@ zero).  This helps the caller to distinguish between an error when creating
 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
index d4ee2cf41340c92c381e58cd997eb3076e19ec73..632a399d97b6101db0254c8d017ffb2f6aa3f31f 100644 (file)
@@ -63,6 +63,8 @@ int OSSL_DECODER_CTX_set_passphrase_cb(OSSL_DECODER_CTX *ctx,
 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.
index c37a6f16f23cc47f92a176b54ed7382780a41f9e..5ffed5ceb2d5d988203f2c09d0ead377cc27f820 100644 (file)
@@ -71,6 +71,8 @@ int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
                                      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);
index 76b9348ec1a2938418b2d212cc9788b018acb0d9..37fc950e46334020f057b63fb18aa99f88c6161b 100644 (file)
@@ -1370,6 +1370,56 @@ static int ec_encode_to_data_multi(void)
 }
 #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,
@@ -1668,6 +1718,9 @@ int setup_tests(void)
             ADD_TEST_SUITE(SLH_DSA_SHAKE_256f);
         }
 #endif /* OPENSSL_NO_SLH_DSA */
+
+        ADD_TEST(encoder_ctx_setters);
+        ADD_TEST(decoder_ctx_setters);
     }
 
     return 1;
index 1cf60c7e848b22509a3e2b3f275b78e64d9bea09..9f351914e1dd855c7134120109294a9d85a389b8 100644 (file)
@@ -5946,3 +5946,7 @@ OSSL_PARAM_clear_free                   ? 4_0_0   EXIST::FUNCTION:
 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: