[WIP] X509: Refactor X509_PUBKEY processing to include provider side keys#13994
[WIP] X509: Refactor X509_PUBKEY processing to include provider side keys#13994levitte wants to merge 9 commits intoopenssl:masterfrom
Conversation
ecossl_dh_keyexch_functions -> ossl_ecdh_keyexch_functions ecossl_dsa_signature_functions -> ossl_ecdsa_signature_functions sm2_asym_cipher_functions -> ossl_sm2_asym_cipher_functions sm2_keymgmt_functions -> ossl_sm2_keymgmt_functions sm2_signature_functions -> ossl_sm2_signature_functions
The EC KEYMGMT implementation handled SM2 as well, except what's needed to support decoding: loading functions for both EC and SM2 that checks for the presence or absence of the SM2 curve the same way as the EC / SM2 import functions.
The decoding of DER into keys with keytype specific routines depended entirely on the absence of the generic algo specific C type from EVP_PKEYs. That is not necessary, and may even prove to be a bit of a disadvantage, depending on what libcrypto has to offer in terms of type specific d2i functionality for different kinds of input structures. To remedy, we try with all available type specific functions first, and only turn to the general d2i functions (those that return an EVP_PKEY) as a last resort.
… decoders This makes it possible to use d2i_<TYPE>_PUBKEY instead of the generic d2i_PUBKEY()
When a SubjectPublicKeyInfo (SPKI) is decoded into an X509_PUBKEY structure, the corresponding EVP_PKEY is automatically added as well. This used to only support our built-in keytypes, and only in legacy form. This is now refactored to try to decode the whole SPKI into an EVP_PKEY using OSSL_DECODER, and cache that in the X509_PUBKEY very early. Only when that fails, the existing decoder callback will try to create a legacy EVP_PKEY. For purposes where it's not desirable to do the provider side SPKI decoding, there is now a function d2i_PUBKEY_legacy(). This is used by all the type specific d2i_<TYPE>_PUBKEY(), as well as in out provider DER->key decoder, to avoid running into recursion problems. Fixes openssl#13893
|
Something to be noted is the inherent problem with the early caching of an EVP_PKEY in the X509_PUBKEY, when someone else wants an easy way to decode the DER, as part of a decoder implementation for a keytype we know nothing about. It becomes a recursion problem. The solution I could come up with was to have a |
|
A slightly different solution could have been to let This could be resolved by decoding the X509_ALGOR |
|
Hmm, this solution doesn't seem to work for me. If I run this code: I get: |
|
Yeah, something is off. See the CI failures |
|
What key type was there in that certificate? I just found a problem where RSA and RSA-PSS gets mixed up... |
|
RSA |
The OSSL_FUNC_KEYMGMT_LOAD function for both plain RSA and RSA-PSS keys now also check that the key to be loaded is the correct type, and refuse to load it if it's not.
Furthermore, there are cases where the decoder might not get the key type it expected. This may happen when certain key types that share the same OpenSSL structure may be mixed up somehow. The known cases are EC vs SM2 and RSA vs RSA-PSS. To remedy, we add the possibility to specify a checking function that can check if the key that was decoded meets decoder expectations.
|
A number of fixups added. @mattcaswell, would you mind trying again? |
Same problem. |
|
But hold on, @mattcaswell... is there point that the EVP_PKEY must be provider backed? I thought the primary problem was that it now may be provider backed. In other words, provider backed EVP_PKEYs were completely inaccessible when decoding an X509_PUBKEY before this change, i.e. other algos than our built in ones were impossible. |
If it is not provider backed, will it be automatically imported to provider if you do for example signature verification of a certificate with the X509_PUBKEY? IMO if that's the case, I think we can keep that. |
|
It remains unclear to me why we would do things differently for key types that happen to have a legacy implementation vs for those that don't. If we've got the codepaths to handle provider based keys - why wouldn't we always do that if there is a provider available to do it? |
Yes, this was implemented early. The keys are exported to the provider that is to do the signature work if that provider doesn't match the key's provider (or that the key is legacy). This is among the earliest things we implemented. |
Generally speaking, priorities (we've all enough on our plates as it is). Do operations work with legacy EVP_PKEYs as well as with provider native EVP_PKEYs? In that case, it shouldn't matter whether X509_get_pubkey() one or the other. |
That remains the primary issue - but I don't understand why it is any harder to not just do the same in all cases. Surely this is easier? Why does it behave differently in these cases? |
I'm frankly not sure what you mean with "different" |
|
I've tested the code that @mattcaswell used, and it turns out that the solution here isn't right. I'll have to revisit this |
I knew there had to be a way: openssl/include/openssl/asn1t.h.in Lines 63 to 66 in a2a5506 openssl/include/openssl/asn1t.h.in Lines 609 to 610 in a2a5506 openssl/include/openssl/asn1t.h.in Lines 652 to 660 in a2a5506 Using that form allows a programmatic "take-over" of the processing of an item. X509_NAME is processed this way, and it seems like the solution for our problem here is to do the same for X509_PUBKEY... |
| && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { | ||
| goto next; | ||
|
|
||
| /* We try the typs specific functions first, if available */ |
| if ((dctx = OSSL_DECODER_CTX_new_by_EVP_PKEY(&pkey, | ||
| "DER", "SubjectPublicKeyInfo", | ||
| NULL, EVP_PKEY_PUBLIC_KEY, | ||
| NULL, NULL)) != NULL |
There was a problem hiding this comment.
Why is there no libctx, propq here?
|
|
||
| static int ec_check(void *key, struct der2key_ctx_st *ctx) | ||
| { | ||
| /* We're trying to be clever by comparing two truths */ |
There was a problem hiding this comment.
This comment seems to be a riddle..
There was a problem hiding this comment.
Not much, read the code...
|
I've made this WIP because of the needed rework |
|
I'm closing in favor of a new PR where I've started over |
|
See #13281 |
|
Ah, oops, yes |
When a SubjectPublicKeyInfo (SPKI) is decoded into an X509_PUBKEY
structure, the corresponding EVP_PKEY is automatically added as well.
This used to only support our built-in keytypes, and only in legacy
form.
This is now refactored to try to decode the whole SPKI into an
EVP_PKEY using OSSL_DECODER, and cache that in the X509_PUBKEY very
early. Only when that fails, the existing decoder callback will try
to create a legacy EVP_PKEY.
For purposes where it's not desirable to do the provider side SPKI
decoding, there is now a function d2i_PUBKEY_legacy(). This is used
by all the type specific d2i__PUBKEY(), as well as in out
provider DER->key decoder, to avoid running into recursion problems.
Fixes #13893
This includes refactoring the DER->key decoder to be a bit more flexible with how it uses keytype specific d2i functions and adds the possibility to use d2i_TYPE_PUBKEY.
This also includes the addition of SM2 encoders and decoders...