ENCODER: Add support for specifying the outermost output structure
authorRichard Levitte <levitte@openssl.org>
Sat, 17 Oct 2020 05:57:04 +0000 (07:57 +0200)
committerRichard Levitte <levitte@openssl.org>
Wed, 11 Nov 2020 11:43:27 +0000 (12:43 +0100)
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/13167)

crypto/encode_decode/encoder_lib.c
crypto/encode_decode/encoder_local.h
doc/man3/OSSL_ENCODER_CTX.pod
doc/man7/provider-encoder.pod
include/openssl/core_names.h
include/openssl/encoder.h
util/libcrypto.num

index 593483313c19283f96c5becd5bd5ed5ba2324ba3..5e4bf69787222351e79ce1930dc44287d5ec2be3 100644 (file)
@@ -97,6 +97,22 @@ int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata,
     return ret;
 }
 
+int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
+{
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if (!ossl_assert(selection != 0)) {
+        ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+
+    ctx->selection = selection;
+    return 1;
+}
+
 int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
                                      const char *output_type)
 {
@@ -109,19 +125,15 @@ int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
     return 1;
 }
 
-int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
+int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
+                                          const char *output_structure)
 {
-    if (!ossl_assert(ctx != NULL)) {
+    if (!ossl_assert(ctx != NULL) || !ossl_assert(output_structure != NULL)) {
         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
 
-    if (!ossl_assert(selection != 0)) {
-        ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
-        return 0;
-    }
-
-    ctx->selection = selection;
+    ctx->output_structure = output_structure;
     return 1;
 }
 
@@ -129,7 +141,7 @@ static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
                                                         void *encoderctx)
 {
     OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
-    OSSL_PARAM params[3];
+    OSSL_PARAM params[4];
 
     if (!ossl_assert(encoder != NULL)) {
         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
@@ -155,12 +167,16 @@ static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
         OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
                                       (char **)&encoder_inst->output_type, 0);
     params[1] =
+        OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE,
+                                      (char **)&encoder_inst->output_structure,
+                                      0);
+    params[2] =
         OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_INPUT_TYPE,
                                       (char **)&encoder_inst->input_type, 0);
-    params[2] = OSSL_PARAM_construct_end();
+    params[3] = OSSL_PARAM_construct_end();
 
     if (!encoder->get_params(params)
-        || !OSSL_PARAM_modified(&params[1]))
+        || !OSSL_PARAM_modified(&params[0]))
         goto err;
 
     if (!OSSL_ENCODER_up_ref(encoder)) {
@@ -312,6 +328,14 @@ OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
     return encoder_inst->output_type;
 }
 
+const char *
+OSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE *encoder_inst)
+{
+    if (encoder_inst == NULL)
+        return NULL;
+    return encoder_inst->output_structure;
+}
+
 static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
 {
     size_t i, end;
@@ -319,6 +343,7 @@ static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
     size_t latest_output_length = 0;
     const char *latest_output_type = NULL;
     const char *last_input_type = NULL;
+    const char *last_output_structure = NULL;
     int ok = 0;
 
     end = OSSL_ENCODER_CTX_get_num_encoders(ctx);
@@ -331,10 +356,12 @@ static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
             OSSL_ENCODER_INSTANCE_get_input_type(encoder_inst);
         const char *current_output_type =
             OSSL_ENCODER_INSTANCE_get_output_type(encoder_inst);
+        const char *current_output_structure =
+            OSSL_ENCODER_INSTANCE_get_output_structure(encoder_inst);
         BIO *current_out;
         BIO *allocated_out = NULL;
         const void *current_data = NULL;
-        OSSL_PARAM abstract[3];
+        OSSL_PARAM abstract[10];
         OSSL_PARAM *abstract_p;
         const OSSL_PARAM *current_abstract = NULL;
 
@@ -374,6 +401,11 @@ static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
                 *abstract_p++ =
                     OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
                                                      (char *)last_input_type, 0);
