@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/LICENSE +206 -0
- package/NOTICE +19 -0
- package/README.md +49 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/tpm-parse.d.ts +92 -0
- package/dist/tpm-parse.d.ts.map +1 -0
- package/dist/tpm-parse.js +170 -0
- package/dist/tpm-parse.js.map +1 -0
- package/dist/tpm-roots.d.ts +90 -0
- package/dist/tpm-roots.d.ts.map +1 -0
- package/dist/tpm-roots.js +139 -0
- package/dist/tpm-roots.js.map +1 -0
- package/dist/verify.d.ts +99 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +402 -0
- package/dist/verify.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal TPM 2.0 binary-format parser.
|
|
3
|
+
*
|
|
4
|
+
* The TPM marshals structured data as big-endian size-prefixed bytes —
|
|
5
|
+
* distinct from CBOR / DER / JSON and wholly specific to the TCG's TPM
|
|
6
|
+
* Structures specification. Verification of a TPM quote requires
|
|
7
|
+
* extracting exactly three fields from the `TPMS_ATTEST` structure:
|
|
8
|
+
*
|
|
9
|
+
* - `magic` — 4-byte constant, must equal `TPM_GENERATED_VALUE`.
|
|
10
|
+
* - `type` — 2-byte constant, `TPM_ST_ATTEST_QUOTE` for quotes.
|
|
11
|
+
* - `qualifiedSigner` — length-prefixed `TPM2B_NAME`, identifies the AK.
|
|
12
|
+
* - `extraData` — length-prefixed `TPM2B_DATA`, this is where
|
|
13
|
+
* motebit threads the identity binding.
|
|
14
|
+
*
|
|
15
|
+
* We deliberately skip the remainder (clockInfo, firmwareVersion, the
|
|
16
|
+
* attested quote body containing PCR digests) — motebit's claim is
|
|
17
|
+
* about identity binding, not platform-state attestation. The body's
|
|
18
|
+
* signature (produced by TPM2_Quote using the AK) covers the entire
|
|
19
|
+
* serialized `TPMS_ATTEST`; any byte drift would invalidate it.
|
|
20
|
+
*
|
|
21
|
+
* Hand-rolled over `node-tpm2-pts`: the parser is ~80 LOC and covers
|
|
22
|
+
* exactly our needs. Pulling a dep for that would cross a larger
|
|
23
|
+
* attack surface than the struct we parse.
|
|
24
|
+
*
|
|
25
|
+
* References:
|
|
26
|
+
* - TCG TPM 2.0 Library, Part 2: Structures — §10.12 `TPMS_ATTEST`.
|
|
27
|
+
* - TCG TPM 2.0 Library, Part 1: Architecture — §36.1 `TPM2B_*` types.
|
|
28
|
+
*/
|
|
29
|
+
/** Constant magic value every TPM-signed attest carries. */
|
|
30
|
+
export const TPM_GENERATED_VALUE = 0xff544347; // ASCII "ÿTCG"
|
|
31
|
+
/** `TPM_ST_ATTEST_QUOTE` — the structure-tag identifying a quote attestation. */
|
|
32
|
+
export const TPM_ST_ATTEST_QUOTE = 0x8018;
|
|
33
|
+
/**
|
|
34
|
+
* Parse a TPM 2.0 `TPMS_ATTEST` structure. Throws on malformed input;
|
|
35
|
+
* the outer `verify.ts` catches and converts to the fail-closed result
|
|
36
|
+
* shape.
|
|
37
|
+
*
|
|
38
|
+
* Wire layout:
|
|
39
|
+
* uint32 magic ; 4 bytes
|
|
40
|
+
* uint16 type ; 2 bytes
|
|
41
|
+
* TPM2B_NAME qualifiedSigner ; uint16 size || bytes
|
|
42
|
+
* TPM2B_DATA extraData ; uint16 size || bytes
|
|
43
|
+
* TPMS_CLOCK_INFO clockInfo ; 17 bytes (fixed)
|
|
44
|
+
* uint64 firmwareVersion ; 8 bytes
|
|
45
|
+
* TPMU_ATTEST attested ; variable, tag-specific
|
|
46
|
+
*
|
|
47
|
+
* We extract magic / type / qualifiedSigner / extraData and stash the
|
|
48
|
+
* rest in `trailer` so the caller can reconstruct the full signed
|
|
49
|
+
* bytes when verifying the AK signature. The caller retains the
|
|
50
|
+
* original buffer; this view points into it via length-accurate
|
|
51
|
+
* subarray copies.
|
|
52
|
+
*/
|
|
53
|
+
export function parseTpmsAttest(bytes) {
|
|
54
|
+
if (bytes.length < 4 + 2 + 2 + 2) {
|
|
55
|
+
throw new Error(`TPMS_ATTEST too short: ${bytes.length} bytes (need at least 10 for header fields)`);
|
|
56
|
+
}
|
|
57
|
+
const reader = new TpmReader(bytes);
|
|
58
|
+
const magic = reader.readUint32();
|
|
59
|
+
const type = reader.readUint16();
|
|
60
|
+
const qualifiedSigner = reader.readTpm2B();
|
|
61
|
+
const extraData = reader.readTpm2B();
|
|
62
|
+
const trailer = reader.remaining();
|
|
63
|
+
return { magic, type, qualifiedSigner, extraData, trailer };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build a minimal `TPMS_ATTEST` byte sequence for tests.
|
|
67
|
+
*
|
|
68
|
+
* Tests fabricate a valid-shape attest so the verifier's parsing +
|
|
69
|
+
* extraData-binding code paths exercise without a real TPM. Production
|
|
70
|
+
* minting lives in the Rust bridge — never call `composeTpmsAttest`
|
|
71
|
+
* outside `__tests__/` or you'll drift from what a real TPM would sign.
|
|
72
|
+
*
|
|
73
|
+
* `trailer` defaults to a deterministic 17-byte clockInfo + 8-byte
|
|
74
|
+
* firmwareVersion filler + 4-byte quote filler so the resulting bytes
|
|
75
|
+
* pass the minimum-length check during parsing; tests that need the
|
|
76
|
+
* real trailing fields can override.
|
|
77
|
+
*/
|
|
78
|
+
export function composeTpmsAttestForTest(input) {
|
|
79
|
+
const magic = input.magic ?? TPM_GENERATED_VALUE;
|
|
80
|
+
const type = input.type ?? TPM_ST_ATTEST_QUOTE;
|
|
81
|
+
const trailer = input.trailer ?? new Uint8Array(17 + 8 + 4);
|
|
82
|
+
const out = new TpmWriter();
|
|
83
|
+
out.writeUint32(magic);
|
|
84
|
+
out.writeUint16(type);
|
|
85
|
+
out.writeTpm2B(input.qualifiedSigner);
|
|
86
|
+
out.writeTpm2B(input.extraData);
|
|
87
|
+
out.writeRaw(trailer);
|
|
88
|
+
return out.toBytes();
|
|
89
|
+
}
|
|
90
|
+
// ── Internal helpers ────────────────────────────────────────────────
|
|
91
|
+
class TpmReader {
|
|
92
|
+
bytes;
|
|
93
|
+
offset = 0;
|
|
94
|
+
constructor(bytes) {
|
|
95
|
+
this.bytes = bytes;
|
|
96
|
+
}
|
|
97
|
+
readUint16() {
|
|
98
|
+
if (this.offset + 2 > this.bytes.length) {
|
|
99
|
+
throw new Error(`TPM reader: uint16 at offset ${this.offset} would overrun buffer`);
|
|
100
|
+
}
|
|
101
|
+
const hi = this.bytes[this.offset];
|
|
102
|
+
const lo = this.bytes[this.offset + 1];
|
|
103
|
+
this.offset += 2;
|
|
104
|
+
return (hi << 8) | lo;
|
|
105
|
+
}
|
|
106
|
+
readUint32() {
|
|
107
|
+
if (this.offset + 4 > this.bytes.length) {
|
|
108
|
+
throw new Error(`TPM reader: uint32 at offset ${this.offset} would overrun buffer`);
|
|
109
|
+
}
|
|
110
|
+
const b0 = this.bytes[this.offset];
|
|
111
|
+
const b1 = this.bytes[this.offset + 1];
|
|
112
|
+
const b2 = this.bytes[this.offset + 2];
|
|
113
|
+
const b3 = this.bytes[this.offset + 3];
|
|
114
|
+
this.offset += 4;
|
|
115
|
+
// Use unsigned-right-shift by 0 to force a non-negative 32-bit value.
|
|
116
|
+
return ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3) >>> 0;
|
|
117
|
+
}
|
|
118
|
+
readTpm2B() {
|
|
119
|
+
const size = this.readUint16();
|
|
120
|
+
if (this.offset + size > this.bytes.length) {
|
|
121
|
+
throw new Error(`TPM reader: TPM2B length ${size} at offset ${this.offset} would overrun buffer ` +
|
|
122
|
+
`(length ${this.bytes.length})`);
|
|
123
|
+
}
|
|
124
|
+
const value = this.bytes.subarray(this.offset, this.offset + size);
|
|
125
|
+
this.offset += size;
|
|
126
|
+
// Return a detached copy — consumers may treat the result as owned.
|
|
127
|
+
return new Uint8Array(value);
|
|
128
|
+
}
|
|
129
|
+
remaining() {
|
|
130
|
+
const rest = this.bytes.subarray(this.offset);
|
|
131
|
+
return new Uint8Array(rest);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
class TpmWriter {
|
|
135
|
+
chunks = [];
|
|
136
|
+
writeUint16(v) {
|
|
137
|
+
const buf = new Uint8Array(2);
|
|
138
|
+
buf[0] = (v >> 8) & 0xff;
|
|
139
|
+
buf[1] = v & 0xff;
|
|
140
|
+
this.chunks.push(buf);
|
|
141
|
+
}
|
|
142
|
+
writeUint32(v) {
|
|
143
|
+
const buf = new Uint8Array(4);
|
|
144
|
+
buf[0] = (v >>> 24) & 0xff;
|
|
145
|
+
buf[1] = (v >>> 16) & 0xff;
|
|
146
|
+
buf[2] = (v >>> 8) & 0xff;
|
|
147
|
+
buf[3] = v & 0xff;
|
|
148
|
+
this.chunks.push(buf);
|
|
149
|
+
}
|
|
150
|
+
writeTpm2B(bytes) {
|
|
151
|
+
this.writeUint16(bytes.length);
|
|
152
|
+
this.chunks.push(new Uint8Array(bytes));
|
|
153
|
+
}
|
|
154
|
+
writeRaw(bytes) {
|
|
155
|
+
this.chunks.push(new Uint8Array(bytes));
|
|
156
|
+
}
|
|
157
|
+
toBytes() {
|
|
158
|
+
let total = 0;
|
|
159
|
+
for (const c of this.chunks)
|
|
160
|
+
total += c.length;
|
|
161
|
+
const out = new Uint8Array(total);
|
|
162
|
+
let at = 0;
|
|
163
|
+
for (const c of this.chunks) {
|
|
164
|
+
out.set(c, at);
|
|
165
|
+
at += c.length;
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=tpm-parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tpm-parse.js","sourceRoot":"","sources":["../src/tpm-parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pinned TPM 2.0 Endorsement-Key vendor root certificates.
|
|
3
|
+
*
|
|
4
|
+
* Every `platform: "tpm"` hardware-attestation claim must chain to one of
|
|
5
|
+
* the root CAs listed here. Pinning is the self-attesting contract — a
|
|
6
|
+
* verifier that dynamically fetched vendor CAs could not be reproduced
|
|
7
|
+
* by a third-party audit. By committing the exact bytes of the CAs we
|
|
8
|
+
* accept, anyone can audit this file, pin the same bytes in their own
|
|
9
|
+
* verifier, and reach the same yes/no answer.
|
|
10
|
+
*
|
|
11
|
+
* The TPM ecosystem is multi-vendor by design: every Windows 11 device
|
|
12
|
+
* ships with TPM 2.0 (Microsoft's mandatory requirement), every modern
|
|
13
|
+
* Linux-on-x86 laptop has one, every Mac with a T2 chip has one. Each
|
|
14
|
+
* vendor maintains a public CA bundle rooted at their Endorsement-Key
|
|
15
|
+
* issuer. The motebit policy pins the four most common:
|
|
16
|
+
*
|
|
17
|
+
* - Infineon (`OptigaTrustM`, `SLB966x` families)
|
|
18
|
+
* - Nuvoton (`NPCT7xx` family)
|
|
19
|
+
* - STMicroelectronics (`ST33TPHF2ESPI`, `ST33HTPH2E32AHB3` families)
|
|
20
|
+
* - Intel PTT (firmware TPM bundled with Intel CSME)
|
|
21
|
+
*
|
|
22
|
+
* AMD fTPM (firmware TPM bundled with AMD PSP) uses a vendor-signed
|
|
23
|
+
* chain that roots to AMD's EK CA; that root is additive and lands in
|
|
24
|
+
* a subsequent pass once the first AMD-shaped test vector is captured.
|
|
25
|
+
*
|
|
26
|
+
* ## Operator follow-up — ship-blocking for production rollout
|
|
27
|
+
*
|
|
28
|
+
* The PEMs below are declared as exported constants so the test suite
|
|
29
|
+
* exercises the same chain-verification code path end-to-end. For a
|
|
30
|
+
* production ship, an operator must replace each placeholder with the
|
|
31
|
+
* exact byte-for-byte vendor root published at the URL in the comment.
|
|
32
|
+
* The test fabrication pattern (`buildFakeChain` in `__tests__`) does
|
|
33
|
+
* not need the real bytes — tests inject their own roots — so swapping
|
|
34
|
+
* in the real vendor PEMs is a mechanical operator task, not a code
|
|
35
|
+
* change. The drift gate `check-hardware-attestation-primitives` covers
|
|
36
|
+
* the parser / composer contract; the vendor-root swap is tracked in
|
|
37
|
+
* `docs/doctrine/hardware-attestation.md` §Non-goals.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Infineon OPTIGA TPM 2.0 Endorsement Key Root CA.
|
|
41
|
+
*
|
|
42
|
+
* Published at: https://pki.infineon.com/OptigaEccRootCA/OptigaEccRootCA.crt
|
|
43
|
+
*
|
|
44
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
45
|
+
* production rollout. Tests override via `rootPems` option.
|
|
46
|
+
*/
|
|
47
|
+
export declare const INFINEON_TPM_EK_ROOT_PEM = "-----BEGIN CERTIFICATE-----\nMIIBdjCCARygAwIBAgIJAIMw8f7k8+xyMAoGCCqGSM49BAMCMCIxIDAeBgNVBAMM\nF01vdGViaXQgSW5maW5lb24gUGxhY2Vob2xkZXIwHhcNMjYwNDIyMDAwMDAwWhcN\nNDYwNDIyMDAwMDAwWjAiMSAwHgYDVQQDDBdNb3RlYml0IEluZmluZW9uIFBsYWNl\naG9sZGVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKZ/4LNYqi/LAI4R6tS2K\nkRUnhkRzkYfi5hmz2E+35mqWVNqCb/FRhk6dEuxCNbwJxFPEK4Opf5lCOs0ZsRdF\n+KNCMEAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQp3ojpUGm1YB9N+9lQHg0s\nVpSoBTAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCjxfFCCf6t\nCpGcGc7Gsk8h2RFQ7CFW8NzkjuvUZZ7bwwIhAJ/CB4+XzV5EhcOf0qRZN8zmJb8G\nB9Z9EFcZ7Nt1l4Tn\n-----END CERTIFICATE-----\n";
|
|
48
|
+
/**
|
|
49
|
+
* Nuvoton NPCT TPM 2.0 Endorsement Key Root CA.
|
|
50
|
+
*
|
|
51
|
+
* Published at: https://www.nuvoton.com/security/NTC-TPM-EK-Cert/Nuvoton TPM Root CA 2110.cer
|
|
52
|
+
*
|
|
53
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
54
|
+
* production rollout. Tests override via `rootPems` option.
|
|
55
|
+
*/
|
|
56
|
+
export declare const NUVOTON_TPM_EK_ROOT_PEM = "-----BEGIN CERTIFICATE-----\nMIIBczCCARmgAwIBAgIJAL7X6p2yXxJJMAoGCCqGSM49BAMCMCAxHjAcBgNVBAMM\nFU1vdGViaXQgTnV2b3RvbiBQbGFjZWhvbGRlcjAeFw0yNjA0MjIwMDAwMDBaFw00\nNjA0MjIwMDAwMDBaMCAxHjAcBgNVBAMMFU1vdGViaXQgTnV2b3RvbiBQbGFjZWhv\nbGRlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJgPwHoU+cVjX3HzkXpEksdn\nf3KPRwMbFYvE3tkqDcW8JqzG8qO5VwPKFPwoAEE2C8dJpKHEk7fA4iGrSXz7x/6j\nQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUNskUYy3Uz8Tvuvbu/B5VTJA2\nlLcwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiAAbU6/dL06n8Cw\nCYI/rHo/cLWEFQKH5VnzDJH4RN5fIgIgAN0F3fYbTBa9H8OXCJdXUDxSDr2iT8E5\nVDz6f2s3uFo=\n-----END CERTIFICATE-----\n";
|
|
57
|
+
/**
|
|
58
|
+
* STMicroelectronics ST33 TPM 2.0 Endorsement Key Root CA.
|
|
59
|
+
*
|
|
60
|
+
* Published at: https://sw-center.st.com/STM_ROOT_CA_2.crt
|
|
61
|
+
*
|
|
62
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
63
|
+
* production rollout. Tests override via `rootPems` option.
|
|
64
|
+
*/
|
|
65
|
+
export declare const STMICRO_TPM_EK_ROOT_PEM = "-----BEGIN CERTIFICATE-----\nMIIBdDCCARqgAwIBAgIJAMZ4+9xZHMuaMAoGCCqGSM49BAMCMCExHzAdBgNVBAMM\nFk1vdGViaXQgU1RNaWNybyBQbGFjZWhvbGRlcjAeFw0yNjA0MjIwMDAwMDBaFw00\nNjA0MjIwMDAwMDBaMCExHzAdBgNVBAMMFk1vdGViaXQgU1RNaWNybyBQbGFjZWhv\nbGRlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLnK3t7y4JBJxzE0EFq+zsOV\n+m9n9D1YDUFb7k6hVIsKvfoH9o3rZkc4uRuSsz7fjC+IsKsMrJKXaU0mxH6ncjej\nQjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUe/x8wdJYzEypFT3M0K1Jy5C6\n1j8wDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiAc9Ln4qhL7fZ5c\noUbLFsTVTEc4aeBMkxqzLrJpZOYVegIgWSfLj2Q5CQ8OFvJx8fVDkxN9OXjYT6Jm\nH6Bvb0gQaG8=\n-----END CERTIFICATE-----\n";
|
|
66
|
+
/**
|
|
67
|
+
* Intel PTT (Platform Trust Technology, firmware TPM inside Intel CSME)
|
|
68
|
+
* Endorsement Key Root CA.
|
|
69
|
+
*
|
|
70
|
+
* Published at: https://upgrades.intel.com/content/CRL/ekcert/EKRootPublicKey.cer
|
|
71
|
+
*
|
|
72
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
73
|
+
* production rollout. Tests override via `rootPems` option.
|
|
74
|
+
*/
|
|
75
|
+
export declare const INTEL_PTT_EK_ROOT_PEM = "-----BEGIN CERTIFICATE-----\nMIIBcjCCARegAwIBAgIJAOQz8pPRrTIxMAoGCCqGSM49BAMCMB8xHTAbBgNVBAMM\nFE1vdGViaXQgSW50ZWwgUGxhY2Vob2xkZXIwHhcNMjYwNDIyMDAwMDAwWhcNNDYw\nNDIyMDAwMDAwWjAfMR0wGwYDVQQDDBRNb3RlYml0IEludGVsIFBsYWNlaG9sZGVy\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkxD3N3JQMgVV8gRZEiQLBPyxX5jw\nWHNJCt8Fc0BbzQZVZ6Vkg4J1oHkLXIpsWcNOwU1RXcE/Pzr2yIjTnJW2VKNCMEAw\nDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQxu9vHJmf+rQznfCVCd9vNQTRwPjAP\nBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQCbX9rmZqJgk7lYPXGj\nWBR+oXt4AYzQ8pQvTSfkG/DBYwIgEY/oKZl5QL3Jt7lJx6lJxF3vLkaKBnJ9t4K4\ngHQ4nCY=\n-----END CERTIFICATE-----\n";
|
|
76
|
+
/**
|
|
77
|
+
* Default pinned-root set returned when a caller passes no `rootPems`
|
|
78
|
+
* override. Ordered by deployment prevalence — Infineon and Intel PTT
|
|
79
|
+
* together cover the vast majority of Windows 11 hosts; Nuvoton and
|
|
80
|
+
* STMicro cover most non-Intel Linux laptops.
|
|
81
|
+
*/
|
|
82
|
+
export declare const DEFAULT_PINNED_TPM_ROOTS: readonly string[];
|
|
83
|
+
/**
|
|
84
|
+
* Sentinel value the consumer-facing verifier emits on a mint path
|
|
85
|
+
* where the Rust bridge returns a `not_supported` failure envelope.
|
|
86
|
+
* Exposed as a constant so call sites match on a named token rather
|
|
87
|
+
* than a raw string literal.
|
|
88
|
+
*/
|
|
89
|
+
export declare const TPM_PLATFORM: "tpm";
|
|
90
|
+
//# sourceMappingURL=tpm-roots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tpm-roots.d.ts","sourceRoot":"","sources":["../src/tpm-roots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,+lBAWpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,2lBAWnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,2lBAWnC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,ulBAWjC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAKrD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAG,KAAc,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pinned TPM 2.0 Endorsement-Key vendor root certificates.
|
|
3
|
+
*
|
|
4
|
+
* Every `platform: "tpm"` hardware-attestation claim must chain to one of
|
|
5
|
+
* the root CAs listed here. Pinning is the self-attesting contract — a
|
|
6
|
+
* verifier that dynamically fetched vendor CAs could not be reproduced
|
|
7
|
+
* by a third-party audit. By committing the exact bytes of the CAs we
|
|
8
|
+
* accept, anyone can audit this file, pin the same bytes in their own
|
|
9
|
+
* verifier, and reach the same yes/no answer.
|
|
10
|
+
*
|
|
11
|
+
* The TPM ecosystem is multi-vendor by design: every Windows 11 device
|
|
12
|
+
* ships with TPM 2.0 (Microsoft's mandatory requirement), every modern
|
|
13
|
+
* Linux-on-x86 laptop has one, every Mac with a T2 chip has one. Each
|
|
14
|
+
* vendor maintains a public CA bundle rooted at their Endorsement-Key
|
|
15
|
+
* issuer. The motebit policy pins the four most common:
|
|
16
|
+
*
|
|
17
|
+
* - Infineon (`OptigaTrustM`, `SLB966x` families)
|
|
18
|
+
* - Nuvoton (`NPCT7xx` family)
|
|
19
|
+
* - STMicroelectronics (`ST33TPHF2ESPI`, `ST33HTPH2E32AHB3` families)
|
|
20
|
+
* - Intel PTT (firmware TPM bundled with Intel CSME)
|
|
21
|
+
*
|
|
22
|
+
* AMD fTPM (firmware TPM bundled with AMD PSP) uses a vendor-signed
|
|
23
|
+
* chain that roots to AMD's EK CA; that root is additive and lands in
|
|
24
|
+
* a subsequent pass once the first AMD-shaped test vector is captured.
|
|
25
|
+
*
|
|
26
|
+
* ## Operator follow-up — ship-blocking for production rollout
|
|
27
|
+
*
|
|
28
|
+
* The PEMs below are declared as exported constants so the test suite
|
|
29
|
+
* exercises the same chain-verification code path end-to-end. For a
|
|
30
|
+
* production ship, an operator must replace each placeholder with the
|
|
31
|
+
* exact byte-for-byte vendor root published at the URL in the comment.
|
|
32
|
+
* The test fabrication pattern (`buildFakeChain` in `__tests__`) does
|
|
33
|
+
* not need the real bytes — tests inject their own roots — so swapping
|
|
34
|
+
* in the real vendor PEMs is a mechanical operator task, not a code
|
|
35
|
+
* change. The drift gate `check-hardware-attestation-primitives` covers
|
|
36
|
+
* the parser / composer contract; the vendor-root swap is tracked in
|
|
37
|
+
* `docs/doctrine/hardware-attestation.md` §Non-goals.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Infineon OPTIGA TPM 2.0 Endorsement Key Root CA.
|
|
41
|
+
*
|
|
42
|
+
* Published at: https://pki.infineon.com/OptigaEccRootCA/OptigaEccRootCA.crt
|
|
43
|
+
*
|
|
44
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
45
|
+
* production rollout. Tests override via `rootPems` option.
|
|
46
|
+
*/
|
|
47
|
+
export const INFINEON_TPM_EK_ROOT_PEM = `-----BEGIN CERTIFICATE-----
|
|
48
|
+
MIIBdjCCARygAwIBAgIJAIMw8f7k8+xyMAoGCCqGSM49BAMCMCIxIDAeBgNVBAMM
|
|
49
|
+
F01vdGViaXQgSW5maW5lb24gUGxhY2Vob2xkZXIwHhcNMjYwNDIyMDAwMDAwWhcN
|
|
50
|
+
NDYwNDIyMDAwMDAwWjAiMSAwHgYDVQQDDBdNb3RlYml0IEluZmluZW9uIFBsYWNl
|
|
51
|
+
aG9sZGVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKZ/4LNYqi/LAI4R6tS2K
|
|
52
|
+
kRUnhkRzkYfi5hmz2E+35mqWVNqCb/FRhk6dEuxCNbwJxFPEK4Opf5lCOs0ZsRdF
|
|
53
|
+
+KNCMEAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQp3ojpUGm1YB9N+9lQHg0s
|
|
54
|
+
VpSoBTAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCjxfFCCf6t
|
|
55
|
+
CpGcGc7Gsk8h2RFQ7CFW8NzkjuvUZZ7bwwIhAJ/CB4+XzV5EhcOf0qRZN8zmJb8G
|
|
56
|
+
B9Z9EFcZ7Nt1l4Tn
|
|
57
|
+
-----END CERTIFICATE-----
|
|
58
|
+
`;
|
|
59
|
+
/**
|
|
60
|
+
* Nuvoton NPCT TPM 2.0 Endorsement Key Root CA.
|
|
61
|
+
*
|
|
62
|
+
* Published at: https://www.nuvoton.com/security/NTC-TPM-EK-Cert/Nuvoton TPM Root CA 2110.cer
|
|
63
|
+
*
|
|
64
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
65
|
+
* production rollout. Tests override via `rootPems` option.
|
|
66
|
+
*/
|
|
67
|
+
export const NUVOTON_TPM_EK_ROOT_PEM = `-----BEGIN CERTIFICATE-----
|
|
68
|
+
MIIBczCCARmgAwIBAgIJAL7X6p2yXxJJMAoGCCqGSM49BAMCMCAxHjAcBgNVBAMM
|
|
69
|
+
FU1vdGViaXQgTnV2b3RvbiBQbGFjZWhvbGRlcjAeFw0yNjA0MjIwMDAwMDBaFw00
|
|
70
|
+
NjA0MjIwMDAwMDBaMCAxHjAcBgNVBAMMFU1vdGViaXQgTnV2b3RvbiBQbGFjZWhv
|
|
71
|
+
bGRlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJgPwHoU+cVjX3HzkXpEksdn
|
|
72
|
+
f3KPRwMbFYvE3tkqDcW8JqzG8qO5VwPKFPwoAEE2C8dJpKHEk7fA4iGrSXz7x/6j
|
|
73
|
+
QjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUNskUYy3Uz8Tvuvbu/B5VTJA2
|
|
74
|
+
lLcwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiAAbU6/dL06n8Cw
|
|
75
|
+
CYI/rHo/cLWEFQKH5VnzDJH4RN5fIgIgAN0F3fYbTBa9H8OXCJdXUDxSDr2iT8E5
|
|
76
|
+
VDz6f2s3uFo=
|
|
77
|
+
-----END CERTIFICATE-----
|
|
78
|
+
`;
|
|
79
|
+
/**
|
|
80
|
+
* STMicroelectronics ST33 TPM 2.0 Endorsement Key Root CA.
|
|
81
|
+
*
|
|
82
|
+
* Published at: https://sw-center.st.com/STM_ROOT_CA_2.crt
|
|
83
|
+
*
|
|
84
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
85
|
+
* production rollout. Tests override via `rootPems` option.
|
|
86
|
+
*/
|
|
87
|
+
export const STMICRO_TPM_EK_ROOT_PEM = `-----BEGIN CERTIFICATE-----
|
|
88
|
+
MIIBdDCCARqgAwIBAgIJAMZ4+9xZHMuaMAoGCCqGSM49BAMCMCExHzAdBgNVBAMM
|
|
89
|
+
Fk1vdGViaXQgU1RNaWNybyBQbGFjZWhvbGRlcjAeFw0yNjA0MjIwMDAwMDBaFw00
|
|
90
|
+
NjA0MjIwMDAwMDBaMCExHzAdBgNVBAMMFk1vdGViaXQgU1RNaWNybyBQbGFjZWhv
|
|
91
|
+
bGRlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLnK3t7y4JBJxzE0EFq+zsOV
|
|
92
|
+
+m9n9D1YDUFb7k6hVIsKvfoH9o3rZkc4uRuSsz7fjC+IsKsMrJKXaU0mxH6ncjej
|
|
93
|
+
QjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUe/x8wdJYzEypFT3M0K1Jy5C6
|
|
94
|
+
1j8wDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiAc9Ln4qhL7fZ5c
|
|
95
|
+
oUbLFsTVTEc4aeBMkxqzLrJpZOYVegIgWSfLj2Q5CQ8OFvJx8fVDkxN9OXjYT6Jm
|
|
96
|
+
H6Bvb0gQaG8=
|
|
97
|
+
-----END CERTIFICATE-----
|
|
98
|
+
`;
|
|
99
|
+
/**
|
|
100
|
+
* Intel PTT (Platform Trust Technology, firmware TPM inside Intel CSME)
|
|
101
|
+
* Endorsement Key Root CA.
|
|
102
|
+
*
|
|
103
|
+
* Published at: https://upgrades.intel.com/content/CRL/ekcert/EKRootPublicKey.cer
|
|
104
|
+
*
|
|
105
|
+
* Placeholder PEM — replace with the real vendor bytes before
|
|
106
|
+
* production rollout. Tests override via `rootPems` option.
|
|
107
|
+
*/
|
|
108
|
+
export const INTEL_PTT_EK_ROOT_PEM = `-----BEGIN CERTIFICATE-----
|
|
109
|
+
MIIBcjCCARegAwIBAgIJAOQz8pPRrTIxMAoGCCqGSM49BAMCMB8xHTAbBgNVBAMM
|
|
110
|
+
FE1vdGViaXQgSW50ZWwgUGxhY2Vob2xkZXIwHhcNMjYwNDIyMDAwMDAwWhcNNDYw
|
|
111
|
+
NDIyMDAwMDAwWjAfMR0wGwYDVQQDDBRNb3RlYml0IEludGVsIFBsYWNlaG9sZGVy
|
|
112
|
+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkxD3N3JQMgVV8gRZEiQLBPyxX5jw
|
|
113
|
+
WHNJCt8Fc0BbzQZVZ6Vkg4J1oHkLXIpsWcNOwU1RXcE/Pzr2yIjTnJW2VKNCMEAw
|
|
114
|
+
DgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQxu9vHJmf+rQznfCVCd9vNQTRwPjAP
|
|
115
|
+
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQCbX9rmZqJgk7lYPXGj
|
|
116
|
+
WBR+oXt4AYzQ8pQvTSfkG/DBYwIgEY/oKZl5QL3Jt7lJx6lJxF3vLkaKBnJ9t4K4
|
|
117
|
+
gHQ4nCY=
|
|
118
|
+
-----END CERTIFICATE-----
|
|
119
|
+
`;
|
|
120
|
+
/**
|
|
121
|
+
* Default pinned-root set returned when a caller passes no `rootPems`
|
|
122
|
+
* override. Ordered by deployment prevalence — Infineon and Intel PTT
|
|
123
|
+
* together cover the vast majority of Windows 11 hosts; Nuvoton and
|
|
124
|
+
* STMicro cover most non-Intel Linux laptops.
|
|
125
|
+
*/
|
|
126
|
+
export const DEFAULT_PINNED_TPM_ROOTS = [
|
|
127
|
+
INFINEON_TPM_EK_ROOT_PEM,
|
|
128
|
+
NUVOTON_TPM_EK_ROOT_PEM,
|
|
129
|
+
STMICRO_TPM_EK_ROOT_PEM,
|
|
130
|
+
INTEL_PTT_EK_ROOT_PEM,
|
|
131
|
+
];
|
|
132
|
+
/**
|
|
133
|
+
* Sentinel value the consumer-facing verifier emits on a mint path
|
|
134
|
+
* where the Rust bridge returns a `not_supported` failure envelope.
|
|
135
|
+
* Exposed as a constant so call sites match on a named token rather
|
|
136
|
+
* than a raw string literal.
|
|
137
|
+
*/
|
|
138
|
+
export const TPM_PLATFORM = "tpm";
|
|
139
|
+
//# sourceMappingURL=tpm-roots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tpm-roots.js","sourceRoot":"","sources":["../src/tpm-roots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;CAWvC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;CAWtC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;CAWtC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;CAWpC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,wBAAwB;IACxB,uBAAuB;IACvB,uBAAuB;IACvB,qBAAqB;CACtB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAc,CAAC"}
|
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
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 type { HardwareAttestationClaim } from "@motebit/protocol";
|
|
35
|
+
export interface TpmVerifyOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Ed25519 identity key (lowercase hex) the motebit VC claims. The
|
|
38
|
+
* TPM quote's extraData MUST bind this key.
|
|
39
|
+
*/
|
|
40
|
+
readonly expectedIdentityPublicKeyHex: string;
|
|
41
|
+
/**
|
|
42
|
+
* motebit_id from the credential subject. Participates in the JCS
|
|
43
|
+
* body the Rust bridge hashes into extraData; re-derived here and
|
|
44
|
+
* byte-compared against the transmitted extraData so a malicious
|
|
45
|
+
* native client cannot substitute a different body.
|
|
46
|
+
*/
|
|
47
|
+
readonly expectedMotebitId?: string;
|
|
48
|
+
/**
|
|
49
|
+
* device_id from the credential subject. Same binding role as
|
|
50
|
+
* `expectedMotebitId`.
|
|
51
|
+
*/
|
|
52
|
+
readonly expectedDeviceId?: string;
|
|
53
|
+
/**
|
|
54
|
+
* `attested_at` (unix ms) from the credential subject. Same binding
|
|
55
|
+
* role as `expectedMotebitId`.
|
|
56
|
+
*/
|
|
57
|
+
readonly expectedAttestedAt?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Override the pinned vendor roots. Tests fabricate their own root
|
|
60
|
+
* so chain verification exercises the same code path without needing
|
|
61
|
+
* real vendor-signed leaves. Defaults to `DEFAULT_PINNED_TPM_ROOTS`.
|
|
62
|
+
*/
|
|
63
|
+
readonly rootPems?: readonly string[];
|
|
64
|
+
/**
|
|
65
|
+
* Clock for chain-validity checks. Defaults to `Date.now`. Tests
|
|
66
|
+
* inject a fixed clock to keep certificate validity windows
|
|
67
|
+
* deterministic.
|
|
68
|
+
*/
|
|
69
|
+
readonly now?: () => number;
|
|
70
|
+
}
|
|
71
|
+
export interface TpmVerifyError {
|
|
72
|
+
readonly message: string;
|
|
73
|
+
}
|
|
74
|
+
export interface TpmVerifyResult {
|
|
75
|
+
readonly valid: boolean;
|
|
76
|
+
readonly cert_chain_valid: boolean;
|
|
77
|
+
readonly quote_signature_valid: boolean;
|
|
78
|
+
readonly quote_shape_valid: boolean;
|
|
79
|
+
readonly identity_bound: boolean;
|
|
80
|
+
readonly errors: readonly TpmVerifyError[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* TPM 2.0 quote verifier.
|
|
84
|
+
*
|
|
85
|
+
* Pure. No network. No filesystem. Deterministic given `now()`.
|
|
86
|
+
*
|
|
87
|
+
* `claim` is the `HardwareAttestationClaim` as carried inside the
|
|
88
|
+
* motebit AgentTrustCredential. For TPM, the `attestation_receipt`
|
|
89
|
+
* field is expected to be four base64url segments separated by `.`:
|
|
90
|
+
*
|
|
91
|
+
* `{tpmsAttestB64}.{signatureB64}.{akCertDerB64}.{intermediatesJoinedB64}`
|
|
92
|
+
*
|
|
93
|
+
* `intermediatesJoinedB64` may itself be an empty segment (`""`) when
|
|
94
|
+
* the AK cert chains directly to a pinned root, or a `,`-joined
|
|
95
|
+
* concatenation of base64url-encoded DER intermediates in leaf-
|
|
96
|
+
* proximal-first order otherwise.
|
|
97
|
+
*/
|
|
98
|
+
export declare function verifyTpmQuote(claim: HardwareAttestationClaim, opts: TpmVerifyOptions): Promise<TpmVerifyResult>;
|
|
99
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAKlE,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,4BAA4B,EAAE,MAAM,CAAC;IAC9C;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;CAC5C;AAKD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,wBAAwB,EAC/B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,eAAe,CAAC,CA0M1B"}
|