Merge pull request #1119 from davidhorstmann-arm/psa-buffer-copy-fn

Implement buffer copying functions for PSA crypto
This commit is contained in:
Dave Rodgman 2023-11-24 10:46:38 +00:00 committed by GitHub
commit c7cc83cc44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 533 additions and 1 deletions

View File

@ -8428,4 +8428,148 @@ psa_status_t psa_pake_abort(
}
#endif /* PSA_WANT_ALG_SOME_PAKE */
/** Copy from an input buffer to a local copy.
*
* \param[in] input Pointer to input buffer.
* \param[in] input_len Length of the input buffer.
* \param[out] input_copy Pointer to a local copy in which to store the input data.
* \param[out] input_copy_len Length of the local copy buffer.
* \return #PSA_SUCCESS, if the buffer was successfully
* copied.
* \return #PSA_ERROR_CORRUPTION_DETECTED, if the local
* copy is too small to hold contents of the
* input buffer.
*/
MBEDTLS_STATIC_TESTABLE
psa_status_t psa_crypto_copy_input(const uint8_t *input, size_t input_len,
uint8_t *input_copy, size_t input_copy_len)
{
if (input_len > input_copy_len) {
return PSA_ERROR_CORRUPTION_DETECTED;
}
if (input_len > 0) {
memcpy(input_copy, input, input_len);
}
return PSA_SUCCESS;
}
/** Copy from a local output buffer into a user-supplied one.
*
* \param[in] output_copy Pointer to a local buffer containing the output.
* \param[in] output_copy_len Length of the local buffer.
* \param[out] output Pointer to user-supplied output buffer.
* \param[out] output_len Length of the user-supplied output buffer.
* \return #PSA_SUCCESS, if the buffer was successfully
* copied.
* \return #PSA_ERROR_BUFFER_TOO_SMALL, if the
* user-supplied output buffer is too small to
* hold the contents of the local buffer.
*/
MBEDTLS_STATIC_TESTABLE
psa_status_t psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_len,
uint8_t *output, size_t output_len)
{
if (output_len < output_copy_len) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
if (output_copy_len > 0) {
memcpy(output, output_copy, output_copy_len);
}
return PSA_SUCCESS;
}
psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len,
psa_crypto_local_input_t *local_input)
{
psa_status_t status;
*local_input = PSA_CRYPTO_LOCAL_INPUT_INIT;
if (input_len == 0) {
return PSA_SUCCESS;
}
local_input->buffer = mbedtls_calloc(input_len, 1);
if (local_input->buffer == NULL) {
/* Since we dealt with the zero-length case above, we know that
* a NULL return value means a failure of allocation. */
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
/* From now on, we must free local_input->buffer on error. */
local_input->length = input_len;
status = psa_crypto_copy_input(input, input_len,
local_input->buffer, local_input->length);
if (status != PSA_SUCCESS) {
goto error;
}
return PSA_SUCCESS;
error:
mbedtls_free(local_input->buffer);
local_input->buffer = NULL;
local_input->length = 0;
return status;
}
void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input)
{
mbedtls_free(local_input->buffer);
local_input->buffer = NULL;
local_input->length = 0;
}
psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len,
psa_crypto_local_output_t *local_output)
{
*local_output = PSA_CRYPTO_LOCAL_OUTPUT_INIT;
if (output_len == 0) {
return PSA_SUCCESS;
}
local_output->buffer = mbedtls_calloc(output_len, 1);
if (local_output->buffer == NULL) {
/* Since we dealt with the zero-length case above, we know that
* a NULL return value means a failure of allocation. */
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
local_output->length = output_len;
local_output->original = output;
return PSA_SUCCESS;
}
psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output)
{
psa_status_t status;
if (local_output->buffer == NULL) {
local_output->length = 0;
return PSA_SUCCESS;
}
if (local_output->original == NULL) {
/* We have an internal copy but nothing to copy back to. */
return PSA_ERROR_CORRUPTION_DETECTED;
}
status = psa_crypto_copy_output(local_output->buffer, local_output->length,
local_output->original, local_output->length);
if (status != PSA_SUCCESS) {
return status;
}
mbedtls_free(local_output->buffer);
local_output->buffer = NULL;
local_output->length = 0;
return PSA_SUCCESS;
}
#endif /* MBEDTLS_PSA_CRYPTO_C */

