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.
- package/Readme.md +159 -0
- package/attest-tpm.mjs +1261 -0
- 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`.
|