+            if (last_output_structure != NULL)
+                *abstract_p++ =
+                    OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
+                                                     (char *)last_output_structure,
+                                                     0);
             *abstract_p++ =
                 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
                                                   latest_output,
@@ -398,6 +430,8 @@ static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
 
         if (current_input_type != NULL)
             last_input_type = current_input_type;
+        if (current_output_structure != NULL)
+            last_output_structure = current_output_structure;
 
         if (!ok)
             goto loop_end;
@@ -418,6 +452,8 @@ static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
             BIO_free(allocated_out);
         }
 
+        latest_output_type = encoder_inst->output_type;
+
      loop_end:
         if (current_data != NULL)
             ctx->cleanup(ctx->construct_data);
index 18cddf50fb3257fe05d88a21a2173045a0511703..be4cba378357655a24517b15f8315d74cebd1d3f 100644 (file)
@@ -52,10 +52,11 @@ struct ossl_decoder_st {
 };
 
 struct ossl_encoder_instance_st {
-    OSSL_ENCODER *encoder;       /* Never NULL */
-    void *encoderctx;            /* Never NULL */
-    const char *input_type;      /* May be NULL */
-    const char *output_type;     /* Never NULL */
+    OSSL_ENCODER *encoder;        /* Never NULL */
+    void *encoderctx;             /* Never NULL */
+    const char *input_type;       /* May be NULL */
+    const char *output_type;      /* Never NULL */
+    const char *output_structure; /* May be NULL */
 };
 
 DEFINE_STACK_OF(OSSL_ENCODER_INSTANCE)
