@super-protocol/sdk-js 3.15.1 → 3.15.3-beta.0
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/dist/cjs/RIGenerator.js +2 -2
- package/dist/cjs/TIIGenerator.js +4 -4
- package/dist/cjs/TeeInputGeneratorBase.d.ts +2 -2
- package/dist/cjs/TeeInputGeneratorBase.js +5 -5
- package/dist/cjs/contracts/abi.d.ts +799 -708
- package/dist/cjs/contracts/abi.js +966 -854
- package/dist/cjs/index.d.ts +0 -1
- package/dist/cjs/index.js +3 -5
- package/dist/cjs/models/Provider.d.ts +0 -1
- package/dist/cjs/models/Provider.js +1 -7
- package/dist/cjs/models/TCB.d.ts +1 -28
- package/dist/cjs/models/TCB.js +1 -61
- package/dist/cjs/models/TeeOffer.d.ts +3 -18
- package/dist/cjs/models/TeeOffer.js +14 -100
- package/dist/cjs/providers/storage/fs-storage-provider.js +35 -15
- package/dist/cjs/staticModels/Consensus.d.ts +5 -16
- package/dist/cjs/staticModels/Consensus.js +16 -86
- package/dist/cjs/staticModels/TeeOffers.d.ts +0 -6
- package/dist/cjs/staticModels/TeeOffers.js +3 -14
- package/dist/cjs/tee/TeeBlockVerifier.d.ts +7 -2
- package/dist/cjs/tee/TeeBlockVerifier.js +6 -18
- package/dist/cjs/tee/statuses.d.ts +0 -7
- package/dist/cjs/tee/statuses.js +2 -10
- package/dist/cjs/types/Consensus.d.ts +5 -31
- package/dist/cjs/types/Consensus.js +2 -10
- package/dist/cjs/utils/helper.d.ts +3 -5
- package/dist/cjs/utils/helper.js +94 -34
- package/dist/mjs/RIGenerator.js +2 -2
- package/dist/mjs/TIIGenerator.js +4 -4
- package/dist/mjs/TeeInputGeneratorBase.d.ts +2 -2
- package/dist/mjs/TeeInputGeneratorBase.js +5 -5
- package/dist/mjs/contracts/abi.d.ts +799 -708
- package/dist/mjs/contracts/abi.js +964 -852
- package/dist/mjs/index.d.ts +0 -1
- package/dist/mjs/index.js +1 -2
- package/dist/mjs/models/Provider.d.ts +0 -1
- package/dist/mjs/models/Provider.js +1 -7
- package/dist/mjs/models/TCB.d.ts +1 -28
- package/dist/mjs/models/TCB.js +2 -62
- package/dist/mjs/models/TeeOffer.d.ts +3 -18
- package/dist/mjs/models/TeeOffer.js +9 -95
- package/dist/mjs/providers/storage/fs-storage-provider.js +35 -15
- package/dist/mjs/staticModels/Consensus.d.ts +5 -16
- package/dist/mjs/staticModels/Consensus.js +17 -87
- package/dist/mjs/staticModels/TeeOffers.d.ts +0 -6
- package/dist/mjs/staticModels/TeeOffers.js +4 -15
- package/dist/mjs/tee/TeeBlockVerifier.d.ts +7 -2
- package/dist/mjs/tee/TeeBlockVerifier.js +6 -18
- package/dist/mjs/tee/statuses.d.ts +0 -7
- package/dist/mjs/tee/statuses.js +1 -9
- package/dist/mjs/types/Consensus.d.ts +5 -31
- package/dist/mjs/types/Consensus.js +1 -9
- package/dist/mjs/utils/helper.d.ts +3 -5
- package/dist/mjs/utils/helper.js +93 -31
- package/package.json +2 -2
- package/dist/cjs/tee/QuoteValidator.d.ts +0 -46
- package/dist/cjs/tee/QuoteValidator.js +0 -456
- package/dist/cjs/tee/TcbSerializer.d.ts +0 -20
- package/dist/cjs/tee/TcbSerializer.js +0 -27
- package/dist/mjs/tee/QuoteValidator.d.ts +0 -46
- package/dist/mjs/tee/QuoteValidator.js +0 -449
- package/dist/mjs/tee/TcbSerializer.d.ts +0 -20
- package/dist/mjs/tee/TcbSerializer.js +0 -23
|
@@ -1,456 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.QuoteValidator = void 0;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const elliptic_1 = __importDefault(require("elliptic"));
|
|
9
|
-
const node_forge_1 = __importDefault(require("node-forge"));
|
|
10
|
-
const x509_1 = require("@fidm/x509");
|
|
11
|
-
const js_encoding_utils_1 = require("js-encoding-utils");
|
|
12
|
-
const pkijs_1 = require("pkijs");
|
|
13
|
-
const asn1js_1 = require("asn1js");
|
|
14
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
15
|
-
const QuoteParser_js_1 = require("./QuoteParser.js");
|
|
16
|
-
const types_js_1 = require("./types.js");
|
|
17
|
-
const logger_js_1 = __importDefault(require("../logger.js"));
|
|
18
|
-
const errors_js_1 = require("./errors.js");
|
|
19
|
-
const statuses_js_1 = require("./statuses.js");
|
|
20
|
-
const dto_js_1 = require("@super-protocol/dto-js");
|
|
21
|
-
const index_js_1 = __importDefault(require("../crypto/index.js"));
|
|
22
|
-
const TeeSignatureVerifier_js_1 = require("./TeeSignatureVerifier.js");
|
|
23
|
-
const pki_common_1 = require("@super-protocol/pki-common");
|
|
24
|
-
const { ec } = elliptic_1.default;
|
|
25
|
-
const { util, asn1 } = node_forge_1.default;
|
|
26
|
-
const INTEL_BASE_SGX_URL = 'https://api.trustedservices.intel.com';
|
|
27
|
-
const INTEL_SGX_ROOT_CA_URL = 'https://certificates.trustedservices.intel.com/IntelSGXRootCA.der';
|
|
28
|
-
const SGX_OID = '1.2.840.113741.1.13.1';
|
|
29
|
-
const FMSPC_OID = `${SGX_OID}.4`;
|
|
30
|
-
const PCEID_OID = `${SGX_OID}.3`;
|
|
31
|
-
const TCB_OID = `${SGX_OID}.2`;
|
|
32
|
-
const PCESVN_OID = `${TCB_OID}.17`;
|
|
33
|
-
const INTEL_ROOT_PUB_KEY = new Uint8Array([
|
|
34
|
-
4, 11, 169, 196, 192, 192, 200, 97, 147, 163, 254, 35, 214, 176, 44, 218, 16, 168, 187, 212, 232,
|
|
35
|
-
142, 72, 180, 69, 133, 97, 163, 110, 112, 85, 37, 245, 103, 145, 142, 46, 220, 136, 228, 13, 134,
|
|
36
|
-
11, 208, 204, 78, 226, 106, 172, 201, 136, 229, 5, 169, 83, 85, 140, 69, 63, 107, 9, 4, 174, 115,
|
|
37
|
-
148,
|
|
38
|
-
]);
|
|
39
|
-
class QuoteValidator {
|
|
40
|
-
isDefault;
|
|
41
|
-
baseUrl;
|
|
42
|
-
teeSgxParser;
|
|
43
|
-
teeTdxParser;
|
|
44
|
-
logger;
|
|
45
|
-
constructor(baseUrl) {
|
|
46
|
-
this.isDefault = baseUrl === INTEL_BASE_SGX_URL;
|
|
47
|
-
this.baseUrl = `${baseUrl}/sgx/certification/v4`;
|
|
48
|
-
this.teeSgxParser = new QuoteParser_js_1.TeeSgxParser();
|
|
49
|
-
this.teeTdxParser = new QuoteParser_js_1.TeeTdxParser();
|
|
50
|
-
this.logger = logger_js_1.default.child({ className: QuoteValidator.name });
|
|
51
|
-
}
|
|
52
|
-
static getSignature(mrEnclave, challengeType, options) {
|
|
53
|
-
return TeeSignatureVerifier_js_1.TeeSignatureVerifier.getSignature(mrEnclave, challengeType, options);
|
|
54
|
-
}
|
|
55
|
-
static async checkSignature(quote, options = { getMrEnclaveSignature: TeeSignatureVerifier_js_1.TeeSignatureVerifier.getSignature }) {
|
|
56
|
-
const { type: quoteType } = QuoteParser_js_1.TeeSgxParser.determineQuoteType(quote);
|
|
57
|
-
switch (quoteType) {
|
|
58
|
-
case types_js_1.QuoteType.SGX: {
|
|
59
|
-
const parser = new QuoteParser_js_1.TeeSgxParser();
|
|
60
|
-
const parsedQuote = parser.parseQuote(quote);
|
|
61
|
-
const report = parser.parseReport(parsedQuote.report);
|
|
62
|
-
TeeSignatureVerifier_js_1.TeeSignatureVerifier.validateSignatureSgx(report.mrSigner);
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
case types_js_1.QuoteType.TDX: {
|
|
66
|
-
const mrEnclave = QuoteParser_js_1.TeeParser.getMrEnclave(quote);
|
|
67
|
-
await TeeSignatureVerifier_js_1.TeeSignatureVerifier.validateSignature(mrEnclave, pki_common_1.ChallengeType.TDX, options);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
splitChain(chain) {
|
|
73
|
-
const begin = '-----BEGIN CERTIFICATE-----';
|
|
74
|
-
const end = '-----END CERTIFICATE-----';
|
|
75
|
-
return chain
|
|
76
|
-
.split(begin)
|
|
77
|
-
.filter(Boolean)
|
|
78
|
-
.map((cert) => begin.concat(cert.slice(0, cert.indexOf(end)), end));
|
|
79
|
-
}
|
|
80
|
-
findSequenceByOID(hexValue, targetOID) {
|
|
81
|
-
const buffer = util.hexToBytes(hexValue);
|
|
82
|
-
const asn1Data = asn1.fromDer(buffer);
|
|
83
|
-
return this.searchForSequence(asn1Data, targetOID);
|
|
84
|
-
}
|
|
85
|
-
searchForSequence(asn1Data, targetOID) {
|
|
86
|
-
if (asn1Data.type === asn1.Type.SEQUENCE) {
|
|
87
|
-
for (const child of asn1Data.value) {
|
|
88
|
-
if (child.type === asn1.Type.OID) {
|
|
89
|
-
const oid = asn1.derToOid(child.value);
|
|
90
|
-
if (oid === targetOID) {
|
|
91
|
-
return asn1Data;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (Array.isArray(asn1Data.value)) {
|
|
97
|
-
for (const child of asn1Data.value) {
|
|
98
|
-
const result = this.searchForSequence(child, targetOID);
|
|
99
|
-
if (result) {
|
|
100
|
-
return result;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
verifyDataBySignature(data, signature, key) {
|
|
107
|
-
const ellipticEc = new ec('p256');
|
|
108
|
-
return ellipticEc.verify(data, {
|
|
109
|
-
r: signature.subarray(0, 32),
|
|
110
|
-
s: signature.subarray(32),
|
|
111
|
-
}, ellipticEc.keyFromPublic(key, 'hex'));
|
|
112
|
-
}
|
|
113
|
-
checkValidDate(from, to) {
|
|
114
|
-
const now = Date.now();
|
|
115
|
-
return from < now && now < to;
|
|
116
|
-
}
|
|
117
|
-
checkChainForIssuers(pckCert, platformCert, rootCert) {
|
|
118
|
-
return (lodash_1.default.isEqual(pckCert.issuer, platformCert.subject) &&
|
|
119
|
-
lodash_1.default.isEqual(platformCert.issuer, rootCert.subject));
|
|
120
|
-
}
|
|
121
|
-
getCrl(crlData) {
|
|
122
|
-
const crlDer = crlData.startsWith('-----')
|
|
123
|
-
? js_encoding_utils_1.formatter.pemToBin(crlData)
|
|
124
|
-
: Buffer.from(crlData, 'hex');
|
|
125
|
-
const crlAsn = (0, asn1js_1.fromBER)(crlDer);
|
|
126
|
-
return new pkijs_1.CertificateRevocationList({ schema: crlAsn.result });
|
|
127
|
-
}
|
|
128
|
-
checkCertificatesInCrl(crl, certIds) {
|
|
129
|
-
if (!crl.thisUpdate || !crl.nextUpdate) {
|
|
130
|
-
throw new errors_js_1.TeeQuoteValidatorError('Certificate revocation list has no update date field');
|
|
131
|
-
}
|
|
132
|
-
if (!this.checkValidDate(crl.thisUpdate.value.valueOf(), crl.nextUpdate.value.valueOf())) {
|
|
133
|
-
throw new errors_js_1.TeeQuoteValidatorError('Certificate revocation list has invalid update date');
|
|
134
|
-
}
|
|
135
|
-
if (crl.revokedCertificates) {
|
|
136
|
-
const isAnyRevoked = crl.revokedCertificates.find((revoked) => certIds.includes(Buffer.from(revoked.userCertificate.valueBlock.valueHexView).toString('hex')));
|
|
137
|
-
if (isAnyRevoked) {
|
|
138
|
-
throw new errors_js_1.TeeQuoteValidatorError('Certificate in revokation list');
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
async getCertificates(quote) {
|
|
143
|
-
const platformCrlResult = await axios_1.default.get(`${this.baseUrl}/pckcrl?ca=platform&encoding=pem`);
|
|
144
|
-
const platformChain = decodeURIComponent(platformCrlResult.headers['sgx-pck-crl-issuer-chain']);
|
|
145
|
-
const [platformFetchedPem, rootFetchedPem] = this.splitChain(platformChain); // [platform, root]
|
|
146
|
-
const platformFetchedCert = x509_1.Certificate.fromPEM(Buffer.from(platformFetchedPem));
|
|
147
|
-
const rootFetchedCert = x509_1.Certificate.fromPEM(Buffer.from(rootFetchedPem));
|
|
148
|
-
if (!this.checkValidDate(platformFetchedCert.validFrom.valueOf(), platformFetchedCert.validTo.valueOf())) {
|
|
149
|
-
throw new errors_js_1.TeeQuoteValidatorError('Platform certificate validation date is not valid');
|
|
150
|
-
}
|
|
151
|
-
if (!this.checkValidDate(rootFetchedCert.validFrom.valueOf(), rootFetchedCert.validTo.valueOf())) {
|
|
152
|
-
throw new errors_js_1.TeeQuoteValidatorError('Root certificate validation date is not valid');
|
|
153
|
-
}
|
|
154
|
-
if (!lodash_1.default.isEqual(rootFetchedCert.issuer, rootFetchedCert.subject)) {
|
|
155
|
-
throw new errors_js_1.TeeQuoteValidatorError('Root certificate is not self-signed');
|
|
156
|
-
}
|
|
157
|
-
if (Buffer.compare(rootFetchedCert.publicKey.keyRaw, INTEL_ROOT_PUB_KEY) !== 0) {
|
|
158
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong Intel root certificate public key');
|
|
159
|
-
}
|
|
160
|
-
const pckCert = x509_1.Certificate.fromPEM(Buffer.from(quote.certificates.device.pem));
|
|
161
|
-
const certType = quote.qeCertificationDataType;
|
|
162
|
-
if (!this.checkValidDate(pckCert.validFrom.valueOf(), pckCert.validTo.valueOf())) {
|
|
163
|
-
throw new errors_js_1.TeeQuoteValidatorError('PCK certificate validation date is not valid');
|
|
164
|
-
}
|
|
165
|
-
if (certType !== 5) {
|
|
166
|
-
throw new errors_js_1.TeeQuoteValidatorError(`Unsupported certification data type: ${certType}`);
|
|
167
|
-
}
|
|
168
|
-
if (rootFetchedPem !== quote.certificates.root.pem) {
|
|
169
|
-
throw new errors_js_1.TeeQuoteValidatorError("Invalid SGX root certificate in quote's certificate chain");
|
|
170
|
-
}
|
|
171
|
-
if (!this.checkChainForIssuers(pckCert, platformFetchedCert, rootFetchedCert)) {
|
|
172
|
-
throw new errors_js_1.TeeQuoteValidatorError('Invalid issuers in certificates chain');
|
|
173
|
-
}
|
|
174
|
-
const certIds = [
|
|
175
|
-
rootFetchedCert.serialNumber,
|
|
176
|
-
platformFetchedCert.serialNumber,
|
|
177
|
-
pckCert.serialNumber,
|
|
178
|
-
];
|
|
179
|
-
const caCrlUrl = this.isDefault
|
|
180
|
-
? INTEL_SGX_ROOT_CA_URL
|
|
181
|
-
: `${this.baseUrl}/crl?uri=${INTEL_SGX_ROOT_CA_URL}`;
|
|
182
|
-
const intelCrlDer = await axios_1.default.get(caCrlUrl, {
|
|
183
|
-
responseType: 'arraybuffer',
|
|
184
|
-
});
|
|
185
|
-
const intelCrlAsn = (0, asn1js_1.fromBER)(Buffer.from(intelCrlDer.data));
|
|
186
|
-
this.checkCertificatesInCrl(new pkijs_1.CertificateRevocationList({ schema: intelCrlAsn.result }), certIds);
|
|
187
|
-
const platformCrl = this.getCrl(platformCrlResult.data);
|
|
188
|
-
this.checkCertificatesInCrl(platformCrl, certIds);
|
|
189
|
-
return { pckCert, rootCertPem: rootFetchedPem };
|
|
190
|
-
}
|
|
191
|
-
async verifyQeReportSignature(quote, pckPublicKey) {
|
|
192
|
-
const signature = Buffer.from(quote.qeReportSignature);
|
|
193
|
-
const reportHash = await this.getSha256Hash(Buffer.from(quote.qeReport));
|
|
194
|
-
return this.verifyDataBySignature(reportHash, signature, pckPublicKey);
|
|
195
|
-
}
|
|
196
|
-
async verifyQeReportData(quote, report) {
|
|
197
|
-
const qeAuthData = quote.qeAuthenticationData;
|
|
198
|
-
const attestationKey = quote.ecdsaAttestationKey;
|
|
199
|
-
const qeReportDataHash = report.dataHash;
|
|
200
|
-
const calculatedHash = await this.getSha256Hash(Buffer.concat([attestationKey, qeAuthData]));
|
|
201
|
-
const result = Buffer.compare(qeReportDataHash, calculatedHash);
|
|
202
|
-
return result === 0;
|
|
203
|
-
}
|
|
204
|
-
async verifyEnclaveReportSignature(quote) {
|
|
205
|
-
const key = Buffer.from(quote.ecdsaAttestationKey);
|
|
206
|
-
const headerBuffer = Buffer.from(quote.rawHeader);
|
|
207
|
-
const reportBuffer = quote.quoteType === types_js_1.QuoteType.SGX
|
|
208
|
-
? Buffer.from(quote.report)
|
|
209
|
-
: Buffer.from(quote.tdQuoteBody);
|
|
210
|
-
const expected = quote.quoteType === types_js_1.QuoteType.SGX
|
|
211
|
-
? Buffer.from(quote.isvEnclaveReportSignature)
|
|
212
|
-
: Buffer.from(quote.quoteSignature);
|
|
213
|
-
const calculatedHash = await this.getSha256Hash(Buffer.concat([headerBuffer, reportBuffer]));
|
|
214
|
-
const ellipticEc = new ec('p256');
|
|
215
|
-
return ellipticEc.verify(calculatedHash, {
|
|
216
|
-
r: expected.subarray(0, 32),
|
|
217
|
-
s: expected.subarray(32),
|
|
218
|
-
}, Buffer.concat([Buffer.from([4]), key]));
|
|
219
|
-
}
|
|
220
|
-
async validateQuoteStructure(quote, report, pckPublicKey) {
|
|
221
|
-
if (!(await this.verifyQeReportSignature(quote, pckPublicKey))) {
|
|
222
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong QE report signature');
|
|
223
|
-
}
|
|
224
|
-
if (!(await this.verifyQeReportData(quote, report))) {
|
|
225
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong QE report data');
|
|
226
|
-
}
|
|
227
|
-
if (!(await this.verifyEnclaveReportSignature(quote))) {
|
|
228
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong enclave report signature');
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
getSgxExtensionData(pckCert) {
|
|
232
|
-
const sgxExtensionData = pckCert.extensions.find((item) => item.oid === SGX_OID);
|
|
233
|
-
if (!sgxExtensionData) {
|
|
234
|
-
throw new errors_js_1.TeeQuoteValidatorError('SGX data not found in PCK certificate');
|
|
235
|
-
}
|
|
236
|
-
return sgxExtensionData;
|
|
237
|
-
}
|
|
238
|
-
getDataFromExtension(sgxExtensionData, targetOid, targetType) {
|
|
239
|
-
const rawData = this.findSequenceByOID(sgxExtensionData.value.toString('hex'), targetOid);
|
|
240
|
-
if (!rawData) {
|
|
241
|
-
throw new errors_js_1.TeeQuoteValidatorError(`OID ${targetOid} not found in PCK certificate's SGX data`);
|
|
242
|
-
}
|
|
243
|
-
const data = rawData.value.filter((asnElement) => asnElement.type === targetType);
|
|
244
|
-
if (!data.length) {
|
|
245
|
-
throw new errors_js_1.TeeQuoteValidatorError(`Data on OID ${targetOid} of type ${targetType} not found`);
|
|
246
|
-
}
|
|
247
|
-
const result = util.bytesToHex(data[0].value);
|
|
248
|
-
return targetType === asn1.Type.OCTETSTRING ? result : parseInt(result, 16).toString();
|
|
249
|
-
}
|
|
250
|
-
async getTcbInfo(fmspc, rootCertPem, quoteType) {
|
|
251
|
-
let tcbUrl = `${this.baseUrl}/tcb?fmspc=${fmspc}`;
|
|
252
|
-
if (quoteType === types_js_1.QuoteType.TDX) {
|
|
253
|
-
tcbUrl = tcbUrl.replace('sgx/certification', 'tdx/certification');
|
|
254
|
-
}
|
|
255
|
-
const tcbData = await axios_1.default.get(tcbUrl);
|
|
256
|
-
const tcbInfoHeader = 'tcb-info-issuer-chain';
|
|
257
|
-
const tcbInfoChain = this.splitChain(decodeURIComponent(tcbData.headers[tcbInfoHeader])); // [tcb, root]
|
|
258
|
-
if (tcbInfoChain[1] !== rootCertPem) {
|
|
259
|
-
throw new errors_js_1.TeeQuoteValidatorError('Invalid SGX root certificate in TCB chain');
|
|
260
|
-
}
|
|
261
|
-
const tcbCert = x509_1.Certificate.fromPEM(Buffer.from(tcbInfoChain[0]));
|
|
262
|
-
const key = tcbCert.publicKey.keyRaw;
|
|
263
|
-
const signature = Buffer.from(tcbData.data.signature, 'hex');
|
|
264
|
-
const calculatedhash = await this.getSha256Hash(Buffer.from(JSON.stringify(tcbData.data.tcbInfo)));
|
|
265
|
-
const result = this.verifyDataBySignature(calculatedhash, signature, key);
|
|
266
|
-
if (!result) {
|
|
267
|
-
throw new errors_js_1.TeeQuoteValidatorError('TCB info signature is not valid');
|
|
268
|
-
}
|
|
269
|
-
if (tcbData.data.tcbInfo.nextUpdate.valueOf() > Date.now()) {
|
|
270
|
-
throw new errors_js_1.TeeQuoteValidatorError('TCB next update date is out of date');
|
|
271
|
-
}
|
|
272
|
-
return tcbData.data;
|
|
273
|
-
}
|
|
274
|
-
async getQEIdentity(rootCertPem, quoteType) {
|
|
275
|
-
let qeIdentityUrl = `${this.baseUrl}/qe/identity`;
|
|
276
|
-
if (quoteType === types_js_1.QuoteType.TDX) {
|
|
277
|
-
qeIdentityUrl = qeIdentityUrl.replace('sgx/certification', 'tdx/certification');
|
|
278
|
-
}
|
|
279
|
-
const qeIdentityData = await axios_1.default.get(qeIdentityUrl);
|
|
280
|
-
const qeIdentityHeader = 'sgx-enclave-identity-issuer-chain';
|
|
281
|
-
const qeIdentityChain = this.splitChain(decodeURIComponent(qeIdentityData.headers[qeIdentityHeader])); // [qeIdentity, root]
|
|
282
|
-
if (qeIdentityChain[1] !== rootCertPem) {
|
|
283
|
-
throw new errors_js_1.TeeQuoteValidatorError('Invalid SGX root certificate in enclave identity chain');
|
|
284
|
-
}
|
|
285
|
-
const qeIdentityCert = x509_1.Certificate.fromPEM(Buffer.from(qeIdentityChain[0]));
|
|
286
|
-
const key = qeIdentityCert.publicKey.keyRaw;
|
|
287
|
-
const signature = Buffer.from(qeIdentityData.data.signature, 'hex');
|
|
288
|
-
const calculatedhash = await this.getSha256Hash(Buffer.from(JSON.stringify(qeIdentityData.data.enclaveIdentity)));
|
|
289
|
-
const result = this.verifyDataBySignature(calculatedhash, signature, key);
|
|
290
|
-
if (!result) {
|
|
291
|
-
throw new errors_js_1.TeeQuoteValidatorError('Enclave identity signature is not valid');
|
|
292
|
-
}
|
|
293
|
-
if (qeIdentityData.data.enclaveIdentity.nextUpdate.valueOf() > Date.now()) {
|
|
294
|
-
throw new errors_js_1.TeeQuoteValidatorError('Enclave identity next update date is out of date');
|
|
295
|
-
}
|
|
296
|
-
return qeIdentityData.data;
|
|
297
|
-
}
|
|
298
|
-
getQEIdentityStatus(report, qeIdentity) {
|
|
299
|
-
const mrSigner = report.mrSigner.toString('hex');
|
|
300
|
-
if (mrSigner.toUpperCase() !== qeIdentity.enclaveIdentity.mrsigner) {
|
|
301
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong MR signer in QE report');
|
|
302
|
-
}
|
|
303
|
-
if (report.isvProdId !== qeIdentity.enclaveIdentity.isvprodid) {
|
|
304
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong ISV PROD ID in QE report');
|
|
305
|
-
}
|
|
306
|
-
const tcbLevel = qeIdentity.enclaveIdentity.tcbLevels.find((tcbLevel) => tcbLevel.tcb.isvsvn <= report.isvSvn);
|
|
307
|
-
const status = tcbLevel?.tcbStatus;
|
|
308
|
-
if (status) {
|
|
309
|
-
this.logger.info(`Enclave identity status is ${tcbLevel?.tcbStatus}`);
|
|
310
|
-
return status;
|
|
311
|
-
}
|
|
312
|
-
return statuses_js_1.QEIdentityStatuses.OutOfDate;
|
|
313
|
-
}
|
|
314
|
-
getTcbStatus(fmspc, pceId, tcbData, sgxExtensionData) {
|
|
315
|
-
if (fmspc.toUpperCase() !== tcbData.tcbInfo.fmspc.toUpperCase()) {
|
|
316
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong FMSPC in PCK certificate');
|
|
317
|
-
}
|
|
318
|
-
if (pceId !== tcbData.tcbInfo.pceId) {
|
|
319
|
-
throw new errors_js_1.TeeQuoteValidatorError('Wrong PCEID in PCK certificate');
|
|
320
|
-
}
|
|
321
|
-
const pceSvn = this.getDataFromExtension(sgxExtensionData, PCESVN_OID, asn1.Type.INTEGER);
|
|
322
|
-
const sgxComponents = [...Array(16).keys()].map((i) => this.getDataFromExtension(sgxExtensionData, `${TCB_OID}.${i + 1}`, asn1.Type.INTEGER));
|
|
323
|
-
const tcbLevel = tcbData.tcbInfo.tcbLevels.find((tcbLevel) => tcbLevel.tcb.pcesvn <= Number(pceSvn) &&
|
|
324
|
-
tcbLevel.tcb.sgxtcbcomponents.every((el, index) => el.svn <= Number(sgxComponents[index])));
|
|
325
|
-
const status = tcbLevel?.tcbStatus;
|
|
326
|
-
if (status) {
|
|
327
|
-
this.logger.info(`TCB status is ${tcbLevel?.tcbStatus}`);
|
|
328
|
-
return status;
|
|
329
|
-
}
|
|
330
|
-
return statuses_js_1.TCBStatuses.OutOfDate;
|
|
331
|
-
}
|
|
332
|
-
getQuoteValidationStatus(qeIdentityStatus, tcbStatus) {
|
|
333
|
-
if (qeIdentityStatus === statuses_js_1.QEIdentityStatuses.OutOfDate) {
|
|
334
|
-
if (tcbStatus === statuses_js_1.TCBStatuses.UpToDate || tcbStatus === statuses_js_1.TCBStatuses.SWHardeningNeeded) {
|
|
335
|
-
return statuses_js_1.QuoteValidationStatuses.SecurityPatchNeeded;
|
|
336
|
-
}
|
|
337
|
-
if (tcbStatus === statuses_js_1.TCBStatuses.OutOfDateConfigurationNeeded ||
|
|
338
|
-
tcbStatus === statuses_js_1.TCBStatuses.ConfigurationAndSWHardeningNeeded) {
|
|
339
|
-
return statuses_js_1.QuoteValidationStatuses.SoftwareUpdateNeeded;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
if (qeIdentityStatus === statuses_js_1.QEIdentityStatuses.Revoked || tcbStatus === statuses_js_1.TCBStatuses.Revoked) {
|
|
343
|
-
throw new errors_js_1.TeeQuoteValidatorError('QE identity or TCB revoked');
|
|
344
|
-
}
|
|
345
|
-
if (tcbStatus === statuses_js_1.TCBStatuses.UpToDate) {
|
|
346
|
-
return statuses_js_1.QuoteValidationStatuses.UpToDate;
|
|
347
|
-
}
|
|
348
|
-
if (tcbStatus === statuses_js_1.TCBStatuses.OutOfDate) {
|
|
349
|
-
return statuses_js_1.QuoteValidationStatuses.SecurityPatchNeeded;
|
|
350
|
-
}
|
|
351
|
-
if (tcbStatus === statuses_js_1.TCBStatuses.ConfigurationNeeded) {
|
|
352
|
-
return statuses_js_1.QuoteValidationStatuses.ConfigurationNeeded;
|
|
353
|
-
}
|
|
354
|
-
return statuses_js_1.QuoteValidationStatuses.SoftwareUpdateNeeded;
|
|
355
|
-
}
|
|
356
|
-
getQuoteValidationStatusDescription(status) {
|
|
357
|
-
switch (status) {
|
|
358
|
-
case statuses_js_1.QuoteValidationStatuses.UpToDate:
|
|
359
|
-
return 'The Quote verification passed and is at the latest TCB level.';
|
|
360
|
-
case statuses_js_1.QuoteValidationStatuses.ConfigurationNeeded:
|
|
361
|
-
return `The SGX platform firmware and SW are at the latest security patching level
|
|
362
|
-
but there are platform hardware configurations may expose the enclave to vulnerabilities.`;
|
|
363
|
-
case statuses_js_1.QuoteValidationStatuses.SecurityPatchNeeded:
|
|
364
|
-
return `The SGX platform firmware and SW are not at the latest security patching level.
|
|
365
|
-
The platform needs to be patched with firmware and/or software patches.`;
|
|
366
|
-
case statuses_js_1.QuoteValidationStatuses.SoftwareUpdateNeeded:
|
|
367
|
-
return `The SGX platform firmware and SW are at the latest security patching level but there are
|
|
368
|
-
certain vulnerabilities that can only be mitigated with software mitigations implemented by the enclave.`;
|
|
369
|
-
default:
|
|
370
|
-
return 'Quote verification failed.';
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
async checkQuote(quote, dataBlob) {
|
|
374
|
-
const logger = this.logger.child({ method: this.checkQuote.name });
|
|
375
|
-
const quoteBuffer = Buffer.from(quote);
|
|
376
|
-
const quoteStatus = await this.validate(quoteBuffer);
|
|
377
|
-
if (quoteStatus.quoteValidationStatus !== statuses_js_1.QuoteValidationStatuses.UpToDate) {
|
|
378
|
-
if (quoteStatus.quoteValidationStatus === statuses_js_1.QuoteValidationStatuses.Error) {
|
|
379
|
-
throw new Error('Quote is invalid');
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
logger.warn(quoteStatus, 'Quote validation status is not UpToDate');
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
const userDataCheckResult = await this.isQuoteHasUserData(quoteBuffer, Buffer.from(dataBlob));
|
|
386
|
-
if (!userDataCheckResult) {
|
|
387
|
-
throw new Error('Quote has invalid user data');
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
async checkSignature(quoteBuffer) {
|
|
391
|
-
await QuoteValidator.checkSignature(quoteBuffer);
|
|
392
|
-
}
|
|
393
|
-
async validate(quoteBuffer) {
|
|
394
|
-
try {
|
|
395
|
-
const quoteType = QuoteParser_js_1.TeeParser.determineQuoteType(quoteBuffer);
|
|
396
|
-
const quote = quoteType.type === types_js_1.QuoteType.SGX
|
|
397
|
-
? this.teeSgxParser.parseQuote(quoteBuffer)
|
|
398
|
-
: this.teeTdxParser.parseQuote(quoteBuffer);
|
|
399
|
-
const report = this.teeSgxParser.parseReport(quote.qeReport);
|
|
400
|
-
const { pckCert, rootCertPem } = await this.getCertificates(quote);
|
|
401
|
-
await this.validateQuoteStructure(quote, report, pckCert.publicKey.keyRaw);
|
|
402
|
-
this.logger.info('Quote structure validated successfully');
|
|
403
|
-
const sgxExtensionData = this.getSgxExtensionData(pckCert);
|
|
404
|
-
const fmspc = this.getDataFromExtension(sgxExtensionData, FMSPC_OID, asn1.Type.OCTETSTRING);
|
|
405
|
-
const pceId = this.getDataFromExtension(sgxExtensionData, PCEID_OID, asn1.Type.OCTETSTRING);
|
|
406
|
-
const tcbData = await this.getTcbInfo(fmspc, rootCertPem, quoteType.type);
|
|
407
|
-
const qeIdentity = await this.getQEIdentity(rootCertPem, quoteType.type);
|
|
408
|
-
const qeIdentityStatus = this.getQEIdentityStatus(report, qeIdentity);
|
|
409
|
-
const tcbStatus = this.getTcbStatus(fmspc, pceId, tcbData, sgxExtensionData); // TODO method 'validate' isn't only for tcb - extract this from quote validator
|
|
410
|
-
const quoteValidationStatus = this.getQuoteValidationStatus(qeIdentityStatus, tcbStatus);
|
|
411
|
-
this.logger.info(`Quote validation status is ${quoteValidationStatus}`);
|
|
412
|
-
return {
|
|
413
|
-
quoteValidationStatus,
|
|
414
|
-
description: this.getQuoteValidationStatusDescription(quoteValidationStatus),
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
catch (error) {
|
|
418
|
-
this.logger.error(`Validation error: ${error}`);
|
|
419
|
-
return {
|
|
420
|
-
quoteValidationStatus: statuses_js_1.QuoteValidationStatuses.Error,
|
|
421
|
-
description: this.getQuoteValidationStatusDescription(statuses_js_1.QuoteValidationStatuses.Error),
|
|
422
|
-
error,
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
async isQuoteHasUserData(quoteBuffer, userDataBuffer) {
|
|
427
|
-
const quoteType = QuoteParser_js_1.TeeParser.determineQuoteType(quoteBuffer);
|
|
428
|
-
const quote = quoteType.type === types_js_1.QuoteType.SGX
|
|
429
|
-
? this.teeSgxParser.parseQuote(quoteBuffer)
|
|
430
|
-
: this.teeTdxParser.parseQuote(quoteBuffer);
|
|
431
|
-
let slicedQuoteData;
|
|
432
|
-
const userDataHash = await this.getSha256Hash(userDataBuffer);
|
|
433
|
-
if (quoteType.type === types_js_1.QuoteType.SGX) {
|
|
434
|
-
slicedQuoteData = this.teeSgxParser
|
|
435
|
-
.parseReport(quote.report)
|
|
436
|
-
.userData.slice(0, userDataHash.length);
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
slicedQuoteData = this.teeTdxParser
|
|
440
|
-
.parseBody(quote.tdQuoteBody)
|
|
441
|
-
.reportData.slice(0, userDataHash.length);
|
|
442
|
-
}
|
|
443
|
-
const compareResult = Buffer.compare(slicedQuoteData, userDataHash);
|
|
444
|
-
return compareResult === 0;
|
|
445
|
-
}
|
|
446
|
-
async getSha256Hash(data) {
|
|
447
|
-
const hashInfo = {
|
|
448
|
-
algo: dto_js_1.HashAlgorithm.SHA256,
|
|
449
|
-
encoding: dto_js_1.Encoding.base64,
|
|
450
|
-
};
|
|
451
|
-
const hashData = await index_js_1.default.createHash(data, hashInfo);
|
|
452
|
-
return Buffer.from(hashData.hash, hashData.encoding);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
exports.QuoteValidator = QuoteValidator;
|
|
456
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUXVvdGVWYWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdGVlL1F1b3RlVmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGtEQUEwQjtBQUMxQix3REFBZ0M7QUFDaEMsNERBQStCO0FBQy9CLHFDQUFvRDtBQUNwRCx5REFBOEM7QUFDOUMsaUNBQWtEO0FBQ2xELG1DQUFpQztBQUNqQyxvREFBdUI7QUFDdkIscURBQXlFO0FBQ3pFLHlDQU9vQjtBQUNwQiw2REFBc0M7QUFFdEMsMkNBQXFEO0FBQ3JELCtDQUF5RjtBQUN6RixtREFBaUU7QUFDakUsa0VBQXdDO0FBQ3hDLHVFQUF3RjtBQUN4RiwyREFBMkQ7QUFFM0QsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLGtCQUFRLENBQUM7QUFDeEIsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxvQkFBSyxDQUFDO0FBRTdCLE1BQU0sa0JBQWtCLEdBQUcsdUNBQXVDLENBQUM7QUFDbkUsTUFBTSxxQkFBcUIsR0FBRyxtRUFBbUUsQ0FBQztBQUNsRyxNQUFNLE9BQU8sR0FBRyx1QkFBdUIsQ0FBQztBQUN4QyxNQUFNLFNBQVMsR0FBRyxHQUFHLE9BQU8sSUFBSSxDQUFDO0FBQ2pDLE1BQU0sU0FBUyxHQUFHLEdBQUcsT0FBTyxJQUFJLENBQUM7QUFDakMsTUFBTSxPQUFPLEdBQUcsR0FBRyxPQUFPLElBQUksQ0FBQztBQUMvQixNQUFNLFVBQVUsR0FBRyxHQUFHLE9BQU8sS0FBSyxDQUFDO0FBQ25DLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxVQUFVLENBQUM7SUFDeEMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHO0lBQ2hHLEdBQUcsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsR0FBRztJQUNoRyxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxHQUFHO0lBQ2hHLEdBQUc7Q0FDSixDQUFDLENBQUM7QUFRSCxNQUFhLGNBQWM7SUFDUixTQUFTLENBQVU7SUFDbkIsT0FBTyxDQUFTO0lBQ2hCLFlBQVksQ0FBZTtJQUMzQixZQUFZLENBQWU7SUFDcEMsTUFBTSxDQUFvQjtJQUVsQyxZQUFZLE9BQWU7UUFDekIsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLEtBQUssa0JBQWtCLENBQUM7UUFDaEQsSUFBSSxDQUFDLE9BQU8sR0FBRyxHQUFHLE9BQU8sdUJBQXVCLENBQUM7UUFDakQsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLDZCQUFZLEVBQUUsQ0FBQztRQUN2QyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksNkJBQVksRUFBRSxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxNQUFNLEdBQUcsbUJBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRSxTQUFTLEVBQUUsY0FBYyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVELE1BQU0sQ0FBQyxZQUFZLENBQ2pCLFNBQWlCLEVBQ2pCLGFBQTRCLEVBQzVCLE9BQTZCO1FBRTdCLE9BQU8sOENBQW9CLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRSxhQUFhLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDOUUsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUN6QixLQUFhLEVBQ2IsVUFBaUMsRUFBRSxxQkFBcUIsRUFBRSw4Q0FBb0IsQ0FBQyxZQUFZLEVBQUU7UUFFN0YsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyw2QkFBWSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRW5FLFFBQVEsU0FBUyxFQUFFLENBQUM7WUFDbEIsS0FBSyxvQkFBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQ25CLE1BQU0sTUFBTSxHQUFHLElBQUksNkJBQVksRUFBRSxDQUFDO2dCQUNsQyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUM3QyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDdEQsOENBQW9CLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUMzRCxNQUFNO1lBQ1IsQ0FBQztZQUNELEtBQUssb0JBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUNuQixNQUFNLFNBQVMsR0FBRywwQkFBUyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDaEQsTUFBTSw4Q0FBb0IsQ0FBQyxpQkFBaUIsQ0FDMUMsU0FBUyxFQUNULDBCQUFhLENBQUMsR0FBRyxFQUNqQixPQUFPLENBQ1IsQ0FBQztnQkFDRixNQUFNO1lBQ1IsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRU8sVUFBVSxDQUFDLEtBQWE7UUFDOUIsTUFBTSxLQUFLLEdBQUcsNkJBQTZCLENBQUM7UUFDNUMsTUFBTSxHQUFHLEdBQUcsMkJBQTJCLENBQUM7UUFFeEMsT0FBTyxLQUFLO2FBQ1QsS0FBSyxDQUFDLEtBQUssQ0FBQzthQUNaLE1BQU0sQ0FBQyxPQUFPLENBQUM7YUFDZixHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVPLGlCQUFpQixDQUFDLFFBQWdCLEVBQUUsU0FBaUI7UUFDM0QsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN6QyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXRDLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRU8saUJBQWlCLENBQUMsUUFBeUIsRUFBRSxTQUFpQjtRQUNwRSxJQUFJLFFBQVEsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUN6QyxLQUFLLE1BQU0sS0FBSyxJQUFJLFFBQVEsQ0FBQyxLQUEwQixFQUFFLENBQUM7Z0JBQ3hELElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO29CQUNqQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxLQUFlLENBQUMsQ0FBQztvQkFDakQsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFLENBQUM7d0JBQ3RCLE9BQU8sUUFBUSxDQUFDO29CQUNsQixDQUFDO2dCQUNILENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNsQyxLQUFLLE1BQU0sS0FBSyxJQUFJLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDbkMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQztnQkFDeEQsSUFBSSxNQUFNLEVBQUUsQ0FBQztvQkFDWCxPQUFPLE1BQU0sQ0FBQztnQkFDaEIsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRU8scUJBQXFCLENBQUMsSUFBWSxFQUFFLFNBQWlCLEVBQUUsR0FBVztRQUN4RSxNQUFNLFVBQVUsR0FBRyxJQUFJLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUVsQyxPQUFPLFVBQVUsQ0FBQyxNQUFNLENBQ3RCLElBQUksRUFDSjtZQUNFLENBQUMsRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDNUIsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1NBQzFCLEVBQ0QsVUFBVSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQ3JDLENBQUM7SUFDSixDQUFDO0lBRU8sY0FBYyxDQUFDLElBQVksRUFBRSxFQUFVO1FBQzdDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN2QixPQUFPLElBQUksR0FBRyxHQUFHLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0lBRU8sb0JBQW9CLENBQzFCLE9BQW9CLEVBQ3BCLFlBQXlCLEVBQ3pCLFFBQXFCO1FBRXJCLE9BQU8sQ0FDTCxnQkFBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLFlBQVksQ0FBQyxPQUFPLENBQUM7WUFDL0MsZ0JBQUMsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLENBQ2pELENBQUM7SUFDSixDQUFDO0lBRU8sTUFBTSxDQUFDLE9BQWU7UUFDNUIsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUM7WUFDeEMsQ0FBQyxDQUFDLDZCQUFTLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztZQUM3QixDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDaEMsTUFBTSxNQUFNLEdBQUcsSUFBQSxnQkFBTyxFQUFDLE1BQW9CLENBQUMsQ0FBQztRQUU3QyxPQUFPLElBQUksaUNBQXlCLENBQUMsRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVPLHNCQUFzQixDQUFDLEdBQThCLEVBQUUsT0FBaUI7UUFDOUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDdkMsTUFBTSxJQUFJLGtDQUFzQixDQUFDLHNEQUFzRCxDQUFDLENBQUM7UUFDM0YsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUN6RixNQUFNLElBQUksa0NBQXNCLENBQUMscURBQXFELENBQUMsQ0FBQztRQUMxRixDQUFDO1FBQ0QsSUFBSSxHQUFHLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUM1QixNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FDNUQsT0FBTyxDQUFDLFFBQVEsQ0FDZCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FDN0UsQ0FDRixDQUFDO1lBQ0YsSUFBSSxZQUFZLEVBQUUsQ0FBQztnQkFDakIsTUFBTSxJQUFJLGtDQUFzQixDQUFDLGdDQUFnQyxDQUFDLENBQUM7WUFDckUsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLGVBQWUsQ0FDM0IsS0FBbUI7UUFFbkIsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxrQ0FBa0MsQ0FBQyxDQUFDO1FBQzdGLE1BQU0sYUFBYSxHQUFHLGtCQUFrQixDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDLENBQUM7UUFDaEcsTUFBTSxDQUFDLGtCQUFrQixFQUFFLGNBQWMsQ0FBQyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxtQkFBbUI7UUFDaEcsTUFBTSxtQkFBbUIsR0FBRyxrQkFBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQztRQUNqRixNQUFNLGVBQWUsR0FBRyxrQkFBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7UUFFekUsSUFDRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQ2xCLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsRUFDdkMsbUJBQW1CLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUN0QyxFQUNELENBQUM7WUFDRCxNQUFNLElBQUksa0NBQXNCLENBQUMsbURBQW1ELENBQUMsQ0FBQztRQUN4RixDQUFDO1FBQ0QsSUFDRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxlQUFlLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQzVGLENBQUM7WUFDRCxNQUFNLElBQUksa0NBQXNCLENBQUMsK0NBQStDLENBQUMsQ0FBQztRQUNwRixDQUFDO1FBQ0QsSUFBSSxDQUFDLGdCQUFDLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsZUFBZSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDaEUsTUFBTSxJQUFJLGtDQUFzQixDQUFDLHFDQUFxQyxDQUFDLENBQUM7UUFDMUUsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQy9FLE1BQU0sSUFBSSxrQ0FBc0IsQ0FBQyx5Q0FBeUMsQ0FBQyxDQUFDO1FBQzlFLENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxrQkFBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDaEYsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLHVCQUF1QixDQUFDO1FBRS9DLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDakYsTUFBTSxJQUFJLGtDQUFzQixDQUFDLDhDQUE4QyxDQUFDLENBQUM7UUFDbkYsQ0FBQztRQUNELElBQUksUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ25CLE1BQU0sSUFBSSxrQ0FBc0IsQ0FBQyx3Q0FBd0MsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUN2RixDQUFDO1FBQ0QsSUFBSSxjQUFjLEtBQUssS0FBSyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDbkQsTUFBTSxJQUFJLGtDQUFzQixDQUFDLDJEQUEyRCxDQUFDLENBQUM7UUFDaEcsQ0FBQztRQUVELElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGVBQWUsQ0FBQyxFQUFFLENBQUM7WUFDOUUsTUFBTSxJQUFJLGtDQUFzQixDQUFDLHVDQUF1QyxDQUFDLENBQUM7UUFDNUUsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFHO1lBQ2QsZUFBZSxDQUFDLFlBQVk7WUFDNUIsbUJBQW1CLENBQUMsWUFBWTtZQUNoQyxPQUFPLENBQUMsWUFBWTtTQUNyQixDQUFDO1FBRUYsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFNBQVM7WUFDN0IsQ0FBQyxDQUFDLHFCQUFxQjtZQUN2QixDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxZQUFZLHFCQUFxQixFQUFFLENBQUM7UUFDdkQsTUFBTSxXQUFXLEdBQUcsTUFBTSxlQUFLLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRTtZQUM1QyxZQUFZLEVBQUUsYUFBYTtTQUM1QixDQUFDLENBQUM7UUFDSCxNQUFNLFdBQVcsR0FBRyxJQUFBLGdCQUFPLEVBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUMzRCxJQUFJLENBQUMsc0JBQXNCLENBQ3pCLElBQUksaUNBQXlCLENBQUMsRUFBRSxNQUFNLEVBQUUsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQzdELE9BQU8sQ0FDUixDQUFDO1FBRUYsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMsc0JBQXNCLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRWxELE9BQU8sRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLGNBQWMsRUFBRSxDQUFDO0lBQ2xELENBQUM7SUFFTyxLQUFLLENBQUMsdUJBQXVCLENBQ25DLEtBQW1CLEVBQ25CLFlBQW9CO1FBRXBCLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDdkQsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7UUFFekUsT0FBTyxJQUFJLENBQUMscUJBQXFCLENBQUMsVUFBVSxFQUFFLFNBQVMsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBRU8sS0FBSyxDQUFDLGtCQUFrQixDQUM5QixLQUFtQixFQUNuQixNQUE0QjtRQUU1QixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsb0JBQW9CLENBQUM7UUFDOUMsTUFBTSxjQUFjLEdBQUcsS0FBSyxDQUFDLG1CQUFtQixDQUFDO1FBQ2pELE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUN6QyxNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGNBQWMsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0YsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUVoRSxPQUFPLE1BQU0sS0FBSyxDQUFDLENBQUM7SUFDdEIsQ0FBQztJQUVPLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxLQUFtQjtRQUM1RCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ25ELE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sWUFBWSxHQUNoQixLQUFLLENBQUMsU0FBUyxLQUFLLG9CQUFTLENBQUMsR0FBRztZQUMvQixDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBRSxLQUE2QixDQUFDLE1BQU0sQ0FBQztZQUNwRCxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBRSxLQUE2QixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzlELE1BQU0sUUFBUSxHQUNaLEtBQUssQ0FBQyxTQUFTLEtBQUssb0JBQVMsQ0FBQyxHQUFHO1lBQy9CLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFFLEtBQTZCLENBQUMseUJBQXlCLENBQUM7WUFDdkUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUUsS0FBNkIsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUVqRSxNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFN0YsTUFBTSxVQUFVLEdBQUcsSUFBSSxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFbEMsT0FBTyxVQUFVLENBQUMsTUFBTSxDQUN0QixjQUFjLEVBQ2Q7WUFDRSxDQUFDLEVBQUUsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQzNCLENBQUMsRUFBRSxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztTQUN6QixFQUNELE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUN2QyxDQUFDO0lBQ0osQ0FBQztJQUVPLEtBQUssQ0FBQyxzQkFBc0IsQ0FDbEMsS0FBbUIsRUFDbkIsTUFBNEIsRUFDNUIsWUFBb0I7UUFFcEIsSUFBSSxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsdUJBQXVCLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUMvRCxNQUFNLElBQUksa0NBQXNCLENBQUMsMkJBQTJCLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsSUFBSSxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNwRCxNQUFNLElBQUksa0NBQXNCLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUMzRCxDQUFDO1FBQ0QsSUFBSSxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsNEJBQTRCLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3RELE1BQU0sSUFBSSxrQ0FBc0IsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7SUFDSCxDQUFDO0lBRU8sbUJBQW1CLENBQUMsT0FBb0I7UUFDOUMsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxPQUFPLENBQUMsQ0FBQztRQUNqRixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUN0QixNQUFNLElBQUksa0NBQXNCLENBQUMsdUNBQXVDLENBQUMsQ0FBQztRQUM1RSxDQUFDO1FBRUQsT0FBTyxnQkFBZ0IsQ0FBQztJQUMxQixDQUFDO0lBRU8sb0JBQW9CLENBQzFCLGdCQUEyQixFQUMzQixTQUFpQixFQUNqQixVQUEyQjtRQUUzQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUMxRixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDYixNQUFNLElBQUksa0NBQXNCLENBQUMsT0FBTyxTQUFTLDBDQUEwQyxDQUFDLENBQUM7UUFDL0YsQ0FBQztRQUNELE1BQU0sSUFBSSxHQUFJLE9BQU8sQ0FBQyxLQUEyQixDQUFDLE1BQU0sQ0FDdEQsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEtBQUssVUFBVSxDQUMvQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNqQixNQUFNLElBQUksa0NBQXNCLENBQUMsZUFBZSxTQUFTLFlBQVksVUFBVSxZQUFZLENBQUMsQ0FBQztRQUMvRixDQUFDO1FBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBZSxDQUFDLENBQUM7UUFFeEQsT0FBTyxVQUFVLEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUN6RixDQUFDO0lBRU8sS0FBSyxDQUFDLFVBQVUsQ0FDdEIsS0FBYSxFQUNiLFdBQW1CLEVBQ25CLFNBQW9CO1FBRXBCLElBQUksTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLE9BQU8sY0FBYyxLQUFLLEVBQUUsQ0FBQztRQUNsRCxJQUFJLFNBQVMsS0FBSyxvQkFBUyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2hDLE1BQU0sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLG1CQUFtQixFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLE1BQU0sZUFBSyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN4QyxNQUFNLGFBQWEsR0FBRyx1QkFBdUIsQ0FBQztRQUM5QyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsY0FBYztRQUN4RyxJQUFJLFlBQVksQ0FBQyxDQUFDLENBQUMsS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksa0NBQXNCLENBQUMsMkNBQTJDLENBQUMsQ0FBQztRQUNoRixDQUFDO1FBRUQsTUFBTSxPQUFPLEdBQUcsa0JBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2xFLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQ3JDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDN0QsTUFBTSxjQUFjLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUM3QyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUNsRCxDQUFDO1FBRUYsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGNBQWMsRUFBRSxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDMUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxJQUFJLGtDQUFzQixDQUFDLGlDQUFpQyxDQUFDLENBQUM7UUFDdEUsQ0FBQztRQUVELElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDO1lBQzNELE1BQU0sSUFBSSxrQ0FBc0IsQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO1FBQzFFLENBQUM7UUFFRCxPQUFPLE9BQU8sQ0FBQyxJQUFnQixDQUFDO0lBQ2xDLENBQUM7SUFFTyxLQUFLLENBQUMsYUFBYSxDQUFDLFdBQW1CLEVBQUUsU0FBb0I7UUFDbkUsSUFBSSxhQUFhLEdBQUcsR0FBRyxJQUFJLENBQUMsT0FBTyxjQUFjLENBQUM7UUFDbEQsSUFBSSxTQUFTLEtBQUssb0JBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNoQyxhQUFhLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7UUFDRCxNQUFNLGNBQWMsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDdEQsTUFBTSxnQkFBZ0IsR0FBRyxtQ0FBbUMsQ0FBQztRQUM3RCxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUNyQyxrQkFBa0IsQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FDN0QsQ0FBQyxDQUFDLHFCQUFxQjtRQUN4QixJQUFJLGVBQWUsQ0FBQyxDQUFDLENBQUMsS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUN2QyxNQUFNLElBQUksa0NBQXNCLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUM3RixDQUFDO1FBRUQsTUFBTSxjQUFjLEdBQUcsa0JBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzVFLE1BQU0sR0FBRyxHQUFHLGNBQWMsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQzVDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDcEUsTUFBTSxjQUFjLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUM3QyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUNqRSxDQUFDO1FBRUYsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGNBQWMsRUFBRSxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDMUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxJQUFJLGtDQUFzQixDQUFDLHlDQUF5QyxDQUFDLENBQUM7UUFDOUUsQ0FBQztRQUVELElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDO1lBQzFFLE1BQU0sSUFBSSxrQ0FBc0IsQ0FBQyxrREFBa0QsQ0FBQyxDQUFDO1FBQ3ZGLENBQUM7UUFFRCxPQUFPLGNBQWMsQ0FBQyxJQUFtQixDQUFDO0lBQzVDLENBQUM7SUFFTyxtQkFBbUIsQ0FDekIsTUFBNEIsRUFDNUIsVUFBdUI7UUFFdkIsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDakQsSUFBSSxRQUFRLENBQUMsV0FBVyxFQUFFLEtBQUssVUFBVSxDQUFDLGVBQWUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNuRSxNQUFNLElBQUksa0NBQXNCLENBQUMsOEJBQThCLENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsU0FBUyxLQUFLLFVBQVUsQ0FBQyxlQUFlLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDOUQsTUFBTSxJQUFJLGtDQUFzQixDQUFDLGdDQUFnQyxDQUFDLENBQUM7UUFDckUsQ0FBQztRQUNELE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLElBQUksQ0FDeEQsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQ25ELENBQUM7UUFFRixNQUFNLE1BQU0sR0FBRyxRQUFRLEVBQUUsU0FBK0IsQ0FBQztRQUN6RCxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsOEJBQThCLFFBQVEsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1lBQ3RFLE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7UUFDRCxPQUFPLGdDQUFrQixDQUFDLFNBQVMsQ0FBQztJQUN0QyxDQUFDO0lBRU8sWUFBWSxDQUNsQixLQUFhLEVBQ2IsS0FBYSxFQUNiLE9BQWlCLEVBQ2pCLGdCQUEyQjtRQUUzQixJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBSyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQ2hFLE1BQU0sSUFBSSxrQ0FBc0IsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7UUFDRCxJQUFJLEtBQUssS0FBSyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3BDLE1BQU0sSUFBSSxrQ0FBc0IsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUYsTUFBTSxhQUFhLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQ3BELElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FDdEYsQ0FBQztRQUNGLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FDN0MsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUNYLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDckMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUM3RixDQUFDO1FBRUYsTUFBTSxNQUFNLEdBQUcsUUFBUSxFQUFFLFNBQXdCLENBQUM7UUFDbEQsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGlCQUFpQixRQUFRLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztZQUN6RCxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO1FBQ0QsT0FBTyx5QkFBVyxDQUFDLFNBQVMsQ0FBQztJQUMvQixDQUFDO0lBRU8sd0JBQXdCLENBQzlCLGdCQUFvQyxFQUNwQyxTQUFzQjtRQUV0QixJQUFJLGdCQUFnQixLQUFLLGdDQUFrQixDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3RELElBQUksU0FBUyxLQUFLLHlCQUFXLENBQUMsUUFBUSxJQUFJLFNBQVMsS0FBSyx5QkFBVyxDQUFDLGlCQUFpQixFQUFFLENBQUM7Z0JBQ3RGLE9BQU8scUNBQXVCLENBQUMsbUJBQW1CLENBQUM7WUFDckQsQ0FBQztZQUNELElBQ0UsU0FBUyxLQUFLLHlCQUFXLENBQUMsNEJBQTRCO2dCQUN0RCxTQUFTLEtBQUsseUJBQVcsQ0FBQyxpQ0FBaUMsRUFDM0QsQ0FBQztnQkFDRCxPQUFPLHFDQUF1QixDQUFDLG9CQUFvQixDQUFDO1lBQ3RELENBQUM7UUFDSCxDQUFDO1FBQ0QsSUFBSSxnQkFBZ0IsS0FBSyxnQ0FBa0IsQ0FBQyxPQUFPLElBQUksU0FBUyxLQUFLLHlCQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekYsTUFBTSxJQUFJLGtDQUFzQixDQUFDLDRCQUE0QixDQUFDLENBQUM7UUFDakUsQ0FBQztRQUNELElBQUksU0FBUyxLQUFLLHlCQUFXLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDdkMsT0FBTyxxQ0FBdUIsQ0FBQyxRQUFRLENBQUM7UUFDMUMsQ0FBQztRQUNELElBQUksU0FBUyxLQUFLLHlCQUFXLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDeEMsT0FBTyxxQ0FBdUIsQ0FBQyxtQkFBbUIsQ0FBQztRQUNyRCxDQUFDO1FBQ0QsSUFBSSxTQUFTLEtBQUsseUJBQVcsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ2xELE9BQU8scUNBQXVCLENBQUMsbUJBQW1CLENBQUM7UUFDckQsQ0FBQztRQUNELE9BQU8scUNBQXVCLENBQUMsb0JBQW9CLENBQUM7SUFDdEQsQ0FBQztJQUVPLG1DQUFtQyxDQUFDLE1BQStCO1FBQ3pFLFFBQVEsTUFBTSxFQUFFLENBQUM7WUFDZixLQUFLLHFDQUF1QixDQUFDLFFBQVE7Z0JBQ25DLE9BQU8sK0RBQStELENBQUM7WUFDekUsS0FBSyxxQ0FBdUIsQ0FBQyxtQkFBbUI7Z0JBQzlDLE9BQU87OEdBQytGLENBQUM7WUFDekcsS0FBSyxxQ0FBdUIsQ0FBQyxtQkFBbUI7Z0JBQzlDLE9BQU87NEZBQzZFLENBQUM7WUFDdkYsS0FBSyxxQ0FBdUIsQ0FBQyxvQkFBb0I7Z0JBQy9DLE9BQU87NkhBQzhHLENBQUM7WUFDeEg7Z0JBQ0UsT0FBTyw0QkFBNEIsQ0FBQztRQUN4QyxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxVQUFVLENBQUMsS0FBaUIsRUFBRSxRQUFvQjtRQUN0RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFbkUsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QyxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDckQsSUFBSSxXQUFXLENBQUMscUJBQXFCLEtBQUsscUNBQXVCLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDM0UsSUFBSSxXQUFXLENBQUMscUJBQXFCLEtBQUsscUNBQXVCLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3hFLE1BQU0sSUFBSSxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUN0QyxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUseUNBQXlDLENBQUMsQ0FBQztZQUN0RSxDQUFDO1FBQ0gsQ0FBQztRQUVELE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUM5RixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDZCQUE2QixDQUFDLENBQUM7UUFDakQsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsY0FBYyxDQUFDLFdBQW1CO1FBQ3RDLE1BQU0sY0FBYyxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxXQUFtQjtRQUNoQyxJQUFJLENBQUM7WUFDSCxNQUFNLFNBQVMsR0FBRywwQkFBUyxDQUFDLGtCQUFrQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQzVELE1BQU0sS0FBSyxHQUNULFNBQVMsQ0FBQyxJQUFJLEtBQUssb0JBQVMsQ0FBQyxHQUFHO2dCQUM5QixDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDO2dCQUMzQyxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDaEQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRTdELE1BQU0sRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRW5FLE1BQU0sSUFBSSxDQUFDLHNCQUFzQixDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUMzRSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFDO1lBRTNELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzNELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxnQkFBZ0IsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUM1RixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMsZ0JBQWdCLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7WUFFNUYsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxXQUFXLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzFFLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRXpFLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsQ0FBQztZQUN0RSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxnRkFBZ0Y7WUFFOUosTUFBTSxxQkFBcUIsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsZ0JBQWdCLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDekYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsOEJBQThCLHFCQUFxQixFQUFFLENBQUMsQ0FBQztZQUV4RSxPQUFPO2dCQUNMLHFCQUFxQjtnQkFDckIsV0FBVyxFQUFFLElBQUksQ0FBQyxtQ0FBbUMsQ0FBQyxxQkFBcUIsQ0FBQzthQUM3RSxDQUFDO1FBQ0osQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUVoRCxPQUFPO2dCQUNMLHFCQUFxQixFQUFFLHFDQUF1QixDQUFDLEtBQUs7Z0JBQ3BELFdBQVcsRUFBRSxJQUFJLENBQUMsbUNBQW1DLENBQUMscUNBQXVCLENBQUMsS0FBSyxDQUFDO2dCQUNwRixLQUFLO2FBQ04sQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRU0sS0FBSyxDQUFDLGtCQUFrQixDQUFDLFdBQW1CLEVBQUUsY0FBc0I7UUFDekUsTUFBTSxTQUFTLEdBQUcsMEJBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1RCxNQUFNLEtBQUssR0FDVCxTQUFTLENBQUMsSUFBSSxLQUFLLG9CQUFTLENBQUMsR0FBRztZQUM5QixDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDO1lBQzNDLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVoRCxJQUFJLGVBQW9DLENBQUM7UUFDekMsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQzlELElBQUksU0FBUyxDQUFDLElBQUksS0FBSyxvQkFBUyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3JDLGVBQWUsR0FBRyxJQUFJLENBQUMsWUFBWTtpQkFDaEMsV0FBVyxDQUFFLEtBQTZCLENBQUMsTUFBTSxDQUFDO2lCQUNsRCxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUMsQ0FBQzthQUFNLENBQUM7WUFDTixlQUFlLEdBQUcsSUFBSSxDQUFDLFlBQVk7aUJBQ2hDLFNBQVMsQ0FBRSxLQUE2QixDQUFDLFdBQVcsQ0FBQztpQkFDckQsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzlDLENBQUM7UUFFRCxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUVwRSxPQUFPLGFBQWEsS0FBSyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVPLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBWTtRQUN0QyxNQUFNLFFBQVEsR0FBRztZQUNmLElBQUksRUFBRSxzQkFBYSxDQUFDLE1BQU07WUFDMUIsUUFBUSxFQUFFLGlCQUFRLENBQUMsTUFBTTtTQUMxQixDQUFDO1FBQ0YsTUFBTSxRQUFRLEdBQUcsTUFBTSxrQkFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDekQsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3ZELENBQUM7Q0FDRjtBQWxrQkQsd0NBa2tCQyJ9
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { TcbVerifiedStatus, ConsensusBenchmark } from '@super-protocol/dto-js';
|
|
2
|
-
import { BlockchainId } from '../types/index.js';
|
|
3
|
-
export type TcbData = {
|
|
4
|
-
checkingTcbId: string;
|
|
5
|
-
pubKey: string;
|
|
6
|
-
checkingTcbIds: BlockchainId[];
|
|
7
|
-
checkingTcbMarks: TcbVerifiedStatus[];
|
|
8
|
-
deviceId: string;
|
|
9
|
-
benchmark: ConsensusBenchmark;
|
|
10
|
-
properties: string;
|
|
11
|
-
};
|
|
12
|
-
export type VersionedTcbData = {
|
|
13
|
-
v: number;
|
|
14
|
-
[key: string]: unknown;
|
|
15
|
-
};
|
|
16
|
-
export declare class TcbDataSerializer {
|
|
17
|
-
private static readonly VERSION;
|
|
18
|
-
static serialize(data: TcbData): Uint8Array;
|
|
19
|
-
static deserialize(buffer: Uint8Array): TcbData;
|
|
20
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TcbDataSerializer = void 0;
|
|
4
|
-
const msgpack_1 = require("@msgpack/msgpack");
|
|
5
|
-
class TcbDataSerializer {
|
|
6
|
-
static VERSION = 1; // Current version of the data structure
|
|
7
|
-
static serialize(data) {
|
|
8
|
-
const serializedData = {
|
|
9
|
-
v: TcbDataSerializer.VERSION,
|
|
10
|
-
quote: data,
|
|
11
|
-
};
|
|
12
|
-
return (0, msgpack_1.encode)(serializedData, { sortKeys: true });
|
|
13
|
-
}
|
|
14
|
-
static deserialize(buffer) {
|
|
15
|
-
const { v, ...rest } = (0, msgpack_1.decode)(buffer);
|
|
16
|
-
switch (v) {
|
|
17
|
-
case 1: {
|
|
18
|
-
return rest;
|
|
19
|
-
}
|
|
20
|
-
// Future versions can be handled here with additional cases
|
|
21
|
-
default:
|
|
22
|
-
throw new Error(`Unsupported version: ${v}`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
exports.TcbDataSerializer = TcbDataSerializer;
|
|
27
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGNiU2VyaWFsaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZWUvVGNiU2VyaWFsaXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw4Q0FBa0Q7QUFtQmxELE1BQWEsaUJBQWlCO0lBQ3BCLE1BQU0sQ0FBVSxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsd0NBQXdDO0lBRTdFLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBYTtRQUM1QixNQUFNLGNBQWMsR0FBcUI7WUFDdkMsQ0FBQyxFQUFFLGlCQUFpQixDQUFDLE9BQU87WUFDNUIsS0FBSyxFQUFFLElBQUk7U0FDWixDQUFDO1FBRUYsT0FBTyxJQUFBLGdCQUFNLEVBQUMsY0FBYyxFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVELE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBa0I7UUFDbkMsTUFBTSxFQUFFLENBQUMsRUFBRSxHQUFHLElBQUksRUFBRSxHQUFHLElBQUEsZ0JBQU0sRUFBQyxNQUFNLENBQXFCLENBQUM7UUFFMUQsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNWLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDUCxPQUFPLElBQWUsQ0FBQztZQUN6QixDQUFDO1lBQ0QsNERBQTREO1lBQzVEO2dCQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakQsQ0FBQztJQUNILENBQUM7O0FBdkJILDhDQXdCQyJ9
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { GetSignatureOptions } from './types.js';
|
|
3
|
-
import { QuoteValidationStatuses } from './statuses.js';
|
|
4
|
-
import { CheckSignatureOptions } from './TeeSignatureVerifier.js';
|
|
5
|
-
import { ChallengeType } from '@super-protocol/pki-common';
|
|
6
|
-
export interface ValidationResult {
|
|
7
|
-
quoteValidationStatus: QuoteValidationStatuses;
|
|
8
|
-
description: string;
|
|
9
|
-
error?: unknown;
|
|
10
|
-
}
|
|
11
|
-
export declare class QuoteValidator {
|
|
12
|
-
private readonly isDefault;
|
|
13
|
-
private readonly baseUrl;
|
|
14
|
-
private readonly teeSgxParser;
|
|
15
|
-
private readonly teeTdxParser;
|
|
16
|
-
private logger;
|
|
17
|
-
constructor(baseUrl: string);
|
|
18
|
-
static getSignature(mrEnclave: Buffer, challengeType: ChallengeType, options?: GetSignatureOptions): Promise<Buffer>;
|
|
19
|
-
static checkSignature(quote: Buffer, options?: CheckSignatureOptions): Promise<void>;
|
|
20
|
-
private splitChain;
|
|
21
|
-
private findSequenceByOID;
|
|
22
|
-
private searchForSequence;
|
|
23
|
-
private verifyDataBySignature;
|
|
24
|
-
private checkValidDate;
|
|
25
|
-
private checkChainForIssuers;
|
|
26
|
-
private getCrl;
|
|
27
|
-
private checkCertificatesInCrl;
|
|
28
|
-
private getCertificates;
|
|
29
|
-
private verifyQeReportSignature;
|
|
30
|
-
private verifyQeReportData;
|
|
31
|
-
private verifyEnclaveReportSignature;
|
|
32
|
-
private validateQuoteStructure;
|
|
33
|
-
private getSgxExtensionData;
|
|
34
|
-
private getDataFromExtension;
|
|
35
|
-
private getTcbInfo;
|
|
36
|
-
private getQEIdentity;
|
|
37
|
-
private getQEIdentityStatus;
|
|
38
|
-
private getTcbStatus;
|
|
39
|
-
private getQuoteValidationStatus;
|
|
40
|
-
private getQuoteValidationStatusDescription;
|
|
41
|
-
checkQuote(quote: Uint8Array, dataBlob: Uint8Array): Promise<void>;
|
|
42
|
-
checkSignature(quoteBuffer: Buffer): Promise<void>;
|
|
43
|
-
validate(quoteBuffer: Buffer): Promise<ValidationResult>;
|
|
44
|
-
isQuoteHasUserData(quoteBuffer: Buffer, userDataBuffer: Buffer): Promise<boolean>;
|
|
45
|
-
private getSha256Hash;
|
|
46
|
-
}
|