routex-settlement 0.1.2 → 0.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.
Files changed (3) hide show
  1. package/index.d.ts +2 -0
  2. package/index.js +208 -28
  3. package/package.json +7 -5
package/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export declare class KeySettlement {
6
6
  private _requirements;
7
7
  private _yaxiSigningKeys;
8
8
  private _serverKey?;
9
+ private _settlementPromise?;
9
10
  private _measurement?;
10
11
  constructor(url: URL, onErrorResponse: (response: Response) => void, onRequestError?: (e: Error) => never);
11
12
  private _settle;
@@ -15,6 +16,7 @@ export declare class KeySettlement {
15
16
  seal(plaintext: Uint8Array, settlementHeaders?: HeadersInit): Promise<Uint8Array>;
16
17
  unseal(ciphertext: Uint8Array): Uint8Array;
17
18
  private _verifyAttestation;
19
+ private _verifyTcbVersion;
18
20
  private _verifyReport;
19
21
  private _verifyVcekChain;
20
22
  }
package/index.js CHANGED
@@ -7,26 +7,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { chacha20poly1305 } from "@noble/ciphers/chacha";
11
- import { bytesToUtf8 } from "@noble/ciphers/utils";
12
- import { bytesToNumberLE, equalBytes } from "@noble/curves/abstract/utils";
13
- import { ed25519, x25519 } from "@noble/curves/ed25519";
14
- import { blake2b } from "@noble/hashes/blake2b";
15
- import { p384 } from "@noble/curves/p384";
16
- import { hkdf } from "@noble/hashes/hkdf";
17
- import { wrapConstructor } from "@noble/hashes/utils";
18
- import { sha256 } from "@noble/hashes/sha2";
10
+ import { chacha20poly1305 } from "@noble/ciphers/chacha.js";
11
+ import { bytesToUtf8 } from "@noble/ciphers/utils.js";
12
+ import { equalBytes } from "@noble/curves/utils.js";
13
+ import { ed25519, x25519 } from "@noble/curves/ed25519.js";
14
+ import { blake2b } from "@noble/hashes/blake2.js";
15
+ import { p384 } from "@noble/curves/nist.js";
16
+ import { hkdf } from "@noble/hashes/hkdf.js";
17
+ import { createHasher } from "@noble/hashes/utils.js";
18
+ import { sha256 } from "@noble/hashes/sha2.js";
19
19
  import * as x509 from "@peculiar/x509";
20
20
  import { AsnConvert } from "@peculiar/asn1-schema";
21
21
  import { SubjectPublicKeyInfo } from "@peculiar/asn1-x509";
22
22
  const REQUIREMENTS = {
23
23
  Genoa: {
24
24
  minCommittedVersion: [0x1, 0x37, 0x26],
25
- minCommitedTcbSnp: 0x16,
25
+ minCommittedTcbSnp: 0x16,
26
26
  },
27
27
  Milan: {
28
28
  minCommittedVersion: [0x1, 0x37, 0x16],
29
- minCommitedTcbSnp: 0x17,
29
+ minCommittedTcbSnp: 0x17,
30
+ },
31
+ // for Turin: SB-3019 doesn't list a TCB[SNP] version in the mitigation, only firmware version
32
+ Turin: {
33
+ minCommittedVersion: [0x1, 0x37, 0x3b],
34
+ minCommittedTcbSnp: 0,
30
35
  },
31
36
  };
32
37
  const YAXI_SIGNING_KEYS = {
@@ -200,6 +205,86 @@ JZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH
200
205
  CViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4
201
206
  AFZEAwoKCQ==
202
207
  -----END CERTIFICATE-----
208
+ `),
209
+ // ARK-Turin
210
+ new x509.X509Certificate(`
211
+ -----BEGIN CERTIFICATE-----
212
+ MIIGiTCCBDigAwIBAgIDAwABMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC
213
+ BQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS
214
+ BgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg
215
+ Q2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp
216
+ Y2VzMRIwEAYDVQQDDAlBUkstVHVyaW4wHhcNMjMwNTE1MjAyNTIxWhcNNDgwNTE1
217
+ MjAyNTIxWjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS
218
+ BgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j
219
+ ZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJU0VWLVR1cmluMIICIjANBgkqhkiG
220
+ 9w0BAQEFAAOCAg8AMIICCgKCAgEAnvg5Grv2Emd9lAhKdO64RXU3UESb6JTm0Hhz
221
+ evx1PyxinxYqJL329qTJM0XmdozLYb7rsHxgM5I2pU18M8gect2pN/YB2LQ1/bIq
222
+ 37TPDbg7ym0MN6KkZ6aERxAX0voYtdDyNxjDAUjpRpCe1FccAev/Es2n/Fz1G1Tm
223
+ C2XepTQqaKpmt6mnDWSCHCVsQoY0gSibeaG6doM6OiNUCbKXaC7KHH5b/96BD1DJ
224
+ 84M+JHqPClFhHqUJwzKF5Qxj4wgWAZzK8UPhiNGjrF6+TBdlFGdSzEqw1jOrCTHd
225
+ uYyLK+5OQ3OIw4S+vZeOVoxJajTIWdsqYP2DLc0HkL0qWOumEOrrc2/4DeETShB0
226
+ MyIpH05kSalyQN2eN5P6ptOB84hddCdbJPEepnD+FqQap1ukw3K8uBcgeBSAF23r
227
+ 6UtT8Uc5h7MsWX3MoZiEHcSkDQQ8IedTk7CLjsK6S7b/lfKqfYiRhKgGkRvsEd/M
228
+ DNcumHZKIgzasJwgagzSggiUo9jXp3EWm84fqyxNXzSutPB7qD5P/ULAB+q9Qgvr
229
+ zC8XneaLP0MNrHhM80UejmsBTIktMvFoWVIelYDLdcoi0eMD5DRccfsgrYaY6h/+
230
+ /qf9tgg+mX09UJpuSPRF38oyqnNNFMl5v/tWLgUsChPU6NCQC17Qaqr8mu2ynyyu
231
+ HEs5JVUCAwEAAaOBozCBoDAdBgNVHQ4EFgQUbYJXt6v2sMgUALjxD0WvG9aq628w
232
+ HwYDVR0jBBgwFoAUZKBfceMMCmTYO3XlAVmeK+4GA0QwEgYDVR0TAQH/BAgwBgEB
233
+ /wIBADAOBgNVHQ8BAf8EBAMCAQQwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cHM6Ly9r
234
+ ZHNpbnRmLmFtZC5jb20vdmNlay92MS9UdXJpbi9jcmwwRgYJKoZIhvcNAQEKMDmg
235
+ DzANBglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIFAKID
236
+ AgEwowMCAQEDggIBAAXWJ3DPahralt5kXLPMm9oKlFRqeU3HcS7kA+VBlBA1lQRU
237
+ hXkbXnTvW1GZcgdZvNCB/VlET61KbCzoFIhPIESVjjb/xWX2kg3X0HHmh1EtCDbH
238
+ aUFM5rq6l+S1h7qOauRZebvrwApDzAANvW0LTHRumfGm/kqh9NDtVCIWPUZ1VQIg
239
+ Gx1T3dwmgOK8ncT1J3W5xIyS0Xu3KC6w7oBlq8G2pPgTcCBJ4JBCTXCEXiAAGaTR
240
+ /TJIaSzoZFLhxYhCMjP8WQGToPGDK2i/lZhkcGHnJOQ+lgrXfpLGqBtLlS3QODyV
241
+ P0MomczG4dqw3THP3Y8Aq9c2KE7SylAKsS/bBKCqkj4OrABkDSkMQEz3BBoFD63a
242
+ D5ZG/Qiz+tmhnptyPVcweC9uJlSWYm25KiV4lT52uBjxatDZKQcrpdgcU8+ozzKU
243
+ 8ICnZPOwfWeyuNMq/juyd/rzg5IePyyvt+13aJ5MlZBXZxJKoxCYIMKUwZigf0Xs
244
+ BteT8gw10/xk5smIFIB2ERtTQPMuTENgrPTUjOeiqmBg663c2dLVol+MDiT4ltqf
245
+ Em4Kl/cc4f+H6bEwhj1QKAN2ipRf+mP0NfzJb+6ZHNsOvyq/WByYpLXV9JJoiDW/
246
+ 8RZwPU/Mn7IuQBauCy78G7FS0ta3q1et74faYBBgeJ6awEasa25CvmsmlU0R
247
+ -----END CERTIFICATE-----
248
+ `),
249
+ // SEV-Turin
250
+ new x509.X509Certificate(`
251
+ -----BEGIN CERTIFICATE-----
252
+ MIIGYzCCBBKgAwIBAgIDAwAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC
253
+ BQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS
254
+ BgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg
255
+ Q2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp
256
+ Y2VzMRIwEAYDVQQDDAlBUkstVHVyaW4wHhcNMjMwNTE1MjAwMzEyWhcNNDgwNTE1
257
+ MjAwMzEyWjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS
258
+ BgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j
259
+ ZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLVR1cmluMIICIjANBgkqhkiG
260
+ 9w0BAQEFAAOCAg8AMIICCgKCAgEAwaAriB7EIuVc4ZB1wD3YfDxL+9eyS7+izm0J
261
+ j3W772NINCWl8Bj3w/JD2ZjmbRxWdIq/4d9iarCKorXloJUB1jRdgxqccTx1aOoi
262
+ g4+2w1XhVVJT7K457wT5ZLNJgQaxqa9Etkwjd6+9sOhlCDE9l43kQ0R2BikVJa/u
263
+ yyVOSwEk5w5tXKOuG9jvq6QtAMJasW38wlqRDaKEGtZ9VUgGon27ZuL4sTJuC/az
264
+ z9/iQBw8kEilzOl95AiTkeY5jSEBDWbAqnZk5qlM7kISKG20kgQm14mhNKDI2p2o
265
+ ua+zuAG7i52epoRF2GfU0TYk/yf+vCNB2tnechFQuP2e8bLk95ZdqPi9/UWw4JXj
266
+ tdEA4u2JYplSSUPQVAXKt6LVqujtJcM59JKr2u0XQ75KwxcMp15gSXhBfInvPAwu
267
+ AY4dEwwGqT8oIg4esPHwEsmChhYeDIxPG9R4fx9O0q6p8Gb+HXlTiS47P9YNeOpi
268
+ dOUKzDl/S1OvyhDtSL8LJc24QATFydo/iD/KUdvFTRlD0crkAMkZLoWQ8hLDGc6B
269
+ ZJXsdd7Zf2e4UW3tI/1oh/2t23Ot3zyhTcv5gDbABu0LjVe98uRnS15SMwK//lJt
270
+ 9e5BqKvgABkSoABf+B4VFtPVEX0ygrYaFaI9i5ABrxnVBmzXpRb21iI1NlNCfOGU
271
+ PIhVpWECAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRkoF9x4wwK
272
+ ZNg7deUBWZ4r7gYDRDAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG
273
+ KWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvVHVyaW4vY3JsMEYGCSqG
274
+ SIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI
275
+ AWUDBAICBQCiAwIBMKMDAgEBA4ICAQA/i6Mz4IETMK8YU/HxP7Bfej5i4aXhenJo
276
+ TuiDX0nqx5CDJm9ELhskxAkJ/oLA1O92UoLybfFk4gEpKFtyfiUYex9LogZj5ix0
277
+ sb2qfSSy9CRnOktGqfpel4e3KAhLgF5n2qZrqyq/8EPPldtSjEXn78sZMlIlUcQK
278
+ SnnNCQZVFpktDfDiEiGNuitux3ghHUrcVuxSbZcrXDbsbMF7NDdfLUUS9TijrL33
279
+ lrCXJs7m8kggGyCusiRQKHli1AEswiA4xU+8xsZrByYTopiGYtbJK8s0UCCXylyO
280
+ uKSubvdAnMDJ5GDD0+DX46LSfv7fgGNSG+LOBWdif7KoQf9cIhKJtxGxZCn/tvHm
281
+ wMzu4Jnx8N2vRnT+8DpBqhxtNvdXmrZUelSeQakx4djMKvmTR8Gd25EnC4RppCkj
282
+ bmPxY3zPd1X7raalTn34EOF9DeLsC9JfzkDuojxpHWMm30wKnDo20mlDQk/zKCDa
283
+ 2Zc+YjtsTZCrTbvdgCukTKNZOUUVlWRu+sO/OwrmS2p16seHTIqHEbE1LntPv3gk
284
+ CcHGDSUAKx9c0Aol+Dj9xpb2nmGqoDeJ59Ja6REkHCdw5TduXyqqMqfD1AX0/QDN
285
+ devCMKlWBRCQ7DFlog3H1a+r/kuMUZ/Ij9yyKlSgYZMJ4VgNKDgTQdcsAL0MCEMr
286
+ zpacMwFusA==
287
+ -----END CERTIFICATE-----
203
288
  `),
204
289
  ],
205
290
  });
@@ -213,7 +298,7 @@ export class KeySettlement {
213
298
  onRequestError !== null && onRequestError !== void 0 ? onRequestError : ((e) => {
214
299
  throw e;
215
300
  });
216
- this._secretKey = x25519.utils.randomPrivateKey();
301
+ this._secretKey = x25519.utils.randomSecretKey();
217
302
  }
218
303
  _settle(headers) {
219
304
  return __awaiter(this, void 0, void 0, function* () {
@@ -223,7 +308,11 @@ export class KeySettlement {
223
308
  body: JSON.stringify({
224
309
  publicKey: btoa(bytesToBinaryString(x25519.getPublicKey(this._secretKey))),
225
310
  }),
226
- }).catch(this._onRequestError);
311
+ })
312
+ .catch(this._onRequestError)
313
+ .finally(() => {
314
+ this._settlementPromise = undefined;
315
+ });
227
316
  if (response.status >= 400) {
228
317
  throw yield this._onErrorResponse(response);
229
318
  }
@@ -243,7 +332,10 @@ export class KeySettlement {
243
332
  _getServerKey(settlementHeaders) {
244
333
  return __awaiter(this, void 0, void 0, function* () {
245
334
  if (this._serverKey == null) {
246
- yield this._settle(settlementHeaders);
335
+ if (this._settlementPromise == null) {
336
+ this._settlementPromise = this._settle(settlementHeaders);
337
+ }
338
+ yield this._settlementPromise;
247
339
  }
248
340
  return this._serverKey;
249
341
  });
@@ -258,7 +350,7 @@ export class KeySettlement {
258
350
  const serverPublicKey = (yield this._getServerKey(settlementHeaders))
259
351
  .publicKey;
260
352
  const tagLength = 16;
261
- const ephemeralSecretKey = x25519.utils.randomPrivateKey();
353
+ const ephemeralSecretKey = x25519.utils.randomSecretKey();
262
354
  const ephemeralPublicKey = x25519.getPublicKey(ephemeralSecretKey);
263
355
  const nonce = _getSealNonce(ephemeralPublicKey, serverPublicKey);
264
356
  const info = _getInfo(ephemeralPublicKey, serverPublicKey);
@@ -308,17 +400,82 @@ export class KeySettlement {
308
400
  return launchMeasurementInSystemVersion;
309
401
  });
310
402
  }
403
+ _verifyTcbVersion(attestationReport, vcekTcb) {
404
+ return __awaiter(this, void 0, void 0, function* () {
405
+ const versionBytes = attestationReport.slice(0, 4);
406
+ const version = new DataView(versionBytes.buffer).getInt32(0, true);
407
+ let turinLike;
408
+ switch (version) {
409
+ case 0:
410
+ case 1:
411
+ throw new Error("Unsupported Attestation Report Version");
412
+ case 2: {
413
+ const chipId = attestationReport.slice(REPORT_OFFSETS.chipId, 64);
414
+ if (equalBytes(chipId, new Uint8Array(64))) {
415
+ throw new Error("Could not derive CPU family: MASK_CHIP_ID enabled");
416
+ }
417
+ turinLike = equalBytes(chipId.slice(8), new Uint8Array(56));
418
+ break;
419
+ }
420
+ default: // from version 3 onwards CPUID_FAM_ID field should exist
421
+ turinLike = attestationReport[REPORT_OFFSETS.cpuIdFamily] == 0x1a;
422
+ }
423
+ const reportedTcb = attestationReport.slice(REPORT_OFFSETS.reportedTcb, REPORT_OFFSETS.reportedTcb + 8);
424
+ let tcb;
425
+ if (turinLike) {
426
+ tcb = {
427
+ microcode: reportedTcb[7],
428
+ snp: reportedTcb[3],
429
+ tee: reportedTcb[2],
430
+ bootloader: reportedTcb[1],
431
+ fmc: reportedTcb[0],
432
+ };
433
+ }
434
+ else {
435
+ tcb = {
436
+ microcode: reportedTcb[7],
437
+ snp: reportedTcb[6],
438
+ tee: reportedTcb[1],
439
+ bootloader: reportedTcb[0],
440
+ fmc: 0,
441
+ };
442
+ }
443
+ if (!(tcb.microcode === vcekTcb.microcode &&
444
+ tcb.snp === vcekTcb.snp &&
445
+ tcb.tee === vcekTcb.tee &&
446
+ tcb.bootloader === vcekTcb.bootloader &&
447
+ tcb.fmc === vcekTcb.fmc)) {
448
+ throw new Error("Verification failed: REPORTED_TCB doesn't match with VCEK's TCB_VERSION");
449
+ }
450
+ });
451
+ }
311
452
  _verifyReport(attestationReport, vcekChain) {
312
453
  return __awaiter(this, void 0, void 0, function* () {
313
454
  if (attestationReport.length != 1184) {
314
455
  throw new Error(`Attestation report has unexpected length: ${attestationReport.length}`);
315
456
  }
316
- const { requirements, publicKey } = yield this._verifyVcekChain(vcekChain);
317
- const sig = {
318
- r: bytesToNumberLE(attestationReport.slice(REPORT_OFFSETS.signatureR, REPORT_OFFSETS.signatureR + 72)),
319
- s: bytesToNumberLE(attestationReport.slice(REPORT_OFFSETS.signatureS, REPORT_OFFSETS.signatureS + 72)),
320
- };
321
- if (!p384.verify(sig, attestationReport.slice(0, 672), new Uint8Array(publicKey), { prehash: true })) {
457
+ const { requirements, publicKey, vcekTcb } = yield this._verifyVcekChain(vcekChain);
458
+ if (!equalBytes(attestationReport.slice(REPORT_OFFSETS.signatureR + 48, REPORT_OFFSETS.signatureR + 72), new Uint8Array(24)) ||
459
+ !equalBytes(attestationReport.slice(REPORT_OFFSETS.signatureS + 48, REPORT_OFFSETS.signatureS + 72), new Uint8Array(24))) {
460
+ throw new Error("Unexpected signature bits");
461
+ }
462
+ const sig = new Uint8Array(96);
463
+ sig.set(attestationReport
464
+ .slice(REPORT_OFFSETS.signatureR, REPORT_OFFSETS.signatureR + 48)
465
+ // Change endianness
466
+ .reverse(), 0);
467
+ sig.set(attestationReport
468
+ .slice(REPORT_OFFSETS.signatureS, REPORT_OFFSETS.signatureS + 48)
469
+ // Change endianness
470
+ .reverse(), 48);
471
+ let valid;
472
+ try {
473
+ valid = p384.verify(sig, attestationReport.slice(0, 672), new Uint8Array(publicKey), { lowS: false });
474
+ }
475
+ catch (_a) {
476
+ valid = false;
477
+ }
478
+ if (!valid) {
322
479
  throw new Error("Verification failed: Invalid attestation report signature");
323
480
  }
324
481
  if ((attestationReport[REPORT_OFFSETS.platInfo] &
@@ -335,9 +492,10 @@ export class KeySettlement {
335
492
  throw new Error("Verification failed: Firmware version too small");
336
493
  }
337
494
  if (attestationReport[REPORT_OFFSETS.committedTcbSnp] <
338
- requirements.minCommitedTcbSnp) {
495
+ requirements.minCommittedTcbSnp) {
339
496
  throw new Error("Verification failed: SNP patch level too small");
340
497
  }
498
+ yield this._verifyTcbVersion(attestationReport, vcekTcb);
341
499
  });
342
500
  }
343
501
  _verifyVcekChain(vcek) {
@@ -353,11 +511,14 @@ export class KeySettlement {
353
511
  if (chain.length != 3) {
354
512
  throw new Error(`Certificate chain verification failed\n\nChain: ${chain}`);
355
513
  }
356
- const productExt = chain[0].extensions.find((ext) => ext.type == "1.3.6.1.4.1.3704.1.2");
357
- if (!productExt) {
358
- throw new Error(`Could not find product name\n\nExtensions: ${chain[0].extensions}`);
359
- }
360
- const productIA5String = new Uint8Array(productExt.value);
514
+ const find_extension = (oid, type) => {
515
+ const ext = chain[0].extensions.find((ext) => ext.type == oid);
516
+ if (!ext) {
517
+ throw new Error(`Could not find ${type}\n\nExtensions: ${chain[0].extensions}`);
518
+ }
519
+ return new Uint8Array(ext.value);
520
+ };
521
+ const productIA5String = find_extension("1.3.6.1.4.1.3704.1.2", "product name");
361
522
  if (productIA5String[0] !== 0x16) {
362
523
  throw new Error(`Unexpected product extension: ${productIA5String}`);
363
524
  }
@@ -366,9 +527,25 @@ export class KeySettlement {
366
527
  throw new Error(`Unexpected product: ${product}`);
367
528
  }
368
529
  const subjectPublicKeyInfo = AsnConvert.parse(chain[0].publicKey.rawData, SubjectPublicKeyInfo);
530
+ const bootloader = find_extension("1.3.6.1.4.1.3704.1.3.1", "bootloader version")[2];
531
+ const tee = find_extension("1.3.6.1.4.1.3704.1.3.2", "TEE")[2];
532
+ const snp = find_extension("1.3.6.1.4.1.3704.1.3.3", "SNP version")[2];
533
+ const microcode = find_extension("1.3.6.1.4.1.3704.1.3.8", "microcode")[2];
534
+ const tcb = {
535
+ bootloader: bootloader,
536
+ tee: tee,
537
+ snp: snp,
538
+ microcode: microcode,
539
+ fmc: 0,
540
+ };
541
+ const fmc = chain[0].extensions.find((ext) => ext.type == "1.3.6.1.4.1.3704.1.3.9");
542
+ if (fmc) {
543
+ tcb.fmc = new Uint8Array(fmc.value)[2];
544
+ }
369
545
  return {
370
546
  requirements: this._requirements[product],
371
547
  publicKey: new Uint8Array(subjectPublicKeyInfo.subjectPublicKey),
548
+ vcekTcb: tcb,
372
549
  };
373
550
  });
374
551
  }
@@ -381,7 +558,7 @@ export function bytesToBinaryString(bytes) {
381
558
  }
382
559
  function _createCipher(publicKey, secretKey, info, nonce) {
383
560
  const sharedSecret = x25519.getSharedSecret(secretKey, publicKey);
384
- const key = hkdf(wrapConstructor(() => blake2b.create({ dkLen: 64 })), sharedSecret, Uint8Array.from([]), info, 32);
561
+ const key = hkdf(createHasher(() => blake2b.create({ dkLen: 64 })), sharedSecret, Uint8Array.from([]), info, 32);
385
562
  return chacha20poly1305(key, nonce);
386
563
  }
387
564
  function _getInfo(ephemeralPublicKey, recipientPublicKey) {
@@ -402,6 +579,9 @@ const REPORT_OFFSETS = {
402
579
  platInfo: 64,
403
580
  reportData: 80,
404
581
  measurement: 144,
582
+ reportedTcb: 384,
583
+ cpuIdFamily: 392,
584
+ chipId: 416,
405
585
  committedTcbSnp: 486,
406
586
  committedBuild: 492,
407
587
  committedMinor: 493,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routex-settlement",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Key settlement for the YAXI routex client",
5
5
  "homepage": "https://yaxi.tech",
6
6
  "author": "YAXI GmbH",
@@ -16,13 +16,14 @@
16
16
  "scripts": {
17
17
  "build": "tsc --build",
18
18
  "clean": "tsc --build --clean",
19
+ "fmt": "prettier --write .",
19
20
  "lint": "eslint",
20
21
  "test": "tsc --build && NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest"
21
22
  },
22
23
  "dependencies": {
23
- "@noble/ciphers": "^1.2.1",
24
- "@noble/curves": "^1.8.1",
25
- "@noble/hashes": "^1.7.1",
24
+ "@noble/ciphers": "^2.0.0",
25
+ "@noble/curves": "^2.0.0",
26
+ "@noble/hashes": "^2.0.0",
26
27
  "@peculiar/asn1-schema": "^2.3.15",
27
28
  "@peculiar/asn1-x509": "^2.3.15",
28
29
  "@peculiar/x509": "^1.12.3"
@@ -31,7 +32,8 @@
31
32
  "@eslint/js": "^9.21.0",
32
33
  "eslint": "^9.21.0",
33
34
  "globals": "^16.0.0",
34
- "jest": "^29.7.0",
35
+ "jest": "^30.1.3",
36
+ "prettier": "^3.6.2",
35
37
  "typescript": "^5.7.3",
36
38
  "typescript-eslint": "^8.24.1"
37
39
  }