Re: ruby-openssl + provider interface: generating keys with provider

Viktor Dukhovni <[email protected]> Thu, 28 Aug 2025 12:57:04 +1000
Newsgroups gmane.comp.encryption.openssl.user
Message-ID <[email protected]>
On Wed, Aug 27, 2025 at 07:02:45PM -0400, Michael Richardson wrote:

> > I am not convinced you really **want** to explicitly "access
> > providers".  Rather, you likely want to have some operations (key
> > generation, loading a key, signing, ...) performed by a chosen
> > provider.
> 
> I don't know if there is semantic subtlety you are trying to get at, but I've
> missed it.   This seems to be semantic pedantry to me.  I'm happy to be wrong.
> 
> I think in 60% of the cases, people building bespoke systems in C, Rust, ruby,
> python, Perl, ... know exactly what they want, and they are mostly targetting
> a specific provider.

The distinction is real, I am not in the habit of linguistic pedantry.
There's a difference between using the EVP API with a properties(7)
value that fetches algorithm handles from a selected provider, and using
the **provider API** to directly call the backend provider interfaces.

What I'm suggesting is that I'm not seeing your so far stated requirements as
cause to dive into the backend provider API.  You should be able to do
everything you set out to do with the EVP API and judicious use of
"provider=tpm2" in the `propq` argument of various "fetch" calls.

> Yes, they might want some agility in moving to a different provider, but they
> will need to test against those anyway.  Their "customers", if they are
> external, will be told which ones work, and that others are "who knows" until
> tested.  For me, this query string is not only unwanted, but could even be dangerous.
> 
> In the other 40% of cases, the systems have been built for others to use, and
> the query string has some significant value because, the systems are not open
> source (or rather, then people installing them are not installing from
> source), so a way for the operator to specify the specific provider, and
> maybe even some parameters to the provider, such as an IP address (in the
> case of an big-iron HSM) to connect to.

The IP address of a network HSM would likely be part of the provider
configuration (load parameters), and would then be implicit in
subsequent calls to the provider.  I would not expect it to have
be specified when fetching algorithms, signing, verifying, ...

> I'm working on a bespoke system written RubyOnRails and Rust
> (different pieces), and to do that I'm trying to make sure that the
> ruby-openssl library can do what I want.  I'd like to benefit as many
> people as possible, but the query string business is not particularly
> useful to me.

Your desire to bypass the EVP API is perplexing.  The backend provider
API primarily there to enable the EVP layer to support a mix of
providers and to allow some providers to "wrap" (be a front ends to)
other providers.  It is not expected that end-applications will directly
interface with provider backends.

>     > Property Query String A property query string is a string
>     > containing a sequence of properties that can be used to select an
>     > algorithm implementation.  For example the query string
>     > "provider=example,foo=bar" will select algorithms from the "example"
>     > provider that have a "foo" property defined for them with a value of
>     > "bar".
> 
> Yes, but I shouldn't have to throw these strings all over the place.
> Once is enough.

If you're sufficiently disinclined to pass explicit `propq` values
to the relevant API calls, you can, if you prefer, use:

    EVP_set_default_properties(3)

to set a default.  Whichever libctx (or NULL for the default) is
the one the provider is loaded into, can be set up to make that
provider be target of all fetch operations.  You can then opt
out of that default with a "local" property of "-provider".

> I've traced into crypto/evp/m_sigver.c, to:
>      static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
> 
> It's a very complex function.  It really deserves some unit tests.
> I found that the loop gets it wrong.  An EVP_MD_CTX has been created a few
> layers up based upon the EVP_PKEY(_CTX), which has a sensible keymgmt
> pointing at the provider which has access to the private key.
> Picking ANY OTHER provider at this point would be stupid, yet the loop
> manages to do exactly that.
> The loop starting after the comments at line 116:
>     for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
> 
> only runs once.  I don't think it should exit the loop when provkey!=NULL.
> Rather, I think it should run all possibilities, and then it should pick the
> *best* one, which is not necessarily the first thing.  It says:
> 
>      * We then try to fetch the keymgmt from the same provider as the
>      * signature, and try to export |ctx->pkey| to that keymgmt (when
>      * this keymgmt happens to be the same as |ctx->keymgmt|, the export
>      * is a no-op, but we call it anyway to not complicate the code even
>      * more).
> 
> but, it doesn't do that.  Instead, on the first iter=1, it does:
>                 signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
>                                                 locpctx->propquery);
> 
> despite libctx and propquery being NULL, so of course, it finds the default
> provider.  I added:
> 
>             if(locpctx->libctx || locpctx->propquery) {
>             }
> 
> around that call, which allowed the second iteration to run, which
> then did what the comment above promised.  The correct signature
> routine was called, and the key was available.

To better understand the mismatch between behaviour and expectations, a
reproducer is needed.  Please share minimal demo code that does not
do what you expect.  If you're somewhat confident the EVP implementation
is not correct, a new issue on Github would be helpful, but a bit of
demo code in this thread might be a reasonable way to rule out any basic
misunderstanding.

> In my case, I've created an X509 object that is trying to self-sign
> the CA public key.  You might say that I need to throw propquery
> strings into that, but that seems very wrong: that part of the code
> shouldn't need to know where the EVP_PKEY is from, it should just use
> it.

Sure, there's no explicit propq in either X509_sign(3) or
X509_sign_ctx(3), so any implied provider would be associated
with the key or EVP_MD_CTX.  Which of these two functions is
the one you're using?

-- 
    Viktor.  🇺🇦 Слава Україні!

-- 
You received this message because you are subscribed to the Google Groups "openssl-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openssl-users+unsubscribe-MCmKBN63+Bmbup2nOX2J7Q@public.gmane.org
To view this discussion visit https://groups.google.com/a/openssl.org/d/msgid/openssl-users/aK_FgNmcLiwDoZ5A%40chardros.imrryr.org.