@certd/acme-client 1.20.15 → 1.20.16
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 +19 -20
- package/package.json +11 -11
- package/src/api.js +1 -17
- package/src/auto.js +12 -12
- package/src/axios.js +1 -4
- package/src/client.js +18 -42
- package/src/crypto/forge.js +18 -31
- package/src/crypto/index.js +25 -40
- package/src/http.js +3 -14
- package/src/index.js +4 -8
- package/src/logger.js +1 -3
- package/src/util.js +2 -13
- package/src/verify.js +1 -6
- package/types/index.d.ts +0 -6
- package/types/index.test-d.ts +0 -1
- package/types/rfc8555.d.ts +0 -4
package/src/crypto/forge.js
CHANGED
|
@@ -13,7 +13,6 @@ const forge = require('node-forge');
|
|
|
13
13
|
|
|
14
14
|
const generateKeyPair = promisify(forge.pki.rsa.generateKeyPair);
|
|
15
15
|
|
|
16
|
-
|
|
17
16
|
/**
|
|
18
17
|
* Attempt to parse forge object from PEM encoded string
|
|
19
18
|
*
|
|
@@ -54,7 +53,6 @@ function forgeObjectFromPem(input) {
|
|
|
54
53
|
return result;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
|
|
58
56
|
/**
|
|
59
57
|
* Parse domain names from a certificate or CSR
|
|
60
58
|
*
|
|
@@ -93,11 +91,10 @@ function parseDomains(obj) {
|
|
|
93
91
|
|
|
94
92
|
return {
|
|
95
93
|
commonName,
|
|
96
|
-
altNames
|
|
94
|
+
altNames,
|
|
97
95
|
};
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
|
|
101
98
|
/**
|
|
102
99
|
* Generate a private RSA key
|
|
103
100
|
*
|
|
@@ -123,7 +120,6 @@ async function createPrivateKey(size = 2048) {
|
|
|
123
120
|
|
|
124
121
|
exports.createPrivateKey = createPrivateKey;
|
|
125
122
|
|
|
126
|
-
|
|
127
123
|
/**
|
|
128
124
|
* Create public key from a private RSA key
|
|
129
125
|
*
|
|
@@ -136,14 +132,13 @@ exports.createPrivateKey = createPrivateKey;
|
|
|
136
132
|
* ```
|
|
137
133
|
*/
|
|
138
134
|
|
|
139
|
-
exports.createPublicKey = async
|
|
135
|
+
exports.createPublicKey = async (key) => {
|
|
140
136
|
const privateKey = forge.pki.privateKeyFromPem(key);
|
|
141
137
|
const publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e);
|
|
142
138
|
const pemKey = forge.pki.publicKeyToPem(publicKey);
|
|
143
139
|
return Buffer.from(pemKey);
|
|
144
140
|
};
|
|
145
141
|
|
|
146
|
-
|
|
147
142
|
/**
|
|
148
143
|
* Parse body of PEM encoded object from buffer or string
|
|
149
144
|
* If multiple objects are chained, the first body will be returned
|
|
@@ -157,7 +152,6 @@ exports.getPemBody = (str) => {
|
|
|
157
152
|
return forge.util.encode64(msg.body);
|
|
158
153
|
};
|
|
159
154
|
|
|
160
|
-
|
|
161
155
|
/**
|
|
162
156
|
* Split chain of PEM encoded objects from buffer or string into array
|
|
163
157
|
*
|
|
@@ -167,7 +161,6 @@ exports.getPemBody = (str) => {
|
|
|
167
161
|
|
|
168
162
|
exports.splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode);
|
|
169
163
|
|
|
170
|
-
|
|
171
164
|
/**
|
|
172
165
|
* Get modulus
|
|
173
166
|
*
|
|
@@ -182,7 +175,7 @@ exports.splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode);
|
|
|
182
175
|
* ```
|
|
183
176
|
*/
|
|
184
177
|
|
|
185
|
-
exports.getModulus = async
|
|
178
|
+
exports.getModulus = async (input) => {
|
|
186
179
|
if (!Buffer.isBuffer(input)) {
|
|
187
180
|
input = Buffer.from(input);
|
|
188
181
|
}
|
|
@@ -191,7 +184,6 @@ exports.getModulus = async function(input) {
|
|
|
191
184
|
return Buffer.from(forge.util.hexToBytes(obj.n.toString(16)), 'binary');
|
|
192
185
|
};
|
|
193
186
|
|
|
194
|
-
|
|
195
187
|
/**
|
|
196
188
|
* Get public exponent
|
|
197
189
|
*
|
|
@@ -206,7 +198,7 @@ exports.getModulus = async function(input) {
|
|
|
206
198
|
* ```
|
|
207
199
|
*/
|
|
208
200
|
|
|
209
|
-
exports.getPublicExponent = async
|
|
201
|
+
exports.getPublicExponent = async (input) => {
|
|
210
202
|
if (!Buffer.isBuffer(input)) {
|
|
211
203
|
input = Buffer.from(input);
|
|
212
204
|
}
|
|
@@ -215,7 +207,6 @@ exports.getPublicExponent = async function(input) {
|
|
|
215
207
|
return Buffer.from(forge.util.hexToBytes(obj.e.toString(16)), 'binary');
|
|
216
208
|
};
|
|
217
209
|
|
|
218
|
-
|
|
219
210
|
/**
|
|
220
211
|
* Read domains from a Certificate Signing Request
|
|
221
212
|
*
|
|
@@ -231,7 +222,7 @@ exports.getPublicExponent = async function(input) {
|
|
|
231
222
|
* ```
|
|
232
223
|
*/
|
|
233
224
|
|
|
234
|
-
exports.readCsrDomains = async
|
|
225
|
+
exports.readCsrDomains = async (csr) => {
|
|
235
226
|
if (!Buffer.isBuffer(csr)) {
|
|
236
227
|
csr = Buffer.from(csr);
|
|
237
228
|
}
|
|
@@ -240,7 +231,6 @@ exports.readCsrDomains = async function(csr) {
|
|
|
240
231
|
return parseDomains(obj);
|
|
241
232
|
};
|
|
242
233
|
|
|
243
|
-
|
|
244
234
|
/**
|
|
245
235
|
* Read information from a certificate
|
|
246
236
|
*
|
|
@@ -260,7 +250,7 @@ exports.readCsrDomains = async function(csr) {
|
|
|
260
250
|
* ```
|
|
261
251
|
*/
|
|
262
252
|
|
|
263
|
-
exports.readCertificateInfo = async
|
|
253
|
+
exports.readCertificateInfo = async (cert) => {
|
|
264
254
|
if (!Buffer.isBuffer(cert)) {
|
|
265
255
|
cert = Buffer.from(cert);
|
|
266
256
|
}
|
|
@@ -270,15 +260,14 @@ exports.readCertificateInfo = async function(cert) {
|
|
|
270
260
|
|
|
271
261
|
return {
|
|
272
262
|
issuer: {
|
|
273
|
-
commonName: issuerCn ? issuerCn.value : null
|
|
263
|
+
commonName: issuerCn ? issuerCn.value : null,
|
|
274
264
|
},
|
|
275
265
|
domains: parseDomains(obj),
|
|
276
266
|
notAfter: obj.validity.notAfter,
|
|
277
|
-
notBefore: obj.validity.notBefore
|
|
267
|
+
notBefore: obj.validity.notBefore,
|
|
278
268
|
};
|
|
279
269
|
};
|
|
280
270
|
|
|
281
|
-
|
|
282
271
|
/**
|
|
283
272
|
* Determine ASN.1 type for CSR subject short name
|
|
284
273
|
* Note: https://datatracker.ietf.org/doc/html/rfc5280
|
|
@@ -299,7 +288,6 @@ function getCsrValueTagClass(shortName) {
|
|
|
299
288
|
}
|
|
300
289
|
}
|
|
301
290
|
|
|
302
|
-
|
|
303
291
|
/**
|
|
304
292
|
* Create array of short names and values for Certificate Signing Request subjects
|
|
305
293
|
*
|
|
@@ -319,7 +307,6 @@ function createCsrSubject(subjectObj) {
|
|
|
319
307
|
}, []);
|
|
320
308
|
}
|
|
321
309
|
|
|
322
|
-
|
|
323
310
|
/**
|
|
324
311
|
* Create array of alt names for Certificate Signing Requests
|
|
325
312
|
* Note: https://github.com/digitalbazaar/forge/blob/dfdde475677a8a25c851e33e8f81dca60d90cfb9/lib/x509.js#L1444-L1454
|
|
@@ -336,7 +323,6 @@ function formatCsrAltNames(altNames) {
|
|
|
336
323
|
});
|
|
337
324
|
}
|
|
338
325
|
|
|
339
|
-
|
|
340
326
|
/**
|
|
341
327
|
* Create a Certificate Signing Request
|
|
342
328
|
*
|
|
@@ -356,29 +342,30 @@ function formatCsrAltNames(altNames) {
|
|
|
356
342
|
* @example Create a Certificate Signing Request
|
|
357
343
|
* ```js
|
|
358
344
|
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
|
359
|
-
*
|
|
345
|
+
* altNames: ['test.example.com'],
|
|
360
346
|
* });
|
|
361
347
|
* ```
|
|
362
348
|
*
|
|
363
349
|
* @example Certificate Signing Request with both common and alternative names
|
|
350
|
+
* > *Warning*: Certificate subject common name has been [deprecated](https://letsencrypt.org/docs/glossary/#def-CN) and its use is [discouraged](https://cabforum.org/uploads/BRv1.2.3.pdf).
|
|
364
351
|
* ```js
|
|
365
352
|
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
|
366
353
|
* keySize: 4096,
|
|
367
354
|
* commonName: 'test.example.com',
|
|
368
|
-
* altNames: ['foo.example.com', 'bar.example.com']
|
|
355
|
+
* altNames: ['foo.example.com', 'bar.example.com'],
|
|
369
356
|
* });
|
|
370
357
|
* ```
|
|
371
358
|
*
|
|
372
359
|
* @example Certificate Signing Request with additional information
|
|
373
360
|
* ```js
|
|
374
361
|
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
|
375
|
-
*
|
|
362
|
+
* altNames: ['test.example.com'],
|
|
376
363
|
* country: 'US',
|
|
377
364
|
* state: 'California',
|
|
378
365
|
* locality: 'Los Angeles',
|
|
379
366
|
* organization: 'The Company Inc.',
|
|
380
367
|
* organizationUnit: 'IT Department',
|
|
381
|
-
* emailAddress: 'contact@example.com'
|
|
368
|
+
* emailAddress: 'contact@example.com',
|
|
382
369
|
* });
|
|
383
370
|
* ```
|
|
384
371
|
*
|
|
@@ -387,11 +374,11 @@ function formatCsrAltNames(altNames) {
|
|
|
387
374
|
* const certificateKey = await acme.forge.createPrivateKey();
|
|
388
375
|
*
|
|
389
376
|
* const [, certificateRequest] = await acme.forge.createCsr({
|
|
390
|
-
*
|
|
377
|
+
* altNames: ['test.example.com'],
|
|
391
378
|
* }, certificateKey);
|
|
392
379
|
*/
|
|
393
380
|
|
|
394
|
-
exports.createCsr = async
|
|
381
|
+
exports.createCsr = async (data, key = null) => {
|
|
395
382
|
if (!key) {
|
|
396
383
|
key = await createPrivateKey(data.keySize);
|
|
397
384
|
}
|
|
@@ -423,7 +410,7 @@ exports.createCsr = async function(data, key = null) {
|
|
|
423
410
|
L: data.locality,
|
|
424
411
|
O: data.organization,
|
|
425
412
|
OU: data.organizationUnit,
|
|
426
|
-
E: data.emailAddress
|
|
413
|
+
E: data.emailAddress,
|
|
427
414
|
});
|
|
428
415
|
|
|
429
416
|
csr.setSubject(subject);
|
|
@@ -434,8 +421,8 @@ exports.createCsr = async function(data, key = null) {
|
|
|
434
421
|
name: 'extensionRequest',
|
|
435
422
|
extensions: [{
|
|
436
423
|
name: 'subjectAltName',
|
|
437
|
-
altNames: formatCsrAltNames(data.altNames)
|
|
438
|
-
}]
|
|
424
|
+
altNames: formatCsrAltNames(data.altNames),
|
|
425
|
+
}],
|
|
439
426
|
}]);
|
|
440
427
|
}
|
|
441
428
|
|
package/src/crypto/index.js
CHANGED
|
@@ -22,7 +22,6 @@ const subjectAltNameOID = '2.5.29.17';
|
|
|
22
22
|
/* id-pe-acmeIdentifier - https://datatracker.ietf.org/doc/html/rfc8737#section-6.1 */
|
|
23
23
|
const alpnAcmeIdentifierOID = '1.3.6.1.5.5.7.1.31';
|
|
24
24
|
|
|
25
|
-
|
|
26
25
|
/**
|
|
27
26
|
* Determine key type and info by attempting to derive public key
|
|
28
27
|
*
|
|
@@ -35,7 +34,7 @@ function getKeyInfo(keyPem) {
|
|
|
35
34
|
const result = {
|
|
36
35
|
isRSA: false,
|
|
37
36
|
isECDSA: false,
|
|
38
|
-
publicKey: crypto.createPublicKey(keyPem)
|
|
37
|
+
publicKey: crypto.createPublicKey(keyPem),
|
|
39
38
|
};
|
|
40
39
|
|
|
41
40
|
if (result.publicKey.asymmetricKeyType === 'rsa') {
|
|
@@ -51,7 +50,6 @@ function getKeyInfo(keyPem) {
|
|
|
51
50
|
return result;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
|
|
55
53
|
/**
|
|
56
54
|
* Generate a private RSA key
|
|
57
55
|
*
|
|
@@ -74,8 +72,8 @@ async function createPrivateRsaKey(modulusLength = 2048) {
|
|
|
74
72
|
modulusLength,
|
|
75
73
|
privateKeyEncoding: {
|
|
76
74
|
type: 'pkcs8',
|
|
77
|
-
format: 'pem'
|
|
78
|
-
}
|
|
75
|
+
format: 'pem',
|
|
76
|
+
},
|
|
79
77
|
});
|
|
80
78
|
|
|
81
79
|
return Buffer.from(pair.privateKey);
|
|
@@ -83,7 +81,6 @@ async function createPrivateRsaKey(modulusLength = 2048) {
|
|
|
83
81
|
|
|
84
82
|
exports.createPrivateRsaKey = createPrivateRsaKey;
|
|
85
83
|
|
|
86
|
-
|
|
87
84
|
/**
|
|
88
85
|
* Alias of `createPrivateRsaKey()`
|
|
89
86
|
*
|
|
@@ -92,7 +89,6 @@ exports.createPrivateRsaKey = createPrivateRsaKey;
|
|
|
92
89
|
|
|
93
90
|
exports.createPrivateKey = createPrivateRsaKey;
|
|
94
91
|
|
|
95
|
-
|
|
96
92
|
/**
|
|
97
93
|
* Generate a private ECDSA key
|
|
98
94
|
*
|
|
@@ -115,14 +111,13 @@ exports.createPrivateEcdsaKey = async (namedCurve = 'P-256') => {
|
|
|
115
111
|
namedCurve,
|
|
116
112
|
privateKeyEncoding: {
|
|
117
113
|
type: 'pkcs8',
|
|
118
|
-
format: 'pem'
|
|
119
|
-
}
|
|
114
|
+
format: 'pem',
|
|
115
|
+
},
|
|
120
116
|
});
|
|
121
117
|
|
|
122
118
|
return Buffer.from(pair.privateKey);
|
|
123
119
|
};
|
|
124
120
|
|
|
125
|
-
|
|
126
121
|
/**
|
|
127
122
|
* Get a public key derived from a RSA or ECDSA key
|
|
128
123
|
*
|
|
@@ -140,13 +135,12 @@ exports.getPublicKey = (keyPem) => {
|
|
|
140
135
|
|
|
141
136
|
const publicKey = info.publicKey.export({
|
|
142
137
|
type: info.isECDSA ? 'spki' : 'pkcs1',
|
|
143
|
-
format: 'pem'
|
|
138
|
+
format: 'pem',
|
|
144
139
|
});
|
|
145
140
|
|
|
146
141
|
return Buffer.from(publicKey);
|
|
147
142
|
};
|
|
148
143
|
|
|
149
|
-
|
|
150
144
|
/**
|
|
151
145
|
* Get a JSON Web Key derived from a RSA or ECDSA key
|
|
152
146
|
*
|
|
@@ -163,7 +157,7 @@ exports.getPublicKey = (keyPem) => {
|
|
|
163
157
|
|
|
164
158
|
function getJwk(keyPem) {
|
|
165
159
|
const jwk = crypto.createPublicKey(keyPem).export({
|
|
166
|
-
format: 'jwk'
|
|
160
|
+
format: 'jwk',
|
|
167
161
|
});
|
|
168
162
|
|
|
169
163
|
/* Sort keys */
|
|
@@ -175,7 +169,6 @@ function getJwk(keyPem) {
|
|
|
175
169
|
|
|
176
170
|
exports.getJwk = getJwk;
|
|
177
171
|
|
|
178
|
-
|
|
179
172
|
/**
|
|
180
173
|
* Produce CryptoKeyPair and signing algorithm from a PEM encoded private key
|
|
181
174
|
*
|
|
@@ -191,7 +184,7 @@ async function getWebCryptoKeyPair(keyPem) {
|
|
|
191
184
|
/* Signing algorithm */
|
|
192
185
|
const sigalg = {
|
|
193
186
|
name: 'RSASSA-PKCS1-v1_5',
|
|
194
|
-
hash: { name: 'SHA-256' }
|
|
187
|
+
hash: { name: 'SHA-256' },
|
|
195
188
|
};
|
|
196
189
|
|
|
197
190
|
if (info.isECDSA) {
|
|
@@ -215,7 +208,6 @@ async function getWebCryptoKeyPair(keyPem) {
|
|
|
215
208
|
return [{ privateKey, publicKey }, sigalg];
|
|
216
209
|
}
|
|
217
210
|
|
|
218
|
-
|
|
219
211
|
/**
|
|
220
212
|
* Split chain of PEM encoded objects from string into array
|
|
221
213
|
*
|
|
@@ -235,7 +227,6 @@ function splitPemChain(chainPem) {
|
|
|
235
227
|
|
|
236
228
|
exports.splitPemChain = splitPemChain;
|
|
237
229
|
|
|
238
|
-
|
|
239
230
|
/**
|
|
240
231
|
* Parse body of PEM encoded object and return a Base64URL string
|
|
241
232
|
* If multiple objects are chained, the first body will be returned
|
|
@@ -256,7 +247,6 @@ exports.getPemBodyAsB64u = (pem) => {
|
|
|
256
247
|
return Buffer.from(dec).toString('base64url');
|
|
257
248
|
};
|
|
258
249
|
|
|
259
|
-
|
|
260
250
|
/**
|
|
261
251
|
* Parse domains from a certificate or CSR
|
|
262
252
|
*
|
|
@@ -277,11 +267,10 @@ function parseDomains(input) {
|
|
|
277
267
|
|
|
278
268
|
return {
|
|
279
269
|
commonName,
|
|
280
|
-
altNames
|
|
270
|
+
altNames,
|
|
281
271
|
};
|
|
282
272
|
}
|
|
283
273
|
|
|
284
|
-
|
|
285
274
|
/**
|
|
286
275
|
* Read domains from a Certificate Signing Request
|
|
287
276
|
*
|
|
@@ -307,7 +296,6 @@ exports.readCsrDomains = (csrPem) => {
|
|
|
307
296
|
return parseDomains(csr);
|
|
308
297
|
};
|
|
309
298
|
|
|
310
|
-
|
|
311
299
|
/**
|
|
312
300
|
* Read information from a certificate
|
|
313
301
|
* If multiple certificates are chained, the first will be read
|
|
@@ -338,15 +326,14 @@ exports.readCertificateInfo = (certPem) => {
|
|
|
338
326
|
|
|
339
327
|
return {
|
|
340
328
|
issuer: {
|
|
341
|
-
commonName: cert.issuerName.getField('CN').pop() || null
|
|
329
|
+
commonName: cert.issuerName.getField('CN').pop() || null,
|
|
342
330
|
},
|
|
343
331
|
domains: parseDomains(cert),
|
|
344
332
|
notBefore: cert.notBefore,
|
|
345
|
-
notAfter: cert.notAfter
|
|
333
|
+
notAfter: cert.notAfter,
|
|
346
334
|
};
|
|
347
335
|
};
|
|
348
336
|
|
|
349
|
-
|
|
350
337
|
/**
|
|
351
338
|
* Determine ASN.1 character string type for CSR subject field name
|
|
352
339
|
*
|
|
@@ -369,7 +356,6 @@ function getCsrAsn1CharStringType(field) {
|
|
|
369
356
|
}
|
|
370
357
|
}
|
|
371
358
|
|
|
372
|
-
|
|
373
359
|
/**
|
|
374
360
|
* Create array of subject fields for a Certificate Signing Request
|
|
375
361
|
*
|
|
@@ -391,7 +377,6 @@ function createCsrSubject(input) {
|
|
|
391
377
|
}, []);
|
|
392
378
|
}
|
|
393
379
|
|
|
394
|
-
|
|
395
380
|
/**
|
|
396
381
|
* Create x509 subject alternate name extension
|
|
397
382
|
*
|
|
@@ -409,7 +394,6 @@ function createSubjectAltNameExtension(altNames) {
|
|
|
409
394
|
}));
|
|
410
395
|
}
|
|
411
396
|
|
|
412
|
-
|
|
413
397
|
/**
|
|
414
398
|
* Create a Certificate Signing Request
|
|
415
399
|
*
|
|
@@ -429,29 +413,30 @@ function createSubjectAltNameExtension(altNames) {
|
|
|
429
413
|
* @example Create a Certificate Signing Request
|
|
430
414
|
* ```js
|
|
431
415
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
|
432
|
-
*
|
|
416
|
+
* altNames: ['test.example.com'],
|
|
433
417
|
* });
|
|
434
418
|
* ```
|
|
435
419
|
*
|
|
436
420
|
* @example Certificate Signing Request with both common and alternative names
|
|
421
|
+
* > *Warning*: Certificate subject common name has been [deprecated](https://letsencrypt.org/docs/glossary/#def-CN) and its use is [discouraged](https://cabforum.org/uploads/BRv1.2.3.pdf).
|
|
437
422
|
* ```js
|
|
438
423
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
|
439
424
|
* keySize: 4096,
|
|
440
425
|
* commonName: 'test.example.com',
|
|
441
|
-
* altNames: ['foo.example.com', 'bar.example.com']
|
|
426
|
+
* altNames: ['foo.example.com', 'bar.example.com'],
|
|
442
427
|
* });
|
|
443
428
|
* ```
|
|
444
429
|
*
|
|
445
430
|
* @example Certificate Signing Request with additional information
|
|
446
431
|
* ```js
|
|
447
432
|
* const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
|
|
448
|
-
*
|
|
433
|
+
* altNames: ['test.example.com'],
|
|
449
434
|
* country: 'US',
|
|
450
435
|
* state: 'California',
|
|
451
436
|
* locality: 'Los Angeles',
|
|
452
437
|
* organization: 'The Company Inc.',
|
|
453
438
|
* organizationUnit: 'IT Department',
|
|
454
|
-
* emailAddress: 'contact@example.com'
|
|
439
|
+
* emailAddress: 'contact@example.com',
|
|
455
440
|
* });
|
|
456
441
|
* ```
|
|
457
442
|
*
|
|
@@ -460,8 +445,9 @@ function createSubjectAltNameExtension(altNames) {
|
|
|
460
445
|
* const certificateKey = await acme.crypto.createPrivateEcdsaKey();
|
|
461
446
|
*
|
|
462
447
|
* const [, certificateRequest] = await acme.crypto.createCsr({
|
|
463
|
-
*
|
|
448
|
+
* altNames: ['test.example.com'],
|
|
464
449
|
* }, certificateKey);
|
|
450
|
+
* ```
|
|
465
451
|
*/
|
|
466
452
|
|
|
467
453
|
exports.createCsr = async (data, keyPem = null) => {
|
|
@@ -489,7 +475,7 @@ exports.createCsr = async (data, keyPem = null) => {
|
|
|
489
475
|
new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature | x509.KeyUsageFlags.keyEncipherment), // eslint-disable-line no-bitwise
|
|
490
476
|
|
|
491
477
|
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 */
|
|
492
|
-
createSubjectAltNameExtension(data.altNames)
|
|
478
|
+
createSubjectAltNameExtension(data.altNames),
|
|
493
479
|
];
|
|
494
480
|
|
|
495
481
|
/* Create CSR */
|
|
@@ -504,8 +490,8 @@ exports.createCsr = async (data, keyPem = null) => {
|
|
|
504
490
|
L: data.locality,
|
|
505
491
|
O: data.organization,
|
|
506
492
|
OU: data.organizationUnit,
|
|
507
|
-
E: data.emailAddress
|
|
508
|
-
})
|
|
493
|
+
E: data.emailAddress,
|
|
494
|
+
}),
|
|
509
495
|
});
|
|
510
496
|
|
|
511
497
|
/* Done */
|
|
@@ -513,7 +499,6 @@ exports.createCsr = async (data, keyPem = null) => {
|
|
|
513
499
|
return [keyPem, Buffer.from(pem)];
|
|
514
500
|
};
|
|
515
501
|
|
|
516
|
-
|
|
517
502
|
/**
|
|
518
503
|
* Create a self-signed ALPN certificate for TLS-ALPN-01 challenges
|
|
519
504
|
*
|
|
@@ -533,6 +518,7 @@ exports.createCsr = async (data, keyPem = null) => {
|
|
|
533
518
|
* ```js
|
|
534
519
|
* const alpnKey = await acme.crypto.createPrivateEcdsaKey();
|
|
535
520
|
* const [, alpnCertificate] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization, alpnKey);
|
|
521
|
+
* ```
|
|
536
522
|
*/
|
|
537
523
|
|
|
538
524
|
exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) => {
|
|
@@ -564,7 +550,7 @@ exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) =
|
|
|
564
550
|
await x509.SubjectKeyIdentifierExtension.create(keys.publicKey),
|
|
565
551
|
|
|
566
552
|
/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 */
|
|
567
|
-
createSubjectAltNameExtension([commonName])
|
|
553
|
+
createSubjectAltNameExtension([commonName]),
|
|
568
554
|
];
|
|
569
555
|
|
|
570
556
|
/* ALPN extension */
|
|
@@ -581,8 +567,8 @@ exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) =
|
|
|
581
567
|
notBefore: now,
|
|
582
568
|
notAfter: now,
|
|
583
569
|
name: createCsrSubject({
|
|
584
|
-
CN: commonName
|
|
585
|
-
})
|
|
570
|
+
CN: commonName,
|
|
571
|
+
}),
|
|
586
572
|
});
|
|
587
573
|
|
|
588
574
|
/* Done */
|
|
@@ -590,7 +576,6 @@ exports.createAlpnCertificate = async (authz, keyAuthorization, keyPem = null) =
|
|
|
590
576
|
return [keyPem, Buffer.from(pem)];
|
|
591
577
|
};
|
|
592
578
|
|
|
593
|
-
|
|
594
579
|
/**
|
|
595
580
|
* Validate that a ALPN certificate contains the expected key authorization
|
|
596
581
|
*
|
package/src/http.js
CHANGED
|
@@ -40,7 +40,6 @@ class HttpClient {
|
|
|
40
40
|
this.jwk = null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
43
|
/**
|
|
45
44
|
* HTTP request
|
|
46
45
|
*
|
|
@@ -70,7 +69,6 @@ class HttpClient {
|
|
|
70
69
|
return resp;
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
|
|
74
72
|
/**
|
|
75
73
|
* Ensure provider directory exists
|
|
76
74
|
*
|
|
@@ -95,7 +93,6 @@ class HttpClient {
|
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
95
|
|
|
98
|
-
|
|
99
96
|
/**
|
|
100
97
|
* Get JSON Web Key
|
|
101
98
|
*
|
|
@@ -110,7 +107,6 @@ class HttpClient {
|
|
|
110
107
|
return this.jwk;
|
|
111
108
|
}
|
|
112
109
|
|
|
113
|
-
|
|
114
110
|
/**
|
|
115
111
|
* Get nonce from directory API endpoint
|
|
116
112
|
*
|
|
@@ -130,7 +126,6 @@ class HttpClient {
|
|
|
130
126
|
return resp.headers['replay-nonce'];
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
|
|
134
129
|
/**
|
|
135
130
|
* Get URL for a directory resource
|
|
136
131
|
*
|
|
@@ -148,7 +143,6 @@ class HttpClient {
|
|
|
148
143
|
return this.directory[resource];
|
|
149
144
|
}
|
|
150
145
|
|
|
151
|
-
|
|
152
146
|
/**
|
|
153
147
|
* Get directory meta field
|
|
154
148
|
*
|
|
@@ -166,7 +160,6 @@ class HttpClient {
|
|
|
166
160
|
return null;
|
|
167
161
|
}
|
|
168
162
|
|
|
169
|
-
|
|
170
163
|
/**
|
|
171
164
|
* Prepare HTTP request body for signature
|
|
172
165
|
*
|
|
@@ -199,11 +192,10 @@ class HttpClient {
|
|
|
199
192
|
/* Body */
|
|
200
193
|
return {
|
|
201
194
|
payload: payload ? Buffer.from(JSON.stringify(payload)).toString('base64url') : '',
|
|
202
|
-
protected: Buffer.from(JSON.stringify(header)).toString('base64url')
|
|
195
|
+
protected: Buffer.from(JSON.stringify(header)).toString('base64url'),
|
|
203
196
|
};
|
|
204
197
|
}
|
|
205
198
|
|
|
206
|
-
|
|
207
199
|
/**
|
|
208
200
|
* Create JWS HTTP request body using HMAC
|
|
209
201
|
*
|
|
@@ -226,7 +218,6 @@ class HttpClient {
|
|
|
226
218
|
return result;
|
|
227
219
|
}
|
|
228
220
|
|
|
229
|
-
|
|
230
221
|
/**
|
|
231
222
|
* Create JWS HTTP request body using RSA or ECC
|
|
232
223
|
*
|
|
@@ -267,13 +258,12 @@ class HttpClient {
|
|
|
267
258
|
result.signature = signer.sign({
|
|
268
259
|
key: this.accountKey,
|
|
269
260
|
padding: RSA_PKCS1_PADDING,
|
|
270
|
-
dsaEncoding: 'ieee-p1363'
|
|
261
|
+
dsaEncoding: 'ieee-p1363',
|
|
271
262
|
}, 'base64url');
|
|
272
263
|
|
|
273
264
|
return result;
|
|
274
265
|
}
|
|
275
266
|
|
|
276
|
-
|
|
277
267
|
/**
|
|
278
268
|
* Signed HTTP request
|
|
279
269
|
*
|
|
@@ -309,7 +299,7 @@ class HttpClient {
|
|
|
309
299
|
const data = this.createSignedBody(url, payload, { nonce, kid });
|
|
310
300
|
const resp = await this.request(url, 'post', { data });
|
|
311
301
|
|
|
312
|
-
/* Retry on bad nonce - https://datatracker.ietf.org/doc/html/
|
|
302
|
+
/* Retry on bad nonce - https://datatracker.ietf.org/doc/html/rfc8555#section-6.5 */
|
|
313
303
|
if (resp.data && resp.data.type && (resp.status === 400) && (resp.data.type === 'urn:ietf:params:acme:error:badNonce') && (attempts < this.maxBadNonceRetries)) {
|
|
314
304
|
nonce = resp.headers['replay-nonce'] || null;
|
|
315
305
|
attempts += 1;
|
|
@@ -323,6 +313,5 @@ class HttpClient {
|
|
|
323
313
|
}
|
|
324
314
|
}
|
|
325
315
|
|
|
326
|
-
|
|
327
316
|
/* Export client */
|
|
328
317
|
module.exports = HttpClient;
|
package/src/index.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
exports.Client = require('./client');
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
/**
|
|
9
8
|
* Directory URLs
|
|
10
9
|
*/
|
|
@@ -12,18 +11,17 @@ exports.Client = require('./client');
|
|
|
12
11
|
exports.directory = {
|
|
13
12
|
buypass: {
|
|
14
13
|
staging: 'https://api.test4.buypass.no/acme/directory',
|
|
15
|
-
production: 'https://api.buypass.com/acme/directory'
|
|
14
|
+
production: 'https://api.buypass.com/acme/directory',
|
|
16
15
|
},
|
|
17
16
|
letsencrypt: {
|
|
18
17
|
staging: 'https://acme-staging-v02.api.letsencrypt.org/directory',
|
|
19
|
-
production: 'https://acme-v02.api.letsencrypt.org/directory'
|
|
18
|
+
production: 'https://acme-v02.api.letsencrypt.org/directory',
|
|
20
19
|
},
|
|
21
20
|
zerossl: {
|
|
22
|
-
production: 'https://acme.zerossl.com/v2/DV90'
|
|
23
|
-
}
|
|
21
|
+
production: 'https://acme.zerossl.com/v2/DV90',
|
|
22
|
+
},
|
|
24
23
|
};
|
|
25
24
|
|
|
26
|
-
|
|
27
25
|
/**
|
|
28
26
|
* Crypto
|
|
29
27
|
*/
|
|
@@ -31,14 +29,12 @@ exports.directory = {
|
|
|
31
29
|
exports.crypto = require('./crypto');
|
|
32
30
|
exports.forge = require('./crypto/forge');
|
|
33
31
|
|
|
34
|
-
|
|
35
32
|
/**
|
|
36
33
|
* Axios
|
|
37
34
|
*/
|
|
38
35
|
|
|
39
36
|
exports.axios = require('./axios');
|
|
40
37
|
|
|
41
|
-
|
|
42
38
|
/**
|
|
43
39
|
* Logger
|
|
44
40
|
*/
|
package/src/logger.js
CHANGED
|
@@ -6,7 +6,6 @@ const debug = require('debug')('acme-client');
|
|
|
6
6
|
|
|
7
7
|
let logger = () => {};
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
/**
|
|
11
10
|
* Set logger function
|
|
12
11
|
*
|
|
@@ -17,11 +16,10 @@ exports.setLogger = (fn) => {
|
|
|
17
16
|
logger = fn;
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
|
|
21
19
|
/**
|
|
22
20
|
* Log message
|
|
23
21
|
*
|
|
24
|
-
* @param {string} Message
|
|
22
|
+
* @param {string} msg Message
|
|
25
23
|
*/
|
|
26
24
|
|
|
27
25
|
exports.log = (msg) => {
|