mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2026-03-30 00:51:06 +02:00
311 lines
12 KiB
C
311 lines
12 KiB
C
/* BEGIN_HEADER */
|
|
/* Positive test cases for PSA crypto APIs that assert constant-time
|
|
* (more accurately constant-flow) behavior. */
|
|
|
|
#include <psa/crypto.h>
|
|
#include <test/constant_flow.h>
|
|
|
|
/* Our software AES implementation is not constant-time. For constant-time
|
|
* testing involving AES, require a hardware-assisted AES that is
|
|
* constant-time.
|
|
*
|
|
* We assume that if the hardware-assisted version is available in the build,
|
|
* it will be available at runtime. The AES tests will fail if run on a
|
|
* processor without AESNI/AESCE.
|
|
*/
|
|
#include "aesce.h"
|
|
#include "aesni.h"
|
|
#if defined(MBEDTLS_AESCE_HAVE_CODE) || defined(MBEDTLS_AESNI_HAVE_CODE)
|
|
#define HAVE_CONSTANT_TIME_AES
|
|
#endif
|
|
|
|
static int ct_cipher_multipart(psa_cipher_operation_t *operation,
|
|
const data_t *iv,
|
|
const data_t *input,
|
|
size_t output_size,
|
|
const data_t *expected_output,
|
|
psa_status_t expected_finish_status)
|
|
{
|
|
unsigned char *output = NULL;
|
|
size_t update_length = SIZE_MAX;
|
|
size_t finish_length = SIZE_MAX;
|
|
psa_status_t status;
|
|
int ok = 0;
|
|
|
|
TEST_CALLOC(output, output_size);
|
|
|
|
PSA_ASSERT(psa_cipher_set_iv(operation, iv->x, iv->len));
|
|
status = psa_cipher_update(operation,
|
|
input->x, input->len,
|
|
output, output_size, &update_length);
|
|
if (expected_finish_status == PSA_ERROR_BUFFER_TOO_SMALL &&
|
|
status == PSA_ERROR_BUFFER_TOO_SMALL) {
|
|
/* The output buffer is already too small for update. That's ok. */
|
|
ok = 1;
|
|
goto exit;
|
|
} else {
|
|
PSA_ASSERT(status);
|
|
}
|
|
TEST_LE_U(update_length, output_size);
|
|
TEST_EQUAL(psa_cipher_finish(operation,
|
|
output + update_length,
|
|
output_size - update_length,
|
|
&finish_length),
|
|
expected_finish_status);
|
|
|
|
TEST_CF_PUBLIC(output, output_size);
|
|
if (expected_finish_status == PSA_SUCCESS) {
|
|
TEST_MEMORY_COMPARE(expected_output->x, expected_output->len,
|
|
output, update_length + finish_length);
|
|
}
|
|
ok = 1;
|
|
|
|
exit:
|
|
mbedtls_free(output);
|
|
psa_cipher_abort(operation);
|
|
return ok;
|
|
}
|
|
|
|
static int ct_cipher_decrypt_oneshot(mbedtls_svc_key_id_t key,
|
|
psa_algorithm_t alg,
|
|
const data_t *input,
|
|
size_t output_size,
|
|
const data_t *expected_output,
|
|
psa_status_t expected_status)
|
|
{
|
|
unsigned char *output = NULL;
|
|
size_t output_length = SIZE_MAX;
|
|
int ok = 0;
|
|
|
|
TEST_CALLOC(output, output_size);
|
|
|
|
TEST_EQUAL(psa_cipher_decrypt(key, alg,
|
|
input->x, input->len,
|
|
output, output_size, &output_length),
|
|
expected_status);
|
|
|
|
TEST_CF_PUBLIC(output, output_size);
|
|
if (expected_status == PSA_SUCCESS) {
|
|
TEST_MEMORY_COMPARE(expected_output->x, expected_output->len,
|
|
output, output_length);
|
|
}
|
|
ok = 1;
|
|
|
|
exit:
|
|
mbedtls_free(output);
|
|
return ok;
|
|
}
|
|
|
|
/* END_HEADER */
|
|
|
|
/* BEGIN_DEPENDENCIES
|
|
* depends_on:MBEDTLS_PSA_CRYPTO_C
|
|
* END_DEPENDENCIES
|
|
*/
|
|
|
|
/* BEGIN_CASE */
|
|
/* Known answer test for cipher multipart encryption.
|
|
* There is no known answer test for one-shot encryption because that
|
|
* uses a random IV. */
|
|
void ct_cipher_encrypt(int alg_arg,
|
|
int key_type_arg, const data_t *key_data,
|
|
const data_t *iv,
|
|
const data_t *plaintext,
|
|
const data_t *expected_ciphertext)
|
|
{
|
|
psa_key_type_t key_type = key_type_arg;
|
|
psa_algorithm_t alg = alg_arg;
|
|
size_t sufficient_output_size =
|
|
PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(key_type, alg, plaintext->len);
|
|
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
|
mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
|
|
psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
|
|
|
|
PSA_INIT();
|
|
TEST_CF_SECRET(key_data->x, key_data->len);
|
|
TEST_CF_SECRET(plaintext->x, plaintext->len);
|
|
//TEST_ASSERT(key_data->x[0] != 42); // uncomment to trip constant-flow test
|
|
|
|
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
|
|
psa_set_key_algorithm(&attributes, alg);
|
|
psa_set_key_type(&attributes, key_type);
|
|
PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len, &key));
|
|
|
|
/* Output buffer too small for the actual output */
|
|
mbedtls_test_set_step(1);
|
|
PSA_ASSERT(psa_cipher_encrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, plaintext,
|
|
expected_ciphertext->len - 1,
|
|
expected_ciphertext,
|
|
PSA_ERROR_BUFFER_TOO_SMALL)) {
|
|
goto exit;
|
|
}
|
|
|
|
if (expected_ciphertext->len < sufficient_output_size) {
|
|
/* For a buffer of intermediate size (between the actual output length
|
|
* and the guaranteed sufficient size), either PSA_SUCCESS or
|
|
* PSA_ERROR_BUFFER_TOO_SMALL is acceptable. Require what the our
|
|
* built-in implementation currently does. */
|
|
psa_status_t intermediate_size_status = PSA_SUCCESS;
|
|
|
|
/* Output buffer size just large enough for the actual output
|
|
* but less than the guaranteed sufficient size */
|
|
mbedtls_test_set_step(2);
|
|
PSA_ASSERT(psa_cipher_encrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, plaintext,
|
|
expected_ciphertext->len,
|
|
expected_ciphertext,
|
|
intermediate_size_status)) {
|
|
goto exit;
|
|
}
|
|
|
|
/* Output buffer size large enough for the actual output
|
|
* but one less than the guaranteed sufficient size */
|
|
mbedtls_test_set_step(3);
|
|
PSA_ASSERT(psa_cipher_encrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, plaintext,
|
|
sufficient_output_size - 1,
|
|
expected_ciphertext,
|
|
intermediate_size_status)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
/* Guaranteed sufficient output buffer size */
|
|
mbedtls_test_set_step(4);
|
|
PSA_ASSERT(psa_cipher_encrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, plaintext,
|
|
sufficient_output_size,
|
|
expected_ciphertext,
|
|
PSA_SUCCESS)) {
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
psa_cipher_abort(&operation);
|
|
psa_destroy_key(key);
|
|
PSA_DONE();
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
/* Known answer for cipher decryption (one-shot and multipart).
|
|
* Supports good cases and invalid padding cases. */
|
|
void ct_cipher_decrypt(int alg_arg,
|
|
int key_type_arg, const data_t *key_data,
|
|
const data_t *iv,
|
|
const data_t *ciphertext,
|
|
const data_t *expected_plaintext,
|
|
int expect_invalid_padding)
|
|
{
|
|
psa_key_type_t key_type = key_type_arg;
|
|
psa_algorithm_t alg = alg_arg;
|
|
size_t sufficient_output_size =
|
|
PSA_CIPHER_DECRYPT_OUTPUT_SIZE(key_type, alg, ciphertext->len);
|
|
psa_status_t expected_status =
|
|
expect_invalid_padding ? PSA_ERROR_INVALID_PADDING : PSA_SUCCESS;
|
|
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
|
mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
|
|
psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
|
|
data_t input = { NULL, iv->len + ciphertext->len };
|
|
|
|
PSA_INIT();
|
|
TEST_CF_SECRET(key_data->x, key_data->len);
|
|
TEST_CF_SECRET(ciphertext->x, ciphertext->len);
|
|
//TEST_ASSERT(key_data->x[0] != 42); // uncomment to trip constant-flow test
|
|
|
|
TEST_CALLOC(input.x, input.len);
|
|
memcpy(input.x, iv->x, iv->len);
|
|
memcpy(input.x + iv->len, ciphertext->x, ciphertext->len);
|
|
|
|
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
|
|
psa_set_key_algorithm(&attributes, alg);
|
|
psa_set_key_type(&attributes, key_type);
|
|
PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len, &key));
|
|
|
|
/* Output buffer too small for the actual output */
|
|
mbedtls_test_set_step(1);
|
|
PSA_ASSERT(psa_cipher_decrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, ciphertext,
|
|
expected_plaintext->len - 1,
|
|
expected_plaintext,
|
|
PSA_ERROR_BUFFER_TOO_SMALL)) {
|
|
goto exit;
|
|
}
|
|
if (!ct_cipher_decrypt_oneshot(key, alg, &input,
|
|
expected_plaintext->len - 1,
|
|
expected_plaintext,
|
|
PSA_ERROR_BUFFER_TOO_SMALL)) {
|
|
goto exit;
|
|
}
|
|
|
|
if (expected_plaintext->len < sufficient_output_size) {
|
|
/* For a buffer of intermediate size (between the actual output length
|
|
* and the guaranteed sufficient size), either PSA_SUCCESS (or
|
|
* PSA_ERROR_INVALID_PADDING if the padding is invalid) or
|
|
* PSA_ERROR_BUFFER_TOO_SMALL is acceptable. Require what the our
|
|
* built-in implementation currently does. */
|
|
psa_status_t intermediate_size_status = expected_status;
|
|
if (alg == PSA_ALG_CBC_PKCS7) {
|
|
intermediate_size_status = PSA_ERROR_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
/* Output buffer size just large enough for the actual output
|
|
* but less than the guaranteed sufficient size */
|
|
mbedtls_test_set_step(2);
|
|
PSA_ASSERT(psa_cipher_decrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, ciphertext,
|
|
expected_plaintext->len,
|
|
expected_plaintext,
|
|
intermediate_size_status)) {
|
|
goto exit;
|
|
}
|
|
if (!ct_cipher_decrypt_oneshot(key, alg, &input,
|
|
expected_plaintext->len - 1,
|
|
expected_plaintext,
|
|
intermediate_size_status)) {
|
|
goto exit;
|
|
}
|
|
|
|
/* Output buffer size large enough for the actual output
|
|
* but one less than the guaranteed sufficient size */
|
|
mbedtls_test_set_step(3);
|
|
PSA_ASSERT(psa_cipher_decrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, ciphertext,
|
|
sufficient_output_size - 1,
|
|
expected_plaintext,
|
|
intermediate_size_status)) {
|
|
goto exit;
|
|
}
|
|
if (!ct_cipher_decrypt_oneshot(key, alg, &input,
|
|
sufficient_output_size - 1,
|
|
expected_plaintext,
|
|
intermediate_size_status)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
/* Guaranteed sufficient output buffer size */
|
|
mbedtls_test_set_step(4);
|
|
PSA_ASSERT(psa_cipher_decrypt_setup(&operation, key, alg));
|
|
if (!ct_cipher_multipart(&operation, iv, ciphertext,
|
|
sufficient_output_size,
|
|
expected_plaintext,
|
|
expected_status)) {
|
|
goto exit;
|
|
}
|
|
if (!ct_cipher_decrypt_oneshot(key, alg, &input,
|
|
sufficient_output_size,
|
|
expected_plaintext,
|
|
expected_status)) {
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
mbedtls_free(input.x);
|
|
psa_cipher_abort(&operation);
|
|
psa_destroy_key(key);
|
|
PSA_DONE();
|
|
}
|
|
/* END_CASE */
|