Commit 66454bf8ba for openssl.org

commit 66454bf8bac860212bb959c1e847a0483a053025
Author: Richard Levitte <levitte@openssl.org>
Date:   Thu Nov 9 10:42:25 2023 +0100

    [design] Functions for explicitly fetched signature algorithms

    This design goes into more details what was outlined in the design for
    [fetching composite (PKEY) algorithms and using them].

    It also changes what functionality will be used for this.  The design for
    signature was originally to add modified initializers for DigestSign and
    DigestVerify, but recent OTC discussions redirected us to have a closer look
    at EVP_PKEY_sign() and EVP_PKEY_verify().

    [fetching composite (PKEY) algorithms and using them]:
        ./fetching-composite-algorithms.md

    Reviewed-by: Paul Dale <ppzgs1@gmail.com>
    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/22672)

diff --git a/doc/designs/fetching-composite-algorithms.md b/doc/designs/fetching-composite-algorithms.md
index 1e3fa99968..c381aa7ccb 100644
--- a/doc/designs/fetching-composite-algorithms.md
+++ b/doc/designs/fetching-composite-algorithms.md
@@ -20,19 +20,19 @@ Public API - Add variants of `EVP_PKEY_CTX` initializers

 As far as this design is concerned, these API sets are affected:

-- SIGNATURE (DigestSign and DigestVerify)
+- SIGNATURE
 - ASYM_CIPHER
 - KEYEXCH

-The proposal is to add these functions:
+The proposal is to add these initializer functions:

 ``` C
-EVP_DigestSignInit_ex2(EVP_PKEY_CTX **pctx,
-                       EVP_SIGNATURE *sig, EVP_PKEY *pkey,
-                       OSSL_LIB_CTX *libctx, const OSSL_PARAM params[]);
-EVP_DigestVerifyInit_ex2(EVP_PKEY_CTX **pctx,
-                         EVP_SIGNATURE *sig, EVP_PKEY *pkey,
-                         OSSL_LIB_CTX *libctx, const OSSL_PARAM params[]);
+int EVP_PKEY_sign_init_ex2(EVP_PKEY_CTX *pctx,
+                           EVP_SIGNATURE *algo, const OSSL_PARAM params[]);
+int EVP_PKEY_verify_init_ex2(EVP_PKEY_CTX *pctx,
+                             EVP_SIGNATURE *algo, const OSSL_PARAM params[]);
+int EVP_PKEY_verify_recover_init_ex2(EVP_PKEY_CTX *pctx,
+                                     EVP_SIGNATURE *algo, const OSSL_PARAM params[]);

 int EVP_PKEY_encrypt_init_ex2(EVP_PKEY_CTX *ctx, EVP_ASYM_CIPHER *asymciph,
                               const OSSL_PARAM params[]);
@@ -43,68 +43,12 @@ int EVP_PKEY_derive_init_ex2(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange,
                              const OSSL_PARAM params[]);
 ```

-Because `EVP_SIGNATURE`, `EVP_ASYM_CIPHER` and `EVP_KEYEXCH` aren't limited
-to composite algorithms, these functions can be used just as well with
-explicit fetches of simple algorithms, say "RSA".  In that case, the caller
-will need to pass necessary auxiliary parameters through the `OSSL_PARAM` or
-a call to a corresponding `set_params` function.
+Detailed proposal for these APIs will be or are prepared in other design
+documents:

-Requirements on the providers
------------------------------
-
-Because it's not immediately obvious from a composite algorithm name what
-key type it requires / supports, at least in code, allowing the use of an
-explicitly fetched implementation of a composite algorithm requires that
-providers cooperate by declaring what key type is required / supported by
-each algorithm.
-
-For non-composite operation algorithms (like "RSA"), this is not necessary,
-see the fallback strategies below.
-
-There are two ways this could be implemented:
-
-1.  through an added provider function that would work like keymgmt's
-    `query_operation_name` function, but would return a key type name
-    instead:
-
-    ``` C
-    # define OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPE         26
-    OSSL_CORE_MAKE_FUNC(const char *, signature_query_key_type, (void))
-
-    # define OSSL_FUNC ASYM_CIPHER_QUERY_KEY_TYPE       12
-    OSSL_CORE_MAKE_FUNC(const char *, asym_cipher_query_key_type, (void))
-
-    # define OSSL_FUNC_KEYEXCH_QUERY_KEY_TYPE           11
-    OSSL_CORE_MAKE_FUNC(const char *, keyexch_query_key_type, (void))
-    ```
-
-2.  through a gettable `OSSL_PARAM`, using the param identity "keytype"
-
-Fallback strategies
--------------------
-
-Because existing providers haven't been updated to declare composite
-algorithms, or to respond to the key type query, some fallback strategies
-will be needed to find out if the `EVP_PKEY` key type is possible to use
-with the fetched algorithm:
-
--   Check if the fetched operation name matches the key type (keymgmt name)
-    of the `EVP_PKEY` that's involved in the operation.  For example, this
-    is useful when someone fetched the `EVP_SIGNATURE` "RSA".
--   Check if the fetched algorithm name matches the name returned by the
-    keymgmt's `query_operation_name` function.  For example, this is useful
-    when someone fetched the `EVP_SIGNATURE` "ECDSA", for which the key type
-    to use is "EC".
--   libcrypto currently has knowledge of some composite algorithm names and
-    what they are composed of, accessible with `OBJ_find_sigid_algs` and
-    similar functionality.  This knowledge is regarded legacy, but can be
-    used to figure out the key type.
-
-If none of these strategies work out, the operation initialization should
-fail.
-
-These strategies have their limitations, but the built-in legacy knowledge
-we currently have in libcrypto should be enough to cover most bases.
+- [Functions for explicitly fetched signature algorithms]
+- [Functions for explicitly fetched asym-cipher algorithms] (not yet designed)
+- [Functions for explicitly fetched keyexch algorithms] (not yet designed)

 -----

