From 6de9422b89cfb04fec570ec17a38ee54f88e4662 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 18 Aug 2023 16:52:38 +0200 Subject: [PATCH] Add Key Storage concept --- .../docs/concepts/key_storage/key_storage.mdx | 105 ++++++++++++++++++ .../docs/identity.rs/0.7-alpha/sidebars.js | 1 + 2 files changed, 106 insertions(+) create mode 100644 shimmer/docs/identity.rs/0.7-alpha/docs/concepts/key_storage/key_storage.mdx diff --git a/shimmer/docs/identity.rs/0.7-alpha/docs/concepts/key_storage/key_storage.mdx b/shimmer/docs/identity.rs/0.7-alpha/docs/concepts/key_storage/key_storage.mdx new file mode 100644 index 00000000000..3038f6aaa46 --- /dev/null +++ b/shimmer/docs/identity.rs/0.7-alpha/docs/concepts/key_storage/key_storage.mdx @@ -0,0 +1,105 @@ +--- +title: Key Storage +sidebar_label: Key Storage +description: Explain the use of the storage interfaces and how they can be implemented +image: /img/Identity_icon.png +keywords: + - key storage + - storage interfaces + - json web key + - json web algorithm + - signing +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Introduction + +The `JwkDocumentExt` API allows modifying a DID document like adding new verification methods. It enables storing the secrets that verification methods represent in a secure manner. It does so by using the two storage interfaces, namely the `JwkStorage` and `KeyIdStorage`. We'll refer to both of these as the _key storage_. In this section, we will go into more depth on those interfaces, and how to implement them yourself. + +The key idea behind the key storage is strongly inspired by the architecture of key management systems (KMS) or secure enclaves: once private keys are entered into the system, they can never be retrieved again. Instead, all operations using the key will have to go through that system. This approach is what allows the key storage to be architected more securely than simply storing and loading private keys from a regular database. Of course, the security is directly dependent on the concrete implementation, which is why we provide one such implementation by default, using [Stronghold](https://github.com/iotaledger/stronghold.rs/), a best-effort in-software enclave. However, there are cases where one cannot use `Stronghold` or may want to integrate key management of identities into their own KMS or similar, which is why the key storage is an abstraction over such systems. Any implementation of a key storage can then be used by the `JwkDocumentExt` API. + +The two interfaces making up the key storage have two respective responsibilities. + +:::info +Even though there are two separate interfaces, they can be implemented using the same backing storage, if desired. +::: + +A brief overview of those functions: + +- `JwkStorage`: CRUD and signing operations on [JSON Web Keys](https://www.rfc-editor.org/rfc/rfc7517). + - `generate`: Generate a new key represented as a JSON Web Key. + - `insert`: Insert an existing JSON Web Key into the storage. + - `sign`: Signs the provided data using the stored private key. + - `delete`: Permanently deletes a key. + - `exists`: Returns whether a key exists. +- `KeyIdStorage`: Stores the mappings from verification methods to their corresponding key identifier in the `JwkStorage`. + - `insert_key_id`: Inserts a mapping from a verification method identifier to a key identifier. + - `get_key_id`: Returns the key identifier for a given verification method identifier. + - `delete_key_id`: Deletes a mapping. + +## Key Identifier + +A `JwkStorage` stores and operates on keys and so they must be identified. In general, Key Management Systems use some form of an identifier for their keys. To abstract over those, the `JwkStorage` interface has a general-purpose `KeyId` type, which is effectively a wrapper around a string. +A `KeyIdStorage` is needed to store the key id that represents the private key for a given verification method. To that end a verification method itself must be identified. While within a document, each fragment must be unique, the same is not true given multiple documents, hence why we cannot only rely on fragments if we don't want to partition the `KeyIdStorage` by DID. The solution to this is using a `MethodDigest`, a hash over a verification method. When following best security practices, each verification method has its own key associated, and thus a unique public key. That, plus the fragment of a method ensures the `MethodDigest` is unique. +So in essence, a `JwkStorage` stores a `KeyId -> JWK` mapping while a `KeyIdStorage` stores a `MethodDigest -> KeyId` mapping. + +:::caution +Given the construction and limitations of the method digest, no two documents should contain a method that shares both the same fragment and public key. This should not happen under typical circumstances, but is good to keep in mind. +::: + +## Key Types + +To express what key types a given `JwkStorage` implementation supports , the `KeyType` is used, which is another simple wrapper around a string. + +:::info +The reason for this design might seem odd in Rust, given the existence of associated types. This more simplistic design is necessary to accommodate implementing the interface via the bindings to the library. +::: + +Implementations are expected to export constants of the key types they support, so users have an easy way to discover the supported types. +In general, storage implementations are free to support any [JSON Web Algorithm](https://www.rfc-editor.org/rfc/rfc7518.html)-compatible key, however the recommended default used by IOTA Identity is the `EdDSA` algorithm with curve `Ed25519`. + +## Implementation + +The IOTA Identity library ships two implementations of key storage. The `JwkMemStore` and `KeyIdMemstore` are insecure in-memory implementations intended as example implementations and for testing. The default key storage implementation is `Stronghold`, which is an example of a storage that implements both storage interfaces simultaneously. `Stronghold` may be interesting for implementers to look at, too, as it needs to deal with some challenges the in-memory version does not have to deal with. + +This section will detail some common challenges and embeds the `MemStore` implementations in Rust and TypeScript. + +### Examples + +This section shows the Rust and TypeScript Memstore implementations. + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/main/bindings/wasm/lib/jwk_storage.ts +``` + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/main/identity_storage/src/key_storage/memstore.rs +``` + + + + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/main/bindings/wasm/lib/key_id_storage.ts +``` + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/main/identity_storage/src/key_id_storage/memstore.rs +``` + + + diff --git a/shimmer/docs/identity.rs/0.7-alpha/sidebars.js b/shimmer/docs/identity.rs/0.7-alpha/sidebars.js index b36dfdacbbe..b8a17ceaccc 100644 --- a/shimmer/docs/identity.rs/0.7-alpha/sidebars.js +++ b/shimmer/docs/identity.rs/0.7-alpha/sidebars.js @@ -57,6 +57,7 @@ module.exports = { 'concepts/verifiable_credentials/verifiable_presentations', ], 'Domain Linkage': ['concepts/domain_linkage/domain_linkage'], + 'Key Storage': ['concepts/key_storage/key_storage'], }, ], },