Skip to content
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

Change the PAKE output function to return a key #114

Merged
merged 10 commits into from
Nov 29, 2023

Conversation

athoelke
Copy link
Contributor

@athoelke athoelke commented Oct 30, 2023

  • Replace psa_pake_get_implicit_key() with psa_pake_get_shared_key()
  • Add key confirmation attribute to the PAKE cipher suite

Fixes #100
Fixes #86

@athoelke athoelke added enhancement New feature or request Crypto API Issue or PR related to the Cryptography API DO NOT MERGE labels Oct 30, 2023
@athoelke
Copy link
Contributor Author

Some feedback would be very welcome from @silabs-Kusumit, @silabs-hannes, @oberon-sk, and @yanesca; given your involvement in the PAKE API development.

@athoelke athoelke self-assigned this Oct 30, 2023
@oberon-sk
Copy link

  • Replace psa_pake_get_implicit_key() with psa_pake_get_shared_key()
  • Add key confirmation attribute to the PAKE cipher suite

lgtm

  1. Should the entire secret be contained in a single key output, or can it be split across multiple output keys?

As far as we understand, the goal of this PR is to export a shared secret and defer any key derivation of one or multiple keys into subsequent calls independent from the PAKE APIs. Then, the entire secret needs to be exported.

  1. Which position should the key attributes parameter take in psa_pake_get_shared_key()? - there is no ideal answer as the precedents in the API are not consistent.

The operation should always be the first parameter, we regard psa_key_derivation_output_key() as an outlier.

@athoelke
Copy link
Contributor Author

  • Replace psa_pake_get_implicit_key() with psa_pake_get_shared_key()
  • Add key confirmation attribute to the PAKE cipher suite

lgtm

Thank you for your review

  1. Should the entire secret be contained in a single key output, or can it be split across multiple output keys?

As far as we understand, the goal of this PR is to export a shared secret and defer any key derivation of one or multiple keys into subsequent calls independent from the PAKE APIs. Then, the entire secret needs to be exported.

The concern is whether there are protocols, or PAKEs that expect the output to be split into two or more pieces as keys. For example, the way that SPAKE2+-draft02 splits the output of Hash(TT) into Ka and Ke. Note that is not a use case we need to support, and Matter's use of SPAKE2+ only uses the entire confirmed PAKE output as a key derivation key.

  1. Which position should the key attributes parameter take in psa_pake_get_shared_key()? - there is no ideal answer as the precedents in the API are not consistent.

The operation should always be the first parameter, we regard psa_key_derivation_output_key() as an outlier.

We have come to the same conclusion.

@oberon-sk
Copy link

The concern is whether there are protocols, or PAKEs that expect the output to be split into two or more pieces as keys. For example, the way that SPAKE2+-draft02 splits the output of Hash(TT) into Ka and Ke. Note that is not a use case we need to support, and Matter's use of SPAKE2+ only uses the entire confirmed PAKE output as a key derivation key.

We are not aware of a use case where this would be required either.

@athoelke
Copy link
Contributor Author

  1. What key types should we permit or deny? - it seems that this is not appropriate for extracting keys that can require a variable amount of keying material (e.g. any DES, FFDH key pairs, Weierstrass ECC key pairs, RSA key pairs)

