1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-08-01 10:06:53 +03:00

Merge pull request #6567 from mprse/ecjpake-driver-dispatch

This commit is contained in:
Dave Rodgman
2023-03-09 19:23:05 +00:00
committed by GitHub
20 changed files with 2924 additions and 600 deletions

View File

@ -916,14 +916,27 @@ static psa_status_t psa_restrict_key_policy(
return PSA_SUCCESS;
}
psa_status_t psa_get_and_lock_key_slot_with_policy(
/** Get the description of a key given its identifier and policy constraints
* and lock it.
*
* The key must have allow all the usage flags set in \p usage. If \p alg is
* nonzero, the key must allow operations with this algorithm. If \p alg is
* zero, the algorithm is not checked.
*
* In case of a persistent key, the function loads the description of the key
* into a key slot if not already done.
*
* On success, the returned key slot is locked. It is the responsibility of
* the caller to unlock the key slot when it does not access it anymore.
*/
static psa_status_t psa_get_and_lock_key_slot_with_policy(
mbedtls_svc_key_id_t key,
psa_key_slot_t **p_slot,
psa_key_usage_t usage,
psa_algorithm_t alg)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
psa_key_slot_t *slot = NULL;
status = psa_get_and_lock_key_slot(key, p_slot);
if (status != PSA_SUCCESS) {
@ -5061,13 +5074,13 @@ psa_status_t psa_key_derivation_abort(psa_key_derivation_operation_t *operation)
operation->ctx.tls12_prf.label_length);
mbedtls_free(operation->ctx.tls12_prf.label);
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
if (operation->ctx.tls12_prf.other_secret != NULL) {
mbedtls_platform_zeroize(operation->ctx.tls12_prf.other_secret,
operation->ctx.tls12_prf.other_secret_length);
mbedtls_free(operation->ctx.tls12_prf.other_secret);
}
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
status = PSA_SUCCESS;
/* We leave the fields Ai and output_block to be erased safely by the
@ -7152,4 +7165,736 @@ exit:
return status;
}
psa_status_t psa_crypto_driver_pake_get_password_len(
const psa_crypto_driver_pake_inputs_t *inputs,
size_t *password_len)
{
if (inputs->password_len == 0) {
return PSA_ERROR_BAD_STATE;
}
*password_len = inputs->password_len;
return PSA_SUCCESS;
}
psa_status_t psa_crypto_driver_pake_get_password(
const psa_crypto_driver_pake_inputs_t *inputs,
uint8_t *buffer, size_t buffer_size, size_t *buffer_length)
{
if (inputs->password_len == 0) {
return PSA_ERROR_BAD_STATE;
}
if (buffer_size < inputs->password_len) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
memcpy(buffer, inputs->password, inputs->password_len);
*buffer_length = inputs->password_len;
return PSA_SUCCESS;
}
psa_status_t psa_crypto_driver_pake_get_role(
const psa_crypto_driver_pake_inputs_t *inputs,
psa_pake_role_t *role)
{
if (inputs->role == PSA_PAKE_ROLE_NONE) {
return PSA_ERROR_BAD_STATE;
}
*role = inputs->role;
return PSA_SUCCESS;
}
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)
{
if (inputs->cipher_suite.algorithm == PSA_ALG_NONE) {
return PSA_ERROR_BAD_STATE;
}
*cipher_suite = inputs->cipher_suite;
return PSA_SUCCESS;
}
psa_status_t psa_pake_setup(
psa_pake_operation_t *operation,
const psa_pake_cipher_suite_t *cipher_suite)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (operation->stage != PSA_PAKE_OPERATION_STAGE_SETUP) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
if (PSA_ALG_IS_PAKE(cipher_suite->algorithm) == 0 ||
PSA_ALG_IS_HASH(cipher_suite->hash) == 0) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
memset(&operation->data.inputs, 0, sizeof(operation->data.inputs));
operation->alg = cipher_suite->algorithm;
operation->data.inputs.cipher_suite = *cipher_suite;
#if defined(PSA_WANT_ALG_JPAKE)
if (operation->alg == PSA_ALG_JPAKE) {
psa_jpake_computation_stage_t *computation_stage =
&operation->computation_stage.jpake;
computation_stage->state = PSA_PAKE_STATE_SETUP;
computation_stage->sequence = PSA_PAKE_SEQ_INVALID;
computation_stage->input_step = PSA_PAKE_STEP_X1_X2;
computation_stage->output_step = PSA_PAKE_STEP_X1_X2;
} else
#endif /* PSA_WANT_ALG_JPAKE */
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
operation->stage = PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS;
return PSA_SUCCESS;
exit:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_set_password_key(
psa_pake_operation_t *operation,
mbedtls_svc_key_id_t password)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot = NULL;
if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
status = psa_get_and_lock_key_slot_with_policy(password, &slot,
PSA_KEY_USAGE_DERIVE,
operation->alg);
if (status != PSA_SUCCESS) {
goto exit;
}
psa_key_attributes_t attributes = {
.core = slot->attr
};
psa_key_type_t type = psa_get_key_type(&attributes);
if (type != PSA_KEY_TYPE_PASSWORD &&
type != PSA_KEY_TYPE_PASSWORD_HASH) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
operation->data.inputs.password = mbedtls_calloc(1, slot->key.bytes);
if (operation->data.inputs.password == NULL) {
status = PSA_ERROR_INSUFFICIENT_MEMORY;
goto exit;
}
memcpy(operation->data.inputs.password, slot->key.data, slot->key.bytes);
operation->data.inputs.password_len = slot->key.bytes;
operation->data.inputs.attributes = attributes;
exit:
if (status != PSA_SUCCESS) {
psa_pake_abort(operation);
}
unlock_status = psa_unlock_key_slot(slot);
return (status == PSA_SUCCESS) ? unlock_status : status;
}
psa_status_t psa_pake_set_user(
psa_pake_operation_t *operation,
const uint8_t *user_id,
size_t user_id_len)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
(void) user_id;
if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
if (user_id_len == 0) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
return PSA_ERROR_NOT_SUPPORTED;
exit:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_set_peer(
psa_pake_operation_t *operation,
const uint8_t *peer_id,
size_t peer_id_len)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
(void) peer_id;
if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
if (peer_id_len == 0) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
return PSA_ERROR_NOT_SUPPORTED;
exit:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_set_role(
psa_pake_operation_t *operation,
psa_pake_role_t role)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
if (role != PSA_PAKE_ROLE_NONE &&
role != PSA_PAKE_ROLE_FIRST &&
role != PSA_PAKE_ROLE_SECOND &&
role != PSA_PAKE_ROLE_CLIENT &&
role != PSA_PAKE_ROLE_SERVER) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
operation->data.inputs.role = role;
return PSA_SUCCESS;
exit:
psa_pake_abort(operation);
return status;
}
/* Auxiliary function to convert core computation stage(step, sequence, state) to single driver step. */
#if defined(PSA_WANT_ALG_JPAKE)
static psa_crypto_driver_pake_step_t convert_jpake_computation_stage_to_driver_step(
psa_jpake_computation_stage_t *stage)
{
switch (stage->state) {
case PSA_PAKE_OUTPUT_X1_X2:
case PSA_PAKE_INPUT_X1_X2:
switch (stage->sequence) {
case PSA_PAKE_X1_STEP_KEY_SHARE:
return PSA_JPAKE_X1_STEP_KEY_SHARE;
case PSA_PAKE_X1_STEP_ZK_PUBLIC:
return PSA_JPAKE_X1_STEP_ZK_PUBLIC;
case PSA_PAKE_X1_STEP_ZK_PROOF:
return PSA_JPAKE_X1_STEP_ZK_PROOF;
case PSA_PAKE_X2_STEP_KEY_SHARE:
return PSA_JPAKE_X2_STEP_KEY_SHARE;
case PSA_PAKE_X2_STEP_ZK_PUBLIC:
return PSA_JPAKE_X2_STEP_ZK_PUBLIC;
case PSA_PAKE_X2_STEP_ZK_PROOF:
return PSA_JPAKE_X2_STEP_ZK_PROOF;
default:
return PSA_JPAKE_STEP_INVALID;
}
break;
case PSA_PAKE_OUTPUT_X2S:
switch (stage->sequence) {
case PSA_PAKE_X1_STEP_KEY_SHARE:
return PSA_JPAKE_X2S_STEP_KEY_SHARE;
case PSA_PAKE_X1_STEP_ZK_PUBLIC:
return PSA_JPAKE_X2S_STEP_ZK_PUBLIC;
case PSA_PAKE_X1_STEP_ZK_PROOF:
return PSA_JPAKE_X2S_STEP_ZK_PROOF;
default:
return PSA_JPAKE_STEP_INVALID;
}
break;
case PSA_PAKE_INPUT_X4S:
switch (stage->sequence) {
case PSA_PAKE_X1_STEP_KEY_SHARE:
return PSA_JPAKE_X4S_STEP_KEY_SHARE;
case PSA_PAKE_X1_STEP_ZK_PUBLIC:
return PSA_JPAKE_X4S_STEP_ZK_PUBLIC;
case PSA_PAKE_X1_STEP_ZK_PROOF:
return PSA_JPAKE_X4S_STEP_ZK_PROOF;
default:
return PSA_JPAKE_STEP_INVALID;
}
break;
default:
return PSA_JPAKE_STEP_INVALID;
}
return PSA_JPAKE_STEP_INVALID;
}
#endif /* PSA_WANT_ALG_JPAKE */
static psa_status_t psa_pake_complete_inputs(
psa_pake_operation_t *operation)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
/* Create copy of the inputs on stack as inputs share memory
with the driver context which will be setup by the driver. */
psa_crypto_driver_pake_inputs_t inputs = operation->data.inputs;
if (inputs.password_len == 0 ||
inputs.role == PSA_PAKE_ROLE_NONE) {
return PSA_ERROR_BAD_STATE;
}
if (operation->alg == PSA_ALG_JPAKE &&
inputs.role != PSA_PAKE_ROLE_CLIENT &&
inputs.role != PSA_PAKE_ROLE_SERVER) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* Clear driver context */
mbedtls_platform_zeroize(&operation->data, sizeof(operation->data));
status = psa_driver_wrapper_pake_setup(operation, &inputs);
/* Driver is responsible for creating its own copy of the password. */
mbedtls_platform_zeroize(inputs.password, inputs.password_len);
mbedtls_free(inputs.password);
if (status == PSA_SUCCESS) {
#if defined(PSA_WANT_ALG_JPAKE)
if (operation->alg == PSA_ALG_JPAKE) {
operation->stage = PSA_PAKE_OPERATION_STAGE_COMPUTATION;
psa_jpake_computation_stage_t *computation_stage =
&operation->computation_stage.jpake;
computation_stage->state = PSA_PAKE_STATE_READY;
computation_stage->sequence = PSA_PAKE_SEQ_INVALID;
computation_stage->input_step = PSA_PAKE_STEP_X1_X2;
computation_stage->output_step = PSA_PAKE_STEP_X1_X2;
} else
#endif /* PSA_WANT_ALG_JPAKE */
{
status = PSA_ERROR_NOT_SUPPORTED;
}
}
return status;
}
#if defined(PSA_WANT_ALG_JPAKE)
static psa_status_t psa_jpake_output_prologue(
psa_pake_operation_t *operation,
psa_pake_step_t step)
{
if (step != PSA_PAKE_STEP_KEY_SHARE &&
step != PSA_PAKE_STEP_ZK_PUBLIC &&
step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_INVALID_ARGUMENT;
}
psa_jpake_computation_stage_t *computation_stage =
&operation->computation_stage.jpake;
if (computation_stage->state == PSA_PAKE_STATE_INVALID) {
return PSA_ERROR_BAD_STATE;
}
if (computation_stage->state != PSA_PAKE_STATE_READY &&
computation_stage->state != PSA_PAKE_OUTPUT_X1_X2 &&
computation_stage->state != PSA_PAKE_OUTPUT_X2S) {
return PSA_ERROR_BAD_STATE;
}
if (computation_stage->state == PSA_PAKE_STATE_READY) {
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
switch (computation_stage->output_step) {
case PSA_PAKE_STEP_X1_X2:
computation_stage->state = PSA_PAKE_OUTPUT_X1_X2;
break;
case PSA_PAKE_STEP_X2S:
computation_stage->state = PSA_PAKE_OUTPUT_X2S;
break;
default:
return PSA_ERROR_BAD_STATE;
}
computation_stage->sequence = PSA_PAKE_X1_STEP_KEY_SHARE;
}
/* Check if step matches current sequence */
switch (computation_stage->sequence) {
case PSA_PAKE_X1_STEP_KEY_SHARE:
case PSA_PAKE_X2_STEP_KEY_SHARE:
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PUBLIC:
case PSA_PAKE_X2_STEP_ZK_PUBLIC:
if (step != PSA_PAKE_STEP_ZK_PUBLIC) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PROOF:
case PSA_PAKE_X2_STEP_ZK_PROOF:
if (step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_BAD_STATE;
}
break;
default:
return PSA_ERROR_BAD_STATE;
}
return PSA_SUCCESS;
}
static psa_status_t psa_jpake_output_epilogue(
psa_pake_operation_t *operation)
{
psa_jpake_computation_stage_t *computation_stage =
&operation->computation_stage.jpake;
if ((computation_stage->state == PSA_PAKE_OUTPUT_X1_X2 &&
computation_stage->sequence == PSA_PAKE_X2_STEP_ZK_PROOF) ||
(computation_stage->state == PSA_PAKE_OUTPUT_X2S &&
computation_stage->sequence == PSA_PAKE_X1_STEP_ZK_PROOF)) {
computation_stage->state = PSA_PAKE_STATE_READY;
computation_stage->output_step++;
computation_stage->sequence = PSA_PAKE_SEQ_INVALID;
} else {
computation_stage->sequence++;
}
return PSA_SUCCESS;
}
#endif /* PSA_WANT_ALG_JPAKE */
psa_status_t psa_pake_output(
psa_pake_operation_t *operation,
psa_pake_step_t step,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_crypto_driver_pake_step_t driver_step = PSA_JPAKE_STEP_INVALID;
*output_length = 0;
if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
status = psa_pake_complete_inputs(operation);
if (status != PSA_SUCCESS) {
goto exit;
}
}
if (operation->stage != PSA_PAKE_OPERATION_STAGE_COMPUTATION) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
if (output_size == 0) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
switch (operation->alg) {
#if defined(PSA_WANT_ALG_JPAKE)
case PSA_ALG_JPAKE:
status = psa_jpake_output_prologue(operation, step);
if (status != PSA_SUCCESS) {
goto exit;
}
driver_step = convert_jpake_computation_stage_to_driver_step(
&operation->computation_stage.jpake);
break;
#endif /* PSA_WANT_ALG_JPAKE */
default:
(void) step;
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = psa_driver_wrapper_pake_output(operation, driver_step,
output, output_size, output_length);
if (status != PSA_SUCCESS) {
goto exit;
}
switch (operation->alg) {
#if defined(PSA_WANT_ALG_JPAKE)
case PSA_ALG_JPAKE:
status = psa_jpake_output_epilogue(operation);
if (status != PSA_SUCCESS) {
goto exit;
}
break;
#endif /* PSA_WANT_ALG_JPAKE */
default:
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
return PSA_SUCCESS;
exit:
psa_pake_abort(operation);
return status;
}
#if defined(PSA_WANT_ALG_JPAKE)
static psa_status_t psa_jpake_input_prologue(
psa_pake_operation_t *operation,
psa_pake_step_t step)
{
if (step != PSA_PAKE_STEP_KEY_SHARE &&
step != PSA_PAKE_STEP_ZK_PUBLIC &&
step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_INVALID_ARGUMENT;
}
psa_jpake_computation_stage_t *computation_stage =
&operation->computation_stage.jpake;
if (computation_stage->state == PSA_PAKE_STATE_INVALID) {
return PSA_ERROR_BAD_STATE;
}
if (computation_stage->state != PSA_PAKE_STATE_READY &&
computation_stage->state != PSA_PAKE_INPUT_X1_X2 &&
computation_stage->state != PSA_PAKE_INPUT_X4S) {
return PSA_ERROR_BAD_STATE;
}
if (computation_stage->state == PSA_PAKE_STATE_READY) {
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
switch (computation_stage->input_step) {
case PSA_PAKE_STEP_X1_X2:
computation_stage->state = PSA_PAKE_INPUT_X1_X2;
break;
case PSA_PAKE_STEP_X2S:
computation_stage->state = PSA_PAKE_INPUT_X4S;
break;
default:
return PSA_ERROR_BAD_STATE;
}
computation_stage->sequence = PSA_PAKE_X1_STEP_KEY_SHARE;
}
/* Check if step matches current sequence */
switch (computation_stage->sequence) {
case PSA_PAKE_X1_STEP_KEY_SHARE:
case PSA_PAKE_X2_STEP_KEY_SHARE:
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PUBLIC:
case PSA_PAKE_X2_STEP_ZK_PUBLIC:
if (step != PSA_PAKE_STEP_ZK_PUBLIC) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PROOF:
case PSA_PAKE_X2_STEP_ZK_PROOF:
if (step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_BAD_STATE;
}
break;
default:
return PSA_ERROR_BAD_STATE;
}
return PSA_SUCCESS;
}
static psa_status_t psa_jpake_input_epilogue(
psa_pake_operation_t *operation)
{
psa_jpake_computation_stage_t *computation_stage =
&operation->computation_stage.jpake;
if ((computation_stage->state == PSA_PAKE_INPUT_X1_X2 &&
computation_stage->sequence == PSA_PAKE_X2_STEP_ZK_PROOF) ||
(computation_stage->state == PSA_PAKE_INPUT_X4S &&
computation_stage->sequence == PSA_PAKE_X1_STEP_ZK_PROOF)) {
computation_stage->state = PSA_PAKE_STATE_READY;
computation_stage->input_step++;
computation_stage->sequence = PSA_PAKE_SEQ_INVALID;
} else {
computation_stage->sequence++;
}
return PSA_SUCCESS;
}
#endif /* PSA_WANT_ALG_JPAKE */
psa_status_t psa_pake_input(
psa_pake_operation_t *operation,
psa_pake_step_t step,
const uint8_t *input,
size_t input_length)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_crypto_driver_pake_step_t driver_step = PSA_JPAKE_STEP_INVALID;
if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) {
status = psa_pake_complete_inputs(operation);
if (status != PSA_SUCCESS) {
goto exit;
}
}
if (operation->stage != PSA_PAKE_OPERATION_STAGE_COMPUTATION) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
if (input_length == 0 || input_length > PSA_PAKE_INPUT_MAX_SIZE) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
switch (operation->alg) {
#if defined(PSA_WANT_ALG_JPAKE)
case PSA_ALG_JPAKE:
status = psa_jpake_input_prologue(operation, step);
if (status != PSA_SUCCESS) {
goto exit;
}
driver_step = convert_jpake_computation_stage_to_driver_step(
&operation->computation_stage.jpake);
break;
#endif /* PSA_WANT_ALG_JPAKE */
default:
(void) step;
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = psa_driver_wrapper_pake_input(operation, driver_step,
input, input_length);
if (status != PSA_SUCCESS) {
goto exit;
}
switch (operation->alg) {
#if defined(PSA_WANT_ALG_JPAKE)
case PSA_ALG_JPAKE:
status = psa_jpake_input_epilogue(operation);
if (status != PSA_SUCCESS) {
goto exit;
}
break;
#endif /* PSA_WANT_ALG_JPAKE */
default:
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
return PSA_SUCCESS;
exit:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_get_implicit_key(
psa_pake_operation_t *operation,
psa_key_derivation_operation_t *output)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED;
uint8_t shared_key[MBEDTLS_PSA_JPAKE_BUFFER_SIZE];
size_t shared_key_len = 0;
if (operation->stage != PSA_PAKE_OPERATION_STAGE_COMPUTATION) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
#if defined(PSA_WANT_ALG_JPAKE)
if (operation->alg == PSA_ALG_JPAKE) {
psa_jpake_computation_stage_t *computation_stage =
&operation->computation_stage.jpake;
if (computation_stage->input_step != PSA_PAKE_STEP_DERIVE ||
computation_stage->output_step != PSA_PAKE_STEP_DERIVE) {
status = PSA_ERROR_BAD_STATE;
goto exit;
}
} else
#endif /* PSA_WANT_ALG_JPAKE */
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = psa_driver_wrapper_pake_get_implicit_key(operation,
shared_key,
sizeof(shared_key),
&shared_key_len);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_key_derivation_input_bytes(output,
PSA_KEY_DERIVATION_INPUT_SECRET,
shared_key,
shared_key_len);
mbedtls_platform_zeroize(shared_key, sizeof(shared_key));
exit:
abort_status = psa_pake_abort(operation);
return status == PSA_SUCCESS ? abort_status : status;
}
psa_status_t psa_pake_abort(
psa_pake_operation_t *operation)
{
psa_status_t status = PSA_SUCCESS;
if (operation->stage == PSA_PAKE_OPERATION_STAGE_COMPUTATION) {
status = psa_driver_wrapper_pake_abort(operation);
}
if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS &&
operation->data.inputs.password != NULL) {
mbedtls_platform_zeroize(operation->data.inputs.password,
operation->data.inputs.password_len);
mbedtls_free(operation->data.inputs.password);
}
memset(operation, 0, sizeof(psa_pake_operation_t));
return status;
}
#endif /* MBEDTLS_PSA_CRYPTO_C */

