pub trait DeviceHandle {
// Required methods
fn id(&self) -> String;
fn available<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn configured<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn registered<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn list<'a, 'async_trait>(
&'a self,
) -> Pin<Box<dyn Future<Output = Box<dyn Iterator<Item = Box<dyn KeyHandle + Send + Sync + 'a>> + Send + Sync + 'a>> + Send + 'async_trait>>
where Self: 'async_trait,
'a: 'async_trait;
// Provided methods
fn description<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = String> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait { ... }
fn set_description<'life0, 'async_trait>(
&'life0 self,
_description: String,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait { ... }
fn register<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: Send + 'async_trait,
'life0: 'async_trait { ... }
fn unregister<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: Send + 'async_trait,
'life0: 'async_trait { ... }
fn unlock<'life0, 'life1, 'async_trait>(
&'life0 mut self,
_password: &'life1 Password,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: Send + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn lock<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: Send + 'async_trait,
'life0: 'async_trait { ... }
}
Expand description
A device that contains zero or more keys.
§Device Properties
A device has three properties: it can be available or not, configured or not, and registered or not.
§Available
A device is available if the secret key material can be used.
(This is independent of whether the secret key material is
locked.) A smart card, for instance, is available when it is
inserted, and it is not available when it is not inserted.
Devices that are available are always returned by
Backend::list
.
§Configured
A device is configured if it can be used without further configuration. (This is independent of whether the secret key material is locked.) To use the secret key material on a smartcard or a TPM, the user may first need to load the OpenPGP certificate corresponding to the secret keys. Most devices, however, are already configured, or are able to configure themselves without the user’s intervention. For instance, OpenPGP smartcards don’t normally contain the OpenPGP certificate corresponding to the secret keys, but they do contain the keys’ OpenPGP fingerprints, and an OpenPGP card backend could fetch the certificate’s without user intervention.
Devices that are available, but not configured should still be
returned by Backend::list
. However, because the keys may not
be known, the keys may not be enumerable or not usable. In this
case, DeviceHandle::list
should return
Error::Unconfigured
.
If a device contains multiple keys, and some can be configured while others aren’t, then each key should be exposed as a separate device; this API assumes that either no key or all keys on a given device are configured.
§Registered
A device that is registered is a device whose meta-data has been
saved locally. Devices that are registered are returned by
Backend::list
even if they are not available. Likewise, the
keys on a registered device are returned by DeviceHandle::list
even when the device is not available. When the key store
attempts to decrypt a message, it may prompt the user to insert an
unavailable, registered device.
When a backend scans for devices, it should not automatically register devices. Once a device has been successfully used, however, a backend may register the device. For instance, a smart card that is discovered by a scan should not automatically be registered. However, when the smart card is successfully used to create a signature or decrypt a message, then it may be registered without further intervention from the user.
§Alternate View
Another, less precise view, is that a device may be in one of the following states:
-
Ready: The device is available and configured.
The device can be used immediately. For instance, a soft key, or a smartcard that is inserted.
A device that is ready may still need to be unlocked.
-
Disconnected: A device that was registered, but is not available.
The device is not available, but the user may be prompted to make it available. For instance, if a key needed to decrypt a message is on a smartcard that is unavailable, the user may be prompted to insert the smartcard. Similarly, if a key is accessible via an ssh tunnel, but the ssh tunnel cannot be established, the user may be prompted to connect to the network.
The backend should still expose all of an unavailable device’s keys (insofar as they are known), however, the decrypt and sign operations should fail with
Error::Unavailable
. -
Unusable: A device that was discovered, but that cannot be used without some additional configuration. For instance, a smartcard or a TPM key may need the corresponding certificate before it can be used.
-
Unknown: A device that is not available, and not registered.
The aforementioned three properties map onto these states as follows:
Available, Configured, Registered: Ready
Available, Configured, Not Registered: Ready
Available, Not Configured, Registered: Unusable
Available, Not Configured, Not Registered: Unusable
Not Available, Configured, Registered: Disconnected
Not Available, Configured, Not Registered: Unknown
Not Available, Not Configured, Registered: Disconnected
Not Available, Not Configured, Not Registered: Unknown
A device is only ever instantiated if it is available or registered.
Required Methods§
Sourcefn id(&self) -> String
fn id(&self) -> String
Returns the device’s id.
The id is a globally unique, stable, and mostly human readable identifier.
Sourcefn available<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn available<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Returns whether the device is available.
A device is available if it is plugged-in.
Sourcefn configured<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn configured<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Returns whether the device is configured.
A device is configured if the keys can be used without further configuration.
Sourcefn registered<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn registered<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Returns whether the device is registered.
A device is registered if the device is locally memorized. In this case, the user may be prompted to insert the device.
Sourcefn list<'a, 'async_trait>(
&'a self,
) -> Pin<Box<dyn Future<Output = Box<dyn Iterator<Item = Box<dyn KeyHandle + Send + Sync + 'a>> + Send + Sync + 'a>> + Send + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
fn list<'a, 'async_trait>(
&'a self,
) -> Pin<Box<dyn Future<Output = Box<dyn Iterator<Item = Box<dyn KeyHandle + Send + Sync + 'a>> + Send + Sync + 'a>> + Send + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
Lists keys on the device.
Returns the keys on the device. If the device is not usable,
then this should return Error::Unconfigured
.
Provided Methods§
Sourcefn description<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = String> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
fn description<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = String> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
Returns the device’s description.
The description is a human readable string, e.g., “GnuK with certificate FINGERPRINT”.
Sourcefn set_description<'life0, 'async_trait>(
&'life0 self,
_description: String,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
fn set_description<'life0, 'async_trait>(
&'life0 self,
_description: String,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
Sets the device’s human readable description.
This should fail if the device is not registered.
Sourcefn register<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
fn register<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
Registers the device.
This explicitly registers the device. The backend should memorize the device and should return it during a scan even if it is not available. If the device is already registered, this should silently succeed.
Sourcefn unregister<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
fn unregister<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
Unregisters the device from the backend.
This should not destroy any secret key material stored on the device. It should just remove any cached state about the device. For instance, if the device is an ssh tunnel, then the ssh tunnel’s configuration should be forgotten. If the device is a smart card, then the smart card should be forgotten. Note: if the smart card is inserted, it is still available and thus still usable.
Note: devices that are not available can only be registered using a backend-specific tool. For instance, a device accessible via an ssh tunnel is never available.
Sourcefn unlock<'life0, 'life1, 'async_trait>(
&'life0 mut self,
_password: &'life1 Password,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn unlock<'life0, 'life1, 'async_trait>(
&'life0 mut self,
_password: &'life1 Password,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Connects to and unlocks the device.
Some devices need to be initialized. For instance, to access a remote key, it may be necessary to create an ssh tunnel. Some devices need to be unlocked before the keys can be enumerated. For instance, if soft keys are stored in a database and the database is encrypted, it may be necessary to supply a password to decrypt the database.
Sourcefn lock<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
fn lock<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
'life0: 'async_trait,
Locks the device and any keys in contains.
Locks the device if it has been previously unlocked as well as any keys managed by the device. If the device is locked or can’t be locked, this is a noop. If the device needs to be deinitialized, it MAY be deinitialized lazily if doing so cannot result in a user-visible error. For instance, if the device uses an ssh tunnel, the ssh tunnel may be closed later.