xref: /freebsd/crypto/openssl/doc/designs/functions-for-explicitly-fetched-signature-algorithms.md (revision e7be843b4a162e68651d3911f0357ed464915629)
1Functions for explicitly fetched PKEY algorithms
2================================================
3
4Quick background
5----------------
6
7There are several proposed designs that end up revolving around the same
8basic need, explicitly fetched signature algorithms.  The following method
9type is affected by this document:
10
11- `EVP_SIGNATURE`
12
13Public API - Add variants of `EVP_PKEY_CTX` functionality
14---------------------------------------------------------
15
16Through OTC discussions, it's been determined that the most suitable APIs to
17touch are the of `EVP_PKEY_` functions.
18Specifically, `EVP_PKEY_sign()`, `EVP_PKEY_verify()`, `EVP_PKEY_verify_recover()`
19and related functions.
20They can be extended to accept an explicitly fetched algorithm of the right
21type, and to be able to incrementally process indefinite length data streams
22when the fetched algorithm permits it (for example, RSA-SHA256).
23
24It must be made clear that the added functionality cannot be used to compose
25an algorithm from different parts.  For example, it's not possible to specify
26a `EVP_SIGNATURE` "RSA" and combine it with a parameter that specifies the
27hash "SHA256" to get the "RSA-SHA256" functionality.  For an `EVP_SIGNATURE`
28"RSA", the input is still expected to be a digest, or some other input that's
29limited to the modulus size of the RSA pkey.
30
31### Making things less confusing with distinct function names
32
33Until now, `EVP_PKEY_sign()` and friends were only expected to act on the
34pre-computed digest of a message (under the condition that proper flags
35and signature md are specified using functions like
36`EVP_PKEY_CTX_set_rsa_padding()` and `EVP_PKEY_CTX_set_signature_md()`),
37or to act as "primitive" [^1] functions (under the condition that proper
38flags are specified, like `RSA_NO_PADDING` for RSA signatures).
39
40This design proposes an extension to also allow full (not pre-hashed)
41messages to be passed, in a streaming style through an *update* and a
42*final* function.
43
44Discussions have revealed that it is potentially confusing to conflate the
45current functionality with streaming style functionality into the same name,
46so this design separates those out with specific init / update / final
47functions for that purpose.  For oneshot functionality, `EVP_PKEY_sign()`
48and `EVP_PKEY_verify()` remain supported.
49
50[^1]: the term "primitive" is borrowed from [PKCS#1](https://www.rfc-editor.org/rfc/rfc8017#section-5)
51
52### Making it possible to verify with an early signature
53
54Some more recent verification algorithms need to obtain the signature
55before processing the data.
56This is particularly important for streaming modes of operation.
57This design proposes a mechanism to accomodate these algorithms
58and modes of operation.
59
60New public API - API Reference
61------------------------------
62
63### For limited input size / oneshot signing with `EVP_SIGNATURE`
64
65``` C
66int EVP_PKEY_sign_init_ex2(EVP_PKEY_CTX *pctx,
67                           EVP_SIGNATURE *algo,
68                           const OSSL_PARAM params[]);
69```
70
71### For signing a stream with `EVP_SIGNATURE`
72
73``` C
74int EVP_PKEY_sign_message_init(EVP_PKEY_CTX *pctx,
75                               EVP_SIGNATURE *algo,
76                               const OSSL_PARAM params[]);
77int EVP_PKEY_sign_message_update(EVP_PKEY_CTX *ctx,
78                                 const unsigned char *in,
79                                 size_t inlen);
80int EVP_PKEY_sign_message_final(EVP_PKEY_CTX *ctx,
81                                unsigned char *sig,
82                                size_t *siglen);
83#define EVP_PKEY_sign_message(ctx,sig,siglen,tbs,tbslen) \
84    EVP_PKEY_sign(ctx,sig,siglen,tbs,tbslen)
85```
86
87### For limited input size / oneshot verification with `EVP_SIGNATURE`
88
89``` C
90int EVP_PKEY_verify_init_ex2(EVP_PKEY_CTX *pctx,
91                             EVP_SIGNATURE *algo,
92                             const OSSL_PARAM params[]);
93```
94
95### For verifying a stream with `EVP_SIGNATURE`
96
97``` C
98/* Initializers */
99int EVP_PKEY_verify_message_init(EVP_PKEY_CTX *pctx,
100                                 EVP_SIGNATURE *algo,
101                                 const OSSL_PARAM params[]);
102/* Signature setter */
103int EVP_PKEY_CTX_set_signature(EVP_PKEY_CTX *pctx,
104                               unsigned char *sig, size_t siglen,
105                               size_t sigsize);
106/* Update and final */
107int EVP_PKEY_verify_message_update(EVP_PKEY_CTX *ctx,
108                                   const unsigned char *in,
109                                   size_t inlen);
110int EVP_PKEY_verify_message_final(EVP_PKEY_CTX *ctx);
111
112#define EVP_PKEY_verify_message(ctx,sig,siglen,tbs,tbslen) \
113    EVP_PKEY_verify(ctx,sig,siglen,tbs,tbslen)
114```
115
116### For verify_recover with `EVP_SIGNATURE`
117
118Preliminary feedback suggests that a streaming interface is uninteresting for
119verify_recover, so we only specify a new init function.
120
121``` C
122/* Initializers */
123int EVP_PKEY_verify_recover_init_ex2(EVP_PKEY_CTX *pctx,
124                                     EVP_SIGNATURE *algo,
125                                     const OSSL_PARAM params[]);
126```
127
128Requirements on the providers
129-----------------------------
130
131Because it's not immediately obvious from a composite algorithm name what
132key type ("RSA", "EC", ...) it requires / supports, at least in code, allowing
133the use of an explicitly fetched implementation of a composite algorithm
134requires that providers cooperate by declaring what key type is required /
135supported by each algorithm.
136
137For non-composite operation algorithms (like "RSA"), this is not necessary,
138see the fallback strategies below.
139
140This is to be implemented through an added provider function that would work
141like keymgmt's `query_operation_name` function, but would return a NULL
142terminated array of key type name instead:
143
144``` C
145# define OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPE         26
146OSSL_CORE_MAKE_FUNC(const char **, signature_query_key_type, (void))
147```
148
149Furthermore, the distinction of intent, i.e. whether the input is expected
150to be a pre-hashed digest or the original message, must be passed on to the
151provider.  Because we already distinguish that with function names in the
152public API, we use the same mapping in the provider interface.
153
154The already existing `signature_sign` and `signature_verify` remain as they
155are, and can be combined with message init calls.
156
157``` C
158# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT      27
159# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE    28
160# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL     29
161OSSL_CORE_MAKE_FUNC(int, signature_sign_message_init,
162                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
163OSSL_CORE_MAKE_FUNC(int, signature_sign_message_update,
164                    (void *ctx, const unsigned char *in, size_t inlen))
165OSSL_CORE_MAKE_FUNC(int, signature_sign_message_final,
166                    (void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize))
167
168# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT    30
169# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE  31
170# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL   32
171OSSL_CORE_MAKE_FUNC(int, signature_verify_message_init,
172                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
173OSSL_CORE_MAKE_FUNC(int, signature_verify_message_update,
174                    (void *ctx, const unsigned char *in, size_t inlen))
175/*
176 * signature_verify_message_final requires that the signature to be verified
177 * against is specified via an OSSL_PARAM.
178 */
179OSSL_CORE_MAKE_FUNC(int, signature_verify_message_final, (void *ctx))
180```
181
182Fallback strategies
183-------------------
184
185Because existing providers haven't been updated to respond to the key type
186query, some fallback strategies will be needed for the init calls that take
187an explicitly fetched `EVP_SIGNATURE` argument (they can at least be used
188for pre-hashed digest operations).  To find out if the `EVP_PKEY` key type
189is possible to use with the explicitly fetched algorithm, the following
190fallback strategies may be used.
191
192-   Check if the fetched operation name matches the key type (keymgmt name)
193    of the `EVP_PKEY` that's involved in the operation.  For example, this
194    is useful when someone fetched the `EVP_SIGNATURE` "RSA".  This requires
195    very little modification, as this is already done with the initializer
196    functions that fetch the algorithm implicitly.
197-   Check if the fetched algorithm name matches the name returned by the
198    keymgmt's `query_operation_name` function.  For example, this is useful
199    when someone fetched the `EVP_SIGNATURE` "ECDSA", for which the key type
200    to use is "EC".  This requires very little modification, as this is
201    already done with the initializer functions that fetch the algorithm
202    implicitly.
203
204If none of these strategies work out, the operation initialization should
205fail.
206