From e8e2b131ca253f9e28c511c8294e27ddbd0b60c6 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 18 Sep 2023 09:30:13 +0200 Subject: [PATCH] [design] Make it possible to use explicitly fetched signature implementation This design is to allow the use of explicitly fetched EVP_SIGNATURE implementations. Ref: openssl/project#171 Reviewed-by: Matt Caswell Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/22129) --- doc/designs/fetching-composite-algorithms.md | 187 +++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 doc/designs/fetching-composite-algorithms.md diff --git a/doc/designs/fetching-composite-algorithms.md b/doc/designs/fetching-composite-algorithms.md new file mode 100644 index 0000000000000..1e3fa9996876d --- /dev/null +++ b/doc/designs/fetching-composite-algorithms.md @@ -0,0 +1,187 @@ +Fetching composite algorithms and using them - adding the bits still missing +============================================================================ + +Quick background +---------------- + +We currently support - at least in the public libcrypto API - explicitly +fetching composite algorithms (such as AES-128-CBC or HMAC-SHA256), and +using them in most cases. In some cases (symmetric ciphers), our providers +also provide them. + +However, there is one class of algorithms where the support for *using* +explicitly fetched algorithms is lacking: asymmetric algorithms. + +For a longer background and explanation, see +[Background / tl;dr](#background-tldr) at the end of this design. + +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) +- ASYM_CIPHER +- KEYEXCH + +The proposal is to add these 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_encrypt_init_ex2(EVP_PKEY_CTX *ctx, EVP_ASYM_CIPHER *asymciph, + const OSSL_PARAM params[]); +int EVP_PKEY_decrypt_init_ex2(EVP_PKEY_CTX *ctx, EVP_ASYM_CIPHER *asymciph, + const OSSL_PARAM params[]); + +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. + +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. + +----- + +----- + +Background / tl;dr +------------------ + +### What is a composite algorithm? + +A composite algorithm is an algorithm that's composed of more than one other +algorithm. In OpenSSL parlance with a focus on signatures, they have been +known as "sigalgs", but this is really broader than just signature algorithms. +Examples are: + +- AES-128-CBC +- hmacWithSHA256 +- sha256WithRSAEncryption + +### The connection with AlgorithmIdentifiers + +AlgorithmIdentifier is an ASN.1 structure that defines an algorithm as an +OID, along with parameters that should be passed to that algorithm. + +It is expected that an application should be able to take that OID and +fetch it directly, after conversion to string form (either a name if the +application or libcrypto happens to know it, or the OID itself in canonical +numerical form). To enable this, explicit fetching is necessary. + +### What we have today + +As a matter of fact, we already have built-in support for fetching +composite algorithms, although our providers do not fully participate in +that support, and *most of the time*, we also have public APIs to use the +fetched result, commonly known as support for explicit fetching. + +The idea is that providers can declare the different compositions of a base +algorithm in the `OSSL_ALGORITHM` array, each pointing to different +`OSSL_DISPATCH` tables, which would in turn refer to pretty much the same +functions, apart from the constructor function. + +For example, we already do this with symmetric ciphers. + +Another example, which we could implement in our providers today, would be +compositions of HMAC: + +``` C +static const OSSL_ALGORITHM deflt_macs[] = { + /* ... */ + { "HMAC-SHA1:hmacWithSHA1:1.2.840.113549.2.7", + "provider=default", ossl_hmac_sha1_functions }, + { "HMAC-SHA224:hmacWithSHA224:1.2.840.113549.2.8", + "provider=default", ossl_hmac_sha224_functions }, + { "HMAC-SHA256:hmacWithSHA256:1.2.840.113549.2.9", + "provider=default", ossl_hmac_sha256_functions }, + { "HMAC-SHA384:hmacWithSHA384:1.2.840.113549.2.10", + "provider=default", ossl_hmac_sha384_functions }, + { "HMAC-SHA512:hmacWithSHA512:1.2.840.113549.2.11", + "provider=default", ossl_hmac_sha512_functions }, + /* ... */ +``` + +### What we don't have today + +There are some classes of algorithms for which we have no support for using +the result of explicit fetching. So for example, while it's possible for a +provider to declare composite algorithms through the `OSSL_ALGORITHM` array, +there's currently no way for an application to use them. + +This all revolves around asymmetric algorithms, where we currently only +support implicit fetching. + +This is hurtful in multiple ways: + +- It fails the provider authors in terms being able to consistently + declare all algorithms through `OSSL_ALGORITHM` arrays. +- It fails the applications in terms of being able to fetch algorithms and + use the result. +- It fails discoverability, for example through the `openssl list` + command.