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

Michael Richardson <mcr-SWp7JaYWvAQV+D8aMU/[email protected]> Wed, 27 Aug 2025 19:02:45 -0400
Newsgroups gmane.comp.encryption.openssl.user
Message-ID <[email protected]>
Viktor Dukhovni <[email protected]> wrote:
    >> I want to access providers from ruby (and ultimately, rails) (I care
    >> about using an IDevID provisioned into a TPM2 device to sign certain
    >> artifacts/claims. The details are not that important, unicast if you
    >> like) I expect the private key to remain in the TPM, rather than be
    >> loaded from an encrypted storage, but that could change in the future.

    > 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.
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.

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.

    >     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.

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.

I doubt my fix is correct, but without some unit test cases that actually
had complete code coverage, I won't know what the full set of behaviour is.
It might be that swapping case 1:/case 2: would work.
Or maybe it's the call to:
        if (tmp_keymgmt != NULL)
            provkey = evp_pkey_export_to_provider(locpctx->pkey, locpctx->libctx,
                                                  &tmp_keymgmt, locpctx->propquery);

that is wrong.  Maybe that should occur only after the loop finishes.
(Again, not ending prematurely)

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.

--
]               Never tell me the odds!                 | ipv6 mesh networks [
]   Michael Richardson, Sandelman Software Works        |    IoT architect   [
]     mcr-SWp7JaYWvAQV+D8aMU/[email protected]  http://www.sandelman.ca/        |   ruby on rails    [




-- 
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/18581.1756335765%40obiwan.sandelman.ca.
signature.asc (application/pgp-signature, 511 B)
-----BEGIN PGP SIGNATURE-----

iQFFBAEBCgAvFiEEbsyLEzg/qUTA43uogItw+93Q3WUFAmivjpURHG1jckBzYW5k
ZWxtYW4uY2EACgkQgItw+93Q3WUMRAgAhL9ZAC6em7kx+CLNR5sFZZl2qimfbyyr
kw8vjQFWUxsJJNMDKpy0WQv58hhJK0/dmMAc1co0Xg7G4jr3y0qU/FJpE/ulqhJJ
CZGmIcx4IXoDLY/Ovqy9ttmqqyruV33gjiN2y6maTVjcD+qQjjt8a/sdx3+ku3g1
Mrycez280EgBYAU69WoI0w3zfAiXRAMEtAYG8UW+cdQ2KirCFNpMXA5YpKAY6g1T
3QVQOoD8gLqiL1Nvon/bUFKi12IiRqFvFfVSIQLMMrYJTKaJDPFke/KBlhbssprk
hf2YbHAFgQ6vICxsetHvSGNpe2WfAlB/wwIKvQrlTbUK8HKgSDoC7Q==
=qFAO
-----END PGP SIGNATURE-----