mirror of
https://github.com/openssl/openssl.git
synced 2025-01-06 13:26:43 +08:00
188 lines
7.3 KiB
Markdown
188 lines
7.3 KiB
Markdown
|
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.
|