API function to register an existing key
As the developer of an application (or application stack) using the PSA crypto API on a device with a secure element, I want to access keys that are provisioned onto the device by a process outside of my control, so that my application can use pre-provisioned keys while sticking to the PSA API.
The idea is that many devices that have a secure element have a factory process for injecting credentials. That process exists and can't be retooled easily, so we can't insist that this process becomes aware of the PSA API. The device does have a software stack that implements the PSA crypto API. Through that API, we can create new keys and use them. But there's no standard way to use the credentials that are provisioned during the device manufacturing.
More generally, there's interest in using a key through PSA even when it's created through proprietary means.
Mbed TLS implemented a function to do that alongside its original secure element interface: mbedtls_psa_register_se_key(). That API was tied to the interface, and had some limitations (notably, it can't be used with volatile keys), so in our next major release (TF-PSA-Crypyo 1.0), we are evolving the API. We have heard interest in making this feature official in the PSA API.
The starting proposal is as follows:
psa_register_opaque_key(
const psa_key_attributes_t *attributes,
const uint8_t *label, size_t label_length,
psa_key_id_t *key_id);
This is a key creation function, taking attributes as input and key_id as output like the others. The way to obtain the key material is by associating the PSA key identifier with some existing “slot”. In PSA terms, the meaning of the label parameter is implementation-specified, and likely to be different for each supported key location.
With Mbed TLS opaque drivers, there are two plausible meanings for label:
- It could be whatever the driver expects as key data — what you'd get as output from asking an opaque driver to import/generate/derive a key.
- Or it could be an input passed to a driver callback.
In practice, the primary intent is to pass a slot number, or slot label, or key name, in the secure element.
Unresolved question: does psa_destroy_key only destroy the PSA key stub, or does it also destroy the underlying key?
Unresolved question: what can this function mean for transparent keys (keys in the location PSA_KEY_LOCATION_LOCAL_STORAGE)? Possibly this might duplicate the functionality that Mbed TLS calls “built-in keys”, which are a way to access keys that were not created through PSA, such as a HUK or HUK-derived key. These are independent features in Mbed TLS partly for historical reasons, but also because they are intended for different scenarios, and it's unclear whether a unified API would handle all the desired scenarios. Typically, the set of available built-in keys is decided by the device integrator and will not change over time, whereas registrable keys can be created dynamically if the proprietary provisioning scheme extends after the factory phase of the device lifecycle. Also they interact very differently with driver dispatch.
Timeline: we would ideally like to release the official psa_register_opaque_key in TF-PSA-Crypto 1.0, which means the official API should be stable (not necessarily released) by late June 2025.
It strikes me that this is closer to Import than it is to Generate.
It is essentially Import, but instead of a buffer with the bits, that you need to move to a protected location, you already have the bits in a protected location and simply need to add the metadata.
If the key is persistent, the metadata and the key material would end up being stored in different places.
So, that leads to the question, does register need to support persistent keys. Would it be acceptable for the application to have to call register each time and to get a volatile handle.
This does of course mean that the discussion on what happens if you try to destroy the key is moot.
So, that leads to the question, does register need to support persistent keys. Would it be acceptable for the application to have to call register each time and to get a volatile handle.
Hmmm, I hadn't really considered that. We did have a request for the volatile case to work. But I think the primary use case is a persistent metadata object:
- The key material is injected during device manufacturing.
- The key metadata is created during application provisioning.
- After that, the application uses the key without knowing where it comes from. Quite possibly the application works with a key that can be pre-provisioned or not depending on which device model it happens to be running on.
I'd expect that in such scenarios, steps 2 and 3 tend to be done by different pieces of code, and the code that uses the key wouldn't know whether to call register and with what label.
Good point
Is it ok to register a persistent key with a key ID outside the application range? This may be tempting in when the registered key is vendor-specific and not handled by normal application code. However, it would be difficult to specify and implement, since such keys should not interfere with volatile keys and any other mechanism by which an implementation may define keys in the implementation range. So I think the answer is no, the same key IDs are acceptable for register as for import/generate/derive.
So this is intended for binding a PSA Crypto key identifier, and key attributes, to some existing key material that is already stored within the implementation under some other naming scheme (the label).
API name
Presumably, as the material is already internal, it will be stored in a specific key location, and the key lifetime in the provided key attributes is essential for the discovery and registration of the key id with the key material. Given that support for unbound key material, and the naming scheme, will be implementation and storage-location specific - I would like to propose that the API name dropped the opaque infix, as this term is not part of the existing specification language. I.e. the API is just psa_register_key().
As an alternative name, I would also suggest psa_bind_key() - as the API binds a key id and attributes to existing key material. However, is there any risk that using the term 'binding' might confuse this with 'cryptographic binding'?
Key attribute handling
Is there any expectation of which key attributes would already be associated with the key material? For example:
- key lifetime/location is known
- key size is known
- key type would PROBABLY be known
- key policy MIGHT be known Would we need flexibility in integrating values in the supplied key attributes with those of the existing key; or can we be strict and require that any provided key attributes must match the key material?
On key destruction
On the question of what happens with psa_destroy(). I think it is difficult to handle all envisaged use cases cleanly if this API sometimes destroys the key material, as well as the meta-data binding; and sometimes just undoes the registration process. Would this depend on the key persistence attribute (part of lifetime) - and is this application determined, or implementation determined?
A suggestion that enables both the intention of the application, and the behavior permitted by the implementation, to be clear, would be to add a separate unregister function that explicitly undoes the actions of psa_register_key(). An application that expects to destroy the key material would use psa_destroy_key() as before - but an implementation is permitted to deny such a request for any or all of this type of key.
We might want to consider if would be permitted, and what it would mean, to create a key, and then unregister it?
With the statements on @athoelke, I'm happy to see "opaque" being dropped from the name in the initial proposal.
Main criticisms:
My main criticism of the initial proposal in this issue (as I've raised in the Mbed TLS biweekly):
- This API is describing something specific to driver level and that the initial proposal is not very generic.
- If we are to add APIs for key-relevant registration it should be generic and natural additions to the existing key management APIs
- Alternatively an addition could be considered for the vendor-specific scope (e.g. tied to psa_key_attributes_t) to hide this from front-end APIs for key management.
When discussing the means of additional context-information that is retrieved from or passed to to any specialized (opaque) driver, I feel it is natural to also discuss a "standard case", where the driver-specific information is already provided, as-is, meaning that the "registration" is inherit in the system and is not something you are required to do with extra API calls. What I mean by this is the case when no additional context-information is required to be passed to any opaque driver to be able to use the driver and its keys
Inherent-registration versus runtime-registration
Inherent registration can be described as follows: Compile-time established link between between a key_id and lifetime to a "driver slot" or any type of address-based locality expressed by the secure element, secure enclave or any type of opaque driver which constitutes an "external storage of keys", Including additional metadata that is relevant for key or driver usage
Runtime-registration can be described as follows: Establishing the aforementioned link between key_id and lifetime to a "driver slot" including setting up additional metadata that is relevant for key usage in runtime
Points for consideration:
- Is the type of per-key registration so specialized that it merits usage of
psa_import_keyor similar APIs instead, since the key is not valid for use by the driver without additional content information? - Why is there a need for an additional front-end API for something that potentially could be solved in compile time or on driver-specific level?
- Is the addition in the front-end APIs a bit too decentralized from the key usage scope?
Registering per-key or per-driver
The issue lists a proposal is focused on per-key registration which is the widest granularity possible for adding metadata to a key in a special driver. This is the main reason psa_import_key is mentioned as an alternative. One can wonder if there is potentially a need for a wider registration, something that could be handled per-driver instead of per-key.
Regardless, if the registration is with the following API:
psa_status_t psa_register_key(psa_key_attributes * attributes,
const uint8_t * metadata, size_t metadata_length,
psa_key_id_t * key_id)
.. then there is a potential of a double registration of key_id coupled with attributes if the usage-patterns ever follow a strategy similar to the builtin keysupport (see later).
And there is an option that the information is vaguely passed from per-key registrations when it is indeed intended per-driver
One option that is likely a bit clearer, which would allow for both types of registration (per-key and per-driver) is to extend the functionality of the psa_key_attributes_t structure type to hold vendor/implementation specific contributions for any type of context-based metadata. Meaning extending the APIs to manage key attributes to add and retrieve custom data:
I propose the following extension:
psa_set_key_metadata(psa_key_attributes_t * attributes,
const uint8_t * metadata, size_t metadata_length);
psa_get_key_metadata(psa_key_attributes_t * attributes,
uint8_t * metadata, size_t metadata_size, size_t * metadata_length);
When using these APIs we would achieve the following:
- Registration is avoided if it is unneeded (if keys can be resolved on driver-level)
- Relevant information for key usage is centralized in a relevant structure for keys
- The granularity of registration can be as wide as per-key (if needed) but is general enough that it is possible to pass per-driver
- Implementations can choose to provide macros for specialized initialization of the
psa_key_attributes_tstructure- Without filling in any additional information using
psa_set_prefixed APIs. - Avoiding specialized call to
psa_import_keyas mentioned before. - Possibly providing per-driver information if the information is reused on multiple keys/algorithms
- Without filling in any additional information using
- If the driver key type is inherently registered, there is no need to run additional APIs (same as today).
Implementation details: It would be best for API to keep this additional feature in psa_key_attributes_t structure as an optional construct so that current implementation isn't imposed an ABI change
Implementation details: It is likely best for the API to store the additional metadata as a pointer and size so that ABIs breaks can be avoided
Background: Builtin key support and SE drivers (driver)
The additions in the raised issue is done to help transition away from the now deprecated methodology of SE drivers in Mbed TLS distribution (now placed in TF-PSA-Crypto)
The existing functionality of SE drivers lives alongside the so-called builtin key support which has multiple points of documentation in the Proposed scope of documentation in TF-PSA-Crypto. The builtin keysupport in itself is a type of opaque-like driver support, but it has the ability to reuse existing transparent drivers if the keys are passed out in-the-clear.
Using the existing builtin key support as a starting point one can see that one of the mandatory APIs to implement is the get_builtin_key driver API, which would populate the key attributes structure and optionally fill in a key_buffer which is used in actual calls.
Note: It is possible to provide any driver-specific metadata via the key_buffer parameter or via the psa_key_attributes_t structure and in case of a "inherit registration" (where everything is known at compile-time or can be resolved through runtime). The builtin key support that is provided today is sufficient to give support for opaque keys as long as the registration is inherent
For any register-like calls where additional information is passed to support opaque drivers (via opaque keys) I hope the information is transferred all the way towards the driver (similar to the existing builtin key support), meaning that PSA crypto implementation above the driver level is only used to route and forward information directly to driver scope and that it is the drivers responsibility to hold and indeed consume this context information.
The implementation example provided here will assume a driver named acme and expect that the acme term is used as a prefix for all APIs
APIs for registering per driver
Given the initial proposal for psa_register_key the implementation would likely be:
psa_status_t acme_register_key(psa_key_attributes_t * attributes,
const uint8_t * metadata, size_t metadata_length,
psa_key_id_t * key_id);
I deem this a double registration because the population of the attributes-type tied to key key_id comes in addition to anything that is inherently registered (by lookup) and provided back as a populated psa_key_attributes_t structure e.g. by using the get_builtin_key API
APIs for registering via psa_key_attributes_t
Alternatively by extending the psa_key_attributes_tstructure the registration is avoided and instead the driver can consume additional metadata by implementing the following APIs:
psa_status_t acme_set_key_metadata(psa_key_attributes_t * attributes,
const uint8_t * metadata, size_t metadata_length);
psa_status_t acme_get_key_metadata(psa_key_attributes_t * attributes,
uint8_t * metadata, size_t metadata_length, size_t * metadata_size);
In this case the following usage-pattern would be possible:
/* Given some_driver_key_id */
psa_status_t status;
psa_key_attributes_t attributes;
/* Populate key attributes from driver, constituting a registration */
status = psa_get_key_attributes(some_driver_key_id, &attributes);
if (status != PSA_SUCCESS) {
return status;
}
/* Given some custom metadata */
psa_set_key_metadata(attributes, &attributes, metadata, metadata_length);
/* Run PSA crypto operations as-is */
Note: This would avoid additional registration beyond lookup-rules for key_id + lifetime processed by a driver (via psa_get_key_attributes).
Final note: I purposefully made use of psa_get_key_attributes to populate information about the key as expressed via any driver. This type of usage-pattern seems useful to populate any relevant information towards an existing or a newly established key. Technically an implementation of a driver specific API acme_get_key_attributes could be used to unify any type of transparent-like drivers (like for a builtin key that is providing full key buffer) and any type of opaque key representation (without providing any key buffer on driver wrapper level)
The main benefit of using psa_get_key_attributes to fully resolve keys is that this is an API that can be called by any and all code without any knowledge about implementation-specific details like whether or not a driver is opaque, transparent, locally stored etc, leading to the best possible reuse
Thank you very much for writing this detailed proposal!
Inherent-registration versus runtime-registration
psa_register_key() is meant to support runtime registration. It can be used for inherent registration, but it isn't the most convenient way to do so.
If there is only one method, then it would have to be runtime registration, because at least it's possible to use it even if you know exactly what to register at compile time. Not that I think there's only one method: I do think we should have both.
Registering per-key or per-driver
I'm a bit confused by this sentence:
The issue lists a proposal is focused on per-key registration which is the widest granularity possible for adding metadata to a key in a special driver.
I don't understand how key registration is “adding metadata”. I see it from the point of view of the key store. When you create a key, the key material has to come from somewhere. We already have three ways to obtain key material: given to the API call (import), randomly generated (generate), or calculated from other keys (derive). Registration is when the key material already exists, and the API call is told where to find it. (It can also be used with key material that is wrapped with an implicit wrapping key, although this is probably not the best way to do that.)
With respect to per-driver registration, I agree that there should be a way for drivers to advertize their built-in keys. The current proposal for built-in keys i s incomplete because the caller has to know which “slot number” to hit. I'm definitely open to other proposals.
On additional metadata in attributes
It is possible to add extra fields to the attribute structure with variable-size data. We made sure this could be done by mandating a call to psa_reset_key_attributes(), which must be called before deallocating a psa_key_attributes_t: it can free the heap blocks owned by the attribute structure.
In Mbed TLS 2.x, we added two extra fields in the attribute structure:
- A fixed-size
slot_numberfield, indicating the location of the key in a dynamic secure element. This cost extra memory which we did get complaints about, not unwarranted. And having a fixed size forced slot numbers to fit a certain format which doesn't work well on all systems: some higher-end platforms want names. - A variable-size
domain_parametersblock, containing extra type information that doesn't fit in a 16-bit type. We used it to provide a way to create RSA keys with a non-default public exponent: the domain parameter of an RSA key was its public exponent. We were planning to use it for custom Diffie-Hellman groups, but we never ended up implementing that.
These extra fields, especially the variable-size domain parameters, proved to be a pain, and they never progressed beyond experimental status. In particular, we got rid of the domain parameters in Mbed TLS 3.6.0. The cost is additional complexity, code size, and RAM usage.
Having the variable-size domain parameter infects any code that calls psa_get_key_attributes, as well as the implementation of psa_get_key_attributes and of key creation functions. That's more variable-size data to manage, which is an additional burden in client-server implementations. It means the application has to worry about leaking memory via a psa_key_attributes_t. So it's possible, but I find it to be a major detriment.
Having data in the attributes only makes sense if you're likely to want to know about it often. The “physical address” of a built-in key doesn't matter during normal usage in the application: you don't need to know that the key is in slot 3 to check what algorithm it's for or perform an operation on it. So it should be passed when the key object is created (“link a key identifier to this existing key material”), and that's all. Hence it should not be in the attribures. Similarly, to generate an RSA key with a non-default public exponent, we now have a function psa_generate_key_custom() where the desired exponent is passed in a separate parameter.
Who chooses key identifiers?
The API currently distinguishes only two entities: the application and the implementation. Each have their own range (2^30-1 keys each). From the perspective of the current API, “the implementation” is monolithic. So far, we've tried to avoid any normative statement about the architecture of the implementation, because we think the API is applicable to a very broad range of architectures, and we want to have application code (and libraries) that are source-compatible between such very differently architected implementations.
The key registration mechanism proposed here is an API call, hence it assigns key identifiers in the same way as the other key creation functions: application choice for a key whose metadata is stored persistently, implementation choice with dynamic allocation for a key whose metadata is not persisted.
Driver registration comes with a new challenge: who decides on the key identifiers? Given that key identifiers have a fixed size, there's no easy way to partition the space. (I wish we had directories, but the cost of directories is very high for the low end of platforms that we want to support.) Hence I tend to favor an extra level of indirection, rather than letting each driver choose: making it the integrator's prerogative. Of course, arguably this is a non-problem in most cases, because most of the platforms we target only have a single driver.
Thanks for the response. I will reiterate a few concepts over the weekend to hopefully make them clearer with regards to my use of the term granularity both for per-driver and per-key-in-driver.
But I want to quickly point out the obvious existing solution to separate keys in domains and to designate and differentiate between keys in local store and key in any external store or in fact any custom transparent or opaque driver. The PSA spec defines the key lifetime with a fully customizable location information. This is enough information to establish separated domains, to route special key management functionalities all the way down to the driver level. My claim is that you don't need to involve the storage mechanism in the PSA core to a large degree. And in doing so the attribute structure is a common, existing way to hold, store, and pass information in and out from the driver. This type is already used in this manner in the PSA Crypto Driver Wrapper APIs.
Why invent something special to be implemented in the PSA core? Especially if all the implementation details can be on driver-level and down, including driver-specific information on how a key is to be handled and/or used and any relevant memory management to do so....
Why not let everything just be resolved via passing key_id plus lifetime/location all the way down to driver and let all information retrieved with a driver-specific lookup that populates a psa_key_attributes_t structure? Structure information that includes any and all inherently registered and/or runtime registered information relevant for a given driver (if this is needed)
I think there are several overlapping use cases in the discussion here, and I agree that the proposed API is not effective for all of those use cases.
Incomplete provisioned keys
The proposed psa_register_key() is specifically useful in the situation where key material has been provisioned to a driver within the implementation, but the driver does not have the full set of attributes. For example, this might arise when the Crypto API is adopted for use with existing protocols where the application is trusted to use the key material correctly - so key type and policy metadata is not provisioned with the key material.
Here the application has to provide the missing attributes before the material can be used as a 'Crypto API key'. So, the API must (a) be part of the application API and (b) operate on a key-by-key basis. psa_register_key() API provides an application-chosen key identifier for use with existing key material in a "named" location inside the key store.
Are there also use cases where the PSA key identifier would be allocated by the implementation for such a key, rather than selected by the application?
'Built in' keys with attributes
In other scenarios the implementation, or a driver, has keys that appear to be 'built in' from the application point of view. The keys exist with a Crypto API key identifier, and have a full set of attributes. These might be immutable keys (provisioned during manufacture), derived-on-demand from immutable secrets, provisioned by other protocols for use by the application, etc. For these use cases, there might need to be a driver-level interface to publish these keys to the key store; and some way to make the key identifiers known to the application.
Although psa_register_key() could be kind-of made to work to map a location and "name" to a key identifier, but it is awkward to use (an full set of attributes is expected, but will not be used), and doesn't make sense as a key-identifier discovery API for such keys.
I suspect that an API (or APIs) that work well for these keys, would not be able to address the 'incomplete key' scenario. Maybe we should consider this separately for designing a suitable API?
Regarding the "does the key identifier now 'own' the key material, or just 'use' it?" scenarios - where one suggested option is to use different APIs to remove the identifier (e.g.psa_destroy_key() vs psa_unregister_key()) - there might be a better way to do this. The first idea has the issue that different key cleanup is required depending on how the key is initially set up - which is a significant change in the API.
An alternative would be to introduce two new registration functions, depending on the application intent:
- If the application expects to take ownership of the key material, it calls
psa_register_key(). A subsequent call topsa_destroy_key()will erase all of the key identifier, the key meta-data, and the key material. It would make sense to require that an implementation does not permit this type of incomplete key to be registered by more than one caller? - If the application is just temporarily attaching a key identifier (and attributes) to the key material, it calls
psa_link_key(). A subsequent call topsa_destroy_key()will erase the key identifier and application-provided meta-data, but the pre-existing key material remains in the original location. An implementation could perhaps permit multiple callers to link key ids to the same key material?
This is perhaps a cleaner API, as the application intent is provided at the point of establishing the key id - so no key store resources are allocated in the case that the intended usage of the key material does not match what the driver permits for that key material.
A key store entry has three parts:
- Key material. Here we are concerned with key material that is created by means that do not involve the PSA API, and we want a PSA API to access the material. The primary scenario is granting access to key material that is stored somewhere, although some APIs may also cover cases where the key material is created on demand by deriving from some master key. The entity that manages the subsystem on which the key resides (e.g. secure element) knows how to access the key material.
- Policies indicating how the key can be used. This covers the key type, the algorithm policy, and access control in some multi-application implementations (which is out of scope of the standard API). Knowledge about these policies may come from the same source as the key material, from the device or platform integrator, and possibly from the application that uses the key — this part is highly variable.
- An identifier that allow the application to refer to the key. Only the device or platform integrator can take the final decision in assigning this identifier, because there is a single namespace. A secure element vendor can propose identifiers, but where this role is distinct, the platform integrator must decide. On a multi-application platform, this concern overlaps with access control policies, since a way to restrict the visibility of a key is to be selective in terms of which clients are allowed to have an identifier for the key.
I see several types of use cases discussed here, and they differ in who can make policy decisions as well as the scope of the identifier.
- A key is created during manufacturing and may be used according to a specific policy. Applications just want to have a way to use the key in an operation (including get-attributes and export-public). The integrator wants to keep out of the loop as much as possible, so that device manufacturers can declare keys and they will be automatically available to applications. This scenario was meant to be covered by built-in keys. The API discussed here may work for this scenario, but it isn't its primary goal.
- A key is created during manufacturing, but without complete policy information. Applications want to have a way to use the key in an operation, but may want to have a say about policy (e.g. if the key can be used for multiple algorithms). The integrator wants to give the application access to the key, possibly providing missing policy information. The application is not supposed to ever destroy the key; it may be permanent, or only modifiable by proprietary means. This is the main intended scenario here.
- A key is created during manufacturing, but without complete policy information. Applications just want to have a way to use the key in an operation (including get-attributes and export-public). The integrator wants to provide policy information, preferably once and for all, taking ownership of the key material. The application (possibly a specific key management application) may then destroy the key and possibly replace it (e.g. to handle device refurbishing). This was the original intended scenario for
register_se_key, but I'm not aware that it is important in practice. A proprietary alternative for taking ownership exists: creating a key file in storage manually.
Scenario (2) is best covered by psa_link_key creating a volatile key. Destroying the volatile key has no impact on the underlying key material.
Creating a temporary reference to a volatile key object has broad applicability:
- It can handle both pre-stored key material, and key material derived on the fly (per-application, per-epoch...).
- It's agnostic in terms of the lifetime of the key, as long as it doesn't get destroyed while in use. In particular, there's no risk of a mismatch between the lifetime of the metadata in storage and the lifetime of the key material.
- It works reasonably well even for built-in keys (although this is a secondary concern).
So my preference is shifting towards psa_link_key() (although I'm not fully happy with the name), and I now wonder if it should support persistent keys or only volatile keys. I do think that a psa_register_key() that takes ownership could also make sense, but it isn't a priority if we have psa_link_key().
Some alternatives to psa_link_key():
-
psa_associate_key() -
psa_identify_key() -
psa_connect_key() -
psa_map_key() -
psa_bind_key() -
psa_attach_key()
2025-05-13 discussion:
-
psa_attach_key()is the least worse name. - It only accepts keys with a volatile lifetime. Persistent lifetimes are rejected.
- Destroying the key does not affect the key material.
- The implementation may refuse certain attribute combinations. This is mostly case-specific. The implementation must reject key types and sizes that are inconsistent with the key material (e.g. attempting to attach an 8-byte key blob with
PSA_KEY_TYPE_AESmust fail).
It only accepts keys with a volatile lifetime. Persistent lifetimes are rejected.
In discussing the behaviour here, we realised that the specification's description of 'volatile keys' is inconsistent. I'll write that up as a separate issue, and provide a proposal to fix/clarify this (Issue #262)
There seem to be two cases.
The first is where the key is n a block of memory, that the PSA crypto implementation can read, but is assumed by the caller to be immutable.
This is essentially an import function. And unless the implementation knows at compile time that the location is immutable and available, - should be treated as an import.
The second case is where the key is in a location that is inaccessible except though the driver API. For example, in a slot in a SE.
So I think you need
- a psa_key_location_t:
- a pointer and length
For the default location, the pointer points to the actual key material. And the function cannot assume the input is immutable, so should copy it into volatile memory - so this is almost identical to import and perhaps the caller should use import.
For any other location, it points to material that can be passed to the driver to identify the key. Normally this is only used between the implementation and the driver - so we do not document this. So I think this needs to be opaque - and we assume there is some out of band method for the application writer to obtain it.
The first is where the key is n a block of memory, that the PSA crypto implementation can read, but is assumed by the caller to be immutable.
That's a possible use case, but I don't think this follows:
For the default location, the pointer points to the actual key material.
This is only useful if the crypto core can't read from that address (otherwise psa_import_key works), but some other more trusted part of the system does, and the caller knows the address (so it lives in the same addresss space, but maybe with different memory protection rules). So we're talking about a system where memory protection is both simple enough not to involve an MMU, and complex enough that the crypto core spans multiple levels of privileges.
I would expect that in far more cases, what you pass to psa_attach_key is not directly an address but either a label that is looked up in some table (possibly just an index in that table), or some input material for deriving from a master secret.
I would expect that in far more cases, what you pass to psa_attach_key is not directly an address but either a label that is looked up in some table (possibly just an index in that table), or some input material for deriving from a master secret.
I agree. The label should be an indirect identifier - i.e. a name, index, or hash. The caller should not need to know the memory address of key material that it cannot itself access. This API is designed for scenarios where the key material is stored in a location that does not use the psa-crypto naming/identifier scheme - and allows the implementation to create the binding from a PSA Crypto key identifier to the key material at runtime.
The ambiguity in what makes a key volatile is raised as issue #262, with a proposed fix (for 1.3) in #263.