View File

@ -842,4 +842,74 @@ psa_status_t mbedtls_psa_verify_hash_complete(
psa_status_t mbedtls_psa_verify_hash_abort(
mbedtls_psa_verify_hash_interruptible_operation_t *operation);
typedef struct psa_crypto_local_input_s {
uint8_t *buffer;
size_t length;
} psa_crypto_local_input_t;
#define PSA_CRYPTO_LOCAL_INPUT_INIT ((psa_crypto_local_input_t) { NULL, 0 })
/** Allocate a local copy of an input buffer and copy the contents into it.
*
* \param[in] input Pointer to input buffer.
* \param[in] input_len Length of the input buffer.
* \param[out] local_input Pointer to a psa_crypto_local_input_t struct
* containing a local input copy.
* \return #PSA_SUCCESS, if the buffer was successfully
* copied.
* \return #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of
* the buffer cannot be allocated.
*/
psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len,
psa_crypto_local_input_t *local_input);
/** Free a local copy of an input buffer.
*
* \param[in] local_input Pointer to a psa_crypto_local_input_t struct
* populated by a previous call to
* psa_crypto_local_input_alloc().
*/
void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input);
typedef struct psa_crypto_local_output_s {
uint8_t *original;
uint8_t *buffer;
size_t length;
} psa_crypto_local_output_t;
#define PSA_CRYPTO_LOCAL_OUTPUT_INIT ((psa_crypto_local_output_t) { NULL, NULL, 0 })
/** Allocate a local copy of an output buffer.
*
* \note This does not copy any data from the original
* output buffer but only allocates a buffer
* whose contents will be copied back to the
* original in a future call to
* psa_crypto_local_output_free().
*
* \param[in] output Pointer to output buffer.
* \param[in] output_len Length of the output buffer.
* \param[out] local_output Pointer to a psa_crypto_local_output_t struct to
* populate with the local output copy.
* \return #PSA_SUCCESS, if the buffer was successfully
* copied.
* \return #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of
* the buffer cannot be allocated.
*/
psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len,
psa_crypto_local_output_t *local_output);
/** Copy from a local copy of an output buffer back to the original, then
* free the local copy.
*
* \param[in] local_output Pointer to a psa_crypto_local_output_t struct
* populated by a previous call to
* psa_crypto_local_output_alloc().
* \return #PSA_SUCCESS, if the local output was
* successfully copied back to the original.
* \return #PSA_ERROR_CORRUPTION_DETECTED, if the output
* could not be copied back to the original.
*/
psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output);
#endif /* PSA_CRYPTO_CORE_H */

View File

@ -72,6 +72,13 @@ psa_status_t mbedtls_psa_crypto_configure_entropy_sources(
psa_status_t psa_mac_key_can_do(
psa_algorithm_t algorithm,
psa_key_type_t key_type);
psa_status_t psa_crypto_copy_input(const uint8_t *input, size_t input_len,
uint8_t *input_copy, size_t input_copy_len);
psa_status_t psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_len,
uint8_t *output, size_t output_len);
#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_PSA_CRYPTO_C */
#endif /* PSA_CRYPTO_INVASIVE_H */

View File

@ -13,7 +13,6 @@
#include "psa/crypto.h"
#include "psa_crypto_slot_management.h"
/* For psa_can_do_hash() */
#include "psa_crypto_core.h"
#include "test/asn1_helpers.h"

View File

@ -0,0 +1,62 @@
PSA input buffer copy: straightforward copy
copy_input:20:20:PSA_SUCCESS
PSA input buffer copy: copy buffer larger than required
copy_input:10:20:PSA_SUCCESS
PSA input buffer copy: copy buffer too small
copy_input:20:10:PSA_ERROR_CORRUPTION_DETECTED
PSA input buffer copy: zero-length source buffer
copy_input:0:10:PSA_SUCCESS
PSA input buffer copy: zero-length both buffers
copy_input:0:0:PSA_SUCCESS
PSA output buffer copy: straightforward copy
copy_output:20:20:PSA_SUCCESS
PSA output buffer copy: output buffer larger than required
copy_output:10:20:PSA_SUCCESS
PSA output buffer copy: output buffer too small
copy_output:20:10:PSA_ERROR_BUFFER_TOO_SMALL
PSA output buffer copy: zero-length source buffer
copy_output:0:10:PSA_SUCCESS
PSA output buffer copy: zero-length both buffers
copy_output:0:0:PSA_SUCCESS
PSA crypto local input alloc
local_input_alloc:200:PSA_SUCCESS
PSA crypto local input alloc, NULL buffer
local_input_alloc:0:PSA_SUCCESS
PSA crypto local input free
local_input_free:200
PSA crypto local input free, NULL buffer
local_input_free:0
PSA crypto local input round-trip
local_input_round_trip
PSA crypto local output alloc
local_output_alloc:200:PSA_SUCCESS
PSA crypto local output alloc, NULL buffer
local_output_alloc:0:PSA_SUCCESS
PSA crypto local output free
local_output_free:200:0:PSA_SUCCESS
PSA crypto local output free, NULL buffer
local_output_free:0:0:PSA_SUCCESS
PSA crypto local output free, NULL original buffer
local_output_free:200:1:PSA_ERROR_CORRUPTION_DETECTED
PSA crypto local output round-trip
local_output_round_trip

View File

