@reclaimprotocol/attestor-core 5.0.4 → 5.0.5

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.
Files changed (122) hide show
  1. package/LICENSE +660 -660
  2. package/browser/resources/attestor-browser.min.mjs +31 -31
  3. package/lib/server/tee/acme-http-server.d.ts +13 -0
  4. package/lib/server/tee/attestation-generate.d.ts +29 -0
  5. package/lib/server/tee/bootstrap.d.ts +11 -0
  6. package/lib/server/tee/cert-manager.d.ts +24 -0
  7. package/lib/server/tee/cloud-logging.d.ts +23 -0
  8. package/lib/server/tee/secret-loader.d.ts +10 -0
  9. package/lib/server/tee/secret-manager.d.ts +3 -0
  10. package/lib/utils/gcp-attestation.d.ts +23 -0
  11. package/package.json +3 -3
  12. package/lib/avs/abis/avsDirectoryABI.js +0 -340
  13. package/lib/avs/abis/delegationABI.js +0 -1
  14. package/lib/avs/abis/registryABI.js +0 -725
  15. package/lib/avs/client/create-claim-on-avs.js +0 -138
  16. package/lib/avs/config.js +0 -20
  17. package/lib/avs/contracts/ReclaimServiceManager.js +0 -1
  18. package/lib/avs/contracts/common.js +0 -1
  19. package/lib/avs/contracts/factories/ReclaimServiceManager__factory.js +0 -1169
  20. package/lib/avs/contracts/factories/index.js +0 -4
  21. package/lib/avs/contracts/index.js +0 -2
  22. package/lib/avs/types/index.js +0 -1
  23. package/lib/avs/utils/contracts.js +0 -33
  24. package/lib/avs/utils/register.js +0 -78
  25. package/lib/avs/utils/tasks.js +0 -40
  26. package/lib/client/create-claim.js +0 -433
  27. package/lib/client/index.js +0 -3
  28. package/lib/client/tunnels/make-rpc-tcp-tunnel.js +0 -51
  29. package/lib/client/tunnels/make-rpc-tls-tunnel.js +0 -131
  30. package/lib/client/utils/attestor-pool.js +0 -25
  31. package/lib/client/utils/client-socket.js +0 -98
  32. package/lib/client/utils/message-handler.js +0 -87
  33. package/lib/config/index.js +0 -44
  34. package/lib/external-rpc/benchmark.js +0 -69
  35. package/lib/external-rpc/event-bus.js +0 -14
  36. package/lib/external-rpc/handle-incoming-msg.js +0 -233
  37. package/lib/external-rpc/jsc-polyfills/1.js +0 -82
  38. package/lib/external-rpc/jsc-polyfills/2.js +0 -20
  39. package/lib/external-rpc/jsc-polyfills/event.js +0 -14
  40. package/lib/external-rpc/jsc-polyfills/index.js +0 -2
  41. package/lib/external-rpc/jsc-polyfills/ws.js +0 -81
  42. package/lib/external-rpc/setup-browser.js +0 -33
  43. package/lib/external-rpc/setup-jsc.js +0 -22
  44. package/lib/external-rpc/types.js +0 -1
  45. package/lib/external-rpc/utils.js +0 -100
  46. package/lib/external-rpc/zk.js +0 -63
  47. package/lib/mechain/abis/governanceABI.js +0 -458
  48. package/lib/mechain/abis/taskABI.js +0 -509
  49. package/lib/mechain/client/create-claim-on-mechain.js +0 -28
  50. package/lib/mechain/client/index.js +0 -1
  51. package/lib/mechain/constants/index.js +0 -3
  52. package/lib/mechain/index.js +0 -2
  53. package/lib/mechain/types/index.js +0 -1
  54. package/lib/proto/api.js +0 -4273
  55. package/lib/proto/tee-bundle.js +0 -1316
  56. package/lib/providers/http/index.js +0 -658
  57. package/lib/providers/http/patch-parse5-tree.js +0 -33
  58. package/lib/providers/http/utils.js +0 -324
  59. package/lib/providers/index.js +0 -4
  60. package/lib/scripts/fetch-ec2-metadata.d.ts +0 -1
  61. package/lib/server/create-server.js +0 -103
  62. package/lib/server/handlers/claimTeeBundle.js +0 -252
  63. package/lib/server/handlers/claimTunnel.js +0 -73
  64. package/lib/server/handlers/completeClaimOnChain.js +0 -22
  65. package/lib/server/handlers/createClaimOnChain.js +0 -26
  66. package/lib/server/handlers/createTaskOnMechain.js +0 -47
  67. package/lib/server/handlers/createTunnel.js +0 -93
  68. package/lib/server/handlers/disconnectTunnel.js +0 -5
  69. package/lib/server/handlers/fetchCertificateBytes.js +0 -41
  70. package/lib/server/handlers/index.js +0 -22
  71. package/lib/server/handlers/init.js +0 -32
  72. package/lib/server/handlers/toprf.js +0 -16
  73. package/lib/server/index.js +0 -4
  74. package/lib/server/socket.js +0 -109
  75. package/lib/server/tunnels/make-tcp-tunnel.js +0 -177
  76. package/lib/server/utils/apm.js +0 -36
  77. package/lib/server/utils/assert-valid-claim-request.js +0 -204
  78. package/lib/server/utils/config-env.js +0 -4
  79. package/lib/server/utils/dns.js +0 -18
  80. package/lib/server/utils/gcp-attestation.js +0 -289
  81. package/lib/server/utils/generics.js +0 -51
  82. package/lib/server/utils/iso.js +0 -256
  83. package/lib/server/utils/keep-alive.js +0 -38
  84. package/lib/server/utils/nitro-attestation.js +0 -325
  85. package/lib/server/utils/process-handshake.js +0 -215
  86. package/lib/server/utils/proxy-session.js +0 -6
  87. package/lib/server/utils/tee-oprf-mpc-verification.js +0 -90
  88. package/lib/server/utils/tee-oprf-verification.js +0 -174
  89. package/lib/server/utils/tee-transcript-reconstruction.js +0 -187
  90. package/lib/server/utils/tee-verification.js +0 -421
  91. package/lib/server/utils/validation.js +0 -38
  92. package/lib/types/bgp.js +0 -1
  93. package/lib/types/claims.js +0 -1
  94. package/lib/types/client.js +0 -1
  95. package/lib/types/general.js +0 -1
  96. package/lib/types/handlers.js +0 -1
  97. package/lib/types/index.js +0 -10
  98. package/lib/types/providers.gen.js +0 -10
  99. package/lib/types/providers.js +0 -1
  100. package/lib/types/rpc.js +0 -1
  101. package/lib/types/signatures.js +0 -1
  102. package/lib/types/tunnel.js +0 -1
  103. package/lib/types/zk.js +0 -1
  104. package/lib/utils/auth.js +0 -59
  105. package/lib/utils/b64-json.js +0 -17
  106. package/lib/utils/bgp-listener.js +0 -119
  107. package/lib/utils/claims.js +0 -99
  108. package/lib/utils/env.js +0 -15
  109. package/lib/utils/error.js +0 -50
  110. package/lib/utils/generics.js +0 -317
  111. package/lib/utils/http-parser.js +0 -246
  112. package/lib/utils/index.js +0 -13
  113. package/lib/utils/logger.js +0 -91
  114. package/lib/utils/prepare-packets.js +0 -62
  115. package/lib/utils/redactions.js +0 -148
  116. package/lib/utils/retries.js +0 -24
  117. package/lib/utils/signatures/eth.js +0 -29
  118. package/lib/utils/signatures/index.js +0 -7
  119. package/lib/utils/socket-base.js +0 -90
  120. package/lib/utils/tls.js +0 -58
  121. package/lib/utils/ws.js +0 -22
  122. package/lib/utils/zk.js +0 -577
