ds-01 1.0.8 → 1.0.10
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secureKeyStore.d.ts","sourceRoot":"","sources":["../../src/utils/secureKeyStore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"secureKeyStore.d.ts","sourceRoot":"","sources":["../../src/utils/secureKeyStore.ts"],"names":[],"mappings":"AA2WA;;;;GAIG;AAEH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CASrD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ1D;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAQrB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CASrD"}
|
|
@@ -9,8 +9,6 @@ const KEY_NAME = "DS01-CLI-Device-Key";
|
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
11
11
|
function getMacHelperPath() {
|
|
12
|
-
// dist/utils/secureKeyStore.js
|
|
13
|
-
// ../native/macos-key-helper.swift
|
|
14
12
|
return path.resolve(__dirname, "../native/macos-key-helper.swift");
|
|
15
13
|
}
|
|
16
14
|
function ensureSupportedOS() {
|
|
@@ -28,13 +26,18 @@ async function createWindowsDeviceKey() {
|
|
|
28
26
|
const script = `
|
|
29
27
|
$ErrorActionPreference = "Stop"
|
|
30
28
|
|
|
31
|
-
$
|
|
29
|
+
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
32
30
|
Where-Object {
|
|
33
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
32
|
+
$_.HasPrivateKey -and
|
|
33
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
34
|
+
})
|
|
36
35
|
|
|
37
|
-
if ($
|
|
36
|
+
if ($certificates.Count -gt 1) {
|
|
37
|
+
throw "Multiple valid DS01 device certificates found. Remove old DS01 device certificates before continuing."
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if ($certificates.Count -eq 1) {
|
|
38
41
|
Write-Output "EXISTS"
|
|
39
42
|
exit 0
|
|
40
43
|
}
|
|
@@ -58,7 +61,11 @@ $params = @{
|
|
|
58
61
|
NotAfter = (Get-Date).AddYears(10)
|
|
59
62
|
}
|
|
60
63
|
|
|
61
|
-
New-SelfSignedCertificate @params
|
|
64
|
+
$certificate = New-SelfSignedCertificate @params
|
|
65
|
+
|
|
66
|
+
if (-not $certificate) {
|
|
67
|
+
throw "Windows failed to create the DS01 device certificate."
|
|
68
|
+
}
|
|
62
69
|
|
|
63
70
|
Write-Output "CREATED"
|
|
64
71
|
`;
|
|
@@ -77,20 +84,41 @@ Write-Output "CREATED"
|
|
|
77
84
|
throw new Error("Failed to create Windows DS01 device key.");
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Find exactly one valid DS01 certificate.
|
|
89
|
+
*
|
|
90
|
+
* We intentionally do not use Select-Object -First 1.
|
|
91
|
+
*
|
|
92
|
+
* 0 certificates -> error
|
|
93
|
+
* 1 certificate -> use it
|
|
94
|
+
* 2+ certificates -> error
|
|
95
|
+
*/
|
|
96
|
+
function getWindowsCertificateLookup() {
|
|
97
|
+
return `
|
|
98
|
+
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
85
99
|
Where-Object {
|
|
86
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
101
|
+
$_.HasPrivateKey -and
|
|
102
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
103
|
+
})
|
|
89
104
|
|
|
90
|
-
if (-
|
|
105
|
+
if ($certificates.Count -eq 0) {
|
|
91
106
|
throw "DS01 device key not found."
|
|
92
107
|
}
|
|
93
108
|
|
|
109
|
+
if ($certificates.Count -gt 1) {
|
|
110
|
+
throw "Multiple valid DS01 device certificates found."
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$certificates[0]
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
async function getWindowsPublicKey() {
|
|
117
|
+
const script = `
|
|
118
|
+
$ErrorActionPreference = "Stop"
|
|
119
|
+
|
|
120
|
+
${getWindowsCertificateLookup()}
|
|
121
|
+
|
|
94
122
|
[Convert]::ToBase64String($cert.RawData)
|
|
95
123
|
`;
|
|
96
124
|
const { stdout } = await execFileAsync("powershell.exe", [
|
|
@@ -114,21 +142,14 @@ async function signWindowsDeviceKey(data) {
|
|
|
114
142
|
const script = `
|
|
115
143
|
$ErrorActionPreference = "Stop"
|
|
116
144
|
|
|
117
|
-
$
|
|
118
|
-
Where-Object {
|
|
119
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
120
|
-
} |
|
|
121
|
-
Select-Object -First 1
|
|
122
|
-
|
|
123
|
-
if (-not $cert) {
|
|
124
|
-
throw "DS01 device key not found."
|
|
125
|
-
}
|
|
145
|
+
${getWindowsCertificateLookup()}
|
|
126
146
|
|
|
127
147
|
if (-not $cert.HasPrivateKey) {
|
|
128
148
|
throw "DS01 device certificate has no private key."
|
|
129
149
|
}
|
|
130
150
|
|
|
131
|
-
$rsa =
|
|
151
|
+
$rsa =
|
|
152
|
+
[System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
|
|
132
153
|
|
|
133
154
|
if (-not $rsa) {
|
|
134
155
|
throw "Unable to access DS01 private signing key."
|
|
@@ -169,15 +190,22 @@ async function deleteWindowsDeviceKey() {
|
|
|
169
190
|
const script = `
|
|
170
191
|
$ErrorActionPreference = "Stop"
|
|
171
192
|
|
|
172
|
-
$
|
|
193
|
+
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
173
194
|
Where-Object {
|
|
174
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
175
|
-
|
|
176
|
-
|
|
195
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
196
|
+
$_.HasPrivateKey -and
|
|
197
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
if ($certificates.Count -gt 1) {
|
|
201
|
+
throw "Multiple valid DS01 device certificates found."
|
|
202
|
+
}
|
|
177
203
|
|
|
178
|
-
if ($
|
|
179
|
-
Remove-Item $
|
|
204
|
+
if ($certificates.Count -eq 1) {
|
|
205
|
+
Remove-Item $certificates[0].PSPath
|
|
180
206
|
}
|
|
207
|
+
|
|
208
|
+
Write-Output "DELETED"
|
|
181
209
|
`;
|
|
182
210
|
await execFileAsync("powershell.exe", [
|
|
183
211
|
"-NoProfile",
|
|
@@ -208,8 +236,10 @@ async function runMacHelper(operation, data) {
|
|
|
208
236
|
}
|
|
209
237
|
async function createMacDeviceKey() {
|
|
210
238
|
const result = await runMacHelper("create");
|
|
211
|
-
if (result !== "CREATED" &&
|
|
212
|
-
|
|
239
|
+
if (result !== "CREATED" &&
|
|
240
|
+
result !== "EXISTS") {
|
|
241
|
+
throw new Error(result ||
|
|
242
|
+
"Failed to create macOS Secure Enclave device key.");
|
|
213
243
|
}
|
|
214
244
|
}
|
|
215
245
|
async function getMacPublicKey() {
|
package/package.json
CHANGED
|
@@ -14,15 +14,13 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
14
14
|
const __dirname = path.dirname(__filename);
|
|
15
15
|
|
|
16
16
|
function getMacHelperPath(): string {
|
|
17
|
-
// dist/utils/secureKeyStore.js
|
|
18
|
-
// ../native/macos-key-helper.swift
|
|
19
17
|
return path.resolve(
|
|
20
18
|
__dirname,
|
|
21
19
|
"../native/macos-key-helper.swift",
|
|
22
20
|
);
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
function ensureSupportedOS() {
|
|
23
|
+
function ensureSupportedOS(): void {
|
|
26
24
|
const platform = os.platform();
|
|
27
25
|
|
|
28
26
|
if (platform !== "win32" && platform !== "darwin") {
|
|
@@ -42,13 +40,18 @@ async function createWindowsDeviceKey(): Promise<void> {
|
|
|
42
40
|
const script = `
|
|
43
41
|
$ErrorActionPreference = "Stop"
|
|
44
42
|
|
|
45
|
-
$
|
|
43
|
+
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
46
44
|
Where-Object {
|
|
47
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
46
|
+
$_.HasPrivateKey -and
|
|
47
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
48
|
+
})
|
|
50
49
|
|
|
51
|
-
if ($
|
|
50
|
+
if ($certificates.Count -gt 1) {
|
|
51
|
+
throw "Multiple valid DS01 device certificates found. Remove old DS01 device certificates before continuing."
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if ($certificates.Count -eq 1) {
|
|
52
55
|
Write-Output "EXISTS"
|
|
53
56
|
exit 0
|
|
54
57
|
}
|
|
@@ -72,7 +75,11 @@ $params = @{
|
|
|
72
75
|
NotAfter = (Get-Date).AddYears(10)
|
|
73
76
|
}
|
|
74
77
|
|
|
75
|
-
New-SelfSignedCertificate @params
|
|
78
|
+
$certificate = New-SelfSignedCertificate @params
|
|
79
|
+
|
|
80
|
+
if (-not $certificate) {
|
|
81
|
+
throw "Windows failed to create the DS01 device certificate."
|
|
82
|
+
}
|
|
76
83
|
|
|
77
84
|
Write-Output "CREATED"
|
|
78
85
|
`;
|
|
@@ -95,24 +102,48 @@ Write-Output "CREATED"
|
|
|
95
102
|
const result = stdout.trim();
|
|
96
103
|
|
|
97
104
|
if (result !== "CREATED" && result !== "EXISTS") {
|
|
98
|
-
throw new Error(
|
|
105
|
+
throw new Error(
|
|
106
|
+
"Failed to create Windows DS01 device key.",
|
|
107
|
+
);
|
|
99
108
|
}
|
|
100
109
|
}
|
|
101
110
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Find exactly one valid DS01 certificate.
|
|
113
|
+
*
|
|
114
|
+
* We intentionally do not use Select-Object -First 1.
|
|
115
|
+
*
|
|
116
|
+
* 0 certificates -> error
|
|
117
|
+
* 1 certificate -> use it
|
|
118
|
+
* 2+ certificates -> error
|
|
119
|
+
*/
|
|
120
|
+
function getWindowsCertificateLookup(): string {
|
|
121
|
+
return `
|
|
122
|
+
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
107
123
|
Where-Object {
|
|
108
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
109
|
-
|
|
110
|
-
|
|
124
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
125
|
+
$_.HasPrivateKey -and
|
|
126
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
127
|
+
})
|
|
111
128
|
|
|
112
|
-
if (-
|
|
129
|
+
if ($certificates.Count -eq 0) {
|
|
113
130
|
throw "DS01 device key not found."
|
|
114
131
|
}
|
|
115
132
|
|
|
133
|
+
if ($certificates.Count -gt 1) {
|
|
134
|
+
throw "Multiple valid DS01 device certificates found."
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$certificates[0]
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function getWindowsPublicKey(): Promise<string> {
|
|
142
|
+
const script = `
|
|
143
|
+
$ErrorActionPreference = "Stop"
|
|
144
|
+
|
|
145
|
+
${getWindowsCertificateLookup()}
|
|
146
|
+
|
|
116
147
|
[Convert]::ToBase64String($cert.RawData)
|
|
117
148
|
`;
|
|
118
149
|
|
|
@@ -134,7 +165,9 @@ if (-not $cert) {
|
|
|
134
165
|
const certificate = stdout.trim();
|
|
135
166
|
|
|
136
167
|
if (!certificate) {
|
|
137
|
-
throw new Error(
|
|
168
|
+
throw new Error(
|
|
169
|
+
"Unable to read Windows DS01 public certificate.",
|
|
170
|
+
);
|
|
138
171
|
}
|
|
139
172
|
|
|
140
173
|
return certificate;
|
|
@@ -143,26 +176,20 @@ if (-not $cert) {
|
|
|
143
176
|
async function signWindowsDeviceKey(
|
|
144
177
|
data: Uint8Array,
|
|
145
178
|
): Promise<Uint8Array> {
|
|
146
|
-
const dataBase64 =
|
|
179
|
+
const dataBase64 =
|
|
180
|
+
Buffer.from(data).toString("base64");
|
|
147
181
|
|
|
148
182
|
const script = `
|
|
149
183
|
$ErrorActionPreference = "Stop"
|
|
150
184
|
|
|
151
|
-
$
|
|
152
|
-
Where-Object {
|
|
153
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
154
|
-
} |
|
|
155
|
-
Select-Object -First 1
|
|
156
|
-
|
|
157
|
-
if (-not $cert) {
|
|
158
|
-
throw "DS01 device key not found."
|
|
159
|
-
}
|
|
185
|
+
${getWindowsCertificateLookup()}
|
|
160
186
|
|
|
161
187
|
if (-not $cert.HasPrivateKey) {
|
|
162
188
|
throw "DS01 device certificate has no private key."
|
|
163
189
|
}
|
|
164
190
|
|
|
165
|
-
$rsa =
|
|
191
|
+
$rsa =
|
|
192
|
+
[System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
|
|
166
193
|
|
|
167
194
|
if (-not $rsa) {
|
|
168
195
|
throw "Unable to access DS01 private signing key."
|
|
@@ -202,25 +229,36 @@ finally {
|
|
|
202
229
|
const signature = stdout.trim();
|
|
203
230
|
|
|
204
231
|
if (!signature) {
|
|
205
|
-
throw new Error(
|
|
232
|
+
throw new Error(
|
|
233
|
+
"Failed to sign data with Windows device key.",
|
|
234
|
+
);
|
|
206
235
|
}
|
|
207
236
|
|
|
208
|
-
return new Uint8Array(
|
|
237
|
+
return new Uint8Array(
|
|
238
|
+
Buffer.from(signature, "base64"),
|
|
239
|
+
);
|
|
209
240
|
}
|
|
210
241
|
|
|
211
242
|
async function deleteWindowsDeviceKey(): Promise<void> {
|
|
212
243
|
const script = `
|
|
213
244
|
$ErrorActionPreference = "Stop"
|
|
214
245
|
|
|
215
|
-
$
|
|
246
|
+
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
216
247
|
Where-Object {
|
|
217
|
-
$_.Subject -eq "CN=${KEY_NAME}"
|
|
218
|
-
|
|
219
|
-
|
|
248
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
249
|
+
$_.HasPrivateKey -and
|
|
250
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
251
|
+
})
|
|
220
252
|
|
|
221
|
-
if ($
|
|
222
|
-
|
|
253
|
+
if ($certificates.Count -gt 1) {
|
|
254
|
+
throw "Multiple valid DS01 device certificates found."
|
|
223
255
|
}
|
|
256
|
+
|
|
257
|
+
if ($certificates.Count -eq 1) {
|
|
258
|
+
Remove-Item $certificates[0].PSPath
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
Write-Output "DELETED"
|
|
224
262
|
`;
|
|
225
263
|
|
|
226
264
|
await execFileAsync(
|
|
@@ -246,7 +284,11 @@ if ($cert) {
|
|
|
246
284
|
*/
|
|
247
285
|
|
|
248
286
|
async function runMacHelper(
|
|
249
|
-
operation:
|
|
287
|
+
operation:
|
|
288
|
+
| "create"
|
|
289
|
+
| "public"
|
|
290
|
+
| "sign"
|
|
291
|
+
| "delete",
|
|
250
292
|
data?: Uint8Array,
|
|
251
293
|
): Promise<string> {
|
|
252
294
|
const helper = getMacHelperPath();
|
|
@@ -254,7 +296,9 @@ async function runMacHelper(
|
|
|
254
296
|
const args = [helper, operation];
|
|
255
297
|
|
|
256
298
|
if (data) {
|
|
257
|
-
args.push(
|
|
299
|
+
args.push(
|
|
300
|
+
Buffer.from(data).toString("base64"),
|
|
301
|
+
);
|
|
258
302
|
}
|
|
259
303
|
|
|
260
304
|
const { stdout } = await execFileAsync(
|
|
@@ -269,17 +313,23 @@ async function runMacHelper(
|
|
|
269
313
|
}
|
|
270
314
|
|
|
271
315
|
async function createMacDeviceKey(): Promise<void> {
|
|
272
|
-
const result =
|
|
316
|
+
const result =
|
|
317
|
+
await runMacHelper("create");
|
|
273
318
|
|
|
274
|
-
if (
|
|
319
|
+
if (
|
|
320
|
+
result !== "CREATED" &&
|
|
321
|
+
result !== "EXISTS"
|
|
322
|
+
) {
|
|
275
323
|
throw new Error(
|
|
276
|
-
result ||
|
|
324
|
+
result ||
|
|
325
|
+
"Failed to create macOS Secure Enclave device key.",
|
|
277
326
|
);
|
|
278
327
|
}
|
|
279
328
|
}
|
|
280
329
|
|
|
281
330
|
async function getMacPublicKey(): Promise<string> {
|
|
282
|
-
const result =
|
|
331
|
+
const result =
|
|
332
|
+
await runMacHelper("public");
|
|
283
333
|
|
|
284
334
|
if (!result) {
|
|
285
335
|
throw new Error(
|
|
@@ -293,7 +343,8 @@ async function getMacPublicKey(): Promise<string> {
|
|
|
293
343
|
async function signMacDeviceKey(
|
|
294
344
|
data: Uint8Array,
|
|
295
345
|
): Promise<Uint8Array> {
|
|
296
|
-
const result =
|
|
346
|
+
const result =
|
|
347
|
+
await runMacHelper("sign", data);
|
|
297
348
|
|
|
298
349
|
if (!result) {
|
|
299
350
|
throw new Error(
|