-
Notifications
You must be signed in to change notification settings - Fork 3k
Device key implementation #6642
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
drivers/DeviceKey.h
Outdated
return instance; | ||
} | ||
|
||
virtual ~DeviceKey(); |
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 is dtor virtual? I do not see any virtual methods, not intended to be a base class ?
drivers/DeviceKey.h
Outdated
* @param output buffer for the CMAC result. | ||
* @return 0 on success, negative error code on failure | ||
*/ | ||
int calc_cmac(const unsigned char *input, size_t isize, uint32_t *ikey_buff, int ikey_size, unsigned char *output); |
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 chosen calc
rather calculate
?
drivers/DeviceKey.h
Outdated
* @param ikey_type type of the required key. Type must be 16 bytes or 32 bytes. | ||
* @return 0 on success, negative error code on failure | ||
*/ | ||
int device_key_derived_key(const unsigned char *isalt, size_t isalt_size, unsigned char *output, uint16_t ikey_type); |
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.
device_key_derived_key
- I have to read the description what it does, can this have more meaningful name? From the description - generate_derived_key()
or similar? Device key is object's name.
drivers/DeviceKey.h
Outdated
#define DEVICE_KEY_16BYTE 16 | ||
#define DEVICE_KEY_32BYTE 32 | ||
|
||
enum DeviceKeyStatus { |
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.
These are return types:
- why then methods have
int
return type ? - not part of the class?
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.
Using the enum can cause type problems in C++. Especially when errors need to be propogated upwards. Just using int simplifies a lot of things for users.
Either way @SenRamakri has bigger plans with error codes.
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.
@0xc0170 @geky
There is a process now to add Error Codes to mbed-os and when this happen, we will change the implementation to use the new error codes mechanism.
Until then We thought it is better for our code to use an internal error code mechanism and return int in order to excuse the caller from the need of using our enum.
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.
Sounds good to me. Still does not answer my second question why is this not part of the class itself.
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.
@0xc0170
Actually only because it mimics the idea of the future solution of _MbedErrorStatus enum. I don't mind to make it part of the class but it’s not the way it would be implemented in the future.
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.
Personally in these situations I still use the enum but then use a typdef in any location where data might be used by another processor.
Then again that's what I do for C not C++.
Worst case I'd rather a typedef be used than a bare int; to give better context for anyone using it.
drivers/DeviceKey.h
Outdated
* @ingroup drivers | ||
*/ | ||
|
||
class DeviceKey : private mbed::NonCopyable<DeviceKey> { |
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 about interrupt safety/thread safety? There should be a note for a driver
@yossi2le Who should review this addition? I would assume nvstore and mbedtls teams. Let me know, I'll assign reviewers |
Please review Ci failures (travis docs and events) |
NVStore is only available if the device has programmable flash (DEVICE_FLASH macro). Does Device Key need the same? (Cause of build failures) |
@0xc0170 regarding the review of nvstore and mbedtls. mbedtls indeed should be assigned to this review. nvstore from the other hand is under my team (storage) responsibility. |
@geky. Thanks for that, you absolutely right about the DEVICE_FLASH macro. |
ARM Internal Ref: IOTSSL-2222 |
…and fixing doxygen issues
drivers/DeviceKey.cpp
Outdated
goto finish; | ||
} | ||
|
||
return DEVICEKEY_SUCCESS; |
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.
The cipher context must be freed on case of success, too. Suggestion: just set ret = DEVICEKEY_SUCCESS
here.
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.
@hanno-arm
10x for that. it will be fix.
drivers/DeviceKey.cpp
Outdated
|
||
finish: | ||
mbedtls_cipher_free( &ctx ); | ||
return ret; |
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.
You are returning a mixture of own error codes and Mbed TLS specific ones here -- is this intended?
drivers/DeviceKey.cpp
Outdated
trng_init(&trng_obj); | ||
|
||
int ret = trng_get_bytes(&trng_obj, (unsigned char *)output, in_size, &size); | ||
if (DEVICEKEY_SUCCESS != ret || in_size != size) { |
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 not valid use of the TRNG API -- trng_get_bytes
is allowed to return less than what was requested, and in this case it's the responsibility of the caller to repeat the call until enough entropy has been gathered.
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.
@hanno-arm
10x for that. Actually the documentation is not clear enough and I think missing an example. I have fixed it. Please review and let me know if this answer the API requirement.
drivers/DeviceKey.cpp
Outdated
|
||
finish: | ||
if (double_size_salt != NULL) { | ||
delete[] double_size_salt; |
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.
Please reliably zeroize double_size_salt
to avoid leakage in memory. Consider e.g. mbedtls_zeroize
.
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.
@hanno-arm
mbedtls_zeroize is static function duplicate inside every mbedtls module. For now I have copied it as static function to my code. I think we should discuss on where this function should sit in order to have only one copy for everyone.
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.
@yossi2le Moving the zeroize function to a separate compilation unit is being considered at the moment. For now, I suggest we live with the additional copy here.
drivers/DeviceKey.cpp
Outdated
} | ||
|
||
//Double the salt size cause cmac always return just 16 bytes | ||
double_size_salt = new unsigned char[isalt_size * 2]; |
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 it is the reason for the use of this doubled salt, as opposed to a different modification of the salt to generate the second half of the key?
Are you following some standard here?
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.
@hanno-arm We are open to proposals. We do not have any preferences here. If you see any problem with the current method please let us know.
drivers/DeviceKey.cpp
Outdated
} | ||
|
||
//First we read if key exist. If it is exists, we return DEVICEKEY_ALREADY_EXIST error | ||
uint32_t read_key[DEVICE_KEY_32BYTE / sizeof(uint32_t)] = {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.
Why is read_key
not defined as a uint8_t
array?
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.
@hanno-arm This is because NVStore had API of uint32_t. This is internal allocation therefore has no impact externally. Do you have any concerns?
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.
@dannybenor No, I don't have concerns, I only found it surprising when I read it. Thanks for your answer!
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.
The TRNG API usage is not used correctly, and the salt needs to be reliably zeroized in the key derivation function.
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 would like to request more information on why CMAC was used here for the key generation. A natural alternative would be to use Mbed TLS' implementation of PKCS5-PBKDF2 instead (HKDF is not yet implemented in Mbed TLS, unfortunately). This function takes password and salt of variable lengths and generates a key of variable length from it using HMAC as the underlying primitive. Using this seems straightforward and would also allow to make the DeviceKey
interface more flexible by supporting an arbitrary output key length, which might be useful in the future.
Build : FAILUREBuild number : 2107 |
@yossi2le @dannybenor Fyi, it looks like we're still facing some CI node issues. Will restart once things are stable again. |
/morph build |
Build : SUCCESSBuild number : 2108 Triggering tests/morph test |
Test : FAILUREBuild number : 1909 |
Exporter Build : SUCCESSBuild number : 1741 |
Starting tests now. We identified that some boards require bigger timeout (test takes at least 40 seconds for some nucleo and GCC ARM, tested locally). /morph build |
Build : SUCCESSBuild number : 2123 Triggering tests/morph test |
Shuffling around some jobs. /morph export-build |
/morph test |
Test : SUCCESSBuild number : 1921 |
Exporter Build : SUCCESSBuild number : 1754 |
/morph uvisor-test |
2 similar comments
/morph uvisor-test |
/morph uvisor-test |
Approved from my side |
|
||
do { | ||
|
||
mbedtls_cipher_init(&ctx); |
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.
@yossi2le What is the reason you moved init+free
inside this loop?
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.
@hanno-arm
Two devices was failed during CI tests in the second round of the loop when we did CMC update.
We have suspected that maybe free and init will clear up some resources and move it into the loop what actually solved the problem.
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.
@yossi2le That shouldn't happen and should be investigated. In any case, free + init
in every iteration is valid usage, too, for the new version is certainly fine.
Description
This PR introducing the device key implementation.
The DeviceKey is a mechanism that implements key derivations from a Root Of Trust (ROT) without ever exposing the ROT itself. In DeviceKey there are two API's, one for key derivation of 128 or 256 bits keys and one for injecting the ROT. injection of ROT is needed only if True Random Generator (TRNG) is not supported.
More details and example can be found in the following repository:
https://github.com/ARMmbed/mbed-os-example-devicekey
Pull request type
[ ] Fix
[ ] Refactor
[ ] New target
[X ] Feature
[ ] Breaking change