diff --git a/library/cipher.c b/library/cipher.c index 63f1f411d..e854cf669 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -1236,7 +1236,7 @@ int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, (mbedtls_cipher_context_psa *) ctx->cipher_ctx; psa_status_t status; - psa_cipher_operation_t cipher_op; + psa_cipher_operation_t cipher_op = PSA_CIPHER_OPERATION_INIT; size_t part_len; if( ctx->operation == MBEDTLS_DECRYPT ) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index cfa07a6ee..22b4c0cf8 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -1373,7 +1373,13 @@ psa_status_t psa_hash_setup( psa_hash_operation_t *operation, psa_algorithm_t alg ) { int ret; - operation->alg = 0; + + /* A context must be freshly initialized before it can be set up. */ + if( operation->alg != 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + switch( alg ) { #if defined(MBEDTLS_MD2_C) @@ -1496,8 +1502,7 @@ psa_status_t psa_hash_update( psa_hash_operation_t *operation, break; #endif default: - ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA; - break; + return( PSA_ERROR_BAD_STATE ); } if( ret != 0 ) @@ -1569,8 +1574,7 @@ psa_status_t psa_hash_finish( psa_hash_operation_t *operation, break; #endif default: - ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA; - break; + return( PSA_ERROR_BAD_STATE ); } status = mbedtls_to_psa_error( ret ); @@ -1994,6 +1998,12 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation, unsigned char truncated = PSA_MAC_TRUNCATED_LENGTH( alg ); psa_algorithm_t full_length_alg = PSA_ALG_FULL_LENGTH_MAC( alg ); + /* A context must be freshly initialized before it can be set up. */ + if( operation->alg != 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + status = psa_mac_init( operation, full_length_alg ); if( status != PSA_SUCCESS ) return( status ); @@ -2112,9 +2122,9 @@ psa_status_t psa_mac_update( psa_mac_operation_t *operation, { psa_status_t status = PSA_ERROR_BAD_STATE; if( ! operation->key_set ) - goto cleanup; + return( PSA_ERROR_BAD_STATE ); if( operation->iv_required && ! operation->iv_set ) - goto cleanup; + return( PSA_ERROR_BAD_STATE ); operation->has_input = 1; #if defined(MBEDTLS_CMAC_C) @@ -2137,10 +2147,9 @@ psa_status_t psa_mac_update( psa_mac_operation_t *operation, { /* This shouldn't happen if `operation` was initialized by * a setup function. */ - status = PSA_ERROR_BAD_STATE; + return( PSA_ERROR_BAD_STATE ); } -cleanup: if( status != PSA_SUCCESS ) psa_mac_abort( operation ); return( status ); @@ -2232,6 +2241,11 @@ psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation, { psa_status_t status; + if( operation->alg == 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + /* Fill the output buffer with something that isn't a valid mac * (barring an attack on the mac and deliberately-crafted input), * in case the caller doesn't check the return status properly. */ @@ -2243,13 +2257,11 @@ psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation, if( ! operation->is_sign ) { - status = PSA_ERROR_BAD_STATE; - goto cleanup; + return( PSA_ERROR_BAD_STATE ); } status = psa_mac_finish_internal( operation, mac, mac_size ); -cleanup: if( status == PSA_SUCCESS ) { status = psa_mac_abort( operation ); @@ -2270,10 +2282,14 @@ psa_status_t psa_mac_verify_finish( psa_mac_operation_t *operation, uint8_t actual_mac[PSA_MAC_MAX_SIZE]; psa_status_t status; + if( operation->alg == 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + if( operation->is_sign ) { - status = PSA_ERROR_BAD_STATE; - goto cleanup; + return( PSA_ERROR_BAD_STATE ); } if( operation->mac_size != mac_length ) { @@ -2895,6 +2911,12 @@ static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation, PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_DECRYPT ); + /* A context must be freshly initialized before it can be set up. */ + if( operation->alg != 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + status = psa_cipher_init( operation, alg ); if( status != PSA_SUCCESS ) return( status ); @@ -2996,8 +3018,7 @@ psa_status_t psa_cipher_generate_iv( psa_cipher_operation_t *operation, int ret; if( operation->iv_set || ! operation->iv_required ) { - status = PSA_ERROR_BAD_STATE; - goto exit; + return( PSA_ERROR_BAD_STATE ); } if( iv_size < operation->iv_size ) { @@ -3029,8 +3050,7 @@ psa_status_t psa_cipher_set_iv( psa_cipher_operation_t *operation, int ret; if( operation->iv_set || ! operation->iv_required ) { - status = PSA_ERROR_BAD_STATE; - goto exit; + return( PSA_ERROR_BAD_STATE ); } if( iv_length != operation->iv_size ) { @@ -3057,6 +3077,12 @@ psa_status_t psa_cipher_update( psa_cipher_operation_t *operation, psa_status_t status; int ret; size_t expected_output_size; + + if( operation->alg == 0 ) + { + return( PSA_ERROR_BAD_STATE ); + } + if( ! PSA_ALG_IS_STREAM_CIPHER( operation->alg ) ) { /* Take the unprocessed partial block left over from previous @@ -3098,13 +3124,11 @@ psa_status_t psa_cipher_finish( psa_cipher_operation_t *operation, if( ! operation->key_set ) { - status = PSA_ERROR_BAD_STATE; - goto error; + return( PSA_ERROR_BAD_STATE ); } if( operation->iv_required && ! operation->iv_set ) { - status = PSA_ERROR_BAD_STATE; - goto error; + return( PSA_ERROR_BAD_STATE ); } if( operation->ctx.cipher.operation == MBEDTLS_ENCRYPT && diff --git a/library/ssl_tls.c b/library/ssl_tls.c index f224d5e94..a0d2617c9 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6529,7 +6529,7 @@ static void ssl_calc_finished_tls_sha256( unsigned char padbuf[32]; #if defined(MBEDTLS_USE_PSA_CRYPTO) size_t hash_size; - psa_hash_operation_t sha256_psa; + psa_hash_operation_t sha256_psa = PSA_HASH_OPERATION_INIT; psa_status_t status; #else mbedtls_sha256_context sha256; @@ -6605,7 +6605,7 @@ static void ssl_calc_finished_tls_sha384( unsigned char padbuf[48]; #if defined(MBEDTLS_USE_PSA_CRYPTO) size_t hash_size; - psa_hash_operation_t sha384_psa; + psa_hash_operation_t sha384_psa = PSA_HASH_OPERATION_INIT; psa_status_t status; #else mbedtls_sha512_context sha512; @@ -10203,7 +10203,7 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, mbedtls_md_type_t md_alg ) { psa_status_t status; - psa_hash_operation_t hash_operation; + psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; psa_algorithm_t hash_alg = mbedtls_psa_translate_md( md_alg ); MBEDTLS_SSL_DEBUG_MSG( 1, ( "Perform PSA-based computation of digest of ServerKeyExchange" ) ); diff --git a/library/x509_crt.c b/library/x509_crt.c index 1b1f0a771..1f853baa3 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1908,7 +1908,7 @@ static int x509_crt_check_signature( const mbedtls_x509_crt *child, if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) return( -1 ); #else - psa_hash_operation_t hash_operation; + psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; psa_algorithm_t hash_alg = mbedtls_psa_translate_md( child->sig_md ); if( psa_hash_setup( &hash_operation, hash_alg ) != PSA_SUCCESS ) diff --git a/library/x509write_csr.c b/library/x509write_csr.c index f2950ad2f..777a6325f 100644 --- a/library/x509write_csr.c +++ b/library/x509write_csr.c @@ -142,7 +142,7 @@ int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, s size_t len = 0; mbedtls_pk_type_t pk_alg; #if defined(MBEDTLS_USE_PSA_CRYPTO) - psa_hash_operation_t hash_operation; + psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; size_t hash_len; psa_algorithm_t hash_alg = mbedtls_psa_translate_md( ctx->md_alg ); #endif /* MBEDTLS_USE_PSA_CRYPTO */ diff --git a/programs/psa/crypto_examples.c b/programs/psa/crypto_examples.c index 9947a70bc..090875613 100644 --- a/programs/psa/crypto_examples.c +++ b/programs/psa/crypto_examples.c @@ -109,7 +109,7 @@ static psa_status_t cipher_encrypt( psa_key_handle_t key_handle, size_t *output_len ) { psa_status_t status; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; size_t iv_len = 0; memset( &operation, 0, sizeof( operation ) ); @@ -140,7 +140,7 @@ static psa_status_t cipher_decrypt( psa_key_handle_t key_handle, size_t *output_len ) { psa_status_t status; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; memset( &operation, 0, sizeof( operation ) ); status = psa_cipher_decrypt_setup( &operation, key_handle, alg ); diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 83ce15873..65ac6d7fb 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -655,6 +655,7 @@ depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C hash_setup:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_ERROR_INVALID_ARGUMENT PSA hash: bad order function calls +depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C hash_bad_order: PSA hash verify: bad arguments @@ -705,6 +706,10 @@ depends_on:MBEDTLS_CMAC_C # Either INVALID_ARGUMENT or NOT_SUPPORTED would be reasonable here mac_setup:PSA_KEY_TYPE_HMAC:"000102030405060708090a0b0c0d0e0f":PSA_ALG_CMAC:PSA_ERROR_NOT_SUPPORTED +PSA MAC: bad order function calls +depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C +mac_bad_order: + PSA MAC sign: RFC4231 Test case 1 - HMAC-SHA-224 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C mac_sign:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_HMAC(PSA_ALG_SHA_224):"4869205468657265":"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22" @@ -922,6 +927,10 @@ depends_on:MBEDTLS_ARC4_C:MBEDTLS_CIPHER_MODE_CTR # Either INVALID_ARGUMENT or NOT_SUPPORTED would be reasonable here cipher_setup:PSA_KEY_TYPE_ARC4:"000102030405060708090a0b0c0d0e0f":PSA_ALG_CTR:PSA_ERROR_NOT_SUPPORTED +PSA cipher: bad order function calls +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC +cipher_bad_order: + PSA symmetric encrypt: AES-CBC-nopad, 16 bytes, good depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC cipher_encrypt:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a":"a076ec9dfbe47d52afc357336f20743b":PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index d900f4d79..5c662d8f1 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1950,6 +1950,7 @@ exit: /* 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 @@ -1960,6 +1961,14 @@ void hash_operation_init( ) 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 ) ); @@ -1990,32 +1999,85 @@ exit: /* BEGIN_CASE */ void hash_bad_order( ) { + psa_algorithm_t alg = PSA_ALG_SHA_256; unsigned char input[] = ""; /* SHA-256 hash of an empty string */ - unsigned char hash[] = { + 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( ) ); - /* psa_hash_update without calling psa_hash_setup beforehand */ - memset( &operation, 0, sizeof( operation ) ); + /* 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_INVALID_ARGUMENT ); + PSA_ERROR_BAD_STATE ); + PSA_ASSERT( psa_hash_abort( &operation ) ); - /* psa_hash_verify without calling psa_hash_setup beforehand */ - memset( &operation, 0, sizeof( operation ) ); - TEST_EQUAL( psa_hash_verify( &operation, hash, sizeof( hash ) ), - PSA_ERROR_INVALID_ARGUMENT ); + /* 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 ) ); - /* psa_hash_finish without calling psa_hash_setup beforehand */ - memset( &operation, 0, sizeof( 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_INVALID_ARGUMENT ); + 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: mbedtls_psa_crypto_free( ); @@ -2168,6 +2230,8 @@ exit: /* 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 @@ -2178,6 +2242,17 @@ void mac_operation_init( ) 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 ) ); @@ -2220,6 +2295,130 @@ exit: } /* 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_policy_t policy = PSA_KEY_POLICY_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_ASSERT( psa_allocate_key( &handle ) ); + psa_key_policy_set_usage( &policy, + PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY, + alg ); + PSA_ASSERT( psa_set_key_policy( handle, &policy ) ); + + PSA_ASSERT( psa_import_key( handle, key_type, + key, sizeof(key) ) ); + + /* 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 ) ); + +exit: + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mac_sign( int key_type_arg, data_t *key, @@ -2318,6 +2517,9 @@ exit: /* 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 @@ -2328,6 +2530,23 @@ void cipher_operation_init( ) 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 ) ); @@ -2368,6 +2587,159 @@ exit: } /* 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_policy_t policy = PSA_KEY_POLICY_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_ASSERT( psa_allocate_key( &handle ) ); + psa_key_policy_set_usage( &policy, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT, + alg ); + PSA_ASSERT( psa_set_key_policy( handle, &policy ) ); + PSA_ASSERT( psa_import_key( handle, key_type, + key, sizeof(key) ) ); + + + /* 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 ) ); + +exit: + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void cipher_encrypt( int alg_arg, int key_type_arg, data_t *key,