forked from openssl/openssl
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[design] Make it possible to use explicitly fetched signature impleme…
…ntation This design is to allow the use of explicitly fetched EVP_SIGNATURE implementations. Ref: openssl/project#171 Reviewed-by: Matt Caswell <[email protected]> Reviewed-by: Paul Dale <[email protected]> (Merged from openssl#22129)
- Loading branch information
Showing
1 changed file
with
187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |