Skip to content

Secure element key creation foundation #157

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

gilles-peskine-arm
Copy link
Collaborator

@gilles-peskine-arm gilles-peskine-arm commented Jun 26, 2019

This PR lays some foundations for creating a key in a secure element. It's work in progress, not yet usable.

What it does so far:

  • Support for import, export and destroy. Any other function on a secure element key is likely to cause a crash.
  • The metadata about SE keys is stored persistently. Not all failure cases are handled.
  • Under the hood, there's a mechanism that functions that operate on keys can use to find out which SE driver handles a key if any (implemented for export). Every such function will need to have this mechanism. I don't think the existing code is the final word on this.
  • The core stores a persistent data buffer on behalf of the driver. The content of the buffer is fully up to the driver. It can be, for example, a slot usage map.
  • Slot allocation is fully up to the driver. The core stores a 64-bit “slot number” for each key.

This PR has reached the goals I wanted to reach for a foundation:

  • Provide enough working code to pass a smoke test (I chose import-export-destroy).
  • Implement enough of the API to see if the information is in the right place where it's needed. I haven't yet implemented the two-phase commit that is necessary to handle power failures during key creation or destruction, but I'm confident that it can be implemented with the current API.

I think the path towards getting this merged is to implement just enough that doing something that isn't implemented yet on a key that is in a secure element would return an error instead of crashing. Implementing more secure element access hooks at this point would be premature: first we should beef up testing.

History:

  1. Original https://github.com/gilles-peskine-arm/mbed-crypto/tree/psa-se_driver-create_key-2
    • Secure element drivers must declare how many “slots” they support, and the core maintains a bitmap indicating which slots are free.
    • Secure element drivers can enforce restrictions on which slot numbers can store which types of keys.
  2. 2019-07-12
    • The core stores a persistent data buffer on behalf of the driver. The content of the buffer is fully up to the driver. It can be, for example, a slot usage map.
    • Slot allocation is fully up to the driver. The core stores a 64-bit “slot number” for each key.

@gilles-peskine-arm gilles-peskine-arm added enhancement New feature or request needs: preceding PR Requires another PR to be merged first needs: review The pull request is ready for review. This generally means that it has no known issues. DO NOT MERGE The PR is not intended to be merged (yet). Usually used for a review of worked in progress. api-spec Issue or PR about the PSA specifications labels Jun 26, 2019
psa_key_lifetime_t lifetime )
{
size_t i;
if( lifetime == 0 )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the same remark as in a different PR - I would suggest swapping zero with a defined constant to signal what does this value mean.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here 0 means no entry. I'll add a comment to explain.

@@ -83,4 +123,10 @@ void psa_unregister_all_se_drivers( void )
memset( driver_table, 0, sizeof( driver_table ) );
}



/****************************************************************/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason behind this comment?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes it visible that this finishes the "Driver registration" section.

Copy link
Contributor

@AndrzejKurek AndrzejKurek Jul 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the end of the file anyway and there's nothing after this section, that's why I ask. It seems redundant to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes planned here.

if( slot == NULL )
return;

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* TOnogrepDO: If the key has already been created in the secure
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be here, at least not in such strange form.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why it's a TODO. Spelled this way so that check-files doesn't tell me something I already know.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not fix check-files in a separate commit instead?

Also, please add a reference in this code comment to a GitHub issue for this TODO, if it's important enough to track fixing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a conscious decision to reject TODO in check-files.sh, so I'm respecting it. Changing our criteria for acceptable code is out of scope of this PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TOnogrepDO will stay in this PR. When Mbed-TLS/mbedtls#2730 makes its way to this branch, we can use TODO.

slot->data.se.slot_number,
slot->lifetime, slot->type, slot->policy.alg, slot->policy.usage,
data, data_length );
/* TOnogrepDO: psa_check_key_slot_attributes? */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be here, at least not in such strange form.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be resolved in a follow-up PR.

* \param before The end of the range.
* It is not included in the search.
* \param[out] found On success, a free slot number such that
* `from <= found < before`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason behind such rule? It will be hard to remember, since it's inconsistent even within this one function call.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand. Why is it so strange that the slot is within an interval, since that's the whole point of the function? What inconsistency are you talking about?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm talking about having the beginning of the range inclusive, but the end - not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the usual way to do ranges, so that end - start = length. What would you expect?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect having the same rules for both sides of the range. I'm not acquainted with other crypto APIs though, so I won't press on changing it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not about crypto APIs, it's about array slices. Most array slicing APIs take (start_inclusive, number_of_items) or (start_inclusive, end_exclusive) as parameters, with end_exclusive = start_inclusive + number_of_items. If you use start_inclusive and end_inclusive, a lot of operations need a +1 or -1, which is awkward and error-prone.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But maybe this would look more familiar with a length parameter instead of an end parameter. I'm considering changing it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moot because this interface has been completely redesigned.

* Success. \c *found contains a slot number which is between
* \p from and \p before-1 inclusive and which is currently free.
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE
* All slots in the indicated range are occupied.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor suggestion: indicated -> requested

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moot because this chunk of text is no longer present.

return( PSA_ERROR_INSUFFICIENT_MEMORY );
drv->slot_usage->size = drv->methods->key_management->slot_count;

/* TOnogrepDO: load */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's still to do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this PR be blocked on loading not being done yet?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be merged as is because it includes a feature that's on by default (SE support) but leads to undefined behavior if used according to the documentation. I don't have precise criteria in mind for when this PR will be mergeable: ideally it would do everything but I also want it to be usable ASAP.

Copy link
Contributor

@Patater Patater Jul 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend not making this PR do everything as a precondition to merging.

Let's try to pick a safe subset to enable by default, and implement that bit. Or, make this off by default until we are comfortable enough with the feature to turn it on by default. The latter approach is quite common and widely known in the industry as a "feature toggle".

We don't want a repeat of PRs we've had trouble merging in the past: ones that keep growing bigger and bigger, and more and more stale.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not planning to remove TOnogrepDO's from this PR in general. This particular one has actually been done.

#define mbedtls_free free
#endif


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Triple whitespace

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's triple whitespace and why is it a problem?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pars pro toto - Three consecutive newline whitespaces. I'm quite certain I haven't seen these in any of the previous MbedTLS files, they seem a bit spacious. Not sure if we have any rule against it though. Pointing it out just in case it's an oversight.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes planned.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should make this 7 consecutive newlines...

7 is better than 3

if( slot == NULL )
return;

#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* TOnogrepDO: If the key has already been created in the secure
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not fix check-files in a separate commit instead?

Also, please add a reference in this code comment to a GitHub issue for this TODO, if it's important enough to track fixing.

return( PSA_ERROR_INSUFFICIENT_MEMORY );
drv->slot_usage->size = drv->methods->key_management->slot_count;

/* TOnogrepDO: load */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this PR be blocked on loading not being done yet?

status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = drv->key_management->p_import(
Copy link
Contributor

@AndrzejKurek AndrzejKurek Jul 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug found by 028eb3d: Lack of error checking

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What error checking specifically? Since we already have a test, whatever that bug is, I propose to fix it in a follow-up PR.

Expose the type of an entry in the SE driver table as an opaque type
to other library modules. Soon, driver table entries will have state,
and callers will need to be able to access this state through
functions using this opaque type.

Provide functions to look up a driver by its lifetime and to retrieve
the method table from an entry.
Instead of having one giant table containing all possible methods,
represent a driver's method table as a structure containing pointers
to substructures. This way a driver that doesn't implement a certain
class of operations can use NULL for this class as a whole instead of
storing NULL for each method.
When creating a key with a lifetime that places it in a secure
element, retrieve the appropriate driver table entry.

This commit doesn't yet achieve behavior: so far the code only
retrieves the driver, it doesn't call the driver.
This slightly increases storage requirements, but works in more use
cases. In particular, it allows drivers to treat choose slot numbers
with a monotonic counter that is incremented each time a key is
created, without worrying about overflow in practice.
Define a structure that is to be instantiated once per driver
instance.

Define a driver initialization method and pass it the driver context.
Pass the driver context to all driver methods except the ones that
operate on an already-setup operation context.

Rename `p_context` arguments to `op_context` to avoid confusion
between contexts.
Add a driver method to allocate a key slot for a key that is about to
be created.
Most driver methods are not allowed to modify the persistent data, so
the driver context structure contains a const pointer to it. Pass a
non-const pointer to the persstent data to the driver methods that
need it: init, allocate, destroy.
Create the driver context when registering the driver.

Implement some helper functions to access driver information.
Since driver table entries contain the driver context, which is
mutable, they can't be const anymore.
@gilles-peskine-arm gilles-peskine-arm removed the needs: work The pull request needs rework before it can be merged. label Jul 25, 2019
@gilles-peskine-arm
Copy link
Collaborator Author

@Patater @AndrzejKurek Thanks for the reviews. I believe I've addressed all your comments except for a few where I'm still waiting for further feedback.

AndrzejKurek
AndrzejKurek previously approved these changes Jul 26, 2019
* If the system crashes while a transaction is in progress, psa_crypto_init()
* calls psa_crypto_load_transaction() and takes care of completing or
* rewinding the transaction. This is done in psa_crypto_recover_transaction()
* in psa_crypto.c. If you add a new type of transactions, be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- If you add a new type of transactions
+ If you add a new type of transaction

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by amending the commit.

Patater
Patater previously approved these changes Jul 26, 2019
Copy link
Contributor

@Patater Patater left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Just one English nit and the rest are non-blocking issues.

@gilles-peskine-arm gilles-peskine-arm dismissed stale reviews from Patater and AndrzejKurek via 66be51c July 26, 2019 11:23
@gilles-peskine-arm gilles-peskine-arm force-pushed the psa-se_driver-create_key branch from cb2e247 to 66be51c Compare July 26, 2019 11:23
Nothing has been saved to disk yet, but there is stale data in
psa_crypto_transaction. This stale data should not be reused, but do
wipe it to reduce the risk of it mattering somehow in the future.
@Patater Patater added the needs: ci Needs a passing full CI run label Jul 26, 2019
@gilles-peskine-arm gilles-peskine-arm removed needs: ci Needs a passing full CI run needs: review The pull request is ready for review. This generally means that it has no known issues. labels Jul 26, 2019
@gilles-peskine-arm gilles-peskine-arm merged commit adb1c52 into ARMmbed:psa-api-1.0-beta Jul 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-spec Issue or PR about the PSA specifications enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants