-
Notifications
You must be signed in to change notification settings - Fork 40
Specify PK for TF-PSA-Crypto 1.0 #203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Specify PK for TF-PSA-Crypto 1.0 #203
Conversation
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good, thanks! I only have a couple of question. The rest is very minor (and some comments are just notes that don't require any kind of action).
docs/architecture/pk-4.md
Outdated
* The poorly defined type `mbedtls_pk_type_t` and the associated function `mbedtls_pk_can_do()`. Use PSA metadata instead. | ||
* Mechanism names: `mbedtls_pk_get_name()`. | ||
* The RSA-oriented length function: `mbedtls_pk_get_len()`. Use `mbedtls_pk_get_bitlen()`. | ||
* PSS-extended functions: `mbedtls_pk_sign_ext()`, `mbedtls_pk_verify_ext()`. PSA has less flexibility than the PK API. Use PSA APIs to get all the flexibility that PSA can have. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider the following scenario: a TLS 1.2/1.3 server has an RSA key that it wants to use for both protocols, which means making either v1.5 signatures (for 1.2) or PSS signatures (for 1.3). I think the way we support it now is with sign_ext()
- nor for the extra fancy PSS settings, just for the ability to say we want PSS.
How is this kind of use case handled in the new PK? Do people need to create two contexts, one for v1.5 one for PSS?
(I don't think mbedtls_pk_set_algorithm()
helps here, because mutating the context every time you want to do a signature would cause all kinds of threading issues.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need two contexts. The idea is that under the hood, this can be a PSA key, and PSA only allows one algorithm family. (Our PSA implementation can support two algorithms, but in the medium term we don't want to assume that this extension is present — even TF-M doesn't expose it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but then we need to document this as a breaking change between 3.x and 4.x/1.x. In 3.x I can parse an RSA key with pk_parse()
, pass it to ssl_conf_own_cert()
and things will just work with TLS 1.2 and 1.3. In 4.x I'll need to create a copy of the context with different permissions and then call ssl_conf_own_cert()
twice. I think that's perfectly OK but ought to be mentioned in the ChangeLog and documented in the migration guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I hadn't really thought this through. I'm at least going to add this to a documentation task.
But now I wonder if we should go further and actually stop using mbedtls_pk_sign_ext
in TLS. (Verify is fine, you can always export public keys). Because otherwise existing users are going to have applications that keep working just fine with 4.0, either because they didn't notice this entry in the migration guide or they didn't think it applied to them since their application kept working. And then it'll break in some 1.x PK refactoring,
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, could not find anything worse than a harmless typo.
* Create an object that wraps the source object. The wrapper object is only valid as long as the source object is valid, and destroying the wrapper object does not affect the source object. Resource management is tricky, but this has a low overhead and works for keys whose material cannot be copied. | ||
* Create an object that aliases the source object: wrap a PSA key in a PK context, or peek at the underlying PSA key of a PK context. The wrapper/underlying object is only valid as long as the source object is valid. A PK context created by wrapping an existing PSA key does not destroy the PSA key. Resource management is tricky, but this has a low overhead and works for keys whose material cannot be copied. | ||
|
||
There is currently no way to access the underlying PSA key of a PK context. A nw function to [access the underlying PSA key of a PK context](#access-the-underlying-psa-key-of-a-pk-context) is not planned for TF-PSA-Crypto 1.0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: nEw
A TLS 1.2+1.3 server with an RSA key needs the key to allow both PKCS#1v1.5 and PSS. The current method is to parse a key and use both algorithms as needed. This won't work in an all-PSA world. Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few questions / clarifications and a smattering of typos, but no big problems with the design as a whole.
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks generally good to me. However, I'm feeling somewhat uncomfortable about this whole set_algorithm()
thing. I'll keep thinking about it.
|
||
An alternative approach is to require copying the key after parsing. This is what we're effectively doing when the application wants to use the key through PSA: it calls `mbedtls_pk_parse_xxx()`, then `mbedtls_pk_import_into_psa()` (after which it can free the intermediate PK object). But what if the application wants to use the key through PK? The current workflow can be: | ||
|
||
* `mbedtls_pk_set_algorithm()` — but as noted above this is not future-proof. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for keys that were just parsed (or more generally, are exportable - or even just copyable) we can make it do an export-import under the hood, so it keeps working when all (private) keys are backed by PSA.
For keys that can't be copied it would fail though. And things that will fail in 1.x should already fail in 1.0. We can achieve that by adding an extra check, or already using the future-proof implementation in 1.0.
Same, the more I sleep on it the more wrong it feels. |
|
||
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204): populate the field `pk->psa_algorithm` when populating `pk`. Use the same approach as the existing function `mbedtls_pk_get_psa_attributes()` for a signature usage. | ||
|
||
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204): implement a new function to change the algorithm associated with a PK context: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having thought about it further, this is definitely wrong. It can't be implemented in a reasonable way on top of a PSA key, since you can't change the PSA key's policy, and having a PK algorithm that doesn't match the policy of the underlying PSA key is pointless.
We need a different solution for the following scenario:
- I parse a key.
- Based on some of the key's metadata, I decide which signature algorithm to use it with.
- I sign with pk.
There is already such a workflow. It's somewhat inefficient, but I think we can live with it.
- Parse the key.
mbedtls_pk_get_psa_attributes()
andmbedtls_pk_import_into_psa()
. This workflow was created precisely to solve this problem.mbedtls_pk_copy_from_psa()
or, to save some resources,mbedtls_pk_wrap_psa()
.
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
Trying to summarize my thoughts. This is mostly redundant with what you've written already, but (re)writing it myself helps me organize my thoughts. I think the public key case is the easiest, so I'll focus on the private key case for now. It seems to me there's two ways a user might want a private RSA key to be used:
Also, there are two ways a user might get their RSA key:
So that's a matrix of 4 cases to consider:
The 4th case is not guaranteed to always work (ie if the key is not exportable), and that's a feature not a bug. Finally, users might either have access to the |
I consider it an optional goal: nice to have, but not a blocker. |
So far the general idea is:
So, it seems to me we have two basic wants: It's easy to express (a) in terms of (b): just copy then destroy the original (though maybe not optimal on resources). It's also easy to express (b) in terms of (a) plus a generic "copy as is" function, but that "copy as is" function is unlikely to be useful for anything else. |
Consider the following scenario: I have a PSA key that allows both v1.5 (primary alg) and PSS (enrolment alg). I create a PK context from it using Should I expect to still be able to do v1.5 signatures with the resulting PK context? It's not clear to me what would be the least surprising here. More generally, I think the fundamental discomfort I have with The only problem with that is that it kind of exposes implementation details: right now, PK is not just a wrapper around PSA, and the plan is that making it a wrapper will be a 4.x thing. I'm almost tempted to suggest making it a wrapper right now (ie, make RSA key storage work the same as ECC key storage currently works (with |
In both TLS and X.509, we want the following control flow: | ||
|
||
1. Parse a certificate, creating a PK context containing a public key. | ||
2. Determine which signature verification algorithm to use. This information does not come from the certiciate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: certiciate
In all the variants that I've considered, PK is explicitly not responsible for enforcing policies. However, since PK is the interface, it unavoidably has some control over expressing policies. For example, given that we don't want to change the parsing interface (because we don't have a good alternative), parsing needs to pick some default policy. And that, in turn, means that there has to be some way of using a different policy. There is already a way through |
What we want to do now (4.0) depends on lot of what we plan to do later (4.x). We don't want to paint ourselves into a corner where we no longer can make the changes we want to do in 4.x without breaking users code. (And as was mentioned in a few other contexts, I think we shouldn't rely just on documentation: things that will break in 4.x should break in 4.0 already.) So, I'd like to discuss what we want to do next, in 4.x, which is move RSA keys from being stored as If at this point, if relying on the "enrolment algorithm" extension is an option, we could make PKparse create RSA keys that are usable with both v1.5 and PSS. This would be the least disruptive compared to current (3.6) behaviour. (PK contexts created by wrapping a PSA key would inherit its policy, as they already to do in 3.6 with Technically I think we could do this, as making TLS/X.509 work with other implementations of PSA crypto is not an official goal until 5.0 (where we're likely to remove PK) - but unofficially perhaps there are people who still want to use PK in a context where the "enrolment alg" extension can't be relied on? If we can't rely on this extension, that means in 4.x (when all PK (private-key) contexts are backed by PSA) then RSA keys suddenly become single-alg. Which means this change should happen in 4.0. Which means either we move that change forward to 4.0, or in the meantime PK has to enforce policies for RSA keys so that code that will break in 4.x breaks in 4.0 already. Wdyt? |
TF-M, last I heard.
That's a good point. So far in the design I've tried to ensure that the new way of doing things will be ok for 4.x, but I haven't added enforcement that “cheating” ways no longer work. I'll think about it.
That is mostly the case with |
Because we're removing this function anyway, right? So there's just So we'll need some changes in You said earlier prototyping wasn't really relevant here because the issue is not to have things work in 4.0 but that they keep working in 4.x. If we add the requirement that things that will fail in 4.x should already fail in 4.0, does this point still stand in your opinion? At this point, I'm under the impression that we're going in the following direction:
I feel like the undecided point so far was mostly the "somehow" above for creating two PK contexts. It seems to me the main contenders are:
It seems to me that this part is really just about user convenience. So I think there are two relatively independent parts to this: A. Whether we want to keep |
Thanks to Manuel for raising this concern. Signed-off-by: Gilles Peskine <[email protected]>
|
||
If the effective capabilities of `mbedtls_ssl_conf_own_cert()` change, we need to be careful not to end up in a situation where: | ||
|
||
1. An application works fine with Mbed TLS 3.6, relying only on documented behavior. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fun (not) game: dive into 3.6 documentation and see if anything says that when you pass the result of pk_parse_key()
(on an RSA) key to mbedtls_ssl_conf_own_cert()
then you'll be able to do handshake signatures with any of v1.5 or PSS as a result. I'm honestly not sure the documentation says anything to that effect (or the opposite).
I'm still strongly inclined to consider that something that shouldn't be broken in 3.6.x, and that should be advertised as a breaking change in 4.0 if we decide to change it, of course. It's just that seeing the wording here made me think, part of our problems every time we touch PK is it's underspecified (and lacks a clear design).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't say it explicitly, but since PK doesn't claim to set a policy on RSA keys, passing a PK object containing a freshly parsed RSA key to a consumer (here SSL) allows that consumer to use both v1.5 and PSS.
Design for
pk.h
in TF-PSA-Crypto 1.0.The design attempts to minimize the amount of work we do before 1.0. A lot of things are left under the carpet. In particular, Mbed TLS library code and tests, as well as sample programs, are allowed to call functions that are now declared as private.
Resolves Mbed-TLS/mbedtls#8452
PR checklist