/* BEGIN_HEADER */ #include #include "psa_crypto_core.h" /* Some tests in this module configure entropy sources. */ #include "psa_crypto_invasive.h" #include "mbedtls/entropy.h" #include "entropy_poll.h" #define ENTROPY_MIN_NV_SEED_SIZE \ MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) #include "psa_crypto_random_impl.h" #if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) /* PSA crypto uses the HMAC_DRBG module. It reads from the entropy source twice: * once for the initial entropy and once for a nonce. The nonce length is * half the entropy length. For SHA-256, SHA-384 or SHA-512, the * entropy length is 256 per the documentation of mbedtls_hmac_drbg_seed(), * and PSA crypto doesn't support other hashes for HMAC_DRBG. */ #define ENTROPY_NONCE_LEN (256 / 2) #else /* PSA crypto uses the CTR_DRBG module. In some configurations, it needs * to read from the entropy source twice: once for the initial entropy * and once for a nonce. */ #include "mbedtls/ctr_drbg.h" #define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN #endif #if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) typedef struct { size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */ size_t max_steps; size_t *length_sequence; size_t step; } fake_entropy_state_t; static int fake_entropy_source(void *state_arg, unsigned char *output, size_t len, size_t *olen) { fake_entropy_state_t *state = state_arg; size_t i; if (state->step >= state->max_steps) { return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; } *olen = MIN(len, state->length_sequence[state->step]); for (i = 0; i < *olen; i++) { output[i] = i; } ++state->step; return 0; } #define ENTROPY_SOURCE_PLATFORM 0x00000001 #define ENTROPY_SOURCE_TIMING 0x00000002 #define ENTROPY_SOURCE_HARDWARE 0x00000004 #define ENTROPY_SOURCE_NV_SEED 0x00000008 #define ENTROPY_SOURCE_FAKE 0x40000000 static uint32_t custom_entropy_sources_mask; static fake_entropy_state_t fake_entropy_state; /* This is a modified version of mbedtls_entropy_init() from entropy.c * which chooses entropy sources dynamically. */ static void custom_entropy_init(mbedtls_entropy_context *ctx) { ctx->source_count = 0; memset(ctx->source, 0, sizeof(ctx->source)); #if defined(MBEDTLS_THREADING_C) mbedtls_mutex_init(&ctx->mutex); #endif ctx->accumulator_started = 0; mbedtls_md_init(&ctx->accumulator); #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) if (custom_entropy_sources_mask & ENTROPY_SOURCE_PLATFORM) { mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL, MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_SOURCE_STRONG); } #endif #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) if (custom_entropy_sources_mask & ENTROPY_SOURCE_HARDWARE) { mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL, MBEDTLS_ENTROPY_MIN_HARDWARE, MBEDTLS_ENTROPY_SOURCE_STRONG); } #endif #if defined(MBEDTLS_ENTROPY_NV_SEED) if (custom_entropy_sources_mask & ENTROPY_SOURCE_NV_SEED) { mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL, MBEDTLS_ENTROPY_BLOCK_SIZE, MBEDTLS_ENTROPY_SOURCE_STRONG); ctx->initial_entropy_run = 0; } else { /* Skip the NV seed even though it's compiled in. */ ctx->initial_entropy_run = 1; } #endif if (custom_entropy_sources_mask & ENTROPY_SOURCE_FAKE) { mbedtls_entropy_add_source(ctx, fake_entropy_source, &fake_entropy_state, fake_entropy_state.threshold, MBEDTLS_ENTROPY_SOURCE_STRONG); } } #endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ #if defined MBEDTLS_THREADING_PTHREAD typedef struct { int do_init; } thread_psa_init_ctx_t; static void *thread_psa_init_function(void *ctx) { thread_psa_init_ctx_t *init_context = (thread_psa_init_ctx_t *) ctx; psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; uint8_t random[10] = { 0 }; if (init_context->do_init) { PSA_ASSERT(psa_crypto_init()); } /* If this is a test only thread, then we can assume PSA is being started * up on another thread and thus we cannot know whether the following tests * will be successful or not. These checks are still useful, however even * without checking the return codes as they may show up race conditions on * the flags they check under TSAN.*/ /* Test getting if drivers are initialised. */ int can_do = psa_can_do_hash(PSA_ALG_NONE); if (init_context->do_init) { TEST_ASSERT(can_do == 1); } #if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) /* Test getting global_data.rng_state. */ status = mbedtls_psa_crypto_configure_entropy_sources(NULL, NULL); if (init_context->do_init) { /* Bad state due to entropy sources already being setup in * psa_crypto_init() */ TEST_EQUAL(status, PSA_ERROR_BAD_STATE); } #endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ /* Test using the PSA RNG ony if we know PSA is up and running. */ if (init_context->do_init) { status = psa_generate_random(random, sizeof(random)); TEST_EQUAL(status, PSA_SUCCESS); } exit: return NULL; } #endif /* defined MBEDTLS_THREADING_PTHREAD */ /* END_HEADER */ /* BEGIN_DEPENDENCIES * depends_on:MBEDTLS_PSA_CRYPTO_C * END_DEPENDENCIES */ /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void create_nv_seed() { static unsigned char seed[ENTROPY_MIN_NV_SEED_SIZE]; TEST_ASSERT(mbedtls_nv_seed_write(seed, sizeof(seed)) >= 0); } /* END_CASE */ /* BEGIN_CASE */ void init_deinit(int count) { psa_status_t status; int i; for (i = 0; i < count; i++) { status = psa_crypto_init(); PSA_ASSERT(status); status = psa_crypto_init(); PSA_ASSERT(status); PSA_DONE(); } } /* END_CASE */ /* BEGIN_CASE */ void deinit_without_init(int count) { int i; for (i = 0; i < count; i++) { PSA_ASSERT(psa_crypto_init()); PSA_DONE(); } PSA_DONE(); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_THREADING_PTHREAD */ void psa_threaded_init(int arg_thread_count) { thread_psa_init_ctx_t init_context; thread_psa_init_ctx_t init_context_2; size_t thread_count = (size_t) arg_thread_count; mbedtls_test_thread_t *threads = NULL; TEST_CALLOC(threads, sizeof(mbedtls_test_thread_t) * thread_count); init_context.do_init = 1; /* Test initialising PSA and testing certain protected globals on multiple * threads. */ for (size_t i = 0; i < thread_count; i++) { TEST_EQUAL( mbedtls_test_thread_create(&threads[i], thread_psa_init_function, (void *) &init_context), 0); } for (size_t i = 0; i < thread_count; i++) { TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0); } PSA_DONE(); init_context_2.do_init = 0; /* Test initialising PSA whilst also testing flags on other threads. */ for (size_t i = 0; i < thread_count; i++) { if (i & 1) { TEST_EQUAL( mbedtls_test_thread_create(&threads[i], thread_psa_init_function, (void *) &init_context), 0); } else { TEST_EQUAL( mbedtls_test_thread_create(&threads[i], thread_psa_init_function, (void *) &init_context_2), 0); } } for (size_t i = 0; i < thread_count; i++) { TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0); } exit: PSA_DONE(); mbedtls_free(threads); } /* END_CASE */ /* BEGIN_CASE */ void validate_module_init_generate_random(int count) { psa_status_t status; uint8_t random[10] = { 0 }; int i; for (i = 0; i < count; i++) { status = psa_crypto_init(); PSA_ASSERT(status); PSA_DONE(); } status = psa_generate_random(random, sizeof(random)); TEST_EQUAL(status, PSA_ERROR_BAD_STATE); } /* END_CASE */ /* BEGIN_CASE */ void validate_module_init_key_based(int count) { psa_status_t status; uint8_t data[10] = { 0 }; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; mbedtls_svc_key_id_t key = mbedtls_svc_key_id_make(0xdead, 0xdead); int i; for (i = 0; i < count; i++) { status = psa_crypto_init(); PSA_ASSERT(status); PSA_DONE(); } psa_set_key_type(&attributes, PSA_KEY_TYPE_RAW_DATA); status = psa_import_key(&attributes, data, sizeof(data), &key); TEST_EQUAL(status, PSA_ERROR_BAD_STATE); TEST_ASSERT(mbedtls_svc_key_id_is_null(key)); } /* END_CASE */ /* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void custom_entropy_sources(int sources_arg, int expected_init_status_arg) { psa_status_t expected_init_status = expected_init_status_arg; uint8_t random[10] = { 0 }; custom_entropy_sources_mask = sources_arg; PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources( custom_entropy_init, mbedtls_entropy_free)); TEST_EQUAL(psa_crypto_init(), expected_init_status); if (expected_init_status != PSA_SUCCESS) { goto exit; } PSA_ASSERT(psa_generate_random(random, sizeof(random))); exit: PSA_DONE(); } /* END_CASE */ /* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void fake_entropy_source(int threshold, int amount1, int amount2, int amount3, int amount4, int expected_init_status_arg) { psa_status_t expected_init_status = expected_init_status_arg; uint8_t random[10] = { 0 }; size_t lengths[4]; fake_entropy_state.threshold = threshold; fake_entropy_state.step = 0; fake_entropy_state.max_steps = 0; if (amount1 >= 0) { lengths[fake_entropy_state.max_steps++] = amount1; } if (amount2 >= 0) { lengths[fake_entropy_state.max_steps++] = amount2; } if (amount3 >= 0) { lengths[fake_entropy_state.max_steps++] = amount3; } if (amount4 >= 0) { lengths[fake_entropy_state.max_steps++] = amount4; } fake_entropy_state.length_sequence = lengths; custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE; PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources( custom_entropy_init, mbedtls_entropy_free)); TEST_EQUAL(psa_crypto_init(), expected_init_status); if (expected_init_status != PSA_SUCCESS) { goto exit; } PSA_ASSERT(psa_generate_random(random, sizeof(random))); exit: PSA_DONE(); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void entropy_from_nv_seed(int seed_size_arg, int expected_init_status_arg) { psa_status_t expected_init_status = expected_init_status_arg; uint8_t random[10] = { 0 }; uint8_t *seed = NULL; size_t seed_size = seed_size_arg; TEST_CALLOC(seed, seed_size); TEST_ASSERT(mbedtls_nv_seed_write(seed, seed_size) >= 0); custom_entropy_sources_mask = ENTROPY_SOURCE_NV_SEED; PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources( custom_entropy_init, mbedtls_entropy_free)); TEST_EQUAL(psa_crypto_init(), expected_init_status); if (expected_init_status != PSA_SUCCESS) { goto exit; } PSA_ASSERT(psa_generate_random(random, sizeof(random))); exit: mbedtls_free(seed); PSA_DONE(); } /* END_CASE */