attest-tpm 1.0.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.
Files changed (3) hide show
  1. package/Readme.md +159 -0
  2. package/attest-tpm.mjs +1261 -0
  3. package/package.json +8 -0
package/Readme.md ADDED
@@ -0,0 +1,159 @@
1
+ # `attest-tpm`
2
+ Hardware protected Code Signing without USB tokens. Run a CA/B compliant Code Signing certificate authority that requires Trusted Platform Module key attestation, or use your TPM to obtain a certificate from such an authority and sign `.exe` files. The only dependency is [Koffi](https://koffi.dev). Typescript is supported.
3
+
4
+ Basic TPM client using `austinhenrie.com`:
5
+ ```javascript
6
+ import * as fs from "fs"
7
+ import * as attestTPM from "attest-tpm"
8
+ const exe = fs.readFileSync(".exe")
9
+
10
+ ;(async () => {
11
+ const tpmCreate = await attestTPM.tpmCreate()
12
+
13
+ fs.writeFileSync(
14
+ "signed.exe",
15
+ await attestTPM.tpmSign(
16
+ tpmCreate.keys,
17
+ await attestTPM.tpmDecrypt(
18
+ tpmCreate.keys,
19
+ await (await fetch(
20
+ "https://tpm-authority.austinhenrie.com",
21
+ { method: "POST", body: tpmCreate.body }
22
+ )).json()
23
+ ),
24
+ exe
25
+ )
26
+ )
27
+
28
+ fs.writeFileSync(
29
+ "root.cer",
30
+ await (await fetch("https://tpm-authority.austinhenrie.com")).bytes()
31
+ )
32
+
33
+ // open `root.cer`, click Install Certificate, and place it in Trusted Root
34
+ // Certification Authorities
35
+ })()
36
+ ```
37
+ Basic authority server:
38
+ ```javascript
39
+ import * as http from "http"
40
+ import * as attestTPM from "attest-tpm"
41
+
42
+ (async () => {
43
+ const cerKeys = await crypto.subtle.generateKey(
44
+ {
45
+ name: "RSASSA-PKCS1-v1_5",
46
+ modulusLength: 4096,
47
+ publicExponent: Uint8Array.from([1, 0, 1]),
48
+ hash: "SHA-256"
49
+ },
50
+ false,
51
+ ["sign"]
52
+ )
53
+
54
+ const signCer = (/**@type {ArrayBuffer}*/ cer) => {
55
+ return crypto.subtle.sign("rsassa-pkcs1-v1_5", cerKeys.privateKey, cer)
56
+ }
57
+
58
+ const authorityCers = await attestTPM.authorityCers(
59
+ cerKeys.publicKey,
60
+ cerKeys.publicKey,
61
+ signCer
62
+ )
63
+
64
+ http.createServer(async (request, response) => {
65
+ let responseContent
66
+
67
+ if (request.method?.[3]) {
68
+ for await (const content of request) {
69
+ responseContent = (await attestTPM.authorityIssue(
70
+ authorityCers.Intermediate,
71
+ content,
72
+ signCer
73
+ )).response
74
+ }
75
+ } else {
76
+ responseContent = authorityCers["Trusted Root"]
77
+ }
78
+
79
+ response.end(responseContent)
80
+ }).listen(80)
81
+ })()
82
+ ```
83
+ ## install
84
+ ```bash
85
+ npm install attest-tpm
86
+ ```
87
+ ## use
88
+ ### `attestTPM.authorityCers`
89
+ Creates Trusted Root and Intermediate certificates.
90
+ #### arguments
91
+ 1. required: A `CryptoKey` to use as the Trusted Root certificate's Public key. Must have `algorithm: { name: "RSASSA-PKCS1-v1_5", modulusLength: 4096, publicExponent: Uint8Array.from([1, 0, 1]), hash: "SHA-256" }`.
92
+ 1. required: A `CryptoKey` to use as the Intermediate certificate's Public key. Must have `algorithm: { name: "RSASSA-PKCS1-v1_5", modulusLength: 4096, publicExponent: Uint8Array.from([1, 0, 1]), hash: "SHA-256" }`.
93
+ 1. required: A function to sign the certificates with the private key matching the Trusted Root certificate. Must accept an `ArrayBuffer` of the Details and return an `ArrayBuffer` of the signature.
94
+ 1. optional: An object with certificate fields.
95
+ - `Issued by`: A string to use as the Trusted Root certificate's Issued by and Issued to and the Intermediate certificate's Issued by.
96
+ - `O`: A string to use as the O in the Trusted Root certificate's Issuer and Subject and in the Intermediate certificate's Issuer.
97
+ - `C`: A string to use as the C in the Trusted Root certificate's Issuer and Subject and in the Intermediate certificate's Issuer. Must be two characters.
98
+ - `Issued to`: A string to use as the Intermediate certificate's Issued to.
99
+ - `On-line Certificate Status Protocol`: A string to use as the On-line Certificate Status Protocol URL in the Intermediate certificate's Authority Information Access.
100
+ - `CRL Distribution Points`: A string to use as the Intermediate certificate's CRL Distribution Points URL.
101
+ #### returns
102
+ An object with certificates.
103
+ - `Trusted Root`: A `Uint8Array` of a `.cer` of a Trusted Root certificate.
104
+ - `Intermediate`: A `Uint8Array` of a `.cer` of an Intermediate certificate.
105
+ ### `attestTPM.tpmCreate`
106
+ Creates TPM keys.
107
+ #### environment
108
+ Must run on a Windows computer with a TPM that supports 3072 bit keys.
109
+ #### returns
110
+ An object with a key pair and certificate request.
111
+ - `keys`: A `Uint8Array` of a key pair that can be provided to `attestTPM.tpmDecrypt` and `attestTPM.tpmSign`. The private key is encrypted by the TPM.
112
+ - `body`: A JSON string that can be provided to `attestTPM.authorityIssue`.
113
+ - `cer`: The TPM certificate.
114
+ - `Public key`: The public key from `keys`.
115
+ ### `attestTPM.authorityIssue`
116
+ Verifies whether a certificate was issued by a TPM manufacturer and creates a Code Signing certificate if so.
117
+ #### arguments
118
+ 1. required: A `Uint8Array` of a `.cer` of an Intermediate certificate.
119
+ 1. required: A `Uint8Array` of a `body` from `attestTPM.tpmCreate`.
120
+ 1. required: A function to sign the Code Signing certificate with the private key matching the Intermediate certificate's Public key. Must accept an `ArrayBuffer` of the Details and return an `ArrayBuffer` of the signature.
121
+ 1. optional: An object with Code Signing certificate fields.
122
+ - `Issued to`: A string to use as the Issued to.
123
+ - `O`: A string to use as the Subject O.
124
+ - `L`: A string to use as the Subject L.
125
+ - `C`: A string to use as the Subject C. Must be two characters.
126
+ - `On-line Certificate Status Protocol`: A string to use as the On-line Certificate Status Protocol URL in Authority Information Access.
127
+ - `Certification Authority Issuer`: A string to use as the Certification Authority Issuer URL in Authority Information Access.
128
+ - `CRL Distribution Points`: A string to use as the CRL Distribution Points URL.
129
+ #### returns
130
+ If `body` verifies, an object with TPM information and certificates.
131
+ - `TPMModel`: A string of the model.
132
+ - `TPMVersion`: A string of the firmware version.
133
+ - `response`: A JSON string that can be provided to `attestTPM.tpmDecrypt`.
134
+ - `Intermediate`: The Intermediate certificate.
135
+ - `key`: A key encrypted such that it can be decrypted by only that individual TPM and only if the private key is inextractable and 3072 bits.
136
+ - `Code Signing`: A Code Signing certificate encrypted by `key`.
137
+ - `Serial number`: A string of `Code Signing`'s Serial number.
138
+
139
+ If `body` doesn't `verify`, an object with an error.
140
+ - `error`: A string of an error message.
141
+ ### `attestTPM.tpmDecrypt`
142
+ Uses a TPM to decrypt a Code Signing certificate.
143
+ #### environment
144
+ Must run as administrator on a Windows computer with the TPM that created the keys.
145
+ #### arguments
146
+ 1. required: A `Uint8Array` of `keys` from `attestTPM.tpmCreate`.
147
+ 1. required: An object of the parsed `response` from `attestTPM.authorityIssue`.
148
+ #### returns
149
+ A `Uint8Array` of a `.p7b` of the Code Signing and Intermediate certificates.
150
+ ### `attestTPM.tpmSign`
151
+ Uses a TPM to sign an `.exe`.
152
+ #### environment
153
+ Must run on a Windows computer with the TPM that created the keys.
154
+ #### arguments
155
+ 1. required: A `Uint8Array` of `keys` from `attestTPM.tpmCreate`.
156
+ 1. required: A `Uint8Array` of a `.p7b` of the Code Signing and Intermediate certificates.
157
+ 1. required: A `Uint8Array` of an `.exe`.
158
+ #### returns
159
+ A `Uint8Array` of a signed and timestamped `.exe`.