-
Notifications
You must be signed in to change notification settings - Fork 3k
STM32 MBEDTLS support with HW crypto #12747
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
Conversation
@jeromecoutant, thank you for your changes. |
This PR cannot be merged due to conflicts. Please rebase to resolve them. |
3c0198c
to
54f0d73
Compare
@ARMmbed/mbed-os-crypto please review. |
@jeromecoutant will talk to the team to review this PR, I'll also review later today |
Started CI |
The team was notified , will review |
Test run: FAILEDSummary: 1 of 7 test jobs failed Failed test jobs:
|
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.
LGTM other than some overly strong synchronization
return; | ||
} | ||
|
||
__disable_irq(); |
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.
Is disabling IRQs really necessary? Is there a weaker synchronization primitive we could use here instead?
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.
This is a question of re-entrance.
Depending of the SW architecture, this code can be simultaneously used from different places (several threads, single thread, even within an interrupt).
Nevertheless, one cryptoprocessor HW instance is available and must be shared.
Even in a single thread, user can call mbedtls primitives in different sequences and all this processing can be interrupted.
For all these reasons, disabling IRQ seems to be the most appropriate solution to deal with all these situations.
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.
If we are for sure using this from an interrupt, sure, I agree we need a stronger primitive. However, AES in an interrupt? What's the use case for that? I suspect just thread safety would be enough for crypto operations, which generally take a long time. As crypto operations do take a long time, you certainly don't want to either do them either within an interrupt context or to block all other interrupts during the crypto operation.
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.
I wouldn't expect any mbed TLS crypto calls to be IRQ safe - not sure it's been defined anywhere.
With the current code, the "mutex init" inside the disable_irq would not be legal, if that was leading to an actual RTOS osMutexInit - that can't be called either from IRQ or with IRQs disabled, so the current form doesn't make sense.
I'd also be very much inclined to avoid the complexity by not attempting the juggling - just write in C++ and use a SingletonPtr<Mutex>
. That would have the mutex be statically allocated (if referenced) and initialised on first use.
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.
What can we use to ensure thread safety, knowing that we're trying to release the mutex here that is used at other places to ensure this thread safety ?
Also we're looking for a C implementation that can be used as well outside of mbed-os ...
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.
-Of course, crypto code would not be called within an interrupt (it cannot because it is done with HAL cryp used in polling mode and this implementation will takes too long time in this case. There is no Use Case yet). Sorry for the noise.
-Anyway, you said “mutex_init” (or “mutex_free)” inside the “disable_irq/enable_irq” would not be legal. “mutex_init”/ “mutex_free” are functions with basic processing (chained lists, …). They would not cause a context switch. I do not see what is wrong in calling them with IRQs disabled. Could you explain please?
-“cryp_context_count” and “cryp_mutex_started” should remain valid variables (“atomicity”). I mean more than one instruction can be completed and a switch to another task should not occur until the instructions are executed. What is the right method? Is there a mbed-OS specific function to protect them?
-As pointed by @LMESTM, what would be the C implementation because this code is also used in mbed TLS environment.
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.
osMutexNew
from IRQ isn't legal because the CMSIS RTOS docs say so.
In practice, it's because RTX uses supervisor calls both for memory protection and serialisation, and for any call to be usable from interrupt or with interrupts disabled on Cortex-M they need an alternative non-supervisor-call form to be manually coded. That's only done for the calls that are needed from IRQ, like osSemaphoreRelease
It's a cute "feature" of the ARM-M architecture that the SVC
instruction causes a Hard Fault if issued with interrupts disabled. Quite different to ARM-A.
An increment of cryp_context_count
won't be atomic in hardware, because it's "load", "add", "store" - three instructions. Breaks if there's a task switch between the load and store, and someone else increments or decrements in the meantime. A plain load or store can be, but you still have potential compiler reordering issues, plus the fact you're performing a complete operation - the mutex init - it's not just one access.
If you're trying to write embedded-portable C code here, I don't think there's a portable construct for atomic operations. C11 and C++11 both have them, but implementations aren't always ideal in embedded. Mbed OS has mstd::atomic
, which is a local implemenation of std::atomic
, but other platforms won't have that. So I think atomics are out.
In Mbed OS I'd use singleton_lock()
to protect your reference count and mutex creation. Is there any equivalent in mbed TLS porting layers? Or is there any place you could guarantee a central init call to init your master mutex?
std::mutex
guarantees auto-init on first lock
- without that you basically need a single init entry point, else you start needing a mutex to protect your mutex creation, and you're stuck in a loop.
|
||
CRYP_HandleTypeDef hcryp_aes; /* AES context */ | ||
uint32_t ctx_save_cr; /* save context for multi-context */ | ||
} |
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.
I'm very happy not to see space reserved for VIA padlock here. Nicely done. :)
return; | ||
} | ||
|
||
__disable_irq(); |
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.
Any weaker synchronization we can use here?
Here any any other places we use __disable_irq()
.
{ | ||
AES_VALIDATE(ctx != NULL); | ||
|
||
__disable_irq(); |
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.
Any weaker synchronization we can use here?
{ | ||
CCM_VALIDATE(ctx != NULL); | ||
|
||
__disable_irq(); |
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.
Any weaker synchronization we can use here?
|
||
mbedtls_zeroize(ctx, sizeof(mbedtls_aes_context)); | ||
#if defined(MBEDTLS_THREADING_C) | ||
if (cryp_mutex_started) { |
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.
Only if cryp_context_count
is now zero, surely? But as with the mbedtls_mutex_init
, this wouldn't be legal with interrupts disabled.
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.
@tbistm as pointed by @kjbracey-arm - shouldn't you check that cryp_context_count is 0 ?
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.
As pointed by @kjbracey-arm, mutex should be freed when it is no more used. This point is relevant and valid.
This PR cannot be merged due to conflicts. Please rebase to resolve them. |
@ARMmbed/mbed-os-maintainers waiting for Arm feedback |
@jeromecoutant what do we need to get this moving? |
Pull request has been modified.
@Patater could you re-review this please ? |
Wait a little, I am implementing @kjbracey-arm comments :-) |
@Patater @kjbracey-arm |
Let's start CI ? |
Test run: SUCCESSSummary: 7 of 7 test jobs passed |
Summary of changes
This pull request enables HW crypto use for all STM32 which support it
STM32F7 specific information:
STM32F4 specific information:
@ARMmbed/team-ublox
STM32L4 specific information:
STM32WB specific information:
@donatieng
STM32L5 specific information:
@ARMmbed/team-st-mcd
@Patater
Impact of changes
Migration actions required
Documentation
Pull request type
Test results
Verified with benchmark application from:
https://github.com/ARMmbed/mbed-os-example-tls/tree/master/benchmark
and MBEDTLS selftests
Few details from this benchmark application:
Reviewers