openssl: Cannot use key and ciphers in different providers
For an external key (non-exportable) I use a custom provider with a minimal store, keymgmt and signature implemented. This works, the key can be loaded, and signing using EVP_PKEY_sign() calls the method in my provider. The latter requires the EVP_PKEY_CTX created with the same propq as the key, though.
Now, to use the corresponding certificate in TLS, I create SSL_CTX in default context so that cipher and digest algorithms are available. And load the key as the private key. This errors during signature as it wants to export the key which is not possible. Is there a way out of this?
An edited snippet of the relevant code:
OSSL_PROVIDER_load(libctx, "ovpn.xkey");
EVP_PKEY *pkey = my_custom_loader(libctx, "provider=ovpn.xkey", uri); /* this loads an opaque pointer as keydata */
SSL_CTX *ctx = SSL_CTX_new_ex(NULL, NULL, method); /* using default context */
SSL_CTX_use_certificate(ctx, cert);
SSL_CTX_use_Privatekey(ctx, pkey);
..
In this case, all is good until signature is needed which fails with calls to provider’s keymgmt_export() with PRIVATE_KEY in selection, not possible for the key. So, it looks like the sign op is tried in the context for SSL_CTX which needs the key exported.
If I use SSL_CTX_new_ex(libctx, "provider=ovpn.xkey", method) it fails quickly with “library has no ciphers”. Is it possible to get the sign operation called in the context of the key’s provider, without losing access to algorithms in the default provider?
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 46 (26 by maintainers)
Commits related to this issue
- EVP_PKEY_derive: Export to operation's provider if needed Fixes #16614 — committed to t8m/openssl by t8m 3 years ago
- CORE: add a provider argument to ossl_method_construct() This makes it possible to limit the search of methods to that particular provider. This uses already available possibilities in ossl_algorith... — committed to levitte/openssl by levitte 3 years ago
- EVP: Add the internal function evp_generic_fetch_from_prov() This function leverages the generic possibility to fetch EVP methods from a specific provider. Fixes #16614 — committed to levitte/openssl by levitte 3 years ago
- EVP: Add internal functions to fetch type specific EVP methods from provider Added functions: evp_signature_fetch_from_prov(), evp_asym_cipher_fetch_from_prov(), evp_keyexch_fetch_from_prov(), evp_k... — committed to levitte/openssl by levitte 3 years ago
- Ensure we use a keymgmt from the same provider for signatures If the pkey cannot export then ensure that we fetch a signature alg from the same provider as the pkey. Partialy fixes #16614 — committed to mattcaswell/openssl by mattcaswell 3 years ago
- EVP: Reverse the fetch logic in all pkey using functionality In all initializing functions for functionality that use an EVP_PKEY, the coded logic was to find an KEYMGMT implementation first, and the... — committed to levitte/openssl by levitte 3 years ago
- EVP: Allow a fallback for operations that work with an EVP_PKEY Functions like EVP_PKEY_sign_init() do an implicit fetch of the operation implementation (EVP_SIGNATURE in this case), then get the KEY... — committed to levitte/openssl by levitte 3 years ago
- CORE: Encure that cached fetches can be done per provider This mostly entails passing around a provider pointer, and handling queries that includes a pointer to a provider, where NULL means "any". T... — committed to levitte/openssl by levitte 3 years ago
- EVP: Allow a fallback for operations that work with an EVP_PKEY Functions like EVP_PKEY_sign_init() do an implicit fetch of the operation implementation (EVP_SIGNATURE in this case), then get the KEY... — committed to openssl/openssl by levitte 3 years ago
- CORE: Encure that cached fetches can be done per provider This mostly entails passing around a provider pointer, and handling queries that includes a pointer to a provider, where NULL means "any". T... — committed to openssl/openssl by levitte 3 years ago
- EVP: Reverse the fetch logic in all pkey using functionality In all initializing functions for functionality that use an EVP_PKEY, the coded logic was to find an KEYMGMT implementation first, and the... — committed to openssl/openssl by levitte 3 years ago
- EVP: Allow a fallback for operations that work with an EVP_PKEY Functions like EVP_PKEY_sign_init() do an implicit fetch of the operation implementation (EVP_SIGNATURE in this case), then get the KEY... — committed to openssl/openssl by levitte 3 years ago
- CORE: Encure that cached fetches can be done per provider This mostly entails passing around a provider pointer, and handling queries that includes a pointer to a provider, where NULL means "any". T... — committed to openssl/openssl by levitte 3 years ago
I simply don’t see what the conflict is?
Load a key from provider “ovpn.xkey” and tell your SSL_CTX to use it. Also tell your SSL_CTX to prefer the default provider (propquery “?provider=default”). Where is the conflict? I expect algorithms to always be fetched from the default provider, except in the case where we need to use the (unexportable) key. In that case our preference to use the default provider doesn’t apply because we cannot use the default provider.
It is perfectly possible for EVP to respect what the caller has asked for, and still be able to operate without failing in the above scenario. The fact that it currently fails is clearly a bug in my eyes.
I fail to see what is making EVP less precise here.
If we fix these two things then I think it goes a long way to solving @selvanair’s problems (you would not need to implement keygen, or anything to do with keyexch, or tls capabilities).
You probably would still need to handle the keymgmt_operation_name with id = OP_KEYEXCH thing though.Basically if we fixed those bugs then you could fetch the key as now:
And then setup SSL_CTX to prefer the default provider over yours:
Doing it this way, libssl would always use algorithms from default whenever possible. However the private key you loaded would have a keymgmt from your customer provider, and (with the bugs mentioned above fixed) then, because your provider cannot export, it would only fetch a SIGNATURE algorithm from your provider (overriding the preference in the propquery for the default provider). I think this even works for the verify stuff, i.e. when verifying you would not be using a key from your custom provider and therefore the SIGNATURE algorithm fetched would be from the default provider and therefore you should be able to get away without having to implement the verify code in your provider.
It looks clear to me that in 3.1 we need to be provide a better way of saying - its the same as that algorithm but with these differences, e.g. some kind of “filter” provider.