@@ -185,3 +129,7 @@ This is hurtful in multiple ways:
     use the result.
 -   It fails discoverability, for example through the `openssl list`
     command.
+
+<!-- links -->
+[Functions for explicitly fetched signature algorithms]:
+    functions-for-explicitly-fetched-signature-algorithms.md
diff --git a/doc/designs/functions-for-explicitly-fetched-signature-algorithms.md b/doc/designs/functions-for-explicitly-fetched-signature-algorithms.md
new file mode 100644
index 0000000000..cb4df1a40c
--- /dev/null
+++ b/doc/designs/functions-for-explicitly-fetched-signature-algorithms.md
@@ -0,0 +1,205 @@
+Functions for explicitly fetched PKEY algorithms
+================================================
+
+Quick background
+----------------
+
+There are several proposed designs that end up revolving around the same
+basic need, explicitly fetched signature algorithms.  The following method
+type is affected by this document:
+
+- `EVP_SIGNATURE`
+
+Public API - Add variants of `EVP_PKEY_CTX` functionality
+---------------------------------------------------------
+
+Through OTC discussions, it's been determined that the most suitable APIs to
+touch are the of `EVP_PKEY_` functions.
+Specifically, `EVP_PKEY_sign()`, `EVP_PKEY_verify()`, `EVP_PKEY_verify_recover()`
+and related functions.
+They can be extended to accept an explicitly fetched algorithm of the right
+type, and to be able to incrementally process indefinite length data streams
+when the fetched algorithm permits it (for example, RSA-SHA256).
+
+It must be made clear that the added functionality cannot be used to compose
+an algorithm from different parts.  For example, it's not possible to specify
+a `EVP_SIGNATURE` "RSA" and combine it with a parameter that specifies the
+hash "SHA256" to get the "RSA-SHA256" functionality.  For an `EVP_SIGNATURE`
+"RSA", the input is still expected to be a digest, or some other input that's
+limited to the modulus size of the RSA pkey.
+
+### Making things less confusing with distinct function names
+
+Until now, `EVP_PKEY_sign()` and friends were only expected to act on the
+pre-computed digest of a message (under the condition that proper flags
+and signature md are specified using functions like
+`EVP_PKEY_CTX_set_rsa_padding()` and `EVP_PKEY_CTX_set_signature_md()`),
+or to act as "primitive" [^1] functions (under the condition that proper
+flags are specified, like `RSA_NO_PADDING` for RSA signatures).
+
+This design proposes an extension to also allow full (not pre-hashed)
+messages to be passed, in a streaming style through an *update* and a
+*final* function.
+
+Discussions have revealed that it is potentially confusing to conflate the
+current functionality with streaming style functionality into the same name,
+so this design separates those out with specific init / update / final
+functions for that purpose.  For oneshot functionality, `EVP_PKEY_sign()`
+and `EVP_PKEY_verify()` remain supported.
+
+[^1]: the term "primitive" is borrowed from [PKCS#1](https://www.rfc-editor.org/rfc/rfc8017#section-5)
+
+### Making it possible to verify with an early signature
+
+Some more recent verification algorithms need to obtain the signature
+before processing the data.
+This is particularly important for streaming modes of operation.
+This design proposes a mechanism to accomodate these algorithms
+and modes of operation.
+
+New public API - API Reference
+------------------------------
+
+### For limited input size / oneshot signing with `EVP_SIGNATURE`
+
+``` C
+int EVP_PKEY_sign_init_ex2(EVP_PKEY_CTX *pctx,
+                           EVP_SIGNATURE *algo,
+                           const OSSL_PARAM params[]);
+```
+
+### For signing a stream with `EVP_SIGNATURE`
+
+``` C
+int EVP_PKEY_sign_message_init(EVP_PKEY_CTX *pctx,
+                               EVP_SIGNATURE *algo,
+                               const OSSL_PARAM params[]);
+int EVP_PKEY_sign_message_update(EVP_PKEY_CTX *ctx,
+                                 const unsigned char *in,
+                                 size_t inlen);
+int EVP_PKEY_sign_message_final(EVP_PKEY_CTX *ctx,
+                                unsigned char *sig,
+                                size_t *siglen);
+#define EVP_PKEY_sign_message(ctx,sig,siglen,tbs,tbslen) \
+    EVP_PKEY_sign(ctx,sig,siglen,tbs,tbslen)
+```
+
+### For limited input size / oneshot verification with `EVP_SIGNATURE`
+
+``` C
+int EVP_PKEY_verify_init_ex2(EVP_PKEY_CTX *pctx,
+                             EVP_SIGNATURE *algo,
+                             const OSSL_PARAM params[]);
+```
+
+### For verifying a stream with `EVP_SIGNATURE`
+
+``` C
+/* Initializers */
+int EVP_PKEY_verify_message_init(EVP_PKEY_CTX *pctx,
+                                 EVP_SIGNATURE *algo,
+                                 const OSSL_PARAM params[]);
+/* Signature setter */
+int EVP_PKEY_CTX_set_signature(EVP_PKEY_CTX *pctx,
+                               unsigned char *sig, size_t siglen,
+                               size_t sigsize);
+/* Update and final */
+int EVP_PKEY_verify_message_update(EVP_PKEY_CTX *ctx,
+                                   const unsigned char *in,
+                                   size_t inlen);
+int EVP_PKEY_verify_message_final(EVP_PKEY_CTX *ctx);
+
+#define EVP_PKEY_verify_message(ctx,sig,siglen,tbs,tbslen) \
+    EVP_PKEY_verify(ctx,sig,siglen,tbs,tbslen)
+```
+
+### For verify_recover with `EVP_SIGNATURE`
+
+Preliminary feedback suggests that a streaming interface is uninteresting for
+verify_recover, so we only specify a new init function.
+
+``` C
+/* Initializers */
+int EVP_PKEY_verify_recover_init_ex2(EVP_PKEY_CTX *pctx,
+                                     EVP_SIGNATURE *algo,
+                                     const OSSL_PARAM params[]);
+```
+
+Requirements on the providers
+-----------------------------
+
+Because it's not immediately obvious from a composite algorithm name what
+key type ("RSA", "EC", ...) it requires / supports, at least in code, allowing
+the use of an explicitly fetched implementation of a composite algorithm
+requires that providers cooperate by declaring what key type is required /
+supported by each algorithm.
+
+For non-composite operation algorithms (like "RSA"), this is not necessary,
+see the fallback strategies below.
+
+This is to be implemented through an added provider function that would work
+like keymgmt's `query_operation_name` function, but would return a NULL
+terminated array of key type name instead:
+
+``` C
+# define OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPE         26
+OSSL_CORE_MAKE_FUNC(const char **, signature_query_key_type, (void))
+```
+
+Furthermore, the distinction of intent, i.e. whether the input is expected
+to be a pre-hashed digest or the original message, must be passed on to the
+provider.  Because we already distinguish that with function names in the
+public API, we use the same mapping in the provider interface.
+
+The already existing `signature_sign` and `signature_verify` remain as they
+are, and can be combined with message init calls.
+
+``` C
+# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT      27
+# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE    28
+# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL     29
+OSSL_CORE_MAKE_FUNC(int, signature_sign_message_init,
+                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, signature_sign_message_update,
+                    (void *ctx, const unsigned char *in, size_t inlen))
+OSSL_CORE_MAKE_FUNC(int, signature_sign_message_final,
+                    (void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize))
+
+# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT    30
+# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE  31
+# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL   32
+OSSL_CORE_MAKE_FUNC(int, signature_verify_message_init,
+                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, signature_verify_message_update,
+                    (void *ctx, const unsigned char *in, size_t inlen))
+/*
+ * signature_verify_message_final requires that the signature to be verified
+ * against is specified via an OSSL_PARAM.
+ */
+OSSL_CORE_MAKE_FUNC(int, signature_verify_message_final, (void *ctx))
+```
+
+Fallback strategies
+-------------------
+
+Because existing providers haven't been updated to respond to the key type
+query, some fallback strategies will be needed for the init calls that take
+an explicitly fetched `EVP_SIGNATURE` argument (they can at least be used
+for pre-hashed digest operations).  To find out if the `EVP_PKEY` key type
+is possible to use with the explicitly fetched algorithm, the following
+fallback strategies may be used.
+
+-   Check if the fetched operation name matches the key type (keymgmt name)
+    of the `EVP_PKEY` that's involved in the operation.  For example, this
+    is useful when someone fetched the `EVP_SIGNATURE` "RSA".  This requires
+    very little modification, as this is already done with the initializer
+    functions that fetch the algorithm implicitly.
+-   Check if the fetched algorithm name matches the name returned by the
+    keymgmt's `query_operation_name` function.  For example, this is useful
+    when someone fetched the `EVP_SIGNATURE` "ECDSA", for which the key type
+    to use is "EC".  This requires very little modification, as this is
+    already done with the initializer functions that fetch the algorithm
+    implicitly.
+
+If none of these strategies work out, the operation initialization should
+fail.