Draft : SPAKE2PLUS protocol flow proposal#73
Draft : SPAKE2PLUS protocol flow proposal#73silabs-Kusumit wants to merge 4 commits intoARM-software:mainfrom
Conversation
Signed-off-by: Kusumit Ghoderao <Kusumit.Ghoder@silabs.com>
|
I'm trying to consider ways to handle the post-registration secrets for the API. The way that So, would it make any sense to:
Either:
It doesn't seem necessary to parameterize both the key type and the KDF, as these keys cannot be generated, they are always derived. |
Thinking a bit out loud.. Having specific key types for these SPAKE2+ secrets sounds like a good thing to me. It feels like any other choice would make it a bit awkward to implement. If I understand correctly, the new KDF algorithm for SPAKE2+ would only perform modulo computations and potentially a group multiplication. The output also wouldn't be usable directly as a symmetric key like you might expect the output of the KDF APIs to be. It feels a bit wrong to include this functionality under the KDF algorithm family. Performing the registration computation purely using the KDF APIs also mean that the user must provide some values as concatenated inputs into the PBKDF, and then later provide the same values in a more structured manner to the PAKE APIs (i.e. user IDs). The use of the password as a regular data input also doesn't really fit into how PSA Crypto wants you to treats secrets. The sheer amount of function calls that will be needed in order to put the registration together with the actual interactive key agreement is quite significant. The computational overhead would at least probably be small compared to the time it takes to run the PBKDF part. All this being said, I can't think of a good alternative that isn't duplicating a large part of the KDF API as part of the PAKE API. Maybe maybe it's possible to come up with some 'registration ciphersuite encoding' that supports some suggested methods to compute |
| * `psa_pake_set_user()` to input ProverID | ||
| * `psa_pake_set_peer()` to input VerifierID | ||
| * `psa_pake_set_role()` to set role as client/server | ||
| * `psa_pake_input()` with *(new)* `PSA_PAKE_STEP_ADDITIONAL_DATA` step to input context (additional data). |
There was a problem hiding this comment.
Continuing the old PR thread.
I also wondered why we weren't using psa_pake_input(), but Saketh's answer convinced me that a new API could make sense. The current set of elements input to/output from psa_pake_input()/psa_pake_output() all come from the interactive part of the protocol -- i.e. the output from one is the input to the other. The context doesn't fit as well into that current set of steps.
There was a problem hiding this comment.
The context input is a part of the setup for the SPAKE2+ operation. Therefore I have added psa_pake_set_context() for adding the context data to the PAKE operation.
|
|
||
| Computing these values is considered Out of Scope for PAKE API as this a registration phase which could happen out of actual protocol flow. | ||
|
|
||
| Since W0 & W1 and L serve as registartion records and verification value, these values can be treated as secrets. |
There was a problem hiding this comment.
Continuation of the old PR thread (and a bit of this comment as well).
I checked with the Matter protocol, and there a commissionee (verifier) should get (w0, L) installed at manufacturing time. When that device is later commissioned to a network, the password is communicated to the commissioner (the prover) OOB. The commissioner computes (w0, w1), and moves on with the rest of the protocol. This process will only happen a single time for that device, so there is no need to store the intermediate result (w0, w1) to the key store.
It also makes sense to me to have a client be able to compute and communicate (w0, L) instead of the password (yay augmented PAKE!).
So I agree that it would be best if it is possible to optionally input the password instead of the values derived using it. It would also be nice if you didn't have to import the password before usage, similar to psa_key_derivation_input_bytes().
There was a problem hiding this comment.
So I agree that it would be best if it is possible to optionally input the password instead of the values derived using it. It would also be nice if you didn't have to import the password before usage, similar to
psa_key_derivation_input_bytes().
At the moment, when a secret input is provided to a KDF via psa_key_derivation_input_bytes(), this prevents the application using psa_key_derivation_output_key(). See the documentation for PSA_KEY_DERIVATION_INPUT_SECRET, PSA_KEY_DERIVATION_INPUT_PASSWORD, and psa_key_derivation_output_key().
If we provide a high-level function, such as psa_pake_registration(), that outputs a key that can be stored in the key-store, then it might be appropriate to permit a non-key input of the password, because storing a SPAKE2+ password in the keystore is not required, and not recommended. However, I am not sure we should relax the 'secret key input for secret key output' requirement that the PAKE or key derivation operations currently have.
There was a problem hiding this comment.
In practice, a concrete PBKDF is required, with specific input parameters (for both the construction of the input keying material, the salt and any iteration count), and a specific length for the
w0s||w1soutput string.Matter does define exactly how this part of the protocol must run, including the absence of identity-strings, and how the PBKDF2 parameters are shared and included in the transcript context.
If we define a higher-level API, such as
psa_pake_registration(), that matches the Matter requirements, does this become a Matter-specific API? - or do we add enough parameters to support other application uses that do have identities, and generate different lengths of intermediatew0s||w1soutput?
and
At the moment, when a secret input is provided to a KDF via
psa_key_derivation_input_bytes(), this prevents the application usingpsa_key_derivation_output_key()
I have defined the psa_pake_registration() to take as input a PBKDF operation and output key attributes. The PBKDF operation will be initialized OOB and can accept a non-key password as input. We can import the non-key output of the KDF with attributes provided as input and store the key id in the PAKE operation.
I agree that this will be helpful for the implementation. |
Adding on to @silabs-hannes comment, I think that we can add a new API Since the registration can happen much before the actual protocol is executed, I think that we should not include the |
|
[Apologies for the delay in responding, but now back from a work conference ...] Thanks for the feedback on the key-pair idea, this does seem to be a valid approach for SPAKE2+. I said:
After some further thinking about it, parameterizing the key type (option 1) makes the most sense, and also fist well with the idea of providing a higher level registration function to derive the private and public keys from the passcode. |
and then...
My initial thoughts of providing just a low-level building block (a KDF to convert
In practice, a concrete PBKDF is required, with specific input parameters (for both the construction of the input keying material, the salt and any iteration count), and a specific length for the Matter does define exactly how this part of the protocol must run, including the absence of identity-strings, and how the PBKDF2 parameters are shared and included in the transcript context. If we define a higher-level API, such as API element namesShould we name the API elements (algorithms in particular) using Or qualify the name using a suffix such as Or just make this version of the API sufficient for Matter only (as that is the primary use case), and use The best answer partly depends on whether we try to make the API more flexible for other uses of SPAKE2+, or more specific to the Matter application usage. |
| 2. `W0||L` as secret key on Verifier side. | ||
| 2. Rename `psa_pake_set_password_key()` as `psa_pake_input_key()` to input mutiple secret keys and define steps for different keys | ||
| 1. For W0 and W1 on Prover side | ||
| 2. For W0 and L on Verifier side |
There was a problem hiding this comment.
Please be careful here. A key is needed for driver dispatch. Connecting PAKE to a driver is already a complex task (see discussion here: Mbed-TLS/mbedtls#7445). If you add several variants with multiple keys driver dispatch may become impossible to handle.
For the same reason it would be advantageous to have a clean sequence of calls:
psa_pake_setuppsa_pake_set_role/psa_pake_set_user/psa_pake_set_peerpsa_pake_set_password_keypsa_pake_input/psa_pake_output
|
|
||
| Expected PAKE API Flow : | ||
| ------------------------------------ | ||
|  |
There was a problem hiding this comment.
Handling Y (= shareV) and cB (= confirmP) in two separate input/output passes with different step types (PSA_PAKE_STEP_KEY_SHARE and PSA_PAKE_STEP_CONFIRM) would be cleaner and simplify usage in cases where the two are transferred in separate protocol elements. Packing them together in a single package is still straight forward by calling both inputs or outputs immediately after each other.
There was a problem hiding this comment.
Handling Y (= shareV) and cB (= confirmP) in two separate input/output passes with different step types (
PSA_PAKE_STEP_KEY_SHAREandPSA_PAKE_STEP_CONFIRM) would be cleaner and simplify usage in cases where the two are transferred in separate protocol elements. Packing them together in a single package is still straight forward by calling both inputs or outputs immediately after each other.
Agreed. I think this diagram copies the style of the J-PAKE sequence diagram - which does not explicitly show every call to psa_pake_input() or psa_pake_output() when multiple parameters are input or output from the operation.
But the associated text should specify that these values are input and output individually, and describe any ordering requirements.
There was a problem hiding this comment.
I will update the flow description to include this
There was a problem hiding this comment.
I have added an example Matter implementation which demonstrates the flow of the PAKE API.
|
While comparing draft-2 and draft-8 for SPAKE2+, I've also noticed that neither the Matter specification, nor the draft-2 for SPAKE2+ specify the length of the confirmation keys Matter does specify that the final confirmation values are computed using HMAC-SHA256, with keys Draft-8 of SPAKE2+ (not referenced by Matter) adds requirements and recommendations for the confirmation key sizes: in the case of HMAC, it recommends a confirmation key size equal to the output of the hash function. Unless there is clarification elsewhere, this seems a reasonable GUESS as to what Matter implementations are expected to do? |
|
I've picked up previously raised issues with the PAKE API (#86 #87 #88 #89), and in response to #86 (and the related concern with the key derivation API #85) have proposed an API to extract the shared secret from the PAKE operation as a derivation key object. With an API like that, it might be possible to propose a different approach to SPAKE2+ (see #73), where the PAKE operation finishes with the output of K_main as the shared secret. The caller is able to implement the key schedule and confirmation process without any further use of the group operations or other secret data - the data used to generate the confirmation values are the key shares that are sent in the initial SPAKE2+ messages. As the primary differences between draft 2 and draft 8 of SPAKE2+ are in the key schedule, this would also move the SPAKE2+ version issue into the application space, and outside of the PAKE operation implementation. |
Reviewing the draft08 and draft02 for SPAKE2+ shows that this is not adequate. Draft02 splits the transcript hash, called K_main in draft08, into two keys, Ka and Ke. So we would need to be able to extract the shared secret from SPAKE2+ sequentially into multiple keys, in a similar way to being able to output multiple keys from a key derivation operation. So for Matter-v1/SPAKE2+-draft02 we would want to be able to do something like this: |
Signed-off-by: Kusumit Ghoderao <Kusumit.Ghoder@silabs.com>
Signed-off-by: Kusumit Ghoderao <Kusumit.Ghoder@silabs.com>
I have added the key pair description to the proposal. |
|
I had a slightly different idea in mind for the flow from the PBKDF through the SPAKE2+ key pair and into the pake operation. In particular I wanted to separate the registration flow from the pake operation flow. It seems that are several use case flows with an augmented PAKE, that justify defining a specific key type for SPAKE2+ in the API. For example:
In use case (2), we shouldn't store the passcode in the Verifier, when we can store the derived w0||L 'verifier key' instead, from which it is not possible to reasonably determine the passcode. In use case (3), the Verifier never has access to the passcode, and only ever handles the verifier key. To enable those use cases, we need an API that exposes the verifier key. An API that just transfers the PBKDF2 output into a PAKE operation is not sufficient. Defining w0||w1 and w0||L as a key pair, with the obvious key-pair to public-key and public-key export and import operations fits these use cases well. (In the key store, the key-pair could be stored as w0||w1, as L can be computed from w1.) So assume we will define a key pair for SPAKE2+, perhaps: These do need some parameterization (e.g. on the ECC curve?)? Or use the pake_primitive as the input to the KEY_PAIR/PUBLIC_KEY macros for consistency with other parts of PAKE? I think that the parameterization of the key type is necessary as the export format for a SPAKE2+ public key depends on the pake primitive. We will need some APIs to support the Spake2P_derive_public_key() and Spake2P_derive_key_pair() operations that output keys. This operation needs some bytes from the PBKDF (the number depends on the PAKE algorithm and chosen cipher-suite), and generates an appropriate key for use with the pake operation. There are various options for how we present this in the API:
In keeping with the style of the PSA Crypto API, I am inclined to go with (1), and use The PAKE operation already has a suitable API for inputing the prover or verifier key, A remaining question is whether there is value in simplifying the application code when passcode derivation is done at the same time as the PAKE protocol - by retaining the ability to transfer the pbkdf2 output directly into the PAKE, and avoiding the creation and destruction of a temporary key. |
Although I like the fact that this approach manages to avoid the draft02 vs draft02-as-used-in-Matter vs draft08 concerns, the result leaves a lot of work to the application code. I am not entirely happy with this, so I think the proposed approach with output and input of confirmation values followed by extraction of the explicit/confirmed key is better. In this case we do have a algorithm version issue, due to the differences in the confirmation protocol, and the optionality in the original draft02 specification. To address this, I think we need to define two algorithm values (although the key types can be shared):
As for all other algorithms, an implementation can support neither, either, or both of these algorithms. I do not think it is necessary, or useful to define a |
athoelke
left a comment
There was a problem hiding this comment.
I've posted some more detailed thoughts on the key types and the API design to separate the registration and exchange flows.
| ### Registration | ||
|
|
||
| Computing these values is considered Out of Scope for PAKE API as this a registration phase which could happen out of actual protocol flow. | ||
| Propose a new API `psa_pake_registration()` which will take as input: |
There was a problem hiding this comment.
See my longer comment in the conversation here.
I think this functionality should be provided with psa_key_derivation_output_key() when a SPAKE2+ key type is requested, followed by a call to psa_pake_set_password_key() to input that key into the pake protocol operation.
There was a problem hiding this comment.
I will update the proposal to include this suggestion and also update the Matter example with the same.
| Key confirmation is part of the SPAKE2+ protocol. Current PSA Cryptography API 1.1 PAKE Extension only supports implicit key confirmation. | ||
|
|
||
| * New API `psa_pake_get_explicit_key()` is required to provide keys with explicit key confirmation. No newline at end of file | ||
| * New API `psa_pake_get_explicit_key()` which will take as input the current PAKE operation and the attributes for the explicit key and return the key id of the explicit key. |
There was a problem hiding this comment.
I wonder about the naming of this API, and by extension, the existing psa_pake_get_implicit_key().
I think the API would be clearer if we called this psa_pake_get_confirmed_key() or psa_pake_output_confirmed_key()? (I like 'output' as this matches the key derivation operation, but I can see that we inject the password with a 'set' function.
As per #86, we should consider whether we want both a 'extract to key' API (which could extract only part of the output?) and a 'inject shared secret into a KDF' API (like the existing psa_pake_get_implicit_key() function).
This is both a big enough sub-topic, with implications for the existing beta API: I will raise a separate issue to have that discussion. This is now #100
| psa_pake_get_explicit_key(psa_pake_operation_t *pake, psa_key_attributes_t *attributes, psa_key_id_t *explicit_key); | ||
| ``` | ||
|
|
||
| ### PSA PAKE API Flow for SPAKE2+ with Matter as example |
There was a problem hiding this comment.
👍 This is helpful to have here (and probably in the spec in some form) is helpful to think through the API design issues.
Signed-off-by: Kusumit Ghoderao <Kusumit.Ghoder@silabs.com>
|
I believe that this PR has now served its purpose. I propose to close this PR without merging. However, if it would be valuable to preserve the RFC document within the main branch of the repository we can consider where such design documents could be stored? |
|
Closing this now, as the proposed changes have all been implemented in the specification. We can still pull the RFC document into the repo at a future date if this would be useful to keep. |
This PR is intended for finalizing the expected SPAKE2+ flow using PAKE API. If flow is finalized, we'll have an actual PR with expected api changes to review later.
This PR continues from #65.