@alejoamiras/tee-rex 4.0.0-devnet.2-patch.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/attestation.d.ts +64 -0
- package/dist/lib/attestation.d.ts.map +1 -0
- package/dist/lib/attestation.js +209 -0
- package/dist/lib/attestation.js.map +1 -0
- package/dist/lib/encrypt.d.ts +5 -0
- package/dist/lib/encrypt.d.ts.map +1 -0
- package/dist/lib/encrypt.js +20 -0
- package/dist/lib/encrypt.js.map +1 -0
- package/dist/lib/logger.d.ts +2 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +3 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/tee-rex-prover.d.ts +39 -0
- package/dist/lib/tee-rex-prover.d.ts.map +1 -0
- package/dist/lib/tee-rex-prover.js +140 -0
- package/dist/lib/tee-rex-prover.js.map +1 -0
- package/dist/test-setup.d.ts +2 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +10 -0
- package/dist/test-setup.js.map +1 -0
- package/package.json +59 -0
- package/src/index.ts +7 -0
- package/src/lib/attestation.test.ts +325 -0
- package/src/lib/attestation.ts +317 -0
- package/src/lib/encrypt.test.ts +72 -0
- package/src/lib/encrypt.ts +29 -0
- package/src/lib/logger.ts +3 -0
- package/src/lib/tee-rex-prover.test.ts +184 -0
- package/src/lib/tee-rex-prover.ts +174 -0
- package/src/test-setup.ts +10 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @alejoamiras/tee-rex
|
|
2
|
+
|
|
3
|
+
Delegate [Aztec](https://aztec.network) transaction proving to a Trusted Execution Environment.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@alejoamiras/tee-rex)
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm add @alejoamiras/tee-rex
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
Drop `TeeRexProver` into your PXE as a custom prover:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createAztecNodeClient } from "@aztec/aztec.js/node";
|
|
19
|
+
import { createPXE } from "@aztec/pxe/client/lazy";
|
|
20
|
+
import { getPXEConfig } from "@aztec/pxe/config";
|
|
21
|
+
import { WASMSimulator } from "@aztec/simulator/client";
|
|
22
|
+
import { TeeRexProver, ProvingMode } from "@alejoamiras/tee-rex";
|
|
23
|
+
|
|
24
|
+
const TEE_REX_API = "http://localhost:4000";
|
|
25
|
+
const node = createAztecNodeClient("<aztec-node-rpc-url>");
|
|
26
|
+
|
|
27
|
+
const prover = new TeeRexProver(TEE_REX_API, new WASMSimulator());
|
|
28
|
+
const pxe = await createPXE(node, getPXEConfig(), {
|
|
29
|
+
proverOrOptions: prover,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// use the PXE as usual — proving is delegated to the TEE
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Switch proving modes
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { ProvingMode } from "@alejoamiras/tee-rex";
|
|
39
|
+
|
|
40
|
+
// delegate proving to a remote TEE (default)
|
|
41
|
+
prover.setProvingMode(ProvingMode.remote);
|
|
42
|
+
|
|
43
|
+
// or prove locally in WASM (fallback)
|
|
44
|
+
prover.setProvingMode(ProvingMode.local);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Configure attestation verification
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
prover.setAttestationConfig({
|
|
51
|
+
// reject servers not running in a TEE
|
|
52
|
+
requireAttestation: true,
|
|
53
|
+
// verify enclave identity via PCR values
|
|
54
|
+
expectedPCRs: { 0: "abc123..." },
|
|
55
|
+
// attestation freshness (default: 5 minutes)
|
|
56
|
+
maxAgeMs: 5 * 60 * 1000,
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
### `TeeRexProver`
|
|
63
|
+
|
|
64
|
+
Aztec private kernel prover that can generate proofs locally or on a remote
|
|
65
|
+
tee-rex server running inside an AWS Nitro Enclave.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
class TeeRexProver extends BBLazyPrivateKernelProver {
|
|
69
|
+
constructor(apiUrl: string, ...args: ConstructorParameters<typeof BBLazyPrivateKernelProver>)
|
|
70
|
+
setProvingMode(mode: ProvingMode): void
|
|
71
|
+
setApiUrl(url: string): void
|
|
72
|
+
setAttestationConfig(config: TeeRexAttestationConfig): void
|
|
73
|
+
createChonkProof(executionSteps: PrivateExecutionStep[]): Promise<ChonkProofWithPublicInputs>
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **`apiUrl`** — TEE-Rex server endpoint (e.g. `http://localhost:4000`)
|
|
78
|
+
- **`...args`** — forwarded to `BBLazyPrivateKernelProver` (typically a `CircuitSimulator` instance)
|
|
79
|
+
- **`setProvingMode(mode)`** — switch between `"remote"` (TEE) and `"local"` (WASM) proving
|
|
80
|
+
- **`setApiUrl(url)`** — update the tee-rex server URL at runtime
|
|
81
|
+
- **`setAttestationConfig(config)`** — configure attestation verification (PCR checks, freshness, require TEE)
|
|
82
|
+
- **`createChonkProof(steps)`** — overrides the parent to route proofs through the TEE server in remote mode
|
|
83
|
+
|
|
84
|
+
### `ProvingMode`
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const ProvingMode = { local: "local", remote: "remote" } as const;
|
|
88
|
+
type ProvingMode = "local" | "remote";
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `TeeRexAttestationConfig`
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
interface TeeRexAttestationConfig {
|
|
95
|
+
requireAttestation?: boolean; // reject servers in standard (non-TEE) mode
|
|
96
|
+
expectedPCRs?: Record<number, string>; // expected PCR values (hex strings)
|
|
97
|
+
maxAgeMs?: number; // max attestation age in ms (default: 5 min)
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `verifyNitroAttestation`
|
|
102
|
+
|
|
103
|
+
Verify a Nitro attestation document and extract the embedded public key. Used internally by `TeeRexProver` but exported for advanced use cases.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
function verifyNitroAttestation(
|
|
107
|
+
attestationDocumentBase64: string,
|
|
108
|
+
options?: AttestationVerifyOptions,
|
|
109
|
+
): Promise<{ publicKey: string; document: NitroAttestationDocument }>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `AttestationError`
|
|
113
|
+
|
|
114
|
+
Error thrown when attestation verification fails. Includes a machine-readable `code` for programmatic handling.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
class AttestationError extends Error {
|
|
118
|
+
readonly code: AttestationErrorCode;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const AttestationErrorCode = {
|
|
122
|
+
INVALID_COSE: "INVALID_COSE",
|
|
123
|
+
INVALID_DOCUMENT: "INVALID_DOCUMENT",
|
|
124
|
+
CHAIN_FAILED: "CHAIN_FAILED",
|
|
125
|
+
SIGNATURE_FAILED: "SIGNATURE_FAILED",
|
|
126
|
+
EXPIRED: "EXPIRED",
|
|
127
|
+
PCR_MISMATCH: "PCR_MISMATCH",
|
|
128
|
+
NONCE_MISMATCH: "NONCE_MISMATCH",
|
|
129
|
+
MISSING_KEY: "MISSING_KEY",
|
|
130
|
+
} as const;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## How It Works
|
|
134
|
+
|
|
135
|
+
`TeeRexProver` extends Aztec's `BBLazyPrivateKernelProver` and overrides `createChonkProof` — the single method responsible for generating the cryptographic proof (ClientIVC). All other operations (witness generation, kernel circuit simulation) run locally in the PXE.
|
|
136
|
+
|
|
137
|
+
In **remote** mode, `createChonkProof`:
|
|
138
|
+
|
|
139
|
+
1. Fetches the server's attestation document from `/attestation`
|
|
140
|
+
2. Verifies the Nitro attestation (COSE_Sign1 signature, certificate chain, PCRs)
|
|
141
|
+
3. Encrypts the proving inputs with the server's attested public key (curve25519 + AES-256-GCM)
|
|
142
|
+
4. POSTs the encrypted data to `/prove` (with automatic retry on transient failures)
|
|
143
|
+
5. Deserializes and returns the proof
|
|
144
|
+
|
|
145
|
+
In **local** mode, it delegates to the parent `BBLazyPrivateKernelProver.createChonkProof` which runs Barretenberg WASM in the browser or Node.js.
|
|
146
|
+
|
|
147
|
+
## Requirements
|
|
148
|
+
|
|
149
|
+
- Aztec `4.0.0-spartan` or compatible version
|
|
150
|
+
- A running TEE-Rex server for remote proving
|
|
151
|
+
- A running Aztec node for PXE connectivity
|
|
152
|
+
|
|
153
|
+
## Contributors
|
|
154
|
+
|
|
155
|
+
Made with love by [Alejo Amiras](https://github.com/alejoamiras)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { AttestationVerifyOptions, NitroAttestationDocument } from "./lib/attestation.js";
|
|
2
|
+
export { AttestationError, AttestationErrorCode, verifyNitroAttestation, } from "./lib/attestation.js";
|
|
3
|
+
export * from "./lib/tee-rex-prover.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ValueOf } from "ts-essentials";
|
|
2
|
+
/** Parsed fields from a Nitro attestation document. */
|
|
3
|
+
export interface NitroAttestationDocument {
|
|
4
|
+
moduleId: string;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
digest: string;
|
|
7
|
+
pcrs: Map<number, Uint8Array>;
|
|
8
|
+
certificate: Uint8Array;
|
|
9
|
+
cabundle: Uint8Array[];
|
|
10
|
+
publicKey?: Uint8Array;
|
|
11
|
+
userData?: Uint8Array;
|
|
12
|
+
nonce?: Uint8Array;
|
|
13
|
+
}
|
|
14
|
+
/** Options for attestation verification. */
|
|
15
|
+
export interface AttestationVerifyOptions {
|
|
16
|
+
/** Expected PCR values. Only the specified PCR indices are checked. */
|
|
17
|
+
expectedPCRs?: Record<number, string>;
|
|
18
|
+
/** Maximum age of the attestation document in milliseconds. Default: 5 minutes. */
|
|
19
|
+
maxAgeMs?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Expected nonce value (hex string). When provided, the attestation document's
|
|
22
|
+
* nonce field must match exactly. Use this to prevent replay attacks by including
|
|
23
|
+
* a challenge in the attestation request.
|
|
24
|
+
*/
|
|
25
|
+
expectedNonce?: string;
|
|
26
|
+
/** @internal Override the root CA for testing. Defaults to the AWS Nitro Enclaves Root CA. */
|
|
27
|
+
rootCaPem?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Verify a Nitro attestation document and extract the embedded public key.
|
|
31
|
+
*
|
|
32
|
+
* Verification steps:
|
|
33
|
+
* 1. Decode the COSE_Sign1 envelope
|
|
34
|
+
* 2. Extract and parse the CBOR attestation document payload
|
|
35
|
+
* 3. Build and verify the certificate chain (cabundle → leaf → AWS Nitro root CA)
|
|
36
|
+
* 4. Verify the COSE_Sign1 signature using the leaf certificate
|
|
37
|
+
* 5. Optionally check PCR values and document freshness
|
|
38
|
+
* 6. Return the embedded public key
|
|
39
|
+
*
|
|
40
|
+
* Uses @peculiar/x509 + Web Crypto API for cross-platform compatibility
|
|
41
|
+
* (works in Node.js, Bun, and browsers).
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyNitroAttestation(attestationDocumentBase64: string, options?: AttestationVerifyOptions): Promise<{
|
|
44
|
+
publicKey: string;
|
|
45
|
+
document: NitroAttestationDocument;
|
|
46
|
+
}>;
|
|
47
|
+
/** Machine-readable error codes for attestation verification failures. */
|
|
48
|
+
export type AttestationErrorCode = ValueOf<typeof AttestationErrorCode>;
|
|
49
|
+
export declare const AttestationErrorCode: {
|
|
50
|
+
readonly INVALID_COSE: "INVALID_COSE";
|
|
51
|
+
readonly INVALID_DOCUMENT: "INVALID_DOCUMENT";
|
|
52
|
+
readonly CHAIN_FAILED: "CHAIN_FAILED";
|
|
53
|
+
readonly SIGNATURE_FAILED: "SIGNATURE_FAILED";
|
|
54
|
+
readonly EXPIRED: "EXPIRED";
|
|
55
|
+
readonly PCR_MISMATCH: "PCR_MISMATCH";
|
|
56
|
+
readonly NONCE_MISMATCH: "NONCE_MISMATCH";
|
|
57
|
+
readonly MISSING_KEY: "MISSING_KEY";
|
|
58
|
+
};
|
|
59
|
+
/** Error thrown when Nitro attestation verification fails. Includes a machine-readable {@link AttestationErrorCode}. */
|
|
60
|
+
export declare class AttestationError extends Error {
|
|
61
|
+
readonly code: AttestationErrorCode;
|
|
62
|
+
constructor(message: string, code?: AttestationErrorCode);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=attestation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../../src/lib/attestation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAsB7C,uDAAuD;AACvD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9B,WAAW,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED,4CAA4C;AAC5C,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,sBAAsB,CAC1C,yBAAyB,EAAE,MAAM,EACjC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,wBAAwB,CAAA;CAAE,CAAC,CA2HpE;AAqGD,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACxE,eAAO,MAAM,oBAAoB;;;;;;;;;CASvB,CAAC;AAEX,wHAAwH;AACxH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;gBAExB,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,oBAA4D;CAKhG"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as x509 from "@peculiar/x509";
|
|
2
|
+
import { decode as decodeCbor, encode as encodeCbor } from "cbor-x";
|
|
3
|
+
import { logger } from "./logger.js";
|
|
4
|
+
/**
|
|
5
|
+
* AWS Nitro Enclaves Root CA certificate (PEM).
|
|
6
|
+
* Source: https://aws-nitro-enclaves.amazonaws.com/AWS_NitroEnclaves_Root-G1.zip
|
|
7
|
+
*/
|
|
8
|
+
const AWS_NITRO_ROOT_CA_PEM = `-----BEGIN CERTIFICATE-----
|
|
9
|
+
MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTEL
|
|
10
|
+
MAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYD
|
|
11
|
+
VQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4
|
|
12
|
+
MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQL
|
|
13
|
+
DANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEG
|
|
14
|
+
BSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb
|
|
15
|
+
48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZE
|
|
16
|
+
h8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkF
|
|
17
|
+
R+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYC
|
|
18
|
+
MQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPW
|
|
19
|
+
rfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6N
|
|
20
|
+
IwLz3/Y=
|
|
21
|
+
-----END CERTIFICATE-----`;
|
|
22
|
+
/**
|
|
23
|
+
* Verify a Nitro attestation document and extract the embedded public key.
|
|
24
|
+
*
|
|
25
|
+
* Verification steps:
|
|
26
|
+
* 1. Decode the COSE_Sign1 envelope
|
|
27
|
+
* 2. Extract and parse the CBOR attestation document payload
|
|
28
|
+
* 3. Build and verify the certificate chain (cabundle → leaf → AWS Nitro root CA)
|
|
29
|
+
* 4. Verify the COSE_Sign1 signature using the leaf certificate
|
|
30
|
+
* 5. Optionally check PCR values and document freshness
|
|
31
|
+
* 6. Return the embedded public key
|
|
32
|
+
*
|
|
33
|
+
* Uses @peculiar/x509 + Web Crypto API for cross-platform compatibility
|
|
34
|
+
* (works in Node.js, Bun, and browsers).
|
|
35
|
+
*/
|
|
36
|
+
export async function verifyNitroAttestation(attestationDocumentBase64, options = {}) {
|
|
37
|
+
const { maxAgeMs = 5 * 60 * 1000 } = options;
|
|
38
|
+
// 1. Decode the COSE_Sign1 envelope
|
|
39
|
+
const raw = Buffer.from(attestationDocumentBase64, "base64");
|
|
40
|
+
const coseSign1 = decodeCbor(raw);
|
|
41
|
+
if (!Array.isArray(coseSign1) || coseSign1.length !== 4) {
|
|
42
|
+
throw new AttestationError("Invalid COSE_Sign1 structure", AttestationErrorCode.INVALID_COSE);
|
|
43
|
+
}
|
|
44
|
+
const [protectedHeaders, , payload, signature] = coseSign1;
|
|
45
|
+
// 2. Parse the attestation document from the payload
|
|
46
|
+
const doc = decodeCbor(payload);
|
|
47
|
+
const attestationDoc = parseAttestationDocument(doc);
|
|
48
|
+
// 3. Build and verify certificate chain
|
|
49
|
+
// Buffer.from() ensures ArrayBuffer backing (not SharedArrayBuffer) for @peculiar/x509 compat
|
|
50
|
+
const leafCert = new x509.X509Certificate(Buffer.from(attestationDoc.certificate));
|
|
51
|
+
const rootCa = new x509.X509Certificate(options.rootCaPem ?? AWS_NITRO_ROOT_CA_PEM);
|
|
52
|
+
// Build chain: cabundle contains certs from root to intermediate(s)
|
|
53
|
+
const caBundleCerts = attestationDoc.cabundle.map((der) => new x509.X509Certificate(Buffer.from(der)));
|
|
54
|
+
await verifyCertificateChain(leafCert, caBundleCerts, rootCa);
|
|
55
|
+
// 4. Verify COSE_Sign1 signature
|
|
56
|
+
// Sig_structure = ["Signature1", protected_headers, external_aad, payload]
|
|
57
|
+
// cbor-x encodes Uint8Array with CBOR tag 64 but Buffer as plain bstr.
|
|
58
|
+
// COSE requires plain bstr, so use Buffer.alloc(0) for the empty external_aad.
|
|
59
|
+
const sigStructure = encodeCbor(["Signature1", protectedHeaders, Buffer.alloc(0), payload]);
|
|
60
|
+
const leafPublicKey = await leafCert.publicKey.export({ name: "ECDSA", namedCurve: "P-384" }, ["verify"]);
|
|
61
|
+
const signatureValid = await crypto.subtle.verify({ name: "ECDSA", hash: "SHA-384" }, leafPublicKey, Buffer.from(signature), Buffer.from(sigStructure));
|
|
62
|
+
if (!signatureValid) {
|
|
63
|
+
throw new AttestationError("COSE_Sign1 signature verification failed", AttestationErrorCode.SIGNATURE_FAILED);
|
|
64
|
+
}
|
|
65
|
+
// 5. Check freshness (with 30s tolerance for clock skew between client and enclave)
|
|
66
|
+
const CLOCK_SKEW_TOLERANCE_MS = 30_000;
|
|
67
|
+
const docAge = Date.now() - attestationDoc.timestamp;
|
|
68
|
+
if (docAge > maxAgeMs + CLOCK_SKEW_TOLERANCE_MS) {
|
|
69
|
+
throw new AttestationError(`Attestation document is too old (${Math.round(docAge / 1000)}s > ${Math.round(maxAgeMs / 1000)}s)`, AttestationErrorCode.EXPIRED);
|
|
70
|
+
}
|
|
71
|
+
// 6. Check PCR values if specified
|
|
72
|
+
if (options.expectedPCRs) {
|
|
73
|
+
for (const [index, expectedHex] of Object.entries(options.expectedPCRs)) {
|
|
74
|
+
const pcrIndex = Number(index);
|
|
75
|
+
const actual = attestationDoc.pcrs.get(pcrIndex);
|
|
76
|
+
if (!actual) {
|
|
77
|
+
throw new AttestationError(`PCR${pcrIndex} not found in attestation document`, AttestationErrorCode.PCR_MISMATCH);
|
|
78
|
+
}
|
|
79
|
+
const actualHex = Buffer.from(actual).toString("hex");
|
|
80
|
+
if (actualHex !== expectedHex.toLowerCase()) {
|
|
81
|
+
throw new AttestationError(`PCR${pcrIndex} mismatch: expected ${expectedHex}, got ${actualHex}`, AttestationErrorCode.PCR_MISMATCH);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// 7. Check nonce if specified
|
|
86
|
+
if (options.expectedNonce) {
|
|
87
|
+
if (!attestationDoc.nonce) {
|
|
88
|
+
throw new AttestationError("Attestation document does not contain a nonce", AttestationErrorCode.NONCE_MISMATCH);
|
|
89
|
+
}
|
|
90
|
+
const actualNonce = Buffer.from(attestationDoc.nonce).toString("hex");
|
|
91
|
+
if (actualNonce !== options.expectedNonce.toLowerCase()) {
|
|
92
|
+
throw new AttestationError(`Nonce mismatch: expected ${options.expectedNonce}, got ${actualNonce}`, AttestationErrorCode.NONCE_MISMATCH);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 8. Extract public key
|
|
96
|
+
if (!attestationDoc.publicKey) {
|
|
97
|
+
throw new AttestationError("Attestation document does not contain a public key", AttestationErrorCode.MISSING_KEY);
|
|
98
|
+
}
|
|
99
|
+
const publicKey = new TextDecoder().decode(attestationDoc.publicKey);
|
|
100
|
+
logger.info("Nitro attestation verified successfully", {
|
|
101
|
+
moduleId: attestationDoc.moduleId,
|
|
102
|
+
pcr0: Buffer.from(attestationDoc.pcrs.get(0) ?? new Uint8Array())
|
|
103
|
+
.toString("hex")
|
|
104
|
+
.slice(0, 16),
|
|
105
|
+
});
|
|
106
|
+
return { publicKey, document: attestationDoc };
|
|
107
|
+
}
|
|
108
|
+
function parseAttestationDocument(doc) {
|
|
109
|
+
if (typeof doc.module_id !== "string") {
|
|
110
|
+
throw new AttestationError("Missing or invalid module_id");
|
|
111
|
+
}
|
|
112
|
+
// cbor-x decodes 8-byte CBOR uint64 as BigInt — Nitro's Rust NSM library always
|
|
113
|
+
// encodes the timestamp as uint64 regardless of value, so we must accept both.
|
|
114
|
+
if (typeof doc.timestamp !== "number" && typeof doc.timestamp !== "bigint") {
|
|
115
|
+
throw new AttestationError("Missing or invalid timestamp");
|
|
116
|
+
}
|
|
117
|
+
if (typeof doc.digest !== "string") {
|
|
118
|
+
throw new AttestationError("Missing or invalid digest");
|
|
119
|
+
}
|
|
120
|
+
if (!(doc.certificate instanceof Uint8Array)) {
|
|
121
|
+
throw new AttestationError("Missing or invalid certificate");
|
|
122
|
+
}
|
|
123
|
+
if (!Array.isArray(doc.cabundle)) {
|
|
124
|
+
throw new AttestationError("Missing or invalid cabundle");
|
|
125
|
+
}
|
|
126
|
+
// Normalize pcrs: cbor-x decodes CBOR maps as plain objects (with string keys)
|
|
127
|
+
// by default, but as Map when using certain configurations. Accept both.
|
|
128
|
+
let pcrs;
|
|
129
|
+
if (doc.pcrs instanceof Map) {
|
|
130
|
+
pcrs = doc.pcrs;
|
|
131
|
+
for (const [key, value] of pcrs) {
|
|
132
|
+
if (typeof key !== "number" || !(value instanceof Uint8Array)) {
|
|
133
|
+
throw new AttestationError("Invalid pcrs entry: expected Map<number, Uint8Array>");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (doc.pcrs && typeof doc.pcrs === "object") {
|
|
138
|
+
pcrs = new Map();
|
|
139
|
+
for (const [key, value] of Object.entries(doc.pcrs)) {
|
|
140
|
+
if (!(value instanceof Uint8Array)) {
|
|
141
|
+
throw new AttestationError("Invalid pcrs entry: expected Map<number, Uint8Array>");
|
|
142
|
+
}
|
|
143
|
+
pcrs.set(Number(key), value);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
throw new AttestationError("Missing or invalid pcrs");
|
|
148
|
+
}
|
|
149
|
+
// Validate cabundle entries
|
|
150
|
+
const cabundle = doc.cabundle;
|
|
151
|
+
for (const entry of cabundle) {
|
|
152
|
+
if (!(entry instanceof Uint8Array)) {
|
|
153
|
+
throw new AttestationError("Invalid cabundle entry: expected Uint8Array[]");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
moduleId: doc.module_id,
|
|
158
|
+
timestamp: Number(doc.timestamp),
|
|
159
|
+
digest: doc.digest,
|
|
160
|
+
pcrs,
|
|
161
|
+
certificate: doc.certificate,
|
|
162
|
+
cabundle: cabundle,
|
|
163
|
+
publicKey: doc.public_key instanceof Uint8Array ? doc.public_key : undefined,
|
|
164
|
+
userData: doc.user_data instanceof Uint8Array ? doc.user_data : undefined,
|
|
165
|
+
nonce: doc.nonce instanceof Uint8Array ? doc.nonce : undefined,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
async function verifyCertificateChain(leaf, intermediates, root) {
|
|
169
|
+
// Verify root is self-signed
|
|
170
|
+
const rootSelfSigned = await root.verify({ signatureOnly: true });
|
|
171
|
+
if (!rootSelfSigned) {
|
|
172
|
+
throw new AttestationError("Root CA is not self-signed", AttestationErrorCode.CHAIN_FAILED);
|
|
173
|
+
}
|
|
174
|
+
// Build ordered chain: root → intermediates → leaf
|
|
175
|
+
const chain = [root, ...intermediates, leaf];
|
|
176
|
+
for (let i = 1; i < chain.length; i++) {
|
|
177
|
+
const cert = chain[i];
|
|
178
|
+
const issuer = chain[i - 1];
|
|
179
|
+
const valid = await cert.verify({ publicKey: issuer, signatureOnly: true });
|
|
180
|
+
if (!valid) {
|
|
181
|
+
throw new AttestationError(`Certificate chain verification failed at index ${i}`, AttestationErrorCode.CHAIN_FAILED);
|
|
182
|
+
}
|
|
183
|
+
// Check validity period
|
|
184
|
+
const now = new Date();
|
|
185
|
+
if (now < cert.notBefore || now > cert.notAfter) {
|
|
186
|
+
throw new AttestationError(`Certificate at index ${i} is not within its validity period`, AttestationErrorCode.CHAIN_FAILED);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
export const AttestationErrorCode = {
|
|
191
|
+
INVALID_COSE: "INVALID_COSE",
|
|
192
|
+
INVALID_DOCUMENT: "INVALID_DOCUMENT",
|
|
193
|
+
CHAIN_FAILED: "CHAIN_FAILED",
|
|
194
|
+
SIGNATURE_FAILED: "SIGNATURE_FAILED",
|
|
195
|
+
EXPIRED: "EXPIRED",
|
|
196
|
+
PCR_MISMATCH: "PCR_MISMATCH",
|
|
197
|
+
NONCE_MISMATCH: "NONCE_MISMATCH",
|
|
198
|
+
MISSING_KEY: "MISSING_KEY",
|
|
199
|
+
};
|
|
200
|
+
/** Error thrown when Nitro attestation verification fails. Includes a machine-readable {@link AttestationErrorCode}. */
|
|
201
|
+
export class AttestationError extends Error {
|
|
202
|
+
code;
|
|
203
|
+
constructor(message, code = AttestationErrorCode.INVALID_DOCUMENT) {
|
|
204
|
+
super(message);
|
|
205
|
+
this.name = "AttestationError";
|
|
206
|
+
this.code = code;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=attestation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation.js","sourceRoot":"","sources":["../../src/lib/attestation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../../src/lib/encrypt.ts"],"names":[],"mappings":"AAIA,wBAAsB,OAAO,CAAC,EAC5B,IAAI,EACJ,mBAAmB,GACpB,EAAE;IACD,IAAI,EAAE,UAAU,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,GAAG,OAAO,CAAC,UAAU,CAAC,CAStB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as openpgp from "openpgp";
|
|
2
|
+
openpgp.config.aeadProtect = true;
|
|
3
|
+
export async function encrypt({ data, encryptionPublicKey, }) {
|
|
4
|
+
const message = await openpgp.createMessage({ binary: data });
|
|
5
|
+
const encryptedArmored = await openpgp.encrypt({
|
|
6
|
+
message,
|
|
7
|
+
encryptionKeys: await openpgp.readKey({ armoredKey: encryptionPublicKey }),
|
|
8
|
+
});
|
|
9
|
+
const encrypted = await unarmorToUint8Array(encryptedArmored);
|
|
10
|
+
return encrypted;
|
|
11
|
+
}
|
|
12
|
+
async function unarmorToUint8Array(armored) {
|
|
13
|
+
const unarmored = await openpgp.unarmor(armored);
|
|
14
|
+
const unarmoredData = unarmored.data;
|
|
15
|
+
if (!(unarmoredData instanceof Uint8Array)) {
|
|
16
|
+
throw new Error("Unarmored data is not a Uint8Array");
|
|
17
|
+
}
|
|
18
|
+
return unarmoredData;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=encrypt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encrypt.js","sourceRoot":"","sources":["../../src/lib/encrypt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,OAAO,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;AAElC,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAC5B,IAAI,EACJ,mBAAmB,GAIpB;IACC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;QAC7C,OAAO;QACP,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC;KAC3E,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;IAC9D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,OAAe;IAChD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,aAAa,GAAY,SAAS,CAAC,IAAI,CAAC;IAC9C,IAAI,CAAC,CAAC,aAAa,YAAY,UAAU,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,mCAAmC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { BBLazyPrivateKernelProver } from "@aztec/bb-prover/client/lazy";
|
|
2
|
+
import type { PrivateExecutionStep } from "@aztec/stdlib/kernel";
|
|
3
|
+
import { ChonkProofWithPublicInputs } from "@aztec/stdlib/proofs";
|
|
4
|
+
import { type ValueOf } from "ts-essentials";
|
|
5
|
+
import { type AttestationVerifyOptions } from "./attestation.js";
|
|
6
|
+
/** Whether proofs are generated locally (WASM) or on a remote tee-rex server. */
|
|
7
|
+
export type ProvingMode = ValueOf<typeof ProvingMode>;
|
|
8
|
+
export declare const ProvingMode: {
|
|
9
|
+
readonly local: "local";
|
|
10
|
+
readonly remote: "remote";
|
|
11
|
+
};
|
|
12
|
+
export interface TeeRexAttestationConfig {
|
|
13
|
+
/** When true, reject servers running in standard (non-TEE) mode. Default: false. */
|
|
14
|
+
requireAttestation?: boolean;
|
|
15
|
+
/** Expected PCR values to verify against the attestation document. */
|
|
16
|
+
expectedPCRs?: AttestationVerifyOptions["expectedPCRs"];
|
|
17
|
+
/** Maximum age of attestation documents in milliseconds. Default: 5 minutes. */
|
|
18
|
+
maxAgeMs?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Aztec private kernel prover that can generate proofs locally or on a remote
|
|
22
|
+
* tee-rex server running inside an AWS Nitro Enclave.
|
|
23
|
+
*
|
|
24
|
+
* In remote mode, witness data is encrypted with the server's attested public
|
|
25
|
+
* key (curve25519 + AES-256-GCM) before being sent over the network.
|
|
26
|
+
*/
|
|
27
|
+
export declare class TeeRexProver extends BBLazyPrivateKernelProver {
|
|
28
|
+
#private;
|
|
29
|
+
private apiUrl;
|
|
30
|
+
constructor(apiUrl: string, ...args: ConstructorParameters<typeof BBLazyPrivateKernelProver>);
|
|
31
|
+
/** Switch between local WASM proving and remote TEE proving. */
|
|
32
|
+
setProvingMode(mode: ProvingMode): void;
|
|
33
|
+
/** Update the tee-rex server URL used for remote proving. */
|
|
34
|
+
setApiUrl(url: string): void;
|
|
35
|
+
/** Configure attestation verification (PCR checks, freshness, require TEE). */
|
|
36
|
+
setAttestationConfig(config: TeeRexAttestationConfig): void;
|
|
37
|
+
createChonkProof(executionSteps: PrivateExecutionStep[]): Promise<ChonkProofWithPublicInputs>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=tee-rex-prover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tee-rex-prover.d.ts","sourceRoot":"","sources":["../../src/lib/tee-rex-prover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAKlE,OAAO,EAAwB,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGnE,OAAO,EAAE,KAAK,wBAAwB,EAA0B,MAAM,kBAAkB,CAAC;AAIzF,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC;AACtD,eAAO,MAAM,WAAW;;;CAGd,CAAC;AAEX,MAAM,WAAW,uBAAuB;IACtC,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sEAAsE;IACtE,YAAY,CAAC,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAC;IACxD,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,yBAAyB;;IAKvD,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM,EACtB,GAAG,IAAI,EAAE,qBAAqB,CAAC,OAAO,yBAAyB,CAAC;IAKlE,gEAAgE;IAChE,cAAc,CAAC,IAAI,EAAE,WAAW;IAIhC,6DAA6D;IAC7D,SAAS,CAAC,GAAG,EAAE,MAAM;IAIrB,+EAA+E;IAC/E,oBAAoB,CAAC,MAAM,EAAE,uBAAuB;IAI9C,gBAAgB,CACpB,cAAc,EAAE,oBAAoB,EAAE,GACrC,OAAO,CAAC,0BAA0B,CAAC;CA4GvC"}
|