Skip to content

Commit

Permalink
Add Key Storage concept
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippGackstatter committed Aug 18, 2023
1 parent 9eee1d5 commit 6de9422
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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.

<Tabs groupId="language" queryString>
<TabItem value="typescript-node" label="Typescript (Node.js)">

```ts reference
https://github.com/iotaledger/identity.rs/blob/main/bindings/wasm/lib/jwk_storage.ts
```

</TabItem>
<TabItem value="rust" label="Rust">

```rust reference
https://github.com/iotaledger/identity.rs/blob/main/identity_storage/src/key_storage/memstore.rs
```

</TabItem>
</Tabs>

<Tabs groupId="language" queryString>
<TabItem value="typescript-node" label="Typescript (Node.js)">

```ts reference
https://github.com/iotaledger/identity.rs/blob/main/bindings/wasm/lib/key_id_storage.ts
```

</TabItem>
<TabItem value="rust" label="Rust">

```rust reference
https://github.com/iotaledger/identity.rs/blob/main/identity_storage/src/key_id_storage/memstore.rs
```

</TabItem>
</Tabs>
1 change: 1 addition & 0 deletions shimmer/docs/identity.rs/0.7-alpha/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
},
],
},
Expand Down

0 comments on commit 6de9422

Please sign in to comment.