routex-settlement 0.1.5 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +2 -2
- package/index.js +109 -76
- package/package.json +4 -3
- package/util.d.ts +2 -1
package/index.d.ts
CHANGED
|
@@ -8,10 +8,10 @@ export declare class KeySettlement {
|
|
|
8
8
|
private _yaxiSigningKeys?;
|
|
9
9
|
private _serverKey?;
|
|
10
10
|
private _settlementPromise?;
|
|
11
|
-
private
|
|
11
|
+
private _systemVersion?;
|
|
12
12
|
constructor(url: URL, onErrorResponse: (response: Response) => void, onRequestError?: (e: Error) => never);
|
|
13
13
|
private _settle;
|
|
14
|
-
|
|
14
|
+
systemVersion(): string | undefined;
|
|
15
15
|
private _getServerKey;
|
|
16
16
|
getBase64SessionId(settlementHeaders?: HeadersInit): Promise<string>;
|
|
17
17
|
seal(plaintext: Uint8Array, settlementHeaders?: HeadersInit): Promise<Uint8Array<ArrayBuffer>>;
|
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { sha256 } from '@noble/hashes/sha2.js';
|
|
|
9
9
|
import { AsnConvert } from '@peculiar/asn1-schema';
|
|
10
10
|
import { SubjectPublicKeyInfo } from '@peculiar/asn1-x509';
|
|
11
11
|
import * as x509 from '@peculiar/x509';
|
|
12
|
+
import { fromBER, Integer, IA5String } from 'asn1js';
|
|
12
13
|
|
|
13
14
|
/******************************************************************************
|
|
14
15
|
Copyright (c) Microsoft Corporation.
|
|
@@ -46,14 +47,17 @@ const REQUIREMENTS = {
|
|
|
46
47
|
Genoa: {
|
|
47
48
|
minCommittedVersion: [0x1, 0x37, 0x31],
|
|
48
49
|
minCommittedTcbSnp: 0x1b,
|
|
50
|
+
minMitVector: (1 << 0) | (1 << 1),
|
|
49
51
|
},
|
|
50
52
|
Milan: {
|
|
51
53
|
minCommittedVersion: [0x1, 0x37, 0x23],
|
|
52
54
|
minCommittedTcbSnp: 0x1b,
|
|
55
|
+
minMitVector: 1 << 1,
|
|
53
56
|
},
|
|
54
57
|
Turin: {
|
|
55
58
|
minCommittedVersion: [0x1, 0x37, 0x41],
|
|
56
59
|
minCommittedTcbSnp: 0x04,
|
|
60
|
+
minMitVector: (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5),
|
|
57
61
|
},
|
|
58
62
|
};
|
|
59
63
|
const YAXI_SIGNING_KEYS = {
|
|
@@ -364,49 +368,30 @@ function verifyAttestation(response, requirements, signingKeys) {
|
|
|
364
368
|
if (!equalBytes(attestationReport.slice(REPORT_OFFSETS.measurement, REPORT_OFFSETS.measurement + 48), launchMeasurementInSystemVersion)) {
|
|
365
369
|
throw new Error("Reported measurement doesn't match expected measurement");
|
|
366
370
|
}
|
|
367
|
-
return launchMeasurementInSystemVersion;
|
|
368
371
|
});
|
|
369
372
|
}
|
|
370
|
-
function
|
|
373
|
+
function parseTcbVersion(tcbBytes, product) {
|
|
374
|
+
if (product === "Turin") {
|
|
375
|
+
return {
|
|
376
|
+
fmc: tcbBytes[0],
|
|
377
|
+
bootloader: tcbBytes[1],
|
|
378
|
+
tee: tcbBytes[2],
|
|
379
|
+
snp: tcbBytes[3],
|
|
380
|
+
microcode: tcbBytes[7],
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
bootloader: tcbBytes[0],
|
|
385
|
+
tee: tcbBytes[1],
|
|
386
|
+
snp: tcbBytes[6],
|
|
387
|
+
microcode: tcbBytes[7],
|
|
388
|
+
fmc: 0,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function _verifyTcbVersion(attestationReport, product, vcekTcb) {
|
|
371
392
|
return __awaiter(this, void 0, void 0, function* () {
|
|
372
|
-
const versionBytes = attestationReport.slice(0, 4);
|
|
373
|
-
const version = new DataView(versionBytes.buffer).getInt32(0, true);
|
|
374
|
-
let turinLike;
|
|
375
|
-
switch (version) {
|
|
376
|
-
case 0:
|
|
377
|
-
case 1:
|
|
378
|
-
throw new Error("Unsupported Attestation Report Version");
|
|
379
|
-
case 2: {
|
|
380
|
-
const chipId = attestationReport.slice(REPORT_OFFSETS.chipId, 64);
|
|
381
|
-
if (equalBytes(chipId, new Uint8Array(64))) {
|
|
382
|
-
throw new Error("Could not derive CPU family: MASK_CHIP_ID enabled");
|
|
383
|
-
}
|
|
384
|
-
turinLike = equalBytes(chipId.slice(8), new Uint8Array(56));
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
default: // from version 3 onwards CPUID_FAM_ID field should exist
|
|
388
|
-
turinLike = attestationReport[REPORT_OFFSETS.cpuIdFamily] == 0x1a;
|
|
389
|
-
}
|
|
390
393
|
const reportedTcb = attestationReport.slice(REPORT_OFFSETS.reportedTcb, REPORT_OFFSETS.reportedTcb + 8);
|
|
391
|
-
|
|
392
|
-
if (turinLike) {
|
|
393
|
-
tcb = {
|
|
394
|
-
microcode: reportedTcb[7],
|
|
395
|
-
snp: reportedTcb[3],
|
|
396
|
-
tee: reportedTcb[2],
|
|
397
|
-
bootloader: reportedTcb[1],
|
|
398
|
-
fmc: reportedTcb[0],
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
tcb = {
|
|
403
|
-
microcode: reportedTcb[7],
|
|
404
|
-
snp: reportedTcb[6],
|
|
405
|
-
tee: reportedTcb[1],
|
|
406
|
-
bootloader: reportedTcb[0],
|
|
407
|
-
fmc: 0,
|
|
408
|
-
};
|
|
409
|
-
}
|
|
394
|
+
const tcb = parseTcbVersion(reportedTcb, product);
|
|
410
395
|
if (!(tcb.microcode === vcekTcb.microcode &&
|
|
411
396
|
tcb.snp === vcekTcb.snp &&
|
|
412
397
|
tcb.tee === vcekTcb.tee &&
|
|
@@ -423,6 +408,10 @@ function _verifyReport(attestationReport, vcekChain, requirementsMap) {
|
|
|
423
408
|
}
|
|
424
409
|
const { product, publicKey, vcekTcb } = yield _verifyVcekChain(vcekChain, requirementsMap);
|
|
425
410
|
const requirements = requirementsMap[product];
|
|
411
|
+
const sigAlgo = attestationReport[REPORT_OFFSETS.sigAlgo];
|
|
412
|
+
if (sigAlgo !== 0x1) {
|
|
413
|
+
throw new Error(`Verification failed: Unsupported signature algorithm ${sigAlgo}, only ECDSA P-384 with SHA-384 (0x1) is supported`);
|
|
414
|
+
}
|
|
426
415
|
if (!equalBytes(attestationReport.slice(REPORT_OFFSETS.signatureR + 48, REPORT_OFFSETS.signatureR + 72), new Uint8Array(24)) ||
|
|
427
416
|
!equalBytes(attestationReport.slice(REPORT_OFFSETS.signatureS + 48, REPORT_OFFSETS.signatureS + 72), new Uint8Array(24))) {
|
|
428
417
|
throw new Error("Unexpected signature bits");
|
|
@@ -451,18 +440,49 @@ function _verifyReport(attestationReport, vcekChain, requirementsMap) {
|
|
|
451
440
|
0) {
|
|
452
441
|
throw new Error("Verification failed: Alias check complete is false");
|
|
453
442
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
443
|
+
const debugAllowed = attestationReport[REPORT_OFFSETS.policy + Math.floor(GUEST_POLICY_BITS.debugAllowed / 8)] &
|
|
444
|
+
(1 << GUEST_POLICY_BITS.debugAllowed % 8);
|
|
445
|
+
if (debugAllowed) {
|
|
446
|
+
throw new Error("Verification failed: Debug mode is enabled in guest policy");
|
|
447
|
+
}
|
|
448
|
+
const vmpl = new DataView(attestationReport.buffer, attestationReport.byteOffset + REPORT_OFFSETS.vmpl, 4).getUint32(0, true);
|
|
449
|
+
if (vmpl > 3) {
|
|
450
|
+
throw new Error(`Verification failed: Unexpected VMPL ${vmpl}`);
|
|
451
|
+
}
|
|
452
|
+
const signingKey = (attestationReport[REPORT_OFFSETS.keyInfo] >> KEY_INFO_BITS.signingKey) &
|
|
453
|
+
((1 << 3) - 1);
|
|
454
|
+
if (signingKey !== 0) {
|
|
455
|
+
throw new Error("Verification failed: Report is not signed by a VCEK");
|
|
456
|
+
}
|
|
457
|
+
const reportedVersion = (attestationReport[REPORT_OFFSETS.committedMajor] << 16) |
|
|
458
|
+
(attestationReport[REPORT_OFFSETS.committedMinor] << 8) |
|
|
459
|
+
attestationReport[REPORT_OFFSETS.committedBuild];
|
|
460
|
+
const requiredVersion = (requirements.minCommittedVersion[0] << 16) |
|
|
461
|
+
(requirements.minCommittedVersion[1] << 8) |
|
|
462
|
+
requirements.minCommittedVersion[2];
|
|
463
|
+
if (reportedVersion < requiredVersion) {
|
|
460
464
|
throw new Error("Verification failed: Firmware version too small");
|
|
461
465
|
}
|
|
462
|
-
|
|
463
|
-
|
|
466
|
+
const committedTcb = parseTcbVersion(attestationReport.slice(REPORT_OFFSETS.committedTcb, REPORT_OFFSETS.committedTcb + 8), product);
|
|
467
|
+
if (committedTcb.snp < requirements.minCommittedTcbSnp) {
|
|
464
468
|
throw new Error("Verification failed: SNP patch level too small");
|
|
465
469
|
}
|
|
470
|
+
if (requirements.minMitVector !== undefined) {
|
|
471
|
+
const reportView = new DataView(attestationReport.buffer, attestationReport.byteOffset, attestationReport.byteLength);
|
|
472
|
+
const reportVersion = reportView.getUint32(REPORT_OFFSETS.version, true);
|
|
473
|
+
const min = BigInt(requirements.minMitVector);
|
|
474
|
+
const checkMitVector = (offset, label) => {
|
|
475
|
+
if (reportVersion < 5) {
|
|
476
|
+
throw new Error(`Verification failed: ${label} mitigation vector not present in report`);
|
|
477
|
+
}
|
|
478
|
+
const value = reportView.getBigUint64(offset, true);
|
|
479
|
+
if ((value & min) !== min) {
|
|
480
|
+
throw new Error(`Verification failed: ${label} mitigation vector required bits not set`);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
checkMitVector(REPORT_OFFSETS.currentMitVector, "Current");
|
|
484
|
+
checkMitVector(REPORT_OFFSETS.launchMitVector, "Launch");
|
|
485
|
+
}
|
|
466
486
|
const cpuModel = attestationReport[REPORT_OFFSETS.cpuIdModel];
|
|
467
487
|
const cpuStep = attestationReport[REPORT_OFFSETS.cpuIdStep];
|
|
468
488
|
let requiredMicrocode;
|
|
@@ -474,7 +494,7 @@ function _verifyReport(attestationReport, vcekChain, requirementsMap) {
|
|
|
474
494
|
}
|
|
475
495
|
else if (cpuModel === 1 && cpuStep === 2) {
|
|
476
496
|
// Milan-X
|
|
477
|
-
requiredMicrocode =
|
|
497
|
+
requiredMicrocode = 0x47;
|
|
478
498
|
}
|
|
479
499
|
break;
|
|
480
500
|
}
|
|
@@ -498,29 +518,29 @@ function _verifyReport(attestationReport, vcekChain, requirementsMap) {
|
|
|
498
518
|
case "Turin":
|
|
499
519
|
if (cpuModel === 2 && cpuStep === 1) {
|
|
500
520
|
// Turin Classic
|
|
501
|
-
requiredMicrocode =
|
|
521
|
+
requiredMicrocode = 0x51;
|
|
502
522
|
}
|
|
503
523
|
else if (cpuModel === 0x11 && cpuStep === 0) {
|
|
504
524
|
// Turin Dense
|
|
505
|
-
requiredMicrocode =
|
|
506
|
-
}
|
|
507
|
-
else if (cpuModel > 2 ||
|
|
508
|
-
(cpuModel === 2 && cpuStep > 1) ||
|
|
509
|
-
(cpuModel === 0x11 && cpuStep > 0)) {
|
|
510
|
-
// Accept any newer models/steppings for Turin
|
|
511
|
-
requiredMicrocode = 0;
|
|
525
|
+
requiredMicrocode = 0x4e;
|
|
512
526
|
}
|
|
513
527
|
}
|
|
514
528
|
if (requiredMicrocode === undefined) {
|
|
515
529
|
throw new Error("Verification failed: Report doesn't match any known CPU family");
|
|
516
530
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
throw new Error("Verification failed: Reported microcode version too small");
|
|
531
|
+
if (committedTcb.microcode < requiredMicrocode) {
|
|
532
|
+
throw new Error("Verification failed: Committed microcode version too small");
|
|
520
533
|
}
|
|
521
|
-
yield _verifyTcbVersion(attestationReport, vcekTcb);
|
|
534
|
+
yield _verifyTcbVersion(attestationReport, product, vcekTcb);
|
|
522
535
|
});
|
|
523
536
|
}
|
|
537
|
+
function readExtensionInt(ext) {
|
|
538
|
+
const { result } = fromBER(ext);
|
|
539
|
+
if (!(result instanceof Integer)) {
|
|
540
|
+
throw new Error("Expected ASN.1 INTEGER");
|
|
541
|
+
}
|
|
542
|
+
return result.valueBlock.valueDec;
|
|
543
|
+
}
|
|
524
544
|
function _verifyVcekChain(vcek, requirements) {
|
|
525
545
|
return __awaiter(this, void 0, void 0, function* () {
|
|
526
546
|
let cert;
|
|
@@ -541,19 +561,20 @@ function _verifyVcekChain(vcek, requirements) {
|
|
|
541
561
|
}
|
|
542
562
|
return new Uint8Array(ext.value);
|
|
543
563
|
};
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
|
|
564
|
+
const productExtension = find_extension("1.3.6.1.4.1.3704.1.2", "product name");
|
|
565
|
+
const { result: productIA5String } = fromBER(productExtension);
|
|
566
|
+
if (!(productIA5String instanceof IA5String)) {
|
|
567
|
+
throw new Error("Expected ASN.1 IA5String for product extension");
|
|
547
568
|
}
|
|
548
|
-
const product =
|
|
569
|
+
const product = productIA5String.valueBlock.value.split("-", 1)[0];
|
|
549
570
|
if (!Object.prototype.hasOwnProperty.call(requirements, product)) {
|
|
550
571
|
throw new Error(`Unexpected product: ${product}`);
|
|
551
572
|
}
|
|
552
573
|
const subjectPublicKeyInfo = AsnConvert.parse(chain[0].publicKey.rawData, SubjectPublicKeyInfo);
|
|
553
|
-
const bootloader = find_extension("1.3.6.1.4.1.3704.1.3.1", "bootloader version")
|
|
554
|
-
const tee = find_extension("1.3.6.1.4.1.3704.1.3.2", "TEE")
|
|
555
|
-
const snp = find_extension("1.3.6.1.4.1.3704.1.3.3", "SNP version")
|
|
556
|
-
const microcode = find_extension("1.3.6.1.4.1.3704.1.3.8", "microcode")
|
|
574
|
+
const bootloader = readExtensionInt(find_extension("1.3.6.1.4.1.3704.1.3.1", "bootloader version"));
|
|
575
|
+
const tee = readExtensionInt(find_extension("1.3.6.1.4.1.3704.1.3.2", "TEE"));
|
|
576
|
+
const snp = readExtensionInt(find_extension("1.3.6.1.4.1.3704.1.3.3", "SNP version"));
|
|
577
|
+
const microcode = readExtensionInt(find_extension("1.3.6.1.4.1.3704.1.3.8", "microcode"));
|
|
557
578
|
const tcb = {
|
|
558
579
|
bootloader: bootloader,
|
|
559
580
|
tee: tee,
|
|
@@ -563,7 +584,7 @@ function _verifyVcekChain(vcek, requirements) {
|
|
|
563
584
|
};
|
|
564
585
|
const fmc = chain[0].extensions.find((ext) => ext.type == "1.3.6.1.4.1.3704.1.3.9");
|
|
565
586
|
if (fmc) {
|
|
566
|
-
tcb.fmc = new Uint8Array(fmc.value)
|
|
587
|
+
tcb.fmc = readExtensionInt(new Uint8Array(fmc.value));
|
|
567
588
|
}
|
|
568
589
|
return {
|
|
569
590
|
product: product,
|
|
@@ -594,24 +615,35 @@ function _getSealNonce(ephemeralPublicKey, recipientPublicKey) {
|
|
|
594
615
|
.digest();
|
|
595
616
|
}
|
|
596
617
|
const REPORT_OFFSETS = {
|
|
618
|
+
version: 0,
|
|
619
|
+
policy: 8,
|
|
620
|
+
vmpl: 48,
|
|
621
|
+
sigAlgo: 52,
|
|
597
622
|
platInfo: 64,
|
|
623
|
+
keyInfo: 72,
|
|
598
624
|
reportData: 80,
|
|
599
625
|
measurement: 144,
|
|
600
626
|
reportedTcb: 384,
|
|
601
|
-
cpuIdFamily: 392,
|
|
602
627
|
cpuIdModel: 393,
|
|
603
628
|
cpuIdStep: 394,
|
|
604
|
-
|
|
605
|
-
committedTcbSnp: 486,
|
|
629
|
+
committedTcb: 480,
|
|
606
630
|
committedBuild: 492,
|
|
607
631
|
committedMinor: 493,
|
|
608
632
|
committedMajor: 494,
|
|
633
|
+
launchMitVector: 504,
|
|
634
|
+
currentMitVector: 512,
|
|
609
635
|
signatureR: 672,
|
|
610
636
|
signatureS: 744,
|
|
611
637
|
};
|
|
612
638
|
const PLATFORM_INFO_BITS = {
|
|
613
639
|
aliasCheckComplete: 5,
|
|
614
640
|
};
|
|
641
|
+
const GUEST_POLICY_BITS = {
|
|
642
|
+
debugAllowed: 19,
|
|
643
|
+
};
|
|
644
|
+
const KEY_INFO_BITS = {
|
|
645
|
+
signingKey: 2,
|
|
646
|
+
};
|
|
615
647
|
function bytesToUtf8(bytes) {
|
|
616
648
|
return __awaiter(this, void 0, void 0, function* () {
|
|
617
649
|
return new TextDecoder().decode(bytes);
|
|
@@ -623,6 +655,7 @@ if (typeof process !== "undefined" && process.env.NODE_ENV === "test") {
|
|
|
623
655
|
_testing$1.YAXI_SIGNING_KEYS = YAXI_SIGNING_KEYS;
|
|
624
656
|
_testing$1.verifyReport = _verifyReport;
|
|
625
657
|
_testing$1.verifyTcbVersion = _verifyTcbVersion;
|
|
658
|
+
_testing$1.readExtensionInt = readExtensionInt;
|
|
626
659
|
}
|
|
627
660
|
|
|
628
661
|
class KeySettlement {
|
|
@@ -654,17 +687,17 @@ class KeySettlement {
|
|
|
654
687
|
throw yield this._onErrorResponse(response);
|
|
655
688
|
}
|
|
656
689
|
const responseData = yield response.json();
|
|
657
|
-
|
|
690
|
+
yield verifyAttestation(responseData, this._requirements, this._yaxiSigningKeys);
|
|
658
691
|
const settlementBoxMessage = JSON.parse(yield bytesToUtf8(this.unseal(binaryStringToBytes(atob(responseData.chachaBox)))));
|
|
659
692
|
this._serverKey = {
|
|
660
693
|
publicKey: binaryStringToBytes(atob(settlementBoxMessage.publicKey)),
|
|
661
694
|
base64SessionId: settlementBoxMessage.sessionId,
|
|
662
695
|
};
|
|
663
|
-
this.
|
|
696
|
+
this._systemVersion = JSON.stringify(responseData.systemVersion);
|
|
664
697
|
});
|
|
665
698
|
}
|
|
666
|
-
|
|
667
|
-
return this.
|
|
699
|
+
systemVersion() {
|
|
700
|
+
return this._systemVersion;
|
|
668
701
|
}
|
|
669
702
|
_getServerKey(settlementHeaders) {
|
|
670
703
|
return __awaiter(this, void 0, void 0, function* () {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "routex-settlement",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Key settlement for the YAXI routex client",
|
|
5
5
|
"homepage": "https://yaxi.tech",
|
|
6
6
|
"author": "YAXI GmbH",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"util.d.ts"
|
|
16
16
|
],
|
|
17
17
|
"scripts": {
|
|
18
|
-
"build": "rollup --input index.ts --dir . --plugin typescript --external @noble/ciphers/chacha.js,@noble/curves/ed25519.js,@noble/curves/nist.js,@noble/curves/utils.js,@noble/hashes/blake2.js,@noble/hashes/hkdf.js,@noble/hashes/sha2.js,@noble/hashes/utils.js,@peculiar/asn1-schema,@peculiar/asn1-x509,@peculiar/x509",
|
|
18
|
+
"build": "rollup --input index.ts --dir . --plugin typescript --external @noble/ciphers/chacha.js,@noble/curves/ed25519.js,@noble/curves/nist.js,@noble/curves/utils.js,@noble/hashes/blake2.js,@noble/hashes/hkdf.js,@noble/hashes/sha2.js,@noble/hashes/utils.js,@peculiar/asn1-schema,@peculiar/asn1-x509,@peculiar/x509,asn1js",
|
|
19
19
|
"clean": "tsc --build --clean",
|
|
20
20
|
"fmt": "prettier --write .",
|
|
21
21
|
"lint": "eslint",
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"@noble/hashes": "^2.0.0",
|
|
28
28
|
"@peculiar/asn1-schema": "^2.3.15",
|
|
29
29
|
"@peculiar/asn1-x509": "^2.3.15",
|
|
30
|
-
"@peculiar/x509": "^1.12.3"
|
|
30
|
+
"@peculiar/x509": "^1.12.3",
|
|
31
|
+
"asn1js": "^3.0.6"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@eslint/js": "^9.21.0",
|
package/util.d.ts
CHANGED
|
@@ -30,9 +30,10 @@ type Requirements = {
|
|
|
30
30
|
[id: string]: {
|
|
31
31
|
minCommittedVersion: [number, number, number];
|
|
32
32
|
minCommittedTcbSnp: number;
|
|
33
|
+
minMitVector?: number;
|
|
33
34
|
};
|
|
34
35
|
};
|
|
35
|
-
export declare function verifyAttestation(response: SettlementResponse, requirements?: Requirements, signingKeys?: typeof YAXI_SIGNING_KEYS): Promise<
|
|
36
|
+
export declare function verifyAttestation(response: SettlementResponse, requirements?: Requirements, signingKeys?: typeof YAXI_SIGNING_KEYS): Promise<void>;
|
|
36
37
|
export declare function bytesToUtf8(bytes: Uint8Array): Promise<string>;
|
|
37
38
|
export declare const _testing: {
|
|
38
39
|
[Key: string]: unknown;
|