/* BEGIN_HEADER */ #include #include "mbedtls/asn1.h" #include "mbedtls/asn1write.h" #include "mbedtls/oid.h" #include "psa_crypto_helpers.h" /** An invalid export length that will never be set by psa_export_key(). */ static const size_t INVALID_EXPORT_LENGTH = ~0U; /* A hash algorithm that is known to be supported. * * This is used in some smoke tests. */ #if defined(MBEDTLS_MD2_C) #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD2 #elif defined(MBEDTLS_MD4_C) #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD4 #elif defined(MBEDTLS_MD5_C) #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_MD5 /* MBEDTLS_RIPEMD160_C omitted. This is necessary for the sake of * exercise_signature_key() because Mbed TLS doesn't support RIPEMD160 * in RSA PKCS#1v1.5 signatures. A RIPEMD160-only configuration would be * implausible anyway. */ #elif defined(MBEDTLS_SHA1_C) #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_1 #elif defined(MBEDTLS_SHA256_C) #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_256 #elif defined(MBEDTLS_SHA512_C) #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA_384 #elif defined(MBEDTLS_SHA3_C) #define KNOWN_SUPPORTED_HASH_ALG PSA_ALG_SHA3_256 #else #undef KNOWN_SUPPORTED_HASH_ALG #endif /* A block cipher that is known to be supported. * * For simplicity's sake, stick to block ciphers with 16-byte blocks. */ #if defined(MBEDTLS_AES_C) #define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_AES #elif defined(MBEDTLS_ARIA_C) #define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_ARIA #elif defined(MBEDTLS_CAMELLIA_C) #define KNOWN_SUPPORTED_BLOCK_CIPHER PSA_KEY_TYPE_CAMELLIA #undef KNOWN_SUPPORTED_BLOCK_CIPHER #endif /* A MAC mode that is known to be supported. * * It must either be HMAC with #KNOWN_SUPPORTED_HASH_ALG or * a block cipher-based MAC with #KNOWN_SUPPORTED_BLOCK_CIPHER. * * This is used in some smoke tests. */ #if defined(KNOWN_SUPPORTED_HASH_ALG) #define KNOWN_SUPPORTED_MAC_ALG ( PSA_ALG_HMAC( KNOWN_SUPPORTED_HASH_ALG ) ) #define KNOWN_SUPPORTED_MAC_KEY_TYPE PSA_KEY_TYPE_HMAC #elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CMAC_C) #define KNOWN_SUPPORTED_MAC_ALG PSA_ALG_CMAC #define KNOWN_SUPPORTED_MAC_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER #else #undef KNOWN_SUPPORTED_MAC_ALG #undef KNOWN_SUPPORTED_MAC_KEY_TYPE #endif /* A cipher algorithm and key type that are known to be supported. * * This is used in some smoke tests. */ #if defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CTR) #define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CTR #elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CBC) #define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CBC_NO_PADDING #elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_CFB) #define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_CFB #elif defined(KNOWN_SUPPORTED_BLOCK_CIPHER) && defined(MBEDTLS_CIPHER_MODE_OFB) #define KNOWN_SUPPORTED_BLOCK_CIPHER_ALG PSA_ALG_OFB #else #undef KNOWN_SUPPORTED_BLOCK_CIPHER_ALG #endif #if defined(KNOWN_SUPPORTED_BLOCK_CIPHER_ALG) #define KNOWN_SUPPORTED_CIPHER_ALG KNOWN_SUPPORTED_BLOCK_CIPHER_ALG #define KNOWN_SUPPORTED_CIPHER_KEY_TYPE KNOWN_SUPPORTED_BLOCK_CIPHER #elif defined(MBEDTLS_RC4_C) #define KNOWN_SUPPORTED_CIPHER_ALG PSA_ALG_RC4 #define KNOWN_SUPPORTED_CIPHER_KEY_TYPE PSA_KEY_TYPE_RC4 #else #undef KNOWN_SUPPORTED_CIPHER_ALG #undef KNOWN_SUPPORTED_CIPHER_KEY_TYPE #endif /** Test if a buffer contains a constant byte value. * * `mem_is_char(buffer, c, size)` is true after `memset(buffer, c, size)`. * * \param buffer Pointer to the beginning of the buffer. * \param c Expected value of every byte. * \param size Size of the buffer in bytes. * * \return 1 if the buffer is all-bits-zero. * \return 0 if there is at least one nonzero byte. */ static int mem_is_char( void *buffer, unsigned char c, size_t size ) { size_t i; for( i = 0; i < size; i++ ) { if( ( (unsigned char *) buffer )[i] != c ) return( 0 ); } return( 1 ); } /* Write the ASN.1 INTEGER with the value 2^(bits-1)+x backwards from *p. */ static int asn1_write_10x( unsigned char **p, unsigned char *start, size_t bits, unsigned char x ) { int ret; int len = bits / 8 + 1; if( bits == 0 ) return( MBEDTLS_ERR_ASN1_INVALID_DATA ); if( bits <= 8 && x >= 1 << ( bits - 1 ) ) return( MBEDTLS_ERR_ASN1_INVALID_DATA ); if( *p < start || *p - start < (ptrdiff_t) len ) return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); *p -= len; ( *p )[len-1] = x; if( bits % 8 == 0 ) ( *p )[1] |= 1; else ( *p )[0] |= 1 << ( bits % 8 ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); return( len ); } static int construct_fake_rsa_key( unsigned char *buffer, size_t buffer_size, unsigned char **p, size_t bits, int keypair ) { size_t half_bits = ( bits + 1 ) / 2; int ret; int len = 0; /* Construct something that looks like a DER encoding of * as defined by PKCS#1 v2.2 (RFC 8017) section A.1.2: * RSAPrivateKey ::= SEQUENCE { * version Version, * modulus INTEGER, -- n * publicExponent INTEGER, -- e * privateExponent INTEGER, -- d * prime1 INTEGER, -- p * prime2 INTEGER, -- q * exponent1 INTEGER, -- d mod (p-1) * exponent2 INTEGER, -- d mod (q-1) * coefficient INTEGER, -- (inverse of q) mod p * otherPrimeInfos OtherPrimeInfos OPTIONAL * } * Or, for a public key, the same structure with only * version, modulus and publicExponent. */ *p = buffer + buffer_size; if( keypair ) { MBEDTLS_ASN1_CHK_ADD( len, /* pq */ asn1_write_10x( p, buffer, half_bits, 1 ) ); MBEDTLS_ASN1_CHK_ADD( len, /* dq */ asn1_write_10x( p, buffer, half_bits, 1 ) ); MBEDTLS_ASN1_CHK_ADD( len, /* dp */ asn1_write_10x( p, buffer, half_bits, 1 ) ); MBEDTLS_ASN1_CHK_ADD( len, /* q */ asn1_write_10x( p, buffer, half_bits, 1 ) ); MBEDTLS_ASN1_CHK_ADD( len, /* p != q to pass mbedtls sanity checks */ asn1_write_10x( p, buffer, half_bits, 3 ) ); MBEDTLS_ASN1_CHK_ADD( len, /* d */ asn1_write_10x( p, buffer, bits, 1 ) ); } MBEDTLS_ASN1_CHK_ADD( len, /* e = 65537 */ asn1_write_10x( p, buffer, 17, 1 ) ); MBEDTLS_ASN1_CHK_ADD( len, /* n */ asn1_write_10x( p, buffer, bits, 1 ) ); if( keypair ) MBEDTLS_ASN1_CHK_ADD( len, /* version = 0 */ mbedtls_asn1_write_int( p, buffer, 0 ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, buffer, len ) ); { const unsigned char tag = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE; MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, buffer, tag ) ); } return( len ); } int exercise_mac_setup( psa_key_type_t key_type, const unsigned char *key_bytes, size_t key_length, psa_algorithm_t alg, psa_mac_operation_t *operation, psa_status_t *status ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_bytes, key_length, &handle ) ); *status = psa_mac_sign_setup( operation, handle, alg ); /* Whether setup succeeded or failed, abort must succeed. */ PSA_ASSERT( psa_mac_abort( operation ) ); /* If setup failed, reproduce the failure, so that the caller can * test the resulting state of the operation object. */ if( *status != PSA_SUCCESS ) { TEST_EQUAL( psa_mac_sign_setup( operation, handle, alg ), *status ); } psa_destroy_key( handle ); return( 1 ); exit: psa_destroy_key( handle ); return( 0 ); } int exercise_cipher_setup( psa_key_type_t key_type, const unsigned char *key_bytes, size_t key_length, psa_algorithm_t alg, psa_cipher_operation_t *operation, psa_status_t *status ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_bytes, key_length, &handle ) ); *status = psa_cipher_encrypt_setup( operation, handle, alg ); /* Whether setup succeeded or failed, abort must succeed. */ PSA_ASSERT( psa_cipher_abort( operation ) ); /* If setup failed, reproduce the failure, so that the caller can * test the resulting state of the operation object. */ if( *status != PSA_SUCCESS ) { TEST_EQUAL( psa_cipher_encrypt_setup( operation, handle, alg ), *status ); } psa_destroy_key( handle ); return( 1 ); exit: psa_destroy_key( handle ); return( 0 ); } static int exercise_mac_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; const unsigned char input[] = "foo"; unsigned char mac[PSA_MAC_MAX_SIZE] = {0}; size_t mac_length = sizeof( mac ); if( usage & PSA_KEY_USAGE_SIGN ) { PSA_ASSERT( psa_mac_sign_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); PSA_ASSERT( psa_mac_sign_finish( &operation, mac, sizeof( mac ), &mac_length ) ); } if( usage & PSA_KEY_USAGE_VERIFY ) { psa_status_t verify_status = ( usage & PSA_KEY_USAGE_SIGN ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE ); PSA_ASSERT( psa_mac_verify_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); TEST_EQUAL( psa_mac_verify_finish( &operation, mac, mac_length ), verify_status ); } return( 1 ); exit: psa_mac_abort( &operation ); return( 0 ); } static int exercise_cipher_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; unsigned char iv[16] = {0}; size_t iv_length = sizeof( iv ); const unsigned char plaintext[16] = "Hello, world..."; unsigned char ciphertext[32] = "(wabblewebblewibblewobblewubble)"; size_t ciphertext_length = sizeof( ciphertext ); unsigned char decrypted[sizeof( ciphertext )]; size_t part_length; if( usage & PSA_KEY_USAGE_ENCRYPT ) { PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_generate_iv( &operation, iv, sizeof( iv ), &iv_length ) ); PSA_ASSERT( psa_cipher_update( &operation, plaintext, sizeof( plaintext ), ciphertext, sizeof( ciphertext ), &ciphertext_length ) ); PSA_ASSERT( psa_cipher_finish( &operation, ciphertext + ciphertext_length, sizeof( ciphertext ) - ciphertext_length, &part_length ) ); ciphertext_length += part_length; } if( usage & PSA_KEY_USAGE_DECRYPT ) { psa_status_t status; int maybe_invalid_padding = 0; if( ! ( usage & PSA_KEY_USAGE_ENCRYPT ) ) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); /* This should be PSA_CIPHER_GET_IV_SIZE but the API doesn't * have this macro yet. */ iv_length = PSA_BLOCK_CIPHER_BLOCK_SIZE( psa_get_key_type( &attributes ) ); maybe_invalid_padding = ! PSA_ALG_IS_STREAM_CIPHER( alg ); } PSA_ASSERT( psa_cipher_decrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv, iv_length ) ); PSA_ASSERT( psa_cipher_update( &operation, ciphertext, ciphertext_length, decrypted, sizeof( decrypted ), &part_length ) ); status = psa_cipher_finish( &operation, decrypted + part_length, sizeof( decrypted ) - part_length, &part_length ); /* For a stream cipher, all inputs are valid. For a block cipher, * if the input is some aribtrary data rather than an actual ciphertext, a padding error is likely. */ if( maybe_invalid_padding ) TEST_ASSERT( status == PSA_SUCCESS || status == PSA_ERROR_INVALID_PADDING ); else PSA_ASSERT( status ); } return( 1 ); exit: psa_cipher_abort( &operation ); return( 0 ); } static int exercise_aead_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { unsigned char nonce[16] = {0}; size_t nonce_length = sizeof( nonce ); unsigned char plaintext[16] = "Hello, world..."; unsigned char ciphertext[48] = "(wabblewebblewibblewobblewubble)"; size_t ciphertext_length = sizeof( ciphertext ); size_t plaintext_length = sizeof( ciphertext ); if( usage & PSA_KEY_USAGE_ENCRYPT ) { PSA_ASSERT( psa_aead_encrypt( handle, alg, nonce, nonce_length, NULL, 0, plaintext, sizeof( plaintext ), ciphertext, sizeof( ciphertext ), &ciphertext_length ) ); } if( usage & PSA_KEY_USAGE_DECRYPT ) { psa_status_t verify_status = ( usage & PSA_KEY_USAGE_ENCRYPT ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE ); TEST_EQUAL( psa_aead_decrypt( handle, alg, nonce, nonce_length, NULL, 0, ciphertext, ciphertext_length, plaintext, sizeof( plaintext ), &plaintext_length ), verify_status ); } return( 1 ); exit: return( 0 ); } static int exercise_signature_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { unsigned char payload[PSA_HASH_MAX_SIZE] = {1}; size_t payload_length = 16; unsigned char signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0}; size_t signature_length = sizeof( signature ); psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH( alg ); /* If the policy allows signing with any hash, just pick one. */ if( PSA_ALG_IS_HASH_AND_SIGN( alg ) && hash_alg == PSA_ALG_ANY_HASH ) { #if defined(KNOWN_SUPPORTED_HASH_ALG) hash_alg = KNOWN_SUPPORTED_HASH_ALG; alg ^= PSA_ALG_ANY_HASH ^ hash_alg; #else test_fail( "No hash algorithm for hash-and-sign testing", __LINE__, __FILE__ ); return( 1 ); #endif } if( usage & PSA_KEY_USAGE_SIGN ) { /* Some algorithms require the payload to have the size of * the hash encoded in the algorithm. Use this input size * even for algorithms that allow other input sizes. */ if( hash_alg != 0 ) payload_length = PSA_HASH_SIZE( hash_alg ); PSA_ASSERT( psa_asymmetric_sign( handle, alg, payload, payload_length, signature, sizeof( signature ), &signature_length ) ); } if( usage & PSA_KEY_USAGE_VERIFY ) { psa_status_t verify_status = ( usage & PSA_KEY_USAGE_SIGN ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE ); TEST_EQUAL( psa_asymmetric_verify( handle, alg, payload, payload_length, signature, signature_length ), verify_status ); } return( 1 ); exit: return( 0 ); } static int exercise_asymmetric_encryption_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { unsigned char plaintext[256] = "Hello, world..."; unsigned char ciphertext[256] = "(wabblewebblewibblewobblewubble)"; size_t ciphertext_length = sizeof( ciphertext ); size_t plaintext_length = 16; if( usage & PSA_KEY_USAGE_ENCRYPT ) { PSA_ASSERT( psa_asymmetric_encrypt( handle, alg, plaintext, plaintext_length, NULL, 0, ciphertext, sizeof( ciphertext ), &ciphertext_length ) ); } if( usage & PSA_KEY_USAGE_DECRYPT ) { psa_status_t status = psa_asymmetric_decrypt( handle, alg, ciphertext, ciphertext_length, NULL, 0, plaintext, sizeof( plaintext ), &plaintext_length ); TEST_ASSERT( status == PSA_SUCCESS || ( ( usage & PSA_KEY_USAGE_ENCRYPT ) == 0 && ( status == PSA_ERROR_INVALID_ARGUMENT || status == PSA_ERROR_INVALID_PADDING ) ) ); } return( 1 ); exit: return( 0 ); } static int exercise_key_derivation_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; unsigned char label[16] = "This is a label."; size_t label_length = sizeof( label ); unsigned char seed[16] = "abcdefghijklmnop"; size_t seed_length = sizeof( seed ); unsigned char output[1]; if( usage & PSA_KEY_USAGE_DERIVE ) { if( PSA_ALG_IS_HKDF( alg ) ) { PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) ); PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_SALT, label, label_length ) ); PSA_ASSERT( psa_key_derivation_input_key( &operation, PSA_KEY_DERIVATION_INPUT_SECRET, handle ) ); PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_INFO, seed, seed_length ) ); } #if defined(PSA_PRE_1_0_KEY_DERIVATION) else { // legacy PSA_ASSERT( psa_key_derivation( &operation, handle, alg, label, label_length, seed, seed_length, sizeof( output ) ) ); } #endif PSA_ASSERT( psa_key_derivation_output_bytes( &operation, output, sizeof( output ) ) ); PSA_ASSERT( psa_key_derivation_abort( &operation ) ); } return( 1 ); exit: return( 0 ); } /* We need two keys to exercise key agreement. Exercise the * private key against its own public key. */ static psa_status_t key_agreement_with_self( psa_key_derivation_operation_t *operation, psa_key_handle_t handle ) { psa_key_type_t private_key_type; psa_key_type_t public_key_type; size_t key_bits; uint8_t *public_key = NULL; size_t public_key_length; /* Return GENERIC_ERROR if something other than the final call to * psa_key_derivation_key_agreement fails. This isn't fully satisfactory, * but it's good enough: callers will report it as a failed test anyway. */ psa_status_t status = PSA_ERROR_GENERIC_ERROR; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); private_key_type = psa_get_key_type( &attributes ); key_bits = psa_get_key_bits( &attributes ); public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( private_key_type ); public_key_length = PSA_KEY_EXPORT_MAX_SIZE( public_key_type, key_bits ); ASSERT_ALLOC( public_key, public_key_length ); PSA_ASSERT( psa_export_public_key( handle, public_key, public_key_length, &public_key_length ) ); status = psa_key_derivation_key_agreement( operation, PSA_KEY_DERIVATION_INPUT_SECRET, handle, public_key, public_key_length ); exit: mbedtls_free( public_key ); psa_reset_key_attributes( &attributes ); return( status ); } /* We need two keys to exercise key agreement. Exercise the * private key against its own public key. */ static psa_status_t raw_key_agreement_with_self( psa_algorithm_t alg, psa_key_handle_t handle ) { psa_key_type_t private_key_type; psa_key_type_t public_key_type; size_t key_bits; uint8_t *public_key = NULL; size_t public_key_length; uint8_t output[1024]; size_t output_length; /* Return GENERIC_ERROR if something other than the final call to * psa_key_derivation_key_agreement fails. This isn't fully satisfactory, * but it's good enough: callers will report it as a failed test anyway. */ psa_status_t status = PSA_ERROR_GENERIC_ERROR; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); private_key_type = psa_get_key_type( &attributes ); key_bits = psa_get_key_bits( &attributes ); public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( private_key_type ); public_key_length = PSA_KEY_EXPORT_MAX_SIZE( public_key_type, key_bits ); ASSERT_ALLOC( public_key, public_key_length ); PSA_ASSERT( psa_export_public_key( handle, public_key, public_key_length, &public_key_length ) ); status = psa_raw_key_agreement( alg, handle, public_key, public_key_length, output, sizeof( output ), &output_length ); exit: mbedtls_free( public_key ); psa_reset_key_attributes( &attributes ); return( status ); } static int exercise_raw_key_agreement_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { int ok = 0; if( usage & PSA_KEY_USAGE_DERIVE ) { /* We need two keys to exercise key agreement. Exercise the * private key against its own public key. */ PSA_ASSERT( raw_key_agreement_with_self( alg, handle ) ); } ok = 1; exit: return( ok ); } static int exercise_key_agreement_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; unsigned char output[1]; int ok = 0; if( usage & PSA_KEY_USAGE_DERIVE ) { /* We need two keys to exercise key agreement. Exercise the * private key against its own public key. */ PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) ); PSA_ASSERT( key_agreement_with_self( &operation, handle ) ); PSA_ASSERT( psa_key_derivation_output_bytes( &operation, output, sizeof( output ) ) ); PSA_ASSERT( psa_key_derivation_abort( &operation ) ); } ok = 1; exit: return( ok ); } static int asn1_skip_integer( unsigned char **p, const unsigned char *end, size_t min_bits, size_t max_bits, int must_be_odd ) { size_t len; size_t actual_bits; unsigned char msb; TEST_EQUAL( mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ), 0 ); /* Tolerate a slight departure from DER encoding: * - 0 may be represented by an empty string or a 1-byte string. * - The sign bit may be used as a value bit. */ if( ( len == 1 && ( *p )[0] == 0 ) || ( len > 1 && ( *p )[0] == 0 && ( ( *p )[1] & 0x80 ) != 0 ) ) { ++( *p ); --len; } if( min_bits == 0 && len == 0 ) return( 1 ); msb = ( *p )[0]; TEST_ASSERT( msb != 0 ); actual_bits = 8 * ( len - 1 ); while( msb != 0 ) { msb >>= 1; ++actual_bits; } TEST_ASSERT( actual_bits >= min_bits ); TEST_ASSERT( actual_bits <= max_bits ); if( must_be_odd ) TEST_ASSERT( ( ( *p )[len-1] & 1 ) != 0 ); *p += len; return( 1 ); exit: return( 0 ); } static int exported_key_sanity_check( psa_key_type_t type, size_t bits, uint8_t *exported, size_t exported_length ) { if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) ) TEST_EQUAL( exported_length, ( bits + 7 ) / 8 ); else TEST_ASSERT( exported_length <= PSA_KEY_EXPORT_MAX_SIZE( type, bits ) ); #if defined(MBEDTLS_DES_C) if( type == PSA_KEY_TYPE_DES ) { /* Check the parity bits. */ unsigned i; for( i = 0; i < bits / 8; i++ ) { unsigned bit_count = 0; unsigned m; for( m = 1; m <= 0x100; m <<= 1 ) { if( exported[i] & m ) ++bit_count; } TEST_ASSERT( bit_count % 2 != 0 ); } } else #endif #if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PK_PARSE_C) if( type == PSA_KEY_TYPE_RSA_KEY_PAIR ) { uint8_t *p = exported; uint8_t *end = exported + exported_length; size_t len; /* RSAPrivateKey ::= SEQUENCE { * version INTEGER, -- must be 0 * modulus INTEGER, -- n * publicExponent INTEGER, -- e * privateExponent INTEGER, -- d * prime1 INTEGER, -- p * prime2 INTEGER, -- q * exponent1 INTEGER, -- d mod (p-1) * exponent2 INTEGER, -- d mod (q-1) * coefficient INTEGER, -- (inverse of q) mod p * } */ TEST_EQUAL( mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ), 0 ); TEST_EQUAL( p + len, end ); if( ! asn1_skip_integer( &p, end, 0, 0, 0 ) ) goto exit; if( ! asn1_skip_integer( &p, end, bits, bits, 1 ) ) goto exit; if( ! asn1_skip_integer( &p, end, 2, bits, 1 ) ) goto exit; /* Require d to be at least half the size of n. */ if( ! asn1_skip_integer( &p, end, bits / 2, bits, 1 ) ) goto exit; /* Require p and q to be at most half the size of n, rounded up. */ if( ! asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) ) goto exit; if( ! asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) ) goto exit; if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) ) goto exit; if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) ) goto exit; if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) ) goto exit; TEST_EQUAL( p, end ); } else #endif /* MBEDTLS_RSA_C */ #if defined(MBEDTLS_ECP_C) if( PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ) ) { /* Just the secret value */ TEST_EQUAL( exported_length, PSA_BITS_TO_BYTES( bits ) ); } else #endif /* MBEDTLS_ECP_C */ if( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ) { uint8_t *p = exported; uint8_t *end = exported + exported_length; size_t len; #if defined(MBEDTLS_RSA_C) if( type == PSA_KEY_TYPE_RSA_PUBLIC_KEY ) { /* RSAPublicKey ::= SEQUENCE { * modulus INTEGER, -- n * publicExponent INTEGER } -- e */ TEST_EQUAL( mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ), 0 ); TEST_EQUAL( p + len, end ); if( ! asn1_skip_integer( &p, end, bits, bits, 1 ) ) goto exit; if( ! asn1_skip_integer( &p, end, 2, bits, 1 ) ) goto exit; TEST_EQUAL( p, end ); } else #endif /* MBEDTLS_RSA_C */ #if defined(MBEDTLS_ECP_C) if( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( type ) ) { /* The representation of an ECC public key is: * - The byte 0x04; * - `x_P` as a `ceiling(m/8)`-byte string, big-endian; * - `y_P` as a `ceiling(m/8)`-byte string, big-endian; * - where m is the bit size associated with the curve. */ TEST_EQUAL( p + 1 + 2 * PSA_BITS_TO_BYTES( bits ), end ); TEST_EQUAL( p[0], 4 ); } else #endif /* MBEDTLS_ECP_C */ { char message[47]; mbedtls_snprintf( message, sizeof( message ), "No sanity check for public key type=0x%08lx", (unsigned long) type ); test_fail( message, __LINE__, __FILE__ ); return( 0 ); } } else { /* No sanity checks for other types */ } return( 1 ); exit: return( 0 ); } static int exercise_export_key( psa_key_handle_t handle, psa_key_usage_t usage ) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; uint8_t *exported = NULL; size_t exported_size = 0; size_t exported_length = 0; int ok = 0; PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); if( ( usage & PSA_KEY_USAGE_EXPORT ) == 0 && ! PSA_KEY_TYPE_IS_PUBLIC_KEY( psa_get_key_type( &attributes ) ) ) { TEST_EQUAL( psa_export_key( handle, NULL, 0, &exported_length ), PSA_ERROR_NOT_PERMITTED ); ok = 1; goto exit; } exported_size = PSA_KEY_EXPORT_MAX_SIZE( psa_get_key_type( &attributes ), psa_get_key_bits( &attributes ) ); ASSERT_ALLOC( exported, exported_size ); PSA_ASSERT( psa_export_key( handle, exported, exported_size, &exported_length ) ); ok = exported_key_sanity_check( psa_get_key_type( &attributes ), psa_get_key_bits( &attributes ), exported, exported_length ); exit: mbedtls_free( exported ); psa_reset_key_attributes( &attributes ); return( ok ); } static int exercise_export_public_key( psa_key_handle_t handle ) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t public_type; uint8_t *exported = NULL; size_t exported_size = 0; size_t exported_length = 0; int ok = 0; PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); if( ! PSA_KEY_TYPE_IS_ASYMMETRIC( psa_get_key_type( &attributes ) ) ) { TEST_EQUAL( psa_export_public_key( handle, NULL, 0, &exported_length ), PSA_ERROR_INVALID_ARGUMENT ); return( 1 ); } public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( psa_get_key_type( &attributes ) ); exported_size = PSA_KEY_EXPORT_MAX_SIZE( public_type, psa_get_key_bits( &attributes ) ); ASSERT_ALLOC( exported, exported_size ); PSA_ASSERT( psa_export_public_key( handle, exported, exported_size, &exported_length ) ); ok = exported_key_sanity_check( public_type, psa_get_key_bits( &attributes ), exported, exported_length ); exit: mbedtls_free( exported ); psa_reset_key_attributes( &attributes ); return( ok ); } /** Do smoke tests on a key. * * Perform one of each operation indicated by \p alg (decrypt/encrypt, * sign/verify, or derivation) that is permitted according to \p usage. * \p usage and \p alg should correspond to the expected policy on the * key. * * Export the key if permitted by \p usage, and check that the output * looks sensible. If \p usage forbids export, check that * \p psa_export_key correctly rejects the attempt. If the key is * asymmetric, also check \p psa_export_public_key. * * If the key fails the tests, this function calls the test framework's * `test_fail` function and returns false. Otherwise this function returns * true. Therefore it should be used as follows: * ``` * if( ! exercise_key( ... ) ) goto exit; * ``` * * \param handle The key to exercise. It should be capable of performing * \p alg. * \param usage The usage flags to assume. * \param alg The algorithm to exercise. * * \retval 0 The key failed the smoke tests. * \retval 1 The key passed the smoke tests. */ static int exercise_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { int ok; if( alg == 0 ) ok = 1; /* If no algorihm, do nothing (used for raw data "keys"). */ else if( PSA_ALG_IS_MAC( alg ) ) ok = exercise_mac_key( handle, usage, alg ); else if( PSA_ALG_IS_CIPHER( alg ) ) ok = exercise_cipher_key( handle, usage, alg ); else if( PSA_ALG_IS_AEAD( alg ) ) ok = exercise_aead_key( handle, usage, alg ); else if( PSA_ALG_IS_SIGN( alg ) ) ok = exercise_signature_key( handle, usage, alg ); else if( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) ) ok = exercise_asymmetric_encryption_key( handle, usage, alg ); else if( PSA_ALG_IS_KEY_DERIVATION( alg ) ) ok = exercise_key_derivation_key( handle, usage, alg ); else if( PSA_ALG_IS_RAW_KEY_AGREEMENT( alg ) ) ok = exercise_raw_key_agreement_key( handle, usage, alg ); else if( PSA_ALG_IS_KEY_AGREEMENT( alg ) ) ok = exercise_key_agreement_key( handle, usage, alg ); else { char message[40]; mbedtls_snprintf( message, sizeof( message ), "No code to exercise alg=0x%08lx", (unsigned long) alg ); test_fail( message, __LINE__, __FILE__ ); ok = 0; } ok = ok && exercise_export_key( handle, usage ); ok = ok && exercise_export_public_key( handle ); return( ok ); } static psa_key_usage_t usage_to_exercise( psa_key_type_t type, psa_algorithm_t alg ) { if( PSA_ALG_IS_MAC( alg ) || PSA_ALG_IS_SIGN( alg ) ) { return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ? PSA_KEY_USAGE_VERIFY : PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY ); } else if( PSA_ALG_IS_CIPHER( alg ) || PSA_ALG_IS_AEAD( alg ) || PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) ) { return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ); } else if( PSA_ALG_IS_KEY_DERIVATION( alg ) || PSA_ALG_IS_KEY_AGREEMENT( alg ) ) { return( PSA_KEY_USAGE_DERIVE ); } else { return( 0 ); } } static int test_operations_on_invalid_handle( psa_key_handle_t handle ) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; uint8_t buffer[1]; size_t length; int ok = 0; psa_set_key_id( &attributes, 0x6964 ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); psa_set_key_algorithm( &attributes, PSA_ALG_CTR ); psa_set_key_type( &attributes, PSA_KEY_TYPE_AES ); TEST_EQUAL( psa_get_key_attributes( handle, &attributes ), PSA_ERROR_INVALID_HANDLE ); TEST_EQUAL( psa_get_key_id( &attributes ), 0 ); TEST_EQUAL( psa_get_key_lifetime( &attributes ), 0 ); TEST_EQUAL( psa_get_key_usage_flags( &attributes ), 0 ); TEST_EQUAL( psa_get_key_algorithm( &attributes ), 0 ); TEST_EQUAL( psa_get_key_type( &attributes ), 0 ); TEST_EQUAL( psa_get_key_bits( &attributes ), 0 ); TEST_EQUAL( psa_export_key( handle, buffer, sizeof( buffer ), &length ), PSA_ERROR_INVALID_HANDLE ); TEST_EQUAL( psa_export_public_key( handle, buffer, sizeof( buffer ), &length ), PSA_ERROR_INVALID_HANDLE ); TEST_EQUAL( psa_close_key( handle ), PSA_ERROR_INVALID_HANDLE ); TEST_EQUAL( psa_destroy_key( handle ), PSA_ERROR_INVALID_HANDLE ); ok = 1; exit: psa_reset_key_attributes( &attributes ); return( ok ); } /* An overapproximation of the amount of storage needed for a key of the * given type and with the given content. The API doesn't make it easy * to find a good value for the size. The current implementation doesn't * care about the value anyway. */ #define KEY_BITS_FROM_DATA( type, data ) \ ( data )->len typedef enum { IMPORT_KEY = 0, GENERATE_KEY = 1, DERIVE_KEY = 2 } generate_method; /* END_HEADER */ /* BEGIN_DEPENDENCIES * depends_on:MBEDTLS_PSA_CRYPTO_C * END_DEPENDENCIES */ /* BEGIN_CASE */ void static_checks( ) { size_t max_truncated_mac_size = PSA_ALG_MAC_TRUNCATION_MASK >> PSA_MAC_TRUNCATION_OFFSET; /* Check that the length for a truncated MAC always fits in the algorithm * encoding. The shifted mask is the maximum truncated value. The * untruncated algorithm may be one byte larger. */ TEST_ASSERT( PSA_MAC_MAX_SIZE <= 1 + max_truncated_mac_size ); } /* END_CASE */ /* BEGIN_CASE */ void attributes_set_get( int id_arg, int lifetime_arg, int usage_flags_arg, int alg_arg, int type_arg, int bits_arg ) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_id_t id = id_arg; psa_key_lifetime_t lifetime = lifetime_arg; psa_key_usage_t usage_flags = usage_flags_arg; psa_algorithm_t alg = alg_arg; psa_key_type_t type = type_arg; size_t bits = bits_arg; TEST_EQUAL( psa_get_key_id( &attributes ), 0 ); TEST_EQUAL( psa_get_key_lifetime( &attributes ), 0 ); TEST_EQUAL( psa_get_key_usage_flags( &attributes ), 0 ); TEST_EQUAL( psa_get_key_algorithm( &attributes ), 0 ); TEST_EQUAL( psa_get_key_type( &attributes ), 0 ); TEST_EQUAL( psa_get_key_bits( &attributes ), 0 ); psa_set_key_id( &attributes, id ); psa_set_key_lifetime( &attributes, lifetime ); psa_set_key_usage_flags( &attributes, usage_flags ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, type ); psa_set_key_bits( &attributes, bits ); TEST_EQUAL( psa_get_key_id( &attributes ), id ); TEST_EQUAL( psa_get_key_lifetime( &attributes ), lifetime ); TEST_EQUAL( psa_get_key_usage_flags( &attributes ), usage_flags ); TEST_EQUAL( psa_get_key_algorithm( &attributes ), alg ); TEST_EQUAL( psa_get_key_type( &attributes ), type ); TEST_EQUAL( psa_get_key_bits( &attributes ), bits ); psa_reset_key_attributes( &attributes ); TEST_EQUAL( psa_get_key_id( &attributes ), 0 ); TEST_EQUAL( psa_get_key_lifetime( &attributes ), 0 ); TEST_EQUAL( psa_get_key_usage_flags( &attributes ), 0 ); TEST_EQUAL( psa_get_key_algorithm( &attributes ), 0 ); TEST_EQUAL( psa_get_key_type( &attributes ), 0 ); TEST_EQUAL( psa_get_key_bits( &attributes ), 0 ); } /* END_CASE */ /* BEGIN_CASE */ void persistence_attributes( int id1_arg, int lifetime_arg, int id2_arg, int expected_id_arg, int expected_lifetime_arg ) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_id_t id1 = id1_arg; psa_key_lifetime_t lifetime = lifetime_arg; psa_key_id_t id2 = id2_arg; psa_key_id_t expected_id = expected_id_arg; psa_key_lifetime_t expected_lifetime = expected_lifetime_arg; if( id1_arg != -1 ) psa_set_key_id( &attributes, id1 ); if( lifetime_arg != -1 ) psa_set_key_lifetime( &attributes, lifetime ); if( id2_arg != -1 ) psa_set_key_id( &attributes, id2 ); TEST_EQUAL( psa_get_key_id( &attributes ), expected_id ); TEST_EQUAL( psa_get_key_lifetime( &attributes ), expected_lifetime ); } /* END_CASE */ /* BEGIN_CASE */ void import( data_t *data, int type_arg, int attr_bits_arg, int expected_status_arg ) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_handle_t handle = 0; psa_key_type_t type = type_arg; size_t attr_bits = attr_bits_arg; psa_status_t expected_status = expected_status_arg; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_type( &attributes, type ); psa_set_key_bits( &attributes, attr_bits ); status = psa_import_key( &attributes, data->x, data->len, &handle ); TEST_EQUAL( status, expected_status ); if( status != PSA_SUCCESS ) goto exit; PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) ); TEST_EQUAL( psa_get_key_type( &got_attributes ), type ); if( attr_bits != 0 ) TEST_EQUAL( attr_bits, got_attributes.bits ); PSA_ASSERT( psa_destroy_key( handle ) ); test_operations_on_invalid_handle( handle ); exit: psa_destroy_key( handle ); psa_reset_key_attributes( &got_attributes ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void import_rsa_made_up( int bits_arg, int keypair, int expected_status_arg ) { psa_key_handle_t handle = 0; size_t bits = bits_arg; psa_status_t expected_status = expected_status_arg; psa_status_t status; psa_key_type_t type = keypair ? PSA_KEY_TYPE_RSA_KEY_PAIR : PSA_KEY_TYPE_RSA_PUBLIC_KEY; size_t buffer_size = /* Slight overapproximations */ keypair ? bits * 9 / 16 + 80 : bits / 8 + 20; unsigned char *buffer = NULL; unsigned char *p; int ret; size_t length; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); ASSERT_ALLOC( buffer, buffer_size ); TEST_ASSERT( ( ret = construct_fake_rsa_key( buffer, buffer_size, &p, bits, keypair ) ) >= 0 ); length = ret; /* Try importing the key */ psa_set_key_type( &attributes, type ); status = psa_import_key( &attributes, p, length, &handle ); TEST_EQUAL( status, expected_status ); if( status == PSA_SUCCESS ) PSA_ASSERT( psa_destroy_key( handle ) ); exit: mbedtls_free( buffer ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void import_export( data_t *data, int type_arg, int usage_arg, int alg_arg, int expected_bits, int export_size_delta, int expected_export_status_arg, int canonical_input ) { psa_key_handle_t handle = 0; psa_key_type_t type = type_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_export_status = expected_export_status_arg; psa_status_t status; unsigned char *exported = NULL; unsigned char *reexported = NULL; size_t export_size; size_t exported_length = INVALID_EXPORT_LENGTH; size_t reexported_length; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; export_size = (ptrdiff_t) data->len + export_size_delta; ASSERT_ALLOC( exported, export_size ); if( ! canonical_input ) ASSERT_ALLOC( reexported, export_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, usage_arg ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, type ); /* Import the key */ PSA_ASSERT( psa_import_key( &attributes, data->x, data->len, &handle ) ); /* Test the key information */ PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) ); TEST_EQUAL( psa_get_key_type( &got_attributes ), type ); TEST_EQUAL( psa_get_key_bits( &got_attributes ), (size_t) expected_bits ); /* Export the key */ status = psa_export_key( handle, exported, export_size, &exported_length ); TEST_EQUAL( status, expected_export_status ); /* The exported length must be set by psa_export_key() to a value between 0 * and export_size. On errors, the exported length must be 0. */ TEST_ASSERT( exported_length != INVALID_EXPORT_LENGTH ); TEST_ASSERT( status == PSA_SUCCESS || exported_length == 0 ); TEST_ASSERT( exported_length <= export_size ); TEST_ASSERT( mem_is_char( exported + exported_length, 0, export_size - exported_length ) ); if( status != PSA_SUCCESS ) { TEST_EQUAL( exported_length, 0 ); goto destroy; } if( ! exercise_export_key( handle, usage_arg ) ) goto exit; if( canonical_input ) ASSERT_COMPARE( data->x, data->len, exported, exported_length ); else { psa_key_handle_t handle2; PSA_ASSERT( psa_import_key( &attributes, exported, exported_length, &handle2 ) ); PSA_ASSERT( psa_export_key( handle2, reexported, export_size, &reexported_length ) ); ASSERT_COMPARE( exported, exported_length, reexported, reexported_length ); PSA_ASSERT( psa_close_key( handle2 ) ); } TEST_ASSERT( exported_length <= PSA_KEY_EXPORT_MAX_SIZE( type, psa_get_key_bits( &got_attributes ) ) ); destroy: /* Destroy the key */ PSA_ASSERT( psa_destroy_key( handle ) ); test_operations_on_invalid_handle( handle ); exit: mbedtls_free( exported ); mbedtls_free( reexported ); psa_reset_key_attributes( &got_attributes ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void invalid_handle( int handle ) { PSA_ASSERT( psa_crypto_init( ) ); test_operations_on_invalid_handle( handle ); exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void import_export_public_key( data_t *data, int type_arg, int alg_arg, int export_size_delta, int expected_export_status_arg, data_t *expected_public_key ) { psa_key_handle_t handle = 0; psa_key_type_t type = type_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_export_status = expected_export_status_arg; psa_status_t status; unsigned char *exported = NULL; size_t export_size = expected_public_key->len + export_size_delta; size_t exported_length = INVALID_EXPORT_LENGTH; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, type ); /* Import the key */ PSA_ASSERT( psa_import_key( &attributes, data->x, data->len, &handle ) ); /* Export the public key */ ASSERT_ALLOC( exported, export_size ); status = psa_export_public_key( handle, exported, export_size, &exported_length ); TEST_EQUAL( status, expected_export_status ); if( status == PSA_SUCCESS ) { psa_key_type_t public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( type ); size_t bits; PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); bits = psa_get_key_bits( &attributes ); TEST_ASSERT( expected_public_key->len <= PSA_KEY_EXPORT_MAX_SIZE( public_type, bits ) ); ASSERT_COMPARE( expected_public_key->x, expected_public_key->len, exported, exported_length ); } exit: mbedtls_free( exported ); psa_destroy_key( handle ); psa_reset_key_attributes( &attributes ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void import_and_exercise_key( data_t *data, int type_arg, int bits_arg, int alg_arg ) { psa_key_handle_t handle = 0; psa_key_type_t type = type_arg; size_t bits = bits_arg; psa_algorithm_t alg = alg_arg; psa_key_usage_t usage = usage_to_exercise( type, alg ); psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, usage ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, type ); /* Import the key */ PSA_ASSERT( psa_import_key( &attributes, data->x, data->len, &handle ) ); /* Test the key information */ PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) ); TEST_EQUAL( psa_get_key_type( &got_attributes ), type ); TEST_EQUAL( psa_get_key_bits( &got_attributes ), bits ); /* Do something with the key according to its type and permitted usage. */ if( ! exercise_key( handle, usage, alg ) ) goto exit; PSA_ASSERT( psa_destroy_key( handle ) ); test_operations_on_invalid_handle( handle ); exit: psa_destroy_key( handle ); psa_reset_key_attributes( &got_attributes ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void key_policy( int usage_arg, int alg_arg ) { psa_key_handle_t handle = 0; psa_algorithm_t alg = alg_arg; psa_key_usage_t usage = usage_arg; psa_key_type_t key_type = PSA_KEY_TYPE_AES; unsigned char key[32] = {0}; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; memset( key, 0x2a, sizeof( key ) ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, usage ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key, sizeof( key ), &handle ) ); PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); TEST_EQUAL( psa_get_key_type( &attributes ), key_type ); TEST_EQUAL( psa_get_key_usage_flags( &attributes ), usage ); TEST_EQUAL( psa_get_key_algorithm( &attributes ), alg ); exit: psa_destroy_key( handle ); psa_reset_key_attributes( &attributes ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void key_attributes_init( ) { /* Test each valid way of initializing the object, except for `= {0}`, as * Clang 5 complains when `-Wmissing-field-initializers` is used, even * though it's OK by the C standard. We could test for this, but we'd need * to supress the Clang warning for the test. */ psa_key_attributes_t func = psa_key_attributes_init( ); psa_key_attributes_t init = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t zero; memset( &zero, 0, sizeof( zero ) ); TEST_EQUAL( psa_get_key_lifetime( &func ), PSA_KEY_LIFETIME_VOLATILE ); TEST_EQUAL( psa_get_key_lifetime( &init ), PSA_KEY_LIFETIME_VOLATILE ); TEST_EQUAL( psa_get_key_lifetime( &zero ), PSA_KEY_LIFETIME_VOLATILE ); TEST_EQUAL( psa_get_key_type( &func ), 0 ); TEST_EQUAL( psa_get_key_type( &init ), 0 ); TEST_EQUAL( psa_get_key_type( &zero ), 0 ); TEST_EQUAL( psa_get_key_bits( &func ), 0 ); TEST_EQUAL( psa_get_key_bits( &init ), 0 ); TEST_EQUAL( psa_get_key_bits( &zero ), 0 ); TEST_EQUAL( psa_get_key_usage_flags( &func ), 0 ); TEST_EQUAL( psa_get_key_usage_flags( &init ), 0 ); TEST_EQUAL( psa_get_key_usage_flags( &zero ), 0 ); TEST_EQUAL( psa_get_key_algorithm( &func ), 0 ); TEST_EQUAL( psa_get_key_algorithm( &init ), 0 ); TEST_EQUAL( psa_get_key_algorithm( &zero ), 0 ); } /* END_CASE */ /* BEGIN_CASE */ void mac_key_policy( int policy_usage, int policy_alg, int key_type, data_t *key_data, int exercise_alg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_status_t status; unsigned char mac[PSA_MAC_MAX_SIZE]; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); status = psa_mac_sign_setup( &operation, handle, exercise_alg ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_SIGN ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); psa_mac_abort( &operation ); memset( mac, 0, sizeof( mac ) ); status = psa_mac_verify_setup( &operation, handle, exercise_alg ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_VERIFY ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_mac_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_key_policy( int policy_usage, int policy_alg, int key_type, data_t *key_data, int exercise_alg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); status = psa_cipher_encrypt_setup( &operation, handle, exercise_alg ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_ENCRYPT ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); psa_cipher_abort( &operation ); status = psa_cipher_decrypt_setup( &operation, handle, exercise_alg ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_DECRYPT ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_cipher_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void aead_key_policy( int policy_usage, int policy_alg, int key_type, data_t *key_data, int nonce_length_arg, int tag_length_arg, int exercise_alg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; unsigned char nonce[16] = {0}; size_t nonce_length = nonce_length_arg; unsigned char tag[16]; size_t tag_length = tag_length_arg; size_t output_length; TEST_ASSERT( nonce_length <= sizeof( nonce ) ); TEST_ASSERT( tag_length <= sizeof( tag ) ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); status = psa_aead_encrypt( handle, exercise_alg, nonce, nonce_length, NULL, 0, NULL, 0, tag, tag_length, &output_length ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_ENCRYPT ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); memset( tag, 0, sizeof( tag ) ); status = psa_aead_decrypt( handle, exercise_alg, nonce, nonce_length, NULL, 0, tag, tag_length, NULL, 0, &output_length ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_DECRYPT ) != 0 ) TEST_EQUAL( status, PSA_ERROR_INVALID_SIGNATURE ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_encryption_key_policy( int policy_usage, int policy_alg, int key_type, data_t *key_data, int exercise_alg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; size_t key_bits; size_t buffer_length; unsigned char *buffer = NULL; size_t output_length; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); key_bits = psa_get_key_bits( &attributes ); buffer_length = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE( key_type, key_bits, exercise_alg ); ASSERT_ALLOC( buffer, buffer_length ); status = psa_asymmetric_encrypt( handle, exercise_alg, NULL, 0, NULL, 0, buffer, buffer_length, &output_length ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_ENCRYPT ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); if( buffer_length != 0 ) memset( buffer, 0, buffer_length ); status = psa_asymmetric_decrypt( handle, exercise_alg, buffer, buffer_length, NULL, 0, buffer, buffer_length, &output_length ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_DECRYPT ) != 0 ) TEST_EQUAL( status, PSA_ERROR_INVALID_PADDING ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_destroy_key( handle ); psa_reset_key_attributes( &attributes ); PSA_DONE( ); mbedtls_free( buffer ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_signature_key_policy( int policy_usage, int policy_alg, int key_type, data_t *key_data, int exercise_alg, int payload_length_arg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; unsigned char payload[PSA_HASH_MAX_SIZE] = {1}; /* If `payload_length_arg > 0`, `exercise_alg` is supposed to be * compatible with the policy and `payload_length_arg` is supposed to be * a valid input length to sign. If `payload_length_arg <= 0`, * `exercise_alg` is supposed to be forbidden by the policy. */ int compatible_alg = payload_length_arg > 0; size_t payload_length = compatible_alg ? payload_length_arg : 0; unsigned char signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0}; size_t signature_length; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); status = psa_asymmetric_sign( handle, exercise_alg, payload, payload_length, signature, sizeof( signature ), &signature_length ); if( compatible_alg && ( policy_usage & PSA_KEY_USAGE_SIGN ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); memset( signature, 0, sizeof( signature ) ); status = psa_asymmetric_verify( handle, exercise_alg, payload, payload_length, signature, sizeof( signature ) ); if( compatible_alg && ( policy_usage & PSA_KEY_USAGE_VERIFY ) != 0 ) TEST_EQUAL( status, PSA_ERROR_INVALID_SIGNATURE ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:PSA_PRE_1_0_KEY_DERIVATION */ void derive_key_policy( int policy_usage, int policy_alg, int key_type, data_t *key_data, int exercise_alg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); status = psa_key_derivation( &operation, handle, exercise_alg, NULL, 0, NULL, 0, 1 ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_DERIVE ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_key_derivation_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void agreement_key_policy( int policy_usage, int policy_alg, int key_type_arg, data_t *key_data, int exercise_alg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t key_type = key_type_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_key_derivation_setup( &operation, exercise_alg ) ); status = key_agreement_with_self( &operation, handle ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_DERIVE ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_key_derivation_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void key_policy_alg2( int key_type_arg, data_t *key_data, int usage_arg, int alg_arg, int alg2_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_usage_t usage = usage_arg; psa_algorithm_t alg = alg_arg; psa_algorithm_t alg2 = alg2_arg; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, usage ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_enrollment_algorithm( &attributes, alg2 ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) ); TEST_EQUAL( psa_get_key_usage_flags( &got_attributes ), usage ); TEST_EQUAL( psa_get_key_algorithm( &got_attributes ), alg ); TEST_EQUAL( psa_get_key_enrollment_algorithm( &got_attributes ), alg2 ); if( ! exercise_key( handle, usage, alg ) ) goto exit; if( ! exercise_key( handle, usage, alg2 ) ) goto exit; exit: psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void raw_agreement_key_policy( int policy_usage, int policy_alg, int key_type_arg, data_t *key_data, int exercise_alg ) { psa_key_handle_t handle = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t key_type = key_type_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, policy_usage ); psa_set_key_algorithm( &attributes, policy_alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); status = raw_key_agreement_with_self( exercise_alg, handle ); if( policy_alg == exercise_alg && ( policy_usage & PSA_KEY_USAGE_DERIVE ) != 0 ) PSA_ASSERT( status ); else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); exit: psa_key_derivation_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void copy_success( int source_usage_arg, int source_alg_arg, int source_alg2_arg, int type_arg, data_t *material, int copy_attributes, int target_usage_arg, int target_alg_arg, int target_alg2_arg, int expected_usage_arg, int expected_alg_arg, int expected_alg2_arg ) { psa_key_attributes_t source_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t target_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_usage_t expected_usage = expected_usage_arg; psa_algorithm_t expected_alg = expected_alg_arg; psa_algorithm_t expected_alg2 = expected_alg2_arg; psa_key_handle_t source_handle = 0; psa_key_handle_t target_handle = 0; uint8_t *export_buffer = NULL; PSA_ASSERT( psa_crypto_init( ) ); /* Prepare the source key. */ psa_set_key_usage_flags( &source_attributes, source_usage_arg ); psa_set_key_algorithm( &source_attributes, source_alg_arg ); psa_set_key_enrollment_algorithm( &source_attributes, source_alg2_arg ); psa_set_key_type( &source_attributes, type_arg ); PSA_ASSERT( psa_import_key( &source_attributes, material->x, material->len, &source_handle ) ); PSA_ASSERT( psa_get_key_attributes( source_handle, &source_attributes ) ); /* Prepare the target attributes. */ if( copy_attributes ) target_attributes = source_attributes; if( target_usage_arg != -1 ) psa_set_key_usage_flags( &target_attributes, target_usage_arg ); if( target_alg_arg != -1 ) psa_set_key_algorithm( &target_attributes, target_alg_arg ); if( target_alg2_arg != -1 ) psa_set_key_enrollment_algorithm( &target_attributes, target_alg2_arg ); /* Copy the key. */ PSA_ASSERT( psa_copy_key( source_handle, &target_attributes, &target_handle ) ); /* Destroy the source to ensure that this doesn't affect the target. */ PSA_ASSERT( psa_destroy_key( source_handle ) ); /* Test that the target slot has the expected content and policy. */ PSA_ASSERT( psa_get_key_attributes( target_handle, &target_attributes ) ); TEST_EQUAL( psa_get_key_type( &source_attributes ), psa_get_key_type( &target_attributes ) ); TEST_EQUAL( psa_get_key_bits( &source_attributes ), psa_get_key_bits( &target_attributes ) ); TEST_EQUAL( expected_usage, psa_get_key_usage_flags( &target_attributes ) ); TEST_EQUAL( expected_alg, psa_get_key_algorithm( &target_attributes ) ); TEST_EQUAL( expected_alg2, psa_get_key_enrollment_algorithm( &target_attributes ) ); if( expected_usage & PSA_KEY_USAGE_EXPORT ) { size_t length; ASSERT_ALLOC( export_buffer, material->len ); PSA_ASSERT( psa_export_key( target_handle, export_buffer, material->len, &length ) ); ASSERT_COMPARE( material->x, material->len, export_buffer, length ); } if( ! exercise_key( target_handle, expected_usage, expected_alg ) ) goto exit; if( ! exercise_key( target_handle, expected_usage, expected_alg2 ) ) goto exit; PSA_ASSERT( psa_close_key( target_handle ) ); exit: psa_reset_key_attributes( &source_attributes ); psa_reset_key_attributes( &target_attributes ); PSA_DONE( ); mbedtls_free( export_buffer ); } /* END_CASE */ /* BEGIN_CASE */ void copy_fail( int source_usage_arg, int source_alg_arg, int source_alg2_arg, int type_arg, data_t *material, int target_type_arg, int target_bits_arg, int target_usage_arg, int target_alg_arg, int target_alg2_arg, int expected_status_arg ) { psa_key_attributes_t source_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t target_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_handle_t source_handle = 0; psa_key_handle_t target_handle = 0; PSA_ASSERT( psa_crypto_init( ) ); /* Prepare the source key. */ psa_set_key_usage_flags( &source_attributes, source_usage_arg ); psa_set_key_algorithm( &source_attributes, source_alg_arg ); psa_set_key_enrollment_algorithm( &source_attributes, source_alg2_arg ); psa_set_key_type( &source_attributes, type_arg ); PSA_ASSERT( psa_import_key( &source_attributes, material->x, material->len, &source_handle ) ); /* Prepare the target attributes. */ psa_set_key_type( &target_attributes, target_type_arg ); psa_set_key_bits( &target_attributes, target_bits_arg ); psa_set_key_usage_flags( &target_attributes, target_usage_arg ); psa_set_key_algorithm( &target_attributes, target_alg_arg ); psa_set_key_enrollment_algorithm( &target_attributes, target_alg2_arg ); /* Try to copy the key. */ TEST_EQUAL( psa_copy_key( source_handle, &target_attributes, &target_handle ), expected_status_arg ); PSA_ASSERT( psa_destroy_key( source_handle ) ); exit: psa_reset_key_attributes( &source_attributes ); psa_reset_key_attributes( &target_attributes ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void hash_operation_init( ) { const uint8_t input[1] = { 0 }; /* Test each valid way of initializing the object, except for `= {0}`, as * Clang 5 complains when `-Wmissing-field-initializers` is used, even * though it's OK by the C standard. We could test for this, but we'd need * to supress the Clang warning for the test. */ psa_hash_operation_t func = psa_hash_operation_init( ); psa_hash_operation_t init = PSA_HASH_OPERATION_INIT; psa_hash_operation_t zero; memset( &zero, 0, sizeof( zero ) ); /* A freshly-initialized hash operation should not be usable. */ TEST_EQUAL( psa_hash_update( &func, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_hash_update( &init, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_hash_update( &zero, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); /* A default hash operation should be abortable without error. */ PSA_ASSERT( psa_hash_abort( &func ) ); PSA_ASSERT( psa_hash_abort( &init ) ); PSA_ASSERT( psa_hash_abort( &zero ) ); } /* END_CASE */ /* BEGIN_CASE */ void hash_setup( int alg_arg, int expected_status_arg ) { psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); status = psa_hash_setup( &operation, alg ); TEST_EQUAL( status, expected_status ); /* Whether setup succeeded or failed, abort must succeed. */ PSA_ASSERT( psa_hash_abort( &operation ) ); /* If setup failed, reproduce the failure, so as to * test the resulting state of the operation object. */ if( status != PSA_SUCCESS ) TEST_EQUAL( psa_hash_setup( &operation, alg ), status ); /* Now the operation object should be reusable. */ #if defined(KNOWN_SUPPORTED_HASH_ALG) PSA_ASSERT( psa_hash_setup( &operation, KNOWN_SUPPORTED_HASH_ALG ) ); PSA_ASSERT( psa_hash_abort( &operation ) ); #endif exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void hash_bad_order( ) { psa_algorithm_t alg = PSA_ALG_SHA_256; unsigned char input[] = ""; /* SHA-256 hash of an empty string */ const unsigned char valid_hash[] = { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }; unsigned char hash[sizeof(valid_hash)] = { 0 }; size_t hash_len; psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; PSA_ASSERT( psa_crypto_init( ) ); /* Call setup twice in a row. */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); TEST_EQUAL( psa_hash_setup( &operation, alg ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call update without calling setup beforehand. */ TEST_EQUAL( psa_hash_update( &operation, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call update after finish. */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); PSA_ASSERT( psa_hash_finish( &operation, hash, sizeof( hash ), &hash_len ) ); TEST_EQUAL( psa_hash_update( &operation, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call verify without calling setup beforehand. */ TEST_EQUAL( psa_hash_verify( &operation, valid_hash, sizeof( valid_hash ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call verify after finish. */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); PSA_ASSERT( psa_hash_finish( &operation, hash, sizeof( hash ), &hash_len ) ); TEST_EQUAL( psa_hash_verify( &operation, valid_hash, sizeof( valid_hash ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call verify twice in a row. */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); PSA_ASSERT( psa_hash_verify( &operation, valid_hash, sizeof( valid_hash ) ) ); TEST_EQUAL( psa_hash_verify( &operation, valid_hash, sizeof( valid_hash ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call finish without calling setup beforehand. */ TEST_EQUAL( psa_hash_finish( &operation, hash, sizeof( hash ), &hash_len ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call finish twice in a row. */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); PSA_ASSERT( psa_hash_finish( &operation, hash, sizeof( hash ), &hash_len ) ); TEST_EQUAL( psa_hash_finish( &operation, hash, sizeof( hash ), &hash_len ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); /* Call finish after calling verify. */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); PSA_ASSERT( psa_hash_verify( &operation, valid_hash, sizeof( valid_hash ) ) ); TEST_EQUAL( psa_hash_finish( &operation, hash, sizeof( hash ), &hash_len ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_abort( &operation ) ); exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */ void hash_verify_bad_args( ) { psa_algorithm_t alg = PSA_ALG_SHA_256; /* SHA-256 hash of an empty string with 2 extra bytes (0xaa and 0xbb) * appended to it */ unsigned char hash[] = { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, 0xaa, 0xbb }; size_t expected_size = PSA_HASH_SIZE( alg ); psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; PSA_ASSERT( psa_crypto_init( ) ); /* psa_hash_verify with a smaller hash than expected */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); TEST_EQUAL( psa_hash_verify( &operation, hash, expected_size - 1 ), PSA_ERROR_INVALID_SIGNATURE ); /* psa_hash_verify with a non-matching hash */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); TEST_EQUAL( psa_hash_verify( &operation, hash + 1, expected_size ), PSA_ERROR_INVALID_SIGNATURE ); /* psa_hash_verify with a hash longer than expected */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); TEST_EQUAL( psa_hash_verify( &operation, hash, sizeof( hash ) ), PSA_ERROR_INVALID_SIGNATURE ); exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */ void hash_finish_bad_args( ) { psa_algorithm_t alg = PSA_ALG_SHA_256; unsigned char hash[PSA_HASH_MAX_SIZE]; size_t expected_size = PSA_HASH_SIZE( alg ); psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; size_t hash_len; PSA_ASSERT( psa_crypto_init( ) ); /* psa_hash_finish with a smaller hash buffer than expected */ PSA_ASSERT( psa_hash_setup( &operation, alg ) ); TEST_EQUAL( psa_hash_finish( &operation, hash, expected_size - 1, &hash_len ), PSA_ERROR_BUFFER_TOO_SMALL ); exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */ void hash_clone_source_state( ) { psa_algorithm_t alg = PSA_ALG_SHA_256; unsigned char hash[PSA_HASH_MAX_SIZE]; psa_hash_operation_t op_source = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_init = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_setup = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_finished = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_aborted = PSA_HASH_OPERATION_INIT; size_t hash_len; PSA_ASSERT( psa_crypto_init( ) ); PSA_ASSERT( psa_hash_setup( &op_source, alg ) ); PSA_ASSERT( psa_hash_setup( &op_setup, alg ) ); PSA_ASSERT( psa_hash_setup( &op_finished, alg ) ); PSA_ASSERT( psa_hash_finish( &op_finished, hash, sizeof( hash ), &hash_len ) ); PSA_ASSERT( psa_hash_setup( &op_aborted, alg ) ); PSA_ASSERT( psa_hash_abort( &op_aborted ) ); TEST_EQUAL( psa_hash_clone( &op_source, &op_setup ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_hash_clone( &op_source, &op_init ) ); PSA_ASSERT( psa_hash_finish( &op_init, hash, sizeof( hash ), &hash_len ) ); PSA_ASSERT( psa_hash_clone( &op_source, &op_finished ) ); PSA_ASSERT( psa_hash_finish( &op_finished, hash, sizeof( hash ), &hash_len ) ); PSA_ASSERT( psa_hash_clone( &op_source, &op_aborted ) ); PSA_ASSERT( psa_hash_finish( &op_aborted, hash, sizeof( hash ), &hash_len ) ); exit: psa_hash_abort( &op_source ); psa_hash_abort( &op_init ); psa_hash_abort( &op_setup ); psa_hash_abort( &op_finished ); psa_hash_abort( &op_aborted ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */ void hash_clone_target_state( ) { psa_algorithm_t alg = PSA_ALG_SHA_256; unsigned char hash[PSA_HASH_MAX_SIZE]; psa_hash_operation_t op_init = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_setup = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_finished = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_aborted = PSA_HASH_OPERATION_INIT; psa_hash_operation_t op_target = PSA_HASH_OPERATION_INIT; size_t hash_len; PSA_ASSERT( psa_crypto_init( ) ); PSA_ASSERT( psa_hash_setup( &op_setup, alg ) ); PSA_ASSERT( psa_hash_setup( &op_finished, alg ) ); PSA_ASSERT( psa_hash_finish( &op_finished, hash, sizeof( hash ), &hash_len ) ); PSA_ASSERT( psa_hash_setup( &op_aborted, alg ) ); PSA_ASSERT( psa_hash_abort( &op_aborted ) ); PSA_ASSERT( psa_hash_clone( &op_setup, &op_target ) ); PSA_ASSERT( psa_hash_finish( &op_target, hash, sizeof( hash ), &hash_len ) ); TEST_EQUAL( psa_hash_clone( &op_init, &op_target ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_hash_clone( &op_finished, &op_target ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_hash_clone( &op_aborted, &op_target ), PSA_ERROR_BAD_STATE ); exit: psa_hash_abort( &op_target ); psa_hash_abort( &op_init ); psa_hash_abort( &op_setup ); psa_hash_abort( &op_finished ); psa_hash_abort( &op_aborted ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void mac_operation_init( ) { const uint8_t input[1] = { 0 }; /* Test each valid way of initializing the object, except for `= {0}`, as * Clang 5 complains when `-Wmissing-field-initializers` is used, even * though it's OK by the C standard. We could test for this, but we'd need * to supress the Clang warning for the test. */ psa_mac_operation_t func = psa_mac_operation_init( ); psa_mac_operation_t init = PSA_MAC_OPERATION_INIT; psa_mac_operation_t zero; memset( &zero, 0, sizeof( zero ) ); /* A freshly-initialized MAC operation should not be usable. */ TEST_EQUAL( psa_mac_update( &func, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_mac_update( &init, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_mac_update( &zero, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); /* A default MAC operation should be abortable without error. */ PSA_ASSERT( psa_mac_abort( &func ) ); PSA_ASSERT( psa_mac_abort( &init ) ); PSA_ASSERT( psa_mac_abort( &zero ) ); } /* END_CASE */ /* BEGIN_CASE */ void mac_setup( int key_type_arg, data_t *key, int alg_arg, int expected_status_arg ) { psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_status_t status = PSA_ERROR_GENERIC_ERROR; #if defined(KNOWN_SUPPORTED_MAC_ALG) const uint8_t smoke_test_key_data[16] = "kkkkkkkkkkkkkkkk"; #endif PSA_ASSERT( psa_crypto_init( ) ); if( ! exercise_mac_setup( key_type, key->x, key->len, alg, &operation, &status ) ) goto exit; TEST_EQUAL( status, expected_status ); /* The operation object should be reusable. */ #if defined(KNOWN_SUPPORTED_MAC_ALG) if( ! exercise_mac_setup( KNOWN_SUPPORTED_MAC_KEY_TYPE, smoke_test_key_data, sizeof( smoke_test_key_data ), KNOWN_SUPPORTED_MAC_ALG, &operation, &status ) ) goto exit; TEST_EQUAL( status, PSA_SUCCESS ); #endif exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void mac_bad_order( ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = PSA_KEY_TYPE_HMAC; psa_algorithm_t alg = PSA_ALG_HMAC(PSA_ALG_SHA_256); const uint8_t key[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; uint8_t sign_mac[PSA_MAC_MAX_SIZE + 10] = { 0 }; size_t sign_mac_length = 0; const uint8_t input[] = { 0xbb, 0xbb, 0xbb, 0xbb }; const uint8_t verify_mac[] = { 0x74, 0x65, 0x93, 0x8c, 0xeb, 0x1d, 0xb3, 0x76, 0x5a, 0x38, 0xe7, 0xdd, 0x85, 0xc5, 0xad, 0x4f, 0x07, 0xe7, 0xd5, 0xb2, 0x64, 0xf0, 0x1a, 0x1a, 0x2c, 0xf9, 0x18, 0xca, 0x59, 0x7e, 0x5d, 0xf6 }; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key, sizeof( key ), &handle ) ); /* Call update without calling setup beforehand. */ TEST_EQUAL( psa_mac_update( &operation, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Call sign finish without calling setup beforehand. */ TEST_EQUAL( psa_mac_sign_finish( &operation, sign_mac, sizeof( sign_mac ), &sign_mac_length), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Call verify finish without calling setup beforehand. */ TEST_EQUAL( psa_mac_verify_finish( &operation, verify_mac, sizeof( verify_mac ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Call setup twice in a row. */ PSA_ASSERT( psa_mac_sign_setup( &operation, handle, alg ) ); TEST_EQUAL( psa_mac_sign_setup( &operation, handle, alg ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Call update after sign finish. */ PSA_ASSERT( psa_mac_sign_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); PSA_ASSERT( psa_mac_sign_finish( &operation, sign_mac, sizeof( sign_mac ), &sign_mac_length ) ); TEST_EQUAL( psa_mac_update( &operation, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Call update after verify finish. */ PSA_ASSERT( psa_mac_verify_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); PSA_ASSERT( psa_mac_verify_finish( &operation, verify_mac, sizeof( verify_mac ) ) ); TEST_EQUAL( psa_mac_update( &operation, input, sizeof( input ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Call sign finish twice in a row. */ PSA_ASSERT( psa_mac_sign_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); PSA_ASSERT( psa_mac_sign_finish( &operation, sign_mac, sizeof( sign_mac ), &sign_mac_length ) ); TEST_EQUAL( psa_mac_sign_finish( &operation, sign_mac, sizeof( sign_mac ), &sign_mac_length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Call verify finish twice in a row. */ PSA_ASSERT( psa_mac_verify_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); PSA_ASSERT( psa_mac_verify_finish( &operation, verify_mac, sizeof( verify_mac ) ) ); TEST_EQUAL( psa_mac_verify_finish( &operation, verify_mac, sizeof( verify_mac ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Setup sign but try verify. */ PSA_ASSERT( psa_mac_sign_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); TEST_EQUAL( psa_mac_verify_finish( &operation, verify_mac, sizeof( verify_mac ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); /* Setup verify but try sign. */ PSA_ASSERT( psa_mac_verify_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) ); TEST_EQUAL( psa_mac_sign_finish( &operation, sign_mac, sizeof( sign_mac ), &sign_mac_length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_mac_abort( &operation ) ); PSA_ASSERT( psa_destroy_key( handle ) ); exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void mac_sign( int key_type_arg, data_t *key, int alg_arg, data_t *input, data_t *expected_mac ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; /* Leave a little extra room in the output buffer. At the end of the * test, we'll check that the implementation didn't overwrite onto * this extra room. */ uint8_t actual_mac[PSA_MAC_MAX_SIZE + 10]; size_t mac_buffer_size = PSA_MAC_FINAL_SIZE( key_type, PSA_BYTES_TO_BITS( key->len ), alg ); size_t mac_length = 0; memset( actual_mac, '+', sizeof( actual_mac ) ); TEST_ASSERT( mac_buffer_size <= PSA_MAC_MAX_SIZE ); TEST_ASSERT( expected_mac->len <= mac_buffer_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); /* Calculate the MAC. */ PSA_ASSERT( psa_mac_sign_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_mac_update( &operation, input->x, input->len ) ); PSA_ASSERT( psa_mac_sign_finish( &operation, actual_mac, mac_buffer_size, &mac_length ) ); /* Compare with the expected value. */ ASSERT_COMPARE( expected_mac->x, expected_mac->len, actual_mac, mac_length ); /* Verify that the end of the buffer is untouched. */ TEST_ASSERT( mem_is_char( actual_mac + mac_length, '+', sizeof( actual_mac ) - mac_length ) ); exit: psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void mac_verify( int key_type_arg, data_t *key, int alg_arg, data_t *input, data_t *expected_mac ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; TEST_ASSERT( expected_mac->len <= PSA_MAC_MAX_SIZE ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); PSA_ASSERT( psa_mac_verify_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_destroy_key( handle ) ); PSA_ASSERT( psa_mac_update( &operation, input->x, input->len ) ); PSA_ASSERT( psa_mac_verify_finish( &operation, expected_mac->x, expected_mac->len ) ); exit: psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_operation_init( ) { const uint8_t input[1] = { 0 }; unsigned char output[1] = { 0 }; size_t output_length; /* Test each valid way of initializing the object, except for `= {0}`, as * Clang 5 complains when `-Wmissing-field-initializers` is used, even * though it's OK by the C standard. We could test for this, but we'd need * to supress the Clang warning for the test. */ psa_cipher_operation_t func = psa_cipher_operation_init( ); psa_cipher_operation_t init = PSA_CIPHER_OPERATION_INIT; psa_cipher_operation_t zero; memset( &zero, 0, sizeof( zero ) ); /* A freshly-initialized cipher operation should not be usable. */ TEST_EQUAL( psa_cipher_update( &func, input, sizeof( input ), output, sizeof( output ), &output_length ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_cipher_update( &init, input, sizeof( input ), output, sizeof( output ), &output_length ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_cipher_update( &zero, input, sizeof( input ), output, sizeof( output ), &output_length ), PSA_ERROR_BAD_STATE ); /* A default cipher operation should be abortable without error. */ PSA_ASSERT( psa_cipher_abort( &func ) ); PSA_ASSERT( psa_cipher_abort( &init ) ); PSA_ASSERT( psa_cipher_abort( &zero ) ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_setup( int key_type_arg, data_t *key, int alg_arg, int expected_status_arg ) { psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_status_t status; #if defined(KNOWN_SUPPORTED_MAC_ALG) const uint8_t smoke_test_key_data[16] = "kkkkkkkkkkkkkkkk"; #endif PSA_ASSERT( psa_crypto_init( ) ); if( ! exercise_cipher_setup( key_type, key->x, key->len, alg, &operation, &status ) ) goto exit; TEST_EQUAL( status, expected_status ); /* The operation object should be reusable. */ #if defined(KNOWN_SUPPORTED_CIPHER_ALG) if( ! exercise_cipher_setup( KNOWN_SUPPORTED_CIPHER_KEY_TYPE, smoke_test_key_data, sizeof( smoke_test_key_data ), KNOWN_SUPPORTED_CIPHER_ALG, &operation, &status ) ) goto exit; TEST_EQUAL( status, PSA_SUCCESS ); #endif exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_bad_order( ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = PSA_KEY_TYPE_AES; psa_algorithm_t alg = PSA_ALG_CBC_PKCS7; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; unsigned char iv[PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES)] = { 0 }; const uint8_t key[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }; const uint8_t text[] = { 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb }; uint8_t buffer[PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES)] = { 0 }; size_t length = 0; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key, sizeof( key ), &handle ) ); /* Call encrypt setup twice in a row. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); TEST_EQUAL( psa_cipher_encrypt_setup( &operation, handle, alg ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Call decrypt setup twice in a row. */ PSA_ASSERT( psa_cipher_decrypt_setup( &operation, handle, alg ) ); TEST_EQUAL( psa_cipher_decrypt_setup( &operation, handle, alg ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Generate an IV without calling setup beforehand. */ TEST_EQUAL( psa_cipher_generate_iv( &operation, buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Generate an IV twice in a row. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_generate_iv( &operation, buffer, sizeof( buffer ), &length ) ); TEST_EQUAL( psa_cipher_generate_iv( &operation, buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Generate an IV after it's already set. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv, sizeof( iv ) ) ); TEST_EQUAL( psa_cipher_generate_iv( &operation, buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Set an IV without calling setup beforehand. */ TEST_EQUAL( psa_cipher_set_iv( &operation, iv, sizeof( iv ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Set an IV after it's already set. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv, sizeof( iv ) ) ); TEST_EQUAL( psa_cipher_set_iv( &operation, iv, sizeof( iv ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Set an IV after it's already generated. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_generate_iv( &operation, buffer, sizeof( buffer ), &length ) ); TEST_EQUAL( psa_cipher_set_iv( &operation, iv, sizeof( iv ) ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Call update without calling setup beforehand. */ TEST_EQUAL( psa_cipher_update( &operation, text, sizeof( text ), buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Call update without an IV where an IV is required. */ TEST_EQUAL( psa_cipher_update( &operation, text, sizeof( text ), buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Call update after finish. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv, sizeof( iv ) ) ); PSA_ASSERT( psa_cipher_finish( &operation, buffer, sizeof( buffer ), &length ) ); TEST_EQUAL( psa_cipher_update( &operation, text, sizeof( text ), buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Call finish without calling setup beforehand. */ TEST_EQUAL( psa_cipher_finish( &operation, buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Call finish without an IV where an IV is required. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); /* Not calling update means we are encrypting an empty buffer, which is OK * for cipher modes with padding. */ TEST_EQUAL( psa_cipher_finish( &operation, buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); /* Call finish twice in a row. */ PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv, sizeof( iv ) ) ); PSA_ASSERT( psa_cipher_finish( &operation, buffer, sizeof( buffer ), &length ) ); TEST_EQUAL( psa_cipher_finish( &operation, buffer, sizeof( buffer ), &length ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_cipher_abort( &operation ) ); PSA_ASSERT( psa_destroy_key( handle ) ); exit: PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_encrypt( int alg_arg, int key_type_arg, data_t *key, data_t *iv, data_t *input, data_t *expected_output, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_status_t status; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; unsigned char *output = NULL; size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); output_buffer_size = ( (size_t) input->len + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); ASSERT_ALLOC( output, output_buffer_size ); PSA_ASSERT( psa_cipher_update( &operation, input->x, input->len, output, output_buffer_size, &function_output_length ) ); total_output_length += function_output_length; status = psa_cipher_finish( &operation, output + total_output_length, output_buffer_size - total_output_length, &function_output_length ); total_output_length += function_output_length; TEST_EQUAL( status, expected_status ); if( expected_status == PSA_SUCCESS ) { PSA_ASSERT( psa_cipher_abort( &operation ) ); ASSERT_COMPARE( expected_output->x, expected_output->len, output, total_output_length ); } exit: mbedtls_free( output ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_encrypt_multipart( int alg_arg, int key_type_arg, data_t *key, data_t *iv, data_t *input, int first_part_size_arg, int output1_length_arg, int output2_length_arg, data_t *expected_output ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t first_part_size = first_part_size_arg; size_t output1_length = output1_length_arg; size_t output2_length = output2_length_arg; unsigned char *output = NULL; size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); PSA_ASSERT( psa_cipher_encrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); output_buffer_size = ( (size_t) input->len + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); ASSERT_ALLOC( output, output_buffer_size ); TEST_ASSERT( first_part_size <= input->len ); PSA_ASSERT( psa_cipher_update( &operation, input->x, first_part_size, output, output_buffer_size, &function_output_length ) ); TEST_ASSERT( function_output_length == output1_length ); total_output_length += function_output_length; PSA_ASSERT( psa_cipher_update( &operation, input->x + first_part_size, input->len - first_part_size, output + total_output_length, output_buffer_size - total_output_length, &function_output_length ) ); TEST_ASSERT( function_output_length == output2_length ); total_output_length += function_output_length; PSA_ASSERT( psa_cipher_finish( &operation, output + total_output_length, output_buffer_size - total_output_length, &function_output_length ) ); total_output_length += function_output_length; PSA_ASSERT( psa_cipher_abort( &operation ) ); ASSERT_COMPARE( expected_output->x, expected_output->len, output, total_output_length ); exit: mbedtls_free( output ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_decrypt_multipart( int alg_arg, int key_type_arg, data_t *key, data_t *iv, data_t *input, int first_part_size_arg, int output1_length_arg, int output2_length_arg, data_t *expected_output ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t first_part_size = first_part_size_arg; size_t output1_length = output1_length_arg; size_t output2_length = output2_length_arg; unsigned char *output = NULL; size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); PSA_ASSERT( psa_cipher_decrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); output_buffer_size = ( (size_t) input->len + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); ASSERT_ALLOC( output, output_buffer_size ); TEST_ASSERT( first_part_size <= input->len ); PSA_ASSERT( psa_cipher_update( &operation, input->x, first_part_size, output, output_buffer_size, &function_output_length ) ); TEST_ASSERT( function_output_length == output1_length ); total_output_length += function_output_length; PSA_ASSERT( psa_cipher_update( &operation, input->x + first_part_size, input->len - first_part_size, output + total_output_length, output_buffer_size - total_output_length, &function_output_length ) ); TEST_ASSERT( function_output_length == output2_length ); total_output_length += function_output_length; PSA_ASSERT( psa_cipher_finish( &operation, output + total_output_length, output_buffer_size - total_output_length, &function_output_length ) ); total_output_length += function_output_length; PSA_ASSERT( psa_cipher_abort( &operation ) ); ASSERT_COMPARE( expected_output->x, expected_output->len, output, total_output_length ); exit: mbedtls_free( output ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_decrypt( int alg_arg, int key_type_arg, data_t *key, data_t *iv, data_t *input, data_t *expected_output, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_status_t status; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; unsigned char *output = NULL; size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); PSA_ASSERT( psa_cipher_decrypt_setup( &operation, handle, alg ) ); PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); output_buffer_size = ( (size_t) input->len + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); ASSERT_ALLOC( output, output_buffer_size ); PSA_ASSERT( psa_cipher_update( &operation, input->x, input->len, output, output_buffer_size, &function_output_length ) ); total_output_length += function_output_length; status = psa_cipher_finish( &operation, output + total_output_length, output_buffer_size - total_output_length, &function_output_length ); total_output_length += function_output_length; TEST_EQUAL( status, expected_status ); if( expected_status == PSA_SUCCESS ) { PSA_ASSERT( psa_cipher_abort( &operation ) ); ASSERT_COMPARE( expected_output->x, expected_output->len, output, total_output_length ); } exit: mbedtls_free( output ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_verify_output( int alg_arg, int key_type_arg, data_t *key, data_t *input ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; unsigned char iv[16] = {0}; size_t iv_size = 16; size_t iv_length = 0; unsigned char *output1 = NULL; size_t output1_size = 0; size_t output1_length = 0; unsigned char *output2 = NULL; size_t output2_size = 0; size_t output2_length = 0; size_t function_output_length = 0; psa_cipher_operation_t operation1 = PSA_CIPHER_OPERATION_INIT; psa_cipher_operation_t operation2 = PSA_CIPHER_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); PSA_ASSERT( psa_cipher_encrypt_setup( &operation1, handle, alg ) ); PSA_ASSERT( psa_cipher_decrypt_setup( &operation2, handle, alg ) ); PSA_ASSERT( psa_cipher_generate_iv( &operation1, iv, iv_size, &iv_length ) ); output1_size = ( (size_t) input->len + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); ASSERT_ALLOC( output1, output1_size ); PSA_ASSERT( psa_cipher_update( &operation1, input->x, input->len, output1, output1_size, &output1_length ) ); PSA_ASSERT( psa_cipher_finish( &operation1, output1 + output1_length, output1_size - output1_length, &function_output_length ) ); output1_length += function_output_length; PSA_ASSERT( psa_cipher_abort( &operation1 ) ); output2_size = output1_length; ASSERT_ALLOC( output2, output2_size ); PSA_ASSERT( psa_cipher_set_iv( &operation2, iv, iv_length ) ); PSA_ASSERT( psa_cipher_update( &operation2, output1, output1_length, output2, output2_size, &output2_length ) ); function_output_length = 0; PSA_ASSERT( psa_cipher_finish( &operation2, output2 + output2_length, output2_size - output2_length, &function_output_length ) ); output2_length += function_output_length; PSA_ASSERT( psa_cipher_abort( &operation2 ) ); ASSERT_COMPARE( input->x, input->len, output2, output2_length ); exit: mbedtls_free( output1 ); mbedtls_free( output2 ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void cipher_verify_output_multipart( int alg_arg, int key_type_arg, data_t *key, data_t *input, int first_part_size_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t first_part_size = first_part_size_arg; unsigned char iv[16] = {0}; size_t iv_size = 16; size_t iv_length = 0; unsigned char *output1 = NULL; size_t output1_buffer_size = 0; size_t output1_length = 0; unsigned char *output2 = NULL; size_t output2_buffer_size = 0; size_t output2_length = 0; size_t function_output_length; psa_cipher_operation_t operation1 = PSA_CIPHER_OPERATION_INIT; psa_cipher_operation_t operation2 = PSA_CIPHER_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); PSA_ASSERT( psa_cipher_encrypt_setup( &operation1, handle, alg ) ); PSA_ASSERT( psa_cipher_decrypt_setup( &operation2, handle, alg ) ); PSA_ASSERT( psa_cipher_generate_iv( &operation1, iv, iv_size, &iv_length ) ); output1_buffer_size = ( (size_t) input->len + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); ASSERT_ALLOC( output1, output1_buffer_size ); TEST_ASSERT( first_part_size <= input->len ); PSA_ASSERT( psa_cipher_update( &operation1, input->x, first_part_size, output1, output1_buffer_size, &function_output_length ) ); output1_length += function_output_length; PSA_ASSERT( psa_cipher_update( &operation1, input->x + first_part_size, input->len - first_part_size, output1, output1_buffer_size, &function_output_length ) ); output1_length += function_output_length; PSA_ASSERT( psa_cipher_finish( &operation1, output1 + output1_length, output1_buffer_size - output1_length, &function_output_length ) ); output1_length += function_output_length; PSA_ASSERT( psa_cipher_abort( &operation1 ) ); output2_buffer_size = output1_length; ASSERT_ALLOC( output2, output2_buffer_size ); PSA_ASSERT( psa_cipher_set_iv( &operation2, iv, iv_length ) ); PSA_ASSERT( psa_cipher_update( &operation2, output1, first_part_size, output2, output2_buffer_size, &function_output_length ) ); output2_length += function_output_length; PSA_ASSERT( psa_cipher_update( &operation2, output1 + first_part_size, output1_length - first_part_size, output2, output2_buffer_size, &function_output_length ) ); output2_length += function_output_length; PSA_ASSERT( psa_cipher_finish( &operation2, output2 + output2_length, output2_buffer_size - output2_length, &function_output_length ) ); output2_length += function_output_length; PSA_ASSERT( psa_cipher_abort( &operation2 ) ); ASSERT_COMPARE( input->x, input->len, output2, output2_length ); exit: mbedtls_free( output1 ); mbedtls_free( output2 ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void aead_encrypt_decrypt( int key_type_arg, data_t *key_data, int alg_arg, data_t *nonce, data_t *additional_data, data_t *input_data, int expected_result_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; unsigned char *output_data = NULL; size_t output_size = 0; size_t output_length = 0; unsigned char *output_data2 = NULL; size_t output_length2 = 0; size_t tag_length = PSA_AEAD_TAG_LENGTH( alg ); psa_status_t expected_result = expected_result_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; output_size = input_data->len + tag_length; /* For all currently defined algorithms, PSA_AEAD_ENCRYPT_OUTPUT_SIZE * should be exact. */ if( expected_result != PSA_ERROR_INVALID_ARGUMENT ) TEST_EQUAL( output_size, PSA_AEAD_ENCRYPT_OUTPUT_SIZE( alg, input_data->len ) ); ASSERT_ALLOC( output_data, output_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); TEST_EQUAL( psa_aead_encrypt( handle, alg, nonce->x, nonce->len, additional_data->x, additional_data->len, input_data->x, input_data->len, output_data, output_size, &output_length ), expected_result ); if( PSA_SUCCESS == expected_result ) { ASSERT_ALLOC( output_data2, output_length ); /* For all currently defined algorithms, PSA_AEAD_DECRYPT_OUTPUT_SIZE * should be exact. */ TEST_EQUAL( input_data->len, PSA_AEAD_DECRYPT_OUTPUT_SIZE( alg, output_length ) ); TEST_EQUAL( psa_aead_decrypt( handle, alg, nonce->x, nonce->len, additional_data->x, additional_data->len, output_data, output_length, output_data2, output_length, &output_length2 ), expected_result ); ASSERT_COMPARE( input_data->x, input_data->len, output_data2, output_length2 ); } exit: psa_destroy_key( handle ); mbedtls_free( output_data ); mbedtls_free( output_data2 ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void aead_encrypt( int key_type_arg, data_t *key_data, int alg_arg, data_t *nonce, data_t *additional_data, data_t *input_data, data_t *expected_result ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; unsigned char *output_data = NULL; size_t output_size = 0; size_t output_length = 0; size_t tag_length = PSA_AEAD_TAG_LENGTH( alg ); psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; output_size = input_data->len + tag_length; /* For all currently defined algorithms, PSA_AEAD_ENCRYPT_OUTPUT_SIZE * should be exact. */ TEST_EQUAL( output_size, PSA_AEAD_ENCRYPT_OUTPUT_SIZE( alg, input_data->len ) ); ASSERT_ALLOC( output_data, output_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_aead_encrypt( handle, alg, nonce->x, nonce->len, additional_data->x, additional_data->len, input_data->x, input_data->len, output_data, output_size, &output_length ) ); ASSERT_COMPARE( expected_result->x, expected_result->len, output_data, output_length ); exit: psa_destroy_key( handle ); mbedtls_free( output_data ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void aead_decrypt( int key_type_arg, data_t *key_data, int alg_arg, data_t *nonce, data_t *additional_data, data_t *input_data, data_t *expected_data, int expected_result_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; unsigned char *output_data = NULL; size_t output_size = 0; size_t output_length = 0; size_t tag_length = PSA_AEAD_TAG_LENGTH( alg ); psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t expected_result = expected_result_arg; output_size = input_data->len - tag_length; /* For all currently defined algorithms, PSA_AEAD_DECRYPT_OUTPUT_SIZE * should be exact. */ if( expected_result != PSA_ERROR_INVALID_ARGUMENT ) TEST_EQUAL( output_size, PSA_AEAD_DECRYPT_OUTPUT_SIZE( alg, input_data->len ) ); ASSERT_ALLOC( output_data, output_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); TEST_EQUAL( psa_aead_decrypt( handle, alg, nonce->x, nonce->len, additional_data->x, additional_data->len, input_data->x, input_data->len, output_data, output_size, &output_length ), expected_result ); if( expected_result == PSA_SUCCESS ) ASSERT_COMPARE( expected_data->x, expected_data->len, output_data, output_length ); exit: psa_destroy_key( handle ); mbedtls_free( output_data ); PSA_DONE( ); } /* 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_EQUAL( actual_size, (size_t) expected_size_arg ); exit: ; } /* END_CASE */ /* BEGIN_CASE */ void sign_deterministic( int key_type_arg, data_t *key_data, int alg_arg, data_t *input_data, data_t *output_data ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t key_bits; unsigned char *signature = NULL; size_t signature_size; size_t signature_length = 0xdeadbeef; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); key_bits = psa_get_key_bits( &attributes ); /* Allocate a buffer which has the size advertized by the * library. */ signature_size = PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE( key_type, key_bits, alg ); TEST_ASSERT( signature_size != 0 ); TEST_ASSERT( signature_size <= PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE ); ASSERT_ALLOC( signature, signature_size ); /* Perform the signature. */ PSA_ASSERT( psa_asymmetric_sign( handle, alg, input_data->x, input_data->len, signature, signature_size, &signature_length ) ); /* Verify that the signature is what is expected. */ ASSERT_COMPARE( output_data->x, output_data->len, signature, signature_length ); exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); mbedtls_free( signature ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void sign_fail( int key_type_arg, data_t *key_data, int alg_arg, data_t *input_data, int signature_size_arg, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t signature_size = signature_size_arg; psa_status_t actual_status; psa_status_t expected_status = expected_status_arg; unsigned char *signature = NULL; size_t signature_length = 0xdeadbeef; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; ASSERT_ALLOC( signature, signature_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); actual_status = psa_asymmetric_sign( handle, alg, input_data->x, input_data->len, signature, signature_size, &signature_length ); TEST_EQUAL( actual_status, expected_status ); /* The value of *signature_length is unspecified on error, but * whatever it is, it should be less than signature_size, so that * if the caller tries to read *signature_length bytes without * checking the error code then they don't overflow a buffer. */ TEST_ASSERT( signature_length <= signature_size ); exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); mbedtls_free( signature ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void sign_verify( int key_type_arg, data_t *key_data, int alg_arg, data_t *input_data ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t key_bits; unsigned char *signature = NULL; size_t signature_size; size_t signature_length = 0xdeadbeef; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); key_bits = psa_get_key_bits( &attributes ); /* Allocate a buffer which has the size advertized by the * library. */ signature_size = PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE( key_type, key_bits, alg ); TEST_ASSERT( signature_size != 0 ); TEST_ASSERT( signature_size <= PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE ); ASSERT_ALLOC( signature, signature_size ); /* Perform the signature. */ PSA_ASSERT( psa_asymmetric_sign( handle, alg, input_data->x, input_data->len, signature, signature_size, &signature_length ) ); /* Check that the signature length looks sensible. */ TEST_ASSERT( signature_length <= signature_size ); TEST_ASSERT( signature_length > 0 ); /* Use the library to verify that the signature is correct. */ PSA_ASSERT( psa_asymmetric_verify( handle, alg, input_data->x, input_data->len, signature, signature_length ) ); if( input_data->len != 0 ) { /* Flip a bit in the input and verify that the signature is now * detected as invalid. Flip a bit at the beginning, not at the end, * because ECDSA may ignore the last few bits of the input. */ input_data->x[0] ^= 1; TEST_EQUAL( psa_asymmetric_verify( handle, alg, input_data->x, input_data->len, signature, signature_length ), PSA_ERROR_INVALID_SIGNATURE ); } exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); mbedtls_free( signature ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_verify( int key_type_arg, data_t *key_data, int alg_arg, data_t *hash_data, data_t *signature_data ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; TEST_ASSERT( signature_data->len <= PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_asymmetric_verify( handle, alg, hash_data->x, hash_data->len, signature_data->x, signature_data->len ) ); exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_verify_fail( int key_type_arg, data_t *key_data, int alg_arg, data_t *hash_data, data_t *signature_data, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_status_t actual_status; psa_status_t expected_status = expected_status_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); actual_status = psa_asymmetric_verify( handle, alg, hash_data->x, hash_data->len, signature_data->x, signature_data->len ); TEST_EQUAL( actual_status, expected_status ); exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_encrypt( int key_type_arg, data_t *key_data, int alg_arg, data_t *input_data, data_t *label, int expected_output_length_arg, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t expected_output_length = expected_output_length_arg; size_t key_bits; unsigned char *output = NULL; size_t output_size; size_t output_length = ~0; psa_status_t actual_status; psa_status_t expected_status = expected_status_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); /* Import the key */ psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); /* Determine the maximum output length */ PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); key_bits = psa_get_key_bits( &attributes ); output_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE( key_type, key_bits, alg ); ASSERT_ALLOC( output, output_size ); /* Encrypt the input */ actual_status = psa_asymmetric_encrypt( handle, alg, input_data->x, input_data->len, label->x, label->len, output, output_size, &output_length ); TEST_EQUAL( actual_status, expected_status ); TEST_EQUAL( output_length, expected_output_length ); /* If the label is empty, the test framework puts a non-null pointer * in label->x. Test that a null pointer works as well. */ if( label->len == 0 ) { output_length = ~0; if( output_size != 0 ) memset( output, 0, output_size ); actual_status = psa_asymmetric_encrypt( handle, alg, input_data->x, input_data->len, NULL, label->len, output, output_size, &output_length ); TEST_EQUAL( actual_status, expected_status ); TEST_EQUAL( output_length, expected_output_length ); } exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); mbedtls_free( output ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_encrypt_decrypt( int key_type_arg, data_t *key_data, int alg_arg, data_t *input_data, data_t *label ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t key_bits; unsigned char *output = NULL; size_t output_size; size_t output_length = ~0; unsigned char *output2 = NULL; size_t output2_size; size_t output2_length = ~0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); /* Determine the maximum ciphertext length */ PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); key_bits = psa_get_key_bits( &attributes ); output_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE( key_type, key_bits, alg ); ASSERT_ALLOC( output, output_size ); output2_size = input_data->len; ASSERT_ALLOC( output2, output2_size ); /* We test encryption by checking that encrypt-then-decrypt gives back * the original plaintext because of the non-optional random * part of encryption process which prevents using fixed vectors. */ PSA_ASSERT( psa_asymmetric_encrypt( handle, alg, input_data->x, input_data->len, label->x, label->len, output, output_size, &output_length ) ); /* We don't know what ciphertext length to expect, but check that * it looks sensible. */ TEST_ASSERT( output_length <= output_size ); PSA_ASSERT( psa_asymmetric_decrypt( handle, alg, output, output_length, label->x, label->len, output2, output2_size, &output2_length ) ); ASSERT_COMPARE( input_data->x, input_data->len, output2, output2_length ); exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); mbedtls_free( output ); mbedtls_free( output2 ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_decrypt( int key_type_arg, data_t *key_data, int alg_arg, data_t *input_data, data_t *label, data_t *expected_data ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; unsigned char *output = NULL; size_t output_size = 0; size_t output_length = ~0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; output_size = expected_data->len; ASSERT_ALLOC( output, output_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); PSA_ASSERT( psa_asymmetric_decrypt( handle, alg, input_data->x, input_data->len, label->x, label->len, output, output_size, &output_length ) ); ASSERT_COMPARE( expected_data->x, expected_data->len, output, output_length ); /* If the label is empty, the test framework puts a non-null pointer * in label->x. Test that a null pointer works as well. */ if( label->len == 0 ) { output_length = ~0; if( output_size != 0 ) memset( output, 0, output_size ); PSA_ASSERT( psa_asymmetric_decrypt( handle, alg, input_data->x, input_data->len, NULL, label->len, output, output_size, &output_length ) ); ASSERT_COMPARE( expected_data->x, expected_data->len, output, output_length ); } exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); mbedtls_free( output ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void asymmetric_decrypt_fail( int key_type_arg, data_t *key_data, int alg_arg, data_t *input_data, data_t *label, int output_size_arg, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; unsigned char *output = NULL; size_t output_size = output_size_arg; size_t output_length = ~0; psa_status_t actual_status; psa_status_t expected_status = expected_status_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; ASSERT_ALLOC( output, output_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); actual_status = psa_asymmetric_decrypt( handle, alg, input_data->x, input_data->len, label->x, label->len, output, output_size, &output_length ); TEST_EQUAL( actual_status, expected_status ); TEST_ASSERT( output_length <= output_size ); /* If the label is empty, the test framework puts a non-null pointer * in label->x. Test that a null pointer works as well. */ if( label->len == 0 ) { output_length = ~0; if( output_size != 0 ) memset( output, 0, output_size ); actual_status = psa_asymmetric_decrypt( handle, alg, input_data->x, input_data->len, NULL, label->len, output, output_size, &output_length ); TEST_EQUAL( actual_status, expected_status ); TEST_ASSERT( output_length <= output_size ); } exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); mbedtls_free( output ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void key_derivation_init( ) { /* Test each valid way of initializing the object, except for `= {0}`, as * Clang 5 complains when `-Wmissing-field-initializers` is used, even * though it's OK by the C standard. We could test for this, but we'd need * to supress the Clang warning for the test. */ size_t capacity; psa_key_derivation_operation_t func = psa_key_derivation_operation_init( ); psa_key_derivation_operation_t init = PSA_KEY_DERIVATION_OPERATION_INIT; psa_key_derivation_operation_t zero; memset( &zero, 0, sizeof( zero ) ); /* A default operation should not be able to report its capacity. */ TEST_EQUAL( psa_key_derivation_get_capacity( &func, &capacity ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_key_derivation_get_capacity( &init, &capacity ), PSA_ERROR_BAD_STATE ); TEST_EQUAL( psa_key_derivation_get_capacity( &zero, &capacity ), PSA_ERROR_BAD_STATE ); /* A default operation should be abortable without error. */ PSA_ASSERT( psa_key_derivation_abort(&func) ); PSA_ASSERT( psa_key_derivation_abort(&init) ); PSA_ASSERT( psa_key_derivation_abort(&zero) ); } /* END_CASE */ /* BEGIN_CASE depends_on:PSA_PRE_1_0_KEY_DERIVATION */ void derive_setup( int key_type_arg, data_t *key_data, int alg_arg, data_t *salt, data_t *label, int requested_capacity_arg, int expected_status_arg ) { psa_key_handle_t handle = 0; size_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; size_t requested_capacity = requested_capacity_arg; psa_status_t expected_status = expected_status_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); TEST_EQUAL( psa_key_derivation( &operation, handle, alg, salt->x, salt->len, label->x, label->len, requested_capacity ), expected_status ); exit: psa_key_derivation_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void derive_input( int alg_arg, int key_type_arg, int step1_arg, data_t *input1, int step2_arg, data_t *input2, int step3_arg, data_t *input3, int expected_status_arg1, int expected_status_arg2, int expected_status_arg3 ) { psa_algorithm_t alg = alg_arg; size_t key_type = key_type_arg; psa_key_derivation_step_t steps[] = {step1_arg, step2_arg, step3_arg}; psa_status_t expected_statuses[] = {expected_status_arg1, expected_status_arg2, expected_status_arg3}; data_t *inputs[] = {input1, input2, input3}; psa_key_handle_t handles[] = {0, 0, 0}; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; size_t i; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) ); for( i = 0; i < ARRAY_LENGTH( steps ); i++ ) { switch( steps[i] ) { case PSA_KEY_DERIVATION_INPUT_SECRET: PSA_ASSERT( psa_import_key( &attributes, inputs[i]->x, inputs[i]->len, &handles[i] ) ); TEST_EQUAL( psa_key_derivation_input_key( &operation, steps[i], handles[i] ), expected_statuses[i] ); break; default: TEST_EQUAL( psa_key_derivation_input_bytes( &operation, steps[i], inputs[i]->x, inputs[i]->len ), expected_statuses[i] ); break; } } exit: psa_key_derivation_abort( &operation ); for( i = 0; i < ARRAY_LENGTH( handles ); i++ ) psa_destroy_key( handles[i] ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:PSA_PRE_1_0_KEY_DERIVATION */ void test_derive_invalid_key_derivation_state( ) { psa_key_handle_t handle = 0; size_t key_type = PSA_KEY_TYPE_DERIVE; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_algorithm_t alg = PSA_ALG_HKDF( PSA_ALG_SHA_256 ); uint8_t buffer[42]; size_t capacity = sizeof( buffer ); const uint8_t key_data[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, key_type ); PSA_ASSERT( psa_import_key( &attributes, key_data, sizeof( key_data ), &handle ) ); /* valid key derivation */ PSA_ASSERT( psa_key_derivation( &operation, handle, alg, NULL, 0, NULL, 0, capacity ) ); /* state of operation shouldn't allow additional generation */ TEST_EQUAL( psa_key_derivation( &operation, handle, alg, NULL, 0, NULL, 0, capacity ), PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_key_derivation_output_bytes( &operation, buffer, capacity ) ); TEST_EQUAL( psa_key_derivation_output_bytes( &operation, buffer, capacity ), PSA_ERROR_INSUFFICIENT_DATA ); exit: psa_key_derivation_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void test_derive_invalid_key_derivation_tests( ) { uint8_t output_buffer[16]; size_t buffer_size = 16; size_t capacity = 0; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; TEST_ASSERT( psa_key_derivation_output_bytes( &operation, output_buffer, buffer_size ) == PSA_ERROR_BAD_STATE ); TEST_ASSERT( psa_key_derivation_get_capacity( &operation, &capacity ) == PSA_ERROR_BAD_STATE ); PSA_ASSERT( psa_key_derivation_abort( &operation ) ); TEST_ASSERT( psa_key_derivation_output_bytes( &operation, output_buffer, buffer_size ) == PSA_ERROR_BAD_STATE ); TEST_ASSERT( psa_key_derivation_get_capacity( &operation, &capacity ) == PSA_ERROR_BAD_STATE ); exit: psa_key_derivation_abort( &operation ); } /* END_CASE */ /* BEGIN_CASE */ void derive_output( int alg_arg, data_t *key_data, data_t *salt, data_t *label, int requested_capacity_arg, data_t *expected_output1, data_t *expected_output2 ) { psa_key_handle_t handle = 0; psa_algorithm_t alg = alg_arg; size_t requested_capacity = requested_capacity_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; uint8_t *expected_outputs[2] = {expected_output1->x, expected_output2->x}; size_t output_sizes[2] = {expected_output1->len, expected_output2->len}; size_t output_buffer_size = 0; uint8_t *output_buffer = NULL; size_t expected_capacity; size_t current_capacity; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; unsigned i; for( i = 0; i < ARRAY_LENGTH( expected_outputs ); i++ ) { if( output_sizes[i] > output_buffer_size ) output_buffer_size = output_sizes[i]; if( output_sizes[i] == 0 ) expected_outputs[i] = NULL; } ASSERT_ALLOC( output_buffer, output_buffer_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); /* Extraction phase. */ if( PSA_ALG_IS_HKDF( alg ) ) { PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) ); PSA_ASSERT( psa_key_derivation_set_capacity( &operation, requested_capacity ) ); PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_SALT, salt->x, salt->len ) ); PSA_ASSERT( psa_key_derivation_input_key( &operation, PSA_KEY_DERIVATION_INPUT_SECRET, handle ) ); PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_INFO, label->x, label->len ) ); } #if defined(PSA_PRE_1_0_KEY_DERIVATION) else { // legacy PSA_ASSERT( psa_key_derivation( &operation, handle, alg, salt->x, salt->len, label->x, label->len, requested_capacity ) ); } #endif PSA_ASSERT( psa_key_derivation_get_capacity( &operation, ¤t_capacity ) ); TEST_EQUAL( current_capacity, requested_capacity ); expected_capacity = requested_capacity; /* Expansion phase. */ for( i = 0; i < ARRAY_LENGTH( expected_outputs ); i++ ) { /* Read some bytes. */ status = psa_key_derivation_output_bytes( &operation, output_buffer, output_sizes[i] ); if( expected_capacity == 0 && output_sizes[i] == 0 ) { /* Reading 0 bytes when 0 bytes are available can go either way. */ TEST_ASSERT( status == PSA_SUCCESS || status == PSA_ERROR_INSUFFICIENT_DATA ); continue; } else if( expected_capacity == 0 || output_sizes[i] > expected_capacity ) { /* Capacity exceeded. */ TEST_EQUAL( status, PSA_ERROR_INSUFFICIENT_DATA ); expected_capacity = 0; continue; } /* Success. Check the read data. */ PSA_ASSERT( status ); if( output_sizes[i] != 0 ) ASSERT_COMPARE( output_buffer, output_sizes[i], expected_outputs[i], output_sizes[i] ); /* Check the operation status. */ expected_capacity -= output_sizes[i]; PSA_ASSERT( psa_key_derivation_get_capacity( &operation, ¤t_capacity ) ); TEST_EQUAL( expected_capacity, current_capacity ); } PSA_ASSERT( psa_key_derivation_abort( &operation ) ); exit: mbedtls_free( output_buffer ); psa_key_derivation_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void derive_full( int alg_arg, data_t *key_data, data_t *salt, data_t *label, int requested_capacity_arg ) { psa_key_handle_t handle = 0; psa_algorithm_t alg = alg_arg; size_t requested_capacity = requested_capacity_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; unsigned char output_buffer[16]; size_t expected_capacity = requested_capacity; size_t current_capacity; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &handle ) ); /* Extraction phase. */ if( PSA_ALG_IS_HKDF( alg ) ) { PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) ); PSA_ASSERT( psa_key_derivation_set_capacity( &operation, requested_capacity ) ); PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_SALT, salt->x, salt->len ) ); PSA_ASSERT( psa_key_derivation_input_key( &operation, PSA_KEY_DERIVATION_INPUT_SECRET, handle ) ); PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_INFO, label->x, label->len ) ); } #if defined(PSA_PRE_1_0_KEY_DERIVATION) else { // legacy PSA_ASSERT( psa_key_derivation( &operation, handle, alg, salt->x, salt->len, label->x, label->len, requested_capacity ) ); } #endif PSA_ASSERT( psa_key_derivation_get_capacity( &operation, ¤t_capacity ) ); TEST_EQUAL( current_capacity, expected_capacity ); /* Expansion phase. */ while( current_capacity > 0 ) { size_t read_size = sizeof( output_buffer ); if( read_size > current_capacity ) read_size = current_capacity; PSA_ASSERT( psa_key_derivation_output_bytes( &operation, output_buffer, read_size ) ); expected_capacity -= read_size; PSA_ASSERT( psa_key_derivation_get_capacity( &operation, ¤t_capacity ) ); TEST_EQUAL( current_capacity, expected_capacity ); } /* Check that the operation refuses to go over capacity. */ TEST_EQUAL( psa_key_derivation_output_bytes( &operation, output_buffer, 1 ), PSA_ERROR_INSUFFICIENT_DATA ); PSA_ASSERT( psa_key_derivation_abort( &operation ) ); exit: psa_key_derivation_abort( &operation ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:PSA_PRE_1_0_KEY_DERIVATION */ void derive_key_exercise( int alg_arg, data_t *key_data, data_t *salt, data_t *label, int derived_type_arg, int derived_bits_arg, int derived_usage_arg, int derived_alg_arg ) { psa_key_handle_t base_handle = 0; psa_key_handle_t derived_handle = 0; psa_algorithm_t alg = alg_arg; psa_key_type_t derived_type = derived_type_arg; size_t derived_bits = derived_bits_arg; psa_key_usage_t derived_usage = derived_usage_arg; psa_algorithm_t derived_alg = derived_alg_arg; size_t capacity = PSA_BITS_TO_BYTES( derived_bits ); psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE ); PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, &base_handle ) ); /* Derive a key. */ PSA_ASSERT( psa_key_derivation( &operation, base_handle, alg, salt->x, salt->len, label->x, label->len, capacity ) ); psa_set_key_usage_flags( &attributes, derived_usage ); psa_set_key_algorithm( &attributes, derived_alg ); psa_set_key_type( &attributes, derived_type ); psa_set_key_bits( &attributes, derived_bits ); PSA_ASSERT( psa_key_derivation_output_key( &attributes, &operation, &derived_handle ) ); /* Test the key information */ PSA_ASSERT( psa_get_key_attributes( derived_handle, &got_attributes ) ); TEST_EQUAL( psa_get_key_type( &got_attributes ), derived_type ); TEST_EQUAL( psa_get_key_bits( &got_attributes ), derived_bits ); /* Exercise the derived key. */ if( ! exercise_key( derived_handle, derived_usage, derived_alg ) ) goto exit; exit: psa_key_derivation_abort( &operation ); psa_reset_key_attributes( &got_attributes ); psa_destroy_key( base_handle ); psa_destroy_key( derived_handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:PSA_PRE_1_0_KEY_DERIVATION */ void derive_key_export( int alg_arg, data_t *key_data, data_t *salt, data_t *label, int bytes1_arg, int bytes2_arg ) { psa_key_handle_t base_handle = 0; psa_key_handle_t derived_handle = 0; psa_algorithm_t alg = alg_arg; size_t bytes1 = bytes1_arg; size_t bytes2 = bytes2_arg; size_t capacity = bytes1 + bytes2; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; uint8_t *output_buffer = NULL; uint8_t *export_buffer = NULL; psa_key_attributes_t base_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t derived_attributes = PSA_KEY_ATTRIBUTES_INIT; size_t length; ASSERT_ALLOC( output_buffer, capacity ); ASSERT_ALLOC( export_buffer, capacity ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &base_attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &base_attributes, alg ); psa_set_key_type( &base_attributes, PSA_KEY_TYPE_DERIVE ); PSA_ASSERT( psa_import_key( &base_attributes, key_data->x, key_data->len, &base_handle ) ); /* Derive some material and output it. */ PSA_ASSERT( psa_key_derivation( &operation, base_handle, alg, salt->x, salt->len, label->x, label->len, capacity ) ); PSA_ASSERT( psa_key_derivation_output_bytes( &operation, output_buffer, capacity ) ); PSA_ASSERT( psa_key_derivation_abort( &operation ) ); /* Derive the same output again, but this time store it in key objects. */ PSA_ASSERT( psa_key_derivation( &operation, base_handle, alg, salt->x, salt->len, label->x, label->len, capacity ) ); psa_set_key_usage_flags( &derived_attributes, PSA_KEY_USAGE_EXPORT ); psa_set_key_algorithm( &derived_attributes, 0 ); psa_set_key_type( &derived_attributes, PSA_KEY_TYPE_RAW_DATA ); psa_set_key_bits( &derived_attributes, PSA_BYTES_TO_BITS( bytes1 ) ); PSA_ASSERT( psa_key_derivation_output_key( &derived_attributes, &operation, &derived_handle ) ); PSA_ASSERT( psa_export_key( derived_handle, export_buffer, bytes1, &length ) ); TEST_EQUAL( length, bytes1 ); PSA_ASSERT( psa_destroy_key( derived_handle ) ); psa_set_key_bits( &derived_attributes, PSA_BYTES_TO_BITS( bytes2 ) ); PSA_ASSERT( psa_key_derivation_output_key( &derived_attributes, &operation, &derived_handle ) ); PSA_ASSERT( psa_export_key( derived_handle, export_buffer + bytes1, bytes2, &length ) ); TEST_EQUAL( length, bytes2 ); /* Compare the outputs from the two runs. */ ASSERT_COMPARE( output_buffer, bytes1 + bytes2, export_buffer, capacity ); exit: mbedtls_free( output_buffer ); mbedtls_free( export_buffer ); psa_key_derivation_abort( &operation ); psa_destroy_key( base_handle ); psa_destroy_key( derived_handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void key_agreement_setup( int alg_arg, int our_key_type_arg, data_t *our_key_data, data_t *peer_key_data, int expected_status_arg ) { psa_key_handle_t our_key = 0; psa_algorithm_t alg = alg_arg; psa_key_type_t our_key_type = our_key_type_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t expected_status = expected_status_arg; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, our_key_type ); PSA_ASSERT( psa_import_key( &attributes, our_key_data->x, our_key_data->len, &our_key ) ); /* The tests currently include inputs that should fail at either step. * Test cases that fail at the setup step should be changed to call * key_derivation_setup instead, and this function should be renamed * to key_agreement_fail. */ status = psa_key_derivation_setup( &operation, alg ); if( status == PSA_SUCCESS ) { TEST_EQUAL( psa_key_derivation_key_agreement( &operation, PSA_KEY_DERIVATION_INPUT_SECRET, our_key, peer_key_data->x, peer_key_data->len ), expected_status ); } else { TEST_ASSERT( status == expected_status ); } exit: psa_key_derivation_abort( &operation ); psa_destroy_key( our_key ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void raw_key_agreement( int alg_arg, int our_key_type_arg, data_t *our_key_data, data_t *peer_key_data, data_t *expected_output ) { psa_key_handle_t our_key = 0; psa_algorithm_t alg = alg_arg; psa_key_type_t our_key_type = our_key_type_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; unsigned char *output = NULL; size_t output_length = ~0; ASSERT_ALLOC( output, expected_output->len ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, our_key_type ); PSA_ASSERT( psa_import_key( &attributes, our_key_data->x, our_key_data->len, &our_key ) ); PSA_ASSERT( psa_raw_key_agreement( alg, our_key, peer_key_data->x, peer_key_data->len, output, expected_output->len, &output_length ) ); ASSERT_COMPARE( output, output_length, expected_output->x, expected_output->len ); exit: mbedtls_free( output ); psa_destroy_key( our_key ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void key_agreement_capacity( int alg_arg, int our_key_type_arg, data_t *our_key_data, data_t *peer_key_data, int expected_capacity_arg ) { psa_key_handle_t our_key = 0; psa_algorithm_t alg = alg_arg; psa_key_type_t our_key_type = our_key_type_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; size_t actual_capacity; unsigned char output[16]; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, our_key_type ); PSA_ASSERT( psa_import_key( &attributes, our_key_data->x, our_key_data->len, &our_key ) ); PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) ); PSA_ASSERT( psa_key_derivation_key_agreement( &operation, PSA_KEY_DERIVATION_INPUT_SECRET, our_key, peer_key_data->x, peer_key_data->len ) ); if( PSA_ALG_IS_HKDF( PSA_ALG_KEY_AGREEMENT_GET_KDF( alg ) ) ) { /* The test data is for info="" */ PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_INFO, NULL, 0 ) ); } /* Test the advertized capacity. */ PSA_ASSERT( psa_key_derivation_get_capacity( &operation, &actual_capacity ) ); TEST_EQUAL( actual_capacity, (size_t) expected_capacity_arg ); /* Test the actual capacity by reading the output. */ while( actual_capacity > sizeof( output ) ) { PSA_ASSERT( psa_key_derivation_output_bytes( &operation, output, sizeof( output ) ) ); actual_capacity -= sizeof( output ); } PSA_ASSERT( psa_key_derivation_output_bytes( &operation, output, actual_capacity ) ); TEST_EQUAL( psa_key_derivation_output_bytes( &operation, output, 1 ), PSA_ERROR_INSUFFICIENT_DATA ); exit: psa_key_derivation_abort( &operation ); psa_destroy_key( our_key ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE */ void key_agreement_output( int alg_arg, int our_key_type_arg, data_t *our_key_data, data_t *peer_key_data, data_t *expected_output1, data_t *expected_output2 ) { psa_key_handle_t our_key = 0; psa_algorithm_t alg = alg_arg; psa_key_type_t our_key_type = our_key_type_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; uint8_t *actual_output = NULL; ASSERT_ALLOC( actual_output, MAX( expected_output1->len, expected_output2->len ) ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, our_key_type ); PSA_ASSERT( psa_import_key( &attributes, our_key_data->x, our_key_data->len, &our_key ) ); PSA_ASSERT( psa_key_derivation_setup( &operation, alg ) ); PSA_ASSERT( psa_key_derivation_key_agreement( &operation, PSA_KEY_DERIVATION_INPUT_SECRET, our_key, peer_key_data->x, peer_key_data->len ) ); if( PSA_ALG_IS_HKDF( PSA_ALG_KEY_AGREEMENT_GET_KDF( alg ) ) ) { /* The test data is for info="" */ PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_INFO, NULL, 0 ) ); } PSA_ASSERT( psa_key_derivation_output_bytes( &operation, actual_output, expected_output1->len ) ); ASSERT_COMPARE( actual_output, expected_output1->len, expected_output1->x, expected_output1->len ); if( expected_output2->len != 0 ) { PSA_ASSERT( psa_key_derivation_output_bytes( &operation, actual_output, expected_output2->len ) ); ASSERT_COMPARE( actual_output, expected_output2->len, expected_output2->x, expected_output2->len ); } exit: psa_key_derivation_abort( &operation ); psa_destroy_key( our_key ); PSA_DONE( ); mbedtls_free( actual_output ); } /* END_CASE */ /* BEGIN_CASE */ void generate_random( int bytes_arg ) { size_t bytes = bytes_arg; const unsigned char trail[] = "don't overwrite me"; unsigned char *output = NULL; unsigned char *changed = NULL; size_t i; unsigned run; ASSERT_ALLOC( output, bytes + sizeof( trail ) ); ASSERT_ALLOC( changed, bytes ); memcpy( output + bytes, trail, sizeof( trail ) ); PSA_ASSERT( psa_crypto_init( ) ); /* Run several times, to ensure that every output byte will be * nonzero at least once with overwhelming probability * (2^(-8*number_of_runs)). */ for( run = 0; run < 10; run++ ) { if( bytes != 0 ) memset( output, 0, bytes ); PSA_ASSERT( psa_generate_random( output, bytes ) ); /* Check that no more than bytes have been overwritten */ ASSERT_COMPARE( output + bytes, sizeof( trail ), trail, sizeof( trail ) ); for( i = 0; i < bytes; i++ ) { if( output[i] != 0 ) ++changed[i]; } } /* Check that every byte was changed to nonzero at least once. This * validates that psa_generate_random is overwriting every byte of * the output buffer. */ for( i = 0; i < bytes; i++ ) { TEST_ASSERT( changed[i] != 0 ); } exit: PSA_DONE( ); mbedtls_free( output ); mbedtls_free( changed ); } /* END_CASE */ /* BEGIN_CASE */ void generate_key( int type_arg, int bits_arg, int usage_arg, int alg_arg, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_key_type_t type = type_arg; psa_key_usage_t usage = usage_arg; size_t bits = bits_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, usage ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, type ); psa_set_key_bits( &attributes, bits ); /* Generate a key */ TEST_EQUAL( psa_generate_key( &attributes, &handle ), expected_status ); if( expected_status != PSA_SUCCESS ) goto exit; /* Test the key information */ PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) ); TEST_EQUAL( psa_get_key_type( &got_attributes ), type ); TEST_EQUAL( psa_get_key_bits( &got_attributes ), bits ); /* Do something with the key according to its type and permitted usage. */ if( ! exercise_key( handle, usage, alg ) ) goto exit; exit: psa_reset_key_attributes( &got_attributes ); psa_destroy_key( handle ); PSA_DONE( ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15 */ void generate_key_rsa( int bits_arg, data_t *e_arg, int expected_status_arg ) { psa_key_handle_t handle = 0; psa_key_type_t type = PSA_KEY_TYPE_RSA_KEY_PAIR; size_t bits = bits_arg; psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT; psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN_RAW; psa_status_t expected_status = expected_status_arg; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; uint8_t *exported = NULL; size_t exported_size = PSA_KEY_EXPORT_MAX_SIZE( PSA_KEY_TYPE_RSA_PUBLIC_KEY, bits ); size_t exported_length = SIZE_MAX; uint8_t *e_read_buffer = NULL; int is_default_public_exponent = 0; size_t e_read_size = PSA_KEY_DOMAIN_PARAMETERS_SIZE( type, bits ); size_t e_read_length = SIZE_MAX; if( e_arg->len == 0 || ( e_arg->len == 3 && e_arg->x[0] == 1 && e_arg->x[1] == 0 && e_arg->x[2] == 1 ) ) { is_default_public_exponent = 1; e_read_size = 0; } ASSERT_ALLOC( e_read_buffer, e_read_size ); ASSERT_ALLOC( exported, exported_size ); PSA_ASSERT( psa_crypto_init( ) ); psa_set_key_usage_flags( &attributes, usage ); psa_set_key_algorithm( &attributes, alg ); PSA_ASSERT( psa_set_key_domain_parameters( &attributes, type, e_arg->x, e_arg->len ) ); psa_set_key_bits( &attributes, bits ); /* Generate a key */ TEST_EQUAL( psa_generate_key( &attributes, &handle ), expected_status ); if( expected_status != PSA_SUCCESS ) goto exit; /* Test the key information */ PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); TEST_EQUAL( psa_get_key_type( &attributes ), type ); TEST_EQUAL( psa_get_key_bits( &attributes ), bits ); PSA_ASSERT( psa_get_key_domain_parameters( &attributes, e_read_buffer, e_read_size, &e_read_length ) ); if( is_default_public_exponent ) TEST_EQUAL( e_read_length, 0 ); else ASSERT_COMPARE( e_read_buffer, e_read_length, e_arg->x, e_arg->len ); /* Do something with the key according to its type and permitted usage. */ if( ! exercise_key( handle, usage, alg ) ) goto exit; /* Export the key and check the public exponent. */ PSA_ASSERT( psa_export_public_key( handle, exported, exported_size, &exported_length ) ); { uint8_t *p = exported; uint8_t *end = exported + exported_length; size_t len; /* RSAPublicKey ::= SEQUENCE { * modulus INTEGER, -- n * publicExponent INTEGER } -- e */ TEST_EQUAL( 0, mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ); TEST_ASSERT( asn1_skip_integer( &p, end, bits, bits, 1 ) ); TEST_EQUAL( 0, mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_INTEGER ) ); if( len >= 1 && p[0] == 0 ) { ++p; --len; } if( e_arg->len == 0 ) { TEST_EQUAL( len, 3 ); TEST_EQUAL( p[0], 1 ); TEST_EQUAL( p[1], 0 ); TEST_EQUAL( p[2], 1 ); } else ASSERT_COMPARE( p, len, e_arg->x, e_arg->len ); } exit: psa_reset_key_attributes( &attributes ); psa_destroy_key( handle ); PSA_DONE( ); mbedtls_free( e_read_buffer ); mbedtls_free( exported ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */ void persistent_key_load_key_from_storage( data_t *data, int type_arg, int bits_arg, int usage_flags_arg, int alg_arg, int generation_method ) { psa_key_id_t key_id = 1; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_handle_t handle = 0; psa_key_handle_t base_key = 0; psa_key_type_t type = type_arg; size_t bits = bits_arg; psa_key_usage_t usage_flags = usage_flags_arg; psa_algorithm_t alg = alg_arg; psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; unsigned char *first_export = NULL; unsigned char *second_export = NULL; size_t export_size = PSA_KEY_EXPORT_MAX_SIZE( type, bits ); size_t first_exported_length; size_t second_exported_length; if( usage_flags & PSA_KEY_USAGE_EXPORT ) { ASSERT_ALLOC( first_export, export_size ); ASSERT_ALLOC( second_export, export_size ); } PSA_ASSERT( psa_crypto_init() ); psa_set_key_id( &attributes, key_id ); psa_set_key_usage_flags( &attributes, usage_flags ); psa_set_key_algorithm( &attributes, alg ); psa_set_key_type( &attributes, type ); psa_set_key_bits( &attributes, bits ); switch( generation_method ) { case IMPORT_KEY: /* Import the key */ PSA_ASSERT( psa_import_key( &attributes, data->x, data->len, &handle ) ); break; case GENERATE_KEY: /* Generate a key */ PSA_ASSERT( psa_generate_key( &attributes, &handle ) ); break; case DERIVE_KEY: { /* Create base key */ psa_algorithm_t derive_alg = PSA_ALG_HKDF( PSA_ALG_SHA_256 ); psa_key_attributes_t base_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_usage_flags( &base_attributes, PSA_KEY_USAGE_DERIVE ); psa_set_key_algorithm( &base_attributes, derive_alg ); psa_set_key_type( &base_attributes, PSA_KEY_TYPE_DERIVE ); PSA_ASSERT( psa_import_key( &base_attributes, data->x, data->len, &base_key ) ); /* Derive a key. */ PSA_ASSERT( psa_key_derivation_setup( &operation, derive_alg ) ); PSA_ASSERT( psa_key_derivation_input_key( &operation, PSA_KEY_DERIVATION_INPUT_SECRET, base_key ) ); PSA_ASSERT( psa_key_derivation_input_bytes( &operation, PSA_KEY_DERIVATION_INPUT_INFO, NULL, 0 ) ); PSA_ASSERT( psa_key_derivation_output_key( &attributes, &operation, &handle ) ); PSA_ASSERT( psa_key_derivation_abort( &operation ) ); PSA_ASSERT( psa_destroy_key( base_key ) ); base_key = 0; } break; } psa_reset_key_attributes( &attributes ); /* Export the key if permitted by the key policy. */ if( usage_flags & PSA_KEY_USAGE_EXPORT ) { PSA_ASSERT( psa_export_key( handle, first_export, export_size, &first_exported_length ) ); if( generation_method == IMPORT_KEY ) ASSERT_COMPARE( data->x, data->len, first_export, first_exported_length ); } /* Shutdown and restart */ PSA_ASSERT( psa_close_key( handle ) ); PSA_DONE(); PSA_ASSERT( psa_crypto_init() ); /* Check key slot still contains key data */ PSA_ASSERT( psa_open_key( key_id, &handle ) ); PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) ); TEST_EQUAL( psa_get_key_id( &attributes ), key_id ); TEST_EQUAL( psa_get_key_lifetime( &attributes ), PSA_KEY_LIFETIME_PERSISTENT ); TEST_EQUAL( psa_get_key_type( &attributes ), type ); TEST_EQUAL( psa_get_key_bits( &attributes ), bits ); TEST_EQUAL( psa_get_key_usage_flags( &attributes ), usage_flags ); TEST_EQUAL( psa_get_key_algorithm( &attributes ), alg ); /* Export the key again if permitted by the key policy. */ if( usage_flags & PSA_KEY_USAGE_EXPORT ) { PSA_ASSERT( psa_export_key( handle, second_export, export_size, &second_exported_length ) ); ASSERT_COMPARE( first_export, first_exported_length, second_export, second_exported_length ); } /* Do something with the key according to its type and permitted usage. */ if( ! exercise_key( handle, usage_flags, alg ) ) goto exit; exit: psa_reset_key_attributes( &attributes ); mbedtls_free( first_export ); mbedtls_free( second_export ); psa_key_derivation_abort( &operation ); psa_destroy_key( base_key ); if( handle == 0 ) { /* In case there was a test failure after creating the persistent key * but while it was not open, try to re-open the persistent key * to delete it. */ psa_open_key( key_id, &handle ); } psa_destroy_key( handle ); PSA_DONE(); } /* END_CASE */