diff --git a/src/psa_aead.c b/src/psa_aead.c index 4daf9c5..b94d85c 100644 --- a/src/psa_aead.c +++ b/src/psa_aead.c @@ -95,6 +95,14 @@ static size_t wolfpsa_aead_tag_length(psa_algorithm_t alg) return PSA_ALG_AEAD_GET_TAG_LENGTH(alg); } +#ifdef HAVE_AESGCM +static int wolfpsa_aead_gcm_check_tag_size(size_t tag_length) +{ + return tag_length == 4 || tag_length == 8 || + (tag_length >= 12 && tag_length <= WC_AES_BLOCK_SIZE); +} +#endif + static psa_status_t wolfpsa_aead_check_key(psa_key_id_t key, psa_key_usage_t usage, psa_algorithm_t alg, @@ -262,6 +270,14 @@ static psa_status_t wolfpsa_aead_setup(psa_aead_operation_t *operation, return PSA_ERROR_INVALID_ARGUMENT; } #endif +#ifdef HAVE_AESGCM + if (PSA_ALG_AEAD_EQUAL(alg, PSA_ALG_GCM) && + !wolfpsa_aead_gcm_check_tag_size(ctx->tag_length)) { + wolfpsa_forcezero_free_key_data(key_data, key_data_length); + XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif ctx->key = (uint8_t *)XMALLOC(key_data_length, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -333,7 +349,7 @@ psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation, } if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_GCM)) { - if (nonce_length == 0 || nonce_length > PSA_AEAD_NONCE_MAX_SIZE) { + if (nonce_length < 12 || nonce_length > PSA_AEAD_NONCE_MAX_SIZE) { return PSA_ERROR_INVALID_ARGUMENT; } } diff --git a/src/psa_asymmetric.c b/src/psa_asymmetric.c index ebaad62..a2ad5d7 100644 --- a/src/psa_asymmetric.c +++ b/src/psa_asymmetric.c @@ -718,6 +718,26 @@ int wc_psa_get_ecc_curve_id(psa_key_type_t type, size_t bits) default: return ECC_CURVE_INVALID; } + + case PSA_ECC_FAMILY_MONTGOMERY: + switch (bits) { + case 255: + #ifdef HAVE_CURVE25519 + return ECC_X25519; + #else + return ECC_CURVE_INVALID; + #endif + + case 448: + #ifdef HAVE_CURVE448 + return ECC_X448; + #else + return ECC_CURVE_INVALID; + #endif + + default: + return ECC_CURVE_INVALID; + } default: return ECC_CURVE_INVALID; diff --git a/src/psa_asymmetric_api.c b/src/psa_asymmetric_api.c index 2fad3a0..1647f8c 100644 --- a/src/psa_asymmetric_api.c +++ b/src/psa_asymmetric_api.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) #include +#include "psa_size.h" #include "psa_trace.h" #include #include @@ -37,6 +38,29 @@ extern int wc_psa_get_ecc_curve_id(psa_key_type_t type, size_t bits); +#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \ + defined(HAVE_CURVE25519_SHARED_SECRET) +psa_status_t psa_asymmetric_key_agreement_x25519( + const uint8_t *private_key, + size_t private_key_length, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length); +#endif +#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \ + defined(HAVE_CURVE448_SHARED_SECRET) +psa_status_t psa_asymmetric_key_agreement_x448( + const uint8_t *private_key, + size_t private_key_length, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length); +#endif + psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type, size_t key_bits, const uint8_t *key_buffer, @@ -665,6 +689,41 @@ psa_status_t psa_raw_key_agreement(psa_algorithm_t alg, wolfpsa_forcezero_free_key_data(key_data, key_data_length); return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_data_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(peer_key_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) { + wolfpsa_forcezero_free_key_data(key_data, key_data_length); + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (PSA_KEY_TYPE_ECC_GET_FAMILY(attributes.type) == + PSA_ECC_FAMILY_MONTGOMERY) { + if (attributes.bits == 255) { +#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \ + defined(HAVE_CURVE25519_SHARED_SECRET) + status = psa_asymmetric_key_agreement_x25519( + key_data, key_data_length, peer_key, peer_key_length, output, + output_size, output_length); +#else + status = PSA_ERROR_NOT_SUPPORTED; +#endif + } + else if (attributes.bits == 448) { +#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \ + defined(HAVE_CURVE448_SHARED_SECRET) + status = psa_asymmetric_key_agreement_x448( + key_data, key_data_length, peer_key, peer_key_length, output, + output_size, output_length); +#else + status = PSA_ERROR_NOT_SUPPORTED; +#endif + } + else { + status = PSA_ERROR_NOT_SUPPORTED; + } + wolfpsa_forcezero_free_key_data(key_data, key_data_length); + return status; + } curve_id = wc_psa_get_ecc_curve_id(attributes.type, attributes.bits); if (curve_id == ECC_CURVE_INVALID) { @@ -782,7 +841,8 @@ psa_status_t psa_key_agreement(psa_key_id_t private_key, return PSA_ERROR_INSUFFICIENT_MEMORY; } - status = psa_raw_key_agreement(alg, private_key, peer_key, peer_key_length, + status = psa_raw_key_agreement(PSA_ALG_KEY_AGREEMENT_GET_BASE(alg), + private_key, peer_key, peer_key_length, secret, secret_len, &output_len); if (status != PSA_SUCCESS) { wc_ForceZero(secret, secret_len); @@ -813,6 +873,18 @@ psa_status_t psa_key_agreement(psa_key_id_t private_key, return status; } + if (PSA_ALG_IS_HKDF(kdf_alg) || PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) { + status = psa_key_derivation_input_bytes(&kdf_op, + PSA_KEY_DERIVATION_INPUT_SALT, + NULL, 0); + if (status != PSA_SUCCESS) { + wc_ForceZero(secret, secret_len); + XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + psa_key_derivation_abort(&kdf_op); + return status; + } + } + status = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_SECRET, secret, output_len); wc_ForceZero(secret, secret_len); @@ -822,6 +894,16 @@ psa_status_t psa_key_agreement(psa_key_id_t private_key, return status; } + if (PSA_ALG_IS_HKDF(kdf_alg) || PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) { + status = psa_key_derivation_input_bytes(&kdf_op, + PSA_KEY_DERIVATION_INPUT_INFO, + NULL, 0); + if (status != PSA_SUCCESS) { + psa_key_derivation_abort(&kdf_op); + return status; + } + } + status = psa_key_derivation_output_key(attributes, &kdf_op, key); psa_key_derivation_abort(&kdf_op); return status; diff --git a/src/psa_cipher.c b/src/psa_cipher.c index b46ba22..fe58f27 100644 --- a/src/psa_cipher.c +++ b/src/psa_cipher.c @@ -252,7 +252,14 @@ static psa_status_t wolfpsa_cipher_check_key( #endif if (attributes->type == PSA_KEY_TYPE_DES) { - if (*key_data_length != 16 && *key_data_length != 24) { + if (*key_data_length == 16) { + wolfpsa_forcezero_free_key_data(*key_data, *key_data_length); + *key_data = NULL; + *key_data_length = 0; + return PSA_ERROR_NOT_SUPPORTED; + } + + if (*key_data_length != 24) { wolfpsa_forcezero_free_key_data(*key_data, *key_data_length); *key_data = NULL; *key_data_length = 0; @@ -366,13 +373,7 @@ psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, #ifndef NO_DES3 byte des_key[DES3_KEY_SIZE]; - if (key_data_length == 16) { - XMEMCPY(des_key, key_data, 16); - XMEMCPY(des_key + 16, key_data, 8); - } - else { - XMEMCPY(des_key, key_data, DES3_KEY_SIZE); - } + XMEMCPY(des_key, key_data, DES3_KEY_SIZE); ret = wc_Des3Init(&ctx->des3, NULL, INVALID_DEVID); if (ret != 0) { @@ -515,13 +516,7 @@ psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation, #ifndef NO_DES3 byte des_key[DES3_KEY_SIZE]; - if (key_data_length == 16) { - XMEMCPY(des_key, key_data, 16); - XMEMCPY(des_key + 16, key_data, 8); - } - else { - XMEMCPY(des_key, key_data, DES3_KEY_SIZE); - } + XMEMCPY(des_key, key_data, DES3_KEY_SIZE); ret = wc_Des3Init(&ctx->des3, NULL, INVALID_DEVID); if (ret != 0) { diff --git a/src/psa_ed25519_ed448.c b/src/psa_ed25519_ed448.c index 9b3ca05..5cf9b30 100644 --- a/src/psa_ed25519_ed448.c +++ b/src/psa_ed25519_ed448.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) && (defined(HAVE_ED25519) || defined(HAVE_ED448)) #include +#include "psa_size.h" #include #include #include @@ -70,6 +71,11 @@ psa_status_t psa_asymmetric_sign_ed25519(psa_key_type_t key_type, key_bits != 255) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED25519 key */ ret = wc_ed25519_init(&ed_key); @@ -129,6 +135,11 @@ psa_status_t psa_asymmetric_verify_ed25519(psa_key_type_t key_type, key_bits != 255) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED25519 key */ @@ -193,6 +204,10 @@ psa_status_t psa_asymmetric_generate_key_ed25519(psa_key_type_t key_type, key_bits != 255) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED25519 key */ ret = wc_ed25519_init(&ed_key); @@ -261,6 +276,10 @@ psa_status_t psa_asymmetric_export_public_key_ed25519(psa_key_type_t key_type, key_bits != 255) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED25519 key */ ret = wc_ed25519_init(&ed_key); @@ -328,6 +347,11 @@ psa_status_t psa_asymmetric_sign_ed448(psa_key_type_t key_type, key_bits != 448) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED448 key */ ret = wc_ed448_init(&ed_key); @@ -387,6 +411,11 @@ psa_status_t psa_asymmetric_verify_ed448(psa_key_type_t key_type, key_bits != 448) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED448 key */ @@ -450,6 +479,10 @@ psa_status_t psa_asymmetric_generate_key_ed448(psa_key_type_t key_type, key_bits != 448) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED448 key */ ret = wc_ed448_init(&ed_key); @@ -518,6 +551,10 @@ psa_status_t psa_asymmetric_export_public_key_ed448(psa_key_type_t key_type, key_bits != 448) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ED448 key */ ret = wc_ed448_init(&ed_key); diff --git a/src/psa_hash_engine.c b/src/psa_hash_engine.c index 90a7960..d2f5654 100644 --- a/src/psa_hash_engine.c +++ b/src/psa_hash_engine.c @@ -637,6 +637,7 @@ psa_status_t psa_hash_finish(psa_hash_operation_t *operation, *hash_length = expected_hash_size; ctx->finalized = 1; psa_hash_cleanup_ctx(ctx); + wc_ForceZero(ctx, sizeof(*ctx)); XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); operation->opaque = (uintptr_t)NULL; diff --git a/src/psa_key_derivation.c b/src/psa_key_derivation.c index cf73f9b..d574997 100644 --- a/src/psa_key_derivation.c +++ b/src/psa_key_derivation.c @@ -359,7 +359,7 @@ psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation, { wolfpsa_kdf_ctx_t *ctx; psa_algorithm_t kdf_alg = alg; - int hash_type; + int hash_type = WC_HASH_TYPE_NONE; if (operation == NULL) { return PSA_ERROR_INVALID_ARGUMENT; @@ -424,6 +424,20 @@ psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation, } } ctx->capacity = PSA_KEY_DERIVATION_UNLIMITED_CAPACITY; + if (PSA_ALG_IS_ANY_HKDF(kdf_alg)) { + int hash_len = wc_HashGetDigestSize(hash_type); + + if (hash_len <= 0) { + XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return PSA_ERROR_NOT_SUPPORTED; + } + if (PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) { + ctx->capacity = (size_t)hash_len; + } + else { + ctx->capacity = 255u * (size_t)hash_len; + } + } operation->opaque = (uintptr_t)ctx; return PSA_SUCCESS; @@ -482,6 +496,9 @@ psa_status_t psa_key_derivation_set_capacity(psa_key_derivation_operation_t *ope return PSA_ERROR_INVALID_ARGUMENT; } } + if (capacity > ctx->capacity) { + return PSA_ERROR_INVALID_ARGUMENT; + } ctx->capacity = capacity; return PSA_SUCCESS; @@ -985,6 +1002,12 @@ static psa_status_t wolfpsa_kdf_pbkdf2(wolfpsa_kdf_ctx_t *ctx, if (hash_type == WC_HASH_TYPE_NONE) { return PSA_ERROR_NOT_SUPPORTED; } + if (ctx->password_length > (size_t)INT_MAX || + ctx->salt_length > (size_t)INT_MAX || + ctx->cost > (uint32_t)INT_MAX || + output_length > (size_t)INT_MAX) { + return PSA_ERROR_INVALID_ARGUMENT; + } ret = wc_PBKDF2(output, password, (int)ctx->password_length, salt, (int)ctx->salt_length, (int)ctx->cost, (int)output_length, hash_type); @@ -1332,11 +1355,18 @@ psa_status_t psa_key_derivation_verify_bytes(psa_key_derivation_operation_t *ope size_t expected_length) { uint8_t *buffer; + uint8_t dummy = 0; psa_status_t status; if (expected == NULL) { return PSA_ERROR_INVALID_ARGUMENT; } + if (expected_length > INT_MAX) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (expected_length == 0) { + return psa_key_derivation_output_bytes(operation, &dummy, 0); + } buffer = (uint8_t *)XMALLOC(expected_length, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buffer == NULL) { @@ -1350,12 +1380,6 @@ psa_status_t psa_key_derivation_verify_bytes(psa_key_derivation_operation_t *ope return status; } - if (expected_length > INT_MAX) { - wc_ForceZero(buffer, expected_length); - XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return PSA_ERROR_INVALID_ARGUMENT; - } - if (ConstantCompare(buffer, expected, (int)expected_length) != 0) { status = PSA_ERROR_INVALID_SIGNATURE; } diff --git a/src/psa_key_storage.c b/src/psa_key_storage.c index d1534e8..4de0b83 100644 --- a/src/psa_key_storage.c +++ b/src/psa_key_storage.c @@ -115,6 +115,42 @@ psa_status_t psa_asymmetric_export_public_key_ed448(psa_key_type_t key_type, size_t output_size, size_t *output_length); #endif +#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \ + defined(HAVE_CURVE25519_KEY_EXPORT) +psa_status_t psa_asymmetric_generate_key_x25519(psa_key_type_t key_type, + size_t key_bits, + uint8_t *private_key, + size_t private_key_size, + size_t *private_key_length, + uint8_t *public_key, + size_t public_key_size, + size_t *public_key_length); +psa_status_t psa_asymmetric_export_public_key_x25519(psa_key_type_t key_type, + size_t key_bits, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *output, + size_t output_size, + size_t *output_length); +#endif +#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \ + defined(HAVE_CURVE448_KEY_EXPORT) +psa_status_t psa_asymmetric_generate_key_x448(psa_key_type_t key_type, + size_t key_bits, + uint8_t *private_key, + size_t private_key_size, + size_t *private_key_length, + uint8_t *public_key, + size_t public_key_size, + size_t *public_key_length); +psa_status_t psa_asymmetric_export_public_key_x448(psa_key_type_t key_type, + size_t key_bits, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *output, + size_t output_size, + size_t *output_length); +#endif static psa_status_t psa_wc_error_to_psa_status(int ret) { @@ -821,7 +857,7 @@ psa_status_t psa_import_key( uint8_t* buffer = NULL; size_t buffer_size; size_t attr_length; - int ret; + int ret = 0; void* store = NULL; psa_key_attributes_t attr; @@ -841,6 +877,10 @@ psa_status_t psa_import_key( data_length); return PSA_ERROR_NOT_SUPPORTED; } + if (!wolfpsa_usage_flags_valid(psa_get_key_usage_flags(&attr))) { + wolfpsa_debug_import_reason("invalid usage flags", &attr, data_length); + return PSA_ERROR_INVALID_ARGUMENT; + } if (attr.type == PSA_KEY_TYPE_NONE) { wolfpsa_debug_import_reason("unsupported key type", &attr, data_length); @@ -880,7 +920,12 @@ psa_status_t psa_import_key( } } else if (attr.type == PSA_KEY_TYPE_DES) { - if (data_length != 16 && data_length != 24) { + if (data_length == 16) { + wolfpsa_debug_import_reason("2-key 3DES is not supported", &attr, + data_length); + return PSA_ERROR_NOT_SUPPORTED; + } + if (data_length != 24) { wolfpsa_debug_import_reason("invalid DES key length", &attr, data_length); return PSA_ERROR_INVALID_ARGUMENT; } @@ -934,9 +979,9 @@ psa_status_t psa_import_key( if (PSA_KEY_LIFETIME_IS_VOLATILE(attr.lifetime)) { status = wolfpsa_volatile_store(*key_id, &attr, data, data_length); - ret = status == PSA_SUCCESS - ? (int)(attr_length + sizeof(size_t) + data_length) - : -1; + if (status == PSA_SUCCESS) { + ret = (int)(attr_length + sizeof(size_t) + data_length); + } } else { /* Open and write key to persistent storage */ @@ -952,6 +997,11 @@ psa_status_t psa_import_key( wc_ForceZero(buffer, buffer_size); XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (status != PSA_SUCCESS) { + *key_id = PSA_KEY_ID_NULL; + return status; + } if (ret < 0 || (size_t)ret != (attr_length + sizeof(size_t) + data_length)) { *key_id = PSA_KEY_ID_NULL; @@ -1081,6 +1131,12 @@ psa_status_t psa_generate_key( return PSA_ERROR_INVALID_ARGUMENT; } } + else if (family == PSA_ECC_FAMILY_MONTGOMERY) { + if (key_bits != 255 && key_bits != 448) { + return PSA_ERROR_INVALID_ARGUMENT; + } + pub_buf_size = PSA_BITS_TO_BYTES(key_bits); + } key_data = (uint8_t *)XMALLOC(priv_buf_size, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -1116,6 +1172,31 @@ psa_status_t psa_generate_key( &pub_len); #else status = PSA_ERROR_NOT_SUPPORTED; +#endif + } + else { + status = PSA_ERROR_INVALID_ARGUMENT; + } + } + else if (family == PSA_ECC_FAMILY_MONTGOMERY) { + if (key_bits == 255) { +#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \ + defined(HAVE_CURVE25519_KEY_EXPORT) + status = psa_asymmetric_generate_key_x25519( + key_type, key_bits, key_data, priv_buf_size, &priv_len, + pub_buf, pub_buf_size, &pub_len); +#else + status = PSA_ERROR_NOT_SUPPORTED; +#endif + } + else if (key_bits == 448) { +#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \ + defined(HAVE_CURVE448_KEY_EXPORT) + status = psa_asymmetric_generate_key_x448( + key_type, key_bits, key_data, priv_buf_size, &priv_len, + pub_buf, pub_buf_size, &pub_len); +#else + status = PSA_ERROR_NOT_SUPPORTED; #endif } else { @@ -1513,6 +1594,30 @@ psa_status_t psa_export_public_key( status = PSA_ERROR_NOT_SUPPORTED; } } + else if (family == PSA_ECC_FAMILY_MONTGOMERY) { + #if defined(HAVE_CURVE25519) && \ + defined(HAVE_CURVE25519_KEY_IMPORT) && \ + defined(HAVE_CURVE25519_KEY_EXPORT) + if (attributes.bits == 255) { + status = psa_asymmetric_export_public_key_x25519( + attributes.type, attributes.bits, key_data, + key_data_length, data, data_size, data_length); + } + else + #endif + #if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \ + defined(HAVE_CURVE448_KEY_EXPORT) + if (attributes.bits == 448) { + status = psa_asymmetric_export_public_key_x448( + attributes.type, attributes.bits, key_data, + key_data_length, data, data_size, data_length); + } + else + #endif + { + status = PSA_ERROR_NOT_SUPPORTED; + } + } else { ecc_key ecc; word32 out_len = (word32)data_size; @@ -1661,7 +1766,7 @@ psa_status_t psa_copy_key( return PSA_ERROR_NOT_PERMITTED; } - if (attributes->type != vol_attr.type) { + if (attributes->type != 0 && attributes->type != vol_attr.type) { wolfpsa_forcezero_free_key_data(key_data, key_data_length); return PSA_ERROR_INVALID_ARGUMENT; } @@ -1681,6 +1786,7 @@ psa_status_t psa_copy_key( return PSA_ERROR_INVALID_ARGUMENT; } + dst_attr.type = (dst_attr.type == 0) ? vol_attr.type : dst_attr.type; dst_attr.bits = (dst_attr.bits == 0) ? vol_attr.bits : dst_attr.bits; dst_attr.policy.usage = psa_get_key_usage_flags(&vol_attr) & psa_get_key_usage_flags(&dst_attr); @@ -1722,7 +1828,7 @@ psa_status_t psa_copy_key( return PSA_ERROR_NOT_PERMITTED; } - if (attributes->type != src_attr.type) { + if (attributes->type != 0 && attributes->type != src_attr.type) { wolfPSA_Store_Close(store); return PSA_ERROR_INVALID_ARGUMENT; } @@ -1743,6 +1849,7 @@ psa_status_t psa_copy_key( } dst_attr = *attributes; + dst_attr.type = (dst_attr.type == 0) ? src_attr.type : dst_attr.type; dst_attr.bits = (dst_attr.bits == 0) ? src_attr.bits : dst_attr.bits; dst_attr.policy.usage = psa_get_key_usage_flags(&src_attr) & psa_get_key_usage_flags(&dst_attr); diff --git a/src/psa_mac.c b/src/psa_mac.c index dacef17..ed9828a 100644 --- a/src/psa_mac.c +++ b/src/psa_mac.c @@ -477,6 +477,7 @@ psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, uint8_t computed[PSA_MAC_MAX_SIZE]; size_t computed_length = 0; size_t min_length; + size_t compare_length; psa_status_t status = PSA_ERROR_BAD_STATE; if (ctx == NULL) { @@ -500,8 +501,13 @@ psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, } } + compare_length = ctx->mac_length; + if ((ctx->alg & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) != 0) { + ctx->mac_length = ctx->full_length; + } status = wolfpsa_mac_final(ctx, computed, sizeof(computed), &computed_length); + ctx->mac_length = compare_length; psa_mac_abort(operation); if (status != PSA_SUCCESS) { goto cleanup; diff --git a/src/psa_mldsa.c b/src/psa_mldsa.c index 51143e9..5f99bfa 100644 --- a/src/psa_mldsa.c +++ b/src/psa_mldsa.c @@ -25,7 +25,9 @@ #include -#if defined(WOLFSSL_PSA_ENGINE) && defined(WOLFSSL_HAVE_DILITHIUM) +#if defined(WOLFSSL_PSA_ENGINE) && \ + (defined(WOLFSSL_HAVE_DILITHIUM) || defined(HAVE_DILITHIUM) || \ + defined(WOLFSSL_WC_DILITHIUM)) #include #include "psa_size.h" @@ -43,11 +45,11 @@ static int psa_ml_dsa_parameter_to_type(psa_ml_dsa_parameter_t parameter) { switch (parameter) { case PSA_ML_DSA_PARAMETER_2: - return DILITHIUM_LEVEL2; + return WC_ML_DSA_44; case PSA_ML_DSA_PARAMETER_3: - return DILITHIUM_LEVEL3; + return WC_ML_DSA_65; case PSA_ML_DSA_PARAMETER_5: - return DILITHIUM_LEVEL5; + return WC_ML_DSA_87; default: return -1; } @@ -80,10 +82,15 @@ psa_status_t psa_ml_dsa_generate_key(psa_ml_dsa_parameter_t parameter, } /* Initialize ML-DSA key */ - ret = wc_dilithium_init_ex(&key, type, NULL, INVALID_DEVID); + ret = wc_dilithium_init_ex(&key, NULL, INVALID_DEVID); if (ret != 0) { return wc_error_to_psa_status(ret); } + ret = wc_dilithium_set_level(&key, (byte)type); + if (ret != 0) { + wc_dilithium_free(&key); + return wc_error_to_psa_status(ret); + } /* Initialize RNG */ ret = wc_InitRng(&rng); @@ -93,7 +100,7 @@ psa_status_t psa_ml_dsa_generate_key(psa_ml_dsa_parameter_t parameter, } /* Generate key pair */ - ret = wc_dilithium_make_key(&rng, &key); + ret = wc_dilithium_make_key(&key, &rng); if (ret != 0) { wc_FreeRng(&rng); wc_dilithium_free(&key); @@ -137,6 +144,8 @@ psa_status_t psa_ml_dsa_sign(psa_ml_dsa_parameter_t parameter, int ret; dilithium_key key; int type; + int sig_size; + WC_RNG rng; word32 sigLen; /* Convert parameter to wolfCrypt key type */ @@ -151,8 +160,13 @@ psa_status_t psa_ml_dsa_sign(psa_ml_dsa_parameter_t parameter, } /* Initialize ML-DSA key */ - ret = wc_dilithium_init_ex(&key, type, NULL, INVALID_DEVID); + ret = wc_dilithium_init_ex(&key, NULL, INVALID_DEVID); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + ret = wc_dilithium_set_level(&key, (byte)type); if (ret != 0) { + wc_dilithium_free(&key); return wc_error_to_psa_status(ret); } @@ -164,21 +178,34 @@ psa_status_t psa_ml_dsa_sign(psa_ml_dsa_parameter_t parameter, } /* Check signature buffer size */ - if (signature_size < key.sig_len) { + sig_size = wc_dilithium_sig_size(&key); + if (sig_size < 0) { + wc_dilithium_free(&key); + return wc_error_to_psa_status(sig_size); + } + if (signature_size < (size_t)sig_size) { wc_dilithium_free(&key); return PSA_ERROR_BUFFER_TOO_SMALL; } + + ret = wc_InitRng(&rng); + if (ret != 0) { + wc_dilithium_free(&key); + return wc_error_to_psa_status(ret); + } - /* Sign message */ + /* Sign message (ML-DSA pure, empty context per FIPS 204) */ sigLen = (word32)signature_size; - ret = wc_dilithium_sign_msg(message, (word32)message_length, signature, - &sigLen, &key); + ret = wc_dilithium_sign_ctx_msg(NULL, 0, message, (word32)message_length, + signature, &sigLen, &key, &rng); if (ret != 0) { + wc_FreeRng(&rng); wc_dilithium_free(&key); return wc_error_to_psa_status(ret); } *signature_length = sigLen; + wc_FreeRng(&rng); wc_dilithium_free(&key); return PSA_SUCCESS; @@ -210,10 +237,15 @@ psa_status_t psa_ml_dsa_verify(psa_ml_dsa_parameter_t parameter, } /* Initialize ML-DSA key */ - ret = wc_dilithium_init_ex(&key, type, NULL, INVALID_DEVID); + ret = wc_dilithium_init_ex(&key, NULL, INVALID_DEVID); if (ret != 0) { return wc_error_to_psa_status(ret); } + ret = wc_dilithium_set_level(&key, (byte)type); + if (ret != 0) { + wc_dilithium_free(&key); + return wc_error_to_psa_status(ret); + } /* Import public key */ ret = wc_dilithium_import_public(public_key, (word32)public_key_size, &key); @@ -222,9 +254,10 @@ psa_status_t psa_ml_dsa_verify(psa_ml_dsa_parameter_t parameter, return wc_error_to_psa_status(ret); } - /* Verify signature */ - ret = wc_dilithium_verify_msg(signature, (word32)signature_length, message, - (word32)message_length, &verify_res, &key); + /* Verify signature (ML-DSA pure, empty context per FIPS 204) */ + ret = wc_dilithium_verify_ctx_msg(signature, (word32)signature_length, + NULL, 0, message, (word32)message_length, + &verify_res, &key); wc_dilithium_free(&key); @@ -239,4 +272,4 @@ psa_status_t psa_ml_dsa_verify(psa_ml_dsa_parameter_t parameter, return PSA_SUCCESS; } -#endif /* WOLFSSL_PSA_ENGINE && WOLFSSL_HAVE_DILITHIUM */ +#endif /* WOLFSSL_PSA_ENGINE && DILITHIUM */ diff --git a/src/psa_mlkem.c b/src/psa_mlkem.c index 4ba4cd3..e8e5d83 100644 --- a/src/psa_mlkem.c +++ b/src/psa_mlkem.c @@ -72,6 +72,9 @@ psa_status_t psa_ml_kem_generate_key(psa_ml_kem_parameter_t parameter, if (type < 0) { return PSA_ERROR_NOT_SUPPORTED; } + if (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ML-KEM key */ ret = wc_MlKemKey_Init(&key, type, NULL, INVALID_DEVID); @@ -162,6 +165,9 @@ psa_status_t psa_ml_kem_encapsulate(psa_ml_kem_parameter_t parameter, if (type < 0) { return PSA_ERROR_NOT_SUPPORTED; } + if (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ML-KEM key */ ret = wc_MlKemKey_Init(&key, type, NULL, INVALID_DEVID); @@ -239,6 +245,10 @@ psa_status_t psa_ml_kem_decapsulate(psa_ml_kem_parameter_t parameter, if (type < 0) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ciphertext_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ML-KEM key */ ret = wc_MlKemKey_Init(&key, type, NULL, INVALID_DEVID); diff --git a/src/psa_montgomery.c b/src/psa_montgomery.c new file mode 100644 index 0000000..08e0641 --- /dev/null +++ b/src/psa_montgomery.c @@ -0,0 +1,433 @@ +/* psa_montgomery.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfPSA. + * + * wolfPSA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPSA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#if defined(WOLFSSL_PSA_ENGINE) && \ + (defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) + +#include +#include "psa_size.h" +#include +#include +#include +#include +#include + +#ifdef HAVE_CURVE25519 +#include +#endif + +#ifdef HAVE_CURVE448 +#include +#endif + +#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \ + defined(HAVE_CURVE25519_KEY_EXPORT) +psa_status_t psa_asymmetric_generate_key_x25519(psa_key_type_t key_type, + size_t key_bits, + uint8_t *private_key, + size_t private_key_size, + size_t *private_key_length, + uint8_t *public_key, + size_t public_key_size, + size_t *public_key_length) +{ + int ret; + curve25519_key key; + WC_RNG rng; + word32 priv_len; + word32 pub_len; + + if (key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY) || + key_bits != 255) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (private_key == NULL || private_key_length == NULL || + public_key == NULL || public_key_length == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + priv_len = (word32)private_key_size; + pub_len = (word32)public_key_size; + + ret = wc_curve25519_init(&key); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + ret = wc_InitRng(&rng); + if (ret != 0) { + wc_curve25519_free(&key); + return wc_error_to_psa_status(ret); + } + + ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &key); + if (ret == 0) { + ret = wc_curve25519_export_private_raw_ex(&key, private_key, + &priv_len, + EC25519_LITTLE_ENDIAN); + } + if (ret == 0) { + ret = wc_curve25519_export_public_ex(&key, public_key, &pub_len, + EC25519_LITTLE_ENDIAN); + } + + wc_FreeRng(&rng); + wc_curve25519_free(&key); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + + *private_key_length = (size_t)priv_len; + *public_key_length = (size_t)pub_len; + return PSA_SUCCESS; +} + +psa_status_t psa_asymmetric_export_public_key_x25519(psa_key_type_t key_type, + size_t key_bits, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + int ret; + uint8_t priv[CURVE25519_KEYSIZE]; + + if ((key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY) && + key_type != PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_MONTGOMERY)) || + key_bits != 255) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (key_buffer == NULL || output == NULL || output_length == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (output_size < CURVE25519_KEYSIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if (key_type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY)) { + if (key_buffer_size != CURVE25519_KEYSIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + XMEMCPY(priv, key_buffer, CURVE25519_KEYSIZE); + priv[0] &= 248; + priv[31] &= 127; + priv[31] |= 64; + ret = wc_curve25519_make_pub(CURVE25519_KEYSIZE, output, + CURVE25519_KEYSIZE, priv); + wc_ForceZero(priv, sizeof(priv)); + } + else { + if (key_buffer_size != CURVE25519_KEYSIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + XMEMCPY(output, key_buffer, CURVE25519_KEYSIZE); + ret = 0; + } + + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + + *output_length = CURVE25519_KEYSIZE; + return PSA_SUCCESS; +} +#endif + +#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \ + defined(HAVE_CURVE25519_SHARED_SECRET) +psa_status_t psa_asymmetric_key_agreement_x25519( + const uint8_t *private_key, + size_t private_key_length, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + int ret; + curve25519_key priv; + curve25519_key pub; + uint8_t peer[CURVE25519_KEYSIZE]; + word32 out_len; +#ifdef WOLFSSL_CURVE25519_BLINDING + WC_RNG rng; +#endif + + if (private_key == NULL || peer_key == NULL || output == NULL || + output_length == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (private_key_length != CURVE25519_KEYSIZE || + peer_key_length != CURVE25519_KEYSIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (output_size < CURVE25519_KEYSIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + if (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } + out_len = (word32)output_size; + + ret = wc_curve25519_init(&priv); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + ret = wc_curve25519_init(&pub); + if (ret != 0) { + wc_curve25519_free(&priv); + return wc_error_to_psa_status(ret); + } +#ifdef WOLFSSL_CURVE25519_BLINDING + ret = wc_InitRng(&rng); + if (ret != 0) { + wc_curve25519_free(&pub); + wc_curve25519_free(&priv); + return wc_error_to_psa_status(ret); + } + ret = wc_curve25519_set_rng(&priv, &rng); + if (ret != 0) { + wc_FreeRng(&rng); + wc_curve25519_free(&pub); + wc_curve25519_free(&priv); + return wc_error_to_psa_status(ret); + } +#endif + + XMEMCPY(peer, peer_key, CURVE25519_KEYSIZE); + peer[CURVE25519_KEYSIZE - 1] &= 127; + + ret = wc_curve25519_import_private_ex(private_key, + (word32)private_key_length, &priv, + EC25519_LITTLE_ENDIAN); + if (ret == 0) { + ret = wc_curve25519_import_public_ex(peer, (word32)peer_key_length, + &pub, EC25519_LITTLE_ENDIAN); + } + if (ret == 0) { + ret = wc_curve25519_shared_secret_ex(&priv, &pub, output, &out_len, + EC25519_LITTLE_ENDIAN); + } + + wc_ForceZero(peer, sizeof(peer)); +#ifdef WOLFSSL_CURVE25519_BLINDING + wc_FreeRng(&rng); +#endif + wc_curve25519_free(&pub); + wc_curve25519_free(&priv); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + + *output_length = (size_t)out_len; + return PSA_SUCCESS; +} +#endif + +#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \ + defined(HAVE_CURVE448_KEY_EXPORT) +psa_status_t psa_asymmetric_generate_key_x448(psa_key_type_t key_type, + size_t key_bits, + uint8_t *private_key, + size_t private_key_size, + size_t *private_key_length, + uint8_t *public_key, + size_t public_key_size, + size_t *public_key_length) +{ + int ret; + curve448_key key; + WC_RNG rng; + word32 priv_len; + word32 pub_len; + + if (key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY) || + key_bits != 448) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (private_key == NULL || private_key_length == NULL || + public_key == NULL || public_key_length == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + priv_len = (word32)private_key_size; + pub_len = (word32)public_key_size; + + ret = wc_curve448_init(&key); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + ret = wc_InitRng(&rng); + if (ret != 0) { + wc_curve448_free(&key); + return wc_error_to_psa_status(ret); + } + + ret = wc_curve448_make_key(&rng, CURVE448_KEY_SIZE, &key); + if (ret == 0) { + ret = wc_curve448_export_private_raw_ex(&key, private_key, &priv_len, + EC448_LITTLE_ENDIAN); + } + if (ret == 0) { + ret = wc_curve448_export_public_ex(&key, public_key, &pub_len, + EC448_LITTLE_ENDIAN); + } + + wc_FreeRng(&rng); + wc_curve448_free(&key); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + + *private_key_length = (size_t)priv_len; + *public_key_length = (size_t)pub_len; + return PSA_SUCCESS; +} + +psa_status_t psa_asymmetric_export_public_key_x448(psa_key_type_t key_type, + size_t key_bits, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + int ret; + uint8_t priv[CURVE448_KEY_SIZE]; + + if ((key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY) && + key_type != PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_MONTGOMERY)) || + key_bits != 448) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (key_buffer == NULL || output == NULL || output_length == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (output_size < CURVE448_KEY_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if (key_type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY)) { + if (key_buffer_size != CURVE448_KEY_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + XMEMCPY(priv, key_buffer, CURVE448_KEY_SIZE); + priv[0] &= 252; + priv[55] |= 128; + ret = wc_curve448_make_pub(CURVE448_KEY_SIZE, output, + CURVE448_KEY_SIZE, priv); + wc_ForceZero(priv, sizeof(priv)); + } + else { + if (key_buffer_size != CURVE448_KEY_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + XMEMCPY(output, key_buffer, CURVE448_KEY_SIZE); + ret = 0; + } + + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + + *output_length = CURVE448_KEY_SIZE; + return PSA_SUCCESS; +} +#endif + +#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \ + defined(HAVE_CURVE448_SHARED_SECRET) +psa_status_t psa_asymmetric_key_agreement_x448( + const uint8_t *private_key, + size_t private_key_length, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + int ret; + curve448_key priv; + curve448_key pub; + word32 out_len; + + if (private_key == NULL || peer_key == NULL || output == NULL || + output_length == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (private_key_length != CURVE448_KEY_SIZE || + peer_key_length != CURVE448_KEY_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (output_size < CURVE448_KEY_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + if (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } + out_len = (word32)output_size; + + ret = wc_curve448_init(&priv); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + ret = wc_curve448_init(&pub); + if (ret != 0) { + wc_curve448_free(&priv); + return wc_error_to_psa_status(ret); + } + + ret = wc_curve448_import_private_ex(private_key, + (word32)private_key_length, &priv, + EC448_LITTLE_ENDIAN); + if (ret == 0) { + ret = wc_curve448_import_public_ex(peer_key, (word32)peer_key_length, + &pub, EC448_LITTLE_ENDIAN); + } + if (ret == 0) { + ret = wc_curve448_shared_secret_ex(&priv, &pub, output, &out_len, + EC448_LITTLE_ENDIAN); + } + + wc_curve448_free(&pub); + wc_curve448_free(&priv); + if (ret != 0) { + return wc_error_to_psa_status(ret); + } + + *output_length = (size_t)out_len; + return PSA_SUCCESS; +} +#endif + +#endif diff --git a/src/psa_rsa.c b/src/psa_rsa.c index 248d1ff..7eb9fe7 100644 --- a/src/psa_rsa.c +++ b/src/psa_rsa.c @@ -272,7 +272,7 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type, /* Verify signature */ if (padding == WC_RSA_PKCSV15_PAD) { - byte decoded[PSA_HASH_MAX_SIZE]; + byte decoded[RSA_MAX_SIZE/8]; if (alg == PSA_ALG_RSA_PKCS1V15_SIGN_RAW) { ret = wc_RsaSSL_Verify_ex(signature, (word32)signature_length, diff --git a/src/psa_store_posix.c b/src/psa_store_posix.c index 76fafb1..7951bea 100644 --- a/src/psa_store_posix.c +++ b/src/psa_store_posix.c @@ -56,6 +56,7 @@ typedef struct WOLFPSA_FileStoreCtx { XFILE file; int is_write; int has_temp; + int write_failed; char final_name[WOLFPSA_STORE_MAX_PATH]; char temp_name[WOLFPSA_STORE_MAX_PATH]; } WOLFPSA_FileStoreCtx; @@ -435,7 +436,7 @@ void wolfPSA_Store_Close(void* store) ctx->file = XBADFILE; } - if (ctx->is_write && ctx->has_temp) { + if (ctx->is_write && ctx->has_temp && ctx->write_failed == 0) { commitRet = wolfPSA_StoreCommitTemp(ctx); if (commitRet != 0) { wolfPSA_StoreAbortTemp(ctx); @@ -470,7 +471,13 @@ int wolfPSA_Store_Write(void* store, unsigned char* buffer, int len) if (ctx != NULL && ctx->file != XBADFILE && ctx->file != NULL) { ret = (int)XFWRITE(buffer, 1, len, ctx->file); if (ret == len) { - (void)XFFLUSH(ctx->file); + if (XFFLUSH(ctx->file) != 0) { + ctx->write_failed = 1; + ret = WOLFPSA_STORE_IO_ERROR; + } + } + else { + ctx->write_failed = 1; } } diff --git a/test/psa_server/psa_api_test.c b/test/psa_server/psa_api_test.c index 6f125f1..4fe716d 100644 --- a/test/psa_server/psa_api_test.c +++ b/test/psa_server/psa_api_test.c @@ -31,6 +31,10 @@ #include #include #include +#if !defined(_WIN32) && !defined(_MSC_VER) +#include +#include +#endif #include #include "psa_aead_internal.h" @@ -40,6 +44,10 @@ #include #include #include +#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_DILITHIUM) || \ + defined(WOLFSSL_WC_DILITHIUM) +#include +#endif #ifndef INVALID_DEVID #define INVALID_DEVID -2 @@ -50,6 +58,7 @@ #define TEST_SKIPPED 2 #define ED25519_PUBLIC_KEY_BYTES 32u #define ED448_PUBLIC_KEY_BYTES 57u +#define X25519_KEY_BYTES 32u typedef int (*test_fn_t)(void); @@ -149,9 +158,11 @@ static int test_hmac(void) static const uint8_t msg[] = "hmac message"; uint8_t expected[WC_SHA256_DIGEST_SIZE]; uint8_t out[WC_SHA256_DIGEST_SIZE]; + uint8_t bad_mac[WC_SHA256_DIGEST_SIZE]; size_t out_len = 0; psa_key_id_t key_id = 0; psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_mac_operation_t op = psa_mac_operation_init(); psa_status_t st; Hmac hmac; int ret; @@ -185,12 +196,102 @@ static int test_hmac(void) if (check_true(out_len == sizeof(expected), "psa_mac_compute length") != TEST_OK) return TEST_FAIL; if (check_buf_eq("psa_mac_compute", out, expected, sizeof(expected)) != TEST_OK) return TEST_FAIL; + st = psa_mac_verify(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + msg, sizeof(msg) - 1, out, out_len); + if (check_status(st, "psa_mac_verify") != TEST_OK) return TEST_FAIL; + + memcpy(bad_mac, out, out_len); + bad_mac[0] ^= 0x01u; + st = psa_mac_verify(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + msg, sizeof(msg) - 1, bad_mac, out_len); + if (check_true(st == PSA_ERROR_INVALID_SIGNATURE, + "psa_mac_verify rejects bad MAC") != TEST_OK) { + return TEST_FAIL; + } + + st = psa_mac_verify_setup(&op, key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + if (check_status(st, "psa_mac_verify_setup") != TEST_OK) return TEST_FAIL; + st = psa_mac_update(&op, msg, sizeof(msg) - 1); + if (check_status(st, "psa_mac_update(verify)") != TEST_OK) return TEST_FAIL; + st = psa_mac_verify_finish(&op, out, out_len - 1); + if (check_true(st == PSA_ERROR_INVALID_SIGNATURE, + "psa_mac_verify_finish rejects short MAC") != TEST_OK) { + (void)psa_mac_abort(&op); + return TEST_FAIL; + } + st = psa_destroy_key(key_id); if (check_status(st, "psa_destroy_key(HMAC)") != TEST_OK) return TEST_FAIL; return TEST_OK; } +static int test_mac_verify_finish_accepts_longer_at_least_length_mac(void) +{ + static const uint8_t key[] = { + 0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe, + 0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81 + }; + static const uint8_t msg[] = "at least length mac"; + uint8_t expected[WC_SHA256_DIGEST_SIZE]; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_mac_operation_t op = psa_mac_operation_init(); + psa_status_t st; + Hmac hmac; + int ret; + int result = TEST_FAIL; + + ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (ret != 0) { + printf("FAIL: wc_HmacInit(at least MAC) (%d)\n", ret); + return TEST_FAIL; + } + ret = wc_HmacSetKey(&hmac, WC_SHA256, key, sizeof(key)); + if (ret != 0) { + wc_HmacFree(&hmac); + printf("FAIL: wc_HmacSetKey(at least MAC) (%d)\n", ret); + return TEST_FAIL; + } + wc_HmacUpdate(&hmac, msg, (word32)sizeof(msg) - 1u); + wc_HmacFinal(&hmac, expected); + wc_HmacFree(&hmac); + + psa_set_key_type(&attrs, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attrs, (size_t)sizeof(key) * 8u); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_VERIFY_MESSAGE); + psa_set_key_algorithm(&attrs, + PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_256), 16)); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(HMAC at least length verify)") != TEST_OK) { + return TEST_FAIL; + } + + st = psa_mac_verify_setup(&op, key_id, + PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_256), 16)); + if (check_status(st, "psa_mac_verify_setup(at least length verify)") != TEST_OK) { + goto cleanup; + } + st = psa_mac_update(&op, msg, sizeof(msg) - 1u); + if (check_status(st, "psa_mac_update(at least length verify)") != TEST_OK) { + goto cleanup; + } + st = psa_mac_verify_finish(&op, expected, sizeof(expected)); + if (check_status(st, "psa_mac_verify_finish accepts longer at least-length MAC") != TEST_OK) { + goto cleanup; + } + + result = TEST_OK; + +cleanup: + (void)psa_mac_abort(&op); + if (key_id != 0) { + (void)psa_destroy_key(key_id); + } + return result; +} + static int test_hash_error_aborts_operation(void) { static const uint8_t msg[] = "hash error state"; @@ -579,6 +680,84 @@ static int test_cipher_rejects_algorithm_mismatch(void) return ret; } +static int test_cipher_requires_decrypt_usage(void) +{ + static const uint8_t key[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c + }; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_cipher_operation_t op = psa_cipher_operation_init(); + psa_status_t st; + int ret = TEST_FAIL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attrs, 128); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_CBC_NO_PADDING); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(AES encrypt-only)") != TEST_OK) { + goto cleanup; + } + + st = psa_cipher_decrypt_setup(&op, key_id, PSA_ALG_CBC_NO_PADDING); + if (check_true(st == PSA_ERROR_NOT_PERMITTED, + "psa_cipher_decrypt_setup requires decrypt usage") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + if (key_id != 0) { + (void)psa_destroy_key(key_id); + } + (void)psa_cipher_abort(&op); + return ret; +} + +static int test_cipher_rejects_non_aes_key_type(void) +{ + static const uint8_t key[32] = { + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67, + 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, + 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f + }; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_cipher_operation_t op = psa_cipher_operation_init(); + psa_status_t st; + int ret = TEST_FAIL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_CHACHA20); + psa_set_key_bits(&attrs, 256); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_STREAM_CIPHER); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(ChaCha20 for AES cipher mismatch)") != TEST_OK) { + return TEST_FAIL; + } + + st = psa_cipher_encrypt_setup(&op, key_id, PSA_ALG_CBC_NO_PADDING); + if (check_true(st == PSA_ERROR_NOT_SUPPORTED, + "psa_cipher_encrypt_setup rejects non-AES key for AES cipher") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + if (key_id != 0) { + (void)psa_destroy_key(key_id); + } + (void)psa_cipher_abort(&op); + return ret; +} + static int test_mac_rejects_algorithm_mismatch(void) { static const uint8_t hmac_key[16] = { @@ -642,6 +821,52 @@ static int test_mac_rejects_algorithm_mismatch(void) return ret; } +static int test_mac_requires_verify_usage(void) +{ + static const uint8_t hmac_key[16] = { + 0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe, + 0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81 + }; + static const uint8_t msg[] = "hmac message"; + uint8_t mac[WC_SHA256_DIGEST_SIZE]; + size_t mac_len = 0; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + int ret = TEST_FAIL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attrs, sizeof(hmac_key) * 8u); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_algorithm(&attrs, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + + st = psa_import_key(&attrs, hmac_key, sizeof(hmac_key), &key_id); + if (check_status(st, "psa_import_key(HMAC sign-only)") != TEST_OK) { + goto cleanup; + } + + st = psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + msg, sizeof(msg) - 1, mac, sizeof(mac), &mac_len); + if (check_status(st, "psa_mac_compute(sign-only)") != TEST_OK) { + goto cleanup; + } + + st = psa_mac_verify(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + msg, sizeof(msg) - 1, mac, mac_len); + if (check_true(st == PSA_ERROR_NOT_PERMITTED, + "psa_mac_verify requires verify usage") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + if (key_id != 0) { + (void)psa_destroy_key(key_id); + } + return ret; +} + static int test_export_key_requires_usage_flag(void) { static const uint8_t key[16] = { @@ -882,6 +1107,103 @@ static int test_export_key_rejects_oversized_persistent_length(void) return ret; } +static int test_import_key_short_write_preserves_persistent_key(void) +{ +#if defined(_WIN32) || defined(_MSC_VER) || !defined(RLIMIT_FSIZE) + return TEST_SKIPPED; +#else + enum { ORIGINAL_LEN = 64, REPLACEMENT_LEN = 1024 }; + uint8_t original[ORIGINAL_LEN]; + uint8_t replacement[REPLACEMENT_LEN]; + uint8_t exported[ORIGINAL_LEN]; + size_t exported_len = 0; + psa_key_id_t key_id = 0; + psa_key_id_t persistent_id = PSA_KEY_ID_USER_MIN + 3175u; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + struct rlimit old_limit; + struct rlimit short_limit; + void (*old_sigxfsz)(int); + int limit_set = 0; + int ret = TEST_FAIL; + size_t i; + + for (i = 0; i < sizeof(original); i++) { + original[i] = (uint8_t)i; + } + for (i = 0; i < sizeof(replacement); i++) { + replacement[i] = (uint8_t)(0xa5u ^ i); + } + + (void)psa_destroy_key(persistent_id); + + psa_set_key_type(&attrs, PSA_KEY_TYPE_RAW_DATA); + psa_set_key_bits(&attrs, ORIGINAL_LEN * 8u); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_EXPORT); + psa_set_key_lifetime(&attrs, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&attrs, persistent_id); + + st = psa_import_key(&attrs, original, sizeof(original), &key_id); + if (check_status(st, "psa_import_key(original persistent RAW_DATA)") != TEST_OK) { + goto cleanup; + } + + if (getrlimit(RLIMIT_FSIZE, &old_limit) != 0) { + ret = TEST_SKIPPED; + goto cleanup; + } + old_sigxfsz = signal(SIGXFSZ, SIG_IGN); + if (old_sigxfsz == SIG_ERR) { + ret = TEST_SKIPPED; + goto cleanup; + } + short_limit.rlim_cur = 1; + short_limit.rlim_max = old_limit.rlim_max; + if (setrlimit(RLIMIT_FSIZE, &short_limit) != 0) { + (void)signal(SIGXFSZ, old_sigxfsz); + ret = TEST_SKIPPED; + goto cleanup; + } + limit_set = 1; + + psa_set_key_bits(&attrs, REPLACEMENT_LEN * 8u); + st = psa_import_key(&attrs, replacement, sizeof(replacement), &key_id); + + (void)setrlimit(RLIMIT_FSIZE, &old_limit); + (void)signal(SIGXFSZ, old_sigxfsz); + limit_set = 0; + + if (check_true(st == PSA_ERROR_STORAGE_FAILURE, + "psa_import_key reports short persistent write") != TEST_OK) { + goto cleanup; + } + + st = psa_export_key(persistent_id, exported, sizeof(exported), &exported_len); + if (check_status(st, "psa_export_key after failed persistent overwrite") != TEST_OK) { + goto cleanup; + } + if (check_true(exported_len == sizeof(original), + "failed persistent overwrite preserves length") != TEST_OK) { + goto cleanup; + } + if (check_buf_eq("failed persistent overwrite preserves data", + exported, original, sizeof(original)) != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + if (limit_set) { + (void)setrlimit(RLIMIT_FSIZE, &old_limit); + (void)signal(SIGXFSZ, old_sigxfsz); + } + psa_reset_key_attributes(&attrs); + (void)psa_destroy_key(persistent_id); + return ret; +#endif +} + static int test_copy_key_requires_copy_usage_flag(void) { static const uint8_t key[16] = { @@ -928,7 +1250,7 @@ static int test_copy_key_requires_copy_usage_flag(void) return ret; } -static int test_copy_key_rejects_attribute_mismatch(void) +static int test_copy_key_inherits_unspecified_type(void) { static const uint8_t key[16] = { 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, @@ -938,6 +1260,7 @@ static int test_copy_key_rejects_attribute_mismatch(void) psa_key_id_t copy_key = PSA_KEY_ID_NULL; psa_key_attributes_t src_attrs = psa_key_attributes_init(); psa_key_attributes_t dst_attrs = psa_key_attributes_init(); + psa_key_attributes_t got_attrs = psa_key_attributes_init(); psa_status_t st; int ret = TEST_FAIL; @@ -947,44 +1270,174 @@ static int test_copy_key_rejects_attribute_mismatch(void) PSA_ALG_CBC_NO_PADDING, PSA_KEY_LIFETIME_VOLATILE); st = psa_import_key(&src_attrs, key, sizeof(key), &src_key); - if (check_status(st, "psa_import_key(AES copy mismatch source)") != TEST_OK) { + if (check_status(st, "psa_import_key(AES copy inherit source)") != TEST_OK) { goto cleanup; } - setup_aes_key_attrs(&dst_attrs, - PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, - PSA_ALG_CBC_NO_PADDING, - PSA_KEY_LIFETIME_VOLATILE); - psa_set_key_type(&dst_attrs, PSA_KEY_TYPE_DES); + psa_set_key_usage_flags(&dst_attrs, + PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&dst_attrs, PSA_ALG_CBC_NO_PADDING); + psa_set_key_lifetime(&dst_attrs, PSA_KEY_LIFETIME_VOLATILE); + st = psa_copy_key(src_key, &dst_attrs, ©_key); - if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, - "psa_copy_key rejects type mismatch") != TEST_OK) { + if (check_status(st, "psa_copy_key inherits unspecified type") != TEST_OK) { goto cleanup; } - setup_aes_key_attrs(&dst_attrs, - PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, - PSA_ALG_CBC_NO_PADDING, - PSA_KEY_LIFETIME_VOLATILE); - psa_set_key_bits(&dst_attrs, 192); - st = psa_copy_key(src_key, &dst_attrs, ©_key); - if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, - "psa_copy_key rejects bit-size mismatch") != TEST_OK) { + st = psa_get_key_attributes(copy_key, &got_attrs); + if (check_status(st, "psa_get_key_attributes(inherited type copy)") != TEST_OK) { goto cleanup; } - - setup_aes_key_attrs(&dst_attrs, - PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, - PSA_ALG_ECB_NO_PADDING, - PSA_KEY_LIFETIME_VOLATILE); - st = psa_copy_key(src_key, &dst_attrs, ©_key); - if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, - "psa_copy_key rejects algorithm mismatch") != TEST_OK) { + if (check_true(psa_get_key_type(&got_attrs) == PSA_KEY_TYPE_AES, + "psa_copy_key inherited type") != TEST_OK) { + goto cleanup; + } + if (check_true(psa_get_key_bits(&got_attrs) == 128, + "psa_copy_key inherited bits") != TEST_OK) { goto cleanup; } - setup_aes_key_attrs(&dst_attrs, - PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, + ret = TEST_OK; + +cleanup: + psa_reset_key_attributes(&got_attrs); + psa_reset_key_attributes(&dst_attrs); + psa_reset_key_attributes(&src_attrs); + if (copy_key != PSA_KEY_ID_NULL) { + (void)psa_destroy_key(copy_key); + } + if (src_key != 0) { + (void)psa_destroy_key(src_key); + } + return ret; +} + +static int test_copy_key_persistent_inherits_unspecified_type(void) +{ + static const uint8_t key[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c + }; + psa_key_id_t src_key = 0; + psa_key_id_t copy_key = PSA_KEY_ID_NULL; + psa_key_id_t persistent_id = PSA_KEY_ID_USER_MIN + 2812u; + psa_key_attributes_t src_attrs = psa_key_attributes_init(); + psa_key_attributes_t dst_attrs = psa_key_attributes_init(); + psa_key_attributes_t got_attrs = psa_key_attributes_init(); + psa_status_t st; + int ret = TEST_FAIL; + + (void)psa_destroy_key(persistent_id); + + setup_aes_key_attrs(&src_attrs, + PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | + PSA_KEY_USAGE_ENCRYPT, + PSA_ALG_CBC_NO_PADDING, + PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&src_attrs, persistent_id); + st = psa_import_key(&src_attrs, key, sizeof(key), &src_key); + if (check_status(st, "psa_import_key(AES persistent copy inherit source)") != TEST_OK) { + goto cleanup; + } + + psa_set_key_usage_flags(&dst_attrs, + PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&dst_attrs, PSA_ALG_CBC_NO_PADDING); + psa_set_key_lifetime(&dst_attrs, PSA_KEY_LIFETIME_PERSISTENT); + + st = psa_copy_key(src_key, &dst_attrs, ©_key); + if (check_status(st, "psa_copy_key persistent inherits unspecified type") != TEST_OK) { + goto cleanup; + } + + st = psa_get_key_attributes(copy_key, &got_attrs); + if (check_status(st, "psa_get_key_attributes(persistent inherited type copy)") != TEST_OK) { + goto cleanup; + } + if (check_true(psa_get_key_type(&got_attrs) == PSA_KEY_TYPE_AES, + "psa_copy_key persistent inherited type") != TEST_OK) { + goto cleanup; + } + if (check_true(psa_get_key_bits(&got_attrs) == 128, + "psa_copy_key persistent inherited bits") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + psa_reset_key_attributes(&got_attrs); + psa_reset_key_attributes(&dst_attrs); + psa_reset_key_attributes(&src_attrs); + if (copy_key != PSA_KEY_ID_NULL) { + (void)psa_destroy_key(copy_key); + } + if (src_key != 0) { + (void)psa_destroy_key(src_key); + } + else { + (void)psa_destroy_key(persistent_id); + } + return ret; +} + +static int test_copy_key_rejects_attribute_mismatch(void) +{ + static const uint8_t key[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c + }; + psa_key_id_t src_key = 0; + psa_key_id_t copy_key = PSA_KEY_ID_NULL; + psa_key_attributes_t src_attrs = psa_key_attributes_init(); + psa_key_attributes_t dst_attrs = psa_key_attributes_init(); + psa_status_t st; + int ret = TEST_FAIL; + + setup_aes_key_attrs(&src_attrs, + PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_EXPORT | + PSA_KEY_USAGE_ENCRYPT, + PSA_ALG_CBC_NO_PADDING, + PSA_KEY_LIFETIME_VOLATILE); + st = psa_import_key(&src_attrs, key, sizeof(key), &src_key); + if (check_status(st, "psa_import_key(AES copy mismatch source)") != TEST_OK) { + goto cleanup; + } + + setup_aes_key_attrs(&dst_attrs, + PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, + PSA_ALG_CBC_NO_PADDING, + PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_type(&dst_attrs, PSA_KEY_TYPE_DES); + st = psa_copy_key(src_key, &dst_attrs, ©_key); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_copy_key rejects type mismatch") != TEST_OK) { + goto cleanup; + } + + setup_aes_key_attrs(&dst_attrs, + PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, + PSA_ALG_CBC_NO_PADDING, + PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_bits(&dst_attrs, 192); + st = psa_copy_key(src_key, &dst_attrs, ©_key); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_copy_key rejects bit-size mismatch") != TEST_OK) { + goto cleanup; + } + + setup_aes_key_attrs(&dst_attrs, + PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, + PSA_ALG_ECB_NO_PADDING, + PSA_KEY_LIFETIME_VOLATILE); + st = psa_copy_key(src_key, &dst_attrs, ©_key); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_copy_key rejects algorithm mismatch") != TEST_OK) { + goto cleanup; + } + + setup_aes_key_attrs(&dst_attrs, + PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT, PSA_ALG_CBC_NO_PADDING, PSA_KEY_LIFETIME_PERSISTENT); st = psa_copy_key(src_key, &dst_attrs, ©_key); @@ -2089,6 +2542,132 @@ static int test_aead_policy_mismatch_rejected(void) return ret; } +static int test_aead_requires_decrypt_usage(void) +{ + static const uint8_t key[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_aead_operation_t op = psa_aead_operation_init(); + psa_status_t st; + int ret = TEST_FAIL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attrs, 128); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_GCM); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(GCM encrypt-only)") != TEST_OK) { + goto cleanup; + } + + st = psa_aead_decrypt_setup(&op, key_id, PSA_ALG_GCM); + if (check_true(st == PSA_ERROR_NOT_PERMITTED, + "psa_aead_decrypt_setup requires decrypt usage") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + (void)psa_aead_abort(&op); + if (key_id != 0) { + (void)psa_destroy_key(key_id); + } + return ret; +} + +static int test_aead_gcm_rejects_short_tags(void) +{ + static const uint8_t key[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_aead_operation_t op = psa_aead_operation_init(); + psa_status_t st; + int ret = TEST_OK; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attrs, 128); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG( + PSA_ALG_GCM, 1)); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(GCM short tag policy)") != TEST_OK) { + return TEST_FAIL; + } + + st = psa_aead_encrypt_setup(&op, key_id, + PSA_ALG_AEAD_WITH_SHORTENED_TAG( + PSA_ALG_GCM, 1)); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_encrypt_setup rejects 1-byte GCM tag") != TEST_OK) { + ret = TEST_FAIL; + } + + psa_aead_abort(&op); + st = psa_destroy_key(key_id); + if (check_status(st, "psa_destroy_key(GCM short tag policy)") != TEST_OK) { + return TEST_FAIL; + } + + return ret; +} + +static int test_aead_gcm_rejects_short_nonce(void) +{ + static const uint8_t key[16] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + static const uint8_t short_nonce[11] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b + }; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_aead_operation_t op = psa_aead_operation_init(); + psa_status_t st; + int ret = TEST_FAIL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attrs, 128); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_GCM); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(GCM short nonce)") != TEST_OK) { + goto cleanup; + } + + st = psa_aead_encrypt_setup(&op, key_id, PSA_ALG_GCM); + if (check_status(st, "psa_aead_encrypt_setup(GCM short nonce)") != TEST_OK) { + goto cleanup; + } + + st = psa_aead_set_nonce(&op, short_nonce, sizeof(short_nonce)); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_set_nonce rejects 11-byte GCM nonce") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + (void)psa_aead_abort(&op); + psa_reset_key_attributes(&attrs); + if (key_id != 0) { + (void)psa_destroy_key(key_id); + } + return ret; +} + static int test_chacha20_poly1305_rejects_aes_key(void) { static const uint8_t key[32] = { @@ -2140,13 +2719,75 @@ static int test_chacha20_poly1305_rejects_aes_key(void) return TEST_OK; } -static int test_chacha20_import_rejects_invalid_key_size(void) +static int test_gcm_ccm_reject_non_aes_key_type(void) { - static const uint8_t key[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + static const uint8_t key[32] = { + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67, + 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, + 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f }; - psa_key_attributes_t attrs = psa_key_attributes_init(); + static const uint8_t nonce[12] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b + }; + static const uint8_t plaintext[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + uint8_t out[sizeof(plaintext) + 16]; + size_t out_len = 0; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + int ret = TEST_FAIL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_CHACHA20); + psa_set_key_bits(&attrs, 256); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_CHACHA20_POLY1305); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(ChaCha20 for GCM/CCM mismatch)") != TEST_OK) { + return TEST_FAIL; + } + + st = psa_aead_encrypt(key_id, PSA_ALG_GCM, + nonce, sizeof(nonce), + NULL, 0, + plaintext, sizeof(plaintext), + out, sizeof(out), &out_len); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_encrypt(ChaCha20 key with GCM) rejected") != TEST_OK) { + goto cleanup; + } + + st = psa_aead_encrypt(key_id, PSA_ALG_CCM, + nonce, sizeof(nonce), + NULL, 0, + plaintext, sizeof(plaintext), + out, sizeof(out), &out_len); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_encrypt(ChaCha20 key with CCM) rejected") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + if (key_id != 0) { + (void)psa_destroy_key(key_id); + } + return ret; +} + +static int test_chacha20_import_rejects_invalid_key_size(void) +{ + static const uint8_t key[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + psa_key_attributes_t attrs = psa_key_attributes_init(); psa_key_id_t key_id = 0; psa_status_t st; @@ -2381,6 +3022,121 @@ static int test_asym_ecc(void) return TEST_OK; } +/* F-3176: exercise high-level psa_key_agreement validation and dispatch. */ +static int test_psa_key_agreement(void) +{ + uint8_t peer_pub[128]; + uint8_t exported[32]; + size_t peer_pub_len = 0; + size_t exported_len = 0; + psa_key_id_t private_key = PSA_KEY_ID_NULL; + psa_key_id_t peer_key = PSA_KEY_ID_NULL; + psa_key_id_t agreed_key = PSA_KEY_ID_NULL; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_key_attributes_t out_attrs = psa_key_attributes_init(); + psa_status_t st; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attrs, 256); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); + psa_set_key_algorithm(&attrs, PSA_ALG_ECDH); + + st = psa_generate_key(&attrs, &private_key); + if (check_status(st, "psa_generate_key(psa_key_agreement private)") != TEST_OK) + return TEST_FAIL; + st = psa_generate_key(&attrs, &peer_key); + if (check_status(st, "psa_generate_key(psa_key_agreement peer)") != TEST_OK) + goto cleanup; + + st = psa_export_public_key(peer_key, peer_pub, sizeof(peer_pub), &peer_pub_len); + if (check_status(st, "psa_export_public_key(psa_key_agreement peer)") != TEST_OK) + goto cleanup; + + psa_set_key_type(&out_attrs, PSA_KEY_TYPE_DERIVE); + psa_set_key_bits(&out_attrs, 256); + psa_set_key_usage_flags(&out_attrs, PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&out_attrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + + st = psa_key_agreement(private_key, peer_pub, peer_pub_len, PSA_ALG_ECDH, + &out_attrs, &agreed_key); + if (check_status(st, "psa_key_agreement raw ECDH to DERIVE key") != TEST_OK) + goto cleanup; + st = psa_destroy_key(agreed_key); + if (check_status(st, "psa_destroy_key(raw agreement output)") != TEST_OK) + goto cleanup; + agreed_key = PSA_KEY_ID_NULL; + + psa_reset_key_attributes(&out_attrs); + psa_set_key_type(&out_attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&out_attrs, 256); + psa_set_key_usage_flags(&out_attrs, PSA_KEY_USAGE_EXPORT); + psa_set_key_algorithm(&out_attrs, PSA_ALG_CTR); + + st = psa_key_agreement(private_key, peer_pub, peer_pub_len, PSA_ALG_ECDH, + &out_attrs, &agreed_key); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_key_agreement rejects raw ECDH to AES key") != TEST_OK) + goto cleanup; + if (check_true(agreed_key == PSA_KEY_ID_NULL, + "psa_key_agreement leaves key null for AES output") != TEST_OK) + goto cleanup; + + st = psa_key_agreement(private_key, peer_pub, peer_pub_len, PSA_ALG_SHA_256, + &out_attrs, &agreed_key); + if (check_true(st == PSA_ERROR_NOT_SUPPORTED, + "psa_key_agreement rejects non-key-agreement algorithm") != TEST_OK) + goto cleanup; + if (check_true(agreed_key == PSA_KEY_ID_NULL, + "psa_key_agreement leaves key null for non-KA algorithm") != TEST_OK) + goto cleanup; + + psa_reset_key_attributes(&out_attrs); + psa_set_key_type(&out_attrs, PSA_KEY_TYPE_RAW_DATA); + psa_set_key_bits(&out_attrs, 128); + psa_set_key_usage_flags(&out_attrs, PSA_KEY_USAGE_EXPORT); + + st = psa_key_agreement(private_key, peer_pub, peer_pub_len, + PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, + PSA_ALG_HKDF(PSA_ALG_SHA_256)), + &out_attrs, &agreed_key); + if (check_status(st, "psa_key_agreement ECDH+HKDF to RAW_DATA key") != TEST_OK) + goto cleanup; + + st = psa_export_key(agreed_key, exported, sizeof(exported), &exported_len); + if (check_status(st, "psa_export_key(ECDH+HKDF output)") != TEST_OK) + goto cleanup; + if (check_true(exported_len == 16, + "psa_key_agreement ECDH+HKDF output length") != TEST_OK) + goto cleanup; + + st = psa_destroy_key(agreed_key); + if (check_status(st, "psa_destroy_key(KDF agreement output)") != TEST_OK) + goto cleanup; + agreed_key = PSA_KEY_ID_NULL; + + st = psa_destroy_key(peer_key); + if (check_status(st, "psa_destroy_key(psa_key_agreement peer)") != TEST_OK) + goto cleanup; + peer_key = PSA_KEY_ID_NULL; + st = psa_destroy_key(private_key); + if (check_status(st, "psa_destroy_key(psa_key_agreement private)") != TEST_OK) + return TEST_FAIL; + + return TEST_OK; + +cleanup: + if (agreed_key != PSA_KEY_ID_NULL) { + (void)psa_destroy_key(agreed_key); + } + if (peer_key != PSA_KEY_ID_NULL) { + (void)psa_destroy_key(peer_key); + } + if (private_key != PSA_KEY_ID_NULL) { + (void)psa_destroy_key(private_key); + } + return TEST_FAIL; +} + static int test_asym_algorithm_mismatch_policy(void) { static const uint8_t msg[] = "wolfpsa asym mismatch"; @@ -2460,6 +3216,60 @@ static int test_asym_algorithm_mismatch_policy(void) return ret; } +static int test_rsa_pkcs1v15_raw_sign_hash_roundtrip_large_input(void) +{ + uint8_t input[65]; + uint8_t sig[512]; + size_t sig_len = 0; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + int result = TEST_FAIL; + size_t i; + + for (i = 0; i < sizeof(input); i++) { + input[i] = (uint8_t)(i + 1u); + } + + psa_set_key_type(&attrs, PSA_KEY_TYPE_RSA_KEY_PAIR); + psa_set_key_bits(&attrs, 2048); + psa_set_key_usage_flags(&attrs, + PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attrs, PSA_ALG_RSA_PKCS1V15_SIGN_RAW); + + st = psa_generate_key(&attrs, &key_id); + if (st == PSA_ERROR_NOT_SUPPORTED) { + return TEST_SKIPPED; + } + if (check_status(st, "psa_generate_key(RSA RAW roundtrip)") != TEST_OK) { + return TEST_FAIL; + } + + st = psa_sign_hash(key_id, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, + input, sizeof(input), sig, sizeof(sig), &sig_len); + if (check_status(st, "psa_sign_hash(RSA RAW 65-byte input)") != TEST_OK) { + goto cleanup; + } + + st = psa_verify_hash(key_id, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, + input, sizeof(input), sig, sig_len); + if (check_status(st, "psa_verify_hash(RSA RAW 65-byte input)") != TEST_OK) { + goto cleanup; + } + + result = TEST_OK; + +cleanup: + if (key_id != PSA_KEY_ID_NULL) { + psa_status_t destroy_st = psa_destroy_key(key_id); + if (result == TEST_OK && + check_status(destroy_st, "psa_destroy_key(RSA RAW roundtrip)") != TEST_OK) { + result = TEST_FAIL; + } + } + return result; +} + static int test_generate_key_rejects_public_key_type(void) { psa_key_id_t key_id = PSA_KEY_ID_NULL; @@ -2533,6 +3343,60 @@ static int test_import_key_rejects_wrapped_volatile_key_id(void) return result; } +static int test_import_key_reports_volatile_store_invalid_argument(void) +{ + static const uint8_t key_data[1] = { 0 }; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_status_t st; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_RAW_DATA); + psa_set_key_bits(&attrs, 8); + psa_set_key_lifetime(&attrs, PSA_KEY_LIFETIME_VOLATILE); + + st = psa_import_key(&attrs, key_data, 0, &key_id); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_import_key reports volatile-store invalid argument") != TEST_OK) { + printf(" expected PSA_ERROR_INVALID_ARGUMENT, got %d\n", (int)st); + return TEST_FAIL; + } + if (check_true(key_id == PSA_KEY_ID_NULL, + "psa_import_key leaves key id null on volatile-store failure") != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_import_key_rejects_unknown_usage_bits(void) +{ + static const uint8_t key[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c + }; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_status_t st; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attrs, 128); + psa_set_key_algorithm(&attrs, PSA_ALG_CBC_NO_PADDING); + attrs.policy.usage = ~(psa_key_usage_t)0; + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_import_key rejects unknown usage bits") != TEST_OK) { + printf(" expected PSA_ERROR_INVALID_ARGUMENT, got %d\n", (int)st); + return TEST_FAIL; + } + if (check_true(key_id == PSA_KEY_ID_NULL, + "psa_import_key leaves key id null on usage failure") != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + static int test_asym_rsa_oaep_usage_policy(void) { static const uint8_t plaintext[] = "psa rsa oaep"; @@ -2705,87 +3569,464 @@ static int test_ed25519_signature_length(void) (void)psa_destroy_key(key_id); return TEST_FAIL; } - - sig_len = sizeof(sig); - st = psa_sign_message(key_id, PSA_ALG_ED25519PH, - msg, sizeof(msg) - 1, - sig, sizeof(sig), &sig_len); - if (check_status(st, "psa_sign_message(ED25519PH)") != TEST_OK) { - (void)psa_destroy_key(key_id); + + sig_len = sizeof(sig); + st = psa_sign_message(key_id, PSA_ALG_ED25519PH, + msg, sizeof(msg) - 1, + sig, sizeof(sig), &sig_len); + if (check_status(st, "psa_sign_message(ED25519PH)") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + if (check_true(sig_len == 64u, "psa_sign_message(ED25519PH) length") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + + st = psa_verify_message(key_id, PSA_ALG_ED25519PH, + msg, sizeof(msg) - 1, sig, sig_len); + if (check_status(st, "psa_verify_message(ED25519PH)") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + + st = psa_destroy_key(key_id); + if (check_status(st, "psa_destroy_key(ED25519)") != TEST_OK) return TEST_FAIL; + + return TEST_OK; +} + +static int test_twisted_edwards_export_public_key(size_t bits, + psa_algorithm_t alg, + size_t expected_pub_len, + const char* label) +{ + uint8_t pub[ED448_PUBLIC_KEY_BYTES]; + size_t pub_len = 0; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + + psa_set_key_type(&attrs, + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS)); + psa_set_key_bits(&attrs, bits); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_EXPORT); + psa_set_key_algorithm(&attrs, alg); + + st = psa_generate_key(&attrs, &key_id); + if (st == PSA_ERROR_NOT_SUPPORTED) { + return TEST_SKIPPED; + } + if (check_status(st, label) != TEST_OK) return TEST_FAIL; + + st = psa_export_public_key(key_id, pub, sizeof(pub), &pub_len); + if (check_status(st, "psa_export_public_key(Twisted Edwards)") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + if (check_true(pub_len == expected_pub_len, + "psa_export_public_key(Twisted Edwards) length") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + + st = psa_destroy_key(key_id); + if (check_status(st, "psa_destroy_key(Twisted Edwards)") != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_ed25519_export_public_key(void) +{ + return test_twisted_edwards_export_public_key(255, PSA_ALG_ED25519PH, + ED25519_PUBLIC_KEY_BYTES, + "psa_generate_key(ED25519 export)"); +} + +static int test_ed448_export_public_key(void) +{ + return test_twisted_edwards_export_public_key(448, PSA_ALG_ED448PH, + ED448_PUBLIC_KEY_BYTES, + "psa_generate_key(ED448 export)"); +} + +static int test_x25519_key_usability(void) +{ + static const uint8_t alice_priv[X25519_KEY_BYTES] = { + 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, + 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, + 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, + 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a + }; + static const uint8_t bob_priv[X25519_KEY_BYTES] = { + 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, + 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, + 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, + 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb + }; + uint8_t alice_pub[X25519_KEY_BYTES]; + uint8_t bob_pub[X25519_KEY_BYTES]; + uint8_t alice_secret[X25519_KEY_BYTES]; + uint8_t bob_secret[X25519_KEY_BYTES]; + uint8_t generated_pub[X25519_KEY_BYTES]; + size_t alice_pub_len = 0; + size_t bob_pub_len = 0; + size_t alice_secret_len = 0; + size_t bob_secret_len = 0; + size_t generated_pub_len = 0; + psa_key_id_t alice_key = 0; + psa_key_id_t bob_key = 0; + psa_key_id_t generated_key = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + + psa_set_key_type(&attrs, + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY)); + psa_set_key_bits(&attrs, 255); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&attrs, PSA_ALG_ECDH); + + st = psa_import_key(&attrs, alice_priv, sizeof(alice_priv), &alice_key); + if (st == PSA_ERROR_NOT_SUPPORTED) { + return TEST_SKIPPED; + } + if (check_status(st, "psa_import_key(X25519 alice)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_import_key(&attrs, bob_priv, sizeof(bob_priv), &bob_key); + if (check_status(st, "psa_import_key(X25519 bob)") != TEST_OK) { + (void)psa_destroy_key(alice_key); + return TEST_FAIL; + } + + st = psa_export_public_key(alice_key, alice_pub, sizeof(alice_pub), + &alice_pub_len); + if (check_status(st, "psa_export_public_key(X25519 alice)") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + st = psa_export_public_key(bob_key, bob_pub, sizeof(bob_pub), &bob_pub_len); + if (check_status(st, "psa_export_public_key(X25519 bob)") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + if (check_true(alice_pub_len == X25519_KEY_BYTES && + bob_pub_len == X25519_KEY_BYTES, + "psa_export_public_key(X25519) length") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + + st = psa_raw_key_agreement(PSA_ALG_ECDH, alice_key, bob_pub, bob_pub_len, + alice_secret, sizeof(alice_secret), + &alice_secret_len); + if (check_status(st, "psa_raw_key_agreement(X25519 alice)") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + st = psa_raw_key_agreement(PSA_ALG_ECDH, bob_key, alice_pub, alice_pub_len, + bob_secret, sizeof(bob_secret), + &bob_secret_len); + if (check_status(st, "psa_raw_key_agreement(X25519 bob)") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + if (check_true(alice_secret_len == X25519_KEY_BYTES && + bob_secret_len == X25519_KEY_BYTES, + "psa_raw_key_agreement(X25519) length") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + if (check_buf_eq("psa_raw_key_agreement(X25519)", alice_secret, + bob_secret, X25519_KEY_BYTES) != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + + st = psa_generate_key(&attrs, &generated_key); + if (check_status(st, "psa_generate_key(X25519)") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + return TEST_FAIL; + } + st = psa_export_public_key(generated_key, generated_pub, + sizeof(generated_pub), &generated_pub_len); + if (check_status(st, "psa_export_public_key(generated X25519)") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + (void)psa_destroy_key(generated_key); + return TEST_FAIL; + } + if (check_true(generated_pub_len == X25519_KEY_BYTES, + "psa_export_public_key(generated X25519) length") != TEST_OK) { + (void)psa_destroy_key(alice_key); + (void)psa_destroy_key(bob_key); + (void)psa_destroy_key(generated_key); + return TEST_FAIL; + } + + st = psa_destroy_key(alice_key); + if (check_status(st, "psa_destroy_key(X25519 alice)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_destroy_key(bob_key); + if (check_status(st, "psa_destroy_key(X25519 bob)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_destroy_key(generated_key); + if (check_status(st, "psa_destroy_key(X25519 generated)") != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_hash_verify_rejects_bad_signature(psa_key_type_t type, + size_t bits, + psa_algorithm_t alg, + const uint8_t* hash, + size_t hash_len, + size_t expected_sig_len, + const char* label) +{ + uint8_t sig[128]; + size_t sig_len = 0; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + int result = TEST_FAIL; + + psa_set_key_type(&attrs, type); + psa_set_key_bits(&attrs, bits); + psa_set_key_usage_flags(&attrs, + PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attrs, alg); + + st = psa_generate_key(&attrs, &key_id); + if (st == PSA_ERROR_NOT_SUPPORTED) { + return TEST_SKIPPED; + } + if (check_status(st, label) != TEST_OK) { + return TEST_FAIL; + } + + st = psa_sign_hash(key_id, alg, hash, hash_len, sig, sizeof(sig), &sig_len); + if (check_status(st, "psa_sign_hash(bad signature setup)") != TEST_OK) { + goto cleanup; + } + if (check_true(sig_len == expected_sig_len, + "psa_sign_hash(bad signature setup) length") != TEST_OK) { + goto cleanup; + } + + st = psa_verify_hash(key_id, alg, hash, hash_len, sig, sig_len); + if (check_status(st, "psa_verify_hash(valid signature setup)") != TEST_OK) { + goto cleanup; + } + + sig[0] ^= 0x01u; + st = psa_verify_hash(key_id, alg, hash, hash_len, sig, sig_len); + if (check_true(st == PSA_ERROR_INVALID_SIGNATURE, + "psa_verify_hash rejects corrupted signature") != TEST_OK) { + printf(" %s expected PSA_ERROR_INVALID_SIGNATURE, got %d\n", + label, (int)st); + goto cleanup; + } + + result = TEST_OK; + +cleanup: + if (key_id != PSA_KEY_ID_NULL) { + psa_status_t destroy_st = psa_destroy_key(key_id); + if (result == TEST_OK && + check_status(destroy_st, "psa_destroy_key(bad signature test)") != TEST_OK) { + result = TEST_FAIL; + } + } + return result; +} + +static int test_asym_verify_rejects_bad_signatures(void) +{ + static const uint8_t hash_sha256[WC_SHA256_DIGEST_SIZE] = { + 0x9f,0x86,0xd0,0x81,0x88,0x4c,0x7d,0x65, + 0x9a,0x2f,0xea,0xa0,0xc5,0x5a,0xd0,0x15, + 0xa3,0xbf,0x4f,0x1b,0x2b,0x0b,0x82,0x2c, + 0xd1,0x5d,0x6c,0x15,0xb0,0xf0,0x0a,0x08 + }; + static const uint8_t hash_ed25519[64] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, + 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f + }; + /* Ed448ph wc API requires the pre-hash input to be exactly + * ED448_PREHASH_SIZE (64) bytes of SHAKE256 output. */ + static const uint8_t hash_ed448[64] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, + 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f + }; + int ed25519_result; + int ed448_result; + + if (test_hash_verify_rejects_bad_signature( + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), + 256, PSA_ALG_ECDSA(PSA_ALG_SHA_256), + hash_sha256, sizeof(hash_sha256), 64u, + "psa_generate_key(ECDSA bad signature)") != TEST_OK) { + return TEST_FAIL; + } + + ed25519_result = test_hash_verify_rejects_bad_signature( + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS), + 255, PSA_ALG_ED25519PH, hash_ed25519, sizeof(hash_ed25519), 64u, + "psa_generate_key(ED25519 bad signature)"); + if (ed25519_result == TEST_FAIL) { + return TEST_FAIL; + } + + ed448_result = test_hash_verify_rejects_bad_signature( + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS), + 448, PSA_ALG_ED448PH, hash_ed448, sizeof(hash_ed448), 114u, + "psa_generate_key(ED448 bad signature)"); + if (ed448_result == TEST_FAIL) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_asym_requires_verify_usage(void) +{ + static const uint8_t hash[WC_SHA256_DIGEST_SIZE] = { + 0x9f,0x86,0xd0,0x81,0x88,0x4c,0x7d,0x65, + 0x9a,0x2f,0xea,0xa0,0xc5,0x5a,0xd0,0x15, + 0xa3,0xbf,0x4f,0x1b,0x2b,0x0b,0x82,0x2c, + 0x15,0xd6,0xa4,0x4f,0x00,0x5e,0x4b,0x49 + }; + uint8_t sig[128]; + size_t sig_len = 0; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + int ret = TEST_FAIL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attrs, 256); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attrs, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + + st = psa_generate_key(&attrs, &key_id); + if (st == PSA_ERROR_NOT_SUPPORTED) { + return TEST_SKIPPED; + } + if (check_status(st, "psa_generate_key(ECDSA sign-only)") != TEST_OK) { return TEST_FAIL; } - if (check_true(sig_len == 64u, "psa_sign_message(ED25519PH) length") != TEST_OK) { - (void)psa_destroy_key(key_id); - return TEST_FAIL; + + st = psa_sign_hash(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), + hash, sizeof(hash), sig, sizeof(sig), &sig_len); + if (check_status(st, "psa_sign_hash(sign-only)") != TEST_OK) { + goto cleanup; } - st = psa_verify_message(key_id, PSA_ALG_ED25519PH, - msg, sizeof(msg) - 1, sig, sig_len); - if (check_status(st, "psa_verify_message(ED25519PH)") != TEST_OK) { - (void)psa_destroy_key(key_id); - return TEST_FAIL; + st = psa_verify_hash(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), + hash, sizeof(hash), sig, sig_len); + if (check_true(st == PSA_ERROR_NOT_PERMITTED, + "psa_verify_hash requires verify usage") != TEST_OK) { + goto cleanup; } - st = psa_destroy_key(key_id); - if (check_status(st, "psa_destroy_key(ED25519)") != TEST_OK) return TEST_FAIL; + ret = TEST_OK; - return TEST_OK; +cleanup: + if (key_id != PSA_KEY_ID_NULL) { + psa_status_t destroy_st = psa_destroy_key(key_id); + if (ret == TEST_OK && + check_status(destroy_st, "psa_destroy_key(ECDSA sign-only)") != TEST_OK) { + ret = TEST_FAIL; + } + } + return ret; } -static int test_twisted_edwards_export_public_key(size_t bits, - psa_algorithm_t alg, - size_t expected_pub_len, - const char* label) +static int test_ml_dsa_verify_rejects_bad_signature(void) { - uint8_t pub[ED448_PUBLIC_KEY_BYTES]; - size_t pub_len = 0; - psa_key_id_t key_id = 0; - psa_key_attributes_t attrs = psa_key_attributes_init(); +#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_DILITHIUM) || \ + defined(WOLFSSL_WC_DILITHIUM) + static const uint8_t message[] = { + 0x46, 0x2f, 0x32, 0x38, 0x32, 0x33, 0x20, 0x4d, + 0x4c, 0x2d, 0x44, 0x53, 0x41, 0x20, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x79 + }; + uint8_t private_key[DILITHIUM_LEVEL2_KEY_SIZE]; + uint8_t public_key[DILITHIUM_LEVEL2_PUB_KEY_SIZE]; + uint8_t signature[DILITHIUM_LEVEL2_SIG_SIZE]; + size_t private_key_length = 0; + size_t public_key_length = 0; + size_t signature_length = 0; psa_status_t st; - psa_set_key_type(&attrs, - PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS)); - psa_set_key_bits(&attrs, bits); - psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_EXPORT); - psa_set_key_algorithm(&attrs, alg); - - st = psa_generate_key(&attrs, &key_id); - if (st == PSA_ERROR_NOT_SUPPORTED) { - return TEST_SKIPPED; + st = psa_ml_dsa_generate_key(PSA_ML_DSA_PARAMETER_2, + private_key, sizeof(private_key), + &private_key_length, + public_key, sizeof(public_key), + &public_key_length); + if (check_status(st, "psa_ml_dsa_generate_key") != TEST_OK) { + return TEST_FAIL; } - if (check_status(st, label) != TEST_OK) return TEST_FAIL; - st = psa_export_public_key(key_id, pub, sizeof(pub), &pub_len); - if (check_status(st, "psa_export_public_key(Twisted Edwards)") != TEST_OK) { - (void)psa_destroy_key(key_id); + st = psa_ml_dsa_sign(PSA_ML_DSA_PARAMETER_2, + private_key, private_key_length, + message, sizeof(message), + signature, sizeof(signature), + &signature_length); + if (check_status(st, "psa_ml_dsa_sign") != TEST_OK) { return TEST_FAIL; } - if (check_true(pub_len == expected_pub_len, - "psa_export_public_key(Twisted Edwards) length") != TEST_OK) { - (void)psa_destroy_key(key_id); + + st = psa_ml_dsa_verify(PSA_ML_DSA_PARAMETER_2, + public_key, public_key_length, + message, sizeof(message), + signature, signature_length); + if (check_status(st, "psa_ml_dsa_verify(valid)") != TEST_OK) { return TEST_FAIL; } - st = psa_destroy_key(key_id); - if (check_status(st, "psa_destroy_key(Twisted Edwards)") != TEST_OK) { + signature[0] ^= 0x01u; + st = psa_ml_dsa_verify(PSA_ML_DSA_PARAMETER_2, + public_key, public_key_length, + message, sizeof(message), + signature, signature_length); + if (check_true(st == PSA_ERROR_INVALID_SIGNATURE, + "psa_ml_dsa_verify rejects corrupted signature") != TEST_OK) { + printf(" expected PSA_ERROR_INVALID_SIGNATURE, got %d\n", (int)st); return TEST_FAIL; } return TEST_OK; -} - -static int test_ed25519_export_public_key(void) -{ - return test_twisted_edwards_export_public_key(255, PSA_ALG_ED25519PH, - ED25519_PUBLIC_KEY_BYTES, - "psa_generate_key(ED25519 export)"); -} - -static int test_ed448_export_public_key(void) -{ - return test_twisted_edwards_export_public_key(448, PSA_ALG_ED448PH, - ED448_PUBLIC_KEY_BYTES, - "psa_generate_key(ED448 export)"); +#else + return TEST_SKIPPED; +#endif } static int test_mac_alg_mismatch(void) @@ -3522,6 +4763,123 @@ static int test_kdf_null_capacity(void) return TEST_OK; } +static int test_kdf_hkdf_default_capacity(void) +{ + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + size_t capacity = 0; + psa_status_t st; + + st = psa_key_derivation_setup(&op, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(HKDF default capacity)") != TEST_OK) { + goto fail; + } + st = psa_key_derivation_get_capacity(&op, &capacity); + if (check_status(st, "psa_key_derivation_get_capacity(HKDF)") != TEST_OK) { + goto fail; + } + if (check_true(capacity == 255u * WC_SHA256_DIGEST_SIZE, + "HKDF default capacity is 255 * hash length") != TEST_OK) { + printf(" expected %u, got %lu\n", + 255u * WC_SHA256_DIGEST_SIZE, (unsigned long)capacity); + goto fail; + } + (void)psa_key_derivation_abort(&op); + + op = psa_key_derivation_operation_init(); + st = psa_key_derivation_setup(&op, PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(HKDF_EXTRACT default capacity)") != TEST_OK) { + goto fail; + } + st = psa_key_derivation_get_capacity(&op, &capacity); + if (check_status(st, "psa_key_derivation_get_capacity(HKDF_EXTRACT)") != TEST_OK) { + goto fail; + } + if (check_true(capacity == WC_SHA256_DIGEST_SIZE, + "HKDF_EXTRACT default capacity is hash length") != TEST_OK) { + printf(" expected %u, got %lu\n", + WC_SHA256_DIGEST_SIZE, (unsigned long)capacity); + goto fail; + } + (void)psa_key_derivation_abort(&op); + + op = psa_key_derivation_operation_init(); + st = psa_key_derivation_setup(&op, PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(HKDF_EXPAND default capacity)") != TEST_OK) { + goto fail; + } + st = psa_key_derivation_get_capacity(&op, &capacity); + if (check_status(st, "psa_key_derivation_get_capacity(HKDF_EXPAND)") != TEST_OK) { + goto fail; + } + if (check_true(capacity == 255u * WC_SHA256_DIGEST_SIZE, + "HKDF_EXPAND default capacity is 255 * hash length") != TEST_OK) { + printf(" expected %u, got %lu\n", + 255u * WC_SHA256_DIGEST_SIZE, (unsigned long)capacity); + goto fail; + } + (void)psa_key_derivation_abort(&op); + + return TEST_OK; + +fail: + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; +} + +static int test_kdf_set_capacity_cannot_increase_remaining_capacity(void) +{ + static const uint8_t secret[] = "hkdf capacity secret"; + static const uint8_t info[] = "hkdf capacity info"; + uint8_t output[8]; + size_t capacity = 0; + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + psa_status_t st; + int ret = TEST_FAIL; + + st = psa_key_derivation_setup(&op, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(HKDF monotonic capacity)") != TEST_OK) { + goto cleanup; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SECRET, + secret, sizeof(secret) - 1u); + if (check_status(st, "psa_key_derivation_input_bytes(SECRET HKDF monotonic capacity)") != TEST_OK) { + goto cleanup; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_INFO, + info, sizeof(info) - 1u); + if (check_status(st, "psa_key_derivation_input_bytes(INFO HKDF monotonic capacity)") != TEST_OK) { + goto cleanup; + } + st = psa_key_derivation_set_capacity(&op, 16u); + if (check_status(st, "psa_key_derivation_set_capacity(initial HKDF monotonic capacity)") != TEST_OK) { + goto cleanup; + } + st = psa_key_derivation_output_bytes(&op, output, sizeof(output)); + if (check_status(st, "psa_key_derivation_output_bytes(HKDF monotonic capacity)") != TEST_OK) { + goto cleanup; + } + st = psa_key_derivation_get_capacity(&op, &capacity); + if (check_status(st, "psa_key_derivation_get_capacity(HKDF remaining capacity)") != TEST_OK) { + goto cleanup; + } + if (check_true(capacity == 8u, + "psa_key_derivation_get_capacity tracks remaining HKDF capacity") != TEST_OK) { + goto cleanup; + } + + st = psa_key_derivation_set_capacity(&op, 9u); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_key_derivation_set_capacity rejects increasing remaining capacity") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + (void)psa_key_derivation_abort(&op); + return ret; +} + static int test_kdf_pbkdf2_zero_cost_rejected(void) { static const uint8_t password[] = "pbkdf2-password"; @@ -3560,6 +4918,51 @@ static int test_kdf_pbkdf2_zero_cost_rejected(void) return ret; } +static int test_kdf_pbkdf2_large_cost_rejected(void) +{ + static const uint8_t password[] = "pbkdf2-password"; + static const uint8_t salt[] = "pbkdf2-salt"; + uint8_t output[16]; + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + psa_status_t st; + int ret = TEST_FAIL; + + st = psa_key_derivation_setup(&op, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(PBKDF2 large cost)") != TEST_OK) { + goto cleanup; + } + + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_PASSWORD, + password, sizeof(password) - 1u); + if (check_status(st, "psa_key_derivation_input_bytes(PBKDF2 large cost password)") != TEST_OK) { + goto cleanup; + } + + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SALT, + salt, sizeof(salt) - 1u); + if (check_status(st, "psa_key_derivation_input_bytes(PBKDF2 large cost salt)") != TEST_OK) { + goto cleanup; + } + + st = psa_key_derivation_input_integer(&op, PSA_KEY_DERIVATION_INPUT_COST, + 0x80000000ULL); + if (check_status(st, "psa_key_derivation_input_integer(PBKDF2 large cost)") != TEST_OK) { + goto cleanup; + } + + st = psa_key_derivation_output_bytes(&op, output, sizeof(output)); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_key_derivation_output_bytes rejects PBKDF2 cost above INT_MAX") != TEST_OK) { + goto cleanup; + } + + ret = TEST_OK; + +cleanup: + (void)psa_key_derivation_abort(&op); + return ret; +} + static int test_kdf_input_key_policy(void) { static const uint8_t secret[] = { @@ -4788,6 +6191,12 @@ int main(int argc, char** argv) if (only == NULL || strcmp(only, "hmac") == 0) { if (run_named_test("hmac", test_hmac) == TEST_FAIL) return TEST_FAIL; } + if (only == NULL || strcmp(only, "mac_verify_finish_at_least_length") == 0) { + if (run_named_test("mac_verify_finish_at_least_length", + test_mac_verify_finish_accepts_longer_at_least_length_mac) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "mac_error_state") == 0) { if (run_named_test("mac_error_state", test_mac_error_aborts_operation) == TEST_FAIL) { @@ -4833,6 +6242,12 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "import_key_short_write_preserves_persistent_key") == 0) { + if (run_named_test("import_key_short_write_preserves_persistent_key", + test_import_key_short_write_preserves_persistent_key) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "copy_key_success") == 0) { if (run_named_test("copy_key_success", test_copy_key_copies_material_and_attributes) == TEST_FAIL) { @@ -4845,6 +6260,18 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "copy_key_inherits_unspecified_type") == 0) { + if (run_named_test("copy_key_inherits_unspecified_type", + test_copy_key_inherits_unspecified_type) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "copy_key_persistent_inherits_unspecified_type") == 0) { + if (run_named_test("copy_key_persistent_inherits_unspecified_type", + test_copy_key_persistent_inherits_unspecified_type) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "copy_key_attribute_mismatch") == 0) { if (run_named_test("copy_key_attribute_mismatch", test_copy_key_rejects_attribute_mismatch) == TEST_FAIL) { @@ -4908,6 +6335,30 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "aead_requires_decrypt_usage") == 0) { + if (run_named_test("aead_requires_decrypt_usage", + test_aead_requires_decrypt_usage) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "aead_gcm_short_tag") == 0) { + if (run_named_test("aead_gcm_short_tag", + test_aead_gcm_rejects_short_tags) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "aead_gcm_short_nonce") == 0) { + if (run_named_test("aead_gcm_short_nonce", + test_aead_gcm_rejects_short_nonce) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "aead_gcm_ccm_non_aes_key") == 0) { + if (run_named_test("aead_gcm_ccm_non_aes_key", + test_gcm_ccm_reject_non_aes_key_type) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "chacha20_aes_reject") == 0) { if (run_named_test("chacha20_aes_reject", test_chacha20_poly1305_rejects_aes_key) == TEST_FAIL) { @@ -4929,12 +6380,24 @@ int main(int argc, char** argv) if (only == NULL || strcmp(only, "asym_ecc") == 0) { if (run_named_test("asym_ecc", test_asym_ecc) == TEST_FAIL) return TEST_FAIL; } + if (only == NULL || strcmp(only, "psa_key_agreement") == 0) { + if (run_named_test("psa_key_agreement", + test_psa_key_agreement) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "asym_algorithm_mismatch_policy") == 0) { if (run_named_test("asym_algorithm_mismatch_policy", test_asym_algorithm_mismatch_policy) == TEST_FAIL) { return TEST_FAIL; } } + if (only == NULL || strcmp(only, "rsa_pkcs1v15_raw_roundtrip_large_input") == 0) { + if (run_named_test("rsa_pkcs1v15_raw_roundtrip_large_input", + test_rsa_pkcs1v15_raw_sign_hash_roundtrip_large_input) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "generate_key_rejects_public_key_type") == 0) { if (run_named_test("generate_key_rejects_public_key_type", test_generate_key_rejects_public_key_type) == TEST_FAIL) { @@ -4947,6 +6410,18 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "import_key_volatile_store_invalid_argument") == 0) { + if (run_named_test("import_key_volatile_store_invalid_argument", + test_import_key_reports_volatile_store_invalid_argument) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "import_key_unknown_usage_bits") == 0) { + if (run_named_test("import_key_unknown_usage_bits", + test_import_key_rejects_unknown_usage_bits) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "asym_rsa_oaep_policy") == 0) { if (run_named_test("asym_rsa_oaep_policy", test_asym_rsa_oaep_usage_policy) == TEST_FAIL) { @@ -4968,15 +6443,57 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "x25519_key_usability") == 0) { + if (run_named_test("x25519_key_usability", + test_x25519_key_usability) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "asym_verify_bad_signature") == 0) { + if (run_named_test("asym_verify_bad_signature", + test_asym_verify_rejects_bad_signatures) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "asym_requires_verify_usage") == 0) { + if (run_named_test("asym_requires_verify_usage", + test_asym_requires_verify_usage) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "ml_dsa_verify_bad_signature") == 0) { + if (run_named_test("ml_dsa_verify_bad_signature", + test_ml_dsa_verify_rejects_bad_signature) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "kdf_null_capacity") == 0) { if (run_named_test("kdf_null_capacity", test_kdf_null_capacity) == TEST_FAIL) return TEST_FAIL; } + if (only == NULL || strcmp(only, "kdf_hkdf_default_capacity") == 0) { + if (run_named_test("kdf_hkdf_default_capacity", + test_kdf_hkdf_default_capacity) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "kdf_monotonic_capacity") == 0) { + if (run_named_test("kdf_monotonic_capacity", + test_kdf_set_capacity_cannot_increase_remaining_capacity) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "kdf_pbkdf2_zero_cost") == 0) { if (run_named_test("kdf_pbkdf2_zero_cost", test_kdf_pbkdf2_zero_cost_rejected) == TEST_FAIL) { return TEST_FAIL; } } + if (only == NULL || strcmp(only, "kdf_pbkdf2_large_cost") == 0) { + if (run_named_test("kdf_pbkdf2_large_cost", + test_kdf_pbkdf2_large_cost_rejected) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "kdf_input_key_policy") == 0) { if (run_named_test("kdf_input_key_policy", test_kdf_input_key_policy) == TEST_FAIL) { return TEST_FAIL; @@ -5058,6 +6575,24 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "cipher_requires_decrypt_usage") == 0) { + if (run_named_test("cipher_requires_decrypt_usage", + test_cipher_requires_decrypt_usage) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "cipher_non_aes_key_type") == 0) { + if (run_named_test("cipher_non_aes_key_type", + test_cipher_rejects_non_aes_key_type) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "mac_requires_verify_usage") == 0) { + if (run_named_test("mac_requires_verify_usage", + test_mac_requires_verify_usage) == TEST_FAIL) { + return TEST_FAIL; + } + } if (only == NULL || strcmp(only, "kdf_tls12_psk_to_ms") == 0) { if (run_named_test("kdf_tls12_psk_to_ms", test_kdf_tls12_psk_to_ms_rfc4279_order) == TEST_FAIL) { diff --git a/test/psa_server/psa_des3_stack_scrub_test.c b/test/psa_server/psa_des3_stack_scrub_test.c index ce3f38c..5e717fc 100644 --- a/test/psa_server/psa_des3_stack_scrub_test.c +++ b/test/psa_server/psa_des3_stack_scrub_test.c @@ -34,10 +34,15 @@ int main(void) { - static const uint8_t key[16] = { + static const uint8_t two_key_tdes[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; + static const uint8_t three_key_tdes[24] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 + }; psa_key_attributes_t attrs = psa_key_attributes_init(); psa_cipher_operation_t op = psa_cipher_operation_init(); psa_key_id_t key_id = PSA_KEY_ID_NULL; @@ -54,7 +59,26 @@ int main(void) psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); psa_set_key_algorithm(&attrs, PSA_ALG_CBC_NO_PADDING); - st = psa_import_key(&attrs, key, sizeof(key), &key_id); + st = psa_import_key(&attrs, two_key_tdes, sizeof(two_key_tdes), &key_id); + if (st != PSA_ERROR_NOT_SUPPORTED) { + printf("FAIL psa_import_key accepted 2-key 3DES status=%d\n", (int)st); + if (st == PSA_SUCCESS) { + (void)psa_destroy_key(key_id); + } + return 1; + } + + psa_reset_key_attributes(&attrs); + attrs = psa_key_attributes_init(); + key_id = PSA_KEY_ID_NULL; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_DES); + psa_set_key_bits(&attrs, 192); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_CBC_NO_PADDING); + + st = psa_import_key(&attrs, three_key_tdes, sizeof(three_key_tdes), + &key_id); if (st != PSA_SUCCESS) { printf("FAIL psa_import_key status=%d\n", (int)st); return 1; diff --git a/user_settings.h b/user_settings.h index 72eb263..c1a20b0 100644 --- a/user_settings.h +++ b/user_settings.h @@ -44,6 +44,8 @@ #define WOLFSSL_SHA384 #define WOLFSSL_SHA512 #define WOLFSSL_SHA3 +#define WOLFSSL_SHAKE128 +#define WOLFSSL_SHAKE256 #undef NO_MD5 #undef NO_DES3 #define HAVE_ECC @@ -71,5 +73,8 @@ #define HAVE_CURVE448 #define HAVE_ED448 #define WOLFSSL_ED448_STREAMING_VERIFY +#define HAVE_DILITHIUM +#define WOLFSSL_WC_DILITHIUM +#define WOLFSSL_HAVE_DILITHIUM #endif /* WOLFSSL_USER_SETTINGS_H */ diff --git a/wolfpsa.map b/wolfpsa.map index 081d22d..c33caa2 100644 --- a/wolfpsa.map +++ b/wolfpsa.map @@ -65,6 +65,9 @@ WOLFPSA_1.0 { psa_mac_verify; psa_mac_verify_finish; psa_mac_verify_setup; + psa_ml_dsa_generate_key; + psa_ml_dsa_sign; + psa_ml_dsa_verify; psa_pake_abort; psa_pake_cs_get_algorithm; psa_pake_cs_get_key_confirmation; diff --git a/wolfpsa/psa/crypto-pqc.h b/wolfpsa/psa/crypto-pqc.h index 110e73a..0c03c0c 100644 --- a/wolfpsa/psa/crypto-pqc.h +++ b/wolfpsa/psa/crypto-pqc.h @@ -20,7 +20,11 @@ */ #ifndef PSA_CRYPTO_PQC_H #define PSA_CRYPTO_PQC_H + +#include "psa/crypto_types.h" + typedef uint8_t psa_slh_dsa_family_t; +typedef uint8_t psa_ml_dsa_parameter_t; #define PSA_ALG_SHA_256_192 ((psa_algorithm_t)0x0200000E) #define PSA_ALG_SHAKE128_256 ((psa_algorithm_t)0x02000016) @@ -32,6 +36,9 @@ typedef uint8_t psa_slh_dsa_family_t; #define PSA_ALG_ML_KEM ((psa_algorithm_t)0x0c000200) #define PSA_KEY_TYPE_ML_DSA_KEY_PAIR ((psa_key_type_t)0x7002) #define PSA_KEY_TYPE_ML_DSA_PUBLIC_KEY ((psa_key_type_t)0x4002) +#define PSA_ML_DSA_PARAMETER_2 ((psa_ml_dsa_parameter_t)2) +#define PSA_ML_DSA_PARAMETER_3 ((psa_ml_dsa_parameter_t)3) +#define PSA_ML_DSA_PARAMETER_5 ((psa_ml_dsa_parameter_t)5) #define PSA_KEY_TYPE_IS_ML_DSA(type) #define PSA_ALG_ML_DSA ((psa_algorithm_t) 0x06004400) #define PSA_ALG_DETERMINISTIC_ML_DSA ((psa_algorithm_t) 0x06004500) diff --git a/wolfpsa/psa/crypto.h b/wolfpsa/psa/crypto.h index 5a9df13..344046a 100644 --- a/wolfpsa/psa/crypto.h +++ b/wolfpsa/psa/crypto.h @@ -352,6 +352,45 @@ psa_status_t psa_verify_hash(psa_key_id_t key, const uint8_t *signature, size_t signature_length); +psa_status_t psa_ml_dsa_generate_key(psa_ml_dsa_parameter_t parameter, + uint8_t *private_key, + size_t private_key_size, + size_t *private_key_length, + uint8_t *public_key, + size_t public_key_size, + size_t *public_key_length); + +psa_status_t psa_ml_dsa_sign(psa_ml_dsa_parameter_t parameter, + const uint8_t *private_key, + size_t private_key_size, + const uint8_t *message, + size_t message_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length); + +psa_status_t psa_ml_dsa_verify(psa_ml_dsa_parameter_t parameter, + const uint8_t *public_key, + size_t public_key_size, + const uint8_t *message, + size_t message_length, + const uint8_t *signature, + size_t signature_length); + +psa_status_t psa_lms_verify(const uint8_t *public_key, + size_t public_key_size, + const uint8_t *message, + size_t message_length, + const uint8_t *signature, + size_t signature_length); + +psa_status_t psa_xmss_verify(const uint8_t *public_key, + size_t public_key_size, + const uint8_t *message, + size_t message_length, + const uint8_t *signature, + size_t signature_length); + psa_status_t psa_asymmetric_encrypt(psa_key_id_t key, psa_algorithm_t alg, const uint8_t *input,