View File

@ -182,24 +182,6 @@ static inline psa_key_slot_number_t psa_key_slot_get_slot_number(
}
#endif
/** Get the description of a key given its identifier and policy constraints
* and lock it.
*
* The key must have allow all the usage flags set in \p usage. If \p alg is
* nonzero, the key must allow operations with this algorithm. If \p alg is
* zero, the algorithm is not checked.
*
* In case of a persistent key, the function loads the description of the key
* into a key slot if not already done.
*
* On success, the returned key slot is locked. It is the responsibility of
* the caller to unlock the key slot when it does not access it anymore.
*/
psa_status_t psa_get_and_lock_key_slot_with_policy(mbedtls_svc_key_id_t key,
psa_key_slot_t **p_slot,
psa_key_usage_t usage,
psa_algorithm_t alg);
/** Completely wipe a slot in memory, including its policy.
*
* Persistent storage is not affected.

View File

@ -408,6 +408,34 @@ psa_status_t psa_driver_wrapper_key_agreement(
size_t shared_secret_size,
size_t *shared_secret_length);
/*
* PAKE functions.
*/
psa_status_t psa_driver_wrapper_pake_setup(
psa_pake_operation_t *operation,
const psa_crypto_driver_pake_inputs_t *inputs);
psa_status_t psa_driver_wrapper_pake_output(
psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
uint8_t *output,
size_t output_size,
size_t *output_length);
psa_status_t psa_driver_wrapper_pake_input(
psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
const uint8_t *input,
size_t input_length);
psa_status_t psa_driver_wrapper_pake_get_implicit_key(
psa_pake_operation_t *operation,
uint8_t *output, size_t output_size,
size_t *output_length);
psa_status_t psa_driver_wrapper_pake_abort(
psa_pake_operation_t *operation);
#endif /* PSA_CRYPTO_DRIVER_WRAPPERS_H */
/* End of automatically generated file. */

