@reclaimprotocol/attestor-core 5.0.1-beta.13 → 5.0.1-beta.16

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 (134) hide show
  1. package/lib/external-rpc/index.js +17321 -3
  2. package/lib/index.d.ts +1 -0
  3. package/lib/index.js +15391 -11
  4. package/lib/scripts/build-browser-debug.d.ts +1 -0
  5. package/package.json +1 -1
  6. package/lib/avs/abis/avsDirectoryABI.js +0 -343
  7. package/lib/avs/abis/delegationABI.js +0 -4
  8. package/lib/avs/abis/registryABI.js +0 -728
  9. package/lib/avs/client/create-claim-on-avs.js +0 -168
  10. package/lib/avs/config.js +0 -26
  11. package/lib/avs/contracts/ReclaimServiceManager.js +0 -0
  12. package/lib/avs/contracts/common.js +0 -0
  13. package/lib/avs/contracts/factories/ReclaimServiceManager__factory.js +0 -1183
  14. package/lib/avs/contracts/factories/index.js +0 -4
  15. package/lib/avs/contracts/index.js +0 -6
  16. package/lib/avs/types/index.js +0 -0
  17. package/lib/avs/utils/contracts.js +0 -53
  18. package/lib/avs/utils/register.js +0 -74
  19. package/lib/avs/utils/tasks.js +0 -48
  20. package/lib/client/create-claim.js +0 -461
  21. package/lib/client/index.js +0 -3
  22. package/lib/client/tunnels/make-rpc-tcp-tunnel.js +0 -53
  23. package/lib/client/tunnels/make-rpc-tls-tunnel.js +0 -127
  24. package/lib/client/utils/attestor-pool.js +0 -24
  25. package/lib/client/utils/client-socket.js +0 -120
  26. package/lib/client/utils/message-handler.js +0 -97
  27. package/lib/config/index.js +0 -62
  28. package/lib/external-rpc/benchmark.js +0 -82
  29. package/lib/external-rpc/event-bus.js +0 -17
  30. package/lib/external-rpc/handle-incoming-msg.js +0 -241
  31. package/lib/external-rpc/jsc-polyfills/1.js +0 -80
  32. package/lib/external-rpc/jsc-polyfills/2.js +0 -15
  33. package/lib/external-rpc/jsc-polyfills/event.js +0 -19
  34. package/lib/external-rpc/jsc-polyfills/index.js +0 -2
  35. package/lib/external-rpc/jsc-polyfills/ws.js +0 -83
  36. package/lib/external-rpc/setup-browser.js +0 -33
  37. package/lib/external-rpc/setup-jsc.js +0 -22
  38. package/lib/external-rpc/types.js +0 -0
  39. package/lib/external-rpc/utils.js +0 -100
  40. package/lib/external-rpc/zk.js +0 -58
  41. package/lib/mechain/abis/governanceABI.js +0 -461
  42. package/lib/mechain/abis/taskABI.js +0 -512
  43. package/lib/mechain/client/create-claim-on-mechain.js +0 -33
  44. package/lib/mechain/client/index.js +0 -1
  45. package/lib/mechain/constants/index.js +0 -8
  46. package/lib/mechain/index.js +0 -2
  47. package/lib/mechain/types/index.js +0 -0
  48. package/lib/proto/api.js +0 -4250
  49. package/lib/proto/tee-bundle.js +0 -1296
  50. package/lib/providers/http/index.js +0 -640
  51. package/lib/providers/http/patch-parse5-tree.js +0 -34
  52. package/lib/providers/http/utils.js +0 -283
  53. package/lib/providers/index.js +0 -7
  54. package/lib/scripts/build-browser.js +0 -38
  55. package/lib/scripts/build-jsc.js +0 -47
  56. package/lib/scripts/build-lib.js +0 -47
  57. package/lib/scripts/check-avs-registration.js +0 -28
  58. package/lib/scripts/fallbacks/crypto.js +0 -4
  59. package/lib/scripts/fallbacks/empty.js +0 -4
  60. package/lib/scripts/fallbacks/re2.js +0 -7
  61. package/lib/scripts/fallbacks/snarkjs.js +0 -10
  62. package/lib/scripts/fallbacks/stwo.js +0 -159
  63. package/lib/scripts/generate-provider-types.js +0 -101
  64. package/lib/scripts/generate-receipt.js +0 -101
  65. package/lib/scripts/generate-toprf-keys.js +0 -24
  66. package/lib/scripts/jsc-cli-rpc.js +0 -35
  67. package/lib/scripts/register-avs-operator.js +0 -3
  68. package/lib/scripts/start-server.js +0 -11
  69. package/lib/scripts/update-avs-metadata.js +0 -20
  70. package/lib/scripts/utils.js +0 -10
  71. package/lib/scripts/whitelist-operator.js +0 -16
  72. package/lib/server/create-server.js +0 -105
  73. package/lib/server/handlers/claimTeeBundle.js +0 -232
  74. package/lib/server/handlers/claimTunnel.js +0 -80
  75. package/lib/server/handlers/completeClaimOnChain.js +0 -29
  76. package/lib/server/handlers/createClaimOnChain.js +0 -32
  77. package/lib/server/handlers/createTaskOnMechain.js +0 -57
  78. package/lib/server/handlers/createTunnel.js +0 -98
  79. package/lib/server/handlers/disconnectTunnel.js +0 -8
  80. package/lib/server/handlers/fetchCertificateBytes.js +0 -57
  81. package/lib/server/handlers/index.js +0 -25
  82. package/lib/server/handlers/init.js +0 -33
  83. package/lib/server/handlers/toprf.js +0 -19
  84. package/lib/server/index.js +0 -4
  85. package/lib/server/socket.js +0 -112
  86. package/lib/server/tunnels/make-tcp-tunnel.js +0 -202
  87. package/lib/server/utils/apm.js +0 -29
  88. package/lib/server/utils/assert-valid-claim-request.js +0 -354
  89. package/lib/server/utils/config-env.js +0 -4
  90. package/lib/server/utils/dns.js +0 -24
  91. package/lib/server/utils/gcp-attestation.js +0 -237
  92. package/lib/server/utils/generics.js +0 -45
  93. package/lib/server/utils/iso.js +0 -259
  94. package/lib/server/utils/keep-alive.js +0 -38
  95. package/lib/server/utils/nitro-attestation.js +0 -249
  96. package/lib/server/utils/oprf-raw.js +0 -61
  97. package/lib/server/utils/process-handshake.js +0 -233
  98. package/lib/server/utils/proxy-session.js +0 -6
  99. package/lib/server/utils/tee-oprf-mpc-verification.js +0 -86
  100. package/lib/server/utils/tee-oprf-verification.js +0 -151
  101. package/lib/server/utils/tee-transcript-reconstruction.js +0 -140
  102. package/lib/server/utils/tee-verification.js +0 -358
  103. package/lib/server/utils/validation.js +0 -45
  104. package/lib/types/bgp.js +0 -0
  105. package/lib/types/claims.js +0 -0
  106. package/lib/types/client.js +0 -0
  107. package/lib/types/general.js +0 -0
  108. package/lib/types/handlers.js +0 -0
  109. package/lib/types/index.js +0 -10
  110. package/lib/types/providers.gen.js +0 -16
  111. package/lib/types/providers.js +0 -0
  112. package/lib/types/rpc.js +0 -0
  113. package/lib/types/signatures.js +0 -0
  114. package/lib/types/tunnel.js +0 -0
  115. package/lib/types/zk.js +0 -0
  116. package/lib/utils/auth.js +0 -71
  117. package/lib/utils/b64-json.js +0 -17
  118. package/lib/utils/bgp-listener.js +0 -123
  119. package/lib/utils/claims.js +0 -89
  120. package/lib/utils/env.js +0 -19
  121. package/lib/utils/error.js +0 -54
  122. package/lib/utils/generics.js +0 -268
  123. package/lib/utils/http-parser.js +0 -201
  124. package/lib/utils/index.js +0 -13
  125. package/lib/utils/logger.js +0 -82
  126. package/lib/utils/prepare-packets.js +0 -69
  127. package/lib/utils/redactions.js +0 -135
  128. package/lib/utils/retries.js +0 -26
  129. package/lib/utils/signatures/eth.js +0 -31
  130. package/lib/utils/signatures/index.js +0 -12
  131. package/lib/utils/socket-base.js +0 -96
  132. package/lib/utils/tls.js +0 -58
  133. package/lib/utils/ws.js +0 -22
  134. package/lib/utils/zk.js +0 -625
