@longarc/mdash 3.0.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 +278 -0
- package/dist/checkpoint/engine.d.ts +208 -0
- package/dist/checkpoint/engine.d.ts.map +1 -0
- package/dist/checkpoint/engine.js +369 -0
- package/dist/checkpoint/engine.js.map +1 -0
- package/dist/context/engine.d.ts +197 -0
- package/dist/context/engine.d.ts.map +1 -0
- package/dist/context/engine.js +392 -0
- package/dist/context/engine.js.map +1 -0
- package/dist/core/commitment.d.ts +154 -0
- package/dist/core/commitment.d.ts.map +1 -0
- package/dist/core/commitment.js +305 -0
- package/dist/core/commitment.js.map +1 -0
- package/dist/core/crypto.d.ts +100 -0
- package/dist/core/crypto.d.ts.map +1 -0
- package/dist/core/crypto.js +243 -0
- package/dist/core/crypto.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +234 -0
- package/dist/index.js.map +1 -0
- package/dist/mcca/engine.d.ts +260 -0
- package/dist/mcca/engine.d.ts.map +1 -0
- package/dist/mcca/engine.js +518 -0
- package/dist/mcca/engine.js.map +1 -0
- package/dist/physics/engine.d.ts +165 -0
- package/dist/physics/engine.d.ts.map +1 -0
- package/dist/physics/engine.js +371 -0
- package/dist/physics/engine.js.map +1 -0
- package/dist/tee/engine.d.ts +285 -0
- package/dist/tee/engine.d.ts.map +1 -0
- package/dist/tee/engine.js +505 -0
- package/dist/tee/engine.js.map +1 -0
- package/dist/warrant/engine.d.ts +195 -0
- package/dist/warrant/engine.d.ts.map +1 -0
- package/dist/warrant/engine.js +409 -0
- package/dist/warrant/engine.js.map +1 -0
- package/dist/zk/engine.d.ts +243 -0
- package/dist/zk/engine.d.ts.map +1 -0
- package/dist/zk/engine.js +489 -0
- package/dist/zk/engine.js.map +1 -0
- package/package.json +25 -0
- package/src/__tests__/phase1.test.ts +1120 -0
- package/src/__tests__/phase2-4.test.ts +898 -0
- package/src/checkpoint/engine.ts +532 -0
- package/src/context/engine.ts +598 -0
- package/src/core/commitment.ts +438 -0
- package/src/core/crypto.ts +304 -0
- package/src/index.ts +320 -0
- package/src/mcca/engine.ts +778 -0
- package/src/physics/engine.ts +563 -0
- package/src/tee/engine.ts +810 -0
- package/src/warrant/engine.ts +625 -0
- package/src/zk/engine.ts +730 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mdash v3.0 - L2 TEE Attestation Layer
|
|
3
|
+
*
|
|
4
|
+
* Hardware-rooted attestation for real-time compliance.
|
|
5
|
+
* Handles 99% of attestation needs with <10ms latency.
|
|
6
|
+
*
|
|
7
|
+
* Supported TEE Platforms:
|
|
8
|
+
* - AWS Nitro Enclaves (primary)
|
|
9
|
+
* - Intel SGX (secondary)
|
|
10
|
+
* - Simulated mode (development/testing)
|
|
11
|
+
*
|
|
12
|
+
* Architecture:
|
|
13
|
+
* - L1 provides instant commitment (<1ms)
|
|
14
|
+
* - L2 adds hardware attestation (<10ms)
|
|
15
|
+
* - L3 provides ZK proofs for disputes (async)
|
|
16
|
+
*
|
|
17
|
+
* @version 3.0.0
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
Hash,
|
|
22
|
+
Seal,
|
|
23
|
+
Timestamp,
|
|
24
|
+
generateTimestamp,
|
|
25
|
+
sha256,
|
|
26
|
+
sha256Object,
|
|
27
|
+
hmacSeal,
|
|
28
|
+
deriveKey,
|
|
29
|
+
} from '../core/crypto.js';
|
|
30
|
+
|
|
31
|
+
import { CommitmentEngine, Commitment } from '../core/commitment.js';
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// TEE TYPES
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
export type TEEPlatform = 'nitro' | 'sgx' | 'simulated';
|
|
38
|
+
|
|
39
|
+
export type AttestationStatus =
|
|
40
|
+
| 'pending'
|
|
41
|
+
| 'attesting'
|
|
42
|
+
| 'verified'
|
|
43
|
+
| 'failed'
|
|
44
|
+
| 'expired';
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Platform Capability Matrix
|
|
48
|
+
*
|
|
49
|
+
* | Feature | Nitro | SGX | Simulated |
|
|
50
|
+
* |-------------------|-------|------|-----------|
|
|
51
|
+
* | Memory encryption | ✓ | ✓ | ✗ |
|
|
52
|
+
* | Remote attestation| ✓ | ✓ | Simulated |
|
|
53
|
+
* | Key sealing | ✓ | ✓ | HMAC |
|
|
54
|
+
* | PCR support | ✓ | ✗ | Simulated |
|
|
55
|
+
* | Quote generation | ✗ | ✓ | Simulated |
|
|
56
|
+
*/
|
|
57
|
+
export interface PlatformCapabilities {
|
|
58
|
+
memoryEncryption: boolean;
|
|
59
|
+
remoteAttestation: boolean;
|
|
60
|
+
keySealing: boolean;
|
|
61
|
+
pcrSupport: boolean;
|
|
62
|
+
quoteGeneration: boolean;
|
|
63
|
+
maxEnclaveSize: number; // MB
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const PLATFORM_CAPABILITIES: Record<TEEPlatform, PlatformCapabilities> = {
|
|
67
|
+
nitro: {
|
|
68
|
+
memoryEncryption: true,
|
|
69
|
+
remoteAttestation: true,
|
|
70
|
+
keySealing: true,
|
|
71
|
+
pcrSupport: true,
|
|
72
|
+
quoteGeneration: false,
|
|
73
|
+
maxEnclaveSize: 8192, // 8GB
|
|
74
|
+
},
|
|
75
|
+
sgx: {
|
|
76
|
+
memoryEncryption: true,
|
|
77
|
+
remoteAttestation: true,
|
|
78
|
+
keySealing: true,
|
|
79
|
+
pcrSupport: false,
|
|
80
|
+
quoteGeneration: true,
|
|
81
|
+
maxEnclaveSize: 256, // 256MB EPC
|
|
82
|
+
},
|
|
83
|
+
simulated: {
|
|
84
|
+
memoryEncryption: false,
|
|
85
|
+
remoteAttestation: true, // Simulated
|
|
86
|
+
keySealing: true, // HMAC-based
|
|
87
|
+
pcrSupport: true, // Simulated
|
|
88
|
+
quoteGeneration: true, // Simulated
|
|
89
|
+
maxEnclaveSize: Infinity,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// ATTESTATION DOCUMENT SCHEMA
|
|
95
|
+
// ============================================================================
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* AWS Nitro Attestation Document (NSM format)
|
|
99
|
+
* Based on AWS Nitro Enclaves attestation spec
|
|
100
|
+
*/
|
|
101
|
+
export interface NitroAttestationDocument {
|
|
102
|
+
/** Module ID (enclave image hash) */
|
|
103
|
+
module_id: string;
|
|
104
|
+
/** UNIX timestamp of document creation */
|
|
105
|
+
timestamp: number;
|
|
106
|
+
/** Digest algorithm (SHA384) */
|
|
107
|
+
digest: 'SHA384';
|
|
108
|
+
/** PCR values (0-15) */
|
|
109
|
+
pcrs: Record<number, string>;
|
|
110
|
+
/** Certificate chain */
|
|
111
|
+
certificate: string;
|
|
112
|
+
/** CA bundle hash */
|
|
113
|
+
cabundle: string[];
|
|
114
|
+
/** Public key (optional, for encrypted response) */
|
|
115
|
+
public_key?: string;
|
|
116
|
+
/** User data (up to 512 bytes) */
|
|
117
|
+
user_data?: string;
|
|
118
|
+
/** Nonce (up to 512 bytes) */
|
|
119
|
+
nonce?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Intel SGX Quote
|
|
124
|
+
*/
|
|
125
|
+
export interface SGXQuote {
|
|
126
|
+
/** ECDSA-256 signature over report body */
|
|
127
|
+
signature: string;
|
|
128
|
+
/** ISV enclave report */
|
|
129
|
+
report_body: {
|
|
130
|
+
/** MRENCLAVE - enclave measurement */
|
|
131
|
+
mr_enclave: string;
|
|
132
|
+
/** MRSIGNER - signer measurement */
|
|
133
|
+
mr_signer: string;
|
|
134
|
+
/** ISV product ID */
|
|
135
|
+
isv_prod_id: number;
|
|
136
|
+
/** ISV security version */
|
|
137
|
+
isv_svn: number;
|
|
138
|
+
/** Report data (64 bytes user data) */
|
|
139
|
+
report_data: string;
|
|
140
|
+
/** Attributes (debug, mode64bit, etc) */
|
|
141
|
+
attributes: string;
|
|
142
|
+
};
|
|
143
|
+
/** QE (Quoting Enclave) certification data */
|
|
144
|
+
qe_certification: {
|
|
145
|
+
type: number;
|
|
146
|
+
data: string;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Unified Attestation Document
|
|
152
|
+
* Works across all platforms
|
|
153
|
+
*/
|
|
154
|
+
export interface AttestationDocument {
|
|
155
|
+
/** Document ID */
|
|
156
|
+
id: string;
|
|
157
|
+
/** Platform that generated this document */
|
|
158
|
+
platform: TEEPlatform;
|
|
159
|
+
/** Timestamp of attestation */
|
|
160
|
+
timestamp: Timestamp;
|
|
161
|
+
/** Enclave measurement hash */
|
|
162
|
+
measurement: Hash;
|
|
163
|
+
/** Data being attested */
|
|
164
|
+
attested_data: Hash;
|
|
165
|
+
/** Platform-specific attestation */
|
|
166
|
+
platform_attestation: NitroAttestationDocument | SGXQuote | SimulatedAttestation;
|
|
167
|
+
/** L1 commitment reference */
|
|
168
|
+
commitment_id: string;
|
|
169
|
+
/** Attestation status */
|
|
170
|
+
status: AttestationStatus;
|
|
171
|
+
/** Expiry time */
|
|
172
|
+
expires_at: Timestamp;
|
|
173
|
+
/** HMAC seal over document */
|
|
174
|
+
seal: Seal;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Simulated attestation (dev/test)
|
|
179
|
+
*/
|
|
180
|
+
export interface SimulatedAttestation {
|
|
181
|
+
type: 'simulated';
|
|
182
|
+
measurement_hash: string;
|
|
183
|
+
nonce: string;
|
|
184
|
+
simulated_pcrs: Record<number, string>;
|
|
185
|
+
signature: string;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ============================================================================
|
|
189
|
+
// TEE CONFIGURATION
|
|
190
|
+
// ============================================================================
|
|
191
|
+
|
|
192
|
+
export interface TEEConfig {
|
|
193
|
+
/** Platform to use */
|
|
194
|
+
platform: TEEPlatform;
|
|
195
|
+
/** Attestation document TTL (ms) */
|
|
196
|
+
attestationTTL: number;
|
|
197
|
+
/** Enable caching */
|
|
198
|
+
enableCache: boolean;
|
|
199
|
+
/** Cache TTL (ms) */
|
|
200
|
+
cacheTTL: number;
|
|
201
|
+
/** Max attestations per second */
|
|
202
|
+
rateLimit: number;
|
|
203
|
+
/** AWS Nitro specific */
|
|
204
|
+
nitro?: {
|
|
205
|
+
/** PCRs to include */
|
|
206
|
+
pcrs: number[];
|
|
207
|
+
/** NSM device path */
|
|
208
|
+
nsmDevice: string;
|
|
209
|
+
};
|
|
210
|
+
/** Intel SGX specific */
|
|
211
|
+
sgx?: {
|
|
212
|
+
/** SPID for attestation service */
|
|
213
|
+
spid: string;
|
|
214
|
+
/** API key for IAS */
|
|
215
|
+
iasApiKey: string;
|
|
216
|
+
/** Use DCAP (Data Center Attestation Primitives) */
|
|
217
|
+
useDCAP: boolean;
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const DEFAULT_CONFIG: TEEConfig = {
|
|
222
|
+
platform: 'simulated',
|
|
223
|
+
attestationTTL: 60 * 1000, // 1 minute
|
|
224
|
+
enableCache: true,
|
|
225
|
+
cacheTTL: 30 * 1000, // 30 seconds
|
|
226
|
+
rateLimit: 1000, // 1000/sec
|
|
227
|
+
nitro: {
|
|
228
|
+
pcrs: [0, 1, 2, 4, 8],
|
|
229
|
+
nsmDevice: '/dev/nsm',
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// ============================================================================
|
|
234
|
+
// ATTESTATION CACHE
|
|
235
|
+
// ============================================================================
|
|
236
|
+
|
|
237
|
+
interface CacheEntry {
|
|
238
|
+
document: AttestationDocument;
|
|
239
|
+
cachedAt: number;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
class AttestationCache {
|
|
243
|
+
private cache: Map<string, CacheEntry> = new Map();
|
|
244
|
+
private ttl: number;
|
|
245
|
+
|
|
246
|
+
constructor(ttlMs: number) {
|
|
247
|
+
this.ttl = ttlMs;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
set(key: string, document: AttestationDocument): void {
|
|
251
|
+
this.cache.set(key, {
|
|
252
|
+
document,
|
|
253
|
+
cachedAt: Date.now(),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
get(key: string): AttestationDocument | null {
|
|
258
|
+
const entry = this.cache.get(key);
|
|
259
|
+
if (!entry) return null;
|
|
260
|
+
|
|
261
|
+
if (Date.now() - entry.cachedAt > this.ttl) {
|
|
262
|
+
this.cache.delete(key);
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return entry.document;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
invalidate(key: string): void {
|
|
270
|
+
this.cache.delete(key);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
clear(): void {
|
|
274
|
+
this.cache.clear();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
getStats(): { size: number; hitRate: number } {
|
|
278
|
+
return {
|
|
279
|
+
size: this.cache.size,
|
|
280
|
+
hitRate: 0, // Would track in production
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ============================================================================
|
|
286
|
+
// TEE ATTESTATION ENGINE
|
|
287
|
+
// ============================================================================
|
|
288
|
+
|
|
289
|
+
export class TEEAttestationEngine {
|
|
290
|
+
private key: CryptoKey | null = null;
|
|
291
|
+
private config: TEEConfig;
|
|
292
|
+
private commitmentEngine: CommitmentEngine;
|
|
293
|
+
private cache: AttestationCache;
|
|
294
|
+
private documents: Map<string, AttestationDocument> = new Map();
|
|
295
|
+
|
|
296
|
+
// Rate limiting
|
|
297
|
+
private requestCount: number = 0;
|
|
298
|
+
private requestWindowStart: number = Date.now();
|
|
299
|
+
|
|
300
|
+
// Metrics
|
|
301
|
+
private metrics = {
|
|
302
|
+
attestations: 0,
|
|
303
|
+
cacheHits: 0,
|
|
304
|
+
cacheMisses: 0,
|
|
305
|
+
failures: 0,
|
|
306
|
+
totalLatencyMs: 0,
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
constructor(commitmentEngine: CommitmentEngine, config: Partial<TEEConfig> = {}) {
|
|
310
|
+
this.commitmentEngine = commitmentEngine;
|
|
311
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
312
|
+
this.cache = new AttestationCache(this.config.cacheTTL);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Initialize the TEE engine
|
|
317
|
+
*/
|
|
318
|
+
async initialize(sealKey: string): Promise<void> {
|
|
319
|
+
this.key = await deriveKey(sealKey);
|
|
320
|
+
|
|
321
|
+
// Platform-specific initialization
|
|
322
|
+
if (this.config.platform === 'nitro') {
|
|
323
|
+
await this.initializeNitro();
|
|
324
|
+
} else if (this.config.platform === 'sgx') {
|
|
325
|
+
await this.initializeSGX();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Initialize AWS Nitro Enclaves
|
|
331
|
+
*/
|
|
332
|
+
private async initializeNitro(): Promise<void> {
|
|
333
|
+
// In production, this would:
|
|
334
|
+
// 1. Open /dev/nsm device
|
|
335
|
+
// 2. Verify enclave environment
|
|
336
|
+
// 3. Generate enclave key pair
|
|
337
|
+
console.log('[TEE] Nitro Enclaves initialized (simulated)');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Initialize Intel SGX
|
|
342
|
+
*/
|
|
343
|
+
private async initializeSGX(): Promise<void> {
|
|
344
|
+
// In production, this would:
|
|
345
|
+
// 1. Initialize SGX SDK
|
|
346
|
+
// 2. Load enclave
|
|
347
|
+
// 3. Establish IAS connection
|
|
348
|
+
console.log('[TEE] Intel SGX initialized (simulated)');
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Attest data with hardware TEE
|
|
353
|
+
* Target: <10ms latency
|
|
354
|
+
*
|
|
355
|
+
* @param data - Data to attest
|
|
356
|
+
* @param commitmentId - L1 commitment reference
|
|
357
|
+
* @returns Attestation document
|
|
358
|
+
*/
|
|
359
|
+
async attest(
|
|
360
|
+
data: unknown,
|
|
361
|
+
commitmentId: string
|
|
362
|
+
): Promise<AttestationDocument> {
|
|
363
|
+
if (!this.key) {
|
|
364
|
+
throw new Error('TEE engine not initialized');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const startTime = performance.now();
|
|
368
|
+
|
|
369
|
+
// Rate limiting
|
|
370
|
+
this.checkRateLimit();
|
|
371
|
+
|
|
372
|
+
// Generate cache key
|
|
373
|
+
const dataHash = await sha256Object(data);
|
|
374
|
+
const cacheKey = `${dataHash}:${commitmentId}`;
|
|
375
|
+
|
|
376
|
+
// Check cache
|
|
377
|
+
if (this.config.enableCache) {
|
|
378
|
+
const cached = this.cache.get(cacheKey);
|
|
379
|
+
if (cached && cached.status === 'verified') {
|
|
380
|
+
this.metrics.cacheHits++;
|
|
381
|
+
return cached;
|
|
382
|
+
}
|
|
383
|
+
this.metrics.cacheMisses++;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Generate attestation based on platform
|
|
387
|
+
let platformAttestation: NitroAttestationDocument | SGXQuote | SimulatedAttestation;
|
|
388
|
+
let measurement: Hash;
|
|
389
|
+
|
|
390
|
+
switch (this.config.platform) {
|
|
391
|
+
case 'nitro':
|
|
392
|
+
const nitroResult = await this.attestNitro(data, dataHash);
|
|
393
|
+
platformAttestation = nitroResult.document;
|
|
394
|
+
measurement = nitroResult.measurement;
|
|
395
|
+
break;
|
|
396
|
+
case 'sgx':
|
|
397
|
+
const sgxResult = await this.attestSGX(data, dataHash);
|
|
398
|
+
platformAttestation = sgxResult.quote;
|
|
399
|
+
measurement = sgxResult.measurement;
|
|
400
|
+
break;
|
|
401
|
+
case 'simulated':
|
|
402
|
+
default:
|
|
403
|
+
const simResult = await this.attestSimulated(data, dataHash);
|
|
404
|
+
platformAttestation = simResult.attestation;
|
|
405
|
+
measurement = simResult.measurement;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const now = generateTimestamp();
|
|
409
|
+
const expiresAt = new Date(
|
|
410
|
+
Date.now() + this.config.attestationTTL
|
|
411
|
+
).toISOString() as Timestamp;
|
|
412
|
+
|
|
413
|
+
// Create attestation document
|
|
414
|
+
const docData = {
|
|
415
|
+
id: `att-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
416
|
+
platform: this.config.platform,
|
|
417
|
+
timestamp: now,
|
|
418
|
+
measurement,
|
|
419
|
+
attested_data: dataHash,
|
|
420
|
+
platform_attestation: platformAttestation,
|
|
421
|
+
commitment_id: commitmentId,
|
|
422
|
+
status: 'verified' as AttestationStatus,
|
|
423
|
+
expires_at: expiresAt,
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// Seal the document
|
|
427
|
+
const seal = await hmacSeal(docData, this.key);
|
|
428
|
+
|
|
429
|
+
const document: AttestationDocument = {
|
|
430
|
+
...docData,
|
|
431
|
+
seal,
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
// Store and cache
|
|
435
|
+
this.documents.set(document.id, document);
|
|
436
|
+
if (this.config.enableCache) {
|
|
437
|
+
this.cache.set(cacheKey, document);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Commit to L1
|
|
441
|
+
await this.commitmentEngine.commit(document, `tee:${document.id}`);
|
|
442
|
+
|
|
443
|
+
// Track metrics
|
|
444
|
+
const elapsed = performance.now() - startTime;
|
|
445
|
+
this.metrics.attestations++;
|
|
446
|
+
this.metrics.totalLatencyMs += elapsed;
|
|
447
|
+
|
|
448
|
+
if (elapsed > 10) {
|
|
449
|
+
console.warn(`[TEE] Attestation exceeded 10ms target: ${elapsed.toFixed(2)}ms`);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return document;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* AWS Nitro Enclaves attestation
|
|
457
|
+
*/
|
|
458
|
+
private async attestNitro(
|
|
459
|
+
data: unknown,
|
|
460
|
+
dataHash: Hash
|
|
461
|
+
): Promise<{ document: NitroAttestationDocument; measurement: Hash }> {
|
|
462
|
+
// In production, this would call /dev/nsm to get attestation document
|
|
463
|
+
// Simulating the NSM response structure
|
|
464
|
+
|
|
465
|
+
const nonce = crypto.randomUUID();
|
|
466
|
+
|
|
467
|
+
// Generate PCR values (simulated)
|
|
468
|
+
const pcrs: Record<number, string> = {};
|
|
469
|
+
for (const pcr of this.config.nitro?.pcrs || [0, 1, 2]) {
|
|
470
|
+
pcrs[pcr] = await sha256(`pcr-${pcr}-${dataHash}`);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Module ID is the enclave image measurement
|
|
474
|
+
const moduleId = await sha256(`nitro-enclave-image-v3.0.0`);
|
|
475
|
+
|
|
476
|
+
const document: NitroAttestationDocument = {
|
|
477
|
+
module_id: moduleId,
|
|
478
|
+
timestamp: Date.now(),
|
|
479
|
+
digest: 'SHA384',
|
|
480
|
+
pcrs,
|
|
481
|
+
certificate: 'simulated-nitro-certificate',
|
|
482
|
+
cabundle: ['simulated-ca-root'],
|
|
483
|
+
user_data: Buffer.from(dataHash).toString('base64').slice(0, 512),
|
|
484
|
+
nonce,
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
return {
|
|
488
|
+
document,
|
|
489
|
+
measurement: moduleId as Hash,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Intel SGX attestation
|
|
495
|
+
*/
|
|
496
|
+
private async attestSGX(
|
|
497
|
+
data: unknown,
|
|
498
|
+
dataHash: Hash
|
|
499
|
+
): Promise<{ quote: SGXQuote; measurement: Hash }> {
|
|
500
|
+
// In production, this would:
|
|
501
|
+
// 1. Call sgx_create_report
|
|
502
|
+
// 2. Send to QE (Quoting Enclave)
|
|
503
|
+
// 3. Get signed quote
|
|
504
|
+
// 4. Optionally verify with IAS
|
|
505
|
+
|
|
506
|
+
const mrEnclave = await sha256(`sgx-enclave-v3.0.0`);
|
|
507
|
+
const mrSigner = await sha256(`long-arc-studios-signing-key`);
|
|
508
|
+
|
|
509
|
+
const quote: SGXQuote = {
|
|
510
|
+
signature: await sha256(`sgx-quote-sig-${dataHash}-${Date.now()}`),
|
|
511
|
+
report_body: {
|
|
512
|
+
mr_enclave: mrEnclave,
|
|
513
|
+
mr_signer: mrSigner,
|
|
514
|
+
isv_prod_id: 1,
|
|
515
|
+
isv_svn: 1,
|
|
516
|
+
report_data: dataHash,
|
|
517
|
+
attributes: '0x0000000000000007', // Debug=0, Mode64=1, Init=1, Prov=1
|
|
518
|
+
},
|
|
519
|
+
qe_certification: {
|
|
520
|
+
type: 5, // PPID_RSA3072_ENCRYPTED
|
|
521
|
+
data: 'simulated-qe-cert-data',
|
|
522
|
+
},
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
return {
|
|
526
|
+
quote,
|
|
527
|
+
measurement: mrEnclave as Hash,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Simulated attestation (development/testing)
|
|
533
|
+
*/
|
|
534
|
+
private async attestSimulated(
|
|
535
|
+
data: unknown,
|
|
536
|
+
dataHash: Hash
|
|
537
|
+
): Promise<{ attestation: SimulatedAttestation; measurement: Hash }> {
|
|
538
|
+
const measurement = await sha256(`simulated-enclave-v3.0.0`);
|
|
539
|
+
const nonce = crypto.randomUUID();
|
|
540
|
+
|
|
541
|
+
// Generate simulated PCRs
|
|
542
|
+
const pcrs: Record<number, string> = {};
|
|
543
|
+
for (let i = 0; i < 16; i++) {
|
|
544
|
+
pcrs[i] = await sha256(`sim-pcr-${i}-${dataHash}`);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const attestation: SimulatedAttestation = {
|
|
548
|
+
type: 'simulated',
|
|
549
|
+
measurement_hash: measurement,
|
|
550
|
+
nonce,
|
|
551
|
+
simulated_pcrs: pcrs,
|
|
552
|
+
signature: await sha256(`sim-sig-${dataHash}-${nonce}`),
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
return {
|
|
556
|
+
attestation,
|
|
557
|
+
measurement: measurement as Hash,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Verify an attestation document
|
|
563
|
+
*/
|
|
564
|
+
async verify(document: AttestationDocument): Promise<{
|
|
565
|
+
valid: boolean;
|
|
566
|
+
errors: string[];
|
|
567
|
+
}> {
|
|
568
|
+
if (!this.key) {
|
|
569
|
+
throw new Error('TEE engine not initialized');
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const errors: string[] = [];
|
|
573
|
+
|
|
574
|
+
// 1. Check expiry
|
|
575
|
+
if (new Date(document.expires_at) < new Date()) {
|
|
576
|
+
errors.push('Attestation document expired');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// 2. Verify seal
|
|
580
|
+
const docWithoutSeal = { ...document };
|
|
581
|
+
delete (docWithoutSeal as any).seal;
|
|
582
|
+
const expectedSeal = await hmacSeal(docWithoutSeal, this.key);
|
|
583
|
+
if (expectedSeal !== document.seal) {
|
|
584
|
+
errors.push('Invalid document seal');
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// 3. Verify L1 commitment exists
|
|
588
|
+
const commitment = this.commitmentEngine.getCommitment(`tee:${document.id}`);
|
|
589
|
+
if (!commitment) {
|
|
590
|
+
errors.push('L1 commitment not found');
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// 4. Platform-specific verification
|
|
594
|
+
switch (document.platform) {
|
|
595
|
+
case 'nitro':
|
|
596
|
+
// Would verify certificate chain with AWS root
|
|
597
|
+
break;
|
|
598
|
+
case 'sgx':
|
|
599
|
+
// Would verify quote with IAS or DCAP
|
|
600
|
+
break;
|
|
601
|
+
case 'simulated':
|
|
602
|
+
// Just verify signature format
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return {
|
|
607
|
+
valid: errors.length === 0,
|
|
608
|
+
errors,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Get attestation document by ID
|
|
614
|
+
*/
|
|
615
|
+
get(id: string): AttestationDocument | null {
|
|
616
|
+
return this.documents.get(id) || null;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Rate limiting check
|
|
621
|
+
*/
|
|
622
|
+
private checkRateLimit(): void {
|
|
623
|
+
const now = Date.now();
|
|
624
|
+
|
|
625
|
+
// Reset window every second
|
|
626
|
+
if (now - this.requestWindowStart > 1000) {
|
|
627
|
+
this.requestCount = 0;
|
|
628
|
+
this.requestWindowStart = now;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
this.requestCount++;
|
|
632
|
+
|
|
633
|
+
if (this.requestCount > this.config.rateLimit) {
|
|
634
|
+
throw new Error('TEE attestation rate limit exceeded');
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Get platform capabilities
|
|
640
|
+
*/
|
|
641
|
+
getCapabilities(): PlatformCapabilities {
|
|
642
|
+
return PLATFORM_CAPABILITIES[this.config.platform];
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Get engine statistics
|
|
647
|
+
*/
|
|
648
|
+
getStats(): {
|
|
649
|
+
platform: TEEPlatform;
|
|
650
|
+
attestations: number;
|
|
651
|
+
cacheHits: number;
|
|
652
|
+
cacheMisses: number;
|
|
653
|
+
failures: number;
|
|
654
|
+
avgLatencyMs: number;
|
|
655
|
+
cacheStats: { size: number; hitRate: number };
|
|
656
|
+
} {
|
|
657
|
+
return {
|
|
658
|
+
platform: this.config.platform,
|
|
659
|
+
attestations: this.metrics.attestations,
|
|
660
|
+
cacheHits: this.metrics.cacheHits,
|
|
661
|
+
cacheMisses: this.metrics.cacheMisses,
|
|
662
|
+
failures: this.metrics.failures,
|
|
663
|
+
avgLatencyMs: this.metrics.attestations > 0
|
|
664
|
+
? this.metrics.totalLatencyMs / this.metrics.attestations
|
|
665
|
+
: 0,
|
|
666
|
+
cacheStats: this.cache.getStats(),
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// ============================================================================
|
|
672
|
+
// TEE VERIFIER (Remote Attestation Verification)
|
|
673
|
+
// ============================================================================
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Verifies attestation documents from external sources
|
|
677
|
+
* Used for cross-enclave or remote attestation scenarios
|
|
678
|
+
*/
|
|
679
|
+
export class TEEVerifier {
|
|
680
|
+
private trustedMeasurements: Set<Hash> = new Set();
|
|
681
|
+
private trustedSigners: Set<Hash> = new Set();
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Add a trusted enclave measurement
|
|
685
|
+
*/
|
|
686
|
+
trustMeasurement(measurement: Hash): void {
|
|
687
|
+
this.trustedMeasurements.add(measurement);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Add a trusted signer (for SGX)
|
|
692
|
+
*/
|
|
693
|
+
trustSigner(signer: Hash): void {
|
|
694
|
+
this.trustedSigners.add(signer);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Verify remote attestation
|
|
699
|
+
*/
|
|
700
|
+
async verifyRemote(document: AttestationDocument): Promise<{
|
|
701
|
+
trusted: boolean;
|
|
702
|
+
reasons: string[];
|
|
703
|
+
}> {
|
|
704
|
+
const reasons: string[] = [];
|
|
705
|
+
|
|
706
|
+
// Check measurement is trusted
|
|
707
|
+
if (!this.trustedMeasurements.has(document.measurement)) {
|
|
708
|
+
reasons.push(`Unknown enclave measurement: ${document.measurement}`);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Platform-specific checks
|
|
712
|
+
if (document.platform === 'sgx') {
|
|
713
|
+
const quote = document.platform_attestation as SGXQuote;
|
|
714
|
+
if (!this.trustedSigners.has(quote.report_body.mr_signer as Hash)) {
|
|
715
|
+
reasons.push(`Unknown signer: ${quote.report_body.mr_signer}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Check expiry
|
|
720
|
+
if (new Date(document.expires_at) < new Date()) {
|
|
721
|
+
reasons.push('Document expired');
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return {
|
|
725
|
+
trusted: reasons.length === 0,
|
|
726
|
+
reasons,
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// ============================================================================
|
|
732
|
+
// ATTESTATION BRIDGE (L1 <-> L2)
|
|
733
|
+
// ============================================================================
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Bridges L1 commitments with L2 attestations
|
|
737
|
+
* Ensures cryptographic continuity between layers
|
|
738
|
+
*/
|
|
739
|
+
export class AttestationBridge {
|
|
740
|
+
private teeEngine: TEEAttestationEngine;
|
|
741
|
+
private commitmentEngine: CommitmentEngine;
|
|
742
|
+
|
|
743
|
+
constructor(teeEngine: TEEAttestationEngine, commitmentEngine: CommitmentEngine) {
|
|
744
|
+
this.teeEngine = teeEngine;
|
|
745
|
+
this.commitmentEngine = commitmentEngine;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Commit and attest in one operation
|
|
750
|
+
* Returns both L1 seal and L2 attestation
|
|
751
|
+
*/
|
|
752
|
+
async commitAndAttest(
|
|
753
|
+
data: unknown,
|
|
754
|
+
operationId: string
|
|
755
|
+
): Promise<{
|
|
756
|
+
commitment: Commitment;
|
|
757
|
+
attestation: AttestationDocument;
|
|
758
|
+
}> {
|
|
759
|
+
// L1: Commit first (<1ms)
|
|
760
|
+
const commitment = await this.commitmentEngine.commit(data, operationId);
|
|
761
|
+
|
|
762
|
+
// L2: Attest with reference to L1 (<10ms)
|
|
763
|
+
const attestation = await this.teeEngine.attest(data, operationId);
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
commitment,
|
|
767
|
+
attestation,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Verify both layers
|
|
773
|
+
*/
|
|
774
|
+
async verifyBoth(
|
|
775
|
+
commitment: Commitment,
|
|
776
|
+
attestation: AttestationDocument
|
|
777
|
+
): Promise<{
|
|
778
|
+
l1Valid: boolean;
|
|
779
|
+
l2Valid: boolean;
|
|
780
|
+
crossLayerValid: boolean;
|
|
781
|
+
errors: string[];
|
|
782
|
+
}> {
|
|
783
|
+
const errors: string[] = [];
|
|
784
|
+
|
|
785
|
+
// Verify L1
|
|
786
|
+
const l1Result = await this.commitmentEngine.verify(commitment);
|
|
787
|
+
if (!l1Result) {
|
|
788
|
+
errors.push('L1 commitment verification failed');
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// Verify L2
|
|
792
|
+
const l2Result = await this.teeEngine.verify(attestation);
|
|
793
|
+
if (!l2Result.valid) {
|
|
794
|
+
errors.push(...l2Result.errors);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// Cross-layer verification
|
|
798
|
+
const crossLayerValid = attestation.commitment_id === commitment.operationId;
|
|
799
|
+
if (!crossLayerValid) {
|
|
800
|
+
errors.push('Cross-layer reference mismatch');
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return {
|
|
804
|
+
l1Valid: l1Result,
|
|
805
|
+
l2Valid: l2Result.valid,
|
|
806
|
+
crossLayerValid,
|
|
807
|
+
errors,
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
}
|