Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/docs/Infrastructure/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Infrastructure",
"position": 3
}
210 changes: 210 additions & 0 deletions docs/docs/Infrastructure/eVault-Key-Delegation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
---
sidebar_position: 1
---

# eVault Key Delegation

This document explains how the eVault system delegates cryptographic keys for signing. It covers key generation, syncing public keys to eVault, and key binding certificates.

## Overview

The eVault system enables users to sign data using keys stored in their eID wallet. The public keys are synced to eVault and bound to the user's eName (W3ID) through key binding certificates. This allows any service to verify signatures by retrieving the public key from eVault.

## Key Delegation Flow

### Key Generation

Keys are generated in the eID wallet during onboarding or pre-verification. The system supports two types of key managers:

1. **Hardware Key Manager**: Uses Native iOS/Android APIs for hardware-backed keys
2. **Software Key Manager**: Uses Web Crypto API to generate software keys

Both generate ECDSA P-256 key pairs with SHA-256 hashing.

The default key ID is `"default"` and is used for all signing operations.

### Setting Keys During eVault Creation

During the eVault provisioning process (onboarding), the public key can be set directly when creating the eVault. The `/provision` endpoint accepts a `publicKey` parameter:

**Provision Request:**
```http
POST /provision
Content-Type: application/json

{
"registryEntropy": "<entropy-token>",
"namespace": "<uuid>",
"verificationId": "<verification-code>",
"publicKey": "z3059301306072a8648ce3d020106082a8648ce3d03010703420004..."
}
```

When provisioning an eVault during onboarding, the eID wallet:
1. Generates or retrieves the public key using `getApplicationPublicKey()`
2. Includes the `publicKey` in the provision request
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should cross reference docs explaining /provision endpoint

3. The eVault stores the public key and generates a key binding certificate automatically

This eliminates the need for a separate sync step when the eVault is first created.

### Syncing Public Keys to eVault

The public key syncing is an autonomous process done by the eID Wallet when linking new devices to the same eName.

```mermaid
sequenceDiagram
participant Wallet as eID Wallet
participant KeyService as KeyService
participant Provisioner as Provisioner Service
participant EVault as eVault Core
participant Registry as Registry Service

Note over Wallet,EVault: Option 1: During eVault Creation
Wallet->>KeyService: Get public key (keyId="default", context="onboarding")
KeyService-->>Wallet: Public key (multibase encoded)
Wallet->>Provisioner: POST /provision (with publicKey parameter)
Provisioner->>EVault: Create eVault with publicKey
EVault->>EVault: Store public key in database
EVault->>Registry: POST /key-binding-certificate (ename, publicKey)
Registry->>Registry: Generate JWT with ename and publicKey
Registry-->>EVault: JWT token (key binding certificate)
EVault->>EVault: Store certificate
EVault-->>Wallet: Success (w3id, uri)

Note over Wallet,EVault: Option 2: After eVault Creation (Sync)
Wallet->>KeyService: Get public key (keyId="default", context="onboarding")
KeyService-->>Wallet: Public key (multibase encoded)
Wallet->>EVault: GET /whois (with X-ENAME header)
EVault-->>Wallet: Existing keyBindingCertificates[]

alt Key already exists
Wallet->>Wallet: Compare current key with certificates
Note over Wallet: Key found, skip sync
else Key not found
Wallet->>EVault: PATCH /public-key (with publicKey in body)
EVault->>EVault: Store public key in database
EVault->>Registry: POST /key-binding-certificate (ename, publicKey)
Registry->>Registry: Generate JWT with ename and publicKey
Registry-->>EVault: JWT token (key binding certificate)
EVault->>EVault: Store certificate
EVault-->>Wallet: Success
end
```

### Key Binding Certificates

Key binding certificates are JWTs that cryptographically bind a public key to an eName. They are generated by the Registry service and stored in eVault.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should mark that they are generated in the Registry only in the prototype and that it was mostly arbitrary decision


**Certificate Structure:**
- **Header**: `{ alg: "ES256", kid: "entropy-key-1" }`
- **Payload**: `{ ename: "@user.w3id", publicKey: "z..." }`
- **Signature**: Signed by Registry's private key (ES256)

The certificate can be verified using the Registry's JWKS endpoint at `/.well-known/jwks.json`.

### eVault Endpoints

#### PATCH /public-key

Stores a public key in eVault for a given eName.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

who can run this? does this override the old public key? how does this work with the option for multiple keys described below?


**Request:**
```http
PATCH /public-key
X-ENAME: @user.w3id
Authorization: Bearer <token>
Content-Type: application/json

{
"publicKey": "z3059301306072a8648ce3d020106082a8648ce3d03010703420004..."
}
```

**Response:**
- `200 OK`: Public key stored successfully
- `400 Bad Request`: Missing X-ENAME header or invalid request
- `401 Unauthorized`: Invalid or missing authentication token

#### GET /whois

Retrieves key binding certificates for a given eName.

**Request:**
```http
GET /whois
X-ENAME: @user.w3id
```

**Response:**
```json
{
"w3id": "@user.w3id",
"keyBindingCertificates": [
"eyJhbGciOiJFUzI1NiIsImtpZCI6ImVudHJvcHkta2V5LTEifQ.eyJlbmFtZSI6IkB1c2VyLnczaWQiLCJwdWJsaWNLZXkiOiJ6MzA1OTMwMTMwNjA3MmE4NjQ4Y2UzZDAyMDEwNjA4MmE4NjQ4Y2UzZDAzMDEwNzAzNDIwMDA0Li4uIn0..."
]
}
```

## Code Examples

### Setting Public Key During eVault Creation

```typescript
// During onboarding - provision eVault with public key
const publicKey = await getApplicationPublicKey(); // Get public key from KeyService

const provisionResponse = await axios.post(
new URL("/provision", provisionerUrl).toString(),
{
registryEntropy,
namespace: uuidv4(),
verificationId,
publicKey: publicKey, // Public key included in provision request
}
);

// eVault is created with the public key already stored
const { w3id, uri } = provisionResponse.data;
```

### Syncing a Public Key to eVault (After Creation)

```typescript
// In eID wallet - sync public key to existing eVault
const vaultController = new VaultController(keyService, userController);
const eName = "@user.w3id";

// Sync public key (automatically checks if already exists)
await vaultController.syncPublicKey(eName);
```

### Retrieving Key Binding Certificates

```typescript
// Resolve eVault URL
const resolveUrl = new URL(
`/resolve?w3id=${encodeURIComponent(eName)}`,
registryBaseUrl
).toString();
const resolveResponse = await axios.get(resolveUrl);
const evaultUrl = resolveResponse.data.uri;

// Get certificates from eVault
const whoisUrl = new URL("/whois", evaultUrl).toString();
const whoisResponse = await axios.get(whoisUrl, {
headers: { "X-ENAME": eName }
});

const certificates = whoisResponse.data.keyBindingCertificates;
// Array of JWT tokens
```

## Security Considerations

1. **Key Storage**: Private keys are never transmitted or stored in eVault. Only public keys are synced.

2. **Certificate Validity**: Key binding certificates expire after 1 hour. eVault regenerates them on-demand when requested.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the attack vector or confusion we are trying to avoid here?


3. **Multiple Keys**: Users can have multiple devices, each with its own key pair. All valid keys can verify signatures.

4. **Key Rotation**: When users add new devices, new keys are added without invalidating old ones, allowing graceful key rotation.
4 changes: 2 additions & 2 deletions docs/docs/Post Platform Guide/_category_.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"label": "Post Platforms Guide",
"position": 4,
"position": 5,
"link": {
"type": "generated-index"
}
}
}
Loading