ds-01 1.0.9 → 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() {
|
|
@@ -23,52 +21,16 @@ function ensureSupportedOS() {
|
|
|
23
21
|
* ---------------------------------------------------------
|
|
24
22
|
* WINDOWS
|
|
25
23
|
* ---------------------------------------------------------
|
|
26
|
-
*
|
|
27
|
-
* Windows uses:
|
|
28
|
-
*
|
|
29
|
-
* Microsoft Platform Crypto Provider
|
|
30
|
-
* RSA 2048
|
|
31
|
-
* NonExportable private key
|
|
32
|
-
*
|
|
33
|
-
* The private key never enters Node.js.
|
|
34
|
-
*
|
|
35
|
-
* Node -> PowerShell -> Windows crypto provider
|
|
36
|
-
* ↓
|
|
37
|
-
* private key
|
|
38
|
-
* ↓
|
|
39
|
-
* signature
|
|
40
|
-
* ↓
|
|
41
|
-
* Node
|
|
42
|
-
*
|
|
43
|
-
* IMPORTANT:
|
|
44
|
-
*
|
|
45
|
-
* We identify the certificate using its properties rather
|
|
46
|
-
* than blindly taking the first certificate with the same
|
|
47
|
-
* subject.
|
|
48
24
|
*/
|
|
49
|
-
/**
|
|
50
|
-
* PowerShell expression used to identify a valid DS01
|
|
51
|
-
* certificate.
|
|
52
|
-
*
|
|
53
|
-
* Requirements:
|
|
54
|
-
*
|
|
55
|
-
* - Correct subject
|
|
56
|
-
* - Has private key
|
|
57
|
-
* - RSA certificate
|
|
58
|
-
* - Platform Crypto Provider
|
|
59
|
-
*/
|
|
60
|
-
const WINDOWS_CERT_FILTER = `
|
|
61
|
-
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
62
|
-
$_.HasPrivateKey -and
|
|
63
|
-
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
64
|
-
`;
|
|
65
25
|
async function createWindowsDeviceKey() {
|
|
66
26
|
const script = `
|
|
67
27
|
$ErrorActionPreference = "Stop"
|
|
68
28
|
|
|
69
29
|
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
70
30
|
Where-Object {
|
|
71
|
-
${
|
|
31
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
32
|
+
$_.HasPrivateKey -and
|
|
33
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
72
34
|
})
|
|
73
35
|
|
|
74
36
|
if ($certificates.Count -gt 1) {
|
|
@@ -82,7 +44,6 @@ if ($certificates.Count -eq 1) {
|
|
|
82
44
|
|
|
83
45
|
$params = @{
|
|
84
46
|
Type = "Custom"
|
|
85
|
-
|
|
86
47
|
Subject = "CN=${KEY_NAME}"
|
|
87
48
|
|
|
88
49
|
Provider = "Microsoft Platform Crypto Provider"
|
|
@@ -90,7 +51,6 @@ $params = @{
|
|
|
90
51
|
KeyAlgorithm = "RSA"
|
|
91
52
|
KeyLength = 2048
|
|
92
53
|
|
|
93
|
-
# Private key cannot be exported.
|
|
94
54
|
KeyExportPolicy = "NonExportable"
|
|
95
55
|
|
|
96
56
|
KeyUsage = "DigitalSignature"
|
|
@@ -125,18 +85,21 @@ Write-Output "CREATED"
|
|
|
125
85
|
}
|
|
126
86
|
}
|
|
127
87
|
/**
|
|
128
|
-
* Find
|
|
88
|
+
* Find exactly one valid DS01 certificate.
|
|
129
89
|
*
|
|
130
|
-
* We
|
|
90
|
+
* We intentionally do not use Select-Object -First 1.
|
|
131
91
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
92
|
+
* 0 certificates -> error
|
|
93
|
+
* 1 certificate -> use it
|
|
94
|
+
* 2+ certificates -> error
|
|
134
95
|
*/
|
|
135
|
-
function
|
|
96
|
+
function getWindowsCertificateLookup() {
|
|
136
97
|
return `
|
|
137
98
|
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
138
99
|
Where-Object {
|
|
139
|
-
${
|
|
100
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
101
|
+
$_.HasPrivateKey -and
|
|
102
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
140
103
|
})
|
|
141
104
|
|
|
142
105
|
if ($certificates.Count -eq 0) {
|
|
@@ -147,19 +110,15 @@ if ($certificates.Count -gt 1) {
|
|
|
147
110
|
throw "Multiple valid DS01 device certificates found."
|
|
148
111
|
}
|
|
149
112
|
|
|
150
|
-
$certificates[0]
|
|
113
|
+
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$certificates[0]
|
|
151
114
|
`;
|
|
152
115
|
}
|
|
153
116
|
async function getWindowsPublicKey() {
|
|
154
117
|
const script = `
|
|
155
118
|
$ErrorActionPreference = "Stop"
|
|
156
119
|
|
|
157
|
-
$
|
|
120
|
+
${getWindowsCertificateLookup()}
|
|
158
121
|
|
|
159
|
-
# Return the complete public certificate.
|
|
160
|
-
#
|
|
161
|
-
# The certificate contains the public key and certificate
|
|
162
|
-
# metadata, but never the private key.
|
|
163
122
|
[Convert]::ToBase64String($cert.RawData)
|
|
164
123
|
`;
|
|
165
124
|
const { stdout } = await execFileAsync("powershell.exe", [
|
|
@@ -183,7 +142,7 @@ async function signWindowsDeviceKey(data) {
|
|
|
183
142
|
const script = `
|
|
184
143
|
$ErrorActionPreference = "Stop"
|
|
185
144
|
|
|
186
|
-
$
|
|
145
|
+
${getWindowsCertificateLookup()}
|
|
187
146
|
|
|
188
147
|
if (-not $cert.HasPrivateKey) {
|
|
189
148
|
throw "DS01 device certificate has no private key."
|
|
@@ -233,7 +192,9 @@ $ErrorActionPreference = "Stop"
|
|
|
233
192
|
|
|
234
193
|
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
235
194
|
Where-Object {
|
|
236
|
-
${
|
|
195
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
196
|
+
$_.HasPrivateKey -and
|
|
197
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
237
198
|
})
|
|
238
199
|
|
|
239
200
|
if ($certificates.Count -gt 1) {
|
package/package.json
CHANGED
|
@@ -14,8 +14,6 @@ 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",
|
|
@@ -36,54 +34,17 @@ function ensureSupportedOS(): void {
|
|
|
36
34
|
* ---------------------------------------------------------
|
|
37
35
|
* WINDOWS
|
|
38
36
|
* ---------------------------------------------------------
|
|
39
|
-
*
|
|
40
|
-
* Windows uses:
|
|
41
|
-
*
|
|
42
|
-
* Microsoft Platform Crypto Provider
|
|
43
|
-
* RSA 2048
|
|
44
|
-
* NonExportable private key
|
|
45
|
-
*
|
|
46
|
-
* The private key never enters Node.js.
|
|
47
|
-
*
|
|
48
|
-
* Node -> PowerShell -> Windows crypto provider
|
|
49
|
-
* ↓
|
|
50
|
-
* private key
|
|
51
|
-
* ↓
|
|
52
|
-
* signature
|
|
53
|
-
* ↓
|
|
54
|
-
* Node
|
|
55
|
-
*
|
|
56
|
-
* IMPORTANT:
|
|
57
|
-
*
|
|
58
|
-
* We identify the certificate using its properties rather
|
|
59
|
-
* than blindly taking the first certificate with the same
|
|
60
|
-
* subject.
|
|
61
37
|
*/
|
|
62
38
|
|
|
63
|
-
/**
|
|
64
|
-
* PowerShell expression used to identify a valid DS01
|
|
65
|
-
* certificate.
|
|
66
|
-
*
|
|
67
|
-
* Requirements:
|
|
68
|
-
*
|
|
69
|
-
* - Correct subject
|
|
70
|
-
* - Has private key
|
|
71
|
-
* - RSA certificate
|
|
72
|
-
* - Platform Crypto Provider
|
|
73
|
-
*/
|
|
74
|
-
const WINDOWS_CERT_FILTER = `
|
|
75
|
-
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
76
|
-
$_.HasPrivateKey -and
|
|
77
|
-
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
78
|
-
`;
|
|
79
|
-
|
|
80
39
|
async function createWindowsDeviceKey(): Promise<void> {
|
|
81
40
|
const script = `
|
|
82
41
|
$ErrorActionPreference = "Stop"
|
|
83
42
|
|
|
84
43
|
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
85
44
|
Where-Object {
|
|
86
|
-
${
|
|
45
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
46
|
+
$_.HasPrivateKey -and
|
|
47
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
87
48
|
})
|
|
88
49
|
|
|
89
50
|
if ($certificates.Count -gt 1) {
|
|
@@ -97,7 +58,6 @@ if ($certificates.Count -eq 1) {
|
|
|
97
58
|
|
|
98
59
|
$params = @{
|
|
99
60
|
Type = "Custom"
|
|
100
|
-
|
|
101
61
|
Subject = "CN=${KEY_NAME}"
|
|
102
62
|
|
|
103
63
|
Provider = "Microsoft Platform Crypto Provider"
|
|
@@ -105,7 +65,6 @@ $params = @{
|
|
|
105
65
|
KeyAlgorithm = "RSA"
|
|
106
66
|
KeyLength = 2048
|
|
107
67
|
|
|
108
|
-
# Private key cannot be exported.
|
|
109
68
|
KeyExportPolicy = "NonExportable"
|
|
110
69
|
|
|
111
70
|
KeyUsage = "DigitalSignature"
|
|
@@ -150,18 +109,21 @@ Write-Output "CREATED"
|
|
|
150
109
|
}
|
|
151
110
|
|
|
152
111
|
/**
|
|
153
|
-
* Find
|
|
112
|
+
* Find exactly one valid DS01 certificate.
|
|
154
113
|
*
|
|
155
|
-
* We
|
|
114
|
+
* We intentionally do not use Select-Object -First 1.
|
|
156
115
|
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
116
|
+
* 0 certificates -> error
|
|
117
|
+
* 1 certificate -> use it
|
|
118
|
+
* 2+ certificates -> error
|
|
159
119
|
*/
|
|
160
|
-
function
|
|
120
|
+
function getWindowsCertificateLookup(): string {
|
|
161
121
|
return `
|
|
162
122
|
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
163
123
|
Where-Object {
|
|
164
|
-
${
|
|
124
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
125
|
+
$_.HasPrivateKey -and
|
|
126
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
165
127
|
})
|
|
166
128
|
|
|
167
129
|
if ($certificates.Count -eq 0) {
|
|
@@ -172,7 +134,7 @@ if ($certificates.Count -gt 1) {
|
|
|
172
134
|
throw "Multiple valid DS01 device certificates found."
|
|
173
135
|
}
|
|
174
136
|
|
|
175
|
-
$certificates[0]
|
|
137
|
+
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$certificates[0]
|
|
176
138
|
`;
|
|
177
139
|
}
|
|
178
140
|
|
|
@@ -180,12 +142,8 @@ async function getWindowsPublicKey(): Promise<string> {
|
|
|
180
142
|
const script = `
|
|
181
143
|
$ErrorActionPreference = "Stop"
|
|
182
144
|
|
|
183
|
-
$
|
|
145
|
+
${getWindowsCertificateLookup()}
|
|
184
146
|
|
|
185
|
-
# Return the complete public certificate.
|
|
186
|
-
#
|
|
187
|
-
# The certificate contains the public key and certificate
|
|
188
|
-
# metadata, but never the private key.
|
|
189
147
|
[Convert]::ToBase64String($cert.RawData)
|
|
190
148
|
`;
|
|
191
149
|
|
|
@@ -224,7 +182,7 @@ async function signWindowsDeviceKey(
|
|
|
224
182
|
const script = `
|
|
225
183
|
$ErrorActionPreference = "Stop"
|
|
226
184
|
|
|
227
|
-
$
|
|
185
|
+
${getWindowsCertificateLookup()}
|
|
228
186
|
|
|
229
187
|
if (-not $cert.HasPrivateKey) {
|
|
230
188
|
throw "DS01 device certificate has no private key."
|
|
@@ -287,7 +245,9 @@ $ErrorActionPreference = "Stop"
|
|
|
287
245
|
|
|
288
246
|
$certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
|
|
289
247
|
Where-Object {
|
|
290
|
-
${
|
|
248
|
+
$_.Subject -eq "CN=${KEY_NAME}" -and
|
|
249
|
+
$_.HasPrivateKey -and
|
|
250
|
+
$_.PublicKey.Oid.Value -eq "1.2.840.113549.1.1.1"
|
|
291
251
|
})
|
|
292
252
|
|
|
293
253
|
if ($certificates.Count -gt 1) {
|