ENCODER: Redefine the libcrypto <-> provider interface
authorRichard Levitte <levitte@openssl.org>
Mon, 14 Sep 2020 06:29:45 +0000 (08:29 +0200)
committerRichard Levitte <levitte@openssl.org>
Sun, 20 Sep 2020 15:29:31 +0000 (17:29 +0200)
This is part of an effort to make OSSL_ENCODER work more like OSSL_DECODER.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12873)

crypto/property/property_parse.c
doc/man7/provider-encoder.pod
include/openssl/core_dispatch.h
include/openssl/core_names.h

index 6d6ca9b266e33b67fcfe1c909c3f7f5e44087492..d53961daeaa616244f50b73a22ec16dd3dd866f2 100644 (file)
@@ -596,9 +596,9 @@ int ossl_property_parse_init(OPENSSL_CTX *ctx)
         "provider",     /* Name of provider (default, legacy, fips) */
         "version",      /* Version number of this provider */
         "fips",         /* FIPS validated or FIPS supporting algorithm */
-        "format",       /* output format for encoders */
-        "type",         /* output type for encoders */
-        "input",        /* input type for decoders */
+        "output",       /* Output type for encoders */
+        "input",        /* Input type for decoders */
+        "structure",    /* Structure name for encoders and decoders */
     };
     size_t i;
 
index 99787e704074638a9ca34a3a29327cb2a4481005..8048458b947fff496357cf54d589193856c898c3 100644 (file)
@@ -2,7 +2,7 @@
 
 =head1 NAME
 
-provider-encoder - The ENCODER library E<lt>-E<gt> provider functions
+provider-encoder - The OSSL_ENCODER library E<lt>-E<gt> provider functions
 
 =head1 SYNOPSIS
 
@@ -14,6 +14,10 @@ provider-encoder - The ENCODER library E<lt>-E<gt> provider functions
   * pointers in OSSL_DISPATCH arrays.
   */
 
+ /* Encoder parameter accessor and descriptor */
+ const OSSL_PARAM *OSSL_FUNC_encoder_gettable_params(void *provctx);
+ int encoder_get_params(OSSL_PARAM params[]);
+
  /* Functions to construct / destruct / manipulate the encoder context */
  void *OSSL_FUNC_encoder_newctx(void *provctx);
  void OSSL_FUNC_encoder_freectx(void *ctx);
@@ -21,29 +25,51 @@ provider-encoder - The ENCODER library E<lt>-E<gt> provider functions
  const OSSL_PARAM *OSSL_FUNC_encoder_settable_ctx_params(void *provctx)
 
  /* Functions to encode object data */
- int OSSL_FUNC_encoder_encode_data(void *ctx, const OSSL_PARAM *data,
-                                         OSSL_CORE_BIO *out,
-                                         OSSL_PASSPHRASE_CALLBACK *cb,
-                                         void *cbarg);
- int OSSL_FUNC_encoder_encode_object(void *ctx, void *obj, OSSL_CORE_BIO *out,
-                                           OSSL_PASSPHRASE_CALLBACK *cb,
-                                           void *cbarg);
+ int OSSL_FUNC_encoder_encode(void *ctx, OSSL_CORE_BIO *out,
+                              const void *obj_raw,
+                              const OSSL_PARAM obj_abstract[],
+                              int selection,
+                              OSSL_PASSPHRASE_CALLBACK *cb,
+                              void *cbarg);
+
+ /* Functions to import and free a temporary object to be encoded */
+ void *encoder_import_object(void *ctx, int selection,
+                             const OSSL_PARAM params[]);
+ void encoder_free_object(void *obj);
+
 
 =head1 DESCRIPTION
 
 I<We use the wide term "encode" in this manual.  This includes but is
 not limited to serialization.>
 