View File

@ -24,6 +24,7 @@
#include <psa/crypto.h>
#include "psa_crypto_core.h"
#include "psa_crypto_pake.h"
#include "psa_crypto_slot_management.h"
#include <mbedtls/ecjpake.h>
@ -78,23 +79,6 @@
* psa_pake_abort()
*/
enum psa_pake_step {
PSA_PAKE_STEP_INVALID = 0,
PSA_PAKE_STEP_X1_X2 = 1,
PSA_PAKE_STEP_X2S = 2,
PSA_PAKE_STEP_DERIVE = 3,
};
enum psa_pake_state {
PSA_PAKE_STATE_INVALID = 0,
PSA_PAKE_STATE_SETUP = 1,
PSA_PAKE_STATE_READY = 2,
PSA_PAKE_OUTPUT_X1_X2 = 3,
PSA_PAKE_OUTPUT_X2S = 4,
PSA_PAKE_INPUT_X1_X2 = 5,
PSA_PAKE_INPUT_X4S = 6,
};
/*
* The first PAKE step shares the same sequences of the second PAKE step
* but with a second set of KEY_SHARE/ZK_PUBLIC/ZK_PROOF outputs/inputs.
@ -156,16 +140,6 @@ enum psa_pake_state {
* psa_pake_get_implicit_key()
* => Input & Output Step = PSA_PAKE_STEP_INVALID
*/
enum psa_pake_sequence {
PSA_PAKE_SEQ_INVALID = 0,
PSA_PAKE_X1_STEP_KEY_SHARE = 1, /* also X2S & X4S KEY_SHARE */
PSA_PAKE_X1_STEP_ZK_PUBLIC = 2, /* also X2S & X4S ZK_PUBLIC */
PSA_PAKE_X1_STEP_ZK_PROOF = 3, /* also X2S & X4S ZK_PROOF */
PSA_PAKE_X2_STEP_KEY_SHARE = 4,
PSA_PAKE_X2_STEP_ZK_PUBLIC = 5,
PSA_PAKE_X2_STEP_ZK_PROOF = 6,
PSA_PAKE_SEQ_END = 7,
};
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
static psa_status_t mbedtls_ecjpake_to_psa_error(int ret)
@ -190,232 +164,16 @@ static psa_status_t mbedtls_ecjpake_to_psa_error(int ret)
#endif
#if defined(MBEDTLS_PSA_BUILTIN_PAKE)
psa_status_t psa_pake_setup(psa_pake_operation_t *operation,
const psa_pake_cipher_suite_t *cipher_suite)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
/* A context must be freshly initialized before it can be set up. */
if (operation->alg != PSA_ALG_NONE) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
if (cipher_suite == NULL ||
PSA_ALG_IS_PAKE(cipher_suite->algorithm) == 0 ||
(cipher_suite->type != PSA_PAKE_PRIMITIVE_TYPE_ECC &&
cipher_suite->type != PSA_PAKE_PRIMITIVE_TYPE_DH) ||
PSA_ALG_IS_HASH(cipher_suite->hash) == 0) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto error;
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
if (cipher_suite->algorithm == PSA_ALG_JPAKE) {
if (cipher_suite->type != PSA_PAKE_PRIMITIVE_TYPE_ECC ||
cipher_suite->family != PSA_ECC_FAMILY_SECP_R1 ||
cipher_suite->bits != 256 ||
cipher_suite->hash != PSA_ALG_SHA_256) {
status = PSA_ERROR_NOT_SUPPORTED;
goto error;
}
operation->alg = cipher_suite->algorithm;
mbedtls_ecjpake_init(&operation->ctx.ecjpake);
operation->state = PSA_PAKE_STATE_SETUP;
operation->sequence = PSA_PAKE_SEQ_INVALID;
operation->input_step = PSA_PAKE_STEP_X1_X2;
operation->output_step = PSA_PAKE_STEP_X1_X2;
mbedtls_platform_zeroize(operation->buffer, MBEDTLS_PSA_PAKE_BUFFER_SIZE);
operation->buffer_length = 0;
operation->buffer_offset = 0;
return PSA_SUCCESS;
} else
#endif
status = PSA_ERROR_NOT_SUPPORTED;
error:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_set_password_key(psa_pake_operation_t *operation,
mbedtls_svc_key_id_t password)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_attributes_t attributes = psa_key_attributes_init();
psa_key_type_t type;
psa_key_usage_t usage;
psa_key_slot_t *slot = NULL;
if (operation->alg == PSA_ALG_NONE ||
operation->state != PSA_PAKE_STATE_SETUP) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
status = psa_get_key_attributes(password, &attributes);
if (status != PSA_SUCCESS) {
goto error;
}
type = psa_get_key_type(&attributes);
usage = psa_get_key_usage_flags(&attributes);
psa_reset_key_attributes(&attributes);
if (type != PSA_KEY_TYPE_PASSWORD &&
type != PSA_KEY_TYPE_PASSWORD_HASH) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto error;
}
if ((usage & PSA_KEY_USAGE_DERIVE) == 0) {
status = PSA_ERROR_NOT_PERMITTED;
goto error;
}
if (operation->password != NULL) {
return PSA_ERROR_BAD_STATE;
}
status = psa_get_and_lock_key_slot_with_policy(password, &slot,
PSA_KEY_USAGE_DERIVE,
PSA_ALG_JPAKE);
if (status != PSA_SUCCESS) {
return status;
}
operation->password = mbedtls_calloc(1, slot->key.bytes);
if (operation->password == NULL) {
psa_unlock_key_slot(slot);
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
memcpy(operation->password, slot->key.data, slot->key.bytes);
operation->password_len = slot->key.bytes;
status = psa_unlock_key_slot(slot);
if (status != PSA_SUCCESS) {
return status;
}
return PSA_SUCCESS;
error:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_set_user(psa_pake_operation_t *operation,
const uint8_t *user_id,
size_t user_id_len)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (operation->alg == PSA_ALG_NONE ||
operation->state != PSA_PAKE_STATE_SETUP) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
if (user_id_len == 0 || user_id == NULL) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto error;
}
status = PSA_ERROR_NOT_SUPPORTED;
error:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_set_peer(psa_pake_operation_t *operation,
const uint8_t *peer_id,
size_t peer_id_len)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (operation->alg == PSA_ALG_NONE ||
operation->state != PSA_PAKE_STATE_SETUP) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
if (peer_id_len == 0 || peer_id == NULL) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto error;
}
status = PSA_ERROR_NOT_SUPPORTED;
error:
psa_pake_abort(operation);
return status;
}
psa_status_t psa_pake_set_role(psa_pake_operation_t *operation,
psa_pake_role_t role)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (operation->alg == PSA_ALG_NONE ||
operation->state != PSA_PAKE_STATE_SETUP) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
if (role != PSA_PAKE_ROLE_NONE &&
role != PSA_PAKE_ROLE_FIRST &&
role != PSA_PAKE_ROLE_SECOND &&
role != PSA_PAKE_ROLE_CLIENT &&
role != PSA_PAKE_ROLE_SERVER) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto error;
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
if (operation->alg == PSA_ALG_JPAKE) {
if (role != PSA_PAKE_ROLE_CLIENT &&
role != PSA_PAKE_ROLE_SERVER) {
return PSA_ERROR_NOT_SUPPORTED;
}
operation->role = role;
return PSA_SUCCESS;
} else
#endif
status = PSA_ERROR_NOT_SUPPORTED;
error:
psa_pake_abort(operation);
return status;
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
static psa_status_t psa_pake_ecjpake_setup(psa_pake_operation_t *operation)
static psa_status_t psa_pake_ecjpake_setup(mbedtls_psa_pake_operation_t *operation)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecjpake_role role;
mbedtls_ecjpake_role role = (operation->role == PSA_PAKE_ROLE_CLIENT) ?
MBEDTLS_ECJPAKE_CLIENT : MBEDTLS_ECJPAKE_SERVER;
if (operation->role == PSA_PAKE_ROLE_CLIENT) {
role = MBEDTLS_ECJPAKE_CLIENT;
} else if (operation->role == PSA_PAKE_ROLE_SERVER) {
role = MBEDTLS_ECJPAKE_SERVER;
} else {
return PSA_ERROR_BAD_STATE;
}
mbedtls_ecjpake_init(&operation->ctx.jpake);
if (operation->password_len == 0) {
return PSA_ERROR_BAD_STATE;
}
ret = mbedtls_ecjpake_setup(&operation->ctx.ecjpake,
ret = mbedtls_ecjpake_setup(&operation->ctx.jpake,
role,
MBEDTLS_MD_SHA256,
MBEDTLS_ECP_DP_SECP256R1,
@ -423,39 +181,101 @@ static psa_status_t psa_pake_ecjpake_setup(psa_pake_operation_t *operation)
operation->password_len);
mbedtls_platform_zeroize(operation->password, operation->password_len);
mbedtls_free(operation->password);
operation->password = NULL;
operation->password_len = 0;
if (ret != 0) {
return mbedtls_ecjpake_to_psa_error(ret);
}
operation->state = PSA_PAKE_STATE_READY;
return PSA_SUCCESS;
}
#endif
static psa_status_t psa_pake_output_internal(
psa_pake_operation_t *operation,
psa_pake_step_t step,
psa_status_t mbedtls_psa_pake_setup(mbedtls_psa_pake_operation_t *operation,
const psa_crypto_driver_pake_inputs_t *inputs)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t password_len = 0;
psa_pake_role_t role = PSA_PAKE_ROLE_NONE;
psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
size_t actual_password_len = 0;
status = psa_crypto_driver_pake_get_password_len(inputs, &password_len);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_crypto_driver_pake_get_role(inputs, &role);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_crypto_driver_pake_get_cipher_suite(inputs, &cipher_suite);
if (status != PSA_SUCCESS) {
return status;
}
operation->password = mbedtls_calloc(1, password_len);
if (operation->password == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
status = psa_crypto_driver_pake_get_password(inputs, operation->password,
password_len, &actual_password_len);
if (status != PSA_SUCCESS) {
goto error;
}
operation->password_len = actual_password_len;
operation->alg = cipher_suite.algorithm;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
if (cipher_suite.algorithm == PSA_ALG_JPAKE) {
if (cipher_suite.type != PSA_PAKE_PRIMITIVE_TYPE_ECC ||
cipher_suite.family != PSA_ECC_FAMILY_SECP_R1 ||
cipher_suite.bits != 256 ||
cipher_suite.hash != PSA_ALG_SHA_256) {
status = PSA_ERROR_NOT_SUPPORTED;
goto error;
}
operation->role = role;
operation->buffer_length = 0;
operation->buffer_offset = 0;
status = psa_pake_ecjpake_setup(operation);
if (status != PSA_SUCCESS) {
goto error;
}
return PSA_SUCCESS;
} else
#else
(void) operation;
(void) inputs;
#endif
{ status = PSA_ERROR_NOT_SUPPORTED; }
error:
/* In case of failure of the setup of a multipart operation, the PSA driver interface
* specifies that the core does not call any other driver entry point thus does not
* call mbedtls_psa_pake_abort(). Therefore call it here to do the needed clean
* up like freeing the memory that may have been allocated to store the password.
*/
mbedtls_psa_pake_abort(operation);
return status;
}
static psa_status_t mbedtls_psa_pake_output_internal(
mbedtls_psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t length;
if (operation->alg == PSA_ALG_NONE ||
operation->state == PSA_PAKE_STATE_INVALID) {
return PSA_ERROR_BAD_STATE;
}
if (output == NULL || output_size == 0 || output_length == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
(void) step; // Unused parameter
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
/*
@ -473,77 +293,11 @@ static psa_status_t psa_pake_output_internal(
* to return the right parts on each step.
*/
if (operation->alg == PSA_ALG_JPAKE) {
if (step != PSA_PAKE_STEP_KEY_SHARE &&
step != PSA_PAKE_STEP_ZK_PUBLIC &&
step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (operation->state == PSA_PAKE_STATE_SETUP) {
status = psa_pake_ecjpake_setup(operation);
if (status != PSA_SUCCESS) {
return status;
}
}
if (operation->state != PSA_PAKE_STATE_READY &&
operation->state != PSA_PAKE_OUTPUT_X1_X2 &&
operation->state != PSA_PAKE_OUTPUT_X2S) {
return PSA_ERROR_BAD_STATE;
}
if (operation->state == PSA_PAKE_STATE_READY) {
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
switch (operation->output_step) {
case PSA_PAKE_STEP_X1_X2:
operation->state = PSA_PAKE_OUTPUT_X1_X2;
break;
case PSA_PAKE_STEP_X2S:
operation->state = PSA_PAKE_OUTPUT_X2S;
break;
default:
return PSA_ERROR_BAD_STATE;
}
operation->sequence = PSA_PAKE_X1_STEP_KEY_SHARE;
}
/* Check if step matches current sequence */
switch (operation->sequence) {
case PSA_PAKE_X1_STEP_KEY_SHARE:
case PSA_PAKE_X2_STEP_KEY_SHARE:
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PUBLIC:
case PSA_PAKE_X2_STEP_ZK_PUBLIC:
if (step != PSA_PAKE_STEP_ZK_PUBLIC) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PROOF:
case PSA_PAKE_X2_STEP_ZK_PROOF:
if (step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_BAD_STATE;
}
break;
default:
return PSA_ERROR_BAD_STATE;
}
/* Initialize & write round on KEY_SHARE sequences */
if (operation->state == PSA_PAKE_OUTPUT_X1_X2 &&
operation->sequence == PSA_PAKE_X1_STEP_KEY_SHARE) {
ret = mbedtls_ecjpake_write_round_one(&operation->ctx.ecjpake,
if (step == PSA_JPAKE_X1_STEP_KEY_SHARE) {
ret = mbedtls_ecjpake_write_round_one(&operation->ctx.jpake,
operation->buffer,
MBEDTLS_PSA_PAKE_BUFFER_SIZE,
sizeof(operation->buffer),
&operation->buffer_length,
mbedtls_psa_get_random,
MBEDTLS_PSA_RANDOM_STATE);
@ -552,11 +306,10 @@ static psa_status_t psa_pake_output_internal(
}
operation->buffer_offset = 0;
} else if (operation->state == PSA_PAKE_OUTPUT_X2S &&
operation->sequence == PSA_PAKE_X1_STEP_KEY_SHARE) {
ret = mbedtls_ecjpake_write_round_two(&operation->ctx.ecjpake,
} else if (step == PSA_JPAKE_X2S_STEP_KEY_SHARE) {
ret = mbedtls_ecjpake_write_round_two(&operation->ctx.jpake,
operation->buffer,
MBEDTLS_PSA_PAKE_BUFFER_SIZE,
sizeof(operation->buffer),
&operation->buffer_length,
mbedtls_psa_get_random,
MBEDTLS_PSA_RANDOM_STATE);
@ -578,8 +331,7 @@ static psa_status_t psa_pake_output_internal(
* output with a length byte, even less a curve identifier, as that
* information is already available.
*/
if (operation->state == PSA_PAKE_OUTPUT_X2S &&
operation->sequence == PSA_PAKE_X1_STEP_KEY_SHARE &&
if (step == PSA_JPAKE_X2S_STEP_KEY_SHARE &&
operation->role == PSA_PAKE_ROLE_SERVER) {
/* Skip ECParameters, with is 3 bytes (RFC 8422) */
operation->buffer_offset += 3;
@ -605,60 +357,44 @@ static psa_status_t psa_pake_output_internal(
operation->buffer_offset += length;
/* Reset buffer after ZK_PROOF sequence */
if ((operation->state == PSA_PAKE_OUTPUT_X1_X2 &&
operation->sequence == PSA_PAKE_X2_STEP_ZK_PROOF) ||
(operation->state == PSA_PAKE_OUTPUT_X2S &&
operation->sequence == PSA_PAKE_X1_STEP_ZK_PROOF)) {
mbedtls_platform_zeroize(operation->buffer, MBEDTLS_PSA_PAKE_BUFFER_SIZE);
if ((step == PSA_JPAKE_X2_STEP_ZK_PROOF) ||
(step == PSA_JPAKE_X2S_STEP_ZK_PROOF)) {
mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer));
operation->buffer_length = 0;
operation->buffer_offset = 0;
operation->state = PSA_PAKE_STATE_READY;
operation->output_step++;
operation->sequence = PSA_PAKE_SEQ_INVALID;
} else {
operation->sequence++;
}
return PSA_SUCCESS;
} else
#else
(void) step;
(void) output;
(void) output_size;
(void) output_length;
#endif
return PSA_ERROR_NOT_SUPPORTED;
{ return PSA_ERROR_NOT_SUPPORTED; }
}
psa_status_t psa_pake_output(psa_pake_operation_t *operation,
psa_pake_step_t step,
uint8_t *output,
size_t output_size,
size_t *output_length)
psa_status_t mbedtls_psa_pake_output(mbedtls_psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_status_t status = psa_pake_output_internal(
psa_status_t status = mbedtls_psa_pake_output_internal(
operation, step, output, output_size, output_length);
if (status != PSA_SUCCESS) {
psa_pake_abort(operation);
}
return status;
}
static psa_status_t psa_pake_input_internal(
psa_pake_operation_t *operation,
psa_pake_step_t step,
static psa_status_t mbedtls_psa_pake_input_internal(
mbedtls_psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
const uint8_t *input,
size_t input_length)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (operation->alg == PSA_ALG_NONE ||
operation->state == PSA_PAKE_STATE_INVALID) {
return PSA_ERROR_BAD_STATE;
}
if (input == NULL || input_length == 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
(void) step; // Unused parameter
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
/*
@ -677,77 +413,6 @@ static psa_status_t psa_pake_input_internal(
* This causes any input error to be only detected on the last step.
*/
if (operation->alg == PSA_ALG_JPAKE) {
if (step != PSA_PAKE_STEP_KEY_SHARE &&
step != PSA_PAKE_STEP_ZK_PUBLIC &&
step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_INVALID_ARGUMENT;
}
const psa_pake_primitive_t prim = PSA_PAKE_PRIMITIVE(
PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256);
if (input_length > (size_t) PSA_PAKE_INPUT_SIZE(PSA_ALG_JPAKE, prim, step)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (operation->state == PSA_PAKE_STATE_SETUP) {
status = psa_pake_ecjpake_setup(operation);
if (status != PSA_SUCCESS) {
return status;
}
}
if (operation->state != PSA_PAKE_STATE_READY &&
operation->state != PSA_PAKE_INPUT_X1_X2 &&
operation->state != PSA_PAKE_INPUT_X4S) {
return PSA_ERROR_BAD_STATE;
}
if (operation->state == PSA_PAKE_STATE_READY) {
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
switch (operation->input_step) {
case PSA_PAKE_STEP_X1_X2:
operation->state = PSA_PAKE_INPUT_X1_X2;
break;
case PSA_PAKE_STEP_X2S:
operation->state = PSA_PAKE_INPUT_X4S;
break;
default:
return PSA_ERROR_BAD_STATE;
}
operation->sequence = PSA_PAKE_X1_STEP_KEY_SHARE;
}
/* Check if step matches current sequence */
switch (operation->sequence) {
case PSA_PAKE_X1_STEP_KEY_SHARE:
case PSA_PAKE_X2_STEP_KEY_SHARE:
if (step != PSA_PAKE_STEP_KEY_SHARE) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PUBLIC:
case PSA_PAKE_X2_STEP_ZK_PUBLIC:
if (step != PSA_PAKE_STEP_ZK_PUBLIC) {
return PSA_ERROR_BAD_STATE;
}
break;
case PSA_PAKE_X1_STEP_ZK_PROOF:
case PSA_PAKE_X2_STEP_ZK_PROOF:
if (step != PSA_PAKE_STEP_ZK_PROOF) {
return PSA_ERROR_BAD_STATE;
}
break;
default:
return PSA_ERROR_BAD_STATE;
}
/*
* Copy input to local buffer and format it as the Mbed TLS API
* expects, i.e. as defined by draft-cragie-tls-ecjpake-01 section 7.
@ -757,8 +422,7 @@ static psa_status_t psa_pake_input_internal(
* ECParameters structure - which means we have to prepend that when
* we're a client.
*/
if (operation->state == PSA_PAKE_INPUT_X4S &&
operation->sequence == PSA_PAKE_X1_STEP_KEY_SHARE &&
if (step == PSA_JPAKE_X4S_STEP_KEY_SHARE &&
operation->role == PSA_PAKE_ROLE_CLIENT) {
/* We only support secp256r1. */
/* This is the ECParameters structure defined by RFC 8422. */
@ -766,11 +430,26 @@ static psa_status_t psa_pake_input_internal(
3, /* named_curve */
0, 23 /* secp256r1 */
};
if (operation->buffer_length + sizeof(ecparameters) >
sizeof(operation->buffer)) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
memcpy(operation->buffer + operation->buffer_length,
ecparameters, sizeof(ecparameters));
operation->buffer_length += sizeof(ecparameters);
}
/*
* The core checks that input_length is smaller than
* PSA_PAKE_INPUT_MAX_SIZE.
* Thus no risk of integer overflow here.
*/
if (operation->buffer_length + input_length + 1 > sizeof(operation->buffer)) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
/* Write the length byte */
operation->buffer[operation->buffer_length] = (uint8_t) input_length;
operation->buffer_length += 1;
@ -781,25 +460,23 @@ static psa_status_t psa_pake_input_internal(
operation->buffer_length += input_length;
/* Load buffer at each last round ZK_PROOF */
if (operation->state == PSA_PAKE_INPUT_X1_X2 &&
operation->sequence == PSA_PAKE_X2_STEP_ZK_PROOF) {
ret = mbedtls_ecjpake_read_round_one(&operation->ctx.ecjpake,
if (step == PSA_JPAKE_X2_STEP_ZK_PROOF) {
ret = mbedtls_ecjpake_read_round_one(&operation->ctx.jpake,
operation->buffer,
operation->buffer_length);
mbedtls_platform_zeroize(operation->buffer, MBEDTLS_PSA_PAKE_BUFFER_SIZE);
mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer));
operation->buffer_length = 0;
if (ret != 0) {
return mbedtls_ecjpake_to_psa_error(ret);
}
} else if (operation->state == PSA_PAKE_INPUT_X4S &&
operation->sequence == PSA_PAKE_X1_STEP_ZK_PROOF) {
ret = mbedtls_ecjpake_read_round_two(&operation->ctx.ecjpake,
} else if (step == PSA_JPAKE_X4S_STEP_ZK_PROOF) {
ret = mbedtls_ecjpake_read_round_two(&operation->ctx.jpake,
operation->buffer,
operation->buffer_length);
mbedtls_platform_zeroize(operation->buffer, MBEDTLS_PSA_PAKE_BUFFER_SIZE);
mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer));
operation->buffer_length = 0;
if (ret != 0) {
@ -807,113 +484,72 @@ static psa_status_t psa_pake_input_internal(
}
}
if ((operation->state == PSA_PAKE_INPUT_X1_X2 &&
operation->sequence == PSA_PAKE_X2_STEP_ZK_PROOF) ||
(operation->state == PSA_PAKE_INPUT_X4S &&
operation->sequence == PSA_PAKE_X1_STEP_ZK_PROOF)) {
operation->state = PSA_PAKE_STATE_READY;
operation->input_step++;
operation->sequence = PSA_PAKE_SEQ_INVALID;
} else {
operation->sequence++;
}
return PSA_SUCCESS;
} else
#else
(void) step;
(void) input;
(void) input_length;
#endif
return PSA_ERROR_NOT_SUPPORTED;
{ return PSA_ERROR_NOT_SUPPORTED; }
}
psa_status_t psa_pake_input(psa_pake_operation_t *operation,
psa_pake_step_t step,
const uint8_t *input,
size_t input_length)
psa_status_t mbedtls_psa_pake_input(mbedtls_psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
const uint8_t *input,
size_t input_length)
{
psa_status_t status = psa_pake_input_internal(
psa_status_t status = mbedtls_psa_pake_input_internal(
operation, step, input, input_length);
if (status != PSA_SUCCESS) {
psa_pake_abort(operation);
}
return status;
}
psa_status_t psa_pake_get_implicit_key(psa_pake_operation_t *operation,
psa_key_derivation_operation_t *output)
psa_status_t mbedtls_psa_pake_get_implicit_key(
mbedtls_psa_pake_operation_t *operation,
uint8_t *output, size_t output_size,
size_t *output_length)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (operation->alg == PSA_ALG_NONE ||
operation->state != PSA_PAKE_STATE_READY ||
operation->input_step != PSA_PAKE_STEP_DERIVE ||
operation->output_step != PSA_PAKE_STEP_DERIVE) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
if (operation->alg == PSA_ALG_JPAKE) {
ret = mbedtls_ecjpake_write_shared_key(&operation->ctx.ecjpake,
operation->buffer,
MBEDTLS_PSA_PAKE_BUFFER_SIZE,
&operation->buffer_length,
ret = mbedtls_ecjpake_write_shared_key(&operation->ctx.jpake,
output,
output_size,
output_length,
mbedtls_psa_get_random,
MBEDTLS_PSA_RANDOM_STATE);
if (ret != 0) {
psa_pake_abort(operation);
return mbedtls_ecjpake_to_psa_error(ret);
}
status = psa_key_derivation_input_bytes(output,
PSA_KEY_DERIVATION_INPUT_SECRET,
operation->buffer,
operation->buffer_length);
mbedtls_platform_zeroize(operation->buffer, MBEDTLS_PSA_PAKE_BUFFER_SIZE);
psa_pake_abort(operation);
return status;
return PSA_SUCCESS;
} else
#else
(void) output;
#endif
status = PSA_ERROR_NOT_SUPPORTED;
error:
psa_key_derivation_abort(output);
psa_pake_abort(operation);
return status;
{ return PSA_ERROR_NOT_SUPPORTED; }
}
psa_status_t psa_pake_abort(psa_pake_operation_t *operation)
psa_status_t mbedtls_psa_pake_abort(mbedtls_psa_pake_operation_t *operation)
{
if (operation->alg == PSA_ALG_NONE) {
return PSA_SUCCESS;
}
mbedtls_platform_zeroize(operation->password, operation->password_len);
mbedtls_free(operation->password);
operation->password = NULL;
operation->password_len = 0;
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
if (operation->alg == PSA_ALG_JPAKE) {
operation->input_step = PSA_PAKE_STEP_INVALID;
operation->output_step = PSA_PAKE_STEP_INVALID;
if (operation->password_len > 0) {
mbedtls_platform_zeroize(operation->password, operation->password_len);
}
mbedtls_free(operation->password);
operation->password = NULL;
operation->password_len = 0;
operation->role = PSA_PAKE_ROLE_NONE;
mbedtls_platform_zeroize(operation->buffer, MBEDTLS_PSA_PAKE_BUFFER_SIZE);
mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer));
operation->buffer_length = 0;
operation->buffer_offset = 0;
mbedtls_ecjpake_free(&operation->ctx.ecjpake);
mbedtls_ecjpake_free(&operation->ctx.jpake);
}
#endif
operation->alg = PSA_ALG_NONE;
operation->state = PSA_PAKE_STATE_INVALID;
operation->sequence = PSA_PAKE_SEQ_INVALID;
return PSA_SUCCESS;
}

171
library/psa_crypto_pake.h Normal file
View File

@ -0,0 +1,171 @@
/*
* PSA PAKE layer on top of Mbed TLS software crypto
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PSA_CRYPTO_PAKE_H
#define PSA_CRYPTO_PAKE_H
#include <psa/crypto.h>
/** Set the session information for a password-authenticated key exchange.
*
* \note The signature of this function is that of a PSA driver
* pake_setup entry point. This function behaves as a pake_setup
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \param[in,out] operation The operation object to set up. It must have
* been initialized but not set up yet.
* \param[in] inputs Inputs required for PAKE operation (role, password,
* key lifetime, cipher suite)
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_NOT_SUPPORTED
* The algorithm in \p cipher_suite is not a supported PAKE algorithm,
* or the PAKE primitive in \p cipher_suite is not supported or not
* compatible with the PAKE algorithm, or the hash algorithm in
* \p cipher_suite is not supported or not compatible with the PAKE
* algorithm and primitive.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* \retval #PSA_ERROR_CORRUPTION_DETECTED
*/
psa_status_t mbedtls_psa_pake_setup(mbedtls_psa_pake_operation_t *operation,
const psa_crypto_driver_pake_inputs_t *inputs);
/** Get output for a step of a password-authenticated key exchange.
*
* \note The signature of this function is that of a PSA driver
* pake_output entry point. This function behaves as a pake_output
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \param[in,out] operation Active PAKE operation.
* \param step The step of the algorithm for which the output is
* requested.
* \param[out] output Buffer where the output is to be written in the
* format appropriate for this driver \p step. Refer to
* the documentation of psa_crypto_driver_pake_step_t for
* more information.
* \param output_size Size of the \p output buffer in bytes. This must
* be at least #PSA_PAKE_OUTPUT_SIZE(\p alg, \p
* primitive, \p step) where \p alg and
* \p primitive are the PAKE algorithm and primitive
* in the operation's cipher suite, and \p step is
* the output step.
*
* \param[out] output_length On success, the number of bytes of the returned
* output.
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* The size of the \p output buffer is too small.
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* \retval #PSA_ERROR_DATA_CORRUPT
* \retval #PSA_ERROR_DATA_INVALID
*/
psa_status_t mbedtls_psa_pake_output(mbedtls_psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
uint8_t *output,
size_t output_size,
size_t *output_length);
/** Provide input for a step of a password-authenticated key exchange.
*
* \note The signature of this function is that of a PSA driver
* pake_input entry point. This function behaves as a pake_input
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \note The core checks that input_length is smaller than PSA_PAKE_INPUT_MAX_SIZE.
*
* \param[in,out] operation Active PAKE operation.
* \param step The driver step for which the input is provided.
* \param[in] input Buffer containing the input in the format
* appropriate for this \p step. Refer to the
* documentation of psa_crypto_driver_pake_step_t
* for more information.
* \param input_length Size of the \p input buffer in bytes.
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_INVALID_SIGNATURE
* The verification fails for a zero-knowledge input step.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* the \p input is not valid for the \p operation's algorithm, cipher suite
* or \p step.
* \retval #PSA_ERROR_NOT_SUPPORTED
* the \p input is not supported for the \p operation's algorithm, cipher
* suite or \p step.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* \retval #PSA_ERROR_DATA_CORRUPT
* \retval #PSA_ERROR_DATA_INVALID
*/
psa_status_t mbedtls_psa_pake_input(mbedtls_psa_pake_operation_t *operation,
psa_crypto_driver_pake_step_t step,
const uint8_t *input,
size_t input_length);
/** Get implicitly confirmed shared secret from a PAKE.
*
* \note The signature of this function is that of a PSA driver
* pake_get_implicit_key entry point. This function behaves as a
* pake_get_implicit_key entry point as defined in the PSA driver
* interface specification for transparent drivers.
*
* \param[in,out] operation Active PAKE operation.
* \param[out] output Output buffer for implicit key.
* \param output_size Size of the output buffer in bytes.
* \param[out] output_length On success, the number of bytes of the implicit key.
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_NOT_SUPPORTED
* Input from a PAKE is not supported by the algorithm in the \p output
* key derivation operation.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* \retval #PSA_ERROR_DATA_CORRUPT
* \retval #PSA_ERROR_DATA_INVALID
*/
psa_status_t mbedtls_psa_pake_get_implicit_key(
mbedtls_psa_pake_operation_t *operation,
uint8_t *output, size_t output_size,
size_t *output_length);
/** Abort a PAKE operation.
*
* \note The signature of this function is that of a PSA driver
* pake_abort entry point. This function behaves as a pake_abort
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \param[in,out] operation The operation to abort.
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_CORRUPTION_DETECTED
*/
psa_status_t mbedtls_psa_pake_abort(mbedtls_psa_pake_operation_t *operation);
#endif /* PSA_CRYPTO_PAKE_H */