-
Notifications
You must be signed in to change notification settings - Fork 27
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
Import and export of non-default key formats #207
base: main
Are you sure you want to change the base?
Conversation
Still flip-flopping on the best way to handle public key export:
|
Second draft following discussion with @gilles-peskine-arm:
I still need to:
And then it will be:
|
862d06a
to
d79e4e9
Compare
Now with a first pass at fully defining This was a mostly cut and paste of the
|
doc/crypto/api/keys/management.rst
Outdated
|
||
The following attributes must be set for keys used in cryptographic operations: | ||
|
||
* The key permitted-algorithm policy, see :secref:`permitted-algorithms`. |
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.
Blocker in the API design: when I'm loading a key which may be of several types, with a format that doesn't contain (enough) policy information, the desired algorithm policy will depend on the type. A typical example: my application can sign with either RSA-PKCS#1v1.5 or ECDSA. I want to set the algorithm policy to PSA_ALG_RSA_PKCS1V15_SIGN_ANY
if the key turns out to be an RSA key, and to PSA_ALG_ECDSA_ANY
if it turns out to be an ECC key.
In the Mbed TLS 3.x equivalent to this interface (pk API), where we were extending the legacy interface to bridge it with PSA, I resolved this by making it a three-step process:
- Parse the key. This creates a legacy object which has type information, but no binding policy information.
- Construct attributes, including a policy, based on the key type. There's a helper function that handles the common cases, but the application can tweak the result or just make up its own attributes.
- Import the key into PSA, with the policy and other attributes chosen at the previous step.
This only works because there's an intermediate stage with a key that is loaded and has type information but does not yet have a policy set. I'd rather avoid having to have this intermediate stage in the PSA API.
I'm currently working on the evolution of Mbed TLS pk API for the next major version, which will be a transition API (keeping old function names, but wrapping around PSA keys). I don't have a satisfactory solution yet in that context either.
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.
The obvious way is to encode, either in the format
argument or in a separate argument, the mapping for “if the loaded key has that type then use this policy”. But that gets pretty hairy.
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.
It does get messy if we want to encode some form of conditional policy logic in a parameter to enable something like "if EC key then permit ECDSA, else if RSA then permit RSA-PSS, else if ....". How far should such flexibility extend?
I can envisage an API that parsed the key data to be able to report the attributes of the key that is encoded in the data, but without creating a key object. The application can then use or amend the reported key attributes before actually importing the key. If the application does not need this flexibility, it can just import the key. The overhead of this approach is parsing the key data twice, which is perhaps particularly an issue for wrapped/encrypted formats.
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.
In a scenario where the key format provides enough information, and the application is prepared to delegate the policy setting to the key data, do we need a permitted algorithm and usage flag value that explicitly indicates this?
For example, if the application sets all the available usage flags - then a strict "intersection with the policy in the key data" would have this effect, but what should the final key policy be if the key data has no explicitly specified policy? (presumably not 'can do anything')
Similarly, we probably want to have different ways to differeniate "no algorithm is permitted" from "I am not specifying a permitted algorithm - use the use one encoded in the AlgorithmIdentifier in the key data".
I've added a first attempt at fully defining This also updates the description of the non-formatted existing API, acknowledging the existence of non-default formats. |
ddfed12
to
555b2d1
Compare
* Decided to do public key export via a dedicated function * Removed ECPoint as a format * Required public keys in key pair formats * Added options for domain parameters * Individual boolean options override defaults instead of providing both option elements * Added references for everything * Defined new terms for ASN.1, DER and PEM
* Open issue regarding handling of encoded policy in key data
555b2d1
to
f7501a2
Compare
Further thoughts since my return from vacation... I think the best way to handle key policy information that may or may not be present in the formatted key data, is to provide an additional parameter to
Would there be a good case for "4. Use the key attribute policy, ignoring any imported policy"? This seems risky as it is discounting any constraints that are present in the imported key? (1) is the theoretically ideal option (as per This approach does not handle the usage flags that are related to permitted key management operations: I am also not sure if we would want to enable independent option 1/2/3 approaches for the permitted algorithm and the usage flags elements of the policy. |
I think this is my preferred approach for handling the use cases described by @gilles-peskine-arm:
This API might look something like:
Alternative names for The application can call I suspect we would want the reported attributes distinguish between an "unknown policy" (algorithm and/or usage flags not provided in import data - in effect this is probably 'anything permitted'), and a "nothing permitted policy"? [An alternative could be to provide no standard API for such a use case, and have an implementation define their own custom key-import-policy option that carries out the specific behavior for every such use case. This is problematic if there are standard protocols that would depend on this use cases, or many different scenarios (with different specific key types and algorithms) in which this is needed.] |
(1) can be achieved by doing (2) followed by The problem with “key attribute policies” is that they require a more complex policy language. It is common to want a “policy policy” like “set the algorithm to RSA-PSS if the key is RSA, to ECDSA if the key is ECC-Weierstrass, and to EdDSA if the key is ECC-Edwards”.
This fails in the common case of formats that lack policy information, or only have partial policy information.
I don't know. Key formats don't always fully match what one needs to do with the key. Though if it's rare enough, there's always the possibility of doing an import with the EXPORT usage flag and then a manual copy.
I'm not very keen on parsing the data twice, and applying credentials twice, but I don't have a better idea.
There are indeed many scenarios where a protocol can work with either RSA/FFDH or ECDSA/ECDH, and will soon be extended with PQC alternatives. A library for this protocol should provide a “load key” function that decides which algorithm to use for each key type (e.g. whether to use PKCS#1v1.5 or PSS for RSA). For agility and performance, this should not require too much complexity in the library. In particular I want to avoid the simplistic algorithm “try parsing as RSA, if it fails try parsing as ECC/ECDSA, if it fails try parsing as ECC/EdDSA, …”. |
The desire for agility - being able to migrate an application to supporting an alternative, or an additional, key/signature type without code changes - is an argument against a simple two-function inspect/import approach, as this requires conditional logic in the application code. And perhaps using a data-driven approach to these use cases might be better, without defining a complex policy-configuration-code scheme. Can we articulate the forms of policy logic that are required, in order to define a manageable data structure to express and encode what is wanted? For example, we could define a key policy configuration as an array of |
Let's make a start by encoding all four options and see how this looks. I suggest separating the options relating to permitted-algorithm from the cryptographic-usage flags (as some formats always have one, but may or may not include the other), but not providing an option related to the key-store management flags (copy/export/cache):
Questions
|
[Edited: initially submitted before complete]
It seems that this could be a workable approach, though discussion on the design of the API is needed. For other data structures in the API, the implementation is free to design the detailed layout to match its requirements - for example, Some possible approaches:
|
Based on the discuss in #149, here is a stab at defining the tricky part of the API: the key data format specifiers and key data format options.
As per usual, it is flushing out some details that are worth discussing, so this is an early DRAFT, to enable that discussion. See the TODOs in the changes for specific details.