pub struct SoftwareKeyStore { /* private fields */ }software only.Expand description
A KeyStore over a file holding a JWK set of private keys.
The file is {"keys": [...]} (RFC 7517 §5) where every key is a private JWK with a kid,
the key id, and an alg, the one algorithm it signs with. Signs EdDSA, ES256 and (feature
secp256k1) ES256K; generates and deletes. RSA keys in the file are refused, since the crate
never signs with RSA (docs/adr/0001-rsa-verification-only.md).
The whole file is read when the store is opened and every key is checked then: a key whose
public members do not match its private scalar, whose alg does not fit, or whose kid is
taken by another key fails SoftwareKeyStore::open with KeyStoreError::InvalidKeySet.
Private material is zeroized when the store is dropped.
Writes (generate, delete, import) replace the file atomically: the new
set is written to a temporary file in the same directory, created with mode 0600 on Unix,
synced and renamed over the old one. A store opened on a file that other users can read is
refused unless SoftwareKeyStoreOptions::allow_insecure_permissions is set. Nothing locks
the file against other processes; one store per file.
The key id of a generated key is the spec’s label when set and the RFC 7638 thumbprint of
the public key otherwise. xtask keys generate provisions a file from the command line.
§Examples
use identity_kit::jose::{JwsAlgorithm, KeyType};
use identity_kit::keys::{KeySpec, KeyStore, SoftwareKeyStore, SoftwareKeyStoreOptions};
let dir = tempfile::tempdir()?;
let path = dir.path().join("keys.json");
let store = SoftwareKeyStore::create(&path)?;
let key = store
.generate(KeySpec::new(KeyType::P256, JwsAlgorithm::ES256).with_label("issuer"))
.await?;
assert_eq!(key.as_str(), "issuer");
// The key is on disk and usable by the next store opened on the file.
let reopened = SoftwareKeyStore::open(&path)?;
assert!(reopened.exists(&key).await?);
assert_eq!(reopened.sign(&key, JwsAlgorithm::ES256, b"payload").await?.len(), 64);Implementations§
Source§impl SoftwareKeyStore
impl SoftwareKeyStore
Sourcepub fn open(path: impl Into<PathBuf>) -> Result<Self, KeyStoreError>
pub fn open(path: impl Into<PathBuf>) -> Result<Self, KeyStoreError>
Opens the key set file at path with the default options.
§Errors
KeyStoreError::Io when the file cannot be read, KeyStoreError::InsecurePermissions
when other users can read it and KeyStoreError::InvalidKeySet when it is not a JWK set
of usable private keys.
Sourcepub fn open_with(
path: impl Into<PathBuf>,
options: SoftwareKeyStoreOptions,
) -> Result<Self, KeyStoreError>
pub fn open_with( path: impl Into<PathBuf>, options: SoftwareKeyStoreOptions, ) -> Result<Self, KeyStoreError>
Sourcepub fn create(path: impl Into<PathBuf>) -> Result<Self, KeyStoreError>
pub fn create(path: impl Into<PathBuf>) -> Result<Self, KeyStoreError>
Creates an empty key set file at path, with mode 0600 on Unix.
§Errors
KeyStoreError::Io when the file exists already or cannot be written.
Sourcepub fn import(&self, jwk: Jwk) -> Result<KeyId, KeyStoreError>
pub fn import(&self, jwk: Jwk) -> Result<KeyId, KeyStoreError>
Adds an existing private JWK to the store and writes the file.
The key id is the kid when set and the RFC 7638 thumbprint of the public key otherwise;
alg must fit the key when set and defaults to the key type’s algorithm.
§Errors
KeyStoreError::InvalidKey when the JWK is not a usable private key of a supported
type, KeyStoreError::AlreadyExists when its id is taken and KeyStoreError::Io when
the file cannot be written.
Trait Implementations§
Source§impl Debug for SoftwareKeyStore
impl Debug for SoftwareKeyStore
Source§impl KeyStore for SoftwareKeyStore
impl KeyStore for SoftwareKeyStore
Source§fn capabilities(&self) -> KeyStoreCapabilities
fn capabilities(&self) -> KeyStoreCapabilities
Source§fn public_jwk<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 KeyId,
) -> Pin<Box<dyn Future<Output = Result<Jwk, KeyStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn public_jwk<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 KeyId,
) -> Pin<Box<dyn Future<Output = Result<Jwk, KeyStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
key, without private parameters. Read moreSource§fn sign<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 KeyId,
alg: JwsAlgorithm,
data: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn sign<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 KeyId,
alg: JwsAlgorithm,
data: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn exists<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 KeyId,
) -> Pin<Box<dyn Future<Output = Result<bool, KeyStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn exists<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 KeyId,
) -> Pin<Box<dyn Future<Output = Result<bool, KeyStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
key exists. Read more