Adding a new Parsec Provider
Creating new providers means enabling Parsec to work on new platforms and is one of the main goals
of the project. As such, the interface that must be implemented by each provider was built with
modularity in mind, allowing developers to choose which operations they implement and when. This
interface is represented by a Rust trait
-
more precisely, the
Provide
trait.
The full list of operations that can be implemented can be found in the link above and will be expanded as the project progresses towards supporting more use cases.
Mandatory methods
Some Provide
trait methods are mandatory for the service to behave normally. They are used on a
service-level by the core provider and so must be supported by all providers.
describe
: Each provider must offer a description of itself in the shape of aProviderInfo
value, by implementing thedescribe
method. The UUID identifying the provider is developer-generated and should not clash with existing providers. This process also requires the new provider to be added to theProviderID
enum. Thedescribe
method is also used to return the supported opcodes by the provider.list_keys
: the provider must implement this method to return all the keys stored within the provider for a particular application name.list_clients
: the provider must implement this method to return the application names that have data stored within the provider.
list_keys
and list_clients
can often be implemented by directly using the
KeyInfoManagerClient
.
Data format
Lots of care must be taken when implementing operations that the inputs and outputs are in the correct format, especially in the case of byte arrays. Detailed description of all input and output can be found in the operations documentation.
Key management
A helpful utility that the Parsec service offers to providers is the use of key info managers. These
allow the provider to persist mappings between key names and key information material and is
generally needed since providers are expected to support UTF-8 encoded strings as key names. To use
the KeyInfoManager in a thread-safe and convenient way, the KeyInfoManagerClient structure can be
used. The key ID type used will have to implement serde
Serialize
and DeserializedOwned
traits.
Dealing with key identity mappings coherency
During the lifetime of the Parsec service, it might happen that the mappings do not correctly reflect the state of the actual key store: a key stored in the KeyInfoManager does not map to any key in the keystore backend. Providers should implement the following policies to prevent that.
- During the provider construction, fetch all key infos linked to that provider. For each one of
them, get the associated ID and issue one command to the backend to check if a key with that ID
exists. If it does not, add the key to a
to_delete
list and then delete all the mappings in theto_delete
list. Check the existing providers' constructors for an example. - Follow the algorithm described in the documentation of
psa_generate_key
,psa_import_key
andpsa_destroy_key
when implementing thoseProvide
methods.
The goal of those policies is to make sure, in a best-effort way, that key management operations have the behavior wanted: it is possible to create a key with the same name if the key creation/deletion operation failed and that at any given time only valid keys can be used.
Because of those policies focused on clients' convenience, it might be possible that some keys become "zombies" in the keystore: they can no longer be accessed via Parsec but still exist.
Please also note that those policies do not protect against hardware attacks. In our threat model is documented as an assumption (ASUM-1):
The hardware modules are physically and functionally secure. Only trusted agents can physically access the system.
Copyright 2019 Contributors to the Parsec project.