From 1d26709dbd4a4f8ef9ea0ff58f2644a4bc3fc49c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 28 Jan 2018 18:13:03 +0100 Subject: [PATCH 01/36] New function mbedtls_rsa_get_bitlen Add a new function mbedtls_rsa_get_bitlen which returns the RSA key size, i.e. the bit size of the modulus. In the pk module, call mbedtls_rsa_get_bitlen instead of mbedtls_rsa_get_len, which gave the wrong result for key sizes that are not a multiple of 8. This commit adds one non-regression test in the pk suite. More tests are needed for RSA key sizes that are a multiple of 8. This commit does not address RSA alternative implementations, which only provide an interface that return the modulus size in bytes. --- include/mbedtls/rsa.h | 10 +++++++ library/pk_wrap.c | 2 +- library/rsa.c | 9 ++++++- tests/suites/test_suite_pk.data | 11 +++++++- tests/suites/test_suite_pk.function | 39 +++++++++++++++++++++++----- tests/suites/test_suite_rsa.function | 27 ++++++++++++------- 6 files changed, 80 insertions(+), 18 deletions(-) diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h index 6eea5af2f..31a8db757 100644 --- a/include/mbedtls/rsa.h +++ b/include/mbedtls/rsa.h @@ -403,6 +403,16 @@ void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, */ size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ); +/** + * \brief This function retrieves the length of the RSA modulus in bits. + * + * \param ctx The initialized RSA context. + * + * \return The length of the RSA modulus in bits. + * + */ +size_t mbedtls_rsa_get_bitlen( const mbedtls_rsa_context *ctx ); + /** * \brief This function generates an RSA keypair. * diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 2c7d2d79b..f9b4c659c 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -66,7 +66,7 @@ static int rsa_can_do( mbedtls_pk_type_t type ) static size_t rsa_get_bitlen( const void *ctx ) { const mbedtls_rsa_context * rsa = (const mbedtls_rsa_context *) ctx; - return( 8 * mbedtls_rsa_get_len( rsa ) ); + return( mbedtls_rsa_get_bitlen( rsa ) ); } static int rsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, diff --git a/library/rsa.c b/library/rsa.c index 88c1cf100..ad196391f 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -480,12 +480,19 @@ void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id /* * Get length in bytes of RSA modulus */ - size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ) { return( ctx->len ); } +/* + * Get length in bits of RSA modulus + */ +size_t mbedtls_rsa_get_bitlen( const mbedtls_rsa_context *ctx ) +{ + return( mbedtls_mpi_bitlen( &ctx->N ) ); +} + #if defined(MBEDTLS_GENPRIME) diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data index a066bd93e..77e3bd887 100644 --- a/tests/suites/test_suite_pk.data +++ b/tests/suites/test_suite_pk.data @@ -1,7 +1,16 @@ -PK utils: RSA +PK utils: RSA, 512 bits depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME pk_utils:MBEDTLS_PK_RSA:512:64:"RSA" +## RSA key generation only supports even bit sizes +#PK utils: RSA, 511 bits +#depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME +#pk_utils:MBEDTLS_PK_RSA:511:64:"RSA" +# +PK utils: RSA, 510 bits +depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME +pk_utils:MBEDTLS_PK_RSA:510:64:"RSA" + PK utils: ECKEY depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED pk_utils:MBEDTLS_PK_ECKEY:192:24:"EC" diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index 9005ddb31..a1d9b0b7a 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -13,13 +13,18 @@ static int rnd_std_rand( void *rng_state, unsigned char *output, size_t len ); #define RSA_KEY_SIZE 512 #define RSA_KEY_LEN 64 -static int pk_genkey( mbedtls_pk_context *pk ) +static int pk_genkey( mbedtls_pk_context *pk, int size ) { ((void) pk); #if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_GENPRIME) if( mbedtls_pk_get_type( pk ) == MBEDTLS_PK_RSA ) - return mbedtls_rsa_gen_key( mbedtls_pk_rsa( *pk ), rnd_std_rand, NULL, RSA_KEY_SIZE, 3 ); + { + if( size == 0 ) + size = RSA_KEY_SIZE; + return( mbedtls_rsa_gen_key( mbedtls_pk_rsa( *pk ), + rnd_std_rand, NULL, size, 3 ) ); + } #endif #if defined(MBEDTLS_ECP_C) if( mbedtls_pk_get_type( pk ) == MBEDTLS_PK_ECKEY || @@ -27,8 +32,30 @@ static int pk_genkey( mbedtls_pk_context *pk ) mbedtls_pk_get_type( pk ) == MBEDTLS_PK_ECDSA ) { int ret; + mbedtls_ecp_group_id curve; + switch( size ) + { + case 0: + case 192: + curve = MBEDTLS_ECP_DP_SECP192R1; + break; + case 224: + curve = MBEDTLS_ECP_DP_SECP224R1; + break; + case 256: + curve = MBEDTLS_ECP_DP_SECP256R1; + break; + case 384: + curve = MBEDTLS_ECP_DP_SECP384R1; + break; + case 521: + curve = MBEDTLS_ECP_DP_SECP521R1; + break; + default: + return( -1 ); + } if( ( ret = mbedtls_ecp_group_load( &mbedtls_pk_ec( *pk )->grp, - MBEDTLS_ECP_DP_SECP192R1 ) ) != 0 ) + curve ) ) != 0 ) return( ret ); return mbedtls_ecp_gen_keypair( &mbedtls_pk_ec( *pk )->grp, &mbedtls_pk_ec( *pk )->d, @@ -77,7 +104,7 @@ void pk_utils( int type, int size, int len, char * name ) mbedtls_pk_init( &pk ); TEST_ASSERT( mbedtls_pk_setup( &pk, mbedtls_pk_info_from_type( type ) ) == 0 ); - TEST_ASSERT( pk_genkey( &pk ) == 0 ); + TEST_ASSERT( pk_genkey( &pk, size ) == 0 ); TEST_ASSERT( (int) mbedtls_pk_get_type( &pk ) == type ); TEST_ASSERT( mbedtls_pk_can_do( &pk, type ) ); @@ -252,7 +279,7 @@ void pk_sign_verify( int type, int sign_ret, int verify_ret ) memset( sig, 0, sizeof sig ); TEST_ASSERT( mbedtls_pk_setup( &pk, mbedtls_pk_info_from_type( type ) ) == 0 ); - TEST_ASSERT( pk_genkey( &pk ) == 0 ); + TEST_ASSERT( pk_genkey( &pk, 0 ) == 0 ); TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256, hash, sizeof hash, sig, &sig_len, rnd_std_rand, NULL ) == sign_ret ); @@ -447,7 +474,7 @@ void pk_rsa_alt( ) /* Initiliaze PK RSA context with random key */ TEST_ASSERT( mbedtls_pk_setup( &rsa, mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); - TEST_ASSERT( pk_genkey( &rsa ) == 0 ); + TEST_ASSERT( pk_genkey( &rsa, RSA_KEY_SIZE ) == 0 ); /* Extract key to the raw rsa context */ TEST_ASSERT( mbedtls_rsa_copy( &raw, mbedtls_pk_rsa( rsa ) ) == 0 ); diff --git a/tests/suites/test_suite_rsa.function b/tests/suites/test_suite_rsa.function index c43ef2050..46c8bf96e 100644 --- a/tests/suites/test_suite_rsa.function +++ b/tests/suites/test_suite_rsa.function @@ -44,7 +44,8 @@ void mbedtls_rsa_pkcs1_sign( data_t * message_str, int padding_mode, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, &P, &Q, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 ); TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 ); @@ -86,7 +87,8 @@ void mbedtls_rsa_pkcs1_verify( data_t * message_str, int padding_mode, TEST_ASSERT( mbedtls_mpi_read_string( &N, radix_N, input_N ) == 0 ); TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, NULL, NULL, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 ); @@ -127,7 +129,8 @@ void rsa_pkcs1_sign_raw( data_t * hash_result, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, &P, &Q, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 ); TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 ); @@ -192,7 +195,8 @@ void rsa_pkcs1_verify_raw( data_t * hash_result, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, NULL, NULL, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 ); @@ -256,7 +260,8 @@ void mbedtls_rsa_pkcs1_encrypt( data_t * message_str, int padding_mode, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, NULL, NULL, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 ); @@ -294,7 +299,8 @@ void rsa_pkcs1_encrypt_bad_rng( data_t * message_str, int padding_mode, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, NULL, NULL, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 ); @@ -342,7 +348,8 @@ void mbedtls_rsa_pkcs1_decrypt( data_t * message_str, int padding_mode, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, &P, &Q, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 ); TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 ); @@ -381,7 +388,8 @@ void mbedtls_rsa_public( data_t * message_str, int mod, int radix_N, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, NULL, NULL, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 ); @@ -440,7 +448,8 @@ void mbedtls_rsa_private( data_t * message_str, int mod, int radix_P, TEST_ASSERT( mbedtls_mpi_read_string( &E, radix_E, input_E ) == 0 ); TEST_ASSERT( mbedtls_rsa_import( &ctx, &N, &P, &Q, NULL, &E ) == 0 ); - TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod / 8 ) ); + TEST_ASSERT( mbedtls_rsa_get_bitlen( &ctx ) == (size_t) mod ); + TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( mod + 7 ) / 8 ); TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 ); TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 ); From 2f9c4dc5ad0fc982c0924b6efc7416a44444e173 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 28 Jan 2018 13:16:24 +0100 Subject: [PATCH 02/36] Add key management functions Define psa_key_type_t and a first stab at a few values. New functions psa_import_key, psa_export_key, psa_destroy_key, psa_get_key_information. Implement them for raw data and RSA. Under the hood, create an in-memory, fixed-size keystore with room for MBEDTLS_PSA_KEY_SLOT_COUNT - 1 keys. --- include/psa/crypto.h | 113 ++++++++++ include/psa/crypto_platform.h | 3 + library/psa_crypto.c | 229 ++++++++++++++++++++ tests/suites/test_suite_psa_crypto.data | 28 +++ tests/suites/test_suite_psa_crypto.function | 120 +++++++++- 5 files changed, 488 insertions(+), 5 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 0bd9c03eb..63f119dc0 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -8,11 +8,27 @@ #include "crypto_platform.h" +#include + #ifdef __DOXYGEN_ONLY__ /** \defgroup platform Implementation-specific definitions * @{ */ +/** \brief Key slot number. + * + * This type represents key slots. It must be an unsigned integral + * type.* The choice of type is implementation-dependent. + * 0 is not a valid key slot number. The meaning of other values is + * implementation dependent. + * + * At any given point in time, each key slot either contains a + * cryptographic object, or is empty. Key slots are persistent: + * once set, the cryptographic object remains in the key slot until + * explicitly destroyed. + */ +typedef _unsigned_integral_type_ psa_key_slot_t; + /**@}*/ #endif @@ -89,6 +105,103 @@ psa_status_t psa_crypto_init(void); /**@}*/ +/** \defgroup crypto_types Key and algorithm types + * @{ + */ + +typedef uint32_t psa_key_type_t; + +#define PSA_KEY_TYPE_NONE 0x00000000 +#define PSA_KEY_TYPE_RAW_DATA 0x00000001 +#define PSA_KEY_TYPE_RSA 0x40000001 +#define PSA_KEY_TYPE_ECC_BASE 0x40010000 + +#define PSA_KEY_TYPE_VENDOR_FLAG 0x80000000 +#define PSA_KEY_TYPE_ASYMMETRIC_FLAG 0x40000000 +#define PSA_KEY_TYPE_ECC_TEST_MASK 0x7fff0000 +#define PSA_KEY_TYPE_ECC_TEST_VALUE 0x40010000 + +#define PSA_KEY_TYPE_IS_VENDOR(type) \ + (((type) & PSA_KEY_TYPE_VENDOR_FLAG) != 0) +#define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \ + (((type) & PSA_KEY_TYPE_ASYMMETRIC_FLAG) != 0) +#define PSA_KEY_TYPE_IS_ECC(type) \ + (((type) & PSA_KEY_TYPE_ECC_TEST_MASK) == PSA_KEY_TYPE_ECC_TEST_VALUE) + +typedef uint32_t psa_algorithm_type_t; + +/**@}*/ + +/** \defgroup key_management Key management + * @{ + */ + +/** + * \brief Import a key in binary format. + * + * This function supports any output from psa_export_key(). + * + * \return * \c PSA_SUCCESS: success. + * * \c PSA_ERROR_NOT_SUPPORTED + * * \c PSA_ERROR_INVALID_ARGUMENT + * * \c PSA_ERROR_INSUFFICIENT_MEMORY + * * \c PSA_ERROR_COMMUNICATION_FAILURE + * * \c PSA_ERROR_HARDWARE_FAILURE + * * \c PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_import_key(psa_key_slot_t key, + psa_key_type_t type, + const uint8_t *data, + size_t data_length); + +/** + * \brief Destroy a key. + * + * \return * \c PSA_SUCCESS: success. + * * \c PSA_ERROR_EMPTY_SLOT + * * \c PSA_ERROR_COMMUNICATION_FAILURE + * * \c PSA_ERROR_HARDWARE_FAILURE + * * \c PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_destroy_key(psa_key_slot_t key); + +/** + * \brief Get basic metadata about a key. + * + * \return * \c PSA_SUCCESS: success. + * * \c PSA_ERROR_EMPTY_SLOT + * * \c PSA_ERROR_COMMUNICATION_FAILURE + * * \c PSA_ERROR_HARDWARE_FAILURE + * * \c PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_get_key_information(psa_key_slot_t key, + psa_key_type_t *type, + size_t *bits); + +/** + * \brief Export a key in binary format. + * + * The output of this function can be passed to psa_import_key() to + * create an equivalent object. + * + * If a key is created with psa_import_key() and then exported with + * this function, it is not guaranteed that the resulting data is + * identical: the implementation may choose a different representation + * of the same key. + * + * \return * \c PSA_SUCCESS: success. + * * \c PSA_ERROR_EMPTY_SLOT + * * \c PSA_ERROR_COMMUNICATION_FAILURE + * * \c PSA_ERROR_HARDWARE_FAILURE + * * \c PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_export_key(psa_key_slot_t key, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/**@}*/ + #ifdef __cplusplus } #endif diff --git a/include/psa/crypto_platform.h b/include/psa/crypto_platform.h index eafc0b3ea..7aabd1bc0 100644 --- a/include/psa/crypto_platform.h +++ b/include/psa/crypto_platform.h @@ -36,4 +36,7 @@ /* PSA requires several types which C99 provides in stdint.h. */ #include +/* Integral type representing a key slot number. */ +typedef uint16_t psa_key_slot_t; + #endif /* PSA_CRYPTO_PLATFORM_H */ diff --git a/library/psa_crypto.c b/library/psa_crypto.c index ca25bb487..31dd0d640 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -29,8 +29,18 @@ #include "psa/crypto.h" +#include +#include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + #include "mbedtls/ctr_drbg.h" #include "mbedtls/entropy.h" +#include "mbedtls/pk.h" /* Implementation that should never be optimized out by the compiler */ @@ -39,10 +49,32 @@ static void mbedtls_zeroize( void *v, size_t n ) volatile unsigned char *p = v; while( n-- ) *p++ = 0; } +/****************************************************************/ +/* Global data, support functions and library management */ +/****************************************************************/ + +/* Number of key slots (plus one because 0 is not used). + * The value is a compile-time constant for now, for simplicity. */ +#define MBEDTLS_PSA_KEY_SLOT_COUNT 32 + +typedef struct { + psa_key_type_t type; + union { + struct raw_data { + uint8_t *data; + size_t bytes; + } raw; +#if defined(MBEDTLS_PK_C) + mbedtls_pk_context pk; +#endif /* MBEDTLS_PK_C */ + } data; +} key_slot_t; + typedef struct { int initialized; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; + key_slot_t key_slots[MBEDTLS_PSA_KEY_SLOT_COUNT]; } psa_global_data_t; static psa_global_data_t global_data; @@ -57,13 +89,210 @@ static psa_status_t mbedtls_to_psa_error( int ret ) case MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE: case MBEDTLS_ERR_ENTROPY_SOURCE_FAILED: return( PSA_ERROR_INSUFFICIENT_ENTROPY ); + case MBEDTLS_ERR_PK_ALLOC_FAILED: + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + case MBEDTLS_ERR_PK_TYPE_MISMATCH: + case MBEDTLS_ERR_PK_BAD_INPUT_DATA: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_PK_FILE_IO_ERROR: + return( PSA_ERROR_TAMPERING_DETECTED ); + case MBEDTLS_ERR_PK_KEY_INVALID_VERSION: + case MBEDTLS_ERR_PK_KEY_INVALID_FORMAT: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_PK_UNKNOWN_PK_ALG: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_PK_PASSWORD_REQUIRED: + case MBEDTLS_ERR_PK_PASSWORD_MISMATCH: + return( PSA_ERROR_NOT_PERMITTED ); + case MBEDTLS_ERR_PK_INVALID_PUBKEY: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_PK_INVALID_ALG: + case MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE: + case MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_PK_SIG_LEN_MISMATCH: + return( PSA_ERROR_INVALID_SIGNATURE ); default: return( PSA_ERROR_UNKNOWN_ERROR ); } } + + +/****************************************************************/ +/* Key management */ +/****************************************************************/ + +psa_status_t psa_import_key(psa_key_slot_t key, + psa_key_type_t type, + const uint8_t *data, + size_t data_length) +{ + key_slot_t *slot; + + if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) + return( PSA_ERROR_INVALID_ARGUMENT ); + slot = &global_data.key_slots[key]; + if( slot->type != PSA_KEY_TYPE_NONE ) + return( PSA_ERROR_OCCUPIED_SLOT ); + + if( type == PSA_KEY_TYPE_RAW_DATA ) + { + if( data_length > SIZE_MAX / 8 ) + return( PSA_ERROR_NOT_SUPPORTED ); + slot->data.raw.data = mbedtls_calloc( 1, data_length ); + if( slot->data.raw.data == NULL ) + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + memcpy( slot->data.raw.data, data, data_length ); + slot->data.raw.bytes = data_length; + } + else +#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) + if( type == PSA_KEY_TYPE_RSA || PSA_KEY_TYPE_IS_ECC( type ) ) + { + int ret; + mbedtls_pk_init( &slot->data.pk ); + ret = mbedtls_pk_parse_key( &slot->data.pk, + data, data_length, + NULL, 0 ); + if( ret != 0 ) + return( mbedtls_to_psa_error( ret ) ); + } + else +#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ + { + return( PSA_ERROR_NOT_SUPPORTED ); + } + + slot->type = type; + return( PSA_SUCCESS ); +} + +psa_status_t psa_destroy_key(psa_key_slot_t key) +{ + key_slot_t *slot; + + if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) + return( PSA_ERROR_INVALID_ARGUMENT ); + slot = &global_data.key_slots[key]; + if( slot->type == PSA_KEY_TYPE_NONE ) + return( PSA_ERROR_EMPTY_SLOT ); + + if( slot->type == PSA_KEY_TYPE_RAW_DATA ) + { + mbedtls_free( slot->data.raw.data ); + } + else +#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) + if( slot->type == PSA_KEY_TYPE_RSA || + PSA_KEY_TYPE_IS_ECC( slot->type ) ) + { + mbedtls_pk_free( &slot->data.pk ); + } + else +#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ + { + /* Shouldn't happen: the key type is not any type that we + * put it. */ + return( PSA_ERROR_TAMPERING_DETECTED ); + } + + mbedtls_zeroize( slot, sizeof( *slot ) ); + return( PSA_SUCCESS ); +} + +psa_status_t psa_get_key_information(psa_key_slot_t key, + psa_key_type_t *type, + size_t *bits) +{ + key_slot_t *slot; + + if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) + return( PSA_ERROR_INVALID_ARGUMENT ); + slot = &global_data.key_slots[key]; + if( type != NULL ) + *type = slot->type; + if( bits != NULL ) + *bits = 0; + if( slot->type == PSA_KEY_TYPE_NONE ) + return( PSA_ERROR_EMPTY_SLOT ); + + if( slot->type == PSA_KEY_TYPE_RAW_DATA ) + { + if( bits != NULL ) + *bits = slot->data.raw.bytes * 8; + } + else +#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) + if( slot->type == PSA_KEY_TYPE_RSA || + PSA_KEY_TYPE_IS_ECC( slot->type ) ) + { + if( bits != NULL ) + *bits = mbedtls_pk_get_bitlen( &slot->data.pk ); + } + else +#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ + { + /* Shouldn't happen: the key type is not any type that we + * put it. */ + return( PSA_ERROR_TAMPERING_DETECTED ); + } + + return( PSA_SUCCESS ); +} + +psa_status_t psa_export_key(psa_key_slot_t key, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + key_slot_t *slot; + + if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) + return( PSA_ERROR_INVALID_ARGUMENT ); + slot = &global_data.key_slots[key]; + if( slot->type == PSA_KEY_TYPE_NONE ) + return( PSA_ERROR_EMPTY_SLOT ); + + if( slot->type == PSA_KEY_TYPE_RAW_DATA ) + { + if( slot->data.raw.bytes > data_size ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + memcpy( data, slot->data.raw.data, slot->data.raw.bytes ); + *data_length = slot->data.raw.bytes; + return( PSA_SUCCESS ); + } + else +#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) + if( slot->type == PSA_KEY_TYPE_RSA || + PSA_KEY_TYPE_IS_ECC( slot->type ) ) + { + int ret; + ret = mbedtls_pk_write_key_der( &slot->data.pk, + data, data_size ); + if( ret < 0 ) + return( mbedtls_to_psa_error( ret ) ); + *data_length = ret; + return( PSA_SUCCESS ); + } + else +#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ + { + return( PSA_ERROR_NOT_SUPPORTED ); + } +} + + + +/****************************************************************/ +/* Module setup */ +/****************************************************************/ + void mbedtls_psa_crypto_free( void ) { + size_t key; + for( key = 1; key < MBEDTLS_PSA_KEY_SLOT_COUNT; key++ ) + psa_destroy_key( key ); mbedtls_ctr_drbg_free( &global_data.ctr_drbg ); mbedtls_entropy_free( &global_data.entropy ); mbedtls_zeroize( &global_data, sizeof( global_data ) ); diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 3d7689bd2..d9149cacf 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -1,2 +1,30 @@ PSA init/deinit init_deinit: + +PSA import/export raw: 0 bytes +import_export:"":PSA_KEY_TYPE_RAW_DATA:0:0:PSA_SUCCESS:1 + +PSA import/export raw: 1 bytes +import_export:"2a":PSA_KEY_TYPE_RAW_DATA:8:0:PSA_SUCCESS:1 + +PSA import/export raw: 1 bytes, larger buffer +import_export:"2a":PSA_KEY_TYPE_RAW_DATA:8:1:PSA_SUCCESS:1 + +PSA import/export raw: 2 bytes, buffer too small +import_export:"2a2b":PSA_KEY_TYPE_RAW_DATA:16:-1:PSA_ERROR_BUFFER_TOO_SMALL:1 + +PSA import/export RSA: good +depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C +import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA:1024:0:PSA_SUCCESS:1 + +PSA import/export RSA: trailing garbage ignored +depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C +import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA:1024:-1:PSA_SUCCESS:0 + +PSA import RSA: truncated +depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C +import:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b":PSA_KEY_TYPE_RSA:PSA_ERROR_INVALID_ARGUMENT + +#PSA import/export EC secp256r1: good +#depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +#import_export:"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_KEY_TYPE_ECC_NISTP256R1:256:0:PSA_SUCCESS:1 diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 9d9eee47b..6fa10dd96 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -10,15 +10,125 @@ /* BEGIN_CASE */ void init_deinit() { - psa_status_t ret; + psa_status_t status; int i; for( i = 0; i <= 1; i++ ) { - ret = psa_crypto_init( ); - TEST_ASSERT( ret == PSA_SUCCESS ); - ret = psa_crypto_init( ); - TEST_ASSERT( ret == PSA_SUCCESS ); + status = psa_crypto_init( ); + TEST_ASSERT( status == PSA_SUCCESS ); + status = psa_crypto_init( ); + TEST_ASSERT( status == PSA_SUCCESS ); mbedtls_psa_crypto_free( ); } } /* END_CASE */ + +/* BEGIN_CASE */ +void import( char *hex, int type, int expected_status ) +{ + int slot = 1; + psa_status_t status; + unsigned char *data = NULL; + size_t data_size; + + data_size = strlen( hex ) / 2; + data = mbedtls_calloc( 1, data_size ); + TEST_ASSERT( data != NULL ); + data_size = unhexify( data, hex ); + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + status = psa_import_key( slot, type, data, data_size ); + TEST_ASSERT( status == (psa_status_t) expected_status ); + if( status == PSA_SUCCESS ) + TEST_ASSERT( psa_destroy_key( slot ) == PSA_SUCCESS ); + +exit: + mbedtls_free( data ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void import_export( char *hex, int type_arg, + int expected_bits, + int export_size_delta, + int expected_export_status, + int canonical_input ) +{ + int slot = 1; + int slot2 = slot + 1; + psa_key_type_t type = type_arg; + psa_status_t status; + unsigned char *data = NULL; + unsigned char *exported = NULL; + unsigned char *reexported = NULL; + size_t data_size; + size_t export_size; + size_t exported_length; + size_t reexported_length; + psa_key_type_t got_type; + size_t got_bits; + + data_size = strlen( hex ) / 2; + data = mbedtls_calloc( 1, data_size ); + TEST_ASSERT( data != NULL ); + data_size = unhexify( data, hex ); + export_size = (ssize_t) data_size + export_size_delta; + exported = mbedtls_calloc( 1, export_size ); + TEST_ASSERT( exported != NULL ); + if( ! canonical_input ) + { + reexported = mbedtls_calloc( 1, export_size ); + TEST_ASSERT( reexported != NULL ); + } + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + /* Import the key */ + TEST_ASSERT( psa_import_key( slot, type, + data, data_size ) == PSA_SUCCESS ); + + /* Test the key information */ + TEST_ASSERT( psa_get_key_information( slot, + &got_type, &got_bits ) == + PSA_SUCCESS ); + TEST_ASSERT( got_type == type ); + TEST_ASSERT( got_bits == (size_t) expected_bits ); + + /* Export the key */ + status = psa_export_key( slot, + exported, export_size, + &exported_length ); + TEST_ASSERT( status == (psa_status_t) expected_export_status ); + if( status != PSA_SUCCESS ) + goto destroy; + + if( canonical_input ) + { + TEST_ASSERT( exported_length == data_size ); + TEST_ASSERT( memcmp( exported, data, data_size ) == 0 ); + } + else + { + TEST_ASSERT( psa_import_key( slot2, type, + exported, export_size ) == + PSA_SUCCESS ); + TEST_ASSERT( psa_export_key( slot2, + reexported, export_size, + &reexported_length ) == + PSA_SUCCESS ); + TEST_ASSERT( reexported_length == exported_length ); + TEST_ASSERT( memcmp( reexported, exported, + exported_length ) == 0 ); + } + +destroy: + /* Destroy the key */ + TEST_ASSERT( psa_destroy_key( slot ) == PSA_SUCCESS ); + TEST_ASSERT( psa_get_key_information( + slot, NULL, NULL ) == PSA_ERROR_EMPTY_SLOT ); + +exit: + mbedtls_free( data ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ From 969ac726d9208c5a21c88a84b1ad955b67b0e63d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 28 Jan 2018 18:16:59 +0100 Subject: [PATCH 03/36] PSA RSA key import: don't rely on pk so much Don't use the pk module except as required for pkparse/pkwrite. The PSA crypto layer is meant to work alongside pk, not on top of it. Fix the compile-time dependencies on RSA/ECP handling in psa_export_key, psa_destroy_key and psa_get_key_information. --- library/psa_crypto.c | 98 +++++++++++++++++++------ tests/suites/test_suite_psa_crypto.data | 6 +- 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 31dd0d640..f6da44e9d 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -39,8 +39,11 @@ #endif #include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecp.h" #include "mbedtls/entropy.h" #include "mbedtls/pk.h" +#include "mbedtls/pk_internal.h" +#include "mbedtls/rsa.h" /* Implementation that should never be optimized out by the compiler */ @@ -64,9 +67,12 @@ typedef struct { uint8_t *data; size_t bytes; } raw; -#if defined(MBEDTLS_PK_C) - mbedtls_pk_context pk; -#endif /* MBEDTLS_PK_C */ +#if defined(MBEDTLS_RSA_C) + mbedtls_rsa_context *rsa; +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + mbedtls_ecp_keypair *ecp; +#endif /* MBEDTLS_ECP_C */ } data; } key_slot_t; @@ -147,19 +153,43 @@ psa_status_t psa_import_key(psa_key_slot_t key, slot->data.raw.bytes = data_length; } else -#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) +#if defined(MBEDTLS_PK_PARSE_C) if( type == PSA_KEY_TYPE_RSA || PSA_KEY_TYPE_IS_ECC( type ) ) { int ret; - mbedtls_pk_init( &slot->data.pk ); - ret = mbedtls_pk_parse_key( &slot->data.pk, - data, data_length, + mbedtls_pk_context pk; + mbedtls_pk_init( &pk ); + ret = mbedtls_pk_parse_key( &pk, data, data_length, NULL, 0 ); if( ret != 0 ) return( mbedtls_to_psa_error( ret ) ); + switch( mbedtls_pk_get_type( &pk ) ) + { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_PK_RSA: + if( type == PSA_KEY_TYPE_RSA ) + slot->data.rsa = pk.pk_ctx; + else + return( PSA_ERROR_INVALID_ARGUMENT ); + break; +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + case MBEDTLS_PK_ECKEY: + if( PSA_KEY_TYPE_IS_ECC( type ) ) + { + // TODO: check curve + slot->data.ecp = pk.pk_ctx; + } + else + return( PSA_ERROR_INVALID_ARGUMENT ); + break; +#endif /* MBEDTLS_ECP_C */ + default: + return( PSA_ERROR_INVALID_ARGUMENT ); + } } else -#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ +#endif /* defined(MBEDTLS_PK_PARSE_C) */ { return( PSA_ERROR_NOT_SUPPORTED ); } @@ -183,14 +213,20 @@ psa_status_t psa_destroy_key(psa_key_slot_t key) mbedtls_free( slot->data.raw.data ); } else -#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) - if( slot->type == PSA_KEY_TYPE_RSA || - PSA_KEY_TYPE_IS_ECC( slot->type ) ) +#if defined(MBEDTLS_RSA_C) + if( slot->type == PSA_KEY_TYPE_RSA ) { - mbedtls_pk_free( &slot->data.pk ); + mbedtls_rsa_free( slot->data.rsa ); } else -#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ +#endif /* defined(MBEDTLS_RSA_C) */ +#if defined(MBEDTLS_ECP_C) + if( PSA_KEY_TYPE_IS_ECC( slot->type ) ) + { + mbedtls_ecp_keypair_free( slot->data.ecp ); + } + else +#endif /* defined(MBEDTLS_ECP_C) */ { /* Shouldn't happen: the key type is not any type that we * put it. */ @@ -223,15 +259,22 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, *bits = slot->data.raw.bytes * 8; } else -#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) - if( slot->type == PSA_KEY_TYPE_RSA || - PSA_KEY_TYPE_IS_ECC( slot->type ) ) +#if defined(MBEDTLS_RSA_C) + if( slot->type == PSA_KEY_TYPE_RSA ) { if( bits != NULL ) - *bits = mbedtls_pk_get_bitlen( &slot->data.pk ); + *bits = mbedtls_rsa_get_bitlen( slot->data.rsa ); } else -#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ +#endif /* defined(MBEDTLS_RSA_C) */ +#if defined(MBEDTLS_ECP_C) + if( PSA_KEY_TYPE_IS_ECC( slot->type ) ) + { + if( bits != NULL ) + *bits = slot->data.ecp->grp.pbits; + } + else +#endif /* defined(MBEDTLS_ECP_C) */ { /* Shouldn't happen: the key type is not any type that we * put it. */ @@ -263,20 +306,31 @@ psa_status_t psa_export_key(psa_key_slot_t key, return( PSA_SUCCESS ); } else -#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) +#if defined(MBEDTLS_PK_WRITE_C) if( slot->type == PSA_KEY_TYPE_RSA || PSA_KEY_TYPE_IS_ECC( slot->type ) ) { + mbedtls_pk_context pk; int ret; - ret = mbedtls_pk_write_key_der( &slot->data.pk, - data, data_size ); + mbedtls_pk_init( &pk ); + if( slot->type == PSA_KEY_TYPE_RSA ) + { + pk.pk_info = &mbedtls_rsa_info; + pk.pk_ctx = slot->data.rsa; + } + else + { + pk.pk_info = &mbedtls_eckey_info; + pk.pk_ctx = slot->data.ecp; + } + ret = mbedtls_pk_write_key_der( &pk, data, data_size ); if( ret < 0 ) return( mbedtls_to_psa_error( ret ) ); *data_length = ret; return( PSA_SUCCESS ); } else -#endif /* defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_PARSE_C) */ +#endif /* definedMBEDTLS_PK_WRITE_C) */ { return( PSA_ERROR_NOT_SUPPORTED ); } diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index d9149cacf..b450a2d38 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -13,7 +13,7 @@ import_export:"2a":PSA_KEY_TYPE_RAW_DATA:8:1:PSA_SUCCESS:1 PSA import/export raw: 2 bytes, buffer too small import_export:"2a2b":PSA_KEY_TYPE_RAW_DATA:16:-1:PSA_ERROR_BUFFER_TOO_SMALL:1 -PSA import/export RSA: good +PSA import/export RSA: good, 1024-bit depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA:1024:0:PSA_SUCCESS:1 @@ -25,6 +25,10 @@ PSA import RSA: truncated depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C import:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b":PSA_KEY_TYPE_RSA:PSA_ERROR_INVALID_ARGUMENT +PSA import/export RSA: good, 1023-bit +depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C +import_export:"3082025a0201000281806c49704e91f3df44fc99e9b3c0fee5025cc04d09529a1dd05754f2da2751d7a9aa5a79f7070132f2c47b31963e37cd74675f9c93ee7c85a143fefe303e94d1ee0e4d30898d17ab3a229e8457ef21fd179039f748305babe7f134f6d58ce5d721a1a5da98f63503d2466c6a515e53494a41180a91e535bd5b55d4dce2c17419870203010001028180491b277413fb35efe82dace68b544a9dd6aa8917d329731955ec66ec3b0178fcf5a29196e1a6c093bf6c8064b36a8f0d9840a78003d11392754a70a77788975515a1442a6c806cafa2f07fe99cac78a86fa868888d654cec4baf205352cf8255acaa47e2455f23b58c0e5ae43fa297bbffe5b970caa80f71e82084fd35425479024100ef27f3fb2df90ac4910ed95fdde4877d09b0dc4e95079f12a7e2041300a8884a39372a1c79691338cd5c3965bcf3a24f2ce9e10de19d4cb87c7546d60ca0aa0d024073e9e1283475e9ab3075da0b005ca7c7b05e76325f8deb648238831c8353041d594307f784cd527cfee9187b997713d71c0ff98f01beac4d1a85583be52e90e302402f0c801e311c2677274671933f96fee4a56c6adaf6ccaa09c4875d5fd3a8542fadf3e14ffabea62e6d90302688b6b17ebc0a42e1353a79e66d6db102d9371e5d02406731ef3c8607fbf266806590a9cfd3a79a435ee355e2d9906fc6b4236c5f3a288ed178844a7d295512f49ed15b3d82325e4f729478af3262aa9bd083f273d49502410090a32c0e8ca3bcd4c66f092cdc369cd1abb4a05b9a6f0e65e5a51da1d96d5aca8c1525b3f11322c0588062fc8592ebf25b7950f918d39018e82b8acccc8f7e7a":PSA_KEY_TYPE_RSA:1023:0:PSA_SUCCESS:1 + #PSA import/export EC secp256r1: good #depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED #import_export:"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_KEY_TYPE_ECC_NISTP256R1:256:0:PSA_SUCCESS:1 From c66ea6a921a2cd63f446e06b80ebd7c3a6ff0c91 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Feb 2018 22:43:28 +0100 Subject: [PATCH 04/36] PSA key import: support RSA public keys Use different key types for private keys and public keys. --- include/psa/crypto.h | 12 +++++++-- library/psa_crypto.c | 34 +++++++++++++++++-------- tests/suites/test_suite_psa_crypto.data | 20 +++++++++------ 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 63f119dc0..7e6156557 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -113,11 +113,15 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_NONE 0x00000000 #define PSA_KEY_TYPE_RAW_DATA 0x00000001 -#define PSA_KEY_TYPE_RSA 0x40000001 +#define PSA_KEY_TYPE_RSA_PUBLIC_KEY 0x40000001 +#define PSA_KEY_TYPE_RSA_KEYPAIR 0x60000001 #define PSA_KEY_TYPE_ECC_BASE 0x40010000 #define PSA_KEY_TYPE_VENDOR_FLAG 0x80000000 #define PSA_KEY_TYPE_ASYMMETRIC_FLAG 0x40000000 +#define PSA_KEY_TYPE_ASYMMETRIC_MASK 0x60000000 +#define PSA_KEY_TYPE_ASYMMETRIC_MASK_PUBLIC 0x40000000 +#define PSA_KEY_TYPE_ASYMMETRIC_MASK_KEYPAIR 0x60000000 #define PSA_KEY_TYPE_ECC_TEST_MASK 0x7fff0000 #define PSA_KEY_TYPE_ECC_TEST_VALUE 0x40010000 @@ -125,7 +129,11 @@ typedef uint32_t psa_key_type_t; (((type) & PSA_KEY_TYPE_VENDOR_FLAG) != 0) #define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \ (((type) & PSA_KEY_TYPE_ASYMMETRIC_FLAG) != 0) -#define PSA_KEY_TYPE_IS_ECC(type) \ +#define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \ + (((type) & PSA_KEY_TYPE_ASYMMETRIC_MASK) == PSA_KEY_TYPE_ASYMMETRIC_MASK_PUBLIC) +#define PSA_KEY_TYPE_IS_KEYPAIR(type) \ + (((type) & PSA_KEY_TYPE_ASYMMETRIC_MASK) == PSA_KEY_TYPE_ASYMMETRIC_MASK_KEYPAIR) +#define PSA_KEY_TYPE_IS_ECC(type) \ (((type) & PSA_KEY_TYPE_ECC_TEST_MASK) == PSA_KEY_TYPE_ECC_TEST_VALUE) typedef uint32_t psa_algorithm_type_t; diff --git a/library/psa_crypto.c b/library/psa_crypto.c index f6da44e9d..741f5d11a 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -154,20 +154,25 @@ psa_status_t psa_import_key(psa_key_slot_t key, } else #if defined(MBEDTLS_PK_PARSE_C) - if( type == PSA_KEY_TYPE_RSA || PSA_KEY_TYPE_IS_ECC( type ) ) + if( type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || + type == PSA_KEY_TYPE_RSA_KEYPAIR || + PSA_KEY_TYPE_IS_ECC( type ) ) { int ret; mbedtls_pk_context pk; mbedtls_pk_init( &pk ); - ret = mbedtls_pk_parse_key( &pk, data, data_length, - NULL, 0 ); + if( PSA_KEY_TYPE_IS_KEYPAIR( type ) ) + ret = mbedtls_pk_parse_key( &pk, data, data_length, NULL, 0 ); + else + ret = mbedtls_pk_parse_public_key( &pk, data, data_length ); if( ret != 0 ) return( mbedtls_to_psa_error( ret ) ); switch( mbedtls_pk_get_type( &pk ) ) { #if defined(MBEDTLS_RSA_C) case MBEDTLS_PK_RSA: - if( type == PSA_KEY_TYPE_RSA ) + if( type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || + type == PSA_KEY_TYPE_RSA_KEYPAIR ) slot->data.rsa = pk.pk_ctx; else return( PSA_ERROR_INVALID_ARGUMENT ); @@ -214,7 +219,8 @@ psa_status_t psa_destroy_key(psa_key_slot_t key) } else #if defined(MBEDTLS_RSA_C) - if( slot->type == PSA_KEY_TYPE_RSA ) + if( slot->type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || + slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ) { mbedtls_rsa_free( slot->data.rsa ); } @@ -244,7 +250,7 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, key_slot_t *slot; if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) - return( PSA_ERROR_INVALID_ARGUMENT ); + return( PSA_ERROR_EMPTY_SLOT ); slot = &global_data.key_slots[key]; if( type != NULL ) *type = slot->type; @@ -260,7 +266,8 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, } else #if defined(MBEDTLS_RSA_C) - if( slot->type == PSA_KEY_TYPE_RSA ) + if( slot->type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || + slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ) { if( bits != NULL ) *bits = mbedtls_rsa_get_bitlen( slot->data.rsa ); @@ -292,7 +299,7 @@ psa_status_t psa_export_key(psa_key_slot_t key, key_slot_t *slot; if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) - return( PSA_ERROR_INVALID_ARGUMENT ); + return( PSA_ERROR_EMPTY_SLOT ); slot = &global_data.key_slots[key]; if( slot->type == PSA_KEY_TYPE_NONE ) return( PSA_ERROR_EMPTY_SLOT ); @@ -307,13 +314,15 @@ psa_status_t psa_export_key(psa_key_slot_t key, } else #if defined(MBEDTLS_PK_WRITE_C) - if( slot->type == PSA_KEY_TYPE_RSA || + if( slot->type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || + slot->type == PSA_KEY_TYPE_RSA_KEYPAIR || PSA_KEY_TYPE_IS_ECC( slot->type ) ) { mbedtls_pk_context pk; int ret; mbedtls_pk_init( &pk ); - if( slot->type == PSA_KEY_TYPE_RSA ) + if( slot->type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || + slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ) { pk.pk_info = &mbedtls_rsa_info; pk.pk_ctx = slot->data.rsa; @@ -323,7 +332,10 @@ psa_status_t psa_export_key(psa_key_slot_t key, pk.pk_info = &mbedtls_eckey_info; pk.pk_ctx = slot->data.ecp; } - ret = mbedtls_pk_write_key_der( &pk, data, data_size ); + if( PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) ) + ret = mbedtls_pk_write_key_der( &pk, data, data_size ); + else + ret = mbedtls_pk_write_pubkey_der( &pk, data, data_size ); if( ret < 0 ) return( mbedtls_to_psa_error( ret ) ); *data_length = ret; diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index b450a2d38..e8407a30c 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -13,21 +13,25 @@ import_export:"2a":PSA_KEY_TYPE_RAW_DATA:8:1:PSA_SUCCESS:1 PSA import/export raw: 2 bytes, buffer too small import_export:"2a2b":PSA_KEY_TYPE_RAW_DATA:16:-1:PSA_ERROR_BUFFER_TOO_SMALL:1 -PSA import/export RSA: good, 1024-bit +PSA import/export RSA public key: good, 1024-bit depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C -import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA:1024:0:PSA_SUCCESS:1 +import_export:"30819f300d06092a864886f70d010101050003818d0030818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_KEY_TYPE_RSA_PUBLIC_KEY:1024:0:PSA_SUCCESS:1 -PSA import/export RSA: trailing garbage ignored +PSA import/export RSA keypair: good, 1024-bit depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C -import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA:1024:-1:PSA_SUCCESS:0 +import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:1024:0:PSA_SUCCESS:1 -PSA import RSA: truncated +PSA import/export RSA keypair: trailing garbage ignored depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C -import:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b":PSA_KEY_TYPE_RSA:PSA_ERROR_INVALID_ARGUMENT +import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA_KEYPAIR:1024:-1:PSA_SUCCESS:0 -PSA import/export RSA: good, 1023-bit +PSA import RSA keypair: truncated depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C -import_export:"3082025a0201000281806c49704e91f3df44fc99e9b3c0fee5025cc04d09529a1dd05754f2da2751d7a9aa5a79f7070132f2c47b31963e37cd74675f9c93ee7c85a143fefe303e94d1ee0e4d30898d17ab3a229e8457ef21fd179039f748305babe7f134f6d58ce5d721a1a5da98f63503d2466c6a515e53494a41180a91e535bd5b55d4dce2c17419870203010001028180491b277413fb35efe82dace68b544a9dd6aa8917d329731955ec66ec3b0178fcf5a29196e1a6c093bf6c8064b36a8f0d9840a78003d11392754a70a77788975515a1442a6c806cafa2f07fe99cac78a86fa868888d654cec4baf205352cf8255acaa47e2455f23b58c0e5ae43fa297bbffe5b970caa80f71e82084fd35425479024100ef27f3fb2df90ac4910ed95fdde4877d09b0dc4e95079f12a7e2041300a8884a39372a1c79691338cd5c3965bcf3a24f2ce9e10de19d4cb87c7546d60ca0aa0d024073e9e1283475e9ab3075da0b005ca7c7b05e76325f8deb648238831c8353041d594307f784cd527cfee9187b997713d71c0ff98f01beac4d1a85583be52e90e302402f0c801e311c2677274671933f96fee4a56c6adaf6ccaa09c4875d5fd3a8542fadf3e14ffabea62e6d90302688b6b17ebc0a42e1353a79e66d6db102d9371e5d02406731ef3c8607fbf266806590a9cfd3a79a435ee355e2d9906fc6b4236c5f3a288ed178844a7d295512f49ed15b3d82325e4f729478af3262aa9bd083f273d49502410090a32c0e8ca3bcd4c66f092cdc369cd1abb4a05b9a6f0e65e5a51da1d96d5aca8c1525b3f11322c0588062fc8592ebf25b7950f918d39018e82b8acccc8f7e7a":PSA_KEY_TYPE_RSA:1023:0:PSA_SUCCESS:1 +import:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_ERROR_INVALID_ARGUMENT + +PSA import/export RSA keypair: good, 1023-bit +depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C +import_export:"3082025a0201000281806c49704e91f3df44fc99e9b3c0fee5025cc04d09529a1dd05754f2da2751d7a9aa5a79f7070132f2c47b31963e37cd74675f9c93ee7c85a143fefe303e94d1ee0e4d30898d17ab3a229e8457ef21fd179039f748305babe7f134f6d58ce5d721a1a5da98f63503d2466c6a515e53494a41180a91e535bd5b55d4dce2c17419870203010001028180491b277413fb35efe82dace68b544a9dd6aa8917d329731955ec66ec3b0178fcf5a29196e1a6c093bf6c8064b36a8f0d9840a78003d11392754a70a77788975515a1442a6c806cafa2f07fe99cac78a86fa868888d654cec4baf205352cf8255acaa47e2455f23b58c0e5ae43fa297bbffe5b970caa80f71e82084fd35425479024100ef27f3fb2df90ac4910ed95fdde4877d09b0dc4e95079f12a7e2041300a8884a39372a1c79691338cd5c3965bcf3a24f2ce9e10de19d4cb87c7546d60ca0aa0d024073e9e1283475e9ab3075da0b005ca7c7b05e76325f8deb648238831c8353041d594307f784cd527cfee9187b997713d71c0ff98f01beac4d1a85583be52e90e302402f0c801e311c2677274671933f96fee4a56c6adaf6ccaa09c4875d5fd3a8542fadf3e14ffabea62e6d90302688b6b17ebc0a42e1353a79e66d6db102d9371e5d02406731ef3c8607fbf266806590a9cfd3a79a435ee355e2d9906fc6b4236c5f3a288ed178844a7d295512f49ed15b3d82325e4f729478af3262aa9bd083f273d49502410090a32c0e8ca3bcd4c66f092cdc369cd1abb4a05b9a6f0e65e5a51da1d96d5aca8c1525b3f11322c0588062fc8592ebf25b7950f918d39018e82b8acccc8f7e7a":PSA_KEY_TYPE_RSA_KEYPAIR:1023:0:PSA_SUCCESS:1 #PSA import/export EC secp256r1: good #depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED From 20035e357978a2cbd1f6915bec82534c386b25d0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Feb 2018 22:44:14 +0100 Subject: [PATCH 05/36] PSA crypto: asymmetric signature (RSA PKCS#1v1.5 only) Define hash algorithms and RSA signature algorithms. New function psa_asymmetric_sign. Implement psa_asymmetric_sign for RSA PKCS#1 v1.5. --- include/psa/crypto.h | 68 +++++++- library/psa_crypto.c | 182 ++++++++++++++++++++ tests/suites/test_suite_psa_crypto.data | 13 ++ tests/suites/test_suite_psa_crypto.function | 95 ++++++++++ 4 files changed, 357 insertions(+), 1 deletion(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 7e6156557..3eee3822b 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -136,7 +136,39 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_IS_ECC(type) \ (((type) & PSA_KEY_TYPE_ECC_TEST_MASK) == PSA_KEY_TYPE_ECC_TEST_VALUE) -typedef uint32_t psa_algorithm_type_t; +typedef uint32_t psa_algorithm_t; + +#define PSA_ALG_HASH_BITS 0x01000000 +#define PSA_ALG_RSA_HASH_MASK 0x000000ff +#define PSA_ALG_MD2 0x01000001 +#define PSA_ALG_MD4 0x01000002 +#define PSA_ALG_MD5 0x01000003 +#define PSA_ALG_SHA_256_128 0x01000004 +#define PSA_ALG_RIPEMD160 0x01000005 +#define PSA_ALG_SHA_1 0x01000006 +#define PSA_ALG_SHA_256_160 0x01000007 +#define PSA_ALG_SHA_224 0x01000008 +#define PSA_ALG_SHA_256 0x01000009 +#define PSA_ALG_SHA_384 0x0100000a +#define PSA_ALG_SHA_512 0x0100000b +#define PSA_ALG_SHA_512_224 0x0100000c +#define PSA_ALG_SHA_512_256 0x0100000d +#define PSA_ALG_SHA3_224 0x01000010 +#define PSA_ALG_SHA3_256 0x01000011 +#define PSA_ALG_SHA3_384 0x01000012 +#define PSA_ALG_SHA3_512 0x01000013 + +#define PSA_ALG_RSA_PKCS1V15_RAW 0x40000100 +#define PSA_ALG_RSA_PSS_MGF1 0x40000200 +#define PSA_ALG_RSA_OAEP 0x40000300 +#define PSA_ALG_RSA_PKCS1V15(hash_alg) \ + (PSA_ALG_RSA_PKCS1V15_RAW | ((hash_alg) & PSA_ALG_RSA_HASH_MASK)) +#define PSA_ALG_IS_RSA_PKCS1V15(alg) \ + (((alg) & 0x7fffff00) == PSA_ALG_RSA_PKCS1V15_RAW) +#define PSA_ALG_RSA_GET_HASH(alg) \ + (((alg) & PSA_ALG_RSA_HASH_MASK) | PSA_ALG_HASH_BITS) + +#define PSA_ALG_VENDOR_FLAG 0x80000000 /**@}*/ @@ -208,6 +240,40 @@ psa_status_t psa_export_key(psa_key_slot_t key, size_t data_size, size_t *data_length); + +/**@}*/ + +/** \defgroup asymmetric Asymmetric cryptography + * @{ + */ + +/** + * \brief Sign a hash or short message with a private key. + * + */ +psa_status_t psa_asymmetric_sign(psa_key_slot_t key, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length); + +/** + * \brief Verify the signature a hash or short message using a public key. + * + */ +psa_status_t psa_asymmetric_verify(psa_key_slot_t key, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *signature, + size_t signature_size); + /**@}*/ #ifdef __cplusplus diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 741f5d11a..256523271 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -41,6 +41,8 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/ecp.h" #include "mbedtls/entropy.h" +#include "mbedtls/md.h" +#include "mbedtls/md_internal.h" #include "mbedtls/pk.h" #include "mbedtls/pk_internal.h" #include "mbedtls/rsa.h" @@ -350,6 +352,186 @@ psa_status_t psa_export_key(psa_key_slot_t key, +/****************************************************************/ +/* Message digests */ +/****************************************************************/ + +static const mbedtls_md_info_t *mbedtls_md_info_of_psa( psa_algorithm_t alg ) +{ + switch( alg ) + { +#if defined(MBEDTLS_MD2_C) + case PSA_ALG_MD2: + return( &mbedtls_md2_info ); +#endif +#if defined(MBEDTLS_MD4_C) + case PSA_ALG_MD4: + return( &mbedtls_md4_info ); +#endif +#if defined(MBEDTLS_MD5_C) + case PSA_ALG_MD5: + return( &mbedtls_md5_info ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case PSA_ALG_RIPEMD160: + return( &mbedtls_ripemd160_info ); +#endif +#if defined(MBEDTLS_SHA1_C) + case PSA_ALG_SHA_1: + return( &mbedtls_sha1_info ); +#endif +#if defined(MBEDTLS_SHA256_C) + case PSA_ALG_SHA_224: + return( &mbedtls_sha224_info ); + case PSA_ALG_SHA_256: + return( &mbedtls_sha256_info ); +#endif +#if defined(MBEDTLS_SHA512_C) + case PSA_ALG_SHA_384: + return( &mbedtls_sha384_info ); + case PSA_ALG_SHA_512: + return( &mbedtls_sha512_info ); +#endif + default: + return( NULL ); + } +} + +#if 0 +static psa_algorithm_t mbedtls_md_alg_to_psa( mbedtls_md_type_t md_alg ) +{ + switch( md_alg ) + { + case MBEDTLS_MD_NONE: + return( 0 ); + case MBEDTLS_MD_MD2: + return( PSA_ALG_MD2 ); + case MBEDTLS_MD_MD4: + return( PSA_ALG_MD4 ); + case MBEDTLS_MD_MD5: + return( PSA_ALG_MD5 ); + case MBEDTLS_MD_SHA1: + return( PSA_ALG_SHA_1 ); + case MBEDTLS_MD_SHA224: + return( PSA_ALG_SHA_224 ); + case MBEDTLS_MD_SHA256: + return( PSA_ALG_SHA_256 ); + case MBEDTLS_MD_SHA384: + return( PSA_ALG_SHA_384 ); + case MBEDTLS_MD_SHA512: + return( PSA_ALG_SHA_512 ); + case MBEDTLS_MD_RIPEMD160: + return( PSA_ALG_RIPEMD160 ); + default: + return( MBEDTLS_MD_NOT_SUPPORTED ); + } +} +#endif + + + +/****************************************************************/ +/* Asymmetric cryptography */ +/****************************************************************/ + +psa_status_t psa_asymmetric_sign(psa_key_slot_t key, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + key_slot_t *slot; + + if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) + return( PSA_ERROR_EMPTY_SLOT ); + slot = &global_data.key_slots[key]; + if( slot->type == PSA_KEY_TYPE_NONE ) + return( PSA_ERROR_EMPTY_SLOT ); + if( ! PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) ) + return( PSA_ERROR_INVALID_ARGUMENT ); + + (void) salt; + (void) salt_length; + +#if defined(MBEDTLS_RSA_C) + if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ) + { + mbedtls_rsa_context *rsa = slot->data.rsa; + int ret; + psa_algorithm_t hash_alg = PSA_ALG_RSA_GET_HASH( alg ); + const mbedtls_md_info_t *md_info = mbedtls_md_info_of_psa( hash_alg ); + mbedtls_md_type_t md_alg = + hash_alg == 0 ? MBEDTLS_MD_NONE : mbedtls_md_get_type( md_info ); + if( md_alg == MBEDTLS_MD_NONE ) + { +#if SIZE_MAX > UINT_MAX + if( hash_length > UINT_MAX ) + return( PSA_ERROR_INVALID_ARGUMENT ); +#endif + } + else + { + if( mbedtls_md_get_size( md_info ) != hash_length ) + return( PSA_ERROR_INVALID_ARGUMENT ); + if( md_info == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + } + if( signature_size < rsa->len ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); +#if defined(MBEDTLS_PKCS1_V15) + if( PSA_ALG_IS_RSA_PKCS1V15( alg ) ) + { + mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V15, + MBEDTLS_MD_NONE ); + ret = mbedtls_rsa_pkcs1_sign( rsa, + mbedtls_ctr_drbg_random, + &global_data.ctr_drbg, + MBEDTLS_RSA_PRIVATE, + md_alg, hash_length, hash, + signature ); + } + else +#endif /* MBEDTLS_PKCS1_V15 */ +#if defined(MBEDTLS_PKCS1_V21) + if( alg == PSA_ALG_RSA_PSS_MGF1 ) + { + mbedtls_rsa_set_padding( rsa, MBEDTLS_RSA_PKCS_V21, md_alg ); + ret = mbedtls_rsa_rsassa_pss_sign( rsa, + mbedtls_ctr_drbg_random, + &global_data.ctr_drbg, + MBEDTLS_RSA_PRIVATE, + md_alg, hash_length, hash, + signature ); + } + else +#endif /* MBEDTLS_PKCS1_V21 */ + { + return( PSA_ERROR_INVALID_ARGUMENT ); + } + *signature_length = ( ret == 0 ? rsa->len : 0 ); + return( mbedtls_to_psa_error( ret ) ); + } + else +#endif /* defined(MBEDTLS_RSA_C) */ +#if defined(MBEDTLS_ECP_C) + if( PSA_KEY_TYPE_IS_ECC( slot->type ) ) + { + // TODO + return( PSA_ERROR_NOT_SUPPORTED ); + } + else +#endif /* defined(MBEDTLS_ECP_C) */ + { + return( PSA_ERROR_NOT_SUPPORTED ); + } +} + + + /****************************************************************/ /* Module setup */ /****************************************************************/ diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index e8407a30c..51fbf3ade 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -36,3 +36,16 @@ import_export:"3082025a0201000281806c49704e91f3df44fc99e9b3c0fee5025cc04d09529a1 #PSA import/export EC secp256r1: good #depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED #import_export:"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_KEY_TYPE_ECC_NISTP256R1:256:0:PSA_SUCCESS:1 +# +PSA sign RSA PKCS#1 v1.5, raw +depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15 +sign_deterministic:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_RAW:"616263":"2c7744983f023ac7bb1c55529d83ed11a76a7898a1bb5ce191375a4aa7495a633d27879ff58eba5a57371c34feb1180e8b850d552476ebb5634df620261992f12ebee9097041dbbea85a42d45b344be5073ceb772ffc604954b9158ba81ec3dc4d9d65e3ab7aa318165f38c36f841f1c69cb1cfa494aa5cbb4d6c0efbafb043a" + +PSA sign RSA PKCS#1 v1.5 SHA-256 +sign_deterministic:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15(PSA_ALG_SHA_256):"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad":"a73664d55b39c7ea6c1e5b5011724a11e1d7073d3a68f48c836fad153a1d91b6abdbc8f69da13b206cc96af6363b114458b026af14b24fab8929ed634c6a2acace0bcc62d9bb6a984afbcbfcd3a0608d32a2bae535b9cd1ecdf9dd281db1e0025c3bfb5512963ec3b98ddaa69e38bc3c84b1b61a04e5648640856aacc6fc7311" + +PSA sign RSA PKCS#1 v1.5 SHA-256, wrong hash size +sign_fail:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15(PSA_ALG_SHA_256):"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015":128:PSA_ERROR_INVALID_ARGUMENT + +PSA sign RSA PKCS#1 v1.5 SHA-256, output buffer too small +sign_fail:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15(PSA_ALG_SHA_256):"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad":127:PSA_ERROR_BUFFER_TOO_SMALL diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 6fa10dd96..35515706d 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -132,3 +132,98 @@ exit: mbedtls_psa_crypto_free( ); } /* END_CASE */ + +/* BEGIN_CASE */ +void sign_deterministic( int key_type_arg, char *key_hex, + int alg_arg, char *input_hex, char *output_hex ) +{ + int slot = 1; + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + unsigned char *key_data = NULL; + size_t key_size; + unsigned char *input_data = NULL; + size_t input_size; + unsigned char *output_data = NULL; + size_t output_size; + unsigned char signature[512]; + size_t signature_length; + + key_data = mbedtls_calloc( 1, strlen( key_hex ) / 2 ); + TEST_ASSERT( key_data != NULL ); + key_size = unhexify( key_data, key_hex ); + input_data = mbedtls_calloc( 1, strlen( input_hex ) / 2 ); + TEST_ASSERT( input_data != NULL ); + input_size = unhexify( input_data, input_hex ); + output_data = mbedtls_calloc( 1, strlen( output_hex ) / 2 ); + TEST_ASSERT( output_data != NULL ); + output_size = unhexify( output_data, output_hex ); + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_import_key( slot, key_type, + key_data, key_size ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_asymmetric_sign( slot, alg, + input_data, input_size, + NULL, 0, + signature, sizeof( signature ), + &signature_length ) == PSA_SUCCESS ); + TEST_ASSERT( signature_length == output_size ); + TEST_ASSERT( memcmp( signature, output_data, output_size ) == 0 ); + +exit: + psa_destroy_key( slot ); + mbedtls_free( key_data ); + mbedtls_free( input_data ); + mbedtls_free( output_data ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void sign_fail( int key_type_arg, char *key_hex, + int alg_arg, char *input_hex, + int signature_size, int expected_status_arg ) +{ + int slot = 1; + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + unsigned char *key_data = NULL; + size_t key_size; + unsigned char *input_data = NULL; + size_t input_size; + psa_status_t actual_status; + psa_status_t expected_status = expected_status_arg; + unsigned char *signature; + size_t signature_length; + + key_data = mbedtls_calloc( 1, strlen( key_hex ) / 2 ); + TEST_ASSERT( key_data != NULL ); + key_size = unhexify( key_data, key_hex ); + input_data = mbedtls_calloc( 1, strlen( input_hex ) / 2 ); + TEST_ASSERT( input_data != NULL ); + input_size = unhexify( input_data, input_hex ); + signature = mbedtls_calloc( 1, signature_size ); + TEST_ASSERT( signature != NULL ); + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_import_key( slot, key_type, + key_data, key_size ) == PSA_SUCCESS ); + + actual_status = psa_asymmetric_sign( slot, alg, + input_data, input_size, + NULL, 0, + signature, signature_size, + &signature_length ); + TEST_ASSERT( actual_status == expected_status ); + +exit: + psa_destroy_key( slot ); + mbedtls_free( key_data ); + mbedtls_free( input_data ); + mbedtls_free( signature ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ From 0189e7512d9d3df9e7db84672a8b01f94da38f01 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Feb 2018 23:57:22 +0100 Subject: [PATCH 06/36] PSA crypto: PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE macro Test it for RSA. --- include/psa/crypto.h | 45 ++++++++++++++++++++- tests/suites/test_suite_psa_crypto.data | 18 +++++++++ tests/suites/test_suite_psa_crypto.function | 27 ++++++++++++- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 3eee3822b..4a60e67f9 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -103,6 +103,9 @@ typedef enum { */ psa_status_t psa_crypto_init(void); +#define BITS_TO_BYTES(bits) (((bits) + 7) / 8) +#define BYTES_TO_BITS(bytes) ((bytes) * 8) + /**@}*/ /** \defgroup crypto_types Key and algorithm types @@ -122,7 +125,8 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_ASYMMETRIC_MASK 0x60000000 #define PSA_KEY_TYPE_ASYMMETRIC_MASK_PUBLIC 0x40000000 #define PSA_KEY_TYPE_ASYMMETRIC_MASK_KEYPAIR 0x60000000 -#define PSA_KEY_TYPE_ECC_TEST_MASK 0x7fff0000 +#define PSA_KEY_TYPE_ASYMMETRIC_TEST_MASK 0x5fff0000 +#define PSA_KEY_TYPE_RSA_TEST_VALUE 0x40000000 #define PSA_KEY_TYPE_ECC_TEST_VALUE 0x40010000 #define PSA_KEY_TYPE_IS_VENDOR(type) \ @@ -133,8 +137,10 @@ typedef uint32_t psa_key_type_t; (((type) & PSA_KEY_TYPE_ASYMMETRIC_MASK) == PSA_KEY_TYPE_ASYMMETRIC_MASK_PUBLIC) #define PSA_KEY_TYPE_IS_KEYPAIR(type) \ (((type) & PSA_KEY_TYPE_ASYMMETRIC_MASK) == PSA_KEY_TYPE_ASYMMETRIC_MASK_KEYPAIR) +#define PSA_KEY_TYPE_IS_RSA(type) \ + (((type) & PSA_KEY_TYPE_ASYMMETRIC_TEST_MASK) == PSA_KEY_TYPE_RSA_TEST_VALUE) #define PSA_KEY_TYPE_IS_ECC(type) \ - (((type) & PSA_KEY_TYPE_ECC_TEST_MASK) == PSA_KEY_TYPE_ECC_TEST_VALUE) + (((type) & PSA_KEY_TYPE_ASYMMETRIC_TEST_MASK) == PSA_KEY_TYPE_ECC_TEST_VALUE) typedef uint32_t psa_algorithm_t; @@ -247,6 +253,41 @@ psa_status_t psa_export_key(psa_key_slot_t key, * @{ */ +/** + * \brief Maximum ECDSA signature size for a given curve bit size + * + * \param curve_bits Curve size in bits + * \return Maximum signature size in bytes + * + * \note This macro returns a compile-time constant if its argument is one. + * + * \warning This macro may evaluate its argument multiple times. + */ +/* + * RFC 4492 page 20: + * + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * Size is at most + * 1 (tag) + 1 (len) + 1 (initial 0) + curve_bytes for each of r and s, + * twice that + 1 (tag) + 2 (len) for the sequence + * (assuming curve_bytes is less than 126 for r and s, + * and less than 124 (total len <= 255) for the sequence) + */ +#define PSA_ECDSA_SIGNATURE_SIZE(curve_bits) \ + ( /*T,L of SEQUENCE*/ ((curve_bits) >= 61 * 8 ? 3 : 2) + \ + /*T,L of r,s*/ 2 * (((curve_bits) >= 127 * 8 ? 3 : 2) + \ + /*V of r,s*/ ((curve_bits) + 8) / 8)) + + +#define PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \ + (PSA_KEY_TYPE_IS_RSA(key_type) ? ((void)alg, BITS_TO_BYTES(key_bits)) : \ + PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(key_bits) : \ + 0) + /** * \brief Sign a hash or short message with a private key. * diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 51fbf3ade..a2d6b89fd 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -37,6 +37,24 @@ import_export:"3082025a0201000281806c49704e91f3df44fc99e9b3c0fee5025cc04d09529a1 #depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED #import_export:"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_KEY_TYPE_ECC_NISTP256R1:256:0:PSA_SUCCESS:1 # +PSA signature size: RSA keypair, 1024 bits, PKCS#1 v1.5 raw +signature_size:PSA_KEY_TYPE_RSA_KEYPAIR:1024:PSA_ALG_RSA_PKCS1V15_RAW:128 + +PSA signature size: RSA public key, 1024 bits, PKCS#1 v1.5 raw +signature_size:PSA_KEY_TYPE_RSA_PUBLIC_KEY:1024:PSA_ALG_RSA_PKCS1V15_RAW:128 + +PSA signature size: RSA keypair, 1024 bits, PKCS#1 v1.5 SHA-256 +signature_size:PSA_KEY_TYPE_RSA_KEYPAIR:1024:PSA_ALG_RSA_PKCS1V15(PSA_ALG_SHA_256):128 + +PSA signature size: RSA keypair, 1024 bits, PSS +signature_size:PSA_KEY_TYPE_RSA_KEYPAIR:1024:PSA_ALG_RSA_PSS_MGF1:128 + +PSA signature size: RSA keypair, 1023 bits, PKCS#1 v1.5 raw +signature_size:PSA_KEY_TYPE_RSA_KEYPAIR:1023:PSA_ALG_RSA_PKCS1V15_RAW:128 + +PSA signature size: RSA keypair, 1025 bits, PKCS#1 v1.5 raw +signature_size:PSA_KEY_TYPE_RSA_KEYPAIR:1025:PSA_ALG_RSA_PKCS1V15_RAW:129 + PSA sign RSA PKCS#1 v1.5, raw depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15 sign_deterministic:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_RAW:"616263":"2c7744983f023ac7bb1c55529d83ed11a76a7898a1bb5ce191375a4aa7495a633d27879ff58eba5a57371c34feb1180e8b850d552476ebb5634df620261992f12ebee9097041dbbea85a42d45b344be5073ceb772ffc604954b9158ba81ec3dc4d9d65e3ab7aa318165f38c36f841f1c69cb1cfa494aa5cbb4d6c0efbafb043a" diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 35515706d..80a778881 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -133,6 +133,18 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void signature_size( int type_arg, int bits, int alg_arg, int expected_size_arg ) +{ + psa_key_type_t type = type_arg; + psa_algorithm_t alg = alg_arg; + size_t actual_size = PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(type, bits, alg); + TEST_ASSERT( actual_size == (size_t) expected_size_arg ); +exit: + ; +} +/* END_CASE */ + /* BEGIN_CASE */ void sign_deterministic( int key_type_arg, char *key_hex, int alg_arg, char *input_hex, char *output_hex ) @@ -142,12 +154,14 @@ void sign_deterministic( int key_type_arg, char *key_hex, psa_algorithm_t alg = alg_arg; unsigned char *key_data = NULL; size_t key_size; + size_t key_bits; unsigned char *input_data = NULL; size_t input_size; unsigned char *output_data = NULL; size_t output_size; - unsigned char signature[512]; size_t signature_length; + unsigned char *signature = NULL; + size_t signature_size; key_data = mbedtls_calloc( 1, strlen( key_hex ) / 2 ); TEST_ASSERT( key_data != NULL ); @@ -163,11 +177,19 @@ void sign_deterministic( int key_type_arg, char *key_hex, TEST_ASSERT( psa_import_key( slot, key_type, key_data, key_size ) == PSA_SUCCESS ); + TEST_ASSERT( psa_get_key_information( slot, + NULL, + &key_bits ) == PSA_SUCCESS ); + + signature_size = PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE( key_type, alg, key_bits ); + TEST_ASSERT( signature_size != 0 ); + signature = mbedtls_calloc( 1, signature_size ); + TEST_ASSERT( signature != NULL ); TEST_ASSERT( psa_asymmetric_sign( slot, alg, input_data, input_size, NULL, 0, - signature, sizeof( signature ), + signature, signature_size, &signature_length ) == PSA_SUCCESS ); TEST_ASSERT( signature_length == output_size ); TEST_ASSERT( memcmp( signature, output_data, output_size ) == 0 ); @@ -177,6 +199,7 @@ exit: mbedtls_free( key_data ); mbedtls_free( input_data ); mbedtls_free( output_data ); + mbedtls_free( signature ); mbedtls_psa_crypto_free( ); } /* END_CASE */ From 93aa0334d98e59ba22bce684787f71e94e081487 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Feb 2018 23:58:03 +0100 Subject: [PATCH 07/36] PSA asymmetric signature: set *signature_length = 0 on failure --- library/psa_crypto.c | 10 ++++++---- tests/suites/test_suite_psa_crypto.function | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 256523271..66d81a365 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -446,6 +446,10 @@ psa_status_t psa_asymmetric_sign(psa_key_slot_t key, { key_slot_t *slot; + *signature_length = 0; + (void) salt; + (void) salt_length; + if( key == 0 || key > MBEDTLS_PSA_KEY_SLOT_COUNT ) return( PSA_ERROR_EMPTY_SLOT ); slot = &global_data.key_slots[key]; @@ -454,9 +458,6 @@ psa_status_t psa_asymmetric_sign(psa_key_slot_t key, if( ! PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) ) return( PSA_ERROR_INVALID_ARGUMENT ); - (void) salt; - (void) salt_length; - #if defined(MBEDTLS_RSA_C) if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ) { @@ -512,7 +513,8 @@ psa_status_t psa_asymmetric_sign(psa_key_slot_t key, { return( PSA_ERROR_INVALID_ARGUMENT ); } - *signature_length = ( ret == 0 ? rsa->len : 0 ); + if( ret == 0 ) + *signature_length = rsa->len; return( mbedtls_to_psa_error( ret ) ); } else diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 80a778881..c5d536e46 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -159,9 +159,9 @@ void sign_deterministic( int key_type_arg, char *key_hex, size_t input_size; unsigned char *output_data = NULL; size_t output_size; - size_t signature_length; unsigned char *signature = NULL; size_t signature_size; + size_t signature_length = 0xdeadbeef; key_data = mbedtls_calloc( 1, strlen( key_hex ) / 2 ); TEST_ASSERT( key_data != NULL ); @@ -219,7 +219,7 @@ void sign_fail( int key_type_arg, char *key_hex, psa_status_t actual_status; psa_status_t expected_status = expected_status_arg; unsigned char *signature; - size_t signature_length; + size_t signature_length = 0xdeadbeef; key_data = mbedtls_calloc( 1, strlen( key_hex ) / 2 ); TEST_ASSERT( key_data != NULL ); @@ -241,6 +241,7 @@ void sign_fail( int key_type_arg, char *key_hex, signature, signature_size, &signature_length ); TEST_ASSERT( actual_status == expected_status ); + TEST_ASSERT( signature_length == 0 ); exit: psa_destroy_key( slot ); From 98f0a24255312cd892627994b62a1e3c2e5ff12b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 6 Feb 2018 18:57:29 +0100 Subject: [PATCH 08/36] Improve key type and algorithm encodings Refine the encoding of key types and algorithms so that ranges of bits make more sense. Define a few symmetric cipher algorithms. --- include/psa/crypto.h | 156 +++++++++++++++++++++++++++++-------------- 1 file changed, 105 insertions(+), 51 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 4a60e67f9..6276bac6e 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -114,67 +114,121 @@ psa_status_t psa_crypto_init(void); typedef uint32_t psa_key_type_t; -#define PSA_KEY_TYPE_NONE 0x00000000 -#define PSA_KEY_TYPE_RAW_DATA 0x00000001 -#define PSA_KEY_TYPE_RSA_PUBLIC_KEY 0x40000001 -#define PSA_KEY_TYPE_RSA_KEYPAIR 0x60000001 -#define PSA_KEY_TYPE_ECC_BASE 0x40010000 +#define PSA_KEY_TYPE_NONE ((psa_key_type_t)0x00000000) +#define PSA_KEY_TYPE_VENDOR_FLAG ((psa_key_type_t)0x80000000) -#define PSA_KEY_TYPE_VENDOR_FLAG 0x80000000 -#define PSA_KEY_TYPE_ASYMMETRIC_FLAG 0x40000000 -#define PSA_KEY_TYPE_ASYMMETRIC_MASK 0x60000000 -#define PSA_KEY_TYPE_ASYMMETRIC_MASK_PUBLIC 0x40000000 -#define PSA_KEY_TYPE_ASYMMETRIC_MASK_KEYPAIR 0x60000000 -#define PSA_KEY_TYPE_ASYMMETRIC_TEST_MASK 0x5fff0000 -#define PSA_KEY_TYPE_RSA_TEST_VALUE 0x40000000 -#define PSA_KEY_TYPE_ECC_TEST_VALUE 0x40010000 +#define PSA_KEY_TYPE_CATEGORY_MASK ((psa_key_type_t)0x7e000000) +#define PSA_KEY_TYPE_RAW_DATA ((psa_key_type_t)0x02000000) +#define PSA_KEY_TYPE_CATEGORY_SYMMETRIC ((psa_key_type_t)0x04000000) +#define PSA_KEY_TYPE_CATEGORY_ASYMMETRIC ((psa_key_type_t)0x06000000) +#define PSA_KEY_TYPE_PAIR_FLAG ((psa_key_type_t)0x01000000) -#define PSA_KEY_TYPE_IS_VENDOR(type) \ +#define PSA_KEY_TYPE_HMAC ((psa_key_type_t)0x02000001) +#define PSA_KEY_TYPE_AES ((psa_key_type_t)0x04000001) +#define PSA_KEY_TYPE_DES ((psa_key_type_t)0x04000002) +#define PSA_KEY_TYPE_CAMELLIA ((psa_key_type_t)0x04000003) +#define PSA_KEY_TYPE_ARC4 ((psa_key_type_t)0x04000004) + +#define PSA_KEY_TYPE_RSA_PUBLIC_KEY ((psa_key_type_t)0x06010000) +#define PSA_KEY_TYPE_RSA_KEYPAIR ((psa_key_type_t)0x07010000) +#define PSA_KEY_TYPE_ECC_BASE ((psa_key_type_t)0x06030000) +#define PSA_KEY_TYPE_ECC_CURVE_MASK ((psa_key_type_t)0x0000ffff) + +#define PSA_KEY_TYPE_IS_VENDOR_DEFINED(type) \ (((type) & PSA_KEY_TYPE_VENDOR_FLAG) != 0) -#define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \ - (((type) & PSA_KEY_TYPE_ASYMMETRIC_FLAG) != 0) -#define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \ - (((type) & PSA_KEY_TYPE_ASYMMETRIC_MASK) == PSA_KEY_TYPE_ASYMMETRIC_MASK_PUBLIC) -#define PSA_KEY_TYPE_IS_KEYPAIR(type) \ - (((type) & PSA_KEY_TYPE_ASYMMETRIC_MASK) == PSA_KEY_TYPE_ASYMMETRIC_MASK_KEYPAIR) +#define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \ + (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_ASYMMETRIC) +#define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \ + (((type) & (PSA_KEY_TYPE_CATEGORY_MASK | PSA_KEY_TYPE_PAIR_FLAG) == \ + PSA_KEY_TYPE_CATEGORY_ASYMMETRIC)) +#define PSA_KEY_TYPE_IS_KEYPAIR(type) \ + (((type) & (PSA_KEY_TYPE_CATEGORY_MASK | PSA_KEY_TYPE_PAIR_FLAG)) == \ + (PSA_KEY_TYPE_CATEGORY_ASYMMETRIC | PSA_KEY_TYPE_PAIR_FLAG)) #define PSA_KEY_TYPE_IS_RSA(type) \ - (((type) & PSA_KEY_TYPE_ASYMMETRIC_TEST_MASK) == PSA_KEY_TYPE_RSA_TEST_VALUE) + (((type) & ~PSA_KEY_TYPE_PAIR_FLAG) == PSA_KEY_TYPE_RSA_PUBLIC_KEY) #define PSA_KEY_TYPE_IS_ECC(type) \ - (((type) & PSA_KEY_TYPE_ASYMMETRIC_TEST_MASK) == PSA_KEY_TYPE_ECC_TEST_VALUE) + (((type) & ~PSA_KEY_TYPE_ECC_CURVE_MASK) == PSA_KEY_TYPE_ECC_BASE) typedef uint32_t psa_algorithm_t; -#define PSA_ALG_HASH_BITS 0x01000000 -#define PSA_ALG_RSA_HASH_MASK 0x000000ff -#define PSA_ALG_MD2 0x01000001 -#define PSA_ALG_MD4 0x01000002 -#define PSA_ALG_MD5 0x01000003 -#define PSA_ALG_SHA_256_128 0x01000004 -#define PSA_ALG_RIPEMD160 0x01000005 -#define PSA_ALG_SHA_1 0x01000006 -#define PSA_ALG_SHA_256_160 0x01000007 -#define PSA_ALG_SHA_224 0x01000008 -#define PSA_ALG_SHA_256 0x01000009 -#define PSA_ALG_SHA_384 0x0100000a -#define PSA_ALG_SHA_512 0x0100000b -#define PSA_ALG_SHA_512_224 0x0100000c -#define PSA_ALG_SHA_512_256 0x0100000d -#define PSA_ALG_SHA3_224 0x01000010 -#define PSA_ALG_SHA3_256 0x01000011 -#define PSA_ALG_SHA3_384 0x01000012 -#define PSA_ALG_SHA3_512 0x01000013 +#define PSA_ALG_VENDOR_FLAG ((psa_algorithm_t)0x80000000) +#define PSA_ALG_CATEGORY_MASK ((psa_algorithm_t)0x7f000000) +#define PSA_ALG_CATEGORY_HASH ((psa_algorithm_t)0x01000000) +#define PSA_ALG_CATEGORY_MAC ((psa_algorithm_t)0x02000000) +#define PSA_ALG_CATEGORY_CIPHER ((psa_algorithm_t)0x04000000) +#define PSA_ALG_CATEGORY_AEAD ((psa_algorithm_t)0x06000000) +#define PSA_ALG_CATEGORY_SIGN ((psa_algorithm_t)0x10000000) +#define PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION ((psa_algorithm_t)0x12000000) +#define PSA_ALG_CATEGORY_KEY_AGREEMENT ((psa_algorithm_t)0x22000000) +#define PSA_ALG_CATEGORY_KEY_DERIVATION ((psa_algorithm_t)0x30000000) -#define PSA_ALG_RSA_PKCS1V15_RAW 0x40000100 -#define PSA_ALG_RSA_PSS_MGF1 0x40000200 -#define PSA_ALG_RSA_OAEP 0x40000300 -#define PSA_ALG_RSA_PKCS1V15(hash_alg) \ - (PSA_ALG_RSA_PKCS1V15_RAW | ((hash_alg) & PSA_ALG_RSA_HASH_MASK)) -#define PSA_ALG_IS_RSA_PKCS1V15(alg) \ +#define PSA_ALG_IS_VENDOR_DEFINED(alg) \ + (((alg) & PSA_ALG_VENDOR_FLAG) != 0) +#define PSA_ALG_IS_HASH(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_HASH) +#define PSA_ALG_IS_MAC(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_MAC) +#define PSA_ALG_IS_CIPHER(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_CIPHER) +#define PSA_ALG_IS_AEAD(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_AEAD) +#define PSA_ALG_IS_SIGN(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_SIGN) +#define PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION) +#define PSA_ALG_IS_KEY_AGREEMENT(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_KEY_AGREEMENT) +#define PSA_ALG_IS_KEY_DERIVATION(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_KEY_DERIVATION) + +#define PSA_ALG_HASH_MASK ((psa_algorithm_t)0x000000ff) +#define PSA_ALG_MD2 ((psa_algorithm_t)0x01000001) +#define PSA_ALG_MD4 ((psa_algorithm_t)0x01000002) +#define PSA_ALG_MD5 ((psa_algorithm_t)0x01000003) +#define PSA_ALG_SHA_256_128 ((psa_algorithm_t)0x01000004) +#define PSA_ALG_RIPEMD160 ((psa_algorithm_t)0x01000005) +#define PSA_ALG_SHA_1 ((psa_algorithm_t)0x01000006) +#define PSA_ALG_SHA_256_160 ((psa_algorithm_t)0x01000007) +#define PSA_ALG_SHA_224 ((psa_algorithm_t)0x01000008) +#define PSA_ALG_SHA_256 ((psa_algorithm_t)0x01000009) +#define PSA_ALG_SHA_384 ((psa_algorithm_t)0x0100000a) +#define PSA_ALG_SHA_512 ((psa_algorithm_t)0x0100000b) +#define PSA_ALG_SHA_512_224 ((psa_algorithm_t)0x0100000c) +#define PSA_ALG_SHA_512_256 ((psa_algorithm_t)0x0100000d) +#define PSA_ALG_SHA3_224 ((psa_algorithm_t)0x01000010) +#define PSA_ALG_SHA3_256 ((psa_algorithm_t)0x01000011) +#define PSA_ALG_SHA3_384 ((psa_algorithm_t)0x01000012) +#define PSA_ALG_SHA3_512 ((psa_algorithm_t)0x01000013) + +#define PSA_ALG_HMAC_BASE ((psa_algorithm_t)0x02800000) +#define PSA_ALG_HMAC(hash_alg) \ + (PSA_ALG_HMAC_BASE | (hash_alg)) +#define PSA_ALG_CBC_MAC ((psa_algorithm_t)0x02000001) +#define PSA_ALG_CMAC ((psa_algorithm_t)0x02000002) +#define PSA_ALG_GMAC ((psa_algorithm_t)0x02000003) + +#define PSA_ALG_BLOCK_CIPHER_BASE_MASK ((psa_algorithm_t)0x000000ff) +#define PSA_ALG_BLOCK_CIPHER_PADDING_MASK ((psa_algorithm_t)0x007f0000) +#define PSA_ALG_BLOCK_CIPHER_PAD_PKCS7 ((psa_algorithm_t)0x00010000) +#define PSA_ALG_CBC_BASE ((psa_algorithm_t)0x04000001) +#define PSA_ALG_CFB_BASE ((psa_algorithm_t)0x04000003) +#define PSA_ALG_OFB_BASE ((psa_algorithm_t)0x04000004) +#define PSA_ALG_XTS_BASE ((psa_algorithm_t)0x04000005) +#define PSA_ALG_STREAM_CIPHER ((psa_algorithm_t)0x04800000) +#define PSA_ALG_CTR ((psa_algorithm_t)0x04800001) + +#define PSA_ALG_CCM ((psa_algorithm_t)0x06000002) +#define PSA_ALG_GCM ((psa_algorithm_t)0x06000003) + +#define PSA_ALG_RSA_PKCS1V15_RAW ((psa_algorithm_t)0x10010000) +#define PSA_ALG_RSA_PSS_MGF1 ((psa_algorithm_t)0x10020000) +#define PSA_ALG_RSA_OAEP ((psa_algorithm_t)0x12020000) +#define PSA_ALG_RSA_PKCS1V15(hash_alg) \ + (PSA_ALG_RSA_PKCS1V15_RAW | ((hash_alg) & PSA_ALG_HASH_MASK)) +#define PSA_ALG_IS_RSA_PKCS1V15(alg) \ (((alg) & 0x7fffff00) == PSA_ALG_RSA_PKCS1V15_RAW) -#define PSA_ALG_RSA_GET_HASH(alg) \ - (((alg) & PSA_ALG_RSA_HASH_MASK) | PSA_ALG_HASH_BITS) - -#define PSA_ALG_VENDOR_FLAG 0x80000000 +#define PSA_ALG_RSA_GET_HASH(alg) \ + (((alg) & PSA_ALG_HASH_MASK) | PSA_ALG_CATEGORY_HASH) /**@}*/ From a59052993862d7e91ea21dfcfdb655454c134149 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Feb 2018 20:59:33 +0100 Subject: [PATCH 09/36] Greatly expanded mbedtls_to_psa_error It now covers most cryptography algorithm modules (missing: bignum, DHM, everything ECC, HMAC_DRBG). --- include/psa/crypto.h | 6 +- library/psa_crypto.c | 149 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 152 insertions(+), 3 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 6276bac6e..c1eb60ff8 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -71,6 +71,8 @@ typedef enum { PSA_ERROR_INSUFFICIENT_STORAGE, /** There was a communication failure inside the implementation. */ PSA_ERROR_COMMUNICATION_FAILURE, + /** There was a storage failure that may have led to data loss. */ + PSA_ERROR_STORAGE_FAILURE, /** A hardware failure was detected. */ PSA_ERROR_HARDWARE_FAILURE, /** A tampering attempt was detected. */ @@ -78,8 +80,10 @@ typedef enum { /** There is not enough entropy to generate random data needed for the requested action. */ PSA_ERROR_INSUFFICIENT_ENTROPY, - /** The signature or MAC is incorrect. */ + /** The signature, MAC or hash is incorrect. */ PSA_ERROR_INVALID_SIGNATURE, + /** The decrypted padding is incorrect. */ + PSA_ERROR_INVALID_PADDING, /** An error occurred that does not correspond to any defined failure cause. */ PSA_ERROR_UNKNOWN_ERROR, diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 66d81a365..84995176c 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -38,14 +38,32 @@ #define mbedtls_free free #endif +#include "mbedtls/arc4.h" +#include "mbedtls/blowfish.h" +#include "mbedtls/camellia.h" +#include "mbedtls/cipher.h" +#include "mbedtls/ccm.h" +#include "mbedtls/cmac.h" #include "mbedtls/ctr_drbg.h" +#include "mbedtls/des.h" #include "mbedtls/ecp.h" #include "mbedtls/entropy.h" +#include "mbedtls/error.h" +#include "mbedtls/gcm.h" +#include "mbedtls/md2.h" +#include "mbedtls/md4.h" +#include "mbedtls/md5.h" #include "mbedtls/md.h" #include "mbedtls/md_internal.h" #include "mbedtls/pk.h" #include "mbedtls/pk_internal.h" +#include "mbedtls/ripemd160.h" #include "mbedtls/rsa.h" +#include "mbedtls/sha1.h" +#include "mbedtls/sha256.h" +#include "mbedtls/sha512.h" +#include "mbedtls/xtea.h" + /* Implementation that should never be optimized out by the compiler */ @@ -89,21 +107,110 @@ static psa_global_data_t global_data; static psa_status_t mbedtls_to_psa_error( int ret ) { - switch( ret ) + /* If there's both a high-level code and low-level code, dispatch on + * the high-level code. */ + switch( ret < -0x7f ? - ( -ret & 0x7f80 ) : ret ) { case 0: return( PSA_SUCCESS ); + + case MBEDTLS_ERR_AES_INVALID_KEY_LENGTH: + case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH: + case MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_AES_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH: + case MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH: + case MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_CCM_BAD_INPUT: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_CCM_AUTH_FAILED: + return( PSA_ERROR_INVALID_SIGNATURE ); + case MBEDTLS_ERR_CCM_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_CIPHER_ALLOC_FAILED: + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + case MBEDTLS_ERR_CIPHER_INVALID_PADDING: + return( PSA_ERROR_INVALID_PADDING ); + case MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED: + return( PSA_ERROR_BAD_STATE ); + case MBEDTLS_ERR_CIPHER_AUTH_FAILED: + return( PSA_ERROR_INVALID_SIGNATURE ); + case MBEDTLS_ERR_CIPHER_INVALID_CONTEXT: + return( PSA_ERROR_TAMPERING_DETECTED ); + case MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED: + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); + case MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG: + case MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR: + return( PSA_ERROR_INSUFFICIENT_ENTROPY ); + + case MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_DES_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + case MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED: case MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE: case MBEDTLS_ERR_ENTROPY_SOURCE_FAILED: return( PSA_ERROR_INSUFFICIENT_ENTROPY ); + + case MBEDTLS_ERR_GCM_AUTH_FAILED: + return( PSA_ERROR_INVALID_SIGNATURE ); + case MBEDTLS_ERR_GCM_BAD_INPUT: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_GCM_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_MD2_HW_ACCEL_FAILED: + case MBEDTLS_ERR_MD4_HW_ACCEL_FAILED: + case MBEDTLS_ERR_MD5_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_MD_BAD_INPUT_DATA: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_MD_ALLOC_FAILED: + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + case MBEDTLS_ERR_MD_FILE_IO_ERROR: + return( PSA_ERROR_STORAGE_FAILURE ); + case MBEDTLS_ERR_MD_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + case MBEDTLS_ERR_PK_ALLOC_FAILED: return( PSA_ERROR_INSUFFICIENT_MEMORY ); case MBEDTLS_ERR_PK_TYPE_MISMATCH: case MBEDTLS_ERR_PK_BAD_INPUT_DATA: return( PSA_ERROR_INVALID_ARGUMENT ); case MBEDTLS_ERR_PK_FILE_IO_ERROR: - return( PSA_ERROR_TAMPERING_DETECTED ); + return( PSA_ERROR_STORAGE_FAILURE ); case MBEDTLS_ERR_PK_KEY_INVALID_VERSION: case MBEDTLS_ERR_PK_KEY_INVALID_FORMAT: return( PSA_ERROR_INVALID_ARGUMENT ); @@ -120,6 +227,44 @@ static psa_status_t mbedtls_to_psa_error( int ret ) return( PSA_ERROR_NOT_SUPPORTED ); case MBEDTLS_ERR_PK_SIG_LEN_MISMATCH: return( PSA_ERROR_INVALID_SIGNATURE ); + case MBEDTLS_ERR_PK_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_RSA_BAD_INPUT_DATA: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_RSA_INVALID_PADDING: + return( PSA_ERROR_INVALID_PADDING ); + case MBEDTLS_ERR_RSA_KEY_GEN_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + case MBEDTLS_ERR_RSA_KEY_CHECK_FAILED: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_RSA_PUBLIC_FAILED: + case MBEDTLS_ERR_RSA_PRIVATE_FAILED: + return( PSA_ERROR_TAMPERING_DETECTED ); + case MBEDTLS_ERR_RSA_VERIFY_FAILED: + return( PSA_ERROR_INVALID_SIGNATURE ); + case MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE: + return( PSA_ERROR_BUFFER_TOO_SMALL ); + case MBEDTLS_ERR_RSA_RNG_FAILED: + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + case MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION: + return( PSA_ERROR_NOT_SUPPORTED ); + case MBEDTLS_ERR_RSA_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED: + case MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED: + case MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + + case MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH: + return( PSA_ERROR_INVALID_ARGUMENT ); + case MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED: + return( PSA_ERROR_HARDWARE_FAILURE ); + default: return( PSA_ERROR_UNKNOWN_ERROR ); } From 9ef733faa0b11bce4dee9be4e0a453d0622bd519 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Feb 2018 21:05:37 +0100 Subject: [PATCH 10/36] Implement hash functions New header file crypto_struct.h. The main file crypto.sh declares structures which are implementation-defined. These structures must be defined in crypto_struct.h, which is included at the end so that the structures can use types defined in crypto.h. Implement psa_hash_start, psa_hash_update and psa_hash_final. This should work for all hash algorithms supported by Mbed TLS, but has only been smoke-tested for SHA-256, and only in the nominal case. --- include/psa/crypto.h | 54 ++++ include/psa/crypto_struct.h | 96 +++++++ library/psa_crypto.c | 283 ++++++++++++++++++++ tests/suites/test_suite_psa_crypto.data | 8 + tests/suites/test_suite_psa_crypto.function | 67 +++++ 5 files changed, 508 insertions(+) create mode 100644 include/psa/crypto_struct.h diff --git a/include/psa/crypto.h b/include/psa/crypto.h index c1eb60ff8..90140d7a9 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -307,6 +307,54 @@ psa_status_t psa_export_key(psa_key_slot_t key, /**@}*/ +/** \defgroup hash Message digests + * @{ + */ + +typedef struct psa_hash_operation_s psa_hash_operation_t; + +#define PSA_HASH_FINAL_SIZE(alg) \ + ( \ + (alg) == PSA_ALG_MD2 ? 16 : \ + (alg) == PSA_ALG_MD4 ? 16 : \ + (alg) == PSA_ALG_MD5 ? 16 : \ + (alg) == PSA_ALG_SHA_256_128 ? 16 : \ + (alg) == PSA_ALG_RIPEMD160 ? 20 : \ + (alg) == PSA_ALG_SHA_1 ? 20 : \ + (alg) == PSA_ALG_SHA_256_160 ? 20 : \ + (alg) == PSA_ALG_SHA_224 ? 28 : \ + (alg) == PSA_ALG_SHA_256 ? 32 : \ + (alg) == PSA_ALG_SHA_384 ? 48 : \ + (alg) == PSA_ALG_SHA_512 ? 64 : \ + (alg) == PSA_ALG_SHA_512_224 ? 28 : \ + (alg) == PSA_ALG_SHA_512_256 ? 32 : \ + (alg) == PSA_ALG_SHA3_224 ? 28 : \ + (alg) == PSA_ALG_SHA3_256 ? 32 : \ + (alg) == PSA_ALG_SHA3_384 ? 48 : \ + (alg) == PSA_ALG_SHA3_512 ? 64 : \ + 0) + +psa_status_t psa_hash_start(psa_hash_operation_t *operation, + psa_algorithm_t alg); + +psa_status_t psa_hash_update(psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length); + +psa_status_t psa_hash_finish(psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); + +psa_status_t psa_hash_verify(psa_hash_operation_t *operation, + const uint8_t *hash, + size_t hash_length); + +psa_status_t ps_hash_abort(psa_hash_operation_t *operation); + +/**@}*/ + +/** \defgroup MAC Message authentication codes /** \defgroup asymmetric Asymmetric cryptography * @{ */ @@ -379,6 +427,12 @@ psa_status_t psa_asymmetric_verify(psa_key_slot_t key, } #endif +/* The file "crypto_struct.h" contains definitions for + * implementation-specific structs that are declared above. */ +#include "crypto_struct.h" + +/* The file "crypto_extra.h" contains vendor-specific definitions. This + * can include vendor-defined algorithms, extra functions, etc. */ #include "crypto_extra.h" #endif /* PSA_CRYPTO_H */ diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h new file mode 100644 index 000000000..6bd4ed23d --- /dev/null +++ b/include/psa/crypto_struct.h @@ -0,0 +1,96 @@ +/** + * \file psa/crypto_struct.h + * + * \brief PSA cryptography module: Mbed TLS structured type implementations + */ +/* + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef PSA_CRYPTO_STRUCT_H +#define PSA_CRYPTO_STRUCT_H + +/* Include the Mbed TLS configuration file, the way Mbed TLS does it + * in each of its header files. */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "../mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/cipher.h" +#include "mbedtls/cmac.h" +#include "mbedtls/gcm.h" +#include "mbedtls/md.h" +#include "mbedtls/md2.h" +#include "mbedtls/md4.h" +#include "mbedtls/md5.h" +#include "mbedtls/ripemd160.h" +#include "mbedtls/sha1.h" +#include "mbedtls/sha256.h" +#include "mbedtls/sha512.h" + +struct psa_hash_operation_s +{ + psa_algorithm_t alg; + union + { +#if defined(MBEDTLS_MD2_C) + mbedtls_md2_context md2; +#endif +#if defined(MBEDTLS_MD4_C) + mbedtls_md4_context md4; +#endif +#if defined(MBEDTLS_MD5_C) + mbedtls_md5_context md5; +#endif +#if defined(MBEDTLS_RIPEMD160_C) + mbedtls_ripemd160_context ripemd160; +#endif +#if defined(MBEDTLS_SHA1_C) + mbedtls_sha1_context sha1; +#endif +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_context sha256; +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_context sha512; +#endif + } ctx; +}; + +struct psa_mac_operation_s +{ + psa_algorithm_t alg; + int key_set : 1; + int iv_required : 1; + int iv_set : 1; + int has_input : 1; + uint8_t mac_size; + union + { +#if defined(MBEDTLS_MD_C) + mbedtls_md_context_t hmac; +#endif +#if defined(MBEDTLS_CMAC_C) + mbedtls_cipher_context_t cmac; +#endif + } ctx; +}; + +#endif /* PSA_CRYPTO_STRUCT_H */ diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 84995176c..ca275495f 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -72,6 +72,20 @@ static void mbedtls_zeroize( void *v, size_t n ) volatile unsigned char *p = v; while( n-- ) *p++ = 0; } +/* constant-time buffer comparison */ +static inline int safer_memcmp( const uint8_t *a, const uint8_t *b, size_t n ) +{ + size_t i; + unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + diff |= a[i] ^ b[i]; + + return( diff ); +} + + + /****************************************************************/ /* Global data, support functions and library management */ /****************************************************************/ @@ -573,6 +587,275 @@ static psa_algorithm_t mbedtls_md_alg_to_psa( mbedtls_md_type_t md_alg ) } #endif +psa_status_t psa_hash_abort( psa_hash_operation_t *operation ) +{ + switch( operation->alg ) + { +#if defined(MBEDTLS_MD2_C) + case PSA_ALG_MD2: + mbedtls_md2_free( &operation->ctx.md2 ); + break; +#endif +#if defined(MBEDTLS_MD4_C) + case PSA_ALG_MD4: + mbedtls_md4_free( &operation->ctx.md4 ); + break; +#endif +#if defined(MBEDTLS_MD5_C) + case PSA_ALG_MD5: + mbedtls_md5_free( &operation->ctx.md5 ); + break; +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case PSA_ALG_RIPEMD160: + mbedtls_ripemd160_free( &operation->ctx.ripemd160 ); + break; +#endif +#if defined(MBEDTLS_SHA1_C) + case PSA_ALG_SHA_1: + mbedtls_sha1_free( &operation->ctx.sha1 ); + break; +#endif +#if defined(MBEDTLS_SHA256_C) + case PSA_ALG_SHA_224: + case PSA_ALG_SHA_256: + mbedtls_sha256_free( &operation->ctx.sha256 ); + break; +#endif +#if defined(MBEDTLS_SHA512_C) + case PSA_ALG_SHA_384: + case PSA_ALG_SHA_512: + mbedtls_sha512_free( &operation->ctx.sha512 ); + break; +#endif + default: + return( PSA_ERROR_NOT_SUPPORTED ); + } + operation->alg = 0; + return( PSA_SUCCESS ); +} + +psa_status_t psa_hash_start( psa_hash_operation_t *operation, + psa_algorithm_t alg ) +{ + int ret; + operation->alg = 0; + switch( alg ) + { +#if defined(MBEDTLS_MD2_C) + case PSA_ALG_MD2: + mbedtls_md2_init( &operation->ctx.md2 ); + ret = mbedtls_md2_starts_ret( &operation->ctx.md2 ); + break; +#endif +#if defined(MBEDTLS_MD4_C) + case PSA_ALG_MD4: + mbedtls_md4_init( &operation->ctx.md4 ); + ret = mbedtls_md4_starts_ret( &operation->ctx.md4 ); + break; +#endif +#if defined(MBEDTLS_MD5_C) + case PSA_ALG_MD5: + mbedtls_md5_init( &operation->ctx.md5 ); + ret = mbedtls_md5_starts_ret( &operation->ctx.md5 ); + break; +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case PSA_ALG_RIPEMD160: + mbedtls_ripemd160_init( &operation->ctx.ripemd160 ); + ret = mbedtls_ripemd160_starts_ret( &operation->ctx.ripemd160 ); + break; +#endif +#if defined(MBEDTLS_SHA1_C) + case PSA_ALG_SHA_1: + mbedtls_sha1_init( &operation->ctx.sha1 ); + ret = mbedtls_sha1_starts_ret( &operation->ctx.sha1 ); + break; +#endif +#if defined(MBEDTLS_SHA256_C) + case PSA_ALG_SHA_224: + mbedtls_sha256_init( &operation->ctx.sha256 ); + ret = mbedtls_sha256_starts_ret( &operation->ctx.sha256, 1 ); + break; + case PSA_ALG_SHA_256: + mbedtls_sha256_init( &operation->ctx.sha256 ); + ret = mbedtls_sha256_starts_ret( &operation->ctx.sha256, 0 ); + break; +#endif +#if defined(MBEDTLS_SHA512_C) + case PSA_ALG_SHA_384: + mbedtls_sha512_init( &operation->ctx.sha512 ); + ret = mbedtls_sha512_starts_ret( &operation->ctx.sha512, 1 ); + break; + case PSA_ALG_SHA_512: + mbedtls_sha512_init( &operation->ctx.sha512 ); + ret = mbedtls_sha512_starts_ret( &operation->ctx.sha512, 0 ); + break; +#endif + default: + return( PSA_ERROR_NOT_SUPPORTED ); + } + if( ret == 0 ) + operation->alg = alg; + else + psa_hash_abort( operation ); + return( mbedtls_to_psa_error( ret ) ); +} + +psa_status_t psa_hash_update( psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length ) +{ + int ret; + switch( operation->alg ) + { +#if defined(MBEDTLS_MD2_C) + case PSA_ALG_MD2: + ret = mbedtls_md2_update_ret( &operation->ctx.md2, + input, input_length ); + break; +#endif +#if defined(MBEDTLS_MD4_C) + case PSA_ALG_MD4: + ret = mbedtls_md4_update_ret( &operation->ctx.md4, + input, input_length ); + break; +#endif +#if defined(MBEDTLS_MD5_C) + case PSA_ALG_MD5: + ret = mbedtls_md5_update_ret( &operation->ctx.md5, + input, input_length ); + break; +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case PSA_ALG_RIPEMD160: + ret = mbedtls_ripemd160_update_ret( &operation->ctx.ripemd160, + input, input_length ); + break; +#endif +#if defined(MBEDTLS_SHA1_C) + case PSA_ALG_SHA_1: + ret = mbedtls_sha1_update_ret( &operation->ctx.sha1, + input, input_length ); + break; +#endif +#if defined(MBEDTLS_SHA256_C) + case PSA_ALG_SHA_224: + case PSA_ALG_SHA_256: + ret = mbedtls_sha256_update_ret( &operation->ctx.sha256, + input, input_length ); + break; +#endif +#if defined(MBEDTLS_SHA512_C) + case PSA_ALG_SHA_384: + case PSA_ALG_SHA_512: + ret = mbedtls_sha512_update_ret( &operation->ctx.sha512, + input, input_length ); + break; +#endif + default: + ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA; + break; + } + if( ret != 0 ) + psa_hash_abort( operation ); + return( mbedtls_to_psa_error( ret ) ); +} + +psa_status_t psa_hash_finish( psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length ) +{ + int ret; + size_t actual_hash_length = PSA_HASH_FINAL_SIZE( operation->alg ); + + /* Fill the output buffer with something that isn't a valid hash + * (barring an attack on the hash and deliberately-crafted input), + * in case the caller doesn't check the return status properly. */ + *hash_length = actual_hash_length; + memset( hash, '!', hash_size ); + + if( hash_size < actual_hash_length ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + + switch( operation->alg ) + { +#if defined(MBEDTLS_MD2_C) + case PSA_ALG_MD2: + ret = mbedtls_md2_finish_ret( &operation->ctx.md2, hash ); + break; +#endif +#if defined(MBEDTLS_MD4_C) + case PSA_ALG_MD4: + ret = mbedtls_md4_finish_ret( &operation->ctx.md4, hash ); + break; +#endif +#if defined(MBEDTLS_MD5_C) + case PSA_ALG_MD5: + ret = mbedtls_md5_finish_ret( &operation->ctx.md5, hash ); + break; +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case PSA_ALG_RIPEMD160: + ret = mbedtls_ripemd160_finish_ret( &operation->ctx.ripemd160, hash ); + break; +#endif +#if defined(MBEDTLS_SHA1_C) + case PSA_ALG_SHA_1: + ret = mbedtls_sha1_finish_ret( &operation->ctx.sha1, hash ); + break; +#endif +#if defined(MBEDTLS_SHA256_C) + case PSA_ALG_SHA_224: + case PSA_ALG_SHA_256: + ret = mbedtls_sha256_finish_ret( &operation->ctx.sha256, hash ); + break; +#endif +#if defined(MBEDTLS_SHA512_C) + case PSA_ALG_SHA_384: + case PSA_ALG_SHA_512: + ret = mbedtls_sha512_finish_ret( &operation->ctx.sha512, hash ); + break; +#endif + default: + ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA; + break; + } + + if( ret == 0 ) + { + return( psa_hash_abort( operation ) ); + } + else + { + psa_hash_abort( operation ); + return( mbedtls_to_psa_error( ret ) ); + } +} + +psa_status_t psa_hash_verify(psa_hash_operation_t *operation, + const uint8_t *hash, + size_t hash_length) +{ + uint8_t actual_hash[MBEDTLS_MD_MAX_SIZE]; + size_t actual_hash_length; + psa_status_t status = psa_hash_finish( operation, + actual_hash, sizeof( actual_hash ), + &actual_hash_length ); + if( status != PSA_SUCCESS ) + return( status ); + if( actual_hash_length != hash_length ) + return( PSA_ERROR_INVALID_SIGNATURE ); + if( safer_memcmp( hash, actual_hash, actual_hash_length ) != 0 ) + return( PSA_ERROR_INVALID_SIGNATURE ); + return( PSA_SUCCESS ); +} + + + + +/****************************************************************/ /****************************************************************/ diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index a2d6b89fd..f53b1a436 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -37,6 +37,14 @@ import_export:"3082025a0201000281806c49704e91f3df44fc99e9b3c0fee5025cc04d09529a1 #depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED #import_export:"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_KEY_TYPE_ECC_NISTP256R1:256:0:PSA_SUCCESS:1 # +PSA hash finish: SHA-256 +depends_on:MBEDTLS_SHA256_C +hash_finish:PSA_ALG_SHA_256:"bd":"68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b" + +PSA hash verify: SHA-256 +depends_on:MBEDTLS_SHA256_C +hash_verify:PSA_ALG_SHA_256:"bd":"68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b" + PSA signature size: RSA keypair, 1024 bits, PKCS#1 v1.5 raw signature_size:PSA_KEY_TYPE_RSA_KEYPAIR:1024:PSA_ALG_RSA_PKCS1V15_RAW:128 diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index c5d536e46..21802d147 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -133,6 +133,73 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void hash_finish( int alg_arg, char *input_hex, char *hash_hex ) +{ + psa_algorithm_t alg = alg_arg; + unsigned char *input = NULL; + size_t input_size; + unsigned char expected_hash[MBEDTLS_MD_MAX_SIZE]; + size_t expected_hash_length; + unsigned char actual_hash[MBEDTLS_MD_MAX_SIZE]; + size_t actual_hash_length; + psa_hash_operation_t operation; + + input_size = strlen( input_hex ) / 2; + input = mbedtls_calloc( 1, input_size ); + TEST_ASSERT( input != NULL ); + input_size = unhexify( input, input_hex ); + expected_hash_length = unhexify( expected_hash, hash_hex ); + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_hash_start( &operation, alg ) == PSA_SUCCESS ); + TEST_ASSERT( psa_hash_update( &operation, + input, input_size ) == PSA_SUCCESS ); + TEST_ASSERT( psa_hash_finish( &operation, + actual_hash, sizeof( actual_hash ), + &actual_hash_length ) == PSA_SUCCESS ); + TEST_ASSERT( actual_hash_length == expected_hash_length ); + TEST_ASSERT( memcmp( expected_hash, actual_hash, + expected_hash_length ) == 0 ); + +exit: + mbedtls_free( input ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void hash_verify( int alg_arg, char *input_hex, char *hash_hex ) +{ + psa_algorithm_t alg = alg_arg; + unsigned char *input = NULL; + size_t input_size; + unsigned char expected_hash[MBEDTLS_MD_MAX_SIZE]; + size_t expected_hash_length; + psa_hash_operation_t operation; + + input_size = strlen( input_hex ) / 2; + input = mbedtls_calloc( 1, input_size ); + TEST_ASSERT( input != NULL ); + input_size = unhexify( input, input_hex ); + expected_hash_length = unhexify( expected_hash, hash_hex ); + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_hash_start( &operation, alg ) == PSA_SUCCESS ); + TEST_ASSERT( psa_hash_update( &operation, + input, input_size ) == PSA_SUCCESS ); + TEST_ASSERT( psa_hash_verify( &operation, + expected_hash, + expected_hash_length ) == PSA_SUCCESS ); + +exit: + mbedtls_free( input ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void signature_size( int type_arg, int bits, int alg_arg, int expected_size_arg ) { From 308b91d7dbb2d58038bece8ed2aaa92d9a290ef0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Feb 2018 09:47:44 +0100 Subject: [PATCH 11/36] Wrote documentation for several functions, macros and types Document key import/export functions, hash functions, and asymmetric sign/verify, as well as some related macros and types. Nicer formatting for return values: use \retval. --- include/psa/crypto.h | 373 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 342 insertions(+), 31 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 90140d7a9..060c007ec 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -18,7 +18,7 @@ /** \brief Key slot number. * * This type represents key slots. It must be an unsigned integral - * type.* The choice of type is implementation-dependent. + * type. The choice of type is implementation-dependent. * 0 is not a valid key slot number. The meaning of other values is * implementation dependent. * @@ -98,12 +98,12 @@ typedef enum { * Applications may call this function more than once. Once a call * succeeds, subsequent calls are guaranteed to succeed. * - * \return * \c PSA_SUCCESS: success. - * * \c PSA_ERROR_INSUFFICIENT_MEMORY - * * \c PSA_ERROR_COMMUNICATION_FAILURE - * * \c PSA_ERROR_HARDWARE_FAILURE - * * \c PSA_ERROR_TAMPERING_DETECTED - * * \c PSA_ERROR_INSUFFICIENT_ENTROPY + * \retval PSA_SUCCESS + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + * \retval PSA_ERROR_INSUFFICIENT_ENTROPY */ psa_status_t psa_crypto_init(void); @@ -116,6 +116,8 @@ psa_status_t psa_crypto_init(void); * @{ */ +/** \brief Encoding of a key type. + */ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_NONE ((psa_key_type_t)0x00000000) @@ -133,7 +135,9 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_CAMELLIA ((psa_key_type_t)0x04000003) #define PSA_KEY_TYPE_ARC4 ((psa_key_type_t)0x04000004) +/** RSA public key. */ #define PSA_KEY_TYPE_RSA_PUBLIC_KEY ((psa_key_type_t)0x06010000) +/** RSA key pair (private and public key). */ #define PSA_KEY_TYPE_RSA_KEYPAIR ((psa_key_type_t)0x07010000) #define PSA_KEY_TYPE_ECC_BASE ((psa_key_type_t)0x06030000) #define PSA_KEY_TYPE_ECC_CURVE_MASK ((psa_key_type_t)0x0000ffff) @@ -153,6 +157,14 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_IS_ECC(type) \ (((type) & ~PSA_KEY_TYPE_ECC_CURVE_MASK) == PSA_KEY_TYPE_ECC_BASE) +/** \brief Encoding of a cryptographic algorithm. + * + * For algorithms that can be applied to multiple key types, this type + * does not encode the key type. For example, for symmetric ciphers + * based on a block cipher, #psa_algorithm_t encodes the block cipher + * mode and the padding mode while the block cipher itself is encoded + * via #psa_key_type_t. + */ typedef uint32_t psa_algorithm_t; #define PSA_ALG_VENDOR_FLAG ((psa_algorithm_t)0x80000000) @@ -168,6 +180,13 @@ typedef uint32_t psa_algorithm_t; #define PSA_ALG_IS_VENDOR_DEFINED(alg) \ (((alg) & PSA_ALG_VENDOR_FLAG) != 0) +/** Whether the specified algorithm is a hash algorithm. + * + * \param alg An algorithm identifier (\c PSA_ALG_XXX value) + * + * \return 1 if \c alg is a hash algorithm, 0 otherwise. + * This macro may return either 0 or 1 if \c alg is not a valid + * algorithm identifier. */ #define PSA_ALG_IS_HASH(alg) \ (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_HASH) #define PSA_ALG_IS_MAC(alg) \ @@ -245,13 +264,26 @@ typedef uint32_t psa_algorithm_t; * * This function supports any output from psa_export_key(). * - * \return * \c PSA_SUCCESS: success. - * * \c PSA_ERROR_NOT_SUPPORTED - * * \c PSA_ERROR_INVALID_ARGUMENT - * * \c PSA_ERROR_INSUFFICIENT_MEMORY - * * \c PSA_ERROR_COMMUNICATION_FAILURE - * * \c PSA_ERROR_HARDWARE_FAILURE - * * \c PSA_ERROR_TAMPERING_DETECTED + * \param key Slot where the key will be stored. This must be a + * valid slot for a key of the chosen type. It must + * be unoccupied. + * \param type Key type (a \c PSA_KEY_TYPE_XXX value). + * \param data Buffer containing the key data. + * \param data_length Size of the \c data buffer in bytes. + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_NOT_SUPPORTED + * The key type or key size is not supported. + * \retval PSA_ERROR_INVALID_ARGUMENT + * The key slot is invalid, + * or the key data is not correctly formatted. + * \retval PSA_ERROR_OCCUPIED_SLOT + There is already a key in the specified slot. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED */ psa_status_t psa_import_key(psa_key_slot_t key, psa_key_type_t type, @@ -261,22 +293,31 @@ psa_status_t psa_import_key(psa_key_slot_t key, /** * \brief Destroy a key. * - * \return * \c PSA_SUCCESS: success. - * * \c PSA_ERROR_EMPTY_SLOT - * * \c PSA_ERROR_COMMUNICATION_FAILURE - * * \c PSA_ERROR_HARDWARE_FAILURE - * * \c PSA_ERROR_TAMPERING_DETECTED + * \retval PSA_SUCCESS + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED */ psa_status_t psa_destroy_key(psa_key_slot_t key); /** * \brief Get basic metadata about a key. * - * \return * \c PSA_SUCCESS: success. - * * \c PSA_ERROR_EMPTY_SLOT - * * \c PSA_ERROR_COMMUNICATION_FAILURE - * * \c PSA_ERROR_HARDWARE_FAILURE - * * \c PSA_ERROR_TAMPERING_DETECTED + * \param key Slot whose content is queried. This must + * be an occupied key slot. + * \param type On success, the key type (a \c PSA_KEY_TYPE_XXX value). + * This may be a null pointer, in which case the key type + * is not written. + * \param bits On success, the key size in bits. + * This may be a null pointer, in which case the key type + * is not written. + * + * \retval PSA_SUCCESS + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED */ psa_status_t psa_get_key_information(psa_key_slot_t key, psa_key_type_t *type, @@ -293,11 +334,32 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, * identical: the implementation may choose a different representation * of the same key. * - * \return * \c PSA_SUCCESS: success. - * * \c PSA_ERROR_EMPTY_SLOT - * * \c PSA_ERROR_COMMUNICATION_FAILURE - * * \c PSA_ERROR_HARDWARE_FAILURE - * * \c PSA_ERROR_TAMPERING_DETECTED + * For standard key types, the output format is as follows: + * + * - For symmetric keys (including MAC keys), the format is the + * raw bytes of the key. + * - For DES, the key data consists of 8 bytes. The parity bits must be + * correct. + * - For Triple-DES, the format is the concatenation of the + * two or three DES keys. + * - For RSA key pairs keys (#PSA_KEY_TYPE_RSA_KEYPAIR), the format + * is the non-encrypted DER representation defined by PKCS\#8 (RFC 5208) + * as PrivateKeyInfo. + * - For RSA public keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY), the format + * is the DER representation defined by X.509. + * + * \param key Slot whose content is to be exported. This must + * be an occupied key slot. + * \param data Buffer where the key data is to be written. + * \param data_size Size of the \c data buffer in bytes. + * \param data_length On success, the number of bytes + * that make up the key data. + * + * \retval PSA_SUCCESS + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED */ psa_status_t psa_export_key(psa_key_slot_t key, uint8_t *data, @@ -311,8 +373,25 @@ psa_status_t psa_export_key(psa_key_slot_t key, * @{ */ +/** The type of the state data structure for multipart hash operations. + * + * This is an implementation-define \c struct. Applications should not + * make any assumptions about the content of this structure except + * as directed by the documentation of a specific implementation. */ typedef struct psa_hash_operation_s psa_hash_operation_t; +/** The size of the output of psa_hash_finish(), in bytes. + * + * This is also the hash size that psa_hash_verify() expects. + * + * \param alg A hash algorithm (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_HASH(alg) is true). + * + * \return The hash size for the specified hash algorithm. + * If the hash algorithm is not recognized, return 0. + * An implementation may return either 0 or the correct size + * for a hash algorithm that it recognizes, but does not support. + */ #define PSA_HASH_FINAL_SIZE(alg) \ ( \ (alg) == PSA_ALG_MD2 ? 16 : \ @@ -334,27 +413,168 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; (alg) == PSA_ALG_SHA3_512 ? 64 : \ 0) +/** Start a multipart hash operation. + * + * The sequence of operations to calculate a hash (message digest) + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Call psa_hash_start() to specify the algorithm. + * -# Call psa_hash_update() zero, one or more time, passing a fragment + * of the message each time. The hash that is calculated is the hash + * of the concatenation of these messages in order. + * -# To calculate the hash, call psa_hash_finish(). + * To compare the hash with an expected value, call psa_hash_verify(). + * + * The application may call psa_hash_abort() at any time after the operation + * has been initialized with psa_hash_start(). + * + * After a successful call to psa_hash_start(), the application must + * eventually destroy the operation through one of the following means: + * - A failed call to psa_hash_update(). + * - A call to psa_hash_final(), psa_hash_verify() or psa_hash_abort(). + * + * \param operation + * \param alg The hash algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_HASH(alg) is true). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not a hash algorithm. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ psa_status_t psa_hash_start(psa_hash_operation_t *operation, psa_algorithm_t alg); +/** Add a message fragment to a multipart hash operation. + * + * The application must call psa_hash_start() before calling this function. + * + * If this function returns an error status, the operation becomes inactive. + * + * \param operation Active hash operation. + * \param input Buffer containing the message fragment to hash. + * \param input_length Size of the \c input buffer in bytes. + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_BAD_STATE + * The operation state is not valid (not started, or already completed). + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ psa_status_t psa_hash_update(psa_hash_operation_t *operation, const uint8_t *input, size_t input_length); +/** Finish the calculation of the hash of a message. + * + * The application must call psa_hash_start() before calling this function. + * This function calculates the hash of the message formed by concatenating + * the inputs passed to preceding calls to psa_hash_update(). + * + * When this function returns, the operation becomes inactive. + * + * \warning Applications should not call this function if they expect + * a specific value for the hash. Call psa_hash_verify() instead. + * Beware that comparing integrity or authenticity data such as + * hash values with a function such as \c memcmp is risky + * because the time taken by the comparison may leak information + * about the hashed data which could allow an attacker to guess + * a valid hash and thereby bypass security controls. + * + * \param operation Active hash operation. + * \param hash Buffer where the hash is to be written. + * \param hash_size Size of the \c hash buffer in bytes. + * \param hash_length On success, the number of bytes + * that make up the hash value. This is always + * #PSA_HASH_FINAL_SIZE(alg) where \c alg is the + * hash algorithm that is calculated. + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_BAD_STATE + * The operation state is not valid (not started, or already completed). + * \retval PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \c hash buffer is too small. You can determine a + * sufficient buffer size by calling #PSA_HASH_FINAL_SIZE(alg) + * where \c alg is the hash algorithm that is calculated. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ psa_status_t psa_hash_finish(psa_hash_operation_t *operation, uint8_t *hash, size_t hash_size, size_t *hash_length); +/** Finish the calculation of the hash of a message and compare it with + * an expected value. + * + * The application must call psa_hash_start() before calling this function. + * This function calculates the hash of the message formed by concatenating + * the inputs passed to preceding calls to psa_hash_update(). It then + * compares the calculated hash with the expected hash passed as a + * parameter to this function. + * + * When this function returns, the operation becomes inactive. + * + * \note Applications shall make the best effort to ensure that the + * comparison between the actual hash and the expected hash is performed + * in constant time. + * + * \param operation Active hash operation. + * \param hash Buffer containing the expected hash value. + * \param hash_length Size of the \c hash buffer in bytes. + * + * \retval PSA_SUCCESS + * The expected hash is identical to the actual hash of the message. + * \retval PSA_ERROR_INVALID_SIGNATURE + * The hash of the message was calculated successfully, but it + * differs from the expected hash. + * \retval PSA_ERROR_BAD_STATE + * The operation state is not valid (not started, or already completed). + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ psa_status_t psa_hash_verify(psa_hash_operation_t *operation, const uint8_t *hash, size_t hash_length); -psa_status_t ps_hash_abort(psa_hash_operation_t *operation); +/** Abort a hash operation. + * + * This function may be called at any time after psa_hash_start(). + * Aborting an operation frees all associated resources except for the + * \c operation structure itself. + * + * Implementation should strive to be robust and handle inactive hash + * operations safely (do nothing and return #PSA_ERROR_BAD_STATE). However, + * application writers should beware that uninitialized memory may happen + * to be indistinguishable from an active hash operation, and the behavior + * of psa_hash_abort() is undefined in this case. + * + * \param operation Active hash operation. + * + * \retval PSA_SUCCESS + * \retval PSA_ERROR_BAD_STATE + * \c operation is not an active hash operation. + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_hash_abort(psa_hash_operation_t *operation); /**@}*/ -/** \defgroup MAC Message authentication codes /** \defgroup asymmetric Asymmetric cryptography * @{ */ @@ -389,6 +609,33 @@ psa_status_t ps_hash_abort(psa_hash_operation_t *operation); /*V of r,s*/ ((curve_bits) + 8) / 8)) +/** Safe signature buffer size for psa_asymmetric_sign(). + * + * This macro returns a safe buffer size for a signature using a key + * of the specified type and size, with the specified algorithm. + * Note that the actual size of the signature may be smaller + * (some algorithms produce a variable-size signature). + * + * \warning This function may call its arguments multiple times or + * zero times, so you should not pass arguments that contain + * side effects. + * + * \param key_type An asymmetric key type (this may indifferently be a + * key pair type or a public key type). + * \param key_bits The size of the key in bits. + * \param alg The signature algorithm. + * + * \return If the parameters are valid and supported, return + * a buffer size in bytes that guarantees that + * psa_asymmetric_sign() will not fail with + * #PSA_ERROR_BUFFER_TOO_SMALL. + * If the parameters are a valid combination that is not supported + * by the implementation, this macro either shall return either a + * sensible size or 0. + * If the parameters are not valid, the + * return value is unspecified. + * + */ #define PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \ (PSA_KEY_TYPE_IS_RSA(key_type) ? ((void)alg, BITS_TO_BYTES(key_bits)) : \ PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(key_bits) : \ @@ -397,6 +644,41 @@ psa_status_t ps_hash_abort(psa_hash_operation_t *operation); /** * \brief Sign a hash or short message with a private key. * + * \param key Key slot containing an asymmetric key pair. + * \param alg A signature algorithm that is compatible with + * the type of \c key. + * \param hash The message to sign. + * \param hash_length Size of the \c hash buffer in bytes. + * \param salt A salt or label, if supported by the signature + * algorithm. + * If the signature algorithm does not support a + * salt, pass \c NULL. + * If the signature algorithm supports an optional + * salt and you do not want to pass a salt, + * pass \c NULL. + * \param salt_length Size of the \c salt buffer in bytes. + * If \c salt is \c NULL, pass 0. + * \param signature Buffer where the signature is to be written. + * \param signature_size Size of the \c signature buffer in bytes. + * \param signature_length On success, the number of bytes + * that make up the returned signature value. + * This is at most #PSA_HASH_FINAL_SIZE(alg) + * (note that it may be less). + * + * \retval PSA_SUCCESS + * \retval PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \c signature buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) + * where \c key_type and \c key_bits are the type and bit-size + * respectively of \c key. + * \retval PSA_ERROR_NOT_SUPPORTED + * \retval PSA_ERROR_INVALID_ARGUMENT + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + * \retval PSA_ERROR_INSUFFICIENT_ENTROPY */ psa_status_t psa_asymmetric_sign(psa_key_slot_t key, psa_algorithm_t alg, @@ -411,6 +693,35 @@ psa_status_t psa_asymmetric_sign(psa_key_slot_t key, /** * \brief Verify the signature a hash or short message using a public key. * + * \param key Key slot containing a public key or an + * asymmetric key pair. + * \param alg A signature algorithm that is compatible with + * the type of \c key. + * \param hash The message whose signature is to be verified. + * \param hash_length Size of the \c hash buffer in bytes. + * \param salt A salt or label, if supported by the signature + * algorithm. + * If the signature algorithm does not support a + * salt, pass \c NULL. + * If the signature algorithm supports an optional + * salt and you do not want to pass a salt, + * pass \c NULL. + * \param salt_length Size of the \c salt buffer in bytes. + * If \c salt is \c NULL, pass 0. + * \param signature Buffer containing the signature to verify. + * \param signature_size Size of the \c signature buffer in bytes. + * + * \retval PSA_SUCCESS + * The signature is valid. + * \retval PSA_ERROR_INVALID_SIGNATURE + * The calculation was perfomed successfully, but the passed + * signature is not a valid signature. + * \retval PSA_ERROR_NOT_SUPPORTED + * \retval PSA_ERROR_INVALID_ARGUMENT + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED */ psa_status_t psa_asymmetric_verify(psa_key_slot_t key, psa_algorithm_t alg, From 8c9def3e7fa05bda96fefd49076d1d6a1a6417cd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Feb 2018 10:02:12 +0100 Subject: [PATCH 12/36] PSA: Implement MAC functions Implement psa_mac_start, psa_mac_update and psa_mac_final. Implement HMAC anc CMAC. Smoke tests. --- include/psa/crypto.h | 79 ++++- library/psa_crypto.c | 301 +++++++++++++++++++- tests/suites/test_suite_psa_crypto.data | 8 + tests/suites/test_suite_psa_crypto.function | 63 ++++ 4 files changed, 437 insertions(+), 14 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 060c007ec..5fb35685d 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -144,6 +144,9 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_IS_VENDOR_DEFINED(type) \ (((type) & PSA_KEY_TYPE_VENDOR_FLAG) != 0) +#define PSA_KEY_TYPE_IS_RAW_BYTES(type) \ + (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_RAW_DATA || \ + ((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_SYMMETRIC) #define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \ (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_ASYMMETRIC) #define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \ @@ -157,6 +160,13 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_IS_ECC(type) \ (((type) & ~PSA_KEY_TYPE_ECC_CURVE_MASK) == PSA_KEY_TYPE_ECC_BASE) +#define PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) \ + ( \ + (type) == PSA_KEY_TYPE_AES ? 16 : \ + (type) == PSA_KEY_TYPE_DES ? 8 : \ + (type) == PSA_KEY_TYPE_CAMELLIA ? 16 : \ + 0) + /** \brief Encoding of a cryptographic algorithm. * * For algorithms that can be applied to multiple key types, this type @@ -223,25 +233,42 @@ typedef uint32_t psa_algorithm_t; #define PSA_ALG_SHA3_384 ((psa_algorithm_t)0x01000012) #define PSA_ALG_SHA3_512 ((psa_algorithm_t)0x01000013) +#define PSA_ALG_MAC_SUBCATEGORY_MASK ((psa_algorithm_t)0x00c00000) #define PSA_ALG_HMAC_BASE ((psa_algorithm_t)0x02800000) #define PSA_ALG_HMAC(hash_alg) \ - (PSA_ALG_HMAC_BASE | (hash_alg)) -#define PSA_ALG_CBC_MAC ((psa_algorithm_t)0x02000001) -#define PSA_ALG_CMAC ((psa_algorithm_t)0x02000002) -#define PSA_ALG_GMAC ((psa_algorithm_t)0x02000003) + (PSA_ALG_HMAC_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) +#define PSA_ALG_HMAC_HASH(hmac_alg) \ + (PSA_ALG_CATEGORY_HASH | ((hmac_alg) & PSA_ALG_HASH_MASK)) +#define PSA_ALG_IS_HMAC(alg) \ + (((alg) & (PSA_ALG_CATEGORY_MASK | PSA_ALG_MAC_SUBCATEGORY_MASK)) == \ + PSA_ALG_HMAC_BASE) +#define PSA_ALG_CIPHER_MAC_BASE ((psa_algorithm_t)0x02c00000) +#define PSA_ALG_CBC_MAC ((psa_algorithm_t)0x02c00001) +#define PSA_ALG_CMAC ((psa_algorithm_t)0x02c00002) +#define PSA_ALG_GMAC ((psa_algorithm_t)0x02c00003) +#define PSA_ALG_IS_CIPHER_MAC(alg) \ + (((alg) & (PSA_ALG_CATEGORY_MASK | PSA_ALG_MAC_SUBCATEGORY_MASK)) == \ + PSA_ALG_CIPHER_MAC_BASE) -#define PSA_ALG_BLOCK_CIPHER_BASE_MASK ((psa_algorithm_t)0x000000ff) +#define PSA_ALG_CIPHER_SUBCATEGORY_MASK ((psa_algorithm_t)0x00c00000) +#define PSA_ALG_BLOCK_CIPHER_BASE ((psa_algorithm_t)0x04000001) +#define PSA_ALG_BLOCK_CIPHER_MODE_MASK ((psa_algorithm_t)0x000000ff) #define PSA_ALG_BLOCK_CIPHER_PADDING_MASK ((psa_algorithm_t)0x007f0000) #define PSA_ALG_BLOCK_CIPHER_PAD_PKCS7 ((psa_algorithm_t)0x00010000) +#define PSA_ALG_IS_BLOCK_CIPHER(alg) \ + (((alg) & (PSA_ALG_CATEGORY_MASK | PSA_ALG_CIPHER_SUBCATEGORY_MASK)) == \ + PSA_ALG_BLOCK_CIPHER_BASE) + #define PSA_ALG_CBC_BASE ((psa_algorithm_t)0x04000001) -#define PSA_ALG_CFB_BASE ((psa_algorithm_t)0x04000003) -#define PSA_ALG_OFB_BASE ((psa_algorithm_t)0x04000004) -#define PSA_ALG_XTS_BASE ((psa_algorithm_t)0x04000005) +#define PSA_ALG_CFB_BASE ((psa_algorithm_t)0x04000002) +#define PSA_ALG_OFB_BASE ((psa_algorithm_t)0x04000003) +#define PSA_ALG_XTS_BASE ((psa_algorithm_t)0x04000004) #define PSA_ALG_STREAM_CIPHER ((psa_algorithm_t)0x04800000) #define PSA_ALG_CTR ((psa_algorithm_t)0x04800001) +#define PSA_ALG_ARC4 ((psa_algorithm_t)0x04800002) -#define PSA_ALG_CCM ((psa_algorithm_t)0x06000002) -#define PSA_ALG_GCM ((psa_algorithm_t)0x06000003) +#define PSA_ALG_CCM ((psa_algorithm_t)0x06000001) +#define PSA_ALG_GCM ((psa_algorithm_t)0x06000002) #define PSA_ALG_RSA_PKCS1V15_RAW ((psa_algorithm_t)0x10010000) #define PSA_ALG_RSA_PSS_MGF1 ((psa_algorithm_t)0x10020000) @@ -575,6 +602,38 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation); /**@}*/ +/** \defgroup MAC Message authentication codes + * @{ + */ + +typedef struct psa_mac_operation_s psa_mac_operation_t; + +#define PSA_MAC_FINAL_SIZE(key_type, key_bits, alg) \ + (PSA_ALG_IS_HMAC(alg) ? PSA_HASH_FINAL_SIZE(PSA_ALG_HMAC_HASH(alg)) : \ + PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) : \ + 0) + +psa_status_t psa_mac_start(psa_mac_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg); + +psa_status_t psa_mac_update(psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length); + +psa_status_t psa_mac_finish(psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +psa_status_t psa_mac_verify(psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length); + +psa_status_t psa_mac_abort(psa_mac_operation_t *operation); + +/**@}*/ + /** \defgroup asymmetric Asymmetric cryptography * @{ */ diff --git a/library/psa_crypto.c b/library/psa_crypto.c index ca275495f..e264990ff 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -303,7 +303,7 @@ psa_status_t psa_import_key(psa_key_slot_t key, if( slot->type != PSA_KEY_TYPE_NONE ) return( PSA_ERROR_OCCUPIED_SLOT ); - if( type == PSA_KEY_TYPE_RAW_DATA ) + if( PSA_KEY_TYPE_IS_RAW_BYTES( type ) ) { if( data_length > SIZE_MAX / 8 ) return( PSA_ERROR_NOT_SUPPORTED ); @@ -374,7 +374,7 @@ psa_status_t psa_destroy_key(psa_key_slot_t key) if( slot->type == PSA_KEY_TYPE_NONE ) return( PSA_ERROR_EMPTY_SLOT ); - if( slot->type == PSA_KEY_TYPE_RAW_DATA ) + if( PSA_KEY_TYPE_IS_RAW_BYTES( slot->type ) ) { mbedtls_free( slot->data.raw.data ); } @@ -420,7 +420,7 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, if( slot->type == PSA_KEY_TYPE_NONE ) return( PSA_ERROR_EMPTY_SLOT ); - if( slot->type == PSA_KEY_TYPE_RAW_DATA ) + if( PSA_KEY_TYPE_IS_RAW_BYTES( slot->type ) ) { if( bits != NULL ) *bits = slot->data.raw.bytes * 8; @@ -465,7 +465,7 @@ psa_status_t psa_export_key(psa_key_slot_t key, if( slot->type == PSA_KEY_TYPE_NONE ) return( PSA_ERROR_EMPTY_SLOT ); - if( slot->type == PSA_KEY_TYPE_RAW_DATA ) + if( PSA_KEY_TYPE_IS_RAW_BYTES( slot->type ) ) { if( slot->data.raw.bytes > data_size ) return( PSA_ERROR_BUFFER_TOO_SMALL ); @@ -856,6 +856,299 @@ psa_status_t psa_hash_verify(psa_hash_operation_t *operation, /****************************************************************/ +/* MAC */ +/****************************************************************/ + +static const mbedtls_cipher_info_t *mbedtls_cipher_info_of_psa( + psa_algorithm_t alg, + psa_key_type_t key_type, + size_t key_bits ) +{ + mbedtls_cipher_id_t cipher_id; + mbedtls_cipher_mode_t mode; + + if( PSA_ALG_IS_CIPHER( alg ) || PSA_ALG_IS_AEAD( alg ) ) + { + if( PSA_ALG_IS_BLOCK_CIPHER( alg ) ) + alg &= ~PSA_ALG_BLOCK_CIPHER_MODE_MASK; + switch( alg ) + { + case PSA_ALG_STREAM_CIPHER: + mode = MBEDTLS_MODE_STREAM; + break; + case PSA_ALG_CBC_BASE: + mode = MBEDTLS_MODE_CBC; + break; + case PSA_ALG_CFB_BASE: + mode = MBEDTLS_MODE_CFB; + break; + case PSA_ALG_OFB_BASE: + mode = MBEDTLS_MODE_OFB; + break; + case PSA_ALG_CTR: + mode = MBEDTLS_MODE_CTR; + break; + case PSA_ALG_CCM: + mode = MBEDTLS_MODE_CCM; + break; + case PSA_ALG_GCM: + mode = MBEDTLS_MODE_GCM; + break; + default: + return( NULL ); + } + } + else if( alg == PSA_ALG_CMAC ) + mode = MBEDTLS_MODE_ECB; + else if( alg == PSA_ALG_GMAC ) + mode = MBEDTLS_MODE_GCM; + else + return( NULL ); + + switch( key_type ) + { + case PSA_KEY_TYPE_AES: + cipher_id = MBEDTLS_CIPHER_ID_AES; + break; + case PSA_KEY_TYPE_DES: + if( key_bits == 64 ) + cipher_id = MBEDTLS_CIPHER_ID_DES; + else + cipher_id = MBEDTLS_CIPHER_ID_3DES; + break; + case PSA_KEY_TYPE_CAMELLIA: + cipher_id = MBEDTLS_CIPHER_ID_CAMELLIA; + break; + case PSA_KEY_TYPE_ARC4: + cipher_id = MBEDTLS_CIPHER_ID_ARC4; + break; + default: + return( NULL ); + } + + return( mbedtls_cipher_info_from_values( cipher_id, key_bits, mode ) ); +} + +psa_status_t psa_mac_abort( psa_mac_operation_t *operation ) +{ + switch( operation->alg ) + { +#if defined(MBEDTLS_CMAC_C) + case PSA_ALG_CMAC: + mbedtls_cipher_free( &operation->ctx.cmac ); + break; +#endif /* MBEDTLS_CMAC_C */ + default: +#if defined(MBEDTLS_MD_C) + if( PSA_ALG_IS_HMAC( operation->alg ) ) + mbedtls_md_free( &operation->ctx.hmac ); + else +#endif /* MBEDTLS_MD_C */ + return( PSA_ERROR_NOT_SUPPORTED ); + } + operation->alg = 0; + operation->key_set = 0; + operation->iv_set = 0; + operation->iv_required = 0; + operation->has_input = 0; + return( PSA_SUCCESS ); +} + +psa_status_t psa_mac_start( psa_mac_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg ) +{ + int ret = MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE; + psa_status_t status; + key_slot_t *slot; + psa_key_type_t key_type; + size_t key_bits; + const mbedtls_cipher_info_t *cipher_info = NULL; + + operation->alg = 0; + operation->key_set = 0; + operation->iv_set = 0; + operation->iv_required = 1; + operation->has_input = 0; + + status = psa_get_key_information( key, &key_type, &key_bits ); + if( status != PSA_SUCCESS ) + return( status ); + slot = &global_data.key_slots[key]; + + if( ! PSA_ALG_IS_HMAC( alg ) ) + { + cipher_info = mbedtls_cipher_info_of_psa( alg, key_type, key_bits ); + if( cipher_info == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + operation->mac_size = cipher_info->block_size; + } + switch( alg ) + { +#if defined(MBEDTLS_CMAC_C) + case PSA_ALG_CMAC: + operation->iv_required = 0; + mbedtls_cipher_init( &operation->ctx.cmac ); + ret = mbedtls_cipher_setup( &operation->ctx.cmac, cipher_info ); + if( ret != 0 ) + break; + ret = mbedtls_cipher_cmac_starts( &operation->ctx.cmac, + slot->data.raw.data, + key_bits ); + break; +#endif /* MBEDTLS_CMAC_C */ + default: +#if defined(MBEDTLS_MD_C) + if( PSA_ALG_IS_HMAC( alg ) ) + { + const mbedtls_md_info_t *md_info = + mbedtls_md_info_of_psa( PSA_ALG_HMAC_HASH( alg ) ); + if( md_info == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + if( key_type != PSA_KEY_TYPE_HMAC ) + return( PSA_ERROR_INVALID_ARGUMENT ); + operation->iv_required = 0; + operation->mac_size = mbedtls_md_get_size( md_info ); + mbedtls_md_init( &operation->ctx.hmac ); + ret = mbedtls_md_setup( &operation->ctx.hmac, md_info, 1 ); + if( ret != 0 ) + break; + ret = mbedtls_md_hmac_starts( &operation->ctx.hmac, + slot->data.raw.data, + slot->data.raw.bytes ); + break; + } + else +#endif /* MBEDTLS_MD_C */ + return( PSA_ERROR_NOT_SUPPORTED ); + } + + /* If we reach this point, then the algorithm-specific part of the + * context has at least been initialized, and may contain data that + * needs to be wiped on error. */ + operation->alg = alg; + if( ret != 0 ) + { + psa_mac_abort( operation ); + return( mbedtls_to_psa_error( ret ) ); + } + operation->key_set = 1; + return( 0 ); +} + +psa_status_t psa_mac_update( psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length ) +{ + int ret; + if( ! operation->key_set ) + return( PSA_ERROR_BAD_STATE ); + if( operation->iv_required && ! operation->iv_set ) + return( PSA_ERROR_BAD_STATE ); + operation->has_input = 1; + + switch( operation->alg ) + { +#if defined(MBEDTLS_CMAC_C) + case PSA_ALG_CMAC: + ret = mbedtls_cipher_cmac_update( &operation->ctx.cmac, + input, input_length ); + break; +#endif /* MBEDTLS_CMAC_C */ + default: +#if defined(MBEDTLS_MD_C) + if( PSA_ALG_IS_HMAC( operation->alg ) ) + { + ret = mbedtls_md_hmac_update( &operation->ctx.hmac, + input, input_length ); + } + else +#endif /* MBEDTLS_MD_C */ + { + ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA; + } + break; + } + if( ret != 0 ) + psa_mac_abort( operation ); + return( mbedtls_to_psa_error( ret ) ); +} + +psa_status_t psa_mac_finish( psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length ) +{ + int ret; + if( ! operation->key_set ) + return( PSA_ERROR_BAD_STATE ); + if( operation->iv_required && ! operation->iv_set ) + return( PSA_ERROR_BAD_STATE ); + + /* Fill the output buffer with something that isn't a valid mac + * (barring an attack on the mac and deliberately-crafted input), + * in case the caller doesn't check the return status properly. */ + *mac_length = operation->mac_size; + memset( mac, '!', mac_size ); + + if( mac_size < operation->mac_size ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + + switch( operation->alg ) + { +#if defined(MBEDTLS_CMAC_C) + case PSA_ALG_CMAC: + ret = mbedtls_cipher_cmac_finish( &operation->ctx.cmac, mac ); + break; +#endif /* MBEDTLS_CMAC_C */ + default: +#if defined(MBEDTLS_MD_C) + if( PSA_ALG_IS_HMAC( operation->alg ) ) + { + ret = mbedtls_md_hmac_finish( &operation->ctx.hmac, mac ); + } + else +#endif /* MBEDTLS_MD_C */ + { + ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA; + } + break; + } + + if( ret == 0 ) + { + return( psa_mac_abort( operation ) ); + } + else + { + psa_mac_abort( operation ); + return( mbedtls_to_psa_error( ret ) ); + } +} + +#define MBEDTLS_PSA_MAC_MAX_SIZE \ + ( MBEDTLS_MD_MAX_SIZE > MBEDTLS_MAX_BLOCK_LENGTH ? \ + MBEDTLS_MD_MAX_SIZE : \ + MBEDTLS_MAX_BLOCK_LENGTH ) +psa_status_t psa_mac_verify( psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length ) +{ + uint8_t actual_mac[MBEDTLS_PSA_MAC_MAX_SIZE]; + size_t actual_mac_length; + psa_status_t status = psa_mac_finish( operation, + actual_mac, sizeof( actual_mac ), + &actual_mac_length ); + if( status != PSA_SUCCESS ) + return( status ); + if( actual_mac_length != mac_length ) + return( PSA_ERROR_INVALID_SIGNATURE ); + if( safer_memcmp( mac, actual_mac, actual_mac_length ) != 0 ) + return( PSA_ERROR_INVALID_SIGNATURE ); + return( PSA_SUCCESS ); +} + + /****************************************************************/ diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index f53b1a436..4f4bef14c 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -45,6 +45,14 @@ PSA hash verify: SHA-256 depends_on:MBEDTLS_SHA256_C hash_verify:PSA_ALG_SHA_256:"bd":"68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b" +PSA MAC verify: HMAC-SHA-256 +depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C +mac_verify:PSA_KEY_TYPE_HMAC:"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f":PSA_ALG_HMAC(PSA_ALG_SHA_256):"":"53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e":"8bb9a1db9806f20df7f77b82138c7914d174d59e13dc4d0169c9057b133e1d62" + +PSA MAC verify: CMAC-AES-128 +depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C +mac_verify:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_CMAC:"":"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747de9ae63030ca32611497c827" + PSA signature size: RSA keypair, 1024 bits, PKCS#1 v1.5 raw signature_size:PSA_KEY_TYPE_RSA_KEYPAIR:1024:PSA_ALG_RSA_PKCS1V15_RAW:128 diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 21802d147..d5305740f 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1,5 +1,7 @@ /* BEGIN_HEADER */ #include "psa/crypto.h" + +#include "mbedtls/md.h" /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -200,6 +202,67 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void mac_verify( int key_type_arg, char *key_hex, + int alg_arg, char *iv_hex, + char *input_hex, char *mac_hex ) +{ + int key_slot = 1; + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + unsigned char *key = NULL; + size_t key_size; + unsigned char *iv = NULL; + size_t iv_size; + unsigned char *input = NULL; + size_t input_size; + unsigned char *expected_mac = NULL; + size_t expected_mac_size; + psa_mac_operation_t operation; + + key_size = strlen( key_hex ) / 2; + key = mbedtls_calloc( 1, key_size ); + TEST_ASSERT( key != NULL ); + key_size = unhexify( key, key_hex ); + iv_size = strlen( iv_hex ) / 2; + if( iv_size != 0 ) + { + iv = mbedtls_calloc( 1, iv_size ); + TEST_ASSERT( iv != NULL ); + iv_size = unhexify( iv, iv_hex ); + } + input_size = strlen( input_hex ) / 2; + input = mbedtls_calloc( 1, input_size ); + TEST_ASSERT( input != NULL ); + input_size = unhexify( input, input_hex ); + expected_mac_size = strlen( mac_hex ) / 2; + expected_mac = mbedtls_calloc( 1, expected_mac_size ); + TEST_ASSERT( expected_mac != NULL ); + expected_mac_size = unhexify( expected_mac, mac_hex ); + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_import_key( key_slot, key_type, + key, key_size ) == PSA_SUCCESS ); + // TODO: support IV + TEST_ASSERT( psa_mac_start( &operation, key_slot, alg ) == PSA_SUCCESS ); + TEST_ASSERT( psa_destroy_key( key_slot ) == PSA_SUCCESS ); + TEST_ASSERT( psa_mac_update( &operation, + input, input_size ) == PSA_SUCCESS ); + TEST_ASSERT( psa_mac_verify( &operation, + expected_mac, + expected_mac_size ) == PSA_SUCCESS ); + +exit: + mbedtls_free( key ); + mbedtls_free( iv ); + mbedtls_free( input ); + mbedtls_free( expected_mac ); + psa_destroy_key( key_slot ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void signature_size( int type_arg, int bits, int alg_arg, int expected_size_arg ) { From 7e4acc5ef859f7b677d989d3d75d21fa3890b0d9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 16 Feb 2018 21:24:11 +0100 Subject: [PATCH 13/36] Document some MAC functions: psa_mac_start Adapt the documentation of hash functions. State that the key object does not need to remain valid throughout the operation. --- include/psa/crypto.h | 58 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 5fb35685d..8cf7e3a3f 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -447,7 +447,7 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; * -# Allocate an operation object which will be passed to all the functions * listed here. * -# Call psa_hash_start() to specify the algorithm. - * -# Call psa_hash_update() zero, one or more time, passing a fragment + * -# Call psa_hash_update() zero, one or more times, passing a fragment * of the message each time. The hash that is calculated is the hash * of the concatenation of these messages in order. * -# To calculate the hash, call psa_hash_finish(). @@ -606,13 +606,69 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation); * @{ */ +/** The type of the state data structure for multipart MAC operations. + * + * This is an implementation-define \c struct. Applications should not + * make any assumptions about the content of this structure except + * as directed by the documentation of a specific implementation. */ typedef struct psa_mac_operation_s psa_mac_operation_t; +/** The size of the output of psa_mac_finish(), in bytes. + * + * This is also the MAC size that psa_mac_verify() expects. + * + * \param alg A MAC algorithm (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_MAC(alg) is true). + * + * \return The MAC size for the specified algorithm. + * If the MAC algorithm is not recognized, return 0. + * An implementation may return either 0 or the correct size + * for a MAC algorithm that it recognizes, but does not support. + */ #define PSA_MAC_FINAL_SIZE(key_type, key_bits, alg) \ (PSA_ALG_IS_HMAC(alg) ? PSA_HASH_FINAL_SIZE(PSA_ALG_HMAC_HASH(alg)) : \ PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) : \ 0) +/** Start a multipart MAC operation. + * + * The sequence of operations to calculate a MAC (message authentication code) + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Call psa_mac_start() to specify the algorithm and key. + * The key remains associated with the operation even if the content + * of the key slot changes. + * -# Call psa_mac_update() zero, one or more times, passing a fragment + * of the message each time. The MAC that is calculated is the MAC + * of the concatenation of these messages in order. + * -# To calculate the MAC, call psa_mac_finish(). + * To compare the MAC with an expected value, call psa_mac_verify(). + * + * The application may call psa_mac_abort() at any time after the operation + * has been initialized with psa_mac_start(). + * + * After a successful call to psa_mac_start(), the application must + * eventually destroy the operation through one of the following means: + * - A failed call to psa_mac_update(). + * - A call to psa_mac_final(), psa_mac_verify() or psa_mac_abort(). + * + * \param operation + * \param alg The MAC algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_MAC(alg) is true). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_INVALID_ARGUMENT + * \c key is not compatible with \c alg. + * \retval PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not a MAC algorithm. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ psa_status_t psa_mac_start(psa_mac_operation_t *operation, psa_key_slot_t key, psa_algorithm_t alg); From 428dc5aef19fb191e528eece58089273b3da7897 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Mar 2018 21:27:18 +0100 Subject: [PATCH 14/36] Prototypes for symmetric cipher functions --- include/psa/crypto.h | 131 +++++++++++++++++++++++++++++++++++- include/psa/crypto_struct.h | 12 ++++ 2 files changed, 141 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 8cf7e3a3f..0998a498d 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -251,9 +251,10 @@ typedef uint32_t psa_algorithm_t; PSA_ALG_CIPHER_MAC_BASE) #define PSA_ALG_CIPHER_SUBCATEGORY_MASK ((psa_algorithm_t)0x00c00000) -#define PSA_ALG_BLOCK_CIPHER_BASE ((psa_algorithm_t)0x04000001) +#define PSA_ALG_BLOCK_CIPHER_BASE ((psa_algorithm_t)0x04000000) #define PSA_ALG_BLOCK_CIPHER_MODE_MASK ((psa_algorithm_t)0x000000ff) -#define PSA_ALG_BLOCK_CIPHER_PADDING_MASK ((psa_algorithm_t)0x007f0000) +#define PSA_ALG_BLOCK_CIPHER_PADDING_MASK ((psa_algorithm_t)0x003f0000) +#define PSA_ALG_BLOCK_CIPHER_PAD_NONE ((psa_algorithm_t)0x00000000) #define PSA_ALG_BLOCK_CIPHER_PAD_PKCS7 ((psa_algorithm_t)0x00010000) #define PSA_ALG_IS_BLOCK_CIPHER(alg) \ (((alg) & (PSA_ALG_CATEGORY_MASK | PSA_ALG_CIPHER_SUBCATEGORY_MASK)) == \ @@ -690,6 +691,132 @@ psa_status_t psa_mac_abort(psa_mac_operation_t *operation); /**@}*/ +/** \defgroup cipher Symmetric ciphers + * @{ + */ + +/** The type of the state data structure for multipart cipher operations. + * + * This is an implementation-defined \c struct. Applications should not + * make any assumptions about the content of this structure except + * as directed by the documentation of a specific implementation. */ +typedef struct psa_cipher_operation_s psa_cipher_operation_t; + +/** Set the key for a multipart symmetric encryption operation. + * + * The sequence of operations to encrypt a message with a symmetric cipher + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Call psa_encrypt_setup() to specify the algorithm and key. + * The key remains associated with the operation even if the content + * of the key slot changes. + * -# Call either psa_encrypt_generate_iv() or psa_encrypt_set_iv() to + * generate or set the IV (initialization vector). You should use + * psa_encrypt_generate_iv() unless the protocol you are implementing + * requires a specific IV value. + * -# Call psa_cipher_update() zero, one or more times, passing a fragment + * of the message each time. + * -# Call psa_cipher_finish(). + * + * The application may call psa_cipher_abort() at any time after the operation + * has been initialized with psa_encrypt_setup(). + * + * After a successful call to psa_encrypt_setup(), the application must + * eventually destroy the operation through one of the following means: + * - A failed call to psa_encrypt_generate_iv(), psa_encrypt_set_iv() + * or psa_cipher_update(). + * - A call to psa_cipher_final() or psa_cipher_abort(). + * + * \param operation + * \param alg The cipher algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_CIPHER(alg) is true). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_NOT_PERMITTED + * \retval PSA_ERROR_INVALID_ARGUMENT + * \c key is not compatible with \c alg. + * \retval PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not a cipher algorithm. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_encrypt_setup(psa_cipher_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg); + +/** Set the key for a multipart symmetric decryption operation. + * + * The sequence of operations to decrypt a message with a symmetric cipher + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Call psa_decrypt_setup() to specify the algorithm and key. + * The key remains associated with the operation even if the content + * of the key slot changes. + * -# Call psa_cipher_update() with the IV (initialization vector) for the + * decryption. If the IV is prepended to the ciphertext, you can call + * psa_cipher_update() on a buffer containing the IV followed by the + * beginning of the message. + * -# Call psa_cipher_update() zero, one or more times, passing a fragment + * of the message each time. + * -# Call psa_cipher_finish(). + * + * The application may call psa_cipher_abort() at any time after the operation + * has been initialized with psa_encrypt_setup(). + * + * After a successful call to psa_decrypt_setup(), the application must + * eventually destroy the operation through one of the following means: + * - A failed call to psa_cipher_update(). + * - A call to psa_cipher_final() or psa_cipher_abort(). + * + * \param operation + * \param alg The cipher algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_CIPHER(alg) is true). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_NOT_PERMITTED + * \retval PSA_ERROR_INVALID_ARGUMENT + * \c key is not compatible with \c alg. + * \retval PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not a cipher algorithm. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_decrypt_setup(psa_cipher_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg); + +psa_status_t psa_encrypt_generate_iv(psa_cipher_operation_t *operation, + unsigned char *iv, + size_t iv_size, + size_t *iv_length); + +psa_status_t psa_encrypt_set_iv(psa_cipher_operation_t *operation, + const unsigned char *iv, + size_t iv_length); + +psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length); + +psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation); + +/**@}*/ + /** \defgroup asymmetric Asymmetric cryptography * @{ */ diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 6bd4ed23d..ffa835e15 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -93,4 +93,16 @@ struct psa_mac_operation_s } ctx; }; +struct psa_cipher_operation_s +{ + psa_algorithm_t alg; + int key_set : 1; + int iv_set : 1; + uint8_t iv_size; + uint8_t block_size; + union + { + } ctx; +}; + #endif /* PSA_CRYPTO_STRUCT_H */ From 3b555710e2d14876a0ef708b6ed1b24c51f00582 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Mar 2018 21:27:57 +0100 Subject: [PATCH 15/36] Prototypes for AEAD functions This is still tentative. --- include/psa/crypto.h | 138 ++++++++++++++++++++++++++++++++++++ include/psa/crypto_struct.h | 13 ++++ 2 files changed, 151 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 0998a498d..c833d7220 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -817,6 +817,144 @@ psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation); /**@}*/ +/** \defgroup aead Authenticated encryption with associated data (AEAD) + * @{ + */ + +/** The type of the state data structure for multipart AEAD operations. + * + * This is an implementation-defined \c struct. Applications should not + * make any assumptions about the content of this structure except + * as directed by the documentation of a specific implementation. */ +typedef struct psa_aead_operation_s psa_aead_operation_t; + +/** Set the key for a multipart authenticated encryption operation. + * + * The sequence of operations to authenticate-and-encrypt a message + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Call psa_aead_encrypt_setup() to specify the algorithm and key. + * The key remains associated with the operation even if the content + * of the key slot changes. + * -# Call either psa_aead_generate_iv() or psa_aead_set_iv() to + * generate or set the IV (initialization vector). You should use + * psa_encrypt_generate_iv() unless the protocol you are implementing + * requires a specific IV value. + * -# Call psa_aead_update_ad() to pass the associated data that is + * to be authenticated but not encrypted. You may omit this step if + * there is no associated data. + * -# Call psa_aead_update() zero, one or more times, passing a fragment + * of the data to encrypt each time. + * -# Call psa_aead_finish(). + * + * The application may call psa_aead_abort() at any time after the operation + * has been initialized with psa_aead_encrypt_setup(). + * + * After a successful call to psa_aead_setup(), the application must + * eventually destroy the operation through one of the following means: + * - A failed call to psa_aead_generate_iv(), psa_aead_set_iv(), + * psa_aead_update_ad() or psa_aead_update(). + * - A call to psa_aead_final() or psa_aead_abort(). + * + * \param operation + * \param alg The AEAD algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_AEAD(alg) is true). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_NOT_PERMITTED + * \retval PSA_ERROR_INVALID_ARGUMENT + * \c key is not compatible with \c alg. + * \retval PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not an AEAD algorithm. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg); + +/** Set the key for a multipart authenticated decryption operation. + * + * The sequence of operations to authenticated and decrypt a message + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Call psa_aead_decrypt_setup() to specify the algorithm and key. + * The key remains associated with the operation even if the content + * of the key slot changes. + * -# Call psa_aead_set_iv() to pass the initialization vector (IV) + * for the authenticated decryption. + * -# Call psa_aead_update_ad() to pass the associated data that is + * to be authenticated but not encrypted. You may omit this step if + * there is no associated data. + * -# Call psa_aead_update() zero, one or more times, passing a fragment + * of the data to decrypt each time. + * -# Call psa_aead_finish(). + * + * The application may call psa_aead_abort() at any time after the operation + * has been initialized with psa_aead_decrypt_setup(). + * + * After a successful call to psa_decrypt_setup(), the application must + * eventually destroy the operation through one of the following means: + * - A failed call to psa_aead_update(). + * - A call to psa_cipher_final() or psa_cipher_abort(). + * + * \param operation + * \param alg The cipher algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_CIPHER(alg) is true). + * + * \retval PSA_SUCCESS + * Success. + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_NOT_PERMITTED + * \retval PSA_ERROR_INVALID_ARGUMENT + * \c key is not compatible with \c alg. + * \retval PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not a cipher algorithm. + * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation, + psa_key_slot_t key, + psa_algorithm_t alg); + +psa_status_t psa_aead_generate_iv(psa_aead_operation_t *operation, + unsigned char *iv, + size_t iv_size, + size_t *iv_length); + +psa_status_t psa_aead_set_iv(psa_aead_operation_t *operation, + const unsigned char *iv, + size_t iv_length); + +psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length); + +psa_status_t psa_aead_update(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length); + +psa_status_t psa_aead_finish(psa_aead_operation_t *operation, + uint8_t *tag, + size_t tag_size, + size_t *tag_length); + +psa_status_t psa_aead_verify(psa_aead_operation_t *operation, + uint8_t *tag, + size_t tag_length); + +psa_status_t psa_aead_abort(psa_aead_operation_t *operation); + +/**@}*/ + /** \defgroup asymmetric Asymmetric cryptography * @{ */ diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index ffa835e15..9e70512d7 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -105,4 +105,17 @@ struct psa_cipher_operation_s } ctx; }; +struct psa_aead_operation_s +{ + psa_algorithm_t alg; + int key_set : 1; + int iv_set : 1; + int ad_set : 1; + uint8_t iv_size; + uint8_t block_size; + union + { + } ctx; +}; + #endif /* PSA_CRYPTO_STRUCT_H */ From 92b3073e36247d34edbf56674b6b4a28516bbb6a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Mar 2018 21:29:30 +0100 Subject: [PATCH 16/36] Minor documentation fixes --- include/psa/crypto.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index c833d7220..94a5e0a9b 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -360,7 +360,7 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, * If a key is created with psa_import_key() and then exported with * this function, it is not guaranteed that the resulting data is * identical: the implementation may choose a different representation - * of the same key. + * of the same key if the format permits it. * * For standard key types, the output format is as follows: * @@ -370,7 +370,7 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, * correct. * - For Triple-DES, the format is the concatenation of the * two or three DES keys. - * - For RSA key pairs keys (#PSA_KEY_TYPE_RSA_KEYPAIR), the format + * - For RSA key pairs (#PSA_KEY_TYPE_RSA_KEYPAIR), the format * is the non-encrypted DER representation defined by PKCS\#8 (RFC 5208) * as PrivateKeyInfo. * - For RSA public keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY), the format @@ -385,6 +385,7 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, * * \retval PSA_SUCCESS * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_NOT_PERMITTED * \retval PSA_ERROR_COMMUNICATION_FAILURE * \retval PSA_ERROR_HARDWARE_FAILURE * \retval PSA_ERROR_TAMPERING_DETECTED @@ -403,7 +404,7 @@ psa_status_t psa_export_key(psa_key_slot_t key, /** The type of the state data structure for multipart hash operations. * - * This is an implementation-define \c struct. Applications should not + * This is an implementation-defined \c struct. Applications should not * make any assumptions about the content of this structure except * as directed by the documentation of a specific implementation. */ typedef struct psa_hash_operation_s psa_hash_operation_t; @@ -609,7 +610,7 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation); /** The type of the state data structure for multipart MAC operations. * - * This is an implementation-define \c struct. Applications should not + * This is an implementation-defined \c struct. Applications should not * make any assumptions about the content of this structure except * as directed by the documentation of a specific implementation. */ typedef struct psa_mac_operation_s psa_mac_operation_t; @@ -661,6 +662,7 @@ typedef struct psa_mac_operation_s psa_mac_operation_t; * \retval PSA_SUCCESS * Success. * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_NOT_PERMITTED * \retval PSA_ERROR_INVALID_ARGUMENT * \c key is not compatible with \c alg. * \retval PSA_ERROR_NOT_SUPPORTED From 7698bcf338e5d3f6ac1ef20264ebae3be837da77 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Mar 2018 21:30:44 +0100 Subject: [PATCH 17/36] Basic interface for key policies Get/set the policy of a key slot. Opaque structure for key policies and field access functions. --- include/psa/crypto.h | 76 +++++++++++++++++++++++++++++++++++++ include/psa/crypto_struct.h | 6 +++ 2 files changed, 82 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 94a5e0a9b..493f5efba 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -395,6 +395,82 @@ psa_status_t psa_export_key(psa_key_slot_t key, size_t data_size, size_t *data_length); +/** + * \brief Export a public key or the public part of a key pair in binary format. + * + * The output of this function can be passed to psa_import_key() to + * create an object that is equivalent to the public key. + * + * For standard key types, the output format is as follows: + * + * - For RSA keys (#PSA_KEY_TYPE_RSA_KEYPAIR or #PSA_KEY_TYPE_RSA_PUBLIC_KEY), + * the format is the DER representation defined by X.509. + * + * \param key Slot whose content is to be exported. This must + * be an occupied key slot. + * \param data Buffer where the key data is to be written. + * \param data_size Size of the \c data buffer in bytes. + * \param data_length On success, the number of bytes + * that make up the key data. + * + * \retval PSA_SUCCESS + * \retval PSA_ERROR_EMPTY_SLOT + * \retval PSA_ERROR_INVALID_ARGUMENT + * \retval PSA_ERROR_COMMUNICATION_FAILURE + * \retval PSA_ERROR_HARDWARE_FAILURE + * \retval PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_export_public_key(psa_key_slot_t key, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/**@}*/ + +/** \defgroup policy Key policies + * @{ + */ + +/** \brief Encoding of permitted usage on a key. */ +typedef uint32_t psa_key_usage_t; + +#define PSA_KEY_USAGE_EXPORT ((psa_key_usage_t)0x00000001) + +#define PSA_KEY_USAGE_ENCRYPT ((psa_key_usage_t)0x00000100) +#define PSA_KEY_USAGE_DECRYPT ((psa_key_usage_t)0x00000200) +#define PSA_KEY_USAGE_SIGN ((psa_key_usage_t)0x00000400) +#define PSA_KEY_USAGE_VERIFY ((psa_key_usage_t)0x00000800) + +/** The type of the key policy data structure. + * + * This is an implementation-defined \c struct. Applications should not + * make any assumptions about the content of this structure except + * as directed by the documentation of a specific implementation. */ +typedef struct psa_key_policy_s psa_key_policy_t; + +/** \brief Initialize a key policy structure to a default that forbids all + * usage of the key. */ +void psa_key_policy_init(psa_key_policy_t *policy); + +void psa_key_policy_set_usage(psa_key_policy_t *policy, + psa_key_usage_t usage, + psa_algorithm_t alg); + +psa_key_usage_t psa_key_policy_get_usage(psa_key_policy_t *policy); + +psa_algorithm_t psa_key_policy_get_algorithm(psa_key_policy_t *policy); + +/** \brief Set the usage policy on a key slot. + * + * This function must be called on an empty key slot, before importing, + * generating or creating a key in the slot. Changing the policy of an + * existing key is not permitted. + */ +psa_status_t psa_set_key_policy(psa_key_slot_t key, + const psa_key_policy_t *policy); + +psa_status_t psa_get_key_policy(psa_key_slot_t key, + psa_key_policy_t *policy); /**@}*/ diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 9e70512d7..c0a673860 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -118,4 +118,10 @@ struct psa_aead_operation_s } ctx; }; +struct psa_key_policy_s +{ + psa_key_usage_t usage; + psa_algorithm_t alg; +}; + #endif /* PSA_CRYPTO_STRUCT_H */ From 609b6a5b67b23ada65442b4a70b114d29105ff49 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 3 Mar 2018 21:31:50 +0100 Subject: [PATCH 18/36] Get the lifetime of a key slot --- include/psa/crypto.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 493f5efba..97fe4c3c2 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -474,6 +474,34 @@ psa_status_t psa_get_key_policy(psa_key_slot_t key, /**@}*/ +/** \defgroup persistence Key lifetime + * @{ + */ + +/** Encoding of key lifetimes. + */ +typedef uint32_t psa_key_lifetime_t; + +/** A volatile key slot retains its content as long as the application is + * running. It is guaranteed to be erased on a power reset. + */ +#define PSA_KEY_LIFETIME_VOLATILE ((psa_key_lifetime_t)0x00000000) + +/** A persistent key slot retains its content as long as it is not explicitly + * destroyed. + */ +#define PSA_KEY_LIFETIME_PERSISTENT ((psa_key_lifetime_t)0x00000001) + +/** A write-once key slot may not be modified once a key has been set. + * It will retain its content as long as the device remains operational. + */ +#define PSA_KEY_LIFETIME_WRITE_ONCE ((psa_key_lifetime_t)0x7fffffff) + +psa_status_t psa_get_key_lifetime(psa_key_slot_t key, + psa_key_lifetime_t *lifetime); + +/**@}*/ + /** \defgroup hash Message digests * @{ */ From e4ebc12fcd1033e78cb2d9e8e0988018e130a886 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 14:16:44 +0100 Subject: [PATCH 19/36] psa_crypto_init: set the global initialized flag --- library/psa_crypto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index e264990ff..ea25c49a4 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -1288,6 +1288,8 @@ psa_status_t psa_crypto_init( void ) if( ret != 0 ) goto exit; + global_data.initialized = 1; + exit: if( ret != 0 ) mbedtls_psa_crypto_free( ); From 2905a7adccfaa18a562ad150d81763c209b0084d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 16:39:31 +0100 Subject: [PATCH 20/36] Fix namespace violation --- include/psa/crypto.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 97fe4c3c2..7eb45fbe8 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -107,8 +107,8 @@ typedef enum { */ psa_status_t psa_crypto_init(void); -#define BITS_TO_BYTES(bits) (((bits) + 7) / 8) -#define BYTES_TO_BITS(bytes) ((bytes) * 8) +#define PSA_BITS_TO_BYTES(bits) (((bits) + 7) / 8) +#define PSA_BYTES_TO_BITS(bytes) ((bytes) * 8) /**@}*/ @@ -1123,7 +1123,7 @@ psa_status_t psa_aead_abort(psa_aead_operation_t *operation); * */ #define PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \ - (PSA_KEY_TYPE_IS_RSA(key_type) ? ((void)alg, BITS_TO_BYTES(key_bits)) : \ + (PSA_KEY_TYPE_IS_RSA(key_type) ? ((void)alg, PSA_BITS_TO_BYTES(key_bits)) : \ PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(key_bits) : \ 0) From f5b9fa13e0f8d6de66c08d6fcfaaf1250059902f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 16:40:18 +0100 Subject: [PATCH 21/36] Documentation clarifications Clarify or add the documentation of some functions and constants. Add a note about what the __DOXYGEN_ONLY__ section is for. --- include/psa/crypto.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 7eb45fbe8..48586a2f1 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -11,6 +11,11 @@ #include #ifdef __DOXYGEN_ONLY__ +/* This __DOXYGEN_ONLY__ block contains mock definitions for things that + * must be defined in the crypto_platform.h header. These mock definitions + * are present in this file as a convenience to generate pretty-printed + * documentation that includes those definitions. */ + /** \defgroup platform Implementation-specific definitions * @{ */ @@ -30,7 +35,7 @@ typedef _unsigned_integral_type_ psa_key_slot_t; /**@}*/ -#endif +#endif /* __DOXYGEN_ONLY__ */ #ifdef __cplusplus extern "C" { @@ -120,7 +125,19 @@ psa_status_t psa_crypto_init(void); */ typedef uint32_t psa_key_type_t; +/** An invalid key type value. + * + * Zero is not the encoding of any key type. + */ #define PSA_KEY_TYPE_NONE ((psa_key_type_t)0x00000000) + +/** Vendor-defined flag + * + * Key types defined by this standard will never have the + * #PSA_KEY_TYPE_VENDOR_FLAG bit set. Vendors who define additional key types + * must use an encoding with the #PSA_KEY_TYPE_VENDOR_FLAG bit set and should + * respect the bitwise structure used by standard encodings whenever practical. + */ #define PSA_KEY_TYPE_VENDOR_FLAG ((psa_key_type_t)0x80000000) #define PSA_KEY_TYPE_CATEGORY_MASK ((psa_key_type_t)0x7e000000) @@ -142,6 +159,7 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_ECC_BASE ((psa_key_type_t)0x06030000) #define PSA_KEY_TYPE_ECC_CURVE_MASK ((psa_key_type_t)0x0000ffff) +/** Whether a key type is vendor-defined. */ #define PSA_KEY_TYPE_IS_VENDOR_DEFINED(type) \ (((type) & PSA_KEY_TYPE_VENDOR_FLAG) != 0) #define PSA_KEY_TYPE_IS_RAW_BYTES(type) \ @@ -290,7 +308,8 @@ typedef uint32_t psa_algorithm_t; /** * \brief Import a key in binary format. * - * This function supports any output from psa_export_key(). + * This function supports any output from psa_export_key(). Refer to the + * documentation of psa_export_key() for the format for each key type. * * \param key Slot where the key will be stored. This must be a * valid slot for a key of the chosen type. It must From 03182e99b63baee25ca221715787409ad557b8b7 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 16:40:52 +0100 Subject: [PATCH 22/36] Fix parameter name in PSA_BLOCK_CIPHER_BLOCK_SIZE --- include/psa/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 48586a2f1..cc9881bad 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -178,7 +178,7 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_IS_ECC(type) \ (((type) & ~PSA_KEY_TYPE_ECC_CURVE_MASK) == PSA_KEY_TYPE_ECC_BASE) -#define PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) \ +#define PSA_BLOCK_CIPHER_BLOCK_SIZE(type) \ ( \ (type) == PSA_KEY_TYPE_AES ? 16 : \ (type) == PSA_KEY_TYPE_DES ? 8 : \ From 6d9121381a8e170afab9a80aeafb11ff28e2a6a1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 16:41:37 +0100 Subject: [PATCH 23/36] Add some comments to document some non-obvious coding choices --- library/psa_crypto.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index ea25c49a4..cc631d950 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -305,6 +305,7 @@ psa_status_t psa_import_key(psa_key_slot_t key, if( PSA_KEY_TYPE_IS_RAW_BYTES( type ) ) { + /* Ensure that a bytes-to-bit conversion won't overflow. */ if( data_length > SIZE_MAX / 8 ) return( PSA_ERROR_NOT_SUPPORTED ); slot->data.raw.data = mbedtls_calloc( 1, data_length ); @@ -396,7 +397,7 @@ psa_status_t psa_destroy_key(psa_key_slot_t key) #endif /* defined(MBEDTLS_ECP_C) */ { /* Shouldn't happen: the key type is not any type that we - * put it. */ + * put in. */ return( PSA_ERROR_TAMPERING_DETECTED ); } @@ -445,7 +446,7 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, #endif /* defined(MBEDTLS_ECP_C) */ { /* Shouldn't happen: the key type is not any type that we - * put it. */ + * put in. */ return( PSA_ERROR_TAMPERING_DETECTED ); } @@ -503,8 +504,11 @@ psa_status_t psa_export_key(psa_key_slot_t key, return( PSA_SUCCESS ); } else -#endif /* definedMBEDTLS_PK_WRITE_C) */ +#endif /* defined(MBEDTLS_PK_WRITE_C) */ { + /* This shouldn't happen in the reference implementation, but + it is valid for a special-purpose implementation to omit + support for exporting certain key types. */ return( PSA_ERROR_NOT_SUPPORTED ); } } From 3c6e970752c41ec0843c8187b7b03fd02be887cf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 16:42:44 +0100 Subject: [PATCH 24/36] Fix memory leak in psa_destroy_key --- library/psa_crypto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index cc631d950..c4e6be168 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -385,6 +385,7 @@ psa_status_t psa_destroy_key(psa_key_slot_t key) slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ) { mbedtls_rsa_free( slot->data.rsa ); + mbedtls_free( slot->data.rsa ); } else #endif /* defined(MBEDTLS_RSA_C) */ @@ -392,6 +393,7 @@ psa_status_t psa_destroy_key(psa_key_slot_t key) if( PSA_KEY_TYPE_IS_ECC( slot->type ) ) { mbedtls_ecp_keypair_free( slot->data.ecp ); + mbedtls_free( slot->data.ecp ); } else #endif /* defined(MBEDTLS_ECP_C) */ From dc2fc8443fe4aa18797ffdea00d6649aa1e158ae Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 16:42:59 +0100 Subject: [PATCH 25/36] Rename xxx_of_psa functions to xxx_from_psa Be consistent with how similar functions are named in Mbed TLS. --- library/psa_crypto.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index c4e6be168..81da8cef0 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -521,7 +521,7 @@ psa_status_t psa_export_key(psa_key_slot_t key, /* Message digests */ /****************************************************************/ -static const mbedtls_md_info_t *mbedtls_md_info_of_psa( psa_algorithm_t alg ) +static const mbedtls_md_info_t *mbedtls_md_info_from_psa( psa_algorithm_t alg ) { switch( alg ) { @@ -865,7 +865,7 @@ psa_status_t psa_hash_verify(psa_hash_operation_t *operation, /* MAC */ /****************************************************************/ -static const mbedtls_cipher_info_t *mbedtls_cipher_info_of_psa( +static const mbedtls_cipher_info_t *mbedtls_cipher_info_from_psa( psa_algorithm_t alg, psa_key_type_t key_type, size_t key_bits ) @@ -984,7 +984,7 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation, if( ! PSA_ALG_IS_HMAC( alg ) ) { - cipher_info = mbedtls_cipher_info_of_psa( alg, key_type, key_bits ); + cipher_info = mbedtls_cipher_info_from_psa( alg, key_type, key_bits ); if( cipher_info == NULL ) return( PSA_ERROR_NOT_SUPPORTED ); operation->mac_size = cipher_info->block_size; @@ -1008,7 +1008,7 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation, if( PSA_ALG_IS_HMAC( alg ) ) { const mbedtls_md_info_t *md_info = - mbedtls_md_info_of_psa( PSA_ALG_HMAC_HASH( alg ) ); + mbedtls_md_info_from_psa( PSA_ALG_HMAC_HASH( alg ) ); if( md_info == NULL ) return( PSA_ERROR_NOT_SUPPORTED ); if( key_type != PSA_KEY_TYPE_HMAC ) @@ -1191,7 +1191,7 @@ psa_status_t psa_asymmetric_sign(psa_key_slot_t key, mbedtls_rsa_context *rsa = slot->data.rsa; int ret; psa_algorithm_t hash_alg = PSA_ALG_RSA_GET_HASH( alg ); - const mbedtls_md_info_t *md_info = mbedtls_md_info_of_psa( hash_alg ); + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_psa( hash_alg ); mbedtls_md_type_t md_alg = hash_alg == 0 ? MBEDTLS_MD_NONE : mbedtls_md_get_type( md_info ); if( md_alg == MBEDTLS_MD_NONE ) From 40f68b98630af5cc46cd7e2bf954e806fdbfab6c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Mar 2018 16:43:36 +0100 Subject: [PATCH 26/36] Use unhexify_alloc where applicable --- tests/suites/test_suite_psa_crypto.function | 51 ++++++--------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index d5305740f..93817948c 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -33,10 +33,8 @@ void import( char *hex, int type, int expected_status ) unsigned char *data = NULL; size_t data_size; - data_size = strlen( hex ) / 2; - data = mbedtls_calloc( 1, data_size ); + data = unhexify_alloc( hex, &data_size ); TEST_ASSERT( data != NULL ); - data_size = unhexify( data, hex ); TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); status = psa_import_key( slot, type, data, data_size ); @@ -71,10 +69,8 @@ void import_export( char *hex, int type_arg, psa_key_type_t got_type; size_t got_bits; - data_size = strlen( hex ) / 2; - data = mbedtls_calloc( 1, data_size ); + data = unhexify_alloc( hex, &data_size ); TEST_ASSERT( data != NULL ); - data_size = unhexify( data, hex ); export_size = (ssize_t) data_size + export_size_delta; exported = mbedtls_calloc( 1, export_size ); TEST_ASSERT( exported != NULL ); @@ -147,10 +143,8 @@ void hash_finish( int alg_arg, char *input_hex, char *hash_hex ) size_t actual_hash_length; psa_hash_operation_t operation; - input_size = strlen( input_hex ) / 2; - input = mbedtls_calloc( 1, input_size ); + input = unhexify_alloc( input_hex, &input_size ); TEST_ASSERT( input != NULL ); - input_size = unhexify( input, input_hex ); expected_hash_length = unhexify( expected_hash, hash_hex ); TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); @@ -181,10 +175,8 @@ void hash_verify( int alg_arg, char *input_hex, char *hash_hex ) size_t expected_hash_length; psa_hash_operation_t operation; - input_size = strlen( input_hex ) / 2; - input = mbedtls_calloc( 1, input_size ); + input = unhexify_alloc( input_hex, &input_size ); TEST_ASSERT( input != NULL ); - input_size = unhexify( input, input_hex ); expected_hash_length = unhexify( expected_hash, hash_hex ); TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); @@ -220,25 +212,17 @@ void mac_verify( int key_type_arg, char *key_hex, size_t expected_mac_size; psa_mac_operation_t operation; - key_size = strlen( key_hex ) / 2; - key = mbedtls_calloc( 1, key_size ); + key = unhexify_alloc( key_hex, &key_size ); TEST_ASSERT( key != NULL ); - key_size = unhexify( key, key_hex ); - iv_size = strlen( iv_hex ) / 2; - if( iv_size != 0 ) + if( iv_hex[0] != 0 ) { - iv = mbedtls_calloc( 1, iv_size ); + iv = unhexify_alloc( iv_hex, &iv_size ); TEST_ASSERT( iv != NULL ); - iv_size = unhexify( iv, iv_hex ); } - input_size = strlen( input_hex ) / 2; - input = mbedtls_calloc( 1, input_size ); + input = unhexify_alloc( input_hex, &input_size ); TEST_ASSERT( input != NULL ); - input_size = unhexify( input, input_hex ); - expected_mac_size = strlen( mac_hex ) / 2; - expected_mac = mbedtls_calloc( 1, expected_mac_size ); + expected_mac = unhexify_alloc( mac_hex, &expected_mac_size ); TEST_ASSERT( expected_mac != NULL ); - expected_mac_size = unhexify( expected_mac, mac_hex ); TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); @@ -293,15 +277,12 @@ void sign_deterministic( int key_type_arg, char *key_hex, size_t signature_size; size_t signature_length = 0xdeadbeef; - key_data = mbedtls_calloc( 1, strlen( key_hex ) / 2 ); + key_data = unhexify_alloc( key_hex, &key_size ); TEST_ASSERT( key_data != NULL ); - key_size = unhexify( key_data, key_hex ); - input_data = mbedtls_calloc( 1, strlen( input_hex ) / 2 ); + input_data = unhexify_alloc( input_hex, &input_size ); TEST_ASSERT( input_data != NULL ); - input_size = unhexify( input_data, input_hex ); - output_data = mbedtls_calloc( 1, strlen( output_hex ) / 2 ); + output_data = unhexify_alloc( output_hex, &output_size ); TEST_ASSERT( output_data != NULL ); - output_size = unhexify( output_data, output_hex ); TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); @@ -348,15 +329,13 @@ void sign_fail( int key_type_arg, char *key_hex, size_t input_size; psa_status_t actual_status; psa_status_t expected_status = expected_status_arg; - unsigned char *signature; + unsigned char *signature = NULL; size_t signature_length = 0xdeadbeef; - key_data = mbedtls_calloc( 1, strlen( key_hex ) / 2 ); + key_data = unhexify_alloc( key_hex, &key_size ); TEST_ASSERT( key_data != NULL ); - key_size = unhexify( key_data, key_hex ); - input_data = mbedtls_calloc( 1, strlen( input_hex ) / 2 ); + input_data = unhexify_alloc( input_hex, &input_size ); TEST_ASSERT( input_data != NULL ); - input_size = unhexify( input_data, input_hex ); signature = mbedtls_calloc( 1, signature_size ); TEST_ASSERT( signature != NULL ); From 06dc26350e7aa73543ce8446373d4ed8c30e079f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Mar 2018 07:47:25 +0100 Subject: [PATCH 27/36] Fix macro definitions for ECC keys Public keys and key pairs have different types. --- include/psa/crypto.h | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index cc9881bad..16d7c08c8 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -156,8 +156,17 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_RSA_PUBLIC_KEY ((psa_key_type_t)0x06010000) /** RSA key pair (private and public key). */ #define PSA_KEY_TYPE_RSA_KEYPAIR ((psa_key_type_t)0x07010000) -#define PSA_KEY_TYPE_ECC_BASE ((psa_key_type_t)0x06030000) +/** DSA public key. */ +#define PSA_KEY_TYPE_DSA_PUBLIC_KEY ((psa_key_type_t)0x06020000) +/** DSA key pair (private and public key). */ +#define PSA_KEY_TYPE_DSA_KEYPAIR ((psa_key_type_t)0x07020000) +#define PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE ((psa_key_type_t)0x06030000) +#define PSA_KEY_TYPE_ECC_KEYPAIR_BASE ((psa_key_type_t)0x07030000) #define PSA_KEY_TYPE_ECC_CURVE_MASK ((psa_key_type_t)0x0000ffff) +#define PSA_KEY_TYPE_ECC_KEYPAIR(curve) \ + (PSA_KEY_TYPE_ECC_KEYPAIR_BASE | (curve)) +#define PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) \ + (PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE | (curve)) /** Whether a key type is vendor-defined. */ #define PSA_KEY_TYPE_IS_VENDOR_DEFINED(type) \ @@ -165,18 +174,32 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_IS_RAW_BYTES(type) \ (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_RAW_DATA || \ ((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_SYMMETRIC) + +/** Whether a key type is asymmetric: either a key pair or a public key. */ #define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \ (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_ASYMMETRIC) +/** Whether a key type is the public part of a key pair. */ #define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \ (((type) & (PSA_KEY_TYPE_CATEGORY_MASK | PSA_KEY_TYPE_PAIR_FLAG) == \ PSA_KEY_TYPE_CATEGORY_ASYMMETRIC)) +/** Whether a key type is a key pair containing a private part and a public + * part. */ #define PSA_KEY_TYPE_IS_KEYPAIR(type) \ (((type) & (PSA_KEY_TYPE_CATEGORY_MASK | PSA_KEY_TYPE_PAIR_FLAG)) == \ (PSA_KEY_TYPE_CATEGORY_ASYMMETRIC | PSA_KEY_TYPE_PAIR_FLAG)) +/** Whether a key type is an RSA key pair or public key. */ +/** The key pair type corresponding to a public key type. */ +#define PSA_KEY_TYPE_KEYPAIR_OF_PUBLIC_KEY(type) \ + ((type) | PSA_KEY_TYPE_PAIR_FLAG) +/** The public key type corresponding to a key pair type. */ +#define PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) \ + ((type) & ~PSA_KEY_TYPE_PAIR_FLAG) #define PSA_KEY_TYPE_IS_RSA(type) \ - (((type) & ~PSA_KEY_TYPE_PAIR_FLAG) == PSA_KEY_TYPE_RSA_PUBLIC_KEY) + (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY) +/** Whether a key type is an elliptic curve key pair or public key. */ #define PSA_KEY_TYPE_IS_ECC(type) \ - (((type) & ~PSA_KEY_TYPE_ECC_CURVE_MASK) == PSA_KEY_TYPE_ECC_BASE) + ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) & \ + ~PSA_KEY_TYPE_ECC_CURVE_MASK) == PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE) #define PSA_BLOCK_CIPHER_BLOCK_SIZE(type) \ ( \ From e3f694f49a1c561689a1279f3ad5c4b9dbf9381d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Mar 2018 07:48:40 +0100 Subject: [PATCH 28/36] Remove non-standard hash algorithms --- include/psa/crypto.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 16d7c08c8..ffa70d5c3 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -259,10 +259,8 @@ typedef uint32_t psa_algorithm_t; #define PSA_ALG_MD2 ((psa_algorithm_t)0x01000001) #define PSA_ALG_MD4 ((psa_algorithm_t)0x01000002) #define PSA_ALG_MD5 ((psa_algorithm_t)0x01000003) -#define PSA_ALG_SHA_256_128 ((psa_algorithm_t)0x01000004) -#define PSA_ALG_RIPEMD160 ((psa_algorithm_t)0x01000005) -#define PSA_ALG_SHA_1 ((psa_algorithm_t)0x01000006) -#define PSA_ALG_SHA_256_160 ((psa_algorithm_t)0x01000007) +#define PSA_ALG_RIPEMD160 ((psa_algorithm_t)0x01000004) +#define PSA_ALG_SHA_1 ((psa_algorithm_t)0x01000005) #define PSA_ALG_SHA_224 ((psa_algorithm_t)0x01000008) #define PSA_ALG_SHA_256 ((psa_algorithm_t)0x01000009) #define PSA_ALG_SHA_384 ((psa_algorithm_t)0x0100000a) @@ -572,10 +570,8 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; (alg) == PSA_ALG_MD2 ? 16 : \ (alg) == PSA_ALG_MD4 ? 16 : \ (alg) == PSA_ALG_MD5 ? 16 : \ - (alg) == PSA_ALG_SHA_256_128 ? 16 : \ (alg) == PSA_ALG_RIPEMD160 ? 20 : \ (alg) == PSA_ALG_SHA_1 ? 20 : \ - (alg) == PSA_ALG_SHA_256_160 ? 20 : \ (alg) == PSA_ALG_SHA_224 ? 28 : \ (alg) == PSA_ALG_SHA_256 ? 32 : \ (alg) == PSA_ALG_SHA_384 ? 48 : \ From d393e18f90bab4c70d00cd5e65a5a64be5c98150 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Mar 2018 07:49:16 +0100 Subject: [PATCH 29/36] Add psa_set_key_lifetime It is likely that most implementations won't support this function. But in case an implementation wants to provide it, standardize its interface. --- include/psa/crypto.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index ffa70d5c3..5edc04fcd 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -537,9 +537,22 @@ typedef uint32_t psa_key_lifetime_t; */ #define PSA_KEY_LIFETIME_WRITE_ONCE ((psa_key_lifetime_t)0x7fffffff) +/** \brief Retrieve the lifetime of a key slot. + * + * The assignment of lifetimes to slots is implementation-dependent. + */ psa_status_t psa_get_key_lifetime(psa_key_slot_t key, psa_key_lifetime_t *lifetime); +/** \brief Change the lifetime of a key slot. + * + * Whether the lifetime of a key slot can be changed at all, and if so + * whether the lifetime of an occupied key slot can be chaned, is + * implementation-dependent. + */ +psa_status_t psa_set_key_lifetime(psa_key_slot_t key, + const psa_key_lifetime_t *lifetime); + /**@}*/ /** \defgroup hash Message digests From 7e1985372206de30c0da8e65e0498f5b1118b47c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 8 Mar 2018 07:50:30 +0100 Subject: [PATCH 30/36] More documentation --- include/psa/crypto.h | 59 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 5edc04fcd..69c93dd6a 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -201,11 +201,24 @@ typedef uint32_t psa_key_type_t; ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) & \ ~PSA_KEY_TYPE_ECC_CURVE_MASK) == PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE) +/** The block size of a block cipher. + * + * \param type A cipher key type (value of type #psa_key_type_t). + * + * \return The block size for a block cipher, or 1 for a stream cipher. + * The return value is undefined if \c type does not identify + * a cipher algorithm. + * + * \note This macro returns a compile-time constant if its argument is one. + * + * \warning This macro may evaluate its argument multiple times. + */ #define PSA_BLOCK_CIPHER_BLOCK_SIZE(type) \ ( \ (type) == PSA_KEY_TYPE_AES ? 16 : \ (type) == PSA_KEY_TYPE_DES ? 8 : \ (type) == PSA_KEY_TYPE_CAMELLIA ? 16 : \ + (type) == PSA_KEY_TYPE_ARC4 ? 1 : \ 0) /** \brief Encoding of a cryptographic algorithm. @@ -233,11 +246,12 @@ typedef uint32_t psa_algorithm_t; (((alg) & PSA_ALG_VENDOR_FLAG) != 0) /** Whether the specified algorithm is a hash algorithm. * - * \param alg An algorithm identifier (\c PSA_ALG_XXX value) + * \param alg An algorithm identifier (value of type #psa_algorithm_t). * * \return 1 if \c alg is a hash algorithm, 0 otherwise. * This macro may return either 0 or 1 if \c alg is not a valid - * algorithm identifier. */ + * algorithm identifier. + */ #define PSA_ALG_IS_HASH(alg) \ (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_HASH) #define PSA_ALG_IS_MAC(alg) \ @@ -474,11 +488,41 @@ psa_status_t psa_export_public_key(psa_key_slot_t key, /** \brief Encoding of permitted usage on a key. */ typedef uint32_t psa_key_usage_t; +/** Whether the key may be exported. + * + * A public key or the public part of a key pair may always be exported + * regardless of the value of this permission flag. + * + * If a key does not have export permission, implementations shall not + * allow the key to be exported in plain form from the cryptoprocessor, + * whether through psa_export_key() or through a proprietary interface. + * The key may however be exportable in a wrapped form, i.e. in a form + * where it is encrypted by another key. + */ #define PSA_KEY_USAGE_EXPORT ((psa_key_usage_t)0x00000001) +/** Whether the key may be used to encrypt a message. + * + * For a key pair, this concerns the public key. + */ #define PSA_KEY_USAGE_ENCRYPT ((psa_key_usage_t)0x00000100) + +/** Whether the key may be used to decrypt a message. + * + * For a key pair, this concerns the private key. + */ #define PSA_KEY_USAGE_DECRYPT ((psa_key_usage_t)0x00000200) + +/** Whether the key may be used to sign a message. + * + * For a key pair, this concerns the private key. + */ #define PSA_KEY_USAGE_SIGN ((psa_key_usage_t)0x00000400) + +/** Whether the key may be used to verify a message signature. + * + * For a key pair, this concerns the public key. + */ #define PSA_KEY_USAGE_VERIFY ((psa_key_usage_t)0x00000800) /** The type of the key policy data structure. @@ -492,6 +536,12 @@ typedef struct psa_key_policy_s psa_key_policy_t; * usage of the key. */ void psa_key_policy_init(psa_key_policy_t *policy); +/** \brief Set the standard fields of a policy structure. + * + * Note that this function does not make any consistency check of the + * parameters. The values are only checked when applying the policy to + * a key slot with psa_set_key_policy(). + */ void psa_key_policy_set_usage(psa_key_policy_t *policy, psa_key_usage_t usage, psa_algorithm_t alg); @@ -505,10 +555,15 @@ psa_algorithm_t psa_key_policy_get_algorithm(psa_key_policy_t *policy); * This function must be called on an empty key slot, before importing, * generating or creating a key in the slot. Changing the policy of an * existing key is not permitted. + * + * Implementations may set restrictions on supported key policies + * depending on the key type and the key slot. */ psa_status_t psa_set_key_policy(psa_key_slot_t key, const psa_key_policy_t *policy); +/** \brief Get the usage policy for a key slot. + */ psa_status_t psa_get_key_policy(psa_key_slot_t key, psa_key_policy_t *policy); From 971f7064e932d19e6b51d095421823fe40f37cc9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Mar 2018 17:52:58 +0100 Subject: [PATCH 31/36] More precise reference for the RSA public key format --- include/psa/crypto.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 69c93dd6a..95c894852 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -428,7 +428,7 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, * is the non-encrypted DER representation defined by PKCS\#8 (RFC 5208) * as PrivateKeyInfo. * - For RSA public keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY), the format - * is the DER representation defined by X.509. + * is the DER representation defined by RFC 5280 as SubjectPublicKeyInfo. * * \param key Slot whose content is to be exported. This must * be an occupied key slot. @@ -458,7 +458,8 @@ psa_status_t psa_export_key(psa_key_slot_t key, * For standard key types, the output format is as follows: * * - For RSA keys (#PSA_KEY_TYPE_RSA_KEYPAIR or #PSA_KEY_TYPE_RSA_PUBLIC_KEY), - * the format is the DER representation defined by X.509. + * is the DER representation of the public key defined by RFC 5280 + * as SubjectPublicKeyInfo. * * \param key Slot whose content is to be exported. This must * be an occupied key slot. From ed522974bdf5528bc668532bfd2a02bc4f4b3bcf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Mar 2018 17:54:15 +0100 Subject: [PATCH 32/36] Clarify how multipart operations get terminated --- include/psa/crypto.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 95c894852..a9cddc027 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -670,7 +670,8 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; * has been initialized with psa_hash_start(). * * After a successful call to psa_hash_start(), the application must - * eventually destroy the operation through one of the following means: + * eventually terminate the operation. The following events terminate an + * operation: * - A failed call to psa_hash_update(). * - A call to psa_hash_final(), psa_hash_verify() or psa_hash_abort(). * @@ -862,7 +863,8 @@ typedef struct psa_mac_operation_s psa_mac_operation_t; * has been initialized with psa_mac_start(). * * After a successful call to psa_mac_start(), the application must - * eventually destroy the operation through one of the following means: + * eventually terminate the operation. The following events terminate an + * operation: * - A failed call to psa_mac_update(). * - A call to psa_mac_final(), psa_mac_verify() or psa_mac_abort(). * @@ -936,7 +938,8 @@ typedef struct psa_cipher_operation_s psa_cipher_operation_t; * has been initialized with psa_encrypt_setup(). * * After a successful call to psa_encrypt_setup(), the application must - * eventually destroy the operation through one of the following means: + * eventually terminate the operation. The following events terminate an + * operation: * - A failed call to psa_encrypt_generate_iv(), psa_encrypt_set_iv() * or psa_cipher_update(). * - A call to psa_cipher_final() or psa_cipher_abort(). @@ -983,7 +986,8 @@ psa_status_t psa_encrypt_setup(psa_cipher_operation_t *operation, * has been initialized with psa_encrypt_setup(). * * After a successful call to psa_decrypt_setup(), the application must - * eventually destroy the operation through one of the following means: + * eventually terminate the operation. The following events terminate an + * operation: * - A failed call to psa_cipher_update(). * - A call to psa_cipher_final() or psa_cipher_abort(). * @@ -1064,8 +1068,9 @@ typedef struct psa_aead_operation_s psa_aead_operation_t; * The application may call psa_aead_abort() at any time after the operation * has been initialized with psa_aead_encrypt_setup(). * - * After a successful call to psa_aead_setup(), the application must - * eventually destroy the operation through one of the following means: + * After a successful call to psa_aead_encrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an + * operation: * - A failed call to psa_aead_generate_iv(), psa_aead_set_iv(), * psa_aead_update_ad() or psa_aead_update(). * - A call to psa_aead_final() or psa_aead_abort(). @@ -1112,8 +1117,9 @@ psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, * The application may call psa_aead_abort() at any time after the operation * has been initialized with psa_aead_decrypt_setup(). * - * After a successful call to psa_decrypt_setup(), the application must - * eventually destroy the operation through one of the following means: + * After a successful call to psa_aead_decrypt_setup(), the application must + * eventually terminate the operation. The following events terminate an + * operation: * - A failed call to psa_aead_update(). * - A call to psa_cipher_final() or psa_cipher_abort(). * From 1906798d4ce0cc5e7d3c5dd1afe9c8e7d6933b73 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Mar 2018 17:54:53 +0100 Subject: [PATCH 33/36] Fix some typos and copypasta --- include/psa/crypto.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index a9cddc027..04e6b4796 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -603,7 +603,7 @@ psa_status_t psa_get_key_lifetime(psa_key_slot_t key, /** \brief Change the lifetime of a key slot. * * Whether the lifetime of a key slot can be changed at all, and if so - * whether the lifetime of an occupied key slot can be chaned, is + * whether the lifetime of an occupied key slot can be changed, is * implementation-dependent. */ psa_status_t psa_set_key_lifetime(psa_key_slot_t key, @@ -673,7 +673,7 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; * eventually terminate the operation. The following events terminate an * operation: * - A failed call to psa_hash_update(). - * - A call to psa_hash_final(), psa_hash_verify() or psa_hash_abort(). + * - A call to psa_hash_finish(), psa_hash_verify() or psa_hash_abort(). * * \param operation * \param alg The hash algorithm to compute (\c PSA_ALG_XXX value @@ -767,7 +767,7 @@ psa_status_t psa_hash_finish(psa_hash_operation_t *operation, * * When this function returns, the operation becomes inactive. * - * \note Applications shall make the best effort to ensure that the + * \note Implementations shall make the best effort to ensure that the * comparison between the actual hash and the expected hash is performed * in constant time. * @@ -866,7 +866,7 @@ typedef struct psa_mac_operation_s psa_mac_operation_t; * eventually terminate the operation. The following events terminate an * operation: * - A failed call to psa_mac_update(). - * - A call to psa_mac_final(), psa_mac_verify() or psa_mac_abort(). + * - A call to psa_mac_finish(), psa_mac_verify() or psa_mac_abort(). * * \param operation * \param alg The MAC algorithm to compute (\c PSA_ALG_XXX value @@ -942,7 +942,7 @@ typedef struct psa_cipher_operation_s psa_cipher_operation_t; * operation: * - A failed call to psa_encrypt_generate_iv(), psa_encrypt_set_iv() * or psa_cipher_update(). - * - A call to psa_cipher_final() or psa_cipher_abort(). + * - A call to psa_cipher_finish() or psa_cipher_abort(). * * \param operation * \param alg The cipher algorithm to compute (\c PSA_ALG_XXX value @@ -989,7 +989,7 @@ psa_status_t psa_encrypt_setup(psa_cipher_operation_t *operation, * eventually terminate the operation. The following events terminate an * operation: * - A failed call to psa_cipher_update(). - * - A call to psa_cipher_final() or psa_cipher_abort(). + * - A call to psa_cipher_finish() or psa_cipher_abort(). * * \param operation * \param alg The cipher algorithm to compute (\c PSA_ALG_XXX value @@ -1073,7 +1073,7 @@ typedef struct psa_aead_operation_s psa_aead_operation_t; * operation: * - A failed call to psa_aead_generate_iv(), psa_aead_set_iv(), * psa_aead_update_ad() or psa_aead_update(). - * - A call to psa_aead_final() or psa_aead_abort(). + * - A call to psa_aead_finish() or psa_aead_abort(). * * \param operation * \param alg The AEAD algorithm to compute (\c PSA_ALG_XXX value @@ -1121,11 +1121,11 @@ psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, * eventually terminate the operation. The following events terminate an * operation: * - A failed call to psa_aead_update(). - * - A call to psa_cipher_final() or psa_cipher_abort(). + * - A call to psa_aead_finish() or psa_aead_abort(). * * \param operation - * \param alg The cipher algorithm to compute (\c PSA_ALG_XXX value - * such that #PSA_ALG_IS_CIPHER(alg) is true). + * \param alg The AEAD algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_AEAD(alg) is true). * * \retval PSA_SUCCESS * Success. @@ -1134,7 +1134,7 @@ psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, * \retval PSA_ERROR_INVALID_ARGUMENT * \c key is not compatible with \c alg. * \retval PSA_ERROR_NOT_SUPPORTED - * \c alg is not supported or is not a cipher algorithm. + * \c alg is not supported or is not an AEAD algorithm. * \retval PSA_ERROR_INSUFFICIENT_MEMORY * \retval PSA_ERROR_COMMUNICATION_FAILURE * \retval PSA_ERROR_HARDWARE_FAILURE From 47c1bc0458dd91644a59f05d249d111d842d5802 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 20 Mar 2018 17:55:04 +0100 Subject: [PATCH 34/36] Correct some return codes --- library/psa_crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 81da8cef0..c93da95b9 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -588,7 +588,7 @@ static psa_algorithm_t mbedtls_md_alg_to_psa( mbedtls_md_type_t md_alg ) case MBEDTLS_MD_RIPEMD160: return( PSA_ALG_RIPEMD160 ); default: - return( MBEDTLS_MD_NOT_SUPPORTED ); + return( 0 ); } } #endif @@ -1039,7 +1039,7 @@ psa_status_t psa_mac_start( psa_mac_operation_t *operation, return( mbedtls_to_psa_error( ret ) ); } operation->key_set = 1; - return( 0 ); + return( PSA_SUCCESS ); } psa_status_t psa_mac_update( psa_mac_operation_t *operation, From 9a1ba0dd3f8b95cf17f46331257dd2bc0ac7d0d5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Mar 2018 20:49:16 +0100 Subject: [PATCH 35/36] Typo in the documentation of psa_get_key_information --- include/psa/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 04e6b4796..e8b22e0f5 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -392,7 +392,7 @@ psa_status_t psa_destroy_key(psa_key_slot_t key); * This may be a null pointer, in which case the key type * is not written. * \param bits On success, the key size in bits. - * This may be a null pointer, in which case the key type + * This may be a null pointer, in which case the key size * is not written. * * \retval PSA_SUCCESS From 058e0b99631b4279a9f939c2773ee10beb197c73 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 22 Mar 2018 16:20:19 +0100 Subject: [PATCH 36/36] Avoid empty unions When no algorithms are present in a category (e.g. no AEAD algorithm), the union in the corresponding operation structure was empty, which is not valid C. Add a dummy field to avoid this. --- include/psa/crypto_struct.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index c0a673860..898784013 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -50,6 +50,7 @@ struct psa_hash_operation_s psa_algorithm_t alg; union { + unsigned dummy; /* Make the union non-empty even with no supported algorithms. */ #if defined(MBEDTLS_MD2_C) mbedtls_md2_context md2; #endif @@ -84,6 +85,7 @@ struct psa_mac_operation_s uint8_t mac_size; union { + unsigned dummy; /* Make the union non-empty even with no supported algorithms. */ #if defined(MBEDTLS_MD_C) mbedtls_md_context_t hmac; #endif @@ -102,6 +104,7 @@ struct psa_cipher_operation_s uint8_t block_size; union { + unsigned dummy; /* Make the union non-empty even with no supported algorithms. */ } ctx; }; @@ -115,6 +118,7 @@ struct psa_aead_operation_s uint8_t block_size; union { + unsigned dummy; /* Make the union non-empty even with no supported algorithms. */ } ctx; };