@@ -63,11 +64,6 @@ DEFINE_STACK_OF(OSSL_ENCODER_INSTANCE)
 void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst);
 
 struct ossl_encoder_ctx_st {
-    /*
-     * The desired output type.  The encoder implementation have a gettable
-     * "output-type" parameter that this will match against.
-     */
-    const char *output_type;
     /*
      * Select what parts of an object will be encoded.  This selection is
      * bit encoded, and the bits correspond to selection bits available with
@@ -75,6 +71,17 @@ struct ossl_encoder_ctx_st {
      * the OSSL_KEYMGMT_SELECT_ macros are used for this.
      */
     int selection;
+    /*
+     * The desired output type.  The encoder implementation must have a
+     * gettable "output-type" parameter that this will match against.
+     */
+    const char *output_type;
+    /*
+     * The desired output structure, if that's relevant for the type of
+     * object being encoded.  It may be used for selection of the starting
+     * encoder implementations in a chain.
+     */
+    const char *output_structure;
 
     /*
      * Decoders that are components of any current decoding path.
index e8771fc08761926da4042cb7c65e9141015fe7eb..d4ea01060ff0d8fddf4b6e0ed5747fe8d5645081 100644 (file)
@@ -7,8 +7,9 @@ OSSL_ENCODER_CTX_new,
 OSSL_ENCODER_settable_ctx_params,
 OSSL_ENCODER_CTX_set_params,
 OSSL_ENCODER_CTX_free,
-OSSL_ENCODER_CTX_set_output_type,
 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_get_num_encoders,
@@ -17,6 +18,7 @@ OSSL_ENCODER_INSTANCE_get_encoder,
 OSSL_ENCODER_INSTANCE_get_encoder_ctx,
 OSSL_ENCODER_INSTANCE_get_input_type,
 OSSL_ENCODER_INSTANCE_get_output_type,
+OSSL_ENCODER_INSTANCE_get_output_structure,
 OSSL_ENCODER_CONSTRUCT,
 OSSL_ENCODER_CLEANUP,
 OSSL_ENCODER_CTX_set_construct,
@@ -36,9 +38,11 @@ OSSL_ENCODER_CTX_set_cleanup
                                  const OSSL_PARAM params[]);
  void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx);
 
+ int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection);
  int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
                                       const char *output_type);
- int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection);
+ int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
+                                           const char *output_structure);
 
  int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder);
  int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
@@ -54,6 +58,8 @@ OSSL_ENCODER_CTX_set_cleanup
  OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst);
  const char *
  OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst);
+ const char *
+ OSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE *encoder_inst);
 
  typedef const void *OSSL_ENCODER_CONSTRUCT(OSSL_ENCODER_INSTANCE *encoder_inst,
                                             void *construct_data);
@@ -110,8 +116,13 @@ encoder chains.
 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_num_encoders() gets the number of encoders currently added
-to the context I<ctx>.
+OSSL_ENCODER_CTX_set_output_structure() sets the desired output structure.
+This may be used to determines what encoder implementations may be used.
+Depending on the type of object being encoded, the output structure may
+not be relevant.
+
+OSSL_ENCODER_CTX_get_num_encoders() gets the number of encoders currently
+added to the context I<ctx>.
 
 OSSL_ENCODER_CTX_set_construct() sets the constructor I<construct>.
 
@@ -144,18 +155,28 @@ or NULL to indicate that an error has occured.
 
 These utility functions may be used by a constructor:
 
-OSSL_ENCODER_INSTANCE_encoder() can be used to get the encoder method from a
-encoder instance I<encoder_inst>.
+OSSL_ENCODER_INSTANCE_get_encoder() can be used to get the encoder
+implementation of the encoder instance I<encoder_inst>.
+
+OSSL_ENCODER_INSTANCE_get_encoder_ctx() can be used to get the encoder
+implementation's provider context of the encoder instance I<encoder_inst>.
 
-OSSL_ENCODER_INSTANCE_encoder_ctx() can be used to get the encoder method's
-provider context from a encoder instance I<encoder_inst>.
+OSSL_ENCODER_INSTANCE_get_input_type() can be used to get the input type for
+the encoder implementation of the encoder instance I<encoder_inst>.
+This may be NULL.
 
-OSSL_ENCODER_INSTANCE_input_type() can be used to get the input type for
-encoder method from a encoder instance I<encoder_inst>.  This may be NULL.
+OSSL_ENCODER_INSTANCE_get_output_type() can be used to get the output type
+for the encoder implementation of the encoder instance I<encoder_inst>.
+This will never be NULL.
 
-OSSL_ENCODER_INSTANCE_output_type() can be used to get the output type for
-encoder method from a encoder instance I<encoder_inst>.  This will never be
-NULL.
+OSSL_ENCODER_INSTANCE_get_output_type() can be used to get the output type
+for the encoder implementation of the encoder instance I<encoder_inst>.
+This will never be NULL.
+
+OSSL_ENCODER_INSTANCE_get_output_structure() can be used to get the output
+structure for the encoder implementation of the encoder instance
+I<encoder_inst>.
+This may be NULL.
 
 =head1 RETURN VALUES
 
@@ -169,25 +190,28 @@ 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_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_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_DECODER_CTX_num_decoders() returns the current number of decoders.  It
-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_DECODER_INSTANCE_decoder() returns an B<OSSL_DECODER> pointer on
+OSSL_ENCODER_INSTANCE_get_encoder() returns an B<OSSL_ENCODER> pointer on
 success, or NULL on failure.
 
-OSSL_DECODER_INSTANCE_decoder_ctx() returns a provider context pointer on
+OSSL_ENCODER_INSTANCE_get_encoder_ctx() returns a provider context pointer on
 success, or NULL on failure.
 
-OSSL_ENCODER_INSTANCE_input_type() returns a string with the name of the
+OSSL_ENCODER_INSTANCE_get_output_type() returns a string with the name of the
 input type, if relevant.  NULL is a valid returned value.
 
-OSSL_ENCODER_INSTANCE_output_type() returns a string with the name of the
+OSSL_ENCODER_INSTANCE_get_output_type() returns a string with the name of the
 output type.
 
+OSSL_ENCODER_INSTANCE_get_output_structure() returns a string with the name
+of the output structure.
+
 =head1 SEE ALSO
 
 L<provider(7)>, L<OSSL_ENCODER(3)>
index 8048458b947fff496357cf54d589193856c898c3..92a8b2d3ec97c66d404005c238fd2f77ae3af89c 100644 (file)
@@ -251,6 +251,19 @@ This parameter is I<mandatory>.
 in a set of properties, it would be possible to determine the output type
 from the C<output> property.
 
+=item "output-structure" (B<OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE>) <UTF8 string>
+
+This is used to specify the outermost output structure for an ENCODER
+implementation.
+
+For example, an output of type "DER" for a key pair could be structured
+using PKCS#8, or a key type specific structure, such as PKCS#1 for RSA
+keys.
+
+=for comment If we had functionality to get the value of a specific property
+in a set of properties, it would be possible to determine the output
+structure from the C<structure> property.
+
 =back
 
 =head2 Encoder operation parameters
index 850351bd30f9da06e006b36fcb2e242f40dd0035..f0b0cd0163de694e49f8bf8293e95f9417fc4ea8 100644 (file)
@@ -453,10 +453,11 @@ extern "C" {
 /*
  * Encoder / decoder parameters
  */
-#define OSSL_ENCODER_PARAM_CIPHER       OSSL_ALG_PARAM_CIPHER
-#define OSSL_ENCODER_PARAM_PROPERTIES   OSSL_ALG_PARAM_PROPERTIES
-#define OSSL_ENCODER_PARAM_INPUT_TYPE   "input-type"
-#define OSSL_ENCODER_PARAM_OUTPUT_TYPE  "output-type"
+#define OSSL_ENCODER_PARAM_CIPHER           OSSL_ALG_PARAM_CIPHER
+#define OSSL_ENCODER_PARAM_PROPERTIES       OSSL_ALG_PARAM_PROPERTIES
+#define OSSL_ENCODER_PARAM_INPUT_TYPE       "input-type"
+#define OSSL_ENCODER_PARAM_OUTPUT_TYPE      "output-type"
+#define OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE "output-structure"
 
 #define OSSL_DECODER_PARAM_PROPERTIES       OSSL_ALG_PARAM_PROPERTIES
 #define OSSL_DECODER_PARAM_INPUT_TYPE       "input-type"
index 669f688b2de44c6f9ec2b54604258711f287e3c9..760ff05c77106637fb11003d1205de4b69aec71e 100644 (file)
@@ -65,9 +65,11 @@ int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
 int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
                                 const char *cipher_name,
                                 const char *propquery);
