-
Notifications
You must be signed in to change notification settings - Fork 3k
PSA Crypto SPM #8804
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PSA Crypto SPM #8804
Changes from all commits
dd73fa6
c7d3523
aea01a8
9cc017f
9406450
53be3cc
ecd556b
4a391d3
6cd4f77
1e27eb1
f771a5a
1a33ae5
2b9f94a
773ac8d
628ef9b
8501e79
5455a2d
aea9713
25239a4
b87ab25
ba6fdcf
34bcf6b
ed8505a
2b3822e
f4581fa
bd47a8c
7b2c924
587fdbb
1325084
7203774
0fde6af
73ebe1a
fb88cb4
54cd8bf
ae0fa60
73cb013
4816266
58f92c3
7f49fd2
59c3c9f
e72d910
a4c498e
bab6116
352bac3
7776fea
ba47b45
79d957a
1d4b6a4
5c2cf07
88f4f48
4cef73d
6e862cf
abf1ccc
daeb19d
b9ea334
8195944
f1c5aeb
5f36447
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,3 +94,6 @@ log | |
|
||
# Icetea related file | ||
test_suite.json | ||
|
||
# default delivery dir | ||
DELIVERY/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* Copyright (c) 2017-2018 ARM Limited | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#ifndef __MBED_HAL_SPM_FAULT_FUNCTIONS__ | ||
#define __MBED_HAL_SPM_FAULT_FUNCTIONS__ | ||
|
||
#include "cmsis_compiler.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
// Retruns the value of the LR register | ||
// Used to determine which stack the exception happend in | ||
__STATIC_FORCEINLINE uint32_t __get_LR(void); | ||
|
||
// This function is required as we need a symbol/address | ||
// to jump to from fault handler. | ||
void do_nothing(void); | ||
|
||
// Test exception handler | ||
static void hard_fault_handler_test(); | ||
|
||
// Using naked function as it will not be executed from beginning to the end. | ||
// The execution flow expected to be interrupted by exception and we will | ||
// return to other function. | ||
// compiler will not produce prolog and epilog code for naked function | ||
// and thus will preserve stack in un-corrupted state | ||
__attribute__((naked)) void call_mem(uint32_t addr); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif // __MBED_HAL_SPM_FAULT_FUNCTIONS__ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* Copyright (c) 2017-2018 ARM Limited | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#if !defined(COMPONENT_PSA_SRV_IPC) | ||
#error [NOT_SUPPORTED] Test supported only on PSA targets | ||
#endif | ||
|
||
#if (defined( __CC_ARM ) || defined(__ARMCC_VERSION) || defined( __ICCARM__ )) | ||
#error [NOT_SUPPORTED] this test is supported on GCC only | ||
#endif | ||
|
||
#include "utest/utest.h" | ||
#include "unity/unity.h" | ||
#include "greentea-client/test_env.h" | ||
#include "cmsis.h" | ||
#include "spm_api.h" | ||
#include <stdlib.h> | ||
#include "fault_functions.h" | ||
|
||
using namespace utest::v1; | ||
|
||
|
||
#define HARDFAULT_IRQn ((IRQn_Type)-13) | ||
#define EXC_RETURN_RETURN_STACK_MSK ((uint32_t)(0x00000004)) | ||
#define PC_INDEX_IN_STACK_FRAME 6 | ||
|
||
volatile uint32_t fault_occurred; | ||
uint32_t real_hard_fault_handler; | ||
|
||
__STATIC_FORCEINLINE uint32_t __get_LR(void) | ||
{ | ||
uint32_t result; | ||
|
||
__ASM volatile("MOV %0, lr" : "=r"(result)); | ||
return (result); | ||
} | ||
|
||
void do_nothing(void) | ||
{ | ||
__NOP(); | ||
} | ||
|
||
static void hard_fault_handler_test() | ||
{ | ||
fault_occurred++; | ||
// LR is set EXC_RETURN | ||
// lowest bits identify PSP vs MSP stack used for stacking | ||
uint32_t lr = __get_LR(); | ||
uint32_t sp; | ||
|
||
if (lr & EXC_RETURN_RETURN_STACK_MSK) { | ||
sp = __get_PSP(); | ||
} else { | ||
sp = __get_MSP(); | ||
} | ||
|
||
// Overwrite return address. | ||
// Fake return to a our special function since current | ||
// instruction under test will always fail due to memory protection | ||
((uint32_t *)sp)[PC_INDEX_IN_STACK_FRAME] = (uint32_t)do_nothing; | ||
} | ||
|
||
__attribute__((naked)) void call_mem(uint32_t addr) | ||
{ | ||
// Only first instruction will be executed in positive flow, | ||
// since exception will be generated for invalid memory access. | ||
// Other instructions are for calling do_nothing function according to AAPCS. | ||
__ASM( | ||
"LDR r1, [r0]\n" | ||
"BX lr\n" | ||
); | ||
} | ||
|
||
static void test_memory(uint32_t addr, uint32_t expected_fatal_count) | ||
{ | ||
call_mem(addr); | ||
// Although call_mem is a "naked" function, it is called using AAPCS. | ||
// Thus we can assume LR will point to next instruction, and caller save registers are backed up | ||
TEST_ASSERT_EQUAL(expected_fatal_count, fault_occurred); | ||
} | ||
|
||
static void secure_ram_fault_test(void) | ||
{ | ||
test_memory(PSA_SECURE_RAM_START, 1); | ||
} | ||
|
||
static void secure_flash_fault_test(void) | ||
{ | ||
test_memory(PSA_SECURE_ROM_START, 1); | ||
} | ||
|
||
static void non_secure_ram_fault_test(void) | ||
{ | ||
test_memory(PSA_NON_SECURE_RAM_START, 0); | ||
} | ||
|
||
static void non_secure_flash_fault_test(void) | ||
{ | ||
test_memory(PSA_NON_SECURE_ROM_START, 0); | ||
} | ||
|
||
utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case) | ||
{ | ||
// Save old hard fault handler and replace it with a new one | ||
// NOTE: only works when VTOR is set to RAM | ||
real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn); | ||
NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test); | ||
fault_occurred = 0; | ||
|
||
return greentea_case_setup_handler(source, index_of_case); | ||
} | ||
|
||
utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed, | ||
const failure_t reason) | ||
{ | ||
// Restore real hard fault handler | ||
NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler); | ||
|
||
return greentea_case_teardown_handler(source, passed, failed, reason); | ||
} | ||
|
||
Case cases[] = { | ||
Case("SPM - Access secure RAM", fault_override_setup, secure_ram_fault_test, fault_override_teardown), | ||
Case("SPM - Access secure Flash", fault_override_setup, secure_flash_fault_test, fault_override_teardown), | ||
Case("SPM - Access non-secure RAM", fault_override_setup, non_secure_ram_fault_test, fault_override_teardown), | ||
Case("SPM - Access non-secure Flash", fault_override_setup, non_secure_flash_fault_test, fault_override_teardown), | ||
}; | ||
|
||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) | ||
{ | ||
#ifndef NO_GREENTEA | ||
GREENTEA_SETUP(20, "default_auto"); | ||
#endif | ||
return greentea_test_setup_handler(number_of_cases); | ||
} | ||
|
||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); | ||
|
||
int main() | ||
{ | ||
Harness::run(specification); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* Copyright (c) 2018 ARM Limited. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the License); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#if ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C)) || (!defined(MBEDTLS_PSA_CRYPTO_SPM ))) | ||
#error [NOT_SUPPORTED] Mbed SPM Crypto is OFF - skipping. | ||
#endif // TARGET_PSA | ||
|
||
#include "greentea-client/test_env.h" | ||
#include "unity/unity.h" | ||
#include "utest/utest.h" | ||
#include "crypto.h" | ||
#include "entropy.h" | ||
#include "entropy_poll.h" | ||
|
||
#define TEST_RANDOM_SIZE 64 | ||
|
||
#if !defined(MAX) | ||
#define MAX(a,b) (((a)>(b))?(a):(b)) | ||
#endif | ||
|
||
/* Calculating the minimum allowed entropy size in bytes */ | ||
#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \ | ||
MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) | ||
|
||
using namespace utest::v1; | ||
|
||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) | ||
{ | ||
#ifndef NO_GREENTEA | ||
GREENTEA_SETUP(60, "default_auto"); | ||
#endif | ||
return greentea_test_setup_handler(number_of_cases); | ||
} | ||
|
||
static void check_multi_crypto_init_deinit() | ||
{ | ||
uint8_t output[TEST_RANDOM_SIZE] = {0}; | ||
uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = {0}; | ||
/* inject some a seed for test*/ | ||
for (int i; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) { | ||
seed[i] = i; | ||
} | ||
/* don't really care if this succeed this is just to make crypto init pass*/ | ||
mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); | ||
psa_status_t status = psa_crypto_init(); | ||
TEST_ASSERT_EQUAL(PSA_SUCCESS, status); | ||
status = psa_crypto_init(); | ||
TEST_ASSERT_EQUAL(PSA_SUCCESS, status); | ||
status = psa_generate_random(output, sizeof(output)); | ||
TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Major: if |
||
mbedtls_psa_crypto_free(); | ||
status = psa_generate_random(output, sizeof(output)); | ||
TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Major: You've just closed the connection to the crypto library, so I see that you've implemented a connection counter in the SPE. It makes sense, but this violates the documented semantics of Should the semantics change? My reasoning for the current semantics is that you should be able to call This deviation needs to be documented in the known issues for this release. |
||
mbedtls_psa_crypto_free(); | ||
status = psa_generate_random(output, sizeof(output)); | ||
TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); | ||
} | ||
|
||
static void check_crypto_init_deinit() | ||
{ | ||
psa_status_t status; | ||
uint8_t output[TEST_RANDOM_SIZE] = {0}; | ||
uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = {0}; | ||
/* inject some a seed for test*/ | ||
for (int i; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) { | ||
seed[i] = i; | ||
} | ||
/* don't really care if this succeed this is just to make crypto init pass*/ | ||
mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); | ||
status = psa_generate_random(output, sizeof(output)); | ||
TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); | ||
status = psa_crypto_init(); | ||
TEST_ASSERT_EQUAL(PSA_SUCCESS, status); | ||
status = psa_generate_random(output, sizeof(output)); | ||
TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); | ||
mbedtls_psa_crypto_free(); | ||
status = psa_generate_random(output, sizeof(output)); | ||
TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); | ||
} | ||
|
||
Case cases[] = { | ||
Case("PSA crypto-init De-init", check_crypto_init_deinit), | ||
Case("PSA crypto- multiple init De-init", check_multi_crypto_init_deinit), | ||
}; | ||
|
||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); | ||
|
||
int main() | ||
{ | ||
return !Harness::run(specification); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we run tests without SPM enabled? Mbed Crypto should work fine without SPM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a different behavior to init with SPM
without you can call init as much as you want and the free releases the context but with SPM in a client-server mode you can have more than 1 client, therefore we keep track on how many time you init and how many times you free.
this test is checking this feature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is just for the crypto init test.