We would like to make this 'derivation keys only' (similar to the psa_key_agreement() PR #101), but need confidence that there are no use cases where the output is used directly for encryption, key wrapping (might need block-cipher-key), or AES-CMAC-based key derivation (would need an AES key).

  1. Should the default key confirmation be: 'unconfirmed', 'confirmed', or 'whatever the default is for the selected algorithm'?

Currently leaning towards a preference of 'confirmed' by default (following a 'secure by default' principle), which means that algorithms like J-PAKE, without a confirmation phase, would require the application to explicitly request an unconfirmed key.

@athoelke athoelke mentioned this pull request Oct 31, 2023
8 tasks
@athoelke
Copy link
Contributor Author

Added a missing update to the J-PAKE graphic, and reversed the definition of the key confirmation constants, so PSA_PAKE_CONFIRMED_KEY is now the default.

A PAKE algorithm uses a specific cryptographic primitive for key establishment, specified using a `PAKE primitive <pake-primitive>`. PAKE algorithms also require a cryptographic hash algorithm, which is agreed between the participants.
Most PAKE algorithms have parameters that must be specified by the application. These parameters include:

* The cryptographic primitive used for for key establishment, specified using a `PAKE primitive <pake-primitive>`.

Choose a reason for hiding this comment

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

Typo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, I can't seem to see the problem. What am I missing?

Choose a reason for hiding this comment

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

The cryptographic primitive used for for key establishment

Small thing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! The hardest to see error in things you have written yourself....

@silabs-Kusumit
Copy link

  1. Should the entire secret be contained in a single key output, or can it be split across multiple output keys?

If the key type of the output will be derivation only then multiple output keys are not needed.

Added a missing update to the J-PAKE graphic, and reversed the definition of the key confirmation constants, so PSA_PAKE_CONFIRMED_KEY is now the default.

lgtm

2. Related to (1): Do we need to provide something that evaluates the size of the shared key output?

If we are returning only a single output key then this may not be needed.

@athoelke
Copy link
Contributor Author

athoelke commented Nov 1, 2023

  1. What key types should we permit or deny? - it seems that this is not appropriate for extracting keys that can require a variable amount of keying material (e.g. any DES, FFDH key pairs, Weierstrass ECC key pairs, RSA key pairs)

Even if we expect that the output should be for derivation only: we should permit implementations to output AES keys (as long as they use all of the shared secret?), as we expect some implementations will provide AES-CMAC based KDFs (see #106).

psa_key_derivation_operation_t *output);
psa_status_t psa_pake_get_shared_key(psa_pake_operation_t *operation,
const psa_key_attributes_t * attributes,
psa_key_id_t * key);
Copy link
Contributor

Choose a reason for hiding this comment

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

The situation here is very similar to the case of key agreement schemes. There we have two APIs: psa_raw_key_agreement() and psa_key_derivation_key_agreement(). Outputing a key derivation object achieves the same as the latter. Outputing a key instead is somewhere between the two: the Crypto API implementation doesn't have full control over the use of the output, but doesn't release the output to the user either.

Outputting a key derivation object has the advantage that the implementation knows about the PAKE when inputting the key to the derivation object and can prevent misuse better or even adjust serialisation format if needed. If the PAKE output is released as a key, the only information the implementation can rely on is the length.

Why do we need to switch to outputting a key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do we need to switch to outputting a key?

See #86. Use cases that use separate derivations to create multiple keys from the output of the PAKE. The existing API cannot be used in such systems, and maintaining the existing API alongside a new one to return a key does not appear to deliver substantial benefit for the application or implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The situation here is very similar to the case of key agreement schemes. There we have two APIs: psa_raw_key_agreement() and psa_key_derivation_key_agreement().

But see also the recent discussions: #85 and #101. One of the conclusions there is that with more time and review when v1.0 was published, psa_key_agreement() would probably be the only key agreement interface, enabling access (via export) to the raw material, but defaulting to keeping the output protected, for use in one (or more) KDF operations. This would also have reduced the algorithm identifier complexity created by combined key agreement and key derivation algorithms.

@yanesca
Copy link
Contributor

yanesca commented Nov 10, 2023

Even if we expect that the output should be for derivation only: we should permit implementations to output AES keys (as long as they use all of the shared secret?), as we expect some implementations will provide AES-CMAC based KDFs (see #106).

I think we should permit implementations to output any type of key that we might need for key derivation. If I understand the proposal in #106 correctly, this would mean PSA_KEY_TYPE_DERIVE, PSA_KEY_TYPE_HMAC, PSA_KEY_TYPE_AES and for the last two the key policy would be set to PSA_ALG_SP800_108_COUNTER_HMAC and PSA_ALG_SP800_108_COUNTER_CMAC respectively.

@yanesca
Copy link
Contributor

yanesca commented Nov 10, 2023

Should the entire secret be contained in a single key output, or can it be split across multiple output keys?

I think most of the PAKEs arrive at one shared secret and the output should be a single key. If a higher level protocol splits that before deriving keys, the partitioning of the key material should be part of the key derivation algorithm. For PAKEs that output several keys (like OPAQUE) we should either add a new API or require the application to call the key output function once more (and define which call produces which key), but we shouldn't output a concatenated key.

Related to (1): Do we need to provide something that evaluates the size of the shared key output?

If we put the output in a key, the caller doesn't need to know the size upfront and can get it from the key attributes later, so I don't think we need to provide anything extra here.

@athoelke
Copy link
Contributor Author

I think most of the PAKEs arrive at one shared secret and the output should be a single key. If a higher level protocol splits that before deriving keys, the partitioning of the key material should be part of the key derivation algorithm.

That is also my opinion, all other things considered.

For PAKEs that output several keys (like OPAQUE) we should either add a new API or require the application to call the key output function once more (and define which call produces which key), but we shouldn't output a concatenated key.

If I understand you correctly, you suggest that for algorithms like OPAQUE, we might decide that the application must call psa_pake_get_shared_key() twice. However, the application does not control how the output is split between those two calls: that is a product of the algorithm itself; in contrast to the idea in (1) where the application could control the splitting of the PAKE output into multiple key objects.

@athoelke
Copy link
Contributor Author

Rebased (following merge of #115), and updated the specification of key types that psa_pake_get_shared_key() can output (see 9d4f2c0).

Some PAKEs (e.g. J-PAKE) produce biased output, that is not suitable for use as an encryption key. Therefore:

* The key type is required.
All PAKE algorithms can output a key of type :code:`PSA_KEY_TYPE_DERIVE` or :code:`PSA_KEY_TYPE_HMAC`.
PAKE algorithms that produce a pseudo-random shared secret, can also output block-cipher key types, for example :code:`PSA_KEY_TYPE_AES`.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this empty line intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case, I think not, it was probably an artefact of cut and pasting the text below the blank line.

Copy link
Contributor

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

LGTM.

@silabs-Kusumit
Copy link

LGTM

* Replace psa_pake_get_implicit_key() with psa_pake_get_shared_key()
* Add key confirmation attribute to the PAKE cipher suite
* The shared secret is always output as a single key
* Removed the input key size, key size is determined by operation
* Removed key-size helper macro as unnecessary
* Recognise that not all PAKE algorithms produce a secret that is suitable for use as an encryption key
* Encourage the use of PAKE output as a key-derivation key
@athoelke
Copy link
Contributor Author

Rebased and merged.

@athoelke athoelke merged commit 80ea731 into ARM-software:main Nov 29, 2023
@athoelke athoelke deleted the pake-get-shared-key branch November 29, 2023 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Crypto API Issue or PR related to the Cryptography API enhancement New feature or request
Projects
4 participants