@ -0,0 +1,250 @@
/* BEGIN_HEADER */
#include <stdint.h>
#include "common.h"
#include "psa/crypto.h"
#include "psa_crypto_core.h"
#include "psa_crypto_invasive.h"
#include "test/psa_crypto_helpers.h"
/* Helper to fill a buffer with a data pattern. The pattern is not
* important, it just allows a basic check that the correct thing has
* been written, in a way that will detect an error in offset. */
static void fill_buffer_pattern(uint8_t *buffer, size_t len)
{
for (size_t i = 0; i < len; i++) {
buffer[i] = (uint8_t) (i % 256);
}
}
/* END_HEADER */
/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_TEST_HOOKS
* END_DEPENDENCIES
*/
/* BEGIN_CASE */
void copy_input(int src_len, int dst_len, psa_status_t exp_status)
{
uint8_t *src_buffer = NULL;
uint8_t *dst_buffer = NULL;
psa_status_t status;
TEST_CALLOC(src_buffer, src_len);
TEST_CALLOC(dst_buffer, dst_len);
fill_buffer_pattern(src_buffer, src_len);
status = psa_crypto_copy_input(src_buffer, src_len, dst_buffer, dst_len);
TEST_EQUAL(status, exp_status);
if (exp_status == PSA_SUCCESS) {
/* Note: We compare the first src_len bytes of each buffer, as this is what was copied. */
TEST_MEMORY_COMPARE(src_buffer, src_len, dst_buffer, src_len);
}
exit:
mbedtls_free(src_buffer);
mbedtls_free(dst_buffer);
}
/* END_CASE */
/* BEGIN_CASE */
void copy_output(int src_len, int dst_len, psa_status_t exp_status)
{
uint8_t *src_buffer = NULL;
uint8_t *dst_buffer = NULL;
psa_status_t status;
TEST_CALLOC(src_buffer, src_len);
TEST_CALLOC(dst_buffer, dst_len);
fill_buffer_pattern(src_buffer, src_len);
status = psa_crypto_copy_output(src_buffer, src_len, dst_buffer, dst_len);
TEST_EQUAL(status, exp_status);
if (exp_status == PSA_SUCCESS) {
/* Note: We compare the first src_len bytes of each buffer, as this is what was copied. */
TEST_MEMORY_COMPARE(src_buffer, src_len, dst_buffer, src_len);
}
exit:
mbedtls_free(src_buffer);
mbedtls_free(dst_buffer);
}
/* END_CASE */
/* BEGIN_CASE */
void local_input_alloc(int input_len, psa_status_t exp_status)
{
uint8_t *input = NULL;
psa_crypto_local_input_t local_input;
psa_status_t status;
local_input.buffer = NULL;
TEST_CALLOC(input, input_len);
fill_buffer_pattern(input, input_len);
status = psa_crypto_local_input_alloc(input, input_len, &local_input);
TEST_EQUAL(status, exp_status);
if (exp_status == PSA_SUCCESS) {
if (input_len != 0) {
TEST_ASSERT(local_input.buffer != input);
}
TEST_MEMORY_COMPARE(input, input_len,
local_input.buffer, local_input.length);
}
exit:
mbedtls_free(local_input.buffer);
mbedtls_free(input);
}
/* END_CASE */
/* BEGIN_CASE */
void local_input_free(int input_len)
{
psa_crypto_local_input_t local_input;
local_input.buffer = NULL;
local_input.length = input_len;
TEST_CALLOC(local_input.buffer, local_input.length);
psa_crypto_local_input_free(&local_input);
TEST_ASSERT(local_input.buffer == NULL);
TEST_EQUAL(local_input.length, 0);
exit:
mbedtls_free(local_input.buffer);
local_input.buffer = NULL;
local_input.length = 0;
}
/* END_CASE */
/* BEGIN_CASE */
void local_input_round_trip()
{
psa_crypto_local_input_t local_input;
uint8_t input[200];
psa_status_t status;
fill_buffer_pattern(input, sizeof(input));
status = psa_crypto_local_input_alloc(input, sizeof(input), &local_input);
TEST_EQUAL(status, PSA_SUCCESS);
TEST_MEMORY_COMPARE(local_input.buffer, local_input.length,
input, sizeof(input));
TEST_ASSERT(local_input.buffer != input);
psa_crypto_local_input_free(&local_input);
TEST_ASSERT(local_input.buffer == NULL);
TEST_EQUAL(local_input.length, 0);
}
/* END_CASE */
/* BEGIN_CASE */
void local_output_alloc(int output_len, psa_status_t exp_status)
{
uint8_t *output = NULL;
psa_crypto_local_output_t local_output;
psa_status_t status;
local_output.buffer = NULL;
TEST_CALLOC(output, output_len);
status = psa_crypto_local_output_alloc(output, output_len, &local_output);
TEST_EQUAL(status, exp_status);
if (exp_status == PSA_SUCCESS) {
TEST_ASSERT(local_output.original == output);
TEST_EQUAL(local_output.length, output_len);
}
exit:
mbedtls_free(local_output.buffer);
local_output.original = NULL;
local_output.buffer = NULL;
local_output.length = 0;
mbedtls_free(output);
output = NULL;
}
/* END_CASE */
/* BEGIN_CASE */
void local_output_free(int output_len, int original_is_null,
psa_status_t exp_status)
{
uint8_t *output = NULL;
uint8_t *buffer_copy_for_comparison = NULL;
psa_crypto_local_output_t local_output = PSA_CRYPTO_LOCAL_OUTPUT_INIT;
psa_status_t status;
if (!original_is_null) {
TEST_CALLOC(output, output_len);
}
TEST_CALLOC(buffer_copy_for_comparison, output_len);
TEST_CALLOC(local_output.buffer, output_len);
local_output.length = output_len;
local_output.original = output;
if (local_output.length != 0) {
fill_buffer_pattern(local_output.buffer, local_output.length);
memcpy(buffer_copy_for_comparison, local_output.buffer, local_output.length);
}
status = psa_crypto_local_output_free(&local_output);
TEST_EQUAL(status, exp_status);
if (exp_status == PSA_SUCCESS) {
TEST_ASSERT(local_output.buffer == NULL);
TEST_EQUAL(local_output.length, 0);
TEST_MEMORY_COMPARE(buffer_copy_for_comparison, output_len,
output, output_len);
}
exit:
mbedtls_free(output);
mbedtls_free(buffer_copy_for_comparison);
mbedtls_free(local_output.buffer);
local_output.length = 0;
}
/* END_CASE */
/* BEGIN_CASE */
void local_output_round_trip()
{
psa_crypto_local_output_t local_output;
uint8_t output[200];
uint8_t *buffer_copy_for_comparison = NULL;
psa_status_t status;
status = psa_crypto_local_output_alloc(output, sizeof(output), &local_output);
TEST_EQUAL(status, PSA_SUCCESS);
TEST_ASSERT(local_output.buffer != output);
/* Simulate the function generating output */
fill_buffer_pattern(local_output.buffer, local_output.length);
TEST_CALLOC(buffer_copy_for_comparison, local_output.length);
memcpy(buffer_copy_for_comparison, local_output.buffer, local_output.length);
psa_crypto_local_output_free(&local_output);
TEST_ASSERT(local_output.buffer == NULL);
TEST_EQUAL(local_output.length, 0);
/* Check that the buffer was correctly copied back */
TEST_MEMORY_COMPARE(output, sizeof(output),
buffer_copy_for_comparison, sizeof(output));
exit:
mbedtls_free(buffer_copy_for_comparison);
}
/* END_CASE */