@motebit/crypto-tpm 1.0.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/verify.js ADDED
@@ -0,0 +1,402 @@
1
+ /**
2
+ * TPM 2.0 quote verifier — the core judgment function this package
3
+ * exports.
4
+ *
5
+ * Flow (matches the TCG verification recipe for TPM2_Quote, plus the
6
+ * motebit-specific identity-key binding step):
7
+ *
8
+ * 1. Split the receipt into (tpmsAttestBase64, signatureBase64,
9
+ * akCertDerBase64, intermediateCertsDerBase64Joined).
10
+ * 2. Parse the TPMS_ATTEST bytes. Assert magic = TPM_GENERATED_VALUE
11
+ * and type = TPM_ST_ATTEST_QUOTE.
12
+ * 3. Parse the AK leaf + any intermediates as X.509. Walk the chain
13
+ * from AK leaf → intermediate → vendor root. Every non-leaf must
14
+ * carry `basicConstraints.cA === true`. Every signature must
15
+ * verify under its issuer's public key. Every validity window
16
+ * must include `now`. The terminal cert's DER must byte-equal
17
+ * ONE of the pinned vendor roots.
18
+ * 4. Verify the AK signature over SHA-256(TPMS_ATTEST_BYTES) using
19
+ * the AK certificate's public key.
20
+ * 5. Re-derive `extraData` from the JCS-canonical body
21
+ * {attested_at, device_id, identity_public_key, motebit_id,
22
+ * platform: "tpm", version: "1"} — SHA-256 of the canonical body
23
+ * — and byte-compare against the transmitted `extraData`. This is
24
+ * the cross-stack binding — without it every other step would
25
+ * prove only that *some* TPM-enrolled device did something, not
26
+ * that the Ed25519 key the credential subject claims is bound
27
+ * to that device.
28
+ *
29
+ * The TPM's own EK certificate provisioning path is NOT verified here
30
+ * — that would require contacting the vendor's EK provisioning service
31
+ * and is out of scope for v1. The outer chain + extraData binding is
32
+ * enough for third-party self-verification of TPM-attested identity.
33
+ */
34
+ import * as x509 from "@peculiar/x509";
35
+ import { DEFAULT_PINNED_TPM_ROOTS } from "./tpm-roots.js";
36
+ import { parseTpmsAttest, TPM_GENERATED_VALUE, TPM_ST_ATTEST_QUOTE } from "./tpm-parse.js";
37
+ /** OID for X.509 basic-constraints extension — carries the CA bit. */
38
+ const BASIC_CONSTRAINTS_OID = "2.5.29.19";
39
+ /**
40
+ * TPM 2.0 quote verifier.
41
+ *
42
+ * Pure. No network. No filesystem. Deterministic given `now()`.
43
+ *
44
+ * `claim` is the `HardwareAttestationClaim` as carried inside the
45
+ * motebit AgentTrustCredential. For TPM, the `attestation_receipt`
46
+ * field is expected to be four base64url segments separated by `.`:
47
+ *
48
+ * `{tpmsAttestB64}.{signatureB64}.{akCertDerB64}.{intermediatesJoinedB64}`
49
+ *
50
+ * `intermediatesJoinedB64` may itself be an empty segment (`""`) when
51
+ * the AK cert chains directly to a pinned root, or a `,`-joined
52
+ * concatenation of base64url-encoded DER intermediates in leaf-
53
+ * proximal-first order otherwise.
54
+ */
55
+ export async function verifyTpmQuote(claim, opts) {
56
+ const errors = [];
57
+ let cert_chain_valid = false;
58
+ let quote_signature_valid = false;
59
+ let quote_shape_valid = false;
60
+ let identity_bound = false;
61
+ if (!claim.attestation_receipt) {
62
+ errors.push({ message: "tpm claim missing `attestation_receipt`" });
63
+ return fail(errors);
64
+ }
65
+ const parts = claim.attestation_receipt.split(".");
66
+ if (parts.length !== 4) {
67
+ errors.push({
68
+ message: `attestation_receipt must be 4 base64url parts (tpmsAttest.signature.akCert.intermediates); got ${parts.length}`,
69
+ });
70
+ return fail(errors);
71
+ }
72
+ const [attestB64, sigB64, akCertB64, intermediatesB64] = parts;
73
+ let attestBytes;
74
+ let sigBytes;
75
+ let akCertBytes;
76
+ let intermediateCertsBytes;
77
+ try {
78
+ attestBytes = fromBase64Url(attestB64);
79
+ sigBytes = fromBase64Url(sigB64);
80
+ akCertBytes = fromBase64Url(akCertB64);
81
+ intermediateCertsBytes =
82
+ intermediatesB64.length === 0 ? [] : intermediatesB64.split(",").map((p) => fromBase64Url(p));
83
+ }
84
+ catch (err) {
85
+ errors.push({ message: `base64url decode failed: ${messageOf(err)}` });
86
+ return fail(errors);
87
+ }
88
+ // ── Step 2: quote shape ─────────────────────────────────────────
89
+ let attest;
90
+ try {
91
+ attest = parseTpmsAttest(attestBytes);
92
+ }
93
+ catch (err) {
94
+ errors.push({ message: `TPMS_ATTEST parse: ${messageOf(err)}` });
95
+ return fail(errors, {
96
+ cert_chain_valid,
97
+ quote_signature_valid,
98
+ quote_shape_valid,
99
+ identity_bound,
100
+ });
101
+ }
102
+ if (attest.magic !== TPM_GENERATED_VALUE) {
103
+ errors.push({
104
+ message: `TPMS_ATTEST magic is 0x${attest.magic.toString(16)}; expected 0x${TPM_GENERATED_VALUE.toString(16)} (TPM_GENERATED_VALUE)`,
105
+ });
106
+ }
107
+ else if (attest.type !== TPM_ST_ATTEST_QUOTE) {
108
+ errors.push({
109
+ message: `TPMS_ATTEST type is 0x${attest.type.toString(16)}; expected 0x${TPM_ST_ATTEST_QUOTE.toString(16)} (TPM_ST_ATTEST_QUOTE)`,
110
+ });
111
+ }
112
+ else {
113
+ quote_shape_valid = true;
114
+ }
115
+ // ── Step 3: chain verify AK → intermediates → pinned vendor root ─
116
+ let akCert;
117
+ let intermediates;
118
+ let rootCerts;
119
+ try {
120
+ akCert = new x509.X509Certificate(toArrayBuffer(akCertBytes));
121
+ intermediates = intermediateCertsBytes.map((b) => new x509.X509Certificate(toArrayBuffer(b)));
122
+ const pems = opts.rootPems ?? DEFAULT_PINNED_TPM_ROOTS;
123
+ rootCerts = pems.map((pem) => new x509.X509Certificate(pem));
124
+ }
125
+ catch (err) {
126
+ errors.push({ message: `x509 parse: ${messageOf(err)}` });
127
+ return fail(errors, {
128
+ cert_chain_valid,
129
+ quote_signature_valid,
130
+ quote_shape_valid,
131
+ identity_bound,
132
+ });
133
+ }
134
+ const nowDate = new Date(opts.now ? opts.now() : Date.now());
135
+ try {
136
+ const chainResult = await verifyTpmCertChain({
137
+ leaf: akCert,
138
+ intermediates,
139
+ pinnedRoots: rootCerts,
140
+ nowDate,
141
+ });
142
+ cert_chain_valid = chainResult.valid;
143
+ if (!cert_chain_valid) {
144
+ errors.push({ message: chainResult.reason });
145
+ }
146
+ }
147
+ catch (err) {
148
+ errors.push({ message: `chain verify crashed: ${messageOf(err)}` });
149
+ return fail(errors, {
150
+ cert_chain_valid,
151
+ quote_signature_valid,
152
+ quote_shape_valid,
153
+ identity_bound,
154
+ });
155
+ }
156
+ // ── Step 4: AK signature over SHA-256(attestBytes) ──────────────
157
+ // TPM 2.0 AKs are most commonly ECDSA-P256 (the TCG's recommended
158
+ // profile). Future RSA-2048 AKs land as an additional dispatch arm
159
+ // once a real-RSA-TPM fixture is captured; today ECDSA is the only
160
+ // shape our test surface exercises and the only shape the Rust
161
+ // bridge will produce at landing.
162
+ //
163
+ // We route BOTH the `publicKey.export(...)` call AND the
164
+ // `subtle.verify(...)` call through the SAME crypto provider — the
165
+ // one registered with `@peculiar/x509`'s `cryptoProvider`. Mixing a
166
+ // CryptoKey minted by `@peculiar/webcrypto` with Node's native
167
+ // `globalThis.crypto.subtle.verify` throws "2nd argument is not of
168
+ // type CryptoKey" because the two providers mint different internal
169
+ // shapes. Staying on one provider keeps the SAB boundary clean.
170
+ try {
171
+ const provider = x509.cryptoProvider.get();
172
+ const cryptoKey = await akCert.publicKey.export({ name: "ECDSA", namedCurve: "P-256" }, ["verify"], provider);
173
+ const sigOk = await provider.subtle.verify({ name: "ECDSA", hash: "SHA-256" }, cryptoKey, sigBytes, attestBytes);
174
+ if (sigOk) {
175
+ quote_signature_valid = true;
176
+ }
177
+ else {
178
+ errors.push({
179
+ message: "AK signature does not verify against SHA-256(TPMS_ATTEST) — quote may be tampered or AK mismatch",
180
+ });
181
+ }
182
+ }
183
+ catch (err) {
184
+ errors.push({ message: `AK signature verify crashed: ${messageOf(err)}` });
185
+ }
186
+ // ── Step 5: identity binding via extraData ──────────────────────
187
+ try {
188
+ if (typeof opts.expectedIdentityPublicKeyHex !== "string" ||
189
+ opts.expectedIdentityPublicKeyHex.length === 0) {
190
+ errors.push({
191
+ message: "identity_bound: expectedIdentityPublicKeyHex not supplied",
192
+ });
193
+ }
194
+ else if (typeof opts.expectedMotebitId !== "string" || opts.expectedMotebitId.length === 0) {
195
+ errors.push({
196
+ message: "identity_bound: expectedMotebitId not supplied (required for body re-derivation)",
197
+ });
198
+ }
199
+ else if (typeof opts.expectedDeviceId !== "string" || opts.expectedDeviceId.length === 0) {
200
+ errors.push({
201
+ message: "identity_bound: expectedDeviceId not supplied (required for body re-derivation)",
202
+ });
203
+ }
204
+ else if (typeof opts.expectedAttestedAt !== "number" ||
205
+ !Number.isFinite(opts.expectedAttestedAt)) {
206
+ errors.push({
207
+ message: "identity_bound: expectedAttestedAt not supplied (required for body re-derivation)",
208
+ });
209
+ }
210
+ else {
211
+ const canonicalBody = buildCanonicalTpmBody({
212
+ attested_at: opts.expectedAttestedAt,
213
+ device_id: opts.expectedDeviceId,
214
+ identity_public_key: opts.expectedIdentityPublicKeyHex.toLowerCase(),
215
+ motebit_id: opts.expectedMotebitId,
216
+ });
217
+ const derived = await sha256Bytes(new TextEncoder().encode(canonicalBody));
218
+ if (bytesEq(derived, attest.extraData)) {
219
+ identity_bound = true;
220
+ }
221
+ else {
222
+ errors.push({
223
+ message: "identity_bound: reconstructed SHA256(canonical body) does not equal transmitted extraData — body naming the caller's identity was not the body the TPM signed over",
224
+ });
225
+ }
226
+ }
227
+ }
228
+ catch (err) {
229
+ errors.push({ message: `identity binding crashed: ${messageOf(err)}` });
230
+ }
231
+ return {
232
+ valid: cert_chain_valid && quote_signature_valid && quote_shape_valid && identity_bound,
233
+ cert_chain_valid,
234
+ quote_signature_valid,
235
+ quote_shape_valid,
236
+ identity_bound,
237
+ errors,
238
+ };
239
+ }
240
+ // ── Helpers ─────────────────────────────────────────────────────────
241
+ function fail(errors, partial) {
242
+ return {
243
+ valid: false,
244
+ cert_chain_valid: partial?.cert_chain_valid ?? false,
245
+ quote_signature_valid: partial?.quote_signature_valid ?? false,
246
+ quote_shape_valid: partial?.quote_shape_valid ?? false,
247
+ identity_bound: partial?.identity_bound ?? false,
248
+ errors,
249
+ };
250
+ }
251
+ function messageOf(err) {
252
+ return err instanceof Error ? err.message : String(err);
253
+ }
254
+ async function sha256Bytes(data) {
255
+ const buf = await globalThis.crypto.subtle.digest("SHA-256", data);
256
+ return new Uint8Array(buf);
257
+ }
258
+ function bytesEq(a, b) {
259
+ if (a.length !== b.length)
260
+ return false;
261
+ for (let i = 0; i < a.length; i++)
262
+ if (a[i] !== b[i])
263
+ return false;
264
+ return true;
265
+ }
266
+ /**
267
+ * Walk the TPM cert chain from AK → intermediates → one of the pinned
268
+ * vendor roots. Enforces:
269
+ *
270
+ * 1. `X509ChainBuilder.build(leaf)` with the AK + intermediates + all
271
+ * pinned roots as the candidate pool produces a complete chain
272
+ * terminating at a self-signed cert.
273
+ * 2. The chain's terminal cert's DER equals at least ONE of the pinned
274
+ * vendor roots — the only acceptable trust anchors.
275
+ * 3. Every non-leaf cert in the chain carries
276
+ * `basicConstraints.cA === true`. A misissued leaf presented as an
277
+ * intermediate fails here even if its signature chains.
278
+ * 4. Every cert's signature verifies under its issuer's public key.
279
+ * 5. Every cert is within its validity window at `nowDate`.
280
+ */
281
+ async function verifyTpmCertChain(input) {
282
+ const { leaf, intermediates, pinnedRoots, nowDate } = input;
283
+ const builder = new x509.X509ChainBuilder({
284
+ certificates: [leaf, ...intermediates, ...pinnedRoots],
285
+ });
286
+ const chain = await builder.build(leaf);
287
+ const terminal = chain[chain.length - 1];
288
+ const terminalSelfSigned = await terminal.isSelfSigned();
289
+ if (!terminalSelfSigned) {
290
+ return {
291
+ valid: false,
292
+ reason: "chain does not terminate at a self-signed root",
293
+ };
294
+ }
295
+ // Terminal DER must byte-equal at least one pinned vendor root. This
296
+ // is what defines "this is a TPM we accept" — the self-signed check
297
+ // alone would allow an attacker-chosen root to pass.
298
+ const terminalDer = new Uint8Array(terminal.rawData);
299
+ const matchedPinnedRoot = pinnedRoots.some((r) => bytesEq(terminalDer, new Uint8Array(r.rawData)));
300
+ if (!matchedPinnedRoot) {
301
+ return {
302
+ valid: false,
303
+ reason: "chain terminal cert DER does not match any pinned TPM vendor root " +
304
+ "(Infineon / Nuvoton / STMicro / Intel PTT)",
305
+ };
306
+ }
307
+ for (let i = 0; i < chain.length; i++) {
308
+ const cert = chain[i];
309
+ if (nowDate < cert.notBefore || nowDate > cert.notAfter) {
310
+ return {
311
+ valid: false,
312
+ reason: `cert at chain position ${i} is outside its validity window at ${nowDate.toISOString()}`,
313
+ };
314
+ }
315
+ const isLeaf = i === 0;
316
+ if (!isLeaf && !certHasCaTrue(cert)) {
317
+ return {
318
+ valid: false,
319
+ reason: `cert at chain position ${i} lacks basicConstraints.cA=true (CA constraint not enforced)`,
320
+ };
321
+ }
322
+ const issuer = i === chain.length - 1 ? cert : chain[i + 1];
323
+ const sigOk = await cert.verify({ publicKey: issuer.publicKey, date: nowDate });
324
+ if (!sigOk) {
325
+ return {
326
+ valid: false,
327
+ reason: `cert at chain position ${i} signature did not verify under its issuer's public key`,
328
+ };
329
+ }
330
+ }
331
+ return { valid: true, reason: "ok" };
332
+ }
333
+ function certHasCaTrue(cert) {
334
+ const ext = cert.getExtension(BASIC_CONSTRAINTS_OID);
335
+ if (!ext)
336
+ return false;
337
+ return ext.ca === true;
338
+ }
339
+ /**
340
+ * Reconstruct the byte-identical canonical body the Rust TPM bridge
341
+ * composes at quote time. Must stay byte-equal to what
342
+ * `apps/desktop/src-tauri/src/tpm.rs::canonical_body` will emit when
343
+ * the full `tss-esapi`-backed path lands.
344
+ *
345
+ * Ordering: alphabetical (JCS):
346
+ * attested_at, device_id, identity_public_key, motebit_id, platform,
347
+ * version.
348
+ *
349
+ * `platform` is always `"tpm"` and `version` is always `"1"` — both
350
+ * constants, matching the sibling App Attest path's shape exactly.
351
+ */
352
+ function buildCanonicalTpmBody(input) {
353
+ return (`{"attested_at":${input.attested_at}` +
354
+ `,"device_id":${jsonEscapeString(input.device_id)}` +
355
+ `,"identity_public_key":${jsonEscapeString(input.identity_public_key)}` +
356
+ `,"motebit_id":${jsonEscapeString(input.motebit_id)}` +
357
+ `,"platform":"tpm"` +
358
+ `,"version":"1"}`);
359
+ }
360
+ function jsonEscapeString(s) {
361
+ let out = '"';
362
+ for (const ch of s) {
363
+ const code = ch.codePointAt(0);
364
+ if (ch === '"')
365
+ out += '\\"';
366
+ else if (ch === "\\")
367
+ out += "\\\\";
368
+ else if (ch === "\n")
369
+ out += "\\n";
370
+ else if (ch === "\r")
371
+ out += "\\r";
372
+ else if (ch === "\t")
373
+ out += "\\t";
374
+ else if (code < 0x20)
375
+ out += `\\u${code.toString(16).padStart(4, "0")}`;
376
+ else
377
+ out += ch;
378
+ }
379
+ out += '"';
380
+ return out;
381
+ }
382
+ function toArrayBuffer(bytes) {
383
+ const copy = new Uint8Array(bytes.length);
384
+ copy.set(bytes);
385
+ return copy.buffer;
386
+ }
387
+ function fromBase64Url(str) {
388
+ let b64 = str.replace(/-/g, "+").replace(/_/g, "/");
389
+ const pad = b64.length % 4;
390
+ if (pad === 2)
391
+ b64 += "==";
392
+ else if (pad === 3)
393
+ b64 += "=";
394
+ else if (pad === 1)
395
+ throw new Error("invalid base64url length");
396
+ const binary = atob(b64);
397
+ const out = new Uint8Array(binary.length);
398
+ for (let i = 0; i < binary.length; i++)
399
+ out[i] = binary.charCodeAt(i);
400
+ return out;
401
+ }
402
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@motebit/crypto-tpm",
3
+ "version": "1.0.0",
4
+ "description": "Apache-2.0 verifier for TPM 2.0 Endorsement-Key hardware-attestation credentials — offline chain verification against pinned vendor EK roots (Infineon, Nuvoton, STMicro, Intel PTT) plus binary TPMS_ATTEST parsing. Plugs into @motebit/crypto's HardwareAttestationVerifiers dispatcher to validate TPM-attested motebit identities on Windows/Linux hosts.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist/**/*.js",
16
+ "dist/**/*.js.map",
17
+ "dist/**/*.d.ts",
18
+ "dist/**/*.d.ts.map",
19
+ "LICENSE",
20
+ "NOTICE",
21
+ "README.md"
22
+ ],
23
+ "sideEffects": false,
24
+ "license": "Apache-2.0",
25
+ "keywords": [
26
+ "motebit",
27
+ "tpm",
28
+ "tpm2",
29
+ "attestation",
30
+ "endorsement-key",
31
+ "hardware-attestation",
32
+ "windows",
33
+ "linux",
34
+ "x509",
35
+ "verify"
36
+ ],
37
+ "homepage": "https://github.com/motebit/motebit/tree/main/packages/crypto-tpm#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/motebit/motebit/issues"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/motebit/motebit",
44
+ "directory": "packages/crypto-tpm"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "motebit": {
50
+ "implements": [
51
+ "spec/credential-v1.md"
52
+ ]
53
+ },
54
+ "dependencies": {
55
+ "@peculiar/x509": "^1.12.0",
56
+ "@motebit/protocol": "1.0.0",
57
+ "@motebit/crypto": "1.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@noble/curves": "~1.9.0",
61
+ "@noble/hashes": "~1.6.0",
62
+ "@peculiar/webcrypto": "^1.5.0",
63
+ "@types/node": "^22.0.0",
64
+ "typescript": "^5.6.0",
65
+ "vitest": "^2.1.0"
66
+ },
67
+ "engines": {
68
+ "node": ">=20"
69
+ },
70
+ "scripts": {
71
+ "build": "tsc -b",
72
+ "test": "vitest run",
73
+ "test:coverage": "vitest run --coverage",
74
+ "typecheck": "tsc --noEmit",
75
+ "lint": "eslint --parser-options=project:tsconfig.eslint.json src/",
76
+ "lint:pack": "publint --strict && attw --pack --profile esm-only",
77
+ "clean": "rm -rf dist .turbo *.tsbuildinfo"
78
+ }
79
+ }