@t2000/sdk 5.19.0 → 5.20.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/dist/index.cjs +90 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +90 -3
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.d.cts
CHANGED
|
@@ -112,6 +112,8 @@ interface VerifyOptions {
|
|
|
112
112
|
/** Confidential model id for fetching the attested receipt-signing key
|
|
113
113
|
* (default `phala/glm-5.2`; the gateway key is workload-wide). */
|
|
114
114
|
model?: string;
|
|
115
|
+
/** Skip the local DCAP quote verification (the slower, network-bound check). */
|
|
116
|
+
skipQuote?: boolean;
|
|
115
117
|
}
|
|
116
118
|
/**
|
|
117
119
|
* Verify a confidential response by its receipt id. Reads the signed receipt
|
package/dist/index.d.ts
CHANGED
|
@@ -112,6 +112,8 @@ interface VerifyOptions {
|
|
|
112
112
|
/** Confidential model id for fetching the attested receipt-signing key
|
|
113
113
|
* (default `phala/glm-5.2`; the gateway key is workload-wide). */
|
|
114
114
|
model?: string;
|
|
115
|
+
/** Skip the local DCAP quote verification (the slower, network-bound check). */
|
|
116
|
+
skipQuote?: boolean;
|
|
115
117
|
}
|
|
116
118
|
/**
|
|
117
119
|
* Verify a confidential response by its receipt id. Reads the signed receipt
|
package/dist/index.js
CHANGED
|
@@ -2107,6 +2107,72 @@ function verifyReceiptSignature(receipt, signingKeyHex) {
|
|
|
2107
2107
|
return false;
|
|
2108
2108
|
}
|
|
2109
2109
|
}
|
|
2110
|
+
async function verifyTdxQuote(base, model, receiptWorkloadId) {
|
|
2111
|
+
let nonce;
|
|
2112
|
+
try {
|
|
2113
|
+
nonce = bytesToHex(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
2114
|
+
} catch {
|
|
2115
|
+
return { status: "skip", detail: "no secure RNG available", forged: false };
|
|
2116
|
+
}
|
|
2117
|
+
let report;
|
|
2118
|
+
try {
|
|
2119
|
+
const res = await fetch(
|
|
2120
|
+
`${base}/aci/attestation?model=${encodeURIComponent(model)}&nonce=${nonce}`
|
|
2121
|
+
);
|
|
2122
|
+
if (res.ok) {
|
|
2123
|
+
report = (await res.json()).report;
|
|
2124
|
+
}
|
|
2125
|
+
} catch {
|
|
2126
|
+
}
|
|
2127
|
+
const quoteHex = report?.attestation?.evidence?.quote;
|
|
2128
|
+
if (!quoteHex) {
|
|
2129
|
+
return {
|
|
2130
|
+
status: "skip",
|
|
2131
|
+
detail: "attestation report (with quote) unavailable \u2014 pass --model?",
|
|
2132
|
+
forged: false
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2135
|
+
try {
|
|
2136
|
+
const dcap = await import('@phala/dcap-qvl');
|
|
2137
|
+
const getCollateralAndVerify = dcap.getCollateralAndVerify ?? dcap.default?.getCollateralAndVerify;
|
|
2138
|
+
if (typeof getCollateralAndVerify !== "function") {
|
|
2139
|
+
return {
|
|
2140
|
+
status: "fail",
|
|
2141
|
+
forged: false,
|
|
2142
|
+
detail: "DCAP verifier unavailable in this build"
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
const quoteBytes = hexToBytes(quoteHex.replace(/^0x/, ""));
|
|
2146
|
+
const vr = await getCollateralAndVerify(quoteBytes);
|
|
2147
|
+
const td = vr.report.asTd10() ?? vr.report.asTd15()?.base ?? null;
|
|
2148
|
+
const reportData = td?.reportData;
|
|
2149
|
+
const signingAddr = report?.signing_address?.replace(/^0x/, "").toLowerCase();
|
|
2150
|
+
const addrBound = Boolean(
|
|
2151
|
+
reportData && signingAddr && bytesToHex(reportData.slice(0, 20)) === signingAddr
|
|
2152
|
+
);
|
|
2153
|
+
const workloadMatch = report?.workload_id === receiptWorkloadId;
|
|
2154
|
+
const tcb = vr.status;
|
|
2155
|
+
const tcbBad = tcb === "Revoked" || tcb === "Unknown";
|
|
2156
|
+
const forged = !(addrBound && workloadMatch) || tcbBad;
|
|
2157
|
+
let detail;
|
|
2158
|
+
if (forged && tcbBad) {
|
|
2159
|
+
detail = `genuine TDX but TCB ${tcb}`;
|
|
2160
|
+
} else if (!addrBound) {
|
|
2161
|
+
detail = "report_data does NOT commit the report's signing address";
|
|
2162
|
+
} else if (!workloadMatch) {
|
|
2163
|
+
detail = "quote workload_id does not match the receipt's";
|
|
2164
|
+
} else {
|
|
2165
|
+
detail = `genuine Intel TDX (verified vs Intel collateral), TCB ${tcb}; report_data commits the attested signing address`;
|
|
2166
|
+
}
|
|
2167
|
+
return { status: forged ? "fail" : "pass", forged, tcbStatus: tcb, detail };
|
|
2168
|
+
} catch (e) {
|
|
2169
|
+
return {
|
|
2170
|
+
status: "fail",
|
|
2171
|
+
forged: false,
|
|
2172
|
+
detail: `could not verify the quote: ${e instanceof Error ? e.message : "error"}`
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2110
2176
|
async function verifyReceipt(receiptId, opts = {}) {
|
|
2111
2177
|
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
2112
2178
|
const network = opts.network ?? "mainnet";
|
|
@@ -2201,7 +2267,6 @@ async function verifyReceipt(receiptId, opts = {}) {
|
|
|
2201
2267
|
});
|
|
2202
2268
|
}
|
|
2203
2269
|
}
|
|
2204
|
-
let signatureForged = false;
|
|
2205
2270
|
let sigStatus = "skip";
|
|
2206
2271
|
let sigDetail = "no signature on receipt";
|
|
2207
2272
|
if (receipt.signature?.value) {
|
|
@@ -2218,7 +2283,6 @@ async function verifyReceipt(receiptId, opts = {}) {
|
|
|
2218
2283
|
} else {
|
|
2219
2284
|
const ok = verifyReceiptSignature(receipt, att.signingKey);
|
|
2220
2285
|
sigStatus = ok ? "pass" : "fail";
|
|
2221
|
-
signatureForged = !ok;
|
|
2222
2286
|
sigDetail = ok ? `signed by the attested receipt key (${receipt.signature.key_id ?? "key"})` : "signature does NOT recover the attested receipt key \u2014 forged/altered";
|
|
2223
2287
|
}
|
|
2224
2288
|
} catch {
|
|
@@ -2231,9 +2295,32 @@ async function verifyReceipt(receiptId, opts = {}) {
|
|
|
2231
2295
|
detail: sigDetail,
|
|
2232
2296
|
trust: sigStatus === "skip" ? "roadmap" : "trustless"
|
|
2233
2297
|
});
|
|
2298
|
+
if (opts.skipQuote) {
|
|
2299
|
+
checks.push({
|
|
2300
|
+
name: "TDX quote (DCAP)",
|
|
2301
|
+
status: "skip",
|
|
2302
|
+
detail: "skipped (--quick)",
|
|
2303
|
+
trust: "trustless"
|
|
2304
|
+
});
|
|
2305
|
+
} else {
|
|
2306
|
+
const q = await verifyTdxQuote(
|
|
2307
|
+
base,
|
|
2308
|
+
opts.model ?? "phala/glm-5.2",
|
|
2309
|
+
workloadId ?? ""
|
|
2310
|
+
);
|
|
2311
|
+
checks.push({
|
|
2312
|
+
name: "TDX quote (DCAP)",
|
|
2313
|
+
status: q.status,
|
|
2314
|
+
detail: q.detail,
|
|
2315
|
+
trust: "trustless"
|
|
2316
|
+
});
|
|
2317
|
+
}
|
|
2318
|
+
const trustlessFailed = checks.some(
|
|
2319
|
+
(c) => c.trust === "trustless" && c.status === "fail"
|
|
2320
|
+
);
|
|
2234
2321
|
return {
|
|
2235
2322
|
receiptId,
|
|
2236
|
-
verified: Boolean(wireHash && workloadId) &&
|
|
2323
|
+
verified: Boolean(wireHash && workloadId) && !trustlessFailed,
|
|
2237
2324
|
anchorVerified,
|
|
2238
2325
|
checks,
|
|
2239
2326
|
wireHash,
|