Skip to content

Relax input restrictions for key derivation #276

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

Conversation

gilles-peskine-arm
Copy link
Collaborator

Key derivation requires a PSA_KEY_TYPE_DERIVE key for a PSA_KEY_DERIVATION_INPUT_SECRET step. This is the common case, but sometimes applications have a buffer in memory which they'll only use for a single key derivation. Sometimes this is even an empty buffer, as when deriving an IV in EAP-TLS. So allow the SECRET to be passed with psa_key_derivation_input_bytes.

Conversely, allow other inputs to be passed as RAW_DATA key objects with psa_key_derivation_input_key.

Fix ARMmbed/psa-crypto#257. Needed to repair the ssl-opt.sh test case export keys functionality which fails when using the latest version of Mbed Crypto (since #257 was merged).

@gilles-peskine-arm gilles-peskine-arm added bug Something isn't working needs: review The pull request is ready for review. This generally means that it has no known issues. labels Sep 23, 2019
switch( step )
{
case PSA_KEY_DERIVATION_INPUT_SECRET:
if( key_type == PSA_KEY_TYPE_DERIVE || key_type == 0 )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does a key type of zero mean? Why not use a define for anything it is?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 is not a valid key type. Here it's used to mean that the input is a direct string rather than a key object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A separate define signalling that (to be used in test data, since it's ambiguous there too) would be useful. If not - at least a comment here and in tests.

Copy link
Collaborator Author

@gilles-peskine-arm gilles-peskine-arm Sep 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: I used PSA_KEY_TYPE_NONE explicitly, both in psa_crypto.c and in the tests.

Copy link
Contributor

@AndrzejKurek AndrzejKurek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clarify the usage of zero as key type.

@yanesca
Copy link
Collaborator

yanesca commented Sep 24, 2019

