1Fetching composite algorithms and using them - adding the bits still missing
2============================================================================
3
4Quick background
5----------------
6
7We currently support - at least in the public libcrypto API - explicitly
8fetching composite algorithms (such as AES-128-CBC or HMAC-SHA256), and
9using them in most cases.  In some cases (symmetric ciphers), our providers
10also provide them.
11
12However, there is one class of algorithms where the support for *using*
13explicitly fetched algorithms is lacking: asymmetric algorithms.
14
15For a longer background and explanation, see
16[Background / tl;dr](#background-tldr) at the end of this design.
17
18Public API - Add variants of `EVP_PKEY_CTX` initializers
19--------------------------------------------------------
20
21As far as this design is concerned, these API sets are affected:
22
23- SIGNATURE (DigestSign and DigestVerify)
24- ASYM_CIPHER
25- KEYEXCH
26
27The proposal is to add these functions:
28
29``` C
30EVP_DigestSignInit_ex2(EVP_PKEY_CTX **pctx,
31                       EVP_SIGNATURE *sig, EVP_PKEY *pkey,
32                       OSSL_LIB_CTX *libctx, const OSSL_PARAM params[]);
33EVP_DigestVerifyInit_ex2(EVP_PKEY_CTX **pctx,
34                         EVP_SIGNATURE *sig, EVP_PKEY *pkey,
35                         OSSL_LIB_CTX *libctx, const OSSL_PARAM params[]);
36
37int EVP_PKEY_encrypt_init_ex2(EVP_PKEY_CTX *ctx, EVP_ASYM_CIPHER *asymciph,
38                              const OSSL_PARAM params[]);
39int EVP_PKEY_decrypt_init_ex2(EVP_PKEY_CTX *ctx, EVP_ASYM_CIPHER *asymciph,
40                              const OSSL_PARAM params[]);
41
42int EVP_PKEY_derive_init_ex2(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange,
43                             const OSSL_PARAM params[]);
44```
45
46Because `EVP_SIGNATURE`, `EVP_ASYM_CIPHER` and `EVP_KEYEXCH` aren't limited
47to composite algorithms, these functions can be used just as well with
48explicit fetches of simple algorithms, say "RSA".  In that case, the caller
49will need to pass necessary auxiliary parameters through the `OSSL_PARAM` or
50a call to a corresponding `set_params` function.
51
52Requirements on the providers
53-----------------------------
54
55Because it's not immediately obvious from a composite algorithm name what
56key type it requires / supports, at least in code, allowing the use of an
57explicitly fetched implementation of a composite algorithm requires that
58providers cooperate by declaring what key type is required / supported by
59each algorithm.
60
61For non-composite operation algorithms (like "RSA"), this is not necessary,
62see the fallback strategies below.
63
64There are two ways this could be implemented:
65
661.  through an added provider function that would work like keymgmt's
67    `query_operation_name` function, but would return a key type name
68    instead:
69
70    ``` C
71    # define OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPE         26
72    OSSL_CORE_MAKE_FUNC(const char *, signature_query_key_type, (void))
73
74    # define OSSL_FUNC ASYM_CIPHER_QUERY_KEY_TYPE       12
75    OSSL_CORE_MAKE_FUNC(const char *, asym_cipher_query_key_type, (void))
76
77    # define OSSL_FUNC_KEYEXCH_QUERY_KEY_TYPE           11
78    OSSL_CORE_MAKE_FUNC(const char *, keyexch_query_key_type, (void))
79    ```
80
812.  through a gettable `OSSL_PARAM`, using the param identity "keytype"
82
83Fallback strategies
84-------------------
85
86Because existing providers haven't been updated to declare composite
87algorithms, or to respond to the key type query, some fallback strategies
88will be needed to find out if the `EVP_PKEY` key type is possible to use
89with the fetched algorithm:
90
91-   Check if the fetched operation name matches the key type (keymgmt name)
92    of the `EVP_PKEY` that's involved in the operation.  For example, this
93    is useful when someone fetched the `EVP_SIGNATURE` "RSA".
94-   Check if the fetched algorithm name matches the name returned by the
95    keymgmt's `query_operation_name` function.  For example, this is useful
96    when someone fetched the `EVP_SIGNATURE` "ECDSA", for which the key type
97    to use is "EC".
98-   libcrypto currently has knowledge of some composite algorithm names and
99    what they are composed of, accessible with `OBJ_find_sigid_algs` and
100    similar functionality.  This knowledge is regarded legacy, but can be
101    used to figure out the key type.
102
103If none of these strategies work out, the operation initialization should
104fail.
105
106These strategies have their limitations, but the built-in legacy knowledge
107we currently have in libcrypto should be enough to cover most bases.
108
109-----
110
111-----
112
113Background / tl;dr
114------------------
115
116### What is a composite algorithm?
117
118A composite algorithm is an algorithm that's composed of more than one other
119algorithm.  In OpenSSL parlance with a focus on signatures, they have been
120known as "sigalgs", but this is really broader than just signature algorithms.
121Examples are:
122
123-   AES-128-CBC
124-   hmacWithSHA256
125-   sha256WithRSAEncryption
126
127### The connection with AlgorithmIdentifiers
128
129AlgorithmIdentifier is an ASN.1 structure that defines an algorithm as an
130OID, along with parameters that should be passed to that algorithm.
131
132It is expected that an application should be able to take that OID and
133fetch it directly, after conversion to string form (either a name if the
134application or libcrypto happens to know it, or the OID itself in canonical
135numerical form).  To enable this, explicit fetching is necessary.
136
137### What we have today
138
139As a matter of fact, we already have built-in support for fetching
140composite algorithms, although our providers do not fully participate in
141that support, and *most of the time*, we also have public APIs to use the
142fetched result, commonly known as support for explicit fetching.
143
144The idea is that providers can declare the different compositions of a base
145algorithm in the `OSSL_ALGORITHM` array, each pointing to different
146`OSSL_DISPATCH` tables, which would in turn refer to pretty much the same
147functions, apart from the constructor function.
148
149For example, we already do this with symmetric ciphers.
150
151Another example, which we could implement in our providers today, would be
152compositions of HMAC:
153
154``` C
155static const OSSL_ALGORITHM deflt_macs[] = {
156    /* ... */
157    { "HMAC-SHA1:hmacWithSHA1:1.2.840.113549.2.7",
158      "provider=default", ossl_hmac_sha1_functions },
159    { "HMAC-SHA224:hmacWithSHA224:1.2.840.113549.2.8",
160      "provider=default", ossl_hmac_sha224_functions },
161    { "HMAC-SHA256:hmacWithSHA256:1.2.840.113549.2.9",
162      "provider=default", ossl_hmac_sha256_functions },
163    { "HMAC-SHA384:hmacWithSHA384:1.2.840.113549.2.10",
164      "provider=default", ossl_hmac_sha384_functions },
165    { "HMAC-SHA512:hmacWithSHA512:1.2.840.113549.2.11",
166      "provider=default", ossl_hmac_sha512_functions },
167    /* ... */
168```
169
170### What we don't have today
171
172There are some classes of algorithms for which we have no support for using
173the result of explicit fetching.  So for example, while it's possible for a
174provider to declare composite algorithms through the `OSSL_ALGORITHM` array,
175there's currently no way for an application to use them.
176
177This all revolves around asymmetric algorithms, where we currently only
178support implicit fetching.
179
180This is hurtful in multiple ways:
181
182-   It fails the provider authors in terms being able to consistently
183    declare all algorithms through `OSSL_ALGORITHM` arrays.
184-   It fails the applications in terms of being able to fetch algorithms and
185    use the result.
186-   It fails discoverability, for example through the `openssl list`
187    command.
188