mbedtls/tests/suites/test_suite_psa_crypto_pake.function
Gilles Peskine 449bd8303e Switch to the new code style
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
2023-01-11 14:50:10 +01:00

907 lines
40 KiB
C

/* BEGIN_HEADER */
#include <stdint.h>
#include "psa/crypto.h"
typedef enum {
ERR_NONE = 0,
/* errors forced internally in the code */
ERR_INJECT_UNINITIALIZED_ACCESS,
ERR_INJECT_DUPLICATE_SETUP,
ERR_INJECT_INVALID_USER,
ERR_INJECT_INVALID_PEER,
ERR_INJECT_SET_USER,
ERR_INJECT_SET_PEER,
ERR_INJECT_EMPTY_IO_BUFFER,
ERR_INJECT_UNKNOWN_STEP,
ERR_INJECT_INVALID_FIRST_STEP,
ERR_INJECT_WRONG_BUFFER_SIZE,
ERR_INJECT_VALID_OPERATION_AFTER_FAILURE,
ERR_INJECT_ANTICIPATE_KEY_DERIVATION_1,
ERR_INJECT_ANTICIPATE_KEY_DERIVATION_2,
ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1,
ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART1,
ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART1,
ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART2,
ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART2,
ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2,
ERR_INJECT_ROUND2_CLIENT_KEY_SHARE,
ERR_INJECT_ROUND2_CLIENT_ZK_PUBLIC,
ERR_INJECT_ROUND2_CLIENT_ZK_PROOF,
ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1,
ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART1,
ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART1,
ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART2,
ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART2,
ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2,
ERR_INJECT_ROUND2_SERVER_KEY_SHARE,
ERR_INJECT_ROUND2_SERVER_ZK_PUBLIC,
ERR_INJECT_ROUND2_SERVER_ZK_PROOF,
/* erros issued from the .data file */
ERR_IN_SETUP,
ERR_IN_SET_ROLE,
ERR_IN_SET_PASSWORD_KEY,
ERR_IN_INPUT,
ERR_IN_OUTPUT,
} ecjpake_error_stage_t;
typedef enum {
PAKE_ROUND_ONE,
PAKE_ROUND_TWO
} pake_round_t;
/*
* Inject an error on the specified buffer ONLY it this is the correct stage.
* Offset 7 is arbitrary, but chosen because it's "in the middle" of the part
* we're corrupting.
*/
#define DO_ROUND_CONDITIONAL_INJECT(this_stage, buf) \
if (this_stage == err_stage) \
{ \
*(buf + 7) ^= 1; \
}
#define DO_ROUND_UPDATE_OFFSETS(main_buf_offset, step_offset, step_size) \
{ \
step_offset = main_buf_offset; \
main_buf_offset += step_size; \
}
#define DO_ROUND_CHECK_FAILURE() \
if (err_stage != ERR_NONE && status != PSA_SUCCESS) \
{ \
TEST_EQUAL(status, expected_error_arg); \
break; \
} \
else \
{ \
TEST_EQUAL(status, PSA_SUCCESS); \
}
#if defined(PSA_WANT_ALG_JPAKE)
static void ecjpake_do_round(psa_algorithm_t alg, unsigned int primitive,
psa_pake_operation_t *server,
psa_pake_operation_t *client,
int client_input_first,
pake_round_t round,
ecjpake_error_stage_t err_stage,
int expected_error_arg)
{
unsigned char *buffer0 = NULL, *buffer1 = NULL;
size_t buffer_length = (
PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_KEY_SHARE) +
PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PUBLIC) +
PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PROOF)) * 2;
/* The output should be exactly this size according to the spec */
const size_t expected_size_key_share =
PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_KEY_SHARE);
/* The output should be exactly this size according to the spec */
const size_t expected_size_zk_public =
PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PUBLIC);
/* The output can be smaller: the spec allows stripping leading zeroes */
const size_t max_expected_size_zk_proof =
PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PROOF);
size_t buffer0_off = 0;
size_t buffer1_off = 0;
size_t s_g1_len, s_g2_len, s_a_len;
size_t s_g1_off, s_g2_off, s_a_off;
size_t s_x1_pk_len, s_x2_pk_len, s_x2s_pk_len;
size_t s_x1_pk_off, s_x2_pk_off, s_x2s_pk_off;
size_t s_x1_pr_len, s_x2_pr_len, s_x2s_pr_len;
size_t s_x1_pr_off, s_x2_pr_off, s_x2s_pr_off;
size_t c_g1_len, c_g2_len, c_a_len;
size_t c_g1_off, c_g2_off, c_a_off;
size_t c_x1_pk_len, c_x2_pk_len, c_x2s_pk_len;
size_t c_x1_pk_off, c_x2_pk_off, c_x2s_pk_off;
size_t c_x1_pr_len, c_x2_pr_len, c_x2s_pr_len;
size_t c_x1_pr_off, c_x2_pr_off, c_x2s_pr_off;
psa_status_t status;
ASSERT_ALLOC(buffer0, buffer_length);
ASSERT_ALLOC(buffer1, buffer_length);
switch (round) {
case PAKE_ROUND_ONE:
/* Server first round Output */
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + buffer0_off,
512 - buffer0_off, &s_g1_len));
TEST_EQUAL(s_g1_len, expected_size_key_share);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_g1_off, s_g1_len);
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + buffer0_off,
512 - buffer0_off, &s_x1_pk_len));
TEST_EQUAL(s_x1_pk_len, expected_size_zk_public);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART1,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_x1_pk_off, s_x1_pk_len);
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + buffer0_off,
512 - buffer0_off, &s_x1_pr_len));
TEST_LE_U(s_x1_pr_len, max_expected_size_zk_proof);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART1,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_x1_pr_off, s_x1_pr_len);
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + buffer0_off,
512 - buffer0_off, &s_g2_len));
TEST_EQUAL(s_g2_len, expected_size_key_share);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART2,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_g2_off, s_g2_len);
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + buffer0_off,
512 - buffer0_off, &s_x2_pk_len));
TEST_EQUAL(s_x2_pk_len, expected_size_zk_public);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART2,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_x2_pk_off, s_x2_pk_len);
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + buffer0_off,
512 - buffer0_off, &s_x2_pr_len));
TEST_LE_U(s_x2_pr_len, max_expected_size_zk_proof);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_x2_pr_off, s_x2_pr_len);
/*
* When injecting errors in inputs, the implementation is
* free to detect it right away of with a delay.
* This permits delaying the error until the end of the input
* sequence, if no error appears then, this will be treated
* as an error.
*/
if (client_input_first == 1) {
/* Client first round Input */
status = psa_pake_input(client, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + s_g1_off, s_g1_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + s_x1_pk_off,
s_x1_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + s_x1_pr_off,
s_x1_pr_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + s_g2_off,
s_g2_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + s_x2_pk_off,
s_x2_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + s_x2_pr_off,
s_x2_pr_len);
DO_ROUND_CHECK_FAILURE();
/* Error didn't trigger, make test fail */
if ((err_stage >= ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1) &&
(err_stage <= ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2)) {
TEST_ASSERT(
!"One of the last psa_pake_input() calls should have returned the expected error.");
}
}
/* Client first round Output */
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
buffer1 + buffer1_off,
512 - buffer1_off, &c_g1_len));
TEST_EQUAL(c_g1_len, expected_size_key_share);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_g1_off, c_g1_len);
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer1 + buffer1_off,
512 - buffer1_off, &c_x1_pk_len));
TEST_EQUAL(c_x1_pk_len, expected_size_zk_public);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART1,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_x1_pk_off, c_x1_pk_len);
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
buffer1 + buffer1_off,
512 - buffer1_off, &c_x1_pr_len));
TEST_LE_U(c_x1_pr_len, max_expected_size_zk_proof);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART1,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_x1_pr_off, c_x1_pr_len);
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
buffer1 + buffer1_off,
512 - buffer1_off, &c_g2_len));
TEST_EQUAL(c_g2_len, expected_size_key_share);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART2,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_g2_off, c_g2_len);
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer1 + buffer1_off,
512 - buffer1_off, &c_x2_pk_len));
TEST_EQUAL(c_x2_pk_len, expected_size_zk_public);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART2,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_x2_pk_off, c_x2_pk_len);
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
buffer1 + buffer1_off,
512 - buffer1_off, &c_x2_pr_len));
TEST_LE_U(c_x2_pr_len, max_expected_size_zk_proof);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_x2_pr_off, buffer1_off);
if (client_input_first == 0) {
/* Client first round Input */
status = psa_pake_input(client, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + s_g1_off, s_g1_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + s_x1_pk_off,
s_x1_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + s_x1_pr_off,
s_x1_pr_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + s_g2_off,
s_g2_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + s_x2_pk_off,
s_x2_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + s_x2_pr_off,
s_x2_pr_len);
DO_ROUND_CHECK_FAILURE();
/* Error didn't trigger, make test fail */
if ((err_stage >= ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1) &&
(err_stage <= ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2)) {
TEST_ASSERT(
!"One of the last psa_pake_input() calls should have returned the expected error.");
}
}
/* Server first round Input */
status = psa_pake_input(server, PSA_PAKE_STEP_KEY_SHARE,
buffer1 + c_g1_off, c_g1_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(server, PSA_PAKE_STEP_ZK_PUBLIC,
buffer1 + c_x1_pk_off, c_x1_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(server, PSA_PAKE_STEP_ZK_PROOF,
buffer1 + c_x1_pr_off, c_x1_pr_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(server, PSA_PAKE_STEP_KEY_SHARE,
buffer1 + c_g2_off, c_g2_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(server, PSA_PAKE_STEP_ZK_PUBLIC,
buffer1 + c_x2_pk_off, c_x2_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(server, PSA_PAKE_STEP_ZK_PROOF,
buffer1 + c_x2_pr_off, c_x2_pr_len);
DO_ROUND_CHECK_FAILURE();
/* Error didn't trigger, make test fail */
if ((err_stage >= ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1) &&
(err_stage <= ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2)) {
TEST_ASSERT(
!"One of the last psa_pake_input() calls should have returned the expected error.");
}
break;
case PAKE_ROUND_TWO:
/* Server second round Output */
buffer0_off = 0;
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + buffer0_off,
512 - buffer0_off, &s_a_len));
TEST_EQUAL(s_a_len, expected_size_key_share);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND2_SERVER_KEY_SHARE,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_a_off, s_a_len);
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + buffer0_off,
512 - buffer0_off, &s_x2s_pk_len));
TEST_EQUAL(s_x2s_pk_len, expected_size_zk_public);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND2_SERVER_ZK_PUBLIC,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_x2s_pk_off, s_x2s_pk_len);
PSA_ASSERT(psa_pake_output(server, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + buffer0_off,
512 - buffer0_off, &s_x2s_pr_len));
TEST_LE_U(s_x2s_pr_len, max_expected_size_zk_proof);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND2_SERVER_ZK_PROOF,
buffer0 + buffer0_off);
DO_ROUND_UPDATE_OFFSETS(buffer0_off, s_x2s_pr_off, s_x2s_pr_len);
if (client_input_first == 1) {
/* Client second round Input */
status = psa_pake_input(client, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + s_a_off, s_a_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + s_x2s_pk_off,
s_x2s_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + s_x2s_pr_off,
s_x2s_pr_len);
DO_ROUND_CHECK_FAILURE();
/* Error didn't trigger, make test fail */
if ((err_stage >= ERR_INJECT_ROUND2_SERVER_KEY_SHARE) &&
(err_stage <= ERR_INJECT_ROUND2_SERVER_ZK_PROOF)) {
TEST_ASSERT(
!"One of the last psa_pake_input() calls should have returned the expected error.");
}
}
/* Client second round Output */
buffer1_off = 0;
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_KEY_SHARE,
buffer1 + buffer1_off,
512 - buffer1_off, &c_a_len));
TEST_EQUAL(c_a_len, expected_size_key_share);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND2_CLIENT_KEY_SHARE,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_a_off, c_a_len);
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer1 + buffer1_off,
512 - buffer1_off, &c_x2s_pk_len));
TEST_EQUAL(c_x2s_pk_len, expected_size_zk_public);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND2_CLIENT_ZK_PUBLIC,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_x2s_pk_off, c_x2s_pk_len);
PSA_ASSERT(psa_pake_output(client, PSA_PAKE_STEP_ZK_PROOF,
buffer1 + buffer1_off,
512 - buffer1_off, &c_x2s_pr_len));
TEST_LE_U(c_x2s_pr_len, max_expected_size_zk_proof);
DO_ROUND_CONDITIONAL_INJECT(
ERR_INJECT_ROUND2_CLIENT_ZK_PROOF,
buffer1 + buffer1_off);
DO_ROUND_UPDATE_OFFSETS(buffer1_off, c_x2s_pr_off, c_x2s_pr_len);
if (client_input_first == 0) {
/* Client second round Input */
status = psa_pake_input(client, PSA_PAKE_STEP_KEY_SHARE,
buffer0 + s_a_off, s_a_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PUBLIC,
buffer0 + s_x2s_pk_off,
s_x2s_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(client, PSA_PAKE_STEP_ZK_PROOF,
buffer0 + s_x2s_pr_off,
s_x2s_pr_len);
DO_ROUND_CHECK_FAILURE();
/* Error didn't trigger, make test fail */
if ((err_stage >= ERR_INJECT_ROUND2_SERVER_KEY_SHARE) &&
(err_stage <= ERR_INJECT_ROUND2_SERVER_ZK_PROOF)) {
TEST_ASSERT(
!"One of the last psa_pake_input() calls should have returned the expected error.");
}
}
/* Server second round Input */
status = psa_pake_input(server, PSA_PAKE_STEP_KEY_SHARE,
buffer1 + c_a_off, c_a_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(server, PSA_PAKE_STEP_ZK_PUBLIC,
buffer1 + c_x2s_pk_off, c_x2s_pk_len);
DO_ROUND_CHECK_FAILURE();
status = psa_pake_input(server, PSA_PAKE_STEP_ZK_PROOF,
buffer1 + c_x2s_pr_off, c_x2s_pr_len);
DO_ROUND_CHECK_FAILURE();
/* Error didn't trigger, make test fail */
if ((err_stage >= ERR_INJECT_ROUND2_CLIENT_KEY_SHARE) &&
(err_stage <= ERR_INJECT_ROUND2_CLIENT_ZK_PROOF)) {
TEST_ASSERT(
!"One of the last psa_pake_input() calls should have returned the expected error.");
}
break;
}
exit:
mbedtls_free(buffer0);
mbedtls_free(buffer1);
}
#endif /* PSA_WANT_ALG_JPAKE */
/*
* This check is used for functions that might either succeed or fail depending
* on the parameters that are passed in from the *.data file:
* - in case of success following functions depend on the current one
* - in case of failure the test is always terminated. There are two options
* here
* - terminated successfully if this exact error was expected at this stage
* - terminated with failure otherwise (either no error was expected at this
* stage or a different error code was expected)
*/
#define SETUP_ALWAYS_CHECK_STEP(test_function, this_check_err_stage) \
status = test_function; \
if (err_stage != this_check_err_stage) \
{ \
PSA_ASSERT(status); \
} \
else \
{ \
TEST_EQUAL(status, expected_error); \
goto exit; \
}
/*
* This check is used for failures that are injected at code level. There's only
* 1 input parameter that is relevant in this case and it's the stage at which
* the error should be injected.
* The check is conditional in this case because, once the error is triggered,
* the pake's context structure is compromised and the setup function cannot
* proceed further. As a consequence the test is terminated.
* The test succeeds if the returned error is exactly the expected one,
* otherwise it fails.
*/
#define SETUP_CONDITIONAL_CHECK_STEP(test_function, this_check_err_stage) \
if (err_stage == this_check_err_stage) \
{ \
TEST_EQUAL(test_function, expected_error); \
goto exit; \
}
/* END_HEADER */
/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_PSA_CRYPTO_C
* END_DEPENDENCIES
*/
/* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
void ecjpake_setup(int alg_arg, int key_type_pw_arg, int key_usage_pw_arg,
int primitive_arg, int hash_arg, int role_arg,
int test_input,
int err_stage_arg,
int expected_error_arg)
{
psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
psa_pake_operation_t operation = psa_pake_operation_init();
psa_algorithm_t alg = alg_arg;
psa_pake_primitive_t primitive = primitive_arg;
psa_key_type_t key_type_pw = key_type_pw_arg;
psa_key_usage_t key_usage_pw = key_usage_pw_arg;
psa_algorithm_t hash_alg = hash_arg;
psa_pake_role_t role = role_arg;
mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
ecjpake_error_stage_t err_stage = err_stage_arg;
psa_status_t expected_error = expected_error_arg;
psa_status_t status;
unsigned char *output_buffer = NULL;
size_t output_len = 0;
const uint8_t unsupp_id[] = "abcd";
const uint8_t password[] = "abcd";
psa_key_derivation_operation_t key_derivation =
PSA_KEY_DERIVATION_OPERATION_INIT;
PSA_INIT();
size_t buf_size = PSA_PAKE_OUTPUT_SIZE(alg, primitive_arg,
PSA_PAKE_STEP_KEY_SHARE);
ASSERT_ALLOC(output_buffer, buf_size);
psa_set_key_usage_flags(&attributes, key_usage_pw);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_type(&attributes, key_type_pw);
PSA_ASSERT(psa_import_key(&attributes, password, sizeof(password),
&key));
psa_pake_cs_set_algorithm(&cipher_suite, alg);
psa_pake_cs_set_primitive(&cipher_suite, primitive);
psa_pake_cs_set_hash(&cipher_suite, hash_alg);
PSA_ASSERT(psa_pake_abort(&operation));
if (err_stage == ERR_INJECT_UNINITIALIZED_ACCESS) {
TEST_EQUAL(psa_pake_set_user(&operation, NULL, 0),
expected_error);
TEST_EQUAL(psa_pake_set_peer(&operation, NULL, 0),
expected_error);
TEST_EQUAL(psa_pake_set_password_key(&operation, key),
expected_error);
TEST_EQUAL(psa_pake_set_role(&operation, role),
expected_error);
TEST_EQUAL(psa_pake_output(&operation, PSA_PAKE_STEP_KEY_SHARE,
NULL, 0, NULL),
expected_error);
TEST_EQUAL(psa_pake_input(&operation, PSA_PAKE_STEP_KEY_SHARE,
NULL, 0),
expected_error);
TEST_EQUAL(psa_pake_get_implicit_key(&operation, &key_derivation),
expected_error);
goto exit;
}
SETUP_ALWAYS_CHECK_STEP(psa_pake_setup(&operation, &cipher_suite),
ERR_IN_SETUP);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_setup(&operation, &cipher_suite),
ERR_INJECT_DUPLICATE_SETUP);
SETUP_ALWAYS_CHECK_STEP(psa_pake_set_role(&operation, role),
ERR_IN_SET_ROLE);
SETUP_ALWAYS_CHECK_STEP(psa_pake_set_password_key(&operation, key),
ERR_IN_SET_PASSWORD_KEY);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_set_user(&operation, NULL, 0),
ERR_INJECT_INVALID_USER);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_set_peer(&operation, NULL, 0),
ERR_INJECT_INVALID_PEER);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_set_user(&operation, unsupp_id, 4),
ERR_INJECT_SET_USER);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_set_peer(&operation, unsupp_id, 4),
ERR_INJECT_SET_PEER);
const size_t size_key_share = PSA_PAKE_INPUT_SIZE(alg, primitive,
PSA_PAKE_STEP_KEY_SHARE);
const size_t size_zk_public = PSA_PAKE_INPUT_SIZE(alg, primitive,
PSA_PAKE_STEP_ZK_PUBLIC);
const size_t size_zk_proof = PSA_PAKE_INPUT_SIZE(alg, primitive,
PSA_PAKE_STEP_ZK_PROOF);
if (test_input) {
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_input(&operation,
PSA_PAKE_STEP_ZK_PROOF, NULL, 0),
ERR_INJECT_EMPTY_IO_BUFFER);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_input(&operation,
PSA_PAKE_STEP_ZK_PROOF + 10,
output_buffer, size_zk_proof),
ERR_INJECT_UNKNOWN_STEP);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_input(&operation,
PSA_PAKE_STEP_ZK_PROOF,
output_buffer, size_zk_proof),
ERR_INJECT_INVALID_FIRST_STEP)
SETUP_ALWAYS_CHECK_STEP(psa_pake_input(&operation,
PSA_PAKE_STEP_KEY_SHARE,
output_buffer, size_key_share),
ERR_IN_INPUT);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_input(&operation,
PSA_PAKE_STEP_ZK_PUBLIC,
output_buffer, size_zk_public + 1),
ERR_INJECT_WRONG_BUFFER_SIZE);
SETUP_CONDITIONAL_CHECK_STEP(
(psa_pake_input(&operation, PSA_PAKE_STEP_ZK_PUBLIC,
output_buffer, size_zk_public + 1),
psa_pake_input(&operation, PSA_PAKE_STEP_ZK_PUBLIC,
output_buffer, size_zk_public)),
ERR_INJECT_VALID_OPERATION_AFTER_FAILURE);
} else {
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_output(&operation,
PSA_PAKE_STEP_ZK_PROOF,
NULL, 0, NULL),
ERR_INJECT_EMPTY_IO_BUFFER);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_output(&operation,
PSA_PAKE_STEP_ZK_PROOF + 10,
output_buffer, buf_size, &output_len),
ERR_INJECT_UNKNOWN_STEP);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_output(&operation,
PSA_PAKE_STEP_ZK_PROOF,
output_buffer, buf_size, &output_len),
ERR_INJECT_INVALID_FIRST_STEP);
SETUP_ALWAYS_CHECK_STEP(psa_pake_output(&operation,
PSA_PAKE_STEP_KEY_SHARE,
output_buffer, buf_size, &output_len),
ERR_IN_OUTPUT);
TEST_ASSERT(output_len > 0);
SETUP_CONDITIONAL_CHECK_STEP(psa_pake_output(&operation,
PSA_PAKE_STEP_ZK_PUBLIC,
output_buffer, size_zk_public - 1,
&output_len),
ERR_INJECT_WRONG_BUFFER_SIZE);
SETUP_CONDITIONAL_CHECK_STEP(
(psa_pake_output(&operation, PSA_PAKE_STEP_ZK_PUBLIC,
output_buffer, size_zk_public - 1, &output_len),
psa_pake_output(&operation, PSA_PAKE_STEP_ZK_PUBLIC,
output_buffer, buf_size, &output_len)),
ERR_INJECT_VALID_OPERATION_AFTER_FAILURE);
}
exit:
PSA_ASSERT(psa_destroy_key(key));
PSA_ASSERT(psa_pake_abort(&operation));
mbedtls_free(output_buffer);
PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
void ecjpake_rounds_inject(int alg_arg, int primitive_arg, int hash_arg,
int client_input_first,
data_t *pw_data,
int err_stage_arg,
int expected_error_arg)
{
psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
psa_pake_operation_t server = psa_pake_operation_init();
psa_pake_operation_t client = psa_pake_operation_init();
psa_algorithm_t alg = alg_arg;
psa_algorithm_t hash_alg = hash_arg;
mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
ecjpake_error_stage_t err_stage = err_stage_arg;
PSA_INIT();
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD);
PSA_ASSERT(psa_import_key(&attributes, pw_data->x, pw_data->len,
&key));
psa_pake_cs_set_algorithm(&cipher_suite, alg);
psa_pake_cs_set_primitive(&cipher_suite, primitive_arg);
psa_pake_cs_set_hash(&cipher_suite, hash_alg);
PSA_ASSERT(psa_pake_setup(&server, &cipher_suite));
PSA_ASSERT(psa_pake_setup(&client, &cipher_suite));
PSA_ASSERT(psa_pake_set_role(&server, PSA_PAKE_ROLE_SERVER));
PSA_ASSERT(psa_pake_set_role(&client, PSA_PAKE_ROLE_CLIENT));
PSA_ASSERT(psa_pake_set_password_key(&server, key));
PSA_ASSERT(psa_pake_set_password_key(&client, key));
ecjpake_do_round(alg, primitive_arg, &server, &client,
client_input_first, PAKE_ROUND_ONE,
err_stage, expected_error_arg);
if (err_stage != ERR_NONE) {
goto exit;
}
ecjpake_do_round(alg, primitive_arg, &server, &client,
client_input_first, PAKE_ROUND_TWO,
err_stage, expected_error_arg);
exit:
psa_destroy_key(key);
psa_pake_abort(&server);
psa_pake_abort(&client);
PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
void ecjpake_rounds(int alg_arg, int primitive_arg, int hash_arg,
int derive_alg_arg, data_t *pw_data,
int client_input_first, int destroy_key,
int err_stage_arg)
{
psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
psa_pake_operation_t server = psa_pake_operation_init();
psa_pake_operation_t client = psa_pake_operation_init();
psa_algorithm_t alg = alg_arg;
psa_algorithm_t hash_alg = hash_arg;
psa_algorithm_t derive_alg = derive_alg_arg;
mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_derivation_operation_t server_derive =
PSA_KEY_DERIVATION_OPERATION_INIT;
psa_key_derivation_operation_t client_derive =
PSA_KEY_DERIVATION_OPERATION_INIT;
ecjpake_error_stage_t err_stage = err_stage_arg;
PSA_INIT();
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD);
PSA_ASSERT(psa_import_key(&attributes, pw_data->x, pw_data->len,
&key));
psa_pake_cs_set_algorithm(&cipher_suite, alg);
psa_pake_cs_set_primitive(&cipher_suite, primitive_arg);
psa_pake_cs_set_hash(&cipher_suite, hash_alg);
/* Get shared key */
PSA_ASSERT(psa_key_derivation_setup(&server_derive, derive_alg));
PSA_ASSERT(psa_key_derivation_setup(&client_derive, derive_alg));
if (PSA_ALG_IS_TLS12_PRF(derive_alg) ||
PSA_ALG_IS_TLS12_PSK_TO_MS(derive_alg)) {
PSA_ASSERT(psa_key_derivation_input_bytes(&server_derive,
PSA_KEY_DERIVATION_INPUT_SEED,
(const uint8_t *) "", 0));
PSA_ASSERT(psa_key_derivation_input_bytes(&client_derive,
PSA_KEY_DERIVATION_INPUT_SEED,
(const uint8_t *) "", 0));
}
PSA_ASSERT(psa_pake_setup(&server, &cipher_suite));
PSA_ASSERT(psa_pake_setup(&client, &cipher_suite));
PSA_ASSERT(psa_pake_set_role(&server, PSA_PAKE_ROLE_SERVER));
PSA_ASSERT(psa_pake_set_role(&client, PSA_PAKE_ROLE_CLIENT));
PSA_ASSERT(psa_pake_set_password_key(&server, key));
PSA_ASSERT(psa_pake_set_password_key(&client, key));
if (destroy_key == 1) {
psa_destroy_key(key);
}
if (err_stage == ERR_INJECT_ANTICIPATE_KEY_DERIVATION_1) {
TEST_EQUAL(psa_pake_get_implicit_key(&server, &server_derive),
PSA_ERROR_BAD_STATE);
TEST_EQUAL(psa_pake_get_implicit_key(&client, &client_derive),
PSA_ERROR_BAD_STATE);
goto exit;
}
/* First round */
ecjpake_do_round(alg, primitive_arg, &server, &client,
client_input_first, PAKE_ROUND_ONE,
ERR_NONE, PSA_SUCCESS);
if (err_stage == ERR_INJECT_ANTICIPATE_KEY_DERIVATION_2) {
TEST_EQUAL(psa_pake_get_implicit_key(&server, &server_derive),
PSA_ERROR_BAD_STATE);
TEST_EQUAL(psa_pake_get_implicit_key(&client, &client_derive),
PSA_ERROR_BAD_STATE);
goto exit;
}
/* Second round */
ecjpake_do_round(alg, primitive_arg, &server, &client,
client_input_first, PAKE_ROUND_TWO,
ERR_NONE, PSA_SUCCESS);
PSA_ASSERT(psa_pake_get_implicit_key(&server, &server_derive));
PSA_ASSERT(psa_pake_get_implicit_key(&client, &client_derive));
exit:
psa_key_derivation_abort(&server_derive);
psa_key_derivation_abort(&client_derive);
psa_destroy_key(key);
psa_pake_abort(&server);
psa_pake_abort(&client);
PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE */
void ecjpake_size_macros()
{
const psa_algorithm_t alg = PSA_ALG_JPAKE;
const size_t bits = 256;
const psa_pake_primitive_t prim = PSA_PAKE_PRIMITIVE(
PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, bits);
const psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(
PSA_ECC_FAMILY_SECP_R1);
// https://armmbed.github.io/mbed-crypto/1.1_PAKE_Extension.0-bet.0/html/pake.html#pake-step-types
/* The output for KEY_SHARE and ZK_PUBLIC is the same as a public key */
TEST_EQUAL(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, bits));
TEST_EQUAL(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, bits));
/* The output for ZK_PROOF is the same bitsize as the curve */
TEST_EQUAL(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
PSA_BITS_TO_BYTES(bits));
/* Input sizes are the same as output sizes */
TEST_EQUAL(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE));
TEST_EQUAL(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC));
TEST_EQUAL(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF));
/* These inequalities will always hold even when other PAKEs are added */
TEST_LE_U(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
PSA_PAKE_OUTPUT_MAX_SIZE);
TEST_LE_U(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
PSA_PAKE_OUTPUT_MAX_SIZE);
TEST_LE_U(PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
PSA_PAKE_OUTPUT_MAX_SIZE);
TEST_LE_U(PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
PSA_PAKE_INPUT_MAX_SIZE);
TEST_LE_U(PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
PSA_PAKE_INPUT_MAX_SIZE);
TEST_LE_U(PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
PSA_PAKE_INPUT_MAX_SIZE);
}
/* END_CASE */