@reclaimprotocol/attestor-core 5.1.1 → 5.1.4

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.
@@ -8807,13 +8807,14 @@ function parseHttpResponse(buff) {
8807
8807
  var RE2;
8808
8808
  import("re2").then((m) => {
8809
8809
  RE2 = m.default;
8810
- }).catch(() => {
8810
+ }).catch((err) => {
8811
+ logger.warn({ err }, "Failed to load RE2; falling back to native RegExp");
8811
8812
  });
8812
8813
  function makeRegex(str) {
8813
8814
  if (RE2) {
8814
8815
  return RE2(str, "sgiu");
8815
8816
  }
8816
- return new RegExp(str, "sgiu");
8817
+ return new RegExp(str, "sgi");
8817
8818
  }
8818
8819
  var TEMPLATE_START_CHARCODE = "{".charCodeAt(0);
8819
8820
  var TEMPLATE_END_CHARCODE = "}".charCodeAt(0);
@@ -9038,6 +9039,9 @@ var HTTP_PROVIDER = {
9038
9039
  if (res.headerIndices["date"]) {
9039
9040
  reveals.push(res.headerIndices["date"]);
9040
9041
  }
9042
+ if (res.headerIndices["content-type"]) {
9043
+ reveals.push(res.headerIndices["content-type"]);
9044
+ }
9041
9045
  if (revealFraming && res.headerIndices["transfer-encoding"]) {
9042
9046
  reveals.push(res.headerIndices["transfer-encoding"]);
9043
9047
  }
@@ -9129,36 +9133,53 @@ var HTTP_PROVIDER = {
9129
9133
  const firstRealIdx = allServerBlocks.findIndex((b) => !b.every((x) => x === REDACTION_CHAR_CODE2));
9130
9134
  const serverBlocks = firstRealIdx === -1 ? [] : allServerBlocks.slice(firstRealIdx);
9131
9135
  const response = concatArrays(...serverBlocks);
9132
- let res;
9133
- res = uint8ArrayToStr(response);
9136
+ let bodyStart;
9137
+ if (shouldRevealCrlf(ctx)) {
9138
+ const responseAfterStatus = response.slice(OK_HTTP_HEADER.length);
9139
+ const separatorIdx = findIndexInUint8Array(
9140
+ responseAfterStatus,
9141
+ strToUint8Array("\r\n\r\n")
9142
+ );
9143
+ if (separatorIdx === -1) {
9144
+ throw new Error("Response body start not found");
9145
+ }
9146
+ bodyStart = OK_HTTP_HEADER.length + separatorIdx + 4;
9147
+ } else {
9148
+ bodyStart = OK_HTTP_HEADER.length;
9149
+ }
9150
+ const headersText = uint8ArrayToStr(response.slice(0, bodyStart));
9134
9151
  const okRegex = makeRegex("^HTTP\\/1.1 2\\d{2}");
9135
- const matchRes = okRegex.exec(res);
9152
+ const matchRes = okRegex.exec(headersText);
9136
9153
  if (!matchRes) {
9137
9154
  const statusRegex = makeRegex("^HTTP\\/1.1 (\\d{3})");
9138
- const matchRes2 = statusRegex.exec(res);
9155
+ const matchRes2 = statusRegex.exec(headersText);
9139
9156
  if (matchRes2 && matchRes2.length > 1) {
9140
9157
  throw new Error(`Provider returned error ${matchRes2[1]}`);
9141
9158
  }
9142
- let lineEnd = res.indexOf("*");
9159
+ let lineEnd = headersText.indexOf("*");
9143
9160
  if (lineEnd === -1) {
9144
- lineEnd = res.indexOf("\n");
9161
+ lineEnd = headersText.indexOf("\n");
9145
9162
  }
9146
9163
  if (lineEnd === -1) {
9147
9164
  lineEnd = OK_HTTP_HEADER.length;
9148
9165
  }
9149
9166
  throw new Error(
9150
- `Response did not start with "HTTP/1.1 2XX" got "${res.slice(0, lineEnd)}"`
9167
+ `Response did not start with "HTTP/1.1 2XX" got "${headersText.slice(0, lineEnd)}"`
9151
9168
  );
9152
9169
  }
9153
- let bodyStart;
9154
- if (shouldRevealCrlf(ctx)) {
9155
- bodyStart = res.indexOf("\r\n\r\n", OK_HTTP_HEADER.length) + 4;
9156
- if (bodyStart < 4) {
9157
- throw new Error("Response body start not found");
9170
+ const paramBody = params.body instanceof Uint8Array ? params.body : strToUint8Array(params.body || "");
9171
+ if (paramBody.length > 0 && !matchRedactedStrings(paramBody, req.body)) {
9172
+ throw new Error("request body mismatch");
9173
+ }
9174
+ let body = response.slice(bodyStart);
9175
+ if (shouldRevealChunkFraming(clientVersion)) {
9176
+ if (/transfer-encoding:\s*chunked/i.test(headersText)) {
9177
+ body = dechunkResponseBody(body);
9158
9178
  }
9159
- } else {
9160
- bodyStart = OK_HTTP_HEADER.length;
9161
9179
  }
9180
+ const charset = shouldRevealCrlf(ctx) ? getResponseBodyCharset(headersText) : void 0;
9181
+ const bodyText = decodeResponseBody(body, charset);
9182
+ let res = headersText + bodyText;
9162
9183
  const dateHeader = makeRegex(dateHeaderRegex).exec(res);
9163
9184
  if (dateHeader && dateHeader.length > 1) {
9164
9185
  const serverDate = new Date(dateHeader[1]);
@@ -9166,14 +9187,7 @@ var HTTP_PROVIDER = {
9166
9187
  logger2.info({ dateHeader: dateHeader[0], current: Date.now() }, "date header is off");
9167
9188
  }
9168
9189
  }
9169
- const paramBody = params.body instanceof Uint8Array ? params.body : strToUint8Array(params.body || "");
9170
- if (paramBody.length > 0 && !matchRedactedStrings(paramBody, req.body)) {
9171
- throw new Error("request body mismatch");
9172
- }
9173
- if (shouldRevealChunkFraming(clientVersion)) {
9174
- const headersStr = res.slice(0, bodyStart);
9175
- res = /transfer-encoding:\s*chunked/i.test(headersStr) ? headersStr + dechunkResponseBody(res.slice(bodyStart)) : res;
9176
- } else if (!secretParams) {
9190
+ if (!shouldRevealChunkFraming(clientVersion) && !secretParams) {
9177
9191
  res = res.slice(bodyStart).replace(/\*{3,}/g, "");
9178
9192
  }
9179
9193
  for (const { type, value, invert } of params.responseMatches || []) {
@@ -9264,12 +9278,35 @@ function shouldRevealCrlf({ version }) {
9264
9278
  function shouldRevealChunkFraming(version) {
9265
9279
  return version >= AttestorVersion.ATTESTOR_VERSION_3_2_0;
9266
9280
  }
9281
+ function getResponseBodyCharset(headers) {
9282
+ const contentType = /(?:^|[\r\n*])content-type\s*:\s*([^*\r\n]*)/i.exec(headers)?.[1];
9283
+ if (typeof contentType === "undefined") {
9284
+ return void 0;
9285
+ }
9286
+ const charsetMatch = /(?:^|;)\s*charset\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^;\s]*))/i.exec(contentType);
9287
+ if (!charsetMatch) {
9288
+ return void 0;
9289
+ }
9290
+ const charset = charsetMatch[1]?.replace(/\\(.)/g, "$1") ?? charsetMatch[2];
9291
+ return charset.trim() || void 0;
9292
+ }
9293
+ function decodeResponseBody(body, charset) {
9294
+ try {
9295
+ return new TextDecoder(charset ?? "utf-8").decode(body);
9296
+ } catch (error) {
9297
+ if (charset) {
9298
+ throw new Error(`Unsupported response charset "${charset}"`, { cause: error });
9299
+ }
9300
+ throw error;
9301
+ }
9302
+ }
9267
9303
  function dechunkResponseBody(body) {
9268
9304
  const parser = makeHttpResponseParser();
9269
- parser.onChunk(
9270
- strToUint8Array("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n" + body)
9271
- );
9272
- return uint8ArrayToStr(parser.res.body ?? new Uint8Array());
9305
+ parser.onChunk(concatenateUint8Arrays7([
9306
+ strToUint8Array("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"),
9307
+ body
9308
+ ]));
9309
+ return parser.res.body ?? new Uint8Array();
9273
9310
  }
9274
9311
  function getHostPort(params, secretParams) {
9275
9312
  const { host } = new URL(getURL(params, secretParams));
@@ -9955,6 +9992,7 @@ async function _createClaimOnAttestor({
9955
9992
  block,
9956
9993
  redactedPlaintext,
9957
9994
  overshotToprfFromPrevBlock,
9995
+ overshotOprfRawFromPrevBlock,
9958
9996
  toprfs,
9959
9997
  oprfRawMarkers
9960
9998
  } = reveal;
@@ -9963,7 +10001,8 @@ async function _createClaimOnAttestor({
9963
10001
  redactedPlaintext,
9964
10002
  toprfs,
9965
10003
  oprfRawMarkers,
9966
- overshotToprfFromPrevBlock
10004
+ overshotToprfFromPrevBlock,
10005
+ overshotOprfRawFromPrevBlock
9967
10006
  });
9968
10007
  revealedPackets.push(
9969
10008
  { sender: "server", message: redactedPlaintext }
package/lib/index.js CHANGED
@@ -7124,13 +7124,14 @@ function parseHttpResponse(buff) {
7124
7124
  var RE2;
7125
7125
  import("re2").then((m) => {
7126
7126
  RE2 = m.default;
7127
- }).catch(() => {
7127
+ }).catch((err) => {
7128
+ logger.warn({ err }, "Failed to load RE2; falling back to native RegExp");
7128
7129
  });
7129
7130
  function makeRegex(str) {
7130
7131
  if (RE2) {
7131
7132
  return RE2(str, "sgiu");
7132
7133
  }
7133
- return new RegExp(str, "sgiu");
7134
+ return new RegExp(str, "sgi");
7134
7135
  }
7135
7136
  var TEMPLATE_START_CHARCODE = "{".charCodeAt(0);
7136
7137
  var TEMPLATE_END_CHARCODE = "}".charCodeAt(0);
@@ -7336,6 +7337,9 @@ var HTTP_PROVIDER = {
7336
7337
  if (res.headerIndices["date"]) {
7337
7338
  reveals.push(res.headerIndices["date"]);
7338
7339
  }
7340
+ if (res.headerIndices["content-type"]) {
7341
+ reveals.push(res.headerIndices["content-type"]);
7342
+ }
7339
7343
  if (revealFraming && res.headerIndices["transfer-encoding"]) {
7340
7344
  reveals.push(res.headerIndices["transfer-encoding"]);
7341
7345
  }
@@ -7427,36 +7431,53 @@ var HTTP_PROVIDER = {
7427
7431
  const firstRealIdx = allServerBlocks.findIndex((b) => !b.every((x) => x === REDACTION_CHAR_CODE2));
7428
7432
  const serverBlocks = firstRealIdx === -1 ? [] : allServerBlocks.slice(firstRealIdx);
7429
7433
  const response = concatArrays(...serverBlocks);
7430
- let res;
7431
- res = uint8ArrayToStr(response);
7434
+ let bodyStart;
7435
+ if (shouldRevealCrlf(ctx)) {
7436
+ const responseAfterStatus = response.slice(OK_HTTP_HEADER.length);
7437
+ const separatorIdx = findIndexInUint8Array(
7438
+ responseAfterStatus,
7439
+ strToUint8Array("\r\n\r\n")
7440
+ );
7441
+ if (separatorIdx === -1) {
7442
+ throw new Error("Response body start not found");
7443
+ }
7444
+ bodyStart = OK_HTTP_HEADER.length + separatorIdx + 4;
7445
+ } else {
7446
+ bodyStart = OK_HTTP_HEADER.length;
7447
+ }
7448
+ const headersText = uint8ArrayToStr(response.slice(0, bodyStart));
7432
7449
  const okRegex = makeRegex("^HTTP\\/1.1 2\\d{2}");
7433
- const matchRes = okRegex.exec(res);
7450
+ const matchRes = okRegex.exec(headersText);
7434
7451
  if (!matchRes) {
7435
7452
  const statusRegex = makeRegex("^HTTP\\/1.1 (\\d{3})");
7436
- const matchRes2 = statusRegex.exec(res);
7453
+ const matchRes2 = statusRegex.exec(headersText);
7437
7454
  if (matchRes2 && matchRes2.length > 1) {
7438
7455
  throw new Error(`Provider returned error ${matchRes2[1]}`);
7439
7456
  }
7440
- let lineEnd = res.indexOf("*");
7457
+ let lineEnd = headersText.indexOf("*");
7441
7458
  if (lineEnd === -1) {
7442
- lineEnd = res.indexOf("\n");
7459
+ lineEnd = headersText.indexOf("\n");
7443
7460
  }
7444
7461
  if (lineEnd === -1) {
7445
7462
  lineEnd = OK_HTTP_HEADER.length;
7446
7463
  }
7447
7464
  throw new Error(
7448
- `Response did not start with "HTTP/1.1 2XX" got "${res.slice(0, lineEnd)}"`
7465
+ `Response did not start with "HTTP/1.1 2XX" got "${headersText.slice(0, lineEnd)}"`
7449
7466
  );
7450
7467
  }
7451
- let bodyStart;
7452
- if (shouldRevealCrlf(ctx)) {
7453
- bodyStart = res.indexOf("\r\n\r\n", OK_HTTP_HEADER.length) + 4;
7454
- if (bodyStart < 4) {
7455
- throw new Error("Response body start not found");
7468
+ const paramBody = params.body instanceof Uint8Array ? params.body : strToUint8Array(params.body || "");
7469
+ if (paramBody.length > 0 && !matchRedactedStrings(paramBody, req.body)) {
7470
+ throw new Error("request body mismatch");
7471
+ }
7472
+ let body = response.slice(bodyStart);
7473
+ if (shouldRevealChunkFraming(clientVersion)) {
7474
+ if (/transfer-encoding:\s*chunked/i.test(headersText)) {
7475
+ body = dechunkResponseBody(body);
7456
7476
  }
7457
- } else {
7458
- bodyStart = OK_HTTP_HEADER.length;
7459
7477
  }
7478
+ const charset = shouldRevealCrlf(ctx) ? getResponseBodyCharset(headersText) : void 0;
7479
+ const bodyText = decodeResponseBody(body, charset);
7480
+ let res = headersText + bodyText;
7460
7481
  const dateHeader = makeRegex(dateHeaderRegex).exec(res);
7461
7482
  if (dateHeader && dateHeader.length > 1) {
7462
7483
  const serverDate = new Date(dateHeader[1]);
@@ -7464,14 +7485,7 @@ var HTTP_PROVIDER = {
7464
7485
  logger2.info({ dateHeader: dateHeader[0], current: Date.now() }, "date header is off");
7465
7486
  }
7466
7487
  }
7467
- const paramBody = params.body instanceof Uint8Array ? params.body : strToUint8Array(params.body || "");
7468
- if (paramBody.length > 0 && !matchRedactedStrings(paramBody, req.body)) {
7469
- throw new Error("request body mismatch");
7470
- }
7471
- if (shouldRevealChunkFraming(clientVersion)) {
7472
- const headersStr = res.slice(0, bodyStart);
7473
- res = /transfer-encoding:\s*chunked/i.test(headersStr) ? headersStr + dechunkResponseBody(res.slice(bodyStart)) : res;
7474
- } else if (!secretParams) {
7488
+ if (!shouldRevealChunkFraming(clientVersion) && !secretParams) {
7475
7489
  res = res.slice(bodyStart).replace(/\*{3,}/g, "");
7476
7490
  }
7477
7491
  for (const { type, value, invert } of params.responseMatches || []) {
@@ -7562,12 +7576,35 @@ function shouldRevealCrlf({ version }) {
7562
7576
  function shouldRevealChunkFraming(version) {
7563
7577
  return version >= AttestorVersion.ATTESTOR_VERSION_3_2_0;
7564
7578
  }
7579
+ function getResponseBodyCharset(headers) {
7580
+ const contentType = /(?:^|[\r\n*])content-type\s*:\s*([^*\r\n]*)/i.exec(headers)?.[1];
7581
+ if (typeof contentType === "undefined") {
7582
+ return void 0;
7583
+ }
7584
+ const charsetMatch = /(?:^|;)\s*charset\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^;\s]*))/i.exec(contentType);
7585
+ if (!charsetMatch) {
7586
+ return void 0;
7587
+ }
7588
+ const charset = charsetMatch[1]?.replace(/\\(.)/g, "$1") ?? charsetMatch[2];
7589
+ return charset.trim() || void 0;
7590
+ }
7591
+ function decodeResponseBody(body, charset) {
7592
+ try {
7593
+ return new TextDecoder(charset ?? "utf-8").decode(body);
7594
+ } catch (error) {
7595
+ if (charset) {
7596
+ throw new Error(`Unsupported response charset "${charset}"`, { cause: error });
7597
+ }
7598
+ throw error;
7599
+ }
7600
+ }
7565
7601
  function dechunkResponseBody(body) {
7566
7602
  const parser = makeHttpResponseParser();
7567
- parser.onChunk(
7568
- strToUint8Array("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n" + body)
7569
- );
7570
- return uint8ArrayToStr(parser.res.body ?? new Uint8Array());
7603
+ parser.onChunk(concatenateUint8Arrays6([
7604
+ strToUint8Array("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"),
7605
+ body
7606
+ ]));
7607
+ return parser.res.body ?? new Uint8Array();
7571
7608
  }
7572
7609
  function getHostPort(params, secretParams) {
7573
7610
  const { host } = new URL(getURL(params, secretParams));
@@ -8454,6 +8491,7 @@ async function _createClaimOnAttestor({
8454
8491
  block,
8455
8492
  redactedPlaintext,
8456
8493
  overshotToprfFromPrevBlock,
8494
+ overshotOprfRawFromPrevBlock,
8457
8495
  toprfs,
8458
8496
  oprfRawMarkers
8459
8497
  } = reveal;
@@ -8462,7 +8500,8 @@ async function _createClaimOnAttestor({
8462
8500
  redactedPlaintext,
8463
8501
  toprfs,
8464
8502
  oprfRawMarkers,
8465
- overshotToprfFromPrevBlock
8503
+ overshotToprfFromPrevBlock,
8504
+ overshotOprfRawFromPrevBlock
8466
8505
  });
8467
8506
  revealedPackets.push(
8468
8507
  { sender: "server", message: redactedPlaintext }
@@ -1,5 +1,20 @@
1
1
  import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
2
2
  export declare const protobufPackage = "teeproto";
3
+ export declare const TLS12CBCRecordMode: {
4
+ readonly TLS12_CBC_RECORD_MODE_UNSPECIFIED: 0;
5
+ readonly TLS12_CBC_RECORD_MODE_MAC_THEN_ENCRYPT: 1;
6
+ readonly TLS12_CBC_RECORD_MODE_ENCRYPT_THEN_MAC: 2;
7
+ readonly UNRECOGNIZED: -1;
8
+ };
9
+ export type TLS12CBCRecordMode = typeof TLS12CBCRecordMode[keyof typeof TLS12CBCRecordMode];
10
+ export declare namespace TLS12CBCRecordMode {
11
+ type TLS12_CBC_RECORD_MODE_UNSPECIFIED = typeof TLS12CBCRecordMode.TLS12_CBC_RECORD_MODE_UNSPECIFIED;
12
+ type TLS12_CBC_RECORD_MODE_MAC_THEN_ENCRYPT = typeof TLS12CBCRecordMode.TLS12_CBC_RECORD_MODE_MAC_THEN_ENCRYPT;
13
+ type TLS12_CBC_RECORD_MODE_ENCRYPT_THEN_MAC = typeof TLS12CBCRecordMode.TLS12_CBC_RECORD_MODE_ENCRYPT_THEN_MAC;
14
+ type UNRECOGNIZED = typeof TLS12CBCRecordMode.UNRECOGNIZED;
15
+ }
16
+ export declare function tLS12CBCRecordModeFromJSON(object: any): TLS12CBCRecordMode;
17
+ export declare function tLS12CBCRecordModeToJSON(object: TLS12CBCRecordMode): string;
3
18
  /** Signature wrapper used everywhere */
4
19
  export declare const BodyType: {
5
20
  readonly BODY_TYPE_UNSPECIFIED: 0;
@@ -27,6 +42,13 @@ export interface ResponseRedactionRange {
27
42
  start: number;
28
43
  length: number;
29
44
  }
45
+ export interface TLS12CBCSessionBinding {
46
+ contractVersion: number;
47
+ cipherSuite: number;
48
+ recordMode: TLS12CBCRecordMode;
49
+ extendedMasterSecret: boolean;
50
+ sessionBinding: Uint8Array;
51
+ }
30
52
  export interface SignedRedactedDecryptionStream {
31
53
  redactedStream: Uint8Array;
32
54
  seqNum: number;
@@ -79,6 +101,9 @@ export interface KOutputPayload {
79
101
  sessionId: string;
80
102
  /** MPC OPRF outputs (TEE-to-TEE computation) - field 10 to match reclaim-tee */
81
103
  oprfOutputs: OPRFOutput[];
104
+ /** Signed TEE attestation generation */
105
+ attestationType: string;
106
+ tls12Cbc: TLS12CBCKOutput | undefined;
82
107
  }
83
108
  export interface TOutputPayload {
84
109
  /** NEW: Single consolidated ciphertext instead of individual packets */
@@ -91,6 +116,23 @@ export interface TOutputPayload {
91
116
  sessionId: string;
92
117
  /** MPC OPRF outputs (TEE-to-TEE computation) - field 10 to match reclaim-tee */
93
118
  oprfOutputs: OPRFOutput[];
119
+ /** Signed TEE attestation generation */
120
+ attestationType: string;
121
+ tls12Cbc: TLS12CBCTOutput | undefined;
122
+ }
123
+ export interface TLS12CBCKOutput {
124
+ binding: TLS12CBCSessionBinding | undefined;
125
+ authenticatedRedactedRequest: Uint8Array;
126
+ requestRecordsSha256: Uint8Array;
127
+ requestRedactionRanges: RequestRedactionRange[];
128
+ }
129
+ export interface TLS12CBCTOutput {
130
+ binding: TLS12CBCSessionBinding | undefined;
131
+ authenticatedRedactedResponse: Uint8Array;
132
+ responseRecordsSha256: Uint8Array;
133
+ responseRedactionRanges: ResponseRedactionRange[];
134
+ plaintextRecordLengths: number[];
135
+ closeNotify: boolean;
94
136
  }
95
137
  /** Attestation report with structured data */
96
138
  export interface AttestationReport {
@@ -130,6 +172,7 @@ export interface VerificationBundle {
130
172
  }
131
173
  export declare const RequestRedactionRange: MessageFns<RequestRedactionRange>;
132
174
  export declare const ResponseRedactionRange: MessageFns<ResponseRedactionRange>;
175
+ export declare const TLS12CBCSessionBinding: MessageFns<TLS12CBCSessionBinding>;
133
176
  export declare const SignedRedactedDecryptionStream: MessageFns<SignedRedactedDecryptionStream>;
134
177
  export declare const CertificateInfo: MessageFns<CertificateInfo>;
135
178
  export declare const HandshakeSecrets: MessageFns<HandshakeSecrets>;
@@ -137,6 +180,8 @@ export declare const Opening: MessageFns<Opening>;
137
180
  export declare const OPRFOutput: MessageFns<OPRFOutput>;
138
181
  export declare const KOutputPayload: MessageFns<KOutputPayload>;
139
182
  export declare const TOutputPayload: MessageFns<TOutputPayload>;
183
+ export declare const TLS12CBCKOutput: MessageFns<TLS12CBCKOutput>;
184
+ export declare const TLS12CBCTOutput: MessageFns<TLS12CBCTOutput>;
140
185
  export declare const AttestationReport: MessageFns<AttestationReport>;
141
186
  export declare const SignedMessage: MessageFns<SignedMessage>;
142
187
  export declare const OPRFVerificationData: MessageFns<OPRFVerificationData>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Ephemeral HTTP server that answers ACME HTTP-01 challenges. Started right
3
+ * before an order is placed and stopped as soon as the order is finalized,
4
+ * so the attestor does not keep port 80 bound during normal operation.
5
+ */
6
+ export declare class AcmeChallengeServer {
7
+ private readonly tokens;
8
+ private server?;
9
+ add(token: string, keyAuthorization: string): void;
10
+ remove(token: string): void;
11
+ start(port: number): Promise<void>;
12
+ stop(): Promise<void>;
13
+ }
@@ -0,0 +1,29 @@
1
+ import type { AttestationReport } from '../../proto/tee-bundle.ts';
2
+ /**
3
+ * Requests a custom attestation token from the Confidential Space launcher
4
+ * over the unix domain socket. Mirrors reclaim-tee's shared/gcp_attestation.go.
5
+ */
6
+ export declare function generateAttestationJwt(nonces: string[]): Promise<Uint8Array>;
7
+ export interface AttestationContext {
8
+ attestorAddress: string;
9
+ tlsCertSha256Hex: () => string | undefined;
10
+ }
11
+ /**
12
+ * Starts the background attestation refresh loop. The first attestation is
13
+ * generated synchronously so getCachedAttestationJwt() is ready by the time
14
+ * the server begins handling claims.
15
+ */
16
+ export declare function startAttestationRefresh(ctx: AttestationContext): Promise<void>;
17
+ export declare function stopAttestationRefresh(): void;
18
+ /**
19
+ * Returns the currently-cached attestation JWT bytes, or undefined if no
20
+ * attestation has been generated yet or the cache has expired without a
21
+ * successful refresh.
22
+ */
23
+ export declare function getCachedAttestationJwt(): Uint8Array | undefined;
24
+ /**
25
+ * Returns an AttestationReport ready to embed in a claim response, or
26
+ * undefined when no attestation is available (i.e. attestor is not running
27
+ * inside a TEE, or the refresh loop has not produced one yet).
28
+ */
29
+ export declare function makeClaimAttestation(): AttestationReport | undefined;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Brings the attestor up in TEE mode:
3
+ * 1. Pull signing/OPRF secrets from GCP Secret Manager into process.env.
4
+ * 2. Load (or obtain via ACME) the TLS cert and start the renewal loop.
5
+ * 3. Start the attestation refresh loop, with the public key + cert hash
6
+ * as nonces.
7
+ *
8
+ * Must run before #src/server/index.ts is imported, since modules in that
9
+ * tree read PRIVATE_KEY at module load.
10
+ */
11
+ export declare function bootstrapTee(): Promise<void>;
@@ -0,0 +1,24 @@
1
+ import tls from 'tls';
2
+ export interface CertManagerConfig {
3
+ projectId: string;
4
+ domain: string;
5
+ email: string;
6
+ directoryUrl: string;
7
+ httpChallengePort: number;
8
+ }
9
+ export interface ActiveCertificate {
10
+ certPem: string;
11
+ keyPem: string;
12
+ notAfter: Date;
13
+ sha256Hex: string;
14
+ secureContext: tls.SecureContext;
15
+ }
16
+ /**
17
+ * Bootstraps the TLS certificate. Tries Secret Manager first; if absent or
18
+ * expiring within the renewal window, runs ACME against the configured
19
+ * directory URL and persists the result.
20
+ */
21
+ export declare function bootstrapCertificate(cfg: CertManagerConfig): Promise<ActiveCertificate>;
22
+ export declare function startRenewalLoop(cfg: CertManagerConfig): void;
23
+ export declare function stopRenewalLoop(): void;
24
+ export declare function getActiveCertificate(): ActiveCertificate | undefined;
@@ -0,0 +1,23 @@
1
+ import type { LogLevel } from '../../types/index.ts';
2
+ interface CloudLoggingOptions {
3
+ projectId: string;
4
+ logName: string;
5
+ level?: LogLevel;
6
+ }
7
+ /**
8
+ * Replaces the default pino logger with one that forwards every log line
9
+ * to GCP Cloud Logging under the given log name. Idempotent.
10
+ *
11
+ * Probes the Cloud Logging client first by writing a no-op entry; if
12
+ * authentication or transport fails, leaves the default stdout logger in
13
+ * place rather than crashing the process. On Confidential Space VMs the
14
+ * launcher's `tee-container-log-redirect` ships stdout to Cloud Logging
15
+ * anyway, so the worst case is logs appear under
16
+ * `confidential-space-launcher` rather than the configured `logName`.
17
+ *
18
+ * We also install a process-wide `unhandledRejection` filter that
19
+ * swallows errors originating in `@google-cloud/logging`, since the SDK
20
+ * has internal lazy gRPC init that escapes our local `.catch()`.
21
+ */
22
+ export declare function installCloudLogging(opts: CloudLoggingOptions): void;
23
+ export {};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Fetches the attestor's signing key and OPRF key material from GCP
3
+ * Secret Manager and writes them into process.env, so that the rest of
4
+ * the server (which reads these via getEnvVariable at module load) sees
5
+ * them as if they had been set in the environment.
6
+ *
7
+ * Must be called before any module that reads PRIVATE_KEY / TOPRF_* is
8
+ * imported, otherwise the reads happen before the values are populated.
9
+ */
10
+ export declare function loadSecretsIntoEnv(projectId: string): Promise<void>;
@@ -0,0 +1,3 @@
1
+ export declare function accessLatestSecret(projectId: string, secretId: string): Promise<Uint8Array>;
2
+ export declare function createSecretIfNotExists(projectId: string, secretId: string): Promise<void>;
3
+ export declare function addSecretVersion(projectId: string, secretId: string, payload: Uint8Array): Promise<void>;
@@ -12,4 +12,6 @@ import { type SevSnpEnvelope } from '../../../server/utils/sev-snp/verify.ts';
12
12
  export declare function verifyGcpLeg(env: SevSnpEnvelope, bound: Buffer, now: Date): {
13
13
  app: string;
14
14
  base: string;
15
+ pcrs: Map<number, Buffer>;
16
+ eventLog: Buffer;
15
17
  };
@@ -9,6 +9,7 @@
9
9
  export interface NitroTpmResult {
10
10
  pcr8: Buffer;
11
11
  pcr11: Buffer;
12
+ pcrs: Map<number, Buffer>;
12
13
  userData: Buffer;
13
14
  }
14
15
  /**
@@ -0,0 +1,9 @@
1
+ type Bank = 'sha256' | 'sha384';
2
+ export interface SecureBootEventLogResult {
3
+ eventLogBytes: number;
4
+ verifiedEvents: number;
5
+ postSeparatorUses: number;
6
+ releasePublicKeySha256: string;
7
+ }
8
+ export declare function verifySecureBootEventLog(raw: Uint8Array, quotedPcrs: Map<number, Buffer>, bank: Bank): SecureBootEventLogResult;
9
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -8,6 +8,8 @@
8
8
  */
9
9
  export declare const SEV_TAG_GCP = 1;
10
10
  export declare const SEV_TAG_AWS = 2;
11
+ export declare const SECURE_BOOT_TAG_GCP = 3;
12
+ export declare const SECURE_BOOT_TAG_AWS = 4;
11
13
  export declare const SNP_APP_PREFIX = "snp-app:";
12
14
  export declare const SNP_BASE_PREFIX = "snp-base:";
13
15
  export declare const APP_PCR = 8;
@@ -17,6 +19,8 @@ export interface SevSnpEnvelope {
17
19
  tpm?: Uint8Array;
18
20
  nitrotpm?: Uint8Array;
19
21
  sev?: Uint8Array;
22
+ sev2?: Uint8Array;
23
+ eventlog?: Uint8Array;
20
24
  nonces?: string[];
21
25
  }
22
26
  export interface SevSnpResult {
@@ -37,6 +41,10 @@ export declare function parseSevSnpEnvelope(att: Uint8Array): Promise<{
37
41
  * what makes the carried nonces unforgeable.
38
42
  */
39
43
  export declare function snpNonceCommitment(nonces: string[]): Buffer;
44
+ /** Commits the AMD report to the exact NitroTPM evidence from the same broker. */
45
+ export declare function awsCombinedV2ReportData(bound: Uint8Array, appHash: Uint8Array, nitroTpm: Uint8Array): Buffer;
46
+ /** Only an absent value or an explicit 0 keeps the AWS expansion path active. */
47
+ export declare function requireAwsAttestationV2(value?: string | undefined): boolean;
40
48
  /**
41
49
  * expectedPCR8: the value the loader produces by extending a pristine (all-zero)
42
50
  * PCR 8 once with alg(appHash), i.e. alg(0^algSize || alg(appHash)). GCP uses the
@@ -57,3 +65,14 @@ export declare function extractTeeKeyFromNonces(nonces: string[]): {
57
65
  * `now` defaults to the real clock; tests may pass a time in the leaf window.
58
66
  */
59
67
  export declare function verifyCombinedSevSnp(att: Uint8Array, now?: Date): Promise<SevSnpResult>;
68
+ /**
69
+ * Verifies the additive Secure Boot claim format. The cloud-specific leg is
70
+ * unchanged from SEV2; only after it succeeds do we replay PCR 4/7/11 and pin R.
71
+ */
72
+ export declare function verifyCombinedSecureBoot(att: Uint8Array, now?: Date): Promise<SevSnpResult>;
73
+ /**
74
+ * Restores the distinct Secure Boot tag on legacy-compatible client evidence.
75
+ * Call this only when an authenticated protocol value requires Secure Boot;
76
+ * the legacy tag alone is intentionally not a generation signal.
77
+ */
78
+ export declare function secureBootAttestationFromCompatibleWire(att: Uint8Array): Buffer;
@@ -0,0 +1,3 @@
1
+ import type { KOutputPayload, TOutputPayload, VerificationBundle } from '../../proto/tee-bundle.ts';
2
+ export type TeeProtocolMode = 'split-aead' | 'tls12-cbc';
3
+ export declare function validateTeeTranscriptContract(bundle: VerificationBundle, kPayload: KOutputPayload, tPayload: TOutputPayload): TeeProtocolMode;
@@ -9,6 +9,7 @@
9
9
  import type { KOutputPayload, TOutputPayload } from '../../proto/tee-bundle.ts';
10
10
  import type { OprfVerificationResult } from '../../server/utils/tee-oprf-verification.ts';
11
11
  import type { Logger } from '../../types/general.ts';
12
+ export declare const MAX_TEE_OPRF_MPC_OUTPUTS = 20;
12
13
  /**
13
14
  * Verifies OPRF MPC outputs from TEE_K and TEE_T match
14
15
  * Returns verified outputs for transcript replacement (same format as ZK OPRF)
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import type { SignedMessage } from '../../proto/tee-bundle.ts';
6
6
  import { KOutputPayload, TOutputPayload } from '../../proto/tee-bundle.ts';
7
+ import type { TeeProtocolMode } from '../../server/utils/tee-cbc-contract.ts';
7
8
  import type { Logger } from '../../types/general.ts';
8
9
  export interface TeeBundleData {
9
10
  teekSigned: SignedMessage;
@@ -13,6 +14,7 @@ export interface TeeBundleData {
13
14
  teekPcr0: string;
14
15
  teetPcr0: string;
15
16
  teeSessionId: string;
17
+ protocolMode: TeeProtocolMode;
16
18
  }
17
19
  export interface TeeSignatureVerificationResult {
18
20
  isValid: boolean;
@@ -26,3 +28,4 @@ export interface TeeSignatureVerificationResult {
26
28
  * @returns Validated TEE bundle data
27
29
  */
28
30
  export declare function verifyTeeBundle(bundleBytes: Uint8Array, logger: Logger): Promise<TeeBundleData>;
31
+ export declare function resolveSignedAttestationType(signedType: string, reportType: string): string;