@@ -1,421 +0,0 @@
1
- /**
2
- * TEE Bundle verification utilities
3
- * Handles validation of TEE verification bundles including attestations and signatures
4
- */
5
- import { ServiceSignatureType } from "../../proto/api.js";
6
- import { BodyType, KOutputPayload, TOutputPayload, VerificationBundle } from "../../proto/tee-bundle.js";
7
- import { validateGcpAttestationAndExtractKey } from "./gcp-attestation.js";
8
- import { validateNitroAttestationAndExtractKey } from "./nitro-attestation.js";
9
- import { AttestorError } from "../../utils/error.js";
10
- import { SIGNATURES } from "../../utils/signatures/index.js";
11
- /**
12
- * Verifies a complete TEE verification bundle
13
- * @param bundleBytes - Raw protobuf-encoded verification bundle
14
- * @param logger - Logger instance
15
- * @returns Validated TEE bundle data
16
- */
17
- export async function verifyTeeBundle(bundleBytes, logger) {
18
- // Parse the verification bundle protobuf
19
- const bundle = parseVerificationBundle(bundleBytes);
20
- // Validate required components are present
21
- validateBundleCompleteness(bundle);
22
- // Extract public keys (from attestations or embedded keys)
23
- const { teekKeyResult, teetKeyResult } = await extractPublicKeys(bundle, logger);
24
- // Verify TEE signatures using extracted public keys
25
- await verifyTeeSignatures(bundle, teekKeyResult, teetKeyResult, logger);
26
- // Ensure signed messages are present
27
- if (!bundle.teekSigned || !bundle.teetSigned) {
28
- throw new AttestorError('ERROR_INVALID_CLAIM', 'Missing TEE signed messages');
29
- }
30
- // Parse TEE payloads
31
- const kOutputPayload = parseKOutputPayload(bundle.teekSigned);
32
- const tOutputPayload = parseTOutputPayload(bundle.teetSigned);
33
- // Validate timestamps
34
- validateTimestamps(kOutputPayload, tOutputPayload, logger);
35
- // Validate session IDs match (prevents cross-session component substitution)
36
- const teeSessionId = validateSessionIds(kOutputPayload, tOutputPayload, logger);
37
- logger.info('TEE bundle verification successful');
38
- return {
39
- teekSigned: bundle.teekSigned,
40
- teetSigned: bundle.teetSigned,
41
- kOutputPayload,
42
- tOutputPayload,
43
- teekPcr0: teekKeyResult.pcr0,
44
- teetPcr0: teetKeyResult.pcr0,
45
- teeSessionId,
46
- };
47
- }
48
- /**
49
- * Parses the raw verification bundle bytes into structured data
50
- */
51
- function parseVerificationBundle(bundleBytes) {
52
- try {
53
- // Use the actual protobuf decoder for the TEE bundle format
54
- return VerificationBundle.decode(bundleBytes);
55
- }
56
- catch (error) {
57
- throw new Error(`Failed to parse verification bundle: ${error.message}`);
58
- }
59
- }
60
- /**
61
- * Validates that all required bundle components are present
62
- */
63
- function validateBundleCompleteness(bundle) {
64
- if (!bundle.teekSigned) {
65
- throw new Error('SECURITY ERROR: missing TEE_K signed message - verification bundle incomplete');
66
- }
67
- if (!bundle.teetSigned) {
68
- throw new Error('SECURITY ERROR: missing TEE_T signed message - verification bundle incomplete');
69
- }
70
- // Check if we're in standalone mode (development/testing) or attestation mode (production)
71
- // Attestations are now embedded in SignedMessage.attestationReport
72
- const hasAttestations = (bundle.teekSigned.attestationReport?.report && bundle.teekSigned.attestationReport.report.length > 0) ||
73
- (bundle.teetSigned.attestationReport?.report && bundle.teetSigned.attestationReport.report.length > 0);
74
- const hasPublicKeys = (bundle.teekSigned.ethAddress && bundle.teekSigned.ethAddress.length > 0) ||
75
- (bundle.teetSigned.ethAddress && bundle.teetSigned.ethAddress.length > 0);
76
- if (!hasAttestations && !hasPublicKeys) {
77
- throw new Error('SECURITY ERROR: bundle must have either Nitro attestations (production) or embedded public keys (development)');
78
- }
79
- // Validate signed message structure
80
- if (bundle.teekSigned.bodyType !== BodyType.BODY_TYPE_K_OUTPUT) {
81
- throw new Error('Invalid TEE_K signed message: wrong body type');
82
- }
83
- if (bundle.teetSigned.bodyType !== BodyType.BODY_TYPE_T_OUTPUT) {
84
- throw new Error('Invalid TEE_T signed message: wrong body type');
85
- }
86
- if (!bundle.teekSigned.body || bundle.teekSigned.body.length === 0) {
87
- throw new Error('Invalid TEE_K signed message: empty body');
88
- }
89
- if (!bundle.teetSigned.body || bundle.teetSigned.body.length === 0) {
90
- throw new Error('Invalid TEE_T signed message: empty body');
91
- }
92
- if (!bundle.teekSigned.signature || bundle.teekSigned.signature.length === 0) {
93
- throw new Error('Invalid TEE_K signed message: missing signature');
94
- }
95
- if (!bundle.teetSigned.signature || bundle.teetSigned.signature.length === 0) {
96
- throw new Error('Invalid TEE_T signed message: missing signature');
97
- }
98
- }
99
- /**
100
- * Extracts public keys from either Nitro attestations or embedded keys (standalone mode)
101
- */
102
- async function extractPublicKeys(bundle, logger) {
103
- // Check if we have attestations (production mode) or embedded keys (standalone mode)
104
- // Attestations are now embedded in SignedMessage.attestationReport
105
- const hasEmbeddedAttestations = (bundle.teekSigned.attestationReport?.report && bundle.teekSigned.attestationReport.report.length > 0) &&
106
- (bundle.teetSigned.attestationReport?.report && bundle.teetSigned.attestationReport.report.length > 0);
107
- let teekKeyResult;
108
- let teetKeyResult;
109
- if (hasEmbeddedAttestations) {
110
- // Production mode: Extract from attestations (Nitro or GCP)
111
- logger.info('Using production mode: extracting keys from attestations');
112
- if (!bundle.teekSigned?.attestationReport?.report) {
113
- throw new Error('TEE_K embedded attestation report missing');
114
- }
115
- if (!bundle.teetSigned?.attestationReport?.report) {
116
- throw new Error('TEE_T embedded attestation report missing');
117
- }
118
- const teekAttestationType = bundle.teekSigned.attestationReport.type || 'nitro';
119
- const teetAttestationType = bundle.teetSigned.attestationReport.type || 'nitro';
120
- logger.info(`TEE_K attestation type: ${teekAttestationType}`);
121
- logger.info(`TEE_T attestation type: ${teetAttestationType}`);
122
- const teekAttestationBytes = bundle.teekSigned.attestationReport.report;
123
- const teetAttestationBytes = bundle.teetSigned.attestationReport.report;
124
- // Validate TEE_K attestation based on type
125
- if (teekAttestationType === 'gcp') {
126
- const gcpResult = await validateGcpAttestationAndExtractKey(teekAttestationBytes, logger);
127
- if (!gcpResult.isValid) {
128
- throw new Error(`TEE_K GCP attestation validation failed: ${gcpResult.errors.join(', ')}`);
129
- }
130
- if (!gcpResult.ethAddress) {
131
- throw new Error('TEE_K GCP attestation validation failed: no address');
132
- }
133
- if (gcpResult.userDataType !== 'tee_k') {
134
- throw new Error(`TEE_K GCP attestation validation failed: wrong TEE type, expected tee_k, got ${gcpResult.userDataType}`);
135
- }
136
- teekKeyResult = {
137
- teeType: gcpResult.userDataType,
138
- ethAddress: '0x' + Buffer.from(gcpResult.ethAddress).toString('hex'),
139
- pcr0: gcpResult.pcr0 || 'gcp-no-digest'
140
- };
141
- }
142
- else {
143
- const nitroResult = await validateNitroAttestationAndExtractKey(teekAttestationBytes);
144
- if (!nitroResult.isValid) {
145
- throw new Error(`TEE_K Nitro attestation validation failed: ${nitroResult.errors.join(', ')}`);
146
- }
147
- if (!nitroResult.ethAddress) {
148
- throw new Error('TEE_K Nitro attestation validation failed: no address');
149
- }
150
- if (nitroResult.userDataType !== 'tee_k') {
151
- throw new Error(`TEE_K Nitro attestation validation failed: wrong TEE type, expected tee_k, got ${nitroResult.userDataType}`);
152
- }
153
- teekKeyResult = {
154
- teeType: nitroResult.userDataType,
155
- ethAddress: nitroResult.ethAddress,
156
- pcr0: nitroResult.pcr0
157
- };
158
- }
159
- // Validate TEE_T attestation based on type
160
- if (teetAttestationType === 'gcp') {
161
- const gcpResult = await validateGcpAttestationAndExtractKey(teetAttestationBytes, logger);
162
- if (!gcpResult.isValid) {
163
- throw new Error(`TEE_T GCP attestation validation failed: ${gcpResult.errors.join(', ')}`);
164
- }
165
- if (!gcpResult.ethAddress) {
166
- throw new Error('TEE_T GCP attestation validation failed: no address');
167
- }
168
- if (gcpResult.userDataType !== 'tee_t') {
169
- throw new Error(`TEE_T GCP attestation validation failed: wrong TEE type, expected tee_t, got ${gcpResult.userDataType}`);
170
- }
171
- teetKeyResult = {
172
- teeType: gcpResult.userDataType,
173
- ethAddress: '0x' + Buffer.from(gcpResult.ethAddress).toString('hex'),
174
- pcr0: gcpResult.pcr0 || 'gcp-no-digest'
175
- };
176
- // Cross-validate: TEE_T must have EXPECTED_TEEK_PCR0 env var matching TEE_K's PCR0
177
- if (!gcpResult.envVars?.EXPECTED_TEEK_PCR0) {
178
- throw new Error('TEE_T GCP attestation missing required EXPECTED_TEEK_PCR0 environment variable');
179
- }
180
- const expectedPcr0 = gcpResult.envVars.EXPECTED_TEEK_PCR0;
181
- const actualPcr0 = teekKeyResult.pcr0;
182
- logger.info(`Cross-validating TEE_K PCR0: expected=${expectedPcr0}, actual=${actualPcr0}`);
183
- if (expectedPcr0 !== actualPcr0) {
184
- throw new Error(`TEE cross-validation failed: TEE_T expects TEE_K PCR0 "${expectedPcr0}" but got "${actualPcr0}"`);
185
- }
186
- logger.info('TEE cross-validation successful: TEE_K PCR0 matches TEE_T expectation');
187
- }
188
- else {
189
- const nitroResult = await validateNitroAttestationAndExtractKey(teetAttestationBytes);
190
- if (!nitroResult.isValid) {
191
- throw new Error(`TEE_T Nitro attestation validation failed: ${nitroResult.errors.join(', ')}`);
192
- }
193
- if (!nitroResult.ethAddress) {
194
- throw new Error('TEE_T Nitro attestation validation failed: no address');
195
- }
196
- if (nitroResult.userDataType !== 'tee_t') {
197
- throw new Error(`TEE_T Nitro attestation validation failed: wrong TEE type, expected tee_t, got ${nitroResult.userDataType}`);
198
- }
199
- teetKeyResult = {
200
- teeType: nitroResult.userDataType,
201
- ethAddress: nitroResult.ethAddress,
202
- pcr0: nitroResult.pcr0
203
- };
204
- }
205
- logger.info('Attestations validated successfully');
206
- }
207
- else {
208
- // Standalone/Development mode: Extract from embedded ETH addresses
209
- // SECURITY: Only allow standalone mode when explicitly enabled via environment variable
210
- const standaloneEnabled = process.env.TEE_STANDALONE === 'true' || process.env.TEE_STANDALONE === '1';
211
- if (!standaloneEnabled) {
212
- throw new Error('Missing attestation reports and standalone mode is not enabled (set TEE_STANDALONE=true to enable)');
213
- }
214
- const hasEmbeddedKeys = (bundle.teekSigned.ethAddress && bundle.teekSigned.ethAddress.length > 0) &&
215
- (bundle.teetSigned.ethAddress && bundle.teetSigned.ethAddress.length > 0);
216
- if (!hasEmbeddedKeys) {
217
- throw new Error('Missing attestation and no embedded ETH addresses for standalone mode');
218
- }
219
- logger.warn('STANDALONE MODE ENABLED: Using embedded ETH addresses without attestation verification');
220
- // Extract TEE_K address (stored as UTF-8 string like "0xe3c8d66...")
221
- const teekAddress = Buffer.from(bundle.teekSigned.ethAddress).toString('utf8');
222
- teekKeyResult = {
223
- teeType: 'tee_k',
224
- ethAddress: teekAddress,
225
- pcr0: 'standalone-mode' // No PCR0 in standalone mode
226
- };
227
- logger.info(`TEE_K standalone address: ${teekAddress}`);
228
- // Extract TEE_T address (stored as UTF-8 string like "0x3b8ad67...")
229
- const teetAddress = Buffer.from(bundle.teetSigned.ethAddress).toString('utf8');
230
- teetKeyResult = {
231
- teeType: 'tee_t',
232
- ethAddress: teetAddress,
233
- pcr0: 'standalone-mode' // No PCR0 in standalone mode
234
- };
235
- logger.info(`TEE_T standalone address: ${teetAddress}`);
236
- logger.info('Standalone mode key extraction successful');
237
- }
238
- return {
239
- teekKeyResult,
240
- teetKeyResult
241
- };
242
- }
243
- /**
244
- * Verifies TEE signatures using extracted key results
245
- */
246
- async function verifyTeeSignatures(bundle, teekKeyResult, teetKeyResult, logger) {
247
- // Verify TEE_K signature
248
- if (!bundle.teekSigned) {
249
- throw new Error('TEE_K signed message is missing');
250
- }
251
- const teekResult = await verifyTeeSignature(bundle.teekSigned, teekKeyResult, 'TEE_K', logger);
252
- if (!teekResult.isValid) {
253
- throw new Error(`TEE_K signature verification failed: ${teekResult.errors.join(', ')}`);
254
- }
255
- // Verify TEE_T signature
256
- if (!bundle.teetSigned) {
257
- throw new Error('TEE_T signed message is missing');
258
- }
259
- const teetResult = await verifyTeeSignature(bundle.teetSigned, teetKeyResult, 'TEE_T', logger);
260
- if (!teetResult.isValid) {
261
- throw new Error(`TEE_T signature verification failed: ${teetResult.errors.join(', ')}`);
262
- }
263
- logger.info('TEE signatures verified successfully');
264
- }
265
- /**
266
- * Verifies a single TEE signature using ETH address format
267
- */
268
- async function verifyTeeSignature(signedMessage, extractedKey, teeType, logger) {
269
- const errors = [];
270
- if (!signedMessage) {
271
- return {
272
- isValid: false,
273
- errors: ['Signed message is null or undefined']
274
- };
275
- }
276
- try {
277
- let ethAddress;
278
- if (extractedKey.ethAddress) {
279
- ethAddress = extractedKey.ethAddress;
280
- logger.debug(`${teeType} using ETH address from attestation: ${ethAddress}`);
281
- }
282
- else {
283
- return {
284
- isValid: false,
285
- errors: ['eth address is null'],
286
- };
287
- }
288
- // Use the ETH signature verification from the existing system
289
- const { verify: verifySig } = SIGNATURES[ServiceSignatureType.SERVICE_SIGNATURE_TYPE_ETH];
290
- // Verify signature over the body bytes
291
- const isValid = await verifySig(signedMessage.body, signedMessage.signature, ethAddress);
292
- if (!isValid) {
293
- errors.push(`${teeType} signature verification failed for address ${ethAddress}`);
294
- }
295
- logger.debug(`${teeType} signature verification result: ${isValid} for address ${ethAddress}`);
296
- return {
297
- isValid: errors.length === 0,
298
- errors,
299
- address: extractedKey.ethAddress
300
- };
301
- }
302
- catch (error) {
303
- errors.push(`${teeType} signature verification error: ${error.message}`);
304
- return {
305
- isValid: false,
306
- errors
307
- };
308
- }
309
- }
310
- /**
311
- * Parses TEE_K output payload
312
- */
313
- function parseKOutputPayload(signedMessage) {
314
- // Use actual protobuf decoding
315
- const payload = KOutputPayload.decode(signedMessage.body);
316
- // Validate required fields
317
- if (!payload.redactedRequest) {
318
- throw new Error('Missing redacted request in TEE_K payload');
319
- }
320
- if (!payload.consolidatedResponseKeystream || payload.consolidatedResponseKeystream.length === 0) {
321
- throw new Error('Missing consolidated response keystream in TEE_K payload');
322
- }
323
- if (!payload.certificateInfo) {
324
- throw new Error('Missing certificate info in TEE_K payload');
325
- }
326
- return payload;
327
- }
328
- /**
329
- * Parses TEE_T output payload
330
- */
331
- function parseTOutputPayload(signedMessage) {
332
- // Use actual protobuf decoding
333
- const payload = TOutputPayload.decode(signedMessage.body);
334
- // Validate required fields
335
- if (!payload.consolidatedResponseCiphertext || payload.consolidatedResponseCiphertext.length === 0) {
336
- throw new Error('Missing consolidated response ciphertext in TEE_T payload');
337
- }
338
- return payload;
339
- }
340
- /**
341
- * Validates that both K and T timestamps are within acceptable range
342
- * @param kPayload - K output payload with timestamp
343
- * @param tPayload - T output payload with timestamp
344
- * @param logger - Logger instance
345
- */
346
- function validateTimestamps(kPayload, tPayload, logger) {
347
- const now = Date.now(); // Current time in milliseconds
348
- const kTimestamp = kPayload.timestampMs;
349
- const tTimestamp = tPayload.timestampMs;
350
- // Convert to seconds for logging consistency with existing code
351
- const kTimestampS = Math.floor(kTimestamp / 1000);
352
- const tTimestampS = Math.floor(tTimestamp / 1000);
353
- const nowS = Math.floor(now / 1000);
354
- logger.info('Validating TEE timestamps', {
355
- kTimestampMs: kTimestamp,
356
- tTimestampMs: tTimestamp,
357
- kTimestampS,
358
- tTimestampS,
359
- nowS
360
- });
361
- // 1. Check that both timestamps are not earlier than 10 minutes in the past
362
- const maxAgeMs = 10 * 60 * 1000; // 10 minutes in milliseconds
363
- const oldestAllowed = now - maxAgeMs;
364
- if (kTimestamp < oldestAllowed) {
365
- throw new Error(`TEE_K timestamp ${kTimestamp} is too old. Must be within 10 minutes of current time ${now}`);
366
- }
367
- if (tTimestamp < oldestAllowed) {
368
- throw new Error(`TEE_T timestamp ${tTimestamp} is too old. Must be within 10 minutes of current time ${now}`);
369
- }
370
- // 1b. Check that timestamps are not in the future (with small tolerance for clock skew)
371
- const maxFutureMs = 60 * 1000; // 1 minute tolerance for clock skew
372
- const maxAllowed = now + maxFutureMs;
373
- if (kTimestamp > maxAllowed) {
374
- throw new Error(`TEE_K timestamp ${kTimestamp} is in the future. Current time is ${now}`);
375
- }
376
- if (tTimestamp > maxAllowed) {
377
- throw new Error(`TEE_T timestamp ${tTimestamp} is in the future. Current time is ${now}`);
378
- }
379
- // 2. Check that both timestamps are within 1 minute of each other
380
- const timestampDiffMs = Math.abs(kTimestamp - tTimestamp);
381
- const maxDiffMs = 60 * 1000; // 1 minute
382
- if (timestampDiffMs > maxDiffMs) {
383
- throw new Error(`TEE timestamps differ by ${timestampDiffMs}ms, which exceeds maximum allowed difference of ${maxDiffMs}ms (1 minute)`);
384
- }
385
- logger.info('TEE timestamp validation successful', {
386
- timestampDiffMs,
387
- ageKMs: now - kTimestamp,
388
- ageTMs: now - tTimestamp
389
- });
390
- }
391
- /**
392
- * Validates that both K and T payloads have matching session IDs
393
- * SECURITY: Prevents cross-session component substitution attacks
394
- * @param kPayload - K output payload with session_id
395
- * @param tPayload - T output payload with session_id
396
- * @param logger - Logger instance
397
- * @returns The validated session ID
398
- */
399
- function validateSessionIds(kPayload, tPayload, logger) {
400
- const kSessionId = kPayload.sessionId;
401
- const tSessionId = tPayload.sessionId;
402
- logger.info('Validating TEE session IDs', {
403
- kSessionId,
404
- tSessionId
405
- });
406
- // Both session IDs must be present
407
- if (!kSessionId || kSessionId.length === 0) {
408
- throw new AttestorError('ERROR_INVALID_CLAIM', 'Missing session_id in TEE_K payload - required for cross-TEE binding');
409
- }
410
- if (!tSessionId || tSessionId.length === 0) {
411
- throw new AttestorError('ERROR_INVALID_CLAIM', 'Missing session_id in TEE_T payload - required for cross-TEE binding');
412
- }
413
- // Session IDs must match
414
- if (kSessionId !== tSessionId) {
415
- throw new AttestorError('ERROR_INVALID_CLAIM', `Session ID mismatch: TEE_K session_id "${kSessionId}" does not match TEE_T session_id "${tSessionId}".`);
416
- }
417
- logger.info('TEE session ID validation successful', {
418
- sessionId: kSessionId
419
- });
420
- return kSessionId;
421
- }
@@ -1,38 +0,0 @@
1
- import { Ajv } from 'ajv';
2
- import { PROVIDER_SCHEMAS } from "../../types/providers.gen.js";
3
- import { AttestorError } from "../../utils/error.js";
4
- const PROVIDER_VALIDATOR_MAP = {};
5
- const AJV = new Ajv({
6
- allErrors: true,
7
- strict: true,
8
- strictRequired: false,
9
- formats: {
10
- binary(data) {
11
- return data instanceof Uint8Array
12
- || (typeof Buffer !== 'undefined'
13
- && Buffer.isBuffer(data));
14
- },
15
- url(data) {
16
- try {
17
- new URL(data);
18
- return true;
19
- }
20
- catch {
21
- return false;
22
- }
23
- }
24
- }
25
- });
26
- export function assertValidateProviderParams(name, params) {
27
- let validate = PROVIDER_VALIDATOR_MAP[name];
28
- if (!validate) {
29
- const schema = PROVIDER_SCHEMAS[name]?.parameters;
30
- if (!schema) {
31
- throw new AttestorError('ERROR_BAD_REQUEST', `Invalid provider name "${String(name)}"`);
32
- }
33
- validate = AJV.compile(schema);
34
- }
35
- if (!validate?.(params)) {
36
- throw new AttestorError('ERROR_BAD_REQUEST', 'Params validation failed', { errors: JSON.stringify(validate.errors) });
37
- }
38
- }
package/lib/types/bgp.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,10 +0,0 @@
1
- export * from "./providers.js";
2
- export * from "./general.js";
3
- export * from "./signatures.js";
4
- export * from "./claims.js";
5
- export * from "./zk.js";
6
- export * from "./client.js";
7
- export * from "./rpc.js";
8
- export * from "./tunnel.js";
9
- export * from "./handlers.js";
10
- export * from "./bgp.js";
@@ -1,10 +0,0 @@
1
- /* eslint-disable */
2
- /* Generated file. Do not edit */
3
- export const HttpProviderParametersJson = { "title": "HttpProviderParameters", "type": "object", "required": ["url", "method", "responseMatches"], "properties": { "url": { "type": "string", "format": "url", "description": "which URL does the request have to be made to Has to be a valid https URL for eg. https://amazon.in/orders?q=abcd" }, "method": { "type": "string", "enum": ["GET", "POST", "PUT", "PATCH"] }, "geoLocation": { "type": "string", "nullable": true, "description": "Specify the geographical location from where to proxy the request. 2-letter ISO country code or parameter (public or secret)" }, "proxySessionId": { "type": "string", "nullable": true, "description": "Specify the unique session id for allowing use of same proxy ip across multiple requests. Can be a smallcase alphanumeric string of length 8-14 characters. eg. \"mystring12345\", \"something1234\"." }, "headers": { "type": "object", "description": "Any additional headers to be sent with the request Note: these will be revealed to the attestor & won't be redacted from the transcript. To add hidden headers, use 'secretParams.headers' instead", "additionalProperties": { "type": "string" } }, "body": { "description": "Body of the HTTP request", "oneOf": [{ "type": "string", "format": "binary" }, { "type": "string" }] }, "writeRedactionMode": { "type": "string", "description": "If the API doesn't perform well with the \"key-update\" method of redaction, you can switch to \"zk\" mode by setting this to \"zk\"", "enum": ["zk", "key-update"] }, "additionalClientOptions": { "type": "object", "description": "Apply TLS configuration when creating the tunnel to the attestor.", "nullable": true, "properties": { "supportedProtocolVersions": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "enum": ["TLS1_2", "TLS1_3"] } } } }, "responseMatches": { "type": "array", "minItems": 1, "uniqueItems": true, "description": "The attestor will use this list to check that the redacted response does indeed match all the provided strings/regexes", "items": { "type": "object", "required": ["value", "type"], "properties": { "value": { "type": "string", "description": "\"regex\": the response must match the regex \"contains\": the response must contain the provided\n string exactly" }, "type": { "type": "string", "description": "The string/regex to match against", "enum": ["regex", "contains"] }, "invert": { "type": "boolean", "description": "Inverses the matching logic. Fail when match is found and proceed otherwise" } }, "additionalProperties": false } }, "responseRedactions": { "type": "array", "uniqueItems": true, "description": "which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (i.e. \"HTTP/1.1 200 OK\") * To disable any redactions, pass an empty array", "items": { "type": "object", "properties": { "xPath": { "type": "string", "nullable": true, "description": "expect an HTML response, and to contain a certain xpath for eg. \"/html/body/div.a1/div.a2/span.a5\"" }, "jsonPath": { "type": "string", "nullable": true, "description": "expect a JSON response, retrieve the item at this path using dot notation for e.g. 'email.addresses.0'" }, "regex": { "type": "string", "nullable": true, "description": "select a regex match from the response" }, "hash": { "type": "string", "description": "If provided, the value inside will be hashed instead of being redacted. Useful for cases where the data inside is an identifiying piece of information that you don't want to reveal to the attestor, eg. an email address.\nIf the hash function produces more bytes than the original value, the hash will be truncated.\nEg. if hash is enabled, the original value is \"hello\", and hashed is \"a1b2c\", then the attestor will only see \"a1b2c\".\nNote: if a regex with named groups is provided, only the named groups will be hashed.", "enum": ["oprf", "oprf-mpc"] } }, "additionalProperties": false } }, "paramValues": { "type": "object", "description": "A map of parameter values which are user in form of {{param}} in URL, responseMatches, responseRedactions, body, geolocation. Those in URL, responseMatches & geo will be put into context and signed This value will NOT be included in provider hash", "additionalProperties": { "type": "string" } } }, "additionalProperties": false };
4
- export const HttpProviderSecretParametersJson = { "title": "HttpProviderSecretParameters", "type": "object", "description": "Secret parameters to be used with HTTP provider. None of the values in this object will be shown to the attestor", "properties": { "cookieStr": { "type": "string", "description": "cookie string for authorisation." }, "authorisationHeader": { "type": "string", "description": "authorisation header value" }, "headers": { "type": "object", "description": "Headers that need to be hidden from the attestor", "additionalProperties": { "type": "string" } }, "paramValues": { "type": "object", "description": "A map of parameter values which are user in form of {{param}} in body these parameters will NOT be shown to attestor and extracted", "additionalProperties": { "type": "string" } } }, "additionalProperties": false };
5
- export const PROVIDER_SCHEMAS = {
6
- http: {
7
- parameters: HttpProviderParametersJson,
8
- secretParameters: HttpProviderSecretParametersJson
9
- },
10
- };
@@ -1 +0,0 @@
1
- export {};
package/lib/types/rpc.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
package/lib/types/zk.js DELETED
@@ -1 +0,0 @@
1
- export {};
package/lib/utils/auth.js DELETED
@@ -1,59 +0,0 @@
1
- import { ethers } from 'ethers';
2
- import { DEFAULT_AUTH_EXPIRY_S } from "../config/index.js";
3
- import { AuthenticatedUserData } from "../proto/api.js";
4
- import { getEnvVariable } from "./env.js";
5
- import { AttestorError } from "./error.js";
6
- import { unixTimestampSeconds } from "./generics.js";
7
- import { SelectedServiceSignature, SIGNATURES } from "./signatures/index.js";
8
- export async function assertValidAuthRequest(request, signatureType) {
9
- const publicKey = getEnvVariable('AUTHENTICATION_PUBLIC_KEY');
10
- // nothing to verify
11
- if (!request) {
12
- // if pub key is provided -- but user didn't attempt to
13
- // authenticate, then we should throw an error
14
- if (publicKey) {
15
- throw new AttestorError('ERROR_AUTHENTICATION_FAILED', 'User must be authenticated');
16
- }
17
- return;
18
- }
19
- if (!publicKey) {
20
- throw new AttestorError('ERROR_BAD_REQUEST', 'The attestor is not configured for authentication');
21
- }
22
- const { signature, data } = request;
23
- if (!data) {
24
- throw new AttestorError('ERROR_AUTHENTICATION_FAILED', 'Missing data in auth request');
25
- }
26
- if (data.expiresAt < unixTimestampSeconds()) {
27
- throw new AttestorError('ERROR_AUTHENTICATION_FAILED', 'Authentication request has expired');
28
- }
29
- const proto = AuthenticatedUserData.encode(data).finish();
30
- const signatureAlg = SIGNATURES[signatureType];
31
- const address = signatureAlg.getAddress(await ethers.utils.arrayify(publicKey));
32
- const verified = await signatureAlg
33
- .verify(proto, signature, address);
34
- if (!verified) {
35
- throw new AttestorError('ERROR_AUTHENTICATION_FAILED', 'Signature verification failed');
36
- }
37
- }
38
- /**
39
- * Create an authentication request with the given data and private key,
40
- * which can then be used to authenticate with the service.
41
- */
42
- export async function createAuthRequest(_data, privateKey) {
43
- const createdAt = unixTimestampSeconds();
44
- const data = {
45
- createdAt,
46
- expiresAt: createdAt + DEFAULT_AUTH_EXPIRY_S,
47
- id: '',
48
- hostWhitelist: [],
49
- ..._data,
50
- };
51
- const proto = AuthenticatedUserData.encode(data).finish();
52
- const signature = await SelectedServiceSignature
53
- .sign(proto, privateKey);
54
- const request = {
55
- data,
56
- signature
57
- };
58
- return request;
59
- }
@@ -1,17 +0,0 @@
1
- import { utils } from 'ethers';
2
- export const B64_JSON_REPLACER = (key, value) => {
3
- if (value instanceof Uint8Array
4
- || (typeof value === 'object'
5
- && value
6
- && 'buffer' in value
7
- && value.buffer instanceof ArrayBuffer)) {
8
- return { type: 'uint8array', value: utils.base64.encode(value) };
9
- }
10
- return value;
11
- };
12
- export const B64_JSON_REVIVER = (key, value) => {
13
- if (value?.type === 'uint8array') {
14
- return utils.base64.decode(value.value);
15
- }
16
- return value;
17
- };