@@ -1,249 +0,0 @@
1
- import { AsnParser } from "@peculiar/asn1-schema";
2
- import { SubjectPublicKeyInfo } from "@peculiar/asn1-x509";
3
- import { Crypto } from "@peculiar/webcrypto";
4
- import { X509Certificate, X509ChainBuilder } from "@peculiar/x509";
5
- import { sign } from "cose-js";
6
- async function getCborDecode() {
7
- const { decode } = await import("cbor-x");
8
- return decode;
9
- }
10
- const AWS_NITRO_ROOT_CERT = `-----BEGIN CERTIFICATE-----
11
- MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTEL
12
- MAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYD
13
- VQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4
14
- MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQL
15
- DANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEG
16
- BSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb
17
- 48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZE
18
- h8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkF
19
- R+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYC
20
- MQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPW
21
- rfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6N
22
- IwLz3/Y=
23
- -----END CERTIFICATE-----`;
24
- async function validateCertificateChain(targetCert, intermediateCerts, rootCert, crypto) {
25
- const errors = [];
26
- try {
27
- const rootSubject = rootCert.subject;
28
- const rootIssuer = rootCert.issuer;
29
- if (rootSubject !== rootIssuer) {
30
- errors.push("Root certificate is not self-signed");
31
- }
32
- try {
33
- const isRootValid = await rootCert.verify(void 0, crypto);
34
- if (!isRootValid) {
35
- errors.push("Root certificate signature verification failed");
36
- }
37
- } catch (error) {
38
- errors.push(`Root certificate verification failed: ${error.message}`);
39
- }
40
- const chainBuilder = new X509ChainBuilder({
41
- certificates: [rootCert, ...intermediateCerts]
42
- });
43
- let chain;
44
- try {
45
- chain = await chainBuilder.build(targetCert, crypto);
46
- } catch (error) {
47
- errors.push(`Certificate chain building failed: ${error.message}`);
48
- return { isValid: false, errors, chain: [] };
49
- }
50
- if (!chain || chain.length === 0) {
51
- errors.push("No valid certificate chain could be built");
52
- return { isValid: false, errors, chain: [] };
53
- }
54
- const now = /* @__PURE__ */ new Date();
55
- for (let i = 0; i < chain.length; i++) {
56
- const cert = chain[i];
57
- if (now < cert.notBefore) {
58
- errors.push(`Certificate ${i} (${cert.subject}) is not yet valid`);
59
- }
60
- if (now > cert.notAfter) {
61
- errors.push(`Certificate ${i} (${cert.subject}) has expired`);
62
- }
63
- if (i < chain.length - 1) {
64
- try {
65
- const issuer = chain[i + 1];
66
- const isValid = await cert.verify(issuer, crypto);
67
- if (!isValid) {
68
- errors.push(`Certificate ${i} signature verification failed`);
69
- }
70
- } catch (error) {
71
- errors.push(`Certificate ${i} verification failed: ${error.message}`);
72
- }
73
- }
74
- }
75
- return {
76
- isValid: errors.length === 0,
77
- errors,
78
- chain
79
- };
80
- } catch (error) {
81
- errors.push(`Certificate chain validation error: ${error.message}`);
82
- return { isValid: false, errors, chain: [] };
83
- }
84
- }
85
- function extractPublicKeyFromUserData(userDataBuffer) {
86
- try {
87
- const userDataString = userDataBuffer.toString("utf-8");
88
- const teeKMatch = userDataString.match(/^tee_k_public_key:(0x[0-9a-fA-F]{40})$/);
89
- const teeTMatch = userDataString.match(/^tee_t_public_key:(0x[0-9a-fA-F]{40})$/);
90
- if (teeKMatch) {
91
- return {
92
- teeType: "tee_k",
93
- ethAddress: teeKMatch[1],
94
- // Store the full ETH address with 0x prefix
95
- pcr0: ""
96
- };
97
- }
98
- if (teeTMatch) {
99
- return {
100
- teeType: "tee_t",
101
- ethAddress: teeTMatch[1],
102
- // Store the full ETH address with 0x prefix
103
- pcr0: ""
104
- };
105
- }
106
- return null;
107
- } catch {
108
- return null;
109
- }
110
- }
111
- async function validateNitroAttestationAndExtractKey(attestationBytes) {
112
- const errors = [];
113
- const warnings = [];
114
- try {
115
- const crypto = new Crypto();
116
- const decode = await getCborDecode();
117
- let decoded;
118
- try {
119
- decoded = decode(Buffer.from(attestationBytes));
120
- } catch (error) {
121
- errors.push(`CBOR decoding failed: ${error.message}`);
122
- return { isValid: false, errors, warnings, pcr0: "" };
123
- }
124
- if (!Array.isArray(decoded) || decoded.length < 4) {
125
- errors.push("Invalid COSE_Sign1 structure: expected array with 4 elements");
126
- return { isValid: false, errors, warnings, pcr0: "" };
127
- }
128
- const [, , payload] = decoded;
129
- if (!payload || payload.length === 0) {
130
- errors.push("Empty or missing payload in COSE_Sign1 structure");
131
- return { isValid: false, errors, warnings, pcr0: "" };
132
- }
133
- let doc;
134
- try {
135
- doc = decode(payload);
136
- } catch (error) {
137
- errors.push(`Payload decoding failed: ${error.message}`);
138
- return { isValid: false, errors, warnings, pcr0: "" };
139
- }
140
- if (doc.module_id.length === 0) {
141
- errors.push("Missing or invalid module_id");
142
- }
143
- if (doc.digest.length === 0) {
144
- errors.push("Missing or invalid digest");
145
- }
146
- if (!doc.pcrs || typeof doc.pcrs !== "object") {
147
- errors.push("Missing or invalid pcrs");
148
- }
149
- if (!Buffer.isBuffer(doc.certificate) || doc.certificate.length === 0) {
150
- errors.push("Missing or invalid certificate");
151
- }
152
- if (!Array.isArray(doc.cabundle) || doc.cabundle.length === 0) {
153
- errors.push("Missing or invalid cabundle");
154
- }
155
- if (errors.length > 0) {
156
- return { isValid: false, errors, warnings, pcr0: "" };
157
- }
158
- const pcr0 = doc.pcrs[0].toString("hex");
159
- const intermediateCerts = [];
160
- for (let i = 0; i < doc.cabundle.length; i++) {
161
- try {
162
- const cert = new X509Certificate(doc.cabundle[i].toString("base64"));
163
- intermediateCerts.push(cert);
164
- } catch (error) {
165
- errors.push(`Failed to parse cabundle certificate ${i}: ${error.message}`);
166
- }
167
- }
168
- let targetCert;
169
- try {
170
- targetCert = new X509Certificate(doc.certificate.toString("base64"));
171
- } catch (error) {
172
- errors.push(`Failed to parse target certificate: ${error.message}`);
173
- return { isValid: false, errors, warnings, pcr0: "" };
174
- }
175
- let rootCert;
176
- try {
177
- rootCert = new X509Certificate(AWS_NITRO_ROOT_CERT);
178
- } catch (error) {
179
- errors.push(`Failed to parse AWS Nitro root certificate: ${error.message}`);
180
- return { isValid: false, errors, warnings, pcr0: "" };
181
- }
182
- const chainResult = await validateCertificateChain(targetCert, intermediateCerts, rootCert, crypto);
183
- if (!chainResult.isValid) {
184
- errors.push(...chainResult.errors);
185
- return { isValid: false, errors, warnings, pcr0: "" };
186
- }
187
- let publicKeyRaw;
188
- try {
189
- publicKeyRaw = Buffer.from(targetCert.publicKey.rawData);
190
- } catch (error) {
191
- errors.push(`Failed to extract public key: ${error.message}`);
192
- return { isValid: false, errors, warnings, pcr0: "" };
193
- }
194
- if (publicKeyRaw.length !== 120 || publicKeyRaw[0] !== 48) {
195
- errors.push(`Invalid public key format: expected 120-byte DER-encoded key, got ${publicKeyRaw.length} bytes`);
196
- return { isValid: false, errors, warnings, pcr0: "" };
197
- }
198
- let spki;
199
- try {
200
- spki = AsnParser.parse(publicKeyRaw, SubjectPublicKeyInfo);
201
- } catch (error) {
202
- errors.push(`Failed to parse SubjectPublicKeyInfo: ${error.message}`);
203
- return { isValid: false, errors, warnings, pcr0: "" };
204
- }
205
- const ecPoint = Buffer.from(spki.subjectPublicKey);
206
- if (ecPoint.length !== 97 || ecPoint[0] !== 4) {
207
- errors.push("Invalid EC point: expected 97-byte uncompressed P-384 key");
208
- return { isValid: false, errors, warnings, pcr0: "" };
209
- }
210
- const x = ecPoint.subarray(1, 49);
211
- const y = ecPoint.subarray(49, 97);
212
- try {
213
- const verifier = {
214
- key: {
215
- x,
216
- y
217
- }
218
- };
219
- const options = { defaultType: 18 };
220
- await sign.verify(Buffer.from(attestationBytes), verifier, options);
221
- } catch (error) {
222
- errors.push(`COSE signature verification failed: ${error.message}`);
223
- return { isValid: false, errors, warnings, pcr0: "" };
224
- }
225
- let userDataType;
226
- let ethAddress;
227
- if (doc.user_data) {
228
- const keyInfo = extractPublicKeyFromUserData(doc.user_data);
229
- if (keyInfo) {
230
- userDataType = keyInfo.teeType;
231
- ethAddress = keyInfo.ethAddress;
232
- }
233
- }
234
- return {
235
- isValid: errors.length === 0,
236
- errors,
237
- warnings,
238
- userDataType,
239
- ethAddress,
240
- pcr0
241
- };
242
- } catch (error) {
243
- errors.push(`Unexpected error during validation: ${error.message}`);
244
- return { isValid: false, errors, warnings, pcr0: "" };
245
- }
246
- }
247
- export {
248
- validateNitroAttestationAndExtractKey
249
- };
@@ -1,61 +0,0 @@
1
- import { getBytes } from "ethers";
2
- import { TOPRF_DOMAIN_SEPARATOR } from "#src/config/index.js";
3
- import { getEnvVariable } from "#src/utils/env.js";
4
- import { makeDefaultOPRFOperator } from "#src/utils/zk.js";
5
- async function computeOPRFRaw(plaintext, markers, logger) {
6
- if (!markers.length) {
7
- return [];
8
- }
9
- const PRIVATE_KEY_STR = getEnvVariable("TOPRF_SHARE_PRIVATE_KEY");
10
- const PUBLIC_KEY_STR = getEnvVariable("TOPRF_SHARE_PUBLIC_KEY");
11
- if (!PRIVATE_KEY_STR || !PUBLIC_KEY_STR) {
12
- throw new Error("TOPRF keys not configured. Cannot compute oprf-raw.");
13
- }
14
- const privateKey = getBytes(PRIVATE_KEY_STR);
15
- const publicKey = getBytes(PUBLIC_KEY_STR);
16
- const operator = makeDefaultOPRFOperator("chacha20", "gnark", logger);
17
- const results = [];
18
- for (const marker of markers) {
19
- const { dataLocation } = marker;
20
- if (!dataLocation) {
21
- logger.warn("oprf-raw marker missing dataLocation, skipping");
22
- continue;
23
- }
24
- const { fromIndex, length } = dataLocation;
25
- const endIndex = fromIndex + length;
26
- if (endIndex > plaintext.length) {
27
- throw new Error(
28
- `oprf-raw marker out of bounds: fromIndex=${fromIndex}, length=${length}, plaintextLength=${plaintext.length}`
29
- );
30
- }
31
- const data = plaintext.slice(fromIndex, endIndex);
32
- const request = await operator.generateOPRFRequestData(
33
- data,
34
- TOPRF_DOMAIN_SEPARATOR,
35
- logger
36
- );
37
- const response = await operator.evaluateOPRF(
38
- privateKey,
39
- request.maskedData,
40
- logger
41
- );
42
- const nullifier = await operator.finaliseOPRF(
43
- publicKey,
44
- request,
45
- [{ ...response, publicKeyShare: publicKey }],
46
- logger
47
- );
48
- results.push({
49
- dataLocation: { fromIndex, length },
50
- nullifier
51
- });
52
- logger.debug(
53
- { fromIndex, length, nullifierHex: Buffer.from(nullifier).toString("hex").slice(0, 16) + "..." },
54
- "computed oprf-raw nullifier"
55
- );
56
- }
57
- return results;
58
- }
59
- export {
60
- computeOPRFRaw
61
- };
@@ -1,233 +0,0 @@
1
- import {
2
- concatenateUint8Arrays,
3
- getSignatureDataTls12,
4
- getSignatureDataTls13,
5
- PACKET_TYPE,
6
- parseCertificates,
7
- parseClientHello,
8
- parseServerCertificateVerify,
9
- parseServerHello,
10
- processServerKeyShare,
11
- SUPPORTED_RECORD_TYPE_MAP,
12
- uint8ArrayToDataView,
13
- verifyCertificateChain,
14
- verifyCertificateSignature
15
- } from "@reclaimprotocol/tls";
16
- import { TranscriptMessageSenderType } from "#src/proto/api.js";
17
- import { decryptDirect } from "#src/utils/index.js";
18
- const RECORD_LENGTH_BYTES = 3;
19
- async function processHandshake(receipt, logger) {
20
- const certificates = [];
21
- const handshakeRawMessages = [];
22
- let currentPacketIdx = 0;
23
- let cipherSuite = void 0;
24
- let tlsVersion = void 0;
25
- let serverRandom = void 0;
26
- let clientRandom = void 0;
27
- let serverFinishedIdx = -1;
28
- let clientFinishedIdx = -1;
29
- let certVerified = false;
30
- let certVerifyHandled = false;
31
- let hostname = void 0;
32
- let clientChangeCipherSpecMsgIdx = -1;
33
- let serverChangeCipherSpecMsgIdx = -1;
34
- let incompletePkt = void 0;
35
- while (serverFinishedIdx < 0 || clientFinishedIdx < 0) {
36
- const packetIdx = currentPacketIdx++;
37
- if (packetIdx >= receipt.length) {
38
- throw new Error(
39
- "Receipt over but server finish: " + serverFinishedIdx + ", client finish: " + clientFinishedIdx
40
- );
41
- }
42
- const { message, reveal, sender } = receipt[packetIdx];
43
- if (message[0] === PACKET_TYPE["CHANGE_CIPHER_SPEC"]) {
44
- if (sender === TranscriptMessageSenderType.TRANSCRIPT_MESSAGE_SENDER_TYPE_CLIENT) {
45
- clientChangeCipherSpecMsgIdx = packetIdx;
46
- logger.trace("found client change cipher spec message");
47
- } else {
48
- serverChangeCipherSpecMsgIdx = packetIdx;
49
- logger.trace("found server change cipher spec message");
50
- }
51
- continue;
52
- }
53
- let plaintext = getWithoutHeader(message);
54
- if (!plaintext) {
55
- throw new Error("incomplete TLS record encountered");
56
- }
57
- if (
58
- // decrypt if wrapped record or after change cipher spec message,
59
- // after which records are encrypted
60
- message[0] === PACKET_TYPE["WRAPPED_RECORD"] || serverChangeCipherSpecMsgIdx > 0 && sender === TranscriptMessageSenderType.TRANSCRIPT_MESSAGE_SENDER_TYPE_SERVER || clientChangeCipherSpecMsgIdx > 0 && sender === TranscriptMessageSenderType.TRANSCRIPT_MESSAGE_SENDER_TYPE_CLIENT
61
- ) {
62
- if (!tlsVersion || !cipherSuite) {
63
- throw new Error("Could not find cipherSuite to use & got enc record");
64
- }
65
- if (!reveal?.directReveal?.key) {
66
- throw new Error(
67
- "no direct reveal for handshake packet: " + packetIdx
68
- );
69
- }
70
- const recordHeader = message.slice(0, 5);
71
- ({ plaintext } = await decryptDirect(
72
- reveal?.directReveal,
73
- cipherSuite,
74
- recordHeader,
75
- tlsVersion,
76
- plaintext
77
- ));
78
- if (tlsVersion === "TLS1_3") {
79
- plaintext = plaintext.slice(0, -1);
80
- }
81
- }
82
- if (incompletePkt) {
83
- const incSender = receipt[incompletePkt.packetIdx].sender;
84
- if (incSender !== sender) {
85
- throw new Error(
86
- "Missing follow up to incomplete packet at idx: " + incompletePkt.packetIdx
87
- );
88
- }
89
- plaintext = concatenateUint8Arrays([
90
- incompletePkt.remainingBytes,
91
- plaintext
92
- ]);
93
- incompletePkt = void 0;
94
- }
95
- const handshakeMessages = [];
96
- for (let offset = 0; offset < plaintext.length; ) {
97
- const type = plaintext[offset];
98
- const content = readWithLength(plaintext.slice(offset + 1), RECORD_LENGTH_BYTES);
99
- if (!content) {
100
- incompletePkt = {
101
- remainingBytes: plaintext.slice(offset),
102
- packetIdx
103
- };
104
- break;
105
- }
106
- handshakeMessages.push({
107
- type,
108
- content,
109
- contentWithHeader: plaintext.slice(
110
- offset,
111
- offset + 1 + RECORD_LENGTH_BYTES + content.length
112
- ),
113
- packetIdx
114
- });
115
- offset += 1 + RECORD_LENGTH_BYTES + content.length;
116
- }
117
- for (const msg of handshakeMessages) {
118
- await processHandshakeMessage(msg);
119
- handshakeRawMessages.push(msg.contentWithHeader);
120
- }
121
- }
122
- if (!certVerified) {
123
- throw new Error("No provider certificates received");
124
- }
125
- if (tlsVersion === "TLS1_3" && serverFinishedIdx < 0) {
126
- throw new Error("server finished message not found");
127
- }
128
- if (tlsVersion === "TLS1_3" && !certVerifyHandled) {
129
- throw new Error("TLS1.3 cert verify packet not received");
130
- }
131
- if (tlsVersion === "TLS1_2" && (serverChangeCipherSpecMsgIdx < 0 || clientChangeCipherSpecMsgIdx < 0)) {
132
- throw new Error("change cipher spec message not found");
133
- }
134
- const nextMsgIndex = Math.max(serverFinishedIdx, clientFinishedIdx) + 1;
135
- return {
136
- tlsVersion,
137
- cipherSuite,
138
- hostname,
139
- nextMsgIndex
140
- };
141
- async function processHandshakeMessage({ type, content, contentWithHeader, packetIdx }) {
142
- switch (type) {
143
- case SUPPORTED_RECORD_TYPE_MAP.CLIENT_HELLO:
144
- const clientHello = parseClientHello(contentWithHeader);
145
- clientRandom = clientHello.serverRandom;
146
- const { SERVER_NAME: sni } = clientHello.extensions;
147
- hostname = sni?.serverName;
148
- if (!hostname) {
149
- throw new Error("client hello has no SNI");
150
- }
151
- break;
152
- case SUPPORTED_RECORD_TYPE_MAP.SERVER_HELLO:
153
- const serverHello = await parseServerHello(content);
154
- cipherSuite = serverHello.cipherSuite;
155
- tlsVersion = serverHello.serverTlsVersion;
156
- serverRandom = serverHello.serverRandom;
157
- logger.info(
158
- { serverTLSVersion: tlsVersion, cipherSuite },
159
- "extracted server hello params"
160
- );
161
- break;
162
- case SUPPORTED_RECORD_TYPE_MAP.CERTIFICATE:
163
- const parseResult = parseCertificates(content, { version: tlsVersion });
164
- certificates.push(...parseResult.certificates);
165
- await verifyCertificateChain(certificates, hostname, logger);
166
- logger.info({ hostname }, "verified provider certificate chain");
167
- certVerified = true;
168
- break;
169
- case SUPPORTED_RECORD_TYPE_MAP.CERTIFICATE_VERIFY:
170
- const signature = parseServerCertificateVerify(content);
171
- if (!certificates?.length) {
172
- throw new Error("No provider certificates received");
173
- }
174
- const signatureData = await getSignatureDataTls13(
175
- handshakeRawMessages,
176
- cipherSuite
177
- );
178
- await verifyCertificateSignature({
179
- ...signature,
180
- publicKey: certificates[0].getPublicKey(),
181
- signatureData
182
- });
183
- certVerifyHandled = true;
184
- break;
185
- case SUPPORTED_RECORD_TYPE_MAP.SERVER_KEY_SHARE:
186
- if (!certificates?.length) {
187
- throw new Error("No provider certificates received");
188
- }
189
- const keyShare = await processServerKeyShare(content);
190
- const signatureData12 = await getSignatureDataTls12(
191
- {
192
- clientRandom,
193
- serverRandom,
194
- curveType: keyShare.publicKeyType,
195
- publicKey: keyShare.publicKey
196
- }
197
- );
198
- await verifyCertificateSignature({
199
- signature: keyShare.signatureBytes,
200
- algorithm: keyShare.signatureAlgorithm,
201
- publicKey: certificates[0].getPublicKey(),
202
- signatureData: signatureData12,
203
- publicKeyType: keyShare.publicKeyType
204
- });
205
- await verifyCertificateChain(certificates, hostname, logger);
206
- logger.info({ hostname }, "verified provider certificate chain");
207
- certVerified = true;
208
- break;
209
- case SUPPORTED_RECORD_TYPE_MAP.FINISHED:
210
- const packet = receipt[packetIdx];
211
- if (packet.sender === TranscriptMessageSenderType.TRANSCRIPT_MESSAGE_SENDER_TYPE_CLIENT) {
212
- clientFinishedIdx = packetIdx;
213
- } else {
214
- serverFinishedIdx = packetIdx;
215
- }
216
- break;
217
- }
218
- }
219
- }
220
- function getWithoutHeader(message) {
221
- return readWithLength(message.slice(3), 2);
222
- }
223
- function readWithLength(data, lengthBytes = 2) {
224
- const dataView = uint8ArrayToDataView(data);
225
- const length = lengthBytes === 1 ? dataView.getUint8(0) : dataView.getUint16(lengthBytes === 3 ? 1 : 0);
226
- if (data.length < lengthBytes + length) {
227
- return void 0;
228
- }
229
- return data.slice(lengthBytes, lengthBytes + length);
230
- }
231
- export {
232
- processHandshake
233
- };
@@ -1,6 +0,0 @@
1
- function isValidProxySessionId(sessionId) {
2
- return typeof sessionId === "string" && sessionId.length >= 8 && sessionId.length < 15 && /^[a-z0-9]+$/.test(sessionId);
3
- }
4
- export {
5
- isValidProxySessionId
6
- };
@@ -1,86 +0,0 @@
1
- import { AttestorError } from "#src/utils/error.js";
2
- function verifyOprfMpcOutputs(kPayload, tPayload, logger) {
3
- const kOutputs = kPayload.oprfOutputs || [];
4
- const tOutputs = tPayload.oprfOutputs || [];
5
- if (kOutputs.length === 0 && tOutputs.length === 0) {
6
- logger.debug("No OPRF MPC outputs to verify");
7
- return [];
8
- }
9
- if (kOutputs.length !== tOutputs.length) {
10
- throw new AttestorError(
11
- "ERROR_INVALID_CLAIM",
12
- `OPRF MPC count mismatch: TEE_K has ${kOutputs.length}, TEE_T has ${tOutputs.length}`
13
- );
14
- }
15
- logger.info(`Verifying ${kOutputs.length} OPRF MPC outputs`);
16
- const results = [];
17
- for (const [i, kOut] of kOutputs.entries()) {
18
- const tOut = tOutputs[i];
19
- if (kOut.tlsStart < 0 || tOut.tlsStart < 0) {
20
- throw new AttestorError(
21
- "ERROR_INVALID_CLAIM",
22
- `OPRF MPC invalid position at index ${i}: negative start position`
23
- );
24
- }
25
- if (kOut.tlsLength <= 0 || kOut.tlsLength > 64 || tOut.tlsLength <= 0 || tOut.tlsLength > 64) {
26
- throw new AttestorError(
27
- "ERROR_INVALID_CLAIM",
28
- `OPRF MPC invalid length at index ${i}: must be 1-64 bytes (TEE_K: ${kOut.tlsLength}, TEE_T: ${tOut.tlsLength})`
29
- );
30
- }
31
- if (kOut.hashOutput.length !== 32 || tOut.hashOutput.length !== 32) {
32
- throw new AttestorError(
33
- "ERROR_INVALID_CLAIM",
34
- `OPRF MPC invalid hash size at index ${i}: expected 32 bytes (TEE_K: ${kOut.hashOutput.length}, TEE_T: ${tOut.hashOutput.length})`
35
- );
36
- }
37
- if (kOut.tlsStart !== tOut.tlsStart || kOut.tlsLength !== tOut.tlsLength) {
38
- throw new AttestorError(
39
- "ERROR_INVALID_CLAIM",
40
- `OPRF MPC position mismatch at index ${i}: TEE_K [${kOut.tlsStart}:${kOut.tlsStart + kOut.tlsLength}] vs TEE_T [${tOut.tlsStart}:${tOut.tlsStart + tOut.tlsLength}]`
41
- );
42
- }
43
- if (!buffersEqual(kOut.hashOutput, tOut.hashOutput)) {
44
- throw new AttestorError(
45
- "ERROR_INVALID_CLAIM",
46
- `OPRF MPC hash mismatch at index ${i}: outputs differ between TEE_K and TEE_T`
47
- );
48
- }
49
- const hashOutputHex = Buffer.from(kOut.hashOutput).toString("hex");
50
- const hashOutputBase64 = Buffer.from(kOut.hashOutput).toString("base64");
51
- logger.info(
52
- {
53
- index: i,
54
- position: kOut.tlsStart,
55
- length: kOut.tlsLength,
56
- hashOutputLen: kOut.hashOutput.length,
57
- hashOutputHex: hashOutputHex.substring(0, 32) + "...",
58
- hashOutputBase64Preview: hashOutputBase64.substring(0, 20) + "..."
59
- },
60
- "OPRF MPC output verified"
61
- );
62
- results.push({
63
- position: kOut.tlsStart,
64
- length: kOut.tlsLength,
65
- output: new Uint8Array(kOut.hashOutput),
66
- // Use SHA256(CMAC) as the replacement value
67
- isMPC: true
68
- });
69
- }
70
- logger.info(`Successfully verified ${results.length} OPRF MPC outputs`);
71
- return results;
72
- }
73
- function buffersEqual(a, b) {
74
- if (a.length !== b.length) {
75
- return false;
76
- }
77
- for (const [i, element] of a.entries()) {
78
- if (element !== b[i]) {
79
- return false;
80
- }
81
- }
82
- return true;
83
- }
84
- export {
85
- verifyOprfMpcOutputs
86
- };