This solves the problem, but I think it relaxes the API too much and makes it easier to misuse. (Of course whatever we do, a dedicated user can misuse it anyways, but I don't think we should make it any easier than it is necessary.)

This way the user can input any data as secret in a single call, potentially making all the derived keys insecure. (Before they had to import it into a key slot to do so, that should raise an alarm in most people and hopefully make them think twice.)

Performing an operation on a key that was originally intended for non-secret data can potentially leak information about the key. (In this particular case I don't think it does, but this interface should be able to serve legacy and future algorithms too, we shouldn't lay traps like this for them if we don't have to.)

We could avoid this if instead of relaxing the constraints, we added a third variant of TLS PRF for IV generation that does not take a secret input at all and throws an error if psa_key_derivation_output_key() is called on the operation. What do you think?

athoelke pushed a commit to athoelke/mbed-crypto that referenced this pull request Sep 24, 2019
…t-616-fix-ecdsa-rng

Fix deterministic ECDSA RNG misuse
@gilles-peskine-arm
Copy link
Collaborator Author

We could avoid this if instead of relaxing the constraints, we added a third variant of TLS PRF for IV generation that does not take a secret input at all and throws an error if psa_key_derivation_output_key() is called on the operation.

I don't like adding another algorithm. What do we do when the next protocol comes along and does the same with some other KDF?

On the other hand, I do like the idea of forbidding psa_key_derivation_output_key() if the SECRET input isn't a key. Do you think that's enough?

@gilles-peskine-arm gilles-peskine-arm added needs: work The pull request needs rework before it can be merged. and removed needs: review The pull request is ready for review. This generally means that it has no known issues. labels Sep 24, 2019
@athoelke
Copy link
Contributor

On the other hand, I do like the idea of forbidding psa_key_derivation_output_key() if the SECRET input isn't a key. Do you think that's enough?

It's definitely cute, and makes some conceptual sense: "don't permit secret outputs if there were no secret inputs".

If the caller really wants to us the output as a key they then have to import the output bytes as a key - which probably alerts a reviewer to check what is happening in that code.

If the caller wants to deterministically generate a key from a non-secret input, then (as currently) they have to import the non-secret to a key-derivation key first. Which also triggers a reviewer to inspect the application behaviour.

@yanesca
Copy link
Collaborator

yanesca commented Sep 24, 2019

On the other hand, I do like the idea of forbidding psa_key_derivation_output_key() if the SECRET input isn't a key. Do you think that's enough?

Yes, I think it should be enough to make allowing non-key SECRET inputs safer.

On the other hand I still feel uncomfortable about allowing keys as a non-SECRET input. This relaxation is not necessary for the current fix, can't we just keep the restriction and hope that eventually we won't need to lift it?

@gilles-peskine-arm
Copy link
Collaborator Author

Label-type inputs have to be RAW_DATA, not DERIVE. It makes sense to me to allow RAW_DATA for a label or info (a personalization string kept in persistent storage), or for a salt or seed (a device-specific value that may or may not be secret and is kept in persistent storage). @yanesca What makes you uncomfortable? The risk that an application will pass the wrong key (which would have to be of the wrong type)?

@yanesca
Copy link
Collaborator

yanesca commented Sep 24, 2019

I am imagining here a RAW_DATA that is supposed to be secret and a key derivation algorithm that leaks information about for example the label. (Yes, such a key derivation algorithm is not safe in the first place.)

I admit that what I am afraid of is highly hypothetical, I just thought if we can avoid it then why not?

@gilles-peskine-arm
Copy link
Collaborator Author

It wouldn't necessarily be bad for a KDF to leak the “label”, although I can't think of a common construction that comes anywhere near it.

RAW_DATA is often not supposed to be kept secret anyway. A common use case is to store a certificate next to the corresponding private key.

A RAW_DATA does need to have the DERIVE usage flag to be used as a label (etc) in a key derivation.

@yanesca
Copy link
Collaborator

yanesca commented Sep 24, 2019

In that case I think it is enough to constrain the secret outputs as discussed above.

@gilles-peskine-arm gilles-peskine-arm added needs: review The pull request is ready for review. This generally means that it has no known issues. needs: work The pull request needs rework before it can be merged. and removed needs: work The pull request needs rework before it can be merged. needs: review The pull request is ready for review. This generally means that it has no known issues. labels Sep 24, 2019
@gilles-peskine-arm
Copy link
Collaborator Author

I implemented the constraint on output_key.

And now I need to resolve a merge conflict. I'm afraid I'm going to need to rebase this. The current state is in https://github.com/gilles-peskine-arm/mbed-crypto/tree/psa-key_derivation-relax_inputs-2.

Systematically use "PSA key derivation setup" for derive_setup. This
resolves the ambiguity between derive_setup and derive_input calls.
This commit only makes derive_input more flexible so that the key
derivation API can be tested with different key types and raw data for
each input step. The behavior of the test cases remains the same.
Allow a direct input as the SECRET input step in a key derivation, in
addition to allowing DERIVE keys. This makes it easier for
applications to run a key derivation where the "secret" input is
obtained from somewhere else. This makes it possible for the "secret"
input to be empty (keys cannot be empty), which some protocols do (for
example the IV derivation in EAP-TLS).

Conversely, allow a RAW_DATA key as the INFO/LABEL/SALT/SEED input to a key
derivation, in addition to allowing direct inputs. This doesn't
improve security, but removes a step when a personalization parameter
is stored in the key store, and allows this personalization parameter
to remain opaque.

Add test cases that explore step/key-type-and-keyhood combinations.
This is valid C99 (since the variable in question is not a VLA and is
not used) but not accepted by IAR 8.20.
No behavior change, just a readability improvement.
Update the documentation of psa_key_derivation_input_key() and
psa_key_derivation_input_bytes() now that the key/buffer distinction
is not mandatory.
After passing some inputs, try getting one byte of output, just to
check that this succeeds (for a valid sequence of inputs) or fails
with BAD_STATE (for an invalid sequence of inputs). Either output a
1-byte key or a 1-byte buffer depending on the test data.

The test data was expanded as follows:
* Output key type (or not a key): same as the SECRET input if success
  is expected, otherwise NONE.
* Expected status: PSA_SUCCESS after valid inputs, BAD_STATE after any
  invalid input.
If none of the inputs to a key derivation is a
PSA_KEY_DERIVATION_INPUT_SECRET passed with
psa_key_derivation_input_key(), forbid
psa_key_derivation_output_key(). It usually doesn't make sense to
derive a key object if the secret isn't itself a proper key.
@gilles-peskine-arm gilles-peskine-arm force-pushed the psa-key_derivation-relax_inputs branch from 2cda070 to 178c9aa Compare September 24, 2019 16:44
@gilles-peskine-arm
Copy link
Collaborator Author

I rebased on top of development plus one new commit 6ddb4d8 "Improve descriptions of derive test cases". Thanks to that commit, there were no conflicts.

@gilles-peskine-arm gilles-peskine-arm added needs: review The pull request is ready for review. This generally means that it has no known issues. and removed needs: work The pull request needs rework before it can be merged. labels Sep 24, 2019
@@ -255,6 +255,7 @@ typedef struct psa_tls12_prf_key_derivation_s
struct psa_key_derivation_s
{
psa_algorithm_t alg;
unsigned int can_output_key : 1;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leaves 31 bits unused. #281

@yanesca
Copy link
Collaborator

yanesca commented Sep 26, 2019

The CI fails only on the ABI check and the known export key issue.

Copy link
Collaborator

@yanesca yanesca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@athoelke
Copy link
Contributor

I'm happy with the documentation improvements. 👍

@gilles-peskine-arm gilles-peskine-arm removed the needs: review The pull request is ready for review. This generally means that it has no known issues. label Sep 26, 2019
@gilles-peskine-arm gilles-peskine-arm merged commit 37b5c83 into ARMmbed:development Sep 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants