-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
EC J-PAKE driver dispatch implementation v.2 #6567
Changes from all commits
56b8d23
7da8c56
a7d08c3
5ae6096
2e73649
d3da040
0379002
d91bcb7
6c76441
6a9785f
061a016
7658a07
4f0035b
0c78180
061f694
e5e41eb
51eac53
96ae8b9
ca67483
c6b9546
95629ab
3f9dbac
be5e27b
e12ed36
2797d37
fcd70e2
9a5b812
d6eb110
5798003
d67a5b6
8c8ab26
b09c487
7b73017
0f50f68
ca8d2b2
18620a3
5cbca79
33ea63d
38b4e17
27cd488
dde6a91
ff01bc4
1c3cfb4
d5d28a2
9dd2440
ac067d7
f62b3bb
d69dca9
a48cf50
3e784d8
e1d51bf
849c35f
4fcc61e
dff21d3
6d77830
b45b8ce
251e86a
6b64862
a54dc69
80a8849
ce131bf
51a677b
5eff103
d59d2a4
bdc21e6
083745e
d93de32
6f2d1f4
f5dcb88
e3ef3a1
4dc83d4
4aa9940
57580f2
691e91a
b8eaf63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -321,6 +321,159 @@ TODO: key input and output for opaque drivers; deterministic key generation for | |
|
||
TODO | ||
|
||
### Driver entry points for PAKE | ||
|
||
A PAKE operation is divided into two stages: collecting inputs and computation. Core side is responsible for keeping inputs and core set-data functions do not have driver entry points. Collected inputs are available for drivers via get-data functions for `password`, `role` and `cipher_suite`. | ||
|
||
### PAKE driver dispatch logic | ||
The core decides whether to dispatch a PAKE operation to a driver based on the location of the provided password. | ||
When all inputs are collected and `"psa_pake_output"` or `"psa_pake_input"` is called for the first time `"pake_setup"` driver entry point is invoked. | ||
|
||
1. If the location of the `password` is the local storage | ||
- if there is a transparent driver for the specified ciphersuite, the core calls that driver's `"pake_setup"` and subsequent entry points. | ||
- otherwise, or on fallback, the core uses its built-in implementation. | ||
2. If the location of the `password` is the location of a secure element | ||
- the core calls the `"pake_setup"` entry point of the secure element driver and subsequent entry points. | ||
|
||
### Summary of entry points for PAKE | ||
|
||
A PAKE driver has the following entry points: | ||
* `"pake_setup"` (mandatory): always the first entry point to be called. It is called when all inputs are collected and the computation stage starts. | ||
* `"pake_output"` (mandatory): derive cryptographic material for the specified step and output it. | ||
* `"pake_input"` (mandatory): provides cryptographic material in the format appropriate for the specified step. | ||
* `"pake_get_implicit_key"` (mandatory): returns implicitly confirmed shared secret from a PAKE. | ||
* `"pake_abort"` (mandatory): always the last entry point to be called. | ||
|
||
For naming purposes, here and in the following subsection, this specification takes the example of a driver with the prefix `"acme"` that implements the PAKE entry point family with a capability that does not use the `"names"` property to declare different type and entry point names. Such a driver must implement the following type and functions, as well as the entry points listed above and described in the following subsections: | ||
``` | ||
typedef ... acme_pake_operation_t; | ||
psa_status_t acme_pake_abort( acme_pake_operation_t *operation ); | ||
``` | ||
|
||
#### PAKE driver inputs | ||
|
||
The core conveys the initial inputs for a PAKE operation via an opaque data structure of type `psa_crypto_driver_pake_inputs_t`. | ||
|
||
``` | ||
typedef ... psa_crypto_driver_pake_inputs_t; // implementation-specific type | ||
``` | ||
|
||
A driver receiving an argument that points to a `psa_crypto_driver_pake_inputs_t` can retrieve its contents by calling one of the get-data functions below. | ||
|
||
``` | ||
psa_status_t psa_crypto_driver_pake_get_password_len( | ||
const psa_crypto_driver_pake_inputs_t *inputs, | ||
size_t *password_len); | ||
|
||
psa_status_t psa_crypto_driver_pake_get_password_bytes( | ||
const psa_crypto_driver_pake_inputs_t *inputs, | ||
uint8_t *buffer, size_t buffer_size, size_t *buffer_length); | ||
|
||
psa_status_t psa_crypto_driver_pake_get_password_key( | ||
const psa_crypto_driver_pake_inputs_t *inputs, | ||
uint8_t** p_key_buffer, size_t *key_buffer_size, | ||
const psa_key_attributes_t *attributes); | ||
|
||
psa_status_t psa_crypto_driver_pake_get_role( | ||
const psa_crypto_driver_pake_inputs_t *inputs, | ||
psa_pake_role_t *role); | ||
|
||
psa_status_t psa_crypto_driver_pake_get_cipher_suite( | ||
const psa_crypto_driver_pake_inputs_t *inputs, | ||
psa_pake_cipher_suite_t *cipher_suite); | ||
``` | ||
The get-data functions take the following parameters: | ||
|
||
The first parameter `inputs` must be a pointer passed by the core to a PAKE driver setup entry point. | ||
Next parameters are return buffers (must not be null pointers). | ||
|
||
These functions can return the following statuses: | ||
* `PSA_SUCCESS`: value has been successfully obtained | ||
* `PSA_ERROR_BAD_STATE`: the inputs are not ready | ||
* `PSA_ERROR_BUFFER_TOO_SMALL` (`psa_crypto_driver_pake_get_password_bytes` and `psa_crypto_driver_pake_get_password_key` only): the output buffer is too small. This is not a fatal error and the driver can, for example, subsequently call the same function again with a larger buffer. Call `psa_crypto_driver_pake_get_password_len` to obtain the required size. | ||
|
||
#### PAKE driver setup | ||
|
||
``` | ||
psa_status_t acme_pake_setup( acme_pake_operation_t *operation, | ||
const psa_crypto_driver_pake_inputs_t *inputs ); | ||
``` | ||
|
||
* `operation` is a zero-initialized operation object. | ||
* `inputs` is an opaque pointer to the [inputs](#pake-driver-inputs) for the PAKE operation. | ||
|
||
The setup driver function should preserve the inputs using get-data functions. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather, something like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this is only about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For other inputs, the interface requires a data buffer belonging to the driver. But There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From PSA drivers: specification for key derivation:
I think that both notes are needed.
|
||
|
||
The pointer output by `psa_crypto_driver_pake_get_password_key` is only valid until the "pake_setup" entry point returns. Opaque drivers must copy all relevant data from the key buffer during the "pake_setup" entry point and must not store the pointer itself. | ||
|
||
#### PAKE driver output | ||
|
||
``` | ||
psa_status_t acme_pake_output(acme_pake_operation_t *operation, | ||
psa_crypto_driver_pake_step_t step, | ||
uint8_t *output, | ||
size_t output_size, | ||
size_t *output_length); | ||
``` | ||
|
||
* `operation` is an operation object. | ||
* `step` computation step based on which driver should perform an action. | ||
* `output` buffer where the output is to be written. | ||
* `output_size` size of the output buffer in bytes. | ||
* `output_length` the number of bytes of the returned output. | ||
|
||
For `PSA_ALG_JPAKE` the following steps are available for output operation: | ||
`step` can be one of the following values: | ||
* `PSA_JPAKE_X1_STEP_KEY_SHARE` Round 1: output our key share (for ephemeral private key X1) | ||
* `PSA_JPAKE_X1_STEP_ZK_PUBLIC` Round 1: output Schnorr NIZKP public key for the X1 key | ||
* `PSA_JPAKE_X1_STEP_ZK_PROOF` Round 1: output Schnorr NIZKP proof for the X1 key | ||
* `PSA_JPAKE_X2_STEP_KEY_SHARE` Round 1: output our key share (for ephemeral private key X2) | ||
* `PSA_JPAKE_X2_STEP_ZK_PUBLIC` Round 1: output Schnorr NIZKP public key for the X2 key | ||
* `PSA_JPAKE_X2_STEP_ZK_PROOF` Round 1: output Schnorr NIZKP proof for the X2 key | ||
* `PSA_JPAKE_X2S_STEP_KEY_SHARE` Round 2: output our X2S key | ||
* `PSA_JPAKE_X2S_STEP_ZK_PUBLIC` Round 2: output Schnorr NIZKP public key for the X2S key | ||
* `PSA_JPAKE_X2S_STEP_ZK_PROOF` Round 2: output Schnorr NIZKP proof for the X2S key | ||
|
||
#### PAKE driver input | ||
``` | ||
psa_status_t acme_pake_input(acme_pake_operation_t *operation, | ||
psa_crypto_driver_pake_step_t step, | ||
uint8_t *input, | ||
size_t input_size); | ||
``` | ||
|
||
* `operation` is an operation object. | ||
* `step` computation step based on which driver should perform an action. | ||
* `input` buffer containing the input. | ||
* `input_length` length of the input in bytes. | ||
|
||
For `PSA_ALG_JPAKE` the following steps are available for input operation: | ||
* `PSA_JPAKE_X1_STEP_KEY_SHARE` Round 1: input key share from peer (for ephemeral private key X1) | ||
* `PSA_JPAKE_X1_STEP_ZK_PUBLIC` Round 1: input Schnorr NIZKP public key for the X1 key | ||
* `PSA_JPAKE_X1_STEP_ZK_PROOF` Round 1: input Schnorr NIZKP proof for the X1 key | ||
* `PSA_JPAKE_X2_STEP_KEY_SHARE` Round 1: input key share from peer (for ephemeral private key X2) | ||
* `PSA_JPAKE_X2_STEP_ZK_PUBLIC` Round 1: input Schnorr NIZKP public key for the X2 key | ||
* `PSA_JPAKE_X2_STEP_ZK_PROOF` Round 1: input Schnorr NIZKP proof for the X2 key | ||
* `PSA_JPAKE_X4S_STEP_KEY_SHARE` Round 2: input X4S key from peer | ||
* `PSA_JPAKE_X4S_STEP_ZK_PUBLIC` Round 2: input Schnorr NIZKP public key for the X4S key | ||
* `PSA_JPAKE_X4S_STEP_ZK_PROOF` Round 2: input Schnorr NIZKP proof for the X4S key | ||
|
||
The core checks that input_length is smaller than PSA_PAKE_INPUT_MAX_SIZE. | ||
|
||
### PAKE driver get implicit key | ||
|
||
``` | ||
psa_status_t acme_pake_get_implicit_key( | ||
acme_pake_operation_t *operation, | ||
uint8_t *output, size_t output_size, | ||
size_t *output_length ); | ||
``` | ||
|
||
* `operation` The driver PAKE operation object to use. | ||
* `output` Buffer where the implicit key is to be written. | ||
* `output_size` Size of the output buffer in bytes. | ||
* `output_length` On success, the number of bytes of the implicit key. | ||
|
||
### Driver entry points for key management | ||
|
||
The driver entry points for key management differ significantly between [transparent drivers](#key-management-with-transparent-drivers) and [opaque drivers](#key-management-with-opaque-drivers). This section describes common elements. Refer to the applicable section for each driver type for more information. | ||
|
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 don't know if it's spelled out explicitly anywhere, but I'm assuming that it's allowed for an opaque driver to support multiple key locations (for example one location for volatile keys inside of the SE, and one location for wrapped keys). In that case, the driver needs to be able to figure out the location to use for the password. For other driver entry points, this is enabled by the key attributes passed alongside the key data. I'm thinking that we need to add something here such that the driver can figure out the location of the password (even though the driver likely can figure that out someway, but that feels like a less clean solution).
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.
Currently core side takes only one password per operation and driver just gets key data via getter function. Probably I'm missing something, but as far as I understand for other key we need to use new operation.
If key location/lifetime of the password is really needed I can add getter function for this as core already have this information in
inputs
.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 same driver (as in, the same code) can support multiple locations, e.g. a phone with dual SIM with the driver supporting both SIM. A driver responsible for a given location is systematically responsible for multiple lifetimes, namely, all the persistence levels (e.g. volatile, stored, factory-set-and-immutable).
The generic way driver entry points for operations are formed is by taking API functions and replacing
psa_key_id_t
byattributes, key_buffer, key_buffer_size
. So indeedpsa_crypto_driver_pake_get_password
should have anattributes
parameter.I made the same mistake as @mprse with
psa_crypto_driver_key_derivation_get_input_key
— noted.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.
Thank you for the details. Looking at location and lifetime there are the following main options:
Location: local storage/secure element
Lifetime: volatile/persistent
Now for example we have the following main combinations:
We have separate drivers for different locations, but now information about key lifetime is missing. What I don't understand is why driver needs this information. It gets key data from core anyway and just need to use 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.
Secure element, volatile is possible. Not very common, but we have had requests for it. Mainly, secure elements are used to provide a higher level of security for long-term keys, and long-term keys are persistent. But using a volatile key with a secure element can be useful sometimes. In particular, it allows using the secure element as an accelerator, so the non-SE part doesn't need to support the algorithm at all. You could do the same with an accelerator driver, but if you already have the secure element driver and you're ok with tweaking your application code, you save code size by not defining an accelerator driver.
The driver needs to know the full lifetime information: the location in case the driver supports multiple location, and the persistence level so that it knows where to load/store the key data (RAM, or potentially multiple storage partitions with different persistence levels).