+int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection);
 int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
                                      const char *output_type);
-int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection);
+int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
+                                          const char *output_structure);
 
 /* Utilities to add encoders */
 int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder);
@@ -84,6 +86,8 @@ const char *
 OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst);
 const char *
 OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst);
+const char *
+OSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE *encoder_inst);
 
 typedef const void *OSSL_ENCODER_CONSTRUCT(OSSL_ENCODER_INSTANCE *encoder_inst,
                                            void *construct_data);
index 40e1fcb43afa83ae9126711982c475a334cc2504..5bd793efbcba3cf6c5b6c9bba841a752d0677b54 100644 (file)
@@ -5288,3 +5288,5 @@ EVP_PKEY_get1_encoded_public_key        ? 3_0_0   EXIST::FUNCTION:
 OSSL_DECODER_CTX_set_selection          ?      3_0_0   EXIST::FUNCTION:
 OSSL_DECODER_CTX_set_input_structure    ?      3_0_0   EXIST::FUNCTION:
 OSSL_DECODER_INSTANCE_get_input_structure ?    3_0_0   EXIST::FUNCTION:
+OSSL_ENCODER_CTX_set_output_structure   ?      3_0_0   EXIST::FUNCTION:
+OSSL_ENCODER_INSTANCE_get_output_structure ?   3_0_0   EXIST::FUNCTION: