-
Notifications
You must be signed in to change notification settings - Fork 5
docs: add docs for key delegation and auth #720
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "label": "Infrastructure", | ||
| "position": 3 | ||
| } |
| 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 | ||
| 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. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
| 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" | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
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
/provisionendpoint