-The ENCODER is a generic method to encode any set of object data
-in L<OSSL_PARAM(3)> array form, or any provider side object into
-encoded form, and write it to the given OSSL_CORE_BIO.  If the caller wants
-to get the encoded stream to memory, it should provide a
-L<BIO_s_membuf(3)>.
+The ENCODER operation is a generic method to encode a provider-native
+object (I<obj_raw>) or an object abstraction (I<object_abstract>, see
+L<provider-object(7)>) into an encoded form, and write the result to
+the given OSSL_CORE_BIO.  If the caller wants to get the encoded
+stream to memory, it should provide a L<BIO_s_membuf(3)>.
 
-The encoder doesn't need to know more about the B<OSSL_CORE_BIO> pointer than
-being able to pass it to the appropriate BIO upcalls (see
+The encoder doesn't need to know more about the B<OSSL_CORE_BIO>
+pointer than being able to pass it to the appropriate BIO upcalls (see
 L<provider-base(7)/Core functions>).
 
+The ENCODER implementation may be part of a chain, where data is
+passed from one to the next.  For example, there may be an
+implementation to encode an object to DER (that object is assumed to
+be provider-native and thereby passed via I<obj_raw>), and another one
+that encodes DER to PEM (that one would receive the DER encoding via
+I<obj_abstract>).
+
+=begin comment
+
+Having the DER encoding passed via I<obj_abstract> may seem
+complicated.  However, there may be associated meta-data, such as the
+original data type, that need to be passed alongside it, and since
+L<provider-object(7)> already defines a way to pass such data,
+inventing another way to do it makes things even more complicated.
+
+=end comment
+
 The encoding using the L<OSSL_PARAM(3)> array form allows a
 encoder to be used for data that's been exported from another
 provider, and thereby allow them to exist independently of each
@@ -66,90 +92,91 @@ B<OSSL_FUNC_{name}>.
 For example, the "function" OSSL_FUNC_encoder_encode_data() has these:
 
  typedef int
-     (OSSL_FUNC_encoder_encode_data_fn)(void *provctx,
-                                            const OSSL_PARAM params[],
-                                            OSSL_CORE_BIO *out);
- static ossl_inline OSSL_FUNC_encoder_encode_data_fn
+     (OSSL_FUNC_encoder_encode_fn)(void *ctx, OSSL_CORE_BIO *out,
+                                   const void *obj_raw,
+                                   const OSSL_PARAM obj_abstract[],
+                                   int selection,
+                                   OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg);
+ static ossl_inline OSSL_FUNC_encoder_encode_fn
      OSSL_FUNC_encoder_encode_data(const OSSL_DISPATCH *opf);
 
 B<OSSL_DISPATCH> arrays are indexed by numbers that are provided as
 macros in L<openssl-core_dispatch.h(7)>, as follows:
 
+ OSSL_FUNC_encoder_get_params          OSSL_FUNC_ENCODER_GET_PARAMS
+ OSSL_FUNC_encoder_gettable_params     OSSL_FUNC_ENCODER_GETTABLE_PARAMS
+
  OSSL_FUNC_encoder_newctx              OSSL_FUNC_ENCODER_NEWCTX
  OSSL_FUNC_encoder_freectx             OSSL_FUNC_ENCODER_FREECTX
  OSSL_FUNC_encoder_set_ctx_params      OSSL_FUNC_ENCODER_SET_CTX_PARAMS
  OSSL_FUNC_encoder_settable_ctx_params OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS
 
- OSSL_FUNC_encoder_encode_data      OSSL_FUNC_ENCODER_ENCODE_DATA
- OSSL_FUNC_encoder_encode_object    OSSL_FUNC_ENCODER_ENCODE_OBJECT
+ OSSL_FUNC_encoder_encode              OSSL_FUNC_ENCODER_ENCODE_DATA
+
+ OSSL_FUNC_encoder_import_object       OSSL_FUNC_ENCODER_IMPORT_OBJECT
+ OSSL_FUNC_encoder_free_object         OSSL_FUNC_ENCODER_FREE_OBJECT
 
 =head2 Names and properties
 
-The name of an implementation should match the type of object it
-handles.  For example, an implementation that encodes an RSA key
-should be named accordingly.
+The name of an implementation should match the type of object it handles.
+For example, an implementation that encodes an RSA key should be named "RSA".
+Likewise, an implementation that further encodes DER should be named "DER".
 
-To be able to specify exactly what encoding format and what type
-of data a encoder implementation is expected to handle, two
-additional properties may be given:
+Properties can be use to further specify details about an implementation:
 
 =over 4
 
-=item format
+=item output
 
-This property is used to specify what kind of output format the
-implementation produces.  Currently known formats are:
+This property is used to specify what type of output implementation
+produces.  Currently known output types are:
 
 =over 4
 
 =item text
 
-An implementation with that format property value outputs human
-readable text, making that implementation suitable for C<-text> output
-in diverse L<openssl(1)> commands.
+An implementation with that output type outputs human readable text, making
+that implementation suitable for C<-text> output in diverse L<openssl(1)>
+commands.
 
 =item pem
 
-An implementation with that format property value outputs PEM
-formatted data.
+An implementation with that output type outputs PEM formatted data.
 
 =item der
 
-An implementation with that format property value outputs DER
-formatted data.
+An implementation with that output type outputs DER formatted data.
 
 =back
 
-=item type
+=item structure
 
-With objects that have multiple purposes, this can be used to specify
-the purpose type.  The currently known use cases are asymmetric keys
-and key parameters, where the type can be one of:
+This property is used to specify the structure that is used for the encoded
+object.  An example could be C<pkcs8>, to specify explicitly that an object
+(presumably an asymmetric key pair, in this case) will be wrapped in a
+PKCS#8 structure as part of the encoding.
 
-=over 4
-
-=item private
+=back
 
-An implementation with that format property value outputs a private
-key.
+The possible values of both these properties is open ended.  A provider may
+very well specify output types and structures that libcrypto doesn't know
+anything about.
 
-=item public
+=head2 Subset selections
 
-An implementation with that format property value outputs a public
-key.
+Sometimes, an object has more than one subset of data that is interesting to
+treat separately or together.  It's possible to specify what subsets are to
+be encoded, with a set of bits I<selection> that are passed in an B<int>.
 
-=item parameters
+This set of bits depend entirely on what kind of provider-side object is
+passed.  For example, those bits are assumed to be the same as those used
+with L<provider-keymgmt(7)> (see L<provider-keymgmt(7)/Key Objects>) when
+the object is an asymmetric key.
 
-An implementation with that format property value outputs key
-parameters.
-
-=back
-
-=back
-
-The possible values of both these properties is open ended.  A
-provider may very well specify other formats that libcrypto doesn't
-know anything about.
+ENCODER implementations are free to regard the I<selection> as a set of
+hints, but must do so with care.  In the end, the output must make sense,
+and if there's a corresponding decoder, the resulting decoded object must
+match the original object that was encoded.
 
 =head2 Context functions
 
@@ -159,40 +186,76 @@ the functions.
 OSSL_FUNC_encoder_freectx() frees the given I<ctx>, if it was created by
 OSSL_FUNC_encoder_newctx().
 
-OSSL_FUNC_encoder_set_ctx_params() sets context data according to
-parameters from I<params> that it recognises.  Unrecognised parameters
-should be ignored.
+OSSL_FUNC_encoder_set_ctx_params() sets context data according to parameters
+from I<params> that it recognises.  Unrecognised parameters should be
+ignored.
 
 OSSL_FUNC_encoder_settable_ctx_params() returns a constant B<OSSL_PARAM>
 array describing the parameters that OSSL_FUNC_encoder_set_ctx_params()
 can handle.
 
-See L<OSSL_PARAM(3)> for further details on the parameters structure used
-by OSSL_FUNC_encoder_set_ctx_params() and OSSL_FUNC_encoder_settable_ctx_params().
+See L<OSSL_PARAM(3)> for further details on the parameters structure used by
+OSSL_FUNC_encoder_set_ctx_params() and OSSL_FUNC_encoder_settable_ctx_params().
+
+=head2 Import functions
+
+A provider-native object may be associated with a foreign provider, and may
+therefore be unsuitable for direct use with a given ENCODER implementation.
+Provided that the foreign provider's implementation to handle the object has
+a function to export that object in L<OSSL_PARAM(3)> array form, the ENCODER
+implementation should be able to import that array and create a suitable
+object to be passed to OSSL_FUNC_encoder_encode()'s I<obj_raw>.
+
+OSSL_FUNC_encoder_import_object() should import the subset of I<params>
+given with I<selection> to create a provider-native object that can be
+passed as I<obj_raw> to OSSL_FUNC_encoder_encode().
+
+OSSL_FUNC_encoder_free_object() should free the object that was created with
+OSSL_FUNC_encoder_import_object().
 
 =head2 Encoding functions
 
 =for comment There will be a "Decoding functions" title as well
 
-OSSL_FUNC_encoder_encode_data() should take an array of B<OSSL_PARAM>,
-I<data>, and if it contains the data necessary for the object type
-that the implementation handles, it should output the object in
-encoded form to the B<OSSL_CORE_BIO>.
+OSSL_FUNC_encoder_encode() should take an provider-native object (in
+I<obj_raw>) or an object abstraction (in I<obj_abstract>), and should output
+the object in encoded form to the B<OSSL_CORE_BIO>.  The I<selection> bits,
+if relevant, should determine in greater detail what will be output.
+The encoding functions also take an B<OSSL_PASSPHRASE_CALLBACK> function
+pointer along with a pointer to application data I<cbarg>, which should be
+used when a pass phrase prompt is needed.
 
-OSSL_FUNC_encoder_encode_object() should take a pointer to an object
-that it knows intimately, and output that object in encoded form to
-the B<OSSL_CORE_BIO>.  The caller I<must> ensure that this function is called
-with a pointer that the provider of this function is familiar with.
-It is not suitable to use with object pointers coming from other
-providers.
+=head2 Encoder parameters
 
-Both encoding functions also take an B<OSSL_PASSPHRASE_CALLBACK>
-function pointer along with a pointer to application data I<cbarg>,
-which should be used when a pass phrase prompt is needed.
+The ENCODER implementation itself has parameters that can be used to
+determine how it fits in a chain of encoders:
 
-=head2 Encoder parameters
+=over 4
+
+=item "input-type" (B<OSSL_ENCODER_PARAM_INPUT_TYPE>) <UTF8 string>
+
+This is used to specify a distinct type name for the object passed as
+I<obj_raw> to OSSL_FUNC_encoder_encode.
+
+This parameter is an optional parameter, to be used if the name of the
+implementation can be ambiguous because of aliases, and something more
+deterministic is needed.
+
+=item "output-type" (B<OSSL_ENCODER_PARAM_OUTPUT_TYPE>) <UTF8 string>
 
-Parameters currently recognised by built-in encoders are as
+This is used to specify the output type for an ENCODER implementation.
+
+This parameter is I<mandatory>.
+
+=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 type
+from the C<output> property.
+
+=back
+
+=head2 Encoder operation parameters
+
+Operation parameters currently recognised by built-in encoders are as
 follows:
 
 =over 4
@@ -220,11 +283,6 @@ However, it is recommended that implementations that do not handle
 property strings return an error on receiving this parameter unless
 its value NULL or the empty string.
 
-=item "passphrase" (B<OSSL_ENCODER_PARAM_PASS>) <octet string>
-
-A pass phrase provided by the application.  When this is given, the
-built-in encoders will not attempt to use the passphrase callback.
-
 =back
 
 Parameters currently recognised by the built-in pass phrase callback:
@@ -250,8 +308,7 @@ parameters was invalid or caused an error, for which 0 is returned.
 OSSL_FUNC_encoder_settable_ctx_params() returns a pointer to an array of
 constant B<OSSL_PARAM> elements.
 
-OSSL_FUNC_encoder_encode_data() and OSSL_FUNC_encoder_encode_object()
-return 1 on success, or 0 on failure.
+OSSL_FUNC_encoder_encode() return 1 on success, or 0 on failure.
 
 =head1 SEE ALSO
 
index 5c6a4f4848a7cea46765494787a1fe2fd4cf2799..63105d6629a91d7728963ec754b3f6ab8512b56b 100644 (file)
@@ -752,24 +752,37 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, kem_settable_ctx_params, (void *provctx)
 /* Encoders and decoders */
 # define OSSL_FUNC_ENCODER_NEWCTX                      1
 # define OSSL_FUNC_ENCODER_FREECTX                     2
-# define OSSL_FUNC_ENCODER_SET_CTX_PARAMS              3
-# define OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS         4
-# define OSSL_FUNC_ENCODER_ENCODE_DATA                10
-# define OSSL_FUNC_ENCODER_ENCODE_OBJECT              11
+# define OSSL_FUNC_ENCODER_GET_PARAMS                  3
+# define OSSL_FUNC_ENCODER_GETTABLE_PARAMS             4
+# define OSSL_FUNC_ENCODER_SET_CTX_PARAMS              5
+# define OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS         6
+# define OSSL_FUNC_ENCODER_ENCODE                     10
+# define OSSL_FUNC_ENCODER_IMPORT_OBJECT              20
+# define OSSL_FUNC_ENCODER_FREE_OBJECT                21
 OSSL_CORE_MAKE_FUNC(void *, encoder_newctx, (void *provctx))
 OSSL_CORE_MAKE_FUNC(void, encoder_freectx, (void *ctx))
+OSSL_CORE_MAKE_FUNC(int, encoder_get_params, (OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, encoder_gettable_params,
+                    (void *provctx))
 OSSL_CORE_MAKE_FUNC(int, encoder_set_ctx_params,
                     (void *ctx, const OSSL_PARAM params[]))
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, encoder_settable_ctx_params,
                     (void *provctx))
 
-OSSL_CORE_MAKE_FUNC(int, encoder_encode_data,
-                    (void *ctx, const OSSL_PARAM[], OSSL_CORE_BIO *out,
-                     OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg))
-OSSL_CORE_MAKE_FUNC(int, encoder_encode_object,
-                    (void *ctx, const void *obj, OSSL_CORE_BIO *out,
+/*
+ * TODO(3.0) investigate if this should be two functions, one that takes a
+ * raw object and one that takes an object abstraction.
+ */
+OSSL_CORE_MAKE_FUNC(int, encoder_encode,
+                    (void *ctx, OSSL_CORE_BIO *out,
+                     const void *obj_raw, const OSSL_PARAM obj_abstract[],
+                     int selection,
                      OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg))
 
+OSSL_CORE_MAKE_FUNC(void *, encoder_import_object,
+                    (void *ctx, int selection, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(void, encoder_free_object, (void *obj))
+
 # define OSSL_FUNC_DECODER_NEWCTX                      1
 # define OSSL_FUNC_DECODER_FREECTX                     2
 # define OSSL_FUNC_DECODER_GET_PARAMS                  3
index 0fc2868d5b78578ca06041e9d0d41628d9b84bb4..e3d3d27a7f39f56d72b7ff8df731aff26dba6e1e 100644 (file)
@@ -445,10 +445,10 @@ extern "C" {
 /*
  * Encoder / decoder parameters
  */
-/* The passphrase may be passed as a utf8 string or an octet string */
 #define OSSL_ENCODER_PARAM_CIPHER       OSSL_ALG_PARAM_CIPHER
 #define OSSL_ENCODER_PARAM_PROPERTIES   OSSL_ALG_PARAM_PROPERTIES
-#define OSSL_ENCODER_PARAM_PASS         "passphrase"
+#define OSSL_ENCODER_PARAM_INPUT_TYPE   "input-type"
+#define OSSL_ENCODER_PARAM_OUTPUT_TYPE  "output-type"
 
 #define OSSL_DECODER_PARAM_CIPHER       OSSL_ALG_PARAM_CIPHER
 #define OSSL_DECODER_PARAM_PROPERTIES   OSSL_ALG_PARAM_PROPERTIES