@certd/acme-client 1.39.11 → 1.39.13

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,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  /**
2
3
  * Legacy node-forge crypto interface
3
4
  *
@@ -10,9 +11,7 @@ import net from 'net';
10
11
  import { promisify } from 'util';
11
12
  import forge from 'node-forge';
12
13
  import { createPrivateEcdsaKey } from './index.js';
13
-
14
14
  const generateKeyPair = promisify(forge.pki.rsa.generateKeyPair);
15
-
16
15
  /**
17
16
  * Attempt to parse forge object from PEM encoded string
18
17
  *
@@ -20,39 +19,31 @@ const generateKeyPair = promisify(forge.pki.rsa.generateKeyPair);
20
19
  * @param {string} input PEM string
21
20
  * @return {object}
22
21
  */
23
-
24
22
  function forgeObjectFromPem(input) {
25
23
  const msg = forge.pem.decode(input)[0];
26
24
  let result;
27
-
28
25
  switch (msg.type) {
29
26
  case 'PRIVATE KEY':
30
27
  case 'RSA PRIVATE KEY':
31
28
  result = forge.pki.privateKeyFromPem(input);
32
29
  break;
33
-
34
30
  case 'PUBLIC KEY':
35
31
  case 'RSA PUBLIC KEY':
36
32
  result = forge.pki.publicKeyFromPem(input);
37
33
  break;
38
-
39
34
  case 'CERTIFICATE':
40
35
  case 'X509 CERTIFICATE':
41
36
  case 'TRUSTED CERTIFICATE':
42
37
  result = forge.pki.certificateFromPem(input).publicKey;
43
38
  break;
44
-
45
39
  case 'CERTIFICATE REQUEST':
46
40
  result = forge.pki.certificationRequestFromPem(input).publicKey;
47
41
  break;
48
-
49
42
  default:
50
43
  throw new Error('Unable to detect forge message type');
51
44
  }
52
-
53
45
  return result;
54
46
  }
55
-
56
47
  /**
57
48
  * Parse domain names from a certificate or CSR
58
49
  *
@@ -60,41 +51,33 @@ function forgeObjectFromPem(input) {
60
51
  * @param {object} obj Forge certificate or CSR
61
52
  * @returns {object} {commonName, altNames}
62
53
  */
63
-
64
54
  function parseDomains(obj) {
65
55
  let commonName = null;
66
56
  let altNames = [];
67
57
  let altNamesDict = [];
68
-
69
58
  const commonNameObject = (obj.subject.attributes || []).find((a) => a.name === 'commonName');
70
59
  const rootAltNames = (obj.extensions || []).find((e) => 'altNames' in e);
71
60
  const rootExtensions = (obj.attributes || []).find((a) => 'extensions' in a);
72
-
73
61
  if (rootAltNames && rootAltNames.altNames && rootAltNames.altNames.length) {
74
62
  altNamesDict = rootAltNames.altNames;
75
63
  }
76
64
  else if (rootExtensions && rootExtensions.extensions && rootExtensions.extensions.length) {
77
65
  const extAltNames = rootExtensions.extensions.find((e) => 'altNames' in e);
78
-
79
66
  if (extAltNames && extAltNames.altNames && extAltNames.altNames.length) {
80
67
  altNamesDict = extAltNames.altNames;
81
68
  }
82
69
  }
83
-
84
70
  if (commonNameObject) {
85
71
  commonName = commonNameObject.value;
86
72
  }
87
-
88
73
  if (altNamesDict) {
89
74
  altNames = altNamesDict.map((a) => a.value);
90
75
  }
91
-
92
76
  return {
93
77
  commonName,
94
78
  altNames,
95
79
  };
96
80
  }
97
-
98
81
  /**
99
82
  * Generate a private RSA key
100
83
  *
@@ -111,14 +94,11 @@ function parseDomains(obj) {
111
94
  * const privateKey = await acme.forge.createPrivateKey(4096);
112
95
  * ```
113
96
  */
114
-
115
97
  export async function createPrivateKey(size = 2048) {
116
98
  const keyPair = await generateKeyPair({ bits: size });
117
99
  const pemKey = forge.pki.privateKeyToPem(keyPair.privateKey);
118
100
  return Buffer.from(pemKey);
119
101
  }
120
-
121
-
122
102
  /**
123
103
  * Create public key from a private RSA key
124
104
  *
@@ -130,14 +110,12 @@ export async function createPrivateKey(size = 2048) {
130
110
  * const publicKey = await acme.forge.createPublicKey(privateKey);
131
111
  * ```
132
112
  */
133
-
134
113
  export const createPublicKey = async (key) => {
135
114
  const privateKey = forge.pki.privateKeyFromPem(key);
136
115
  const publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e);
137
116
  const pemKey = forge.pki.publicKeyToPem(publicKey);
138
117
  return Buffer.from(pemKey);
139
118
  };
140
-
141
119
  /**
142
120
  * Parse body of PEM encoded object from buffer or string
143
121
  * If multiple objects are chained, the first body will be returned
@@ -145,21 +123,17 @@ export const createPublicKey = async (key) => {
145
123
  * @param {buffer|string} str PEM encoded buffer or string
146
124
  * @returns {string} PEM body
147
125
  */
148
-
149
126
  export const getPemBody = (str) => {
150
127
  const msg = forge.pem.decode(str)[0];
151
128
  return forge.util.encode64(msg.body);
152
129
  };
153
-
154
130
  /**
155
131
  * Split chain of PEM encoded objects from buffer or string into array
156
132
  *
157
133
  * @param {buffer|string} str PEM encoded buffer or string
158
134
  * @returns {string[]} Array of PEM bodies
159
135
  */
160
-
161
136
  export const splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode);
162
-
163
137
  /**
164
138
  * Get modulus
165
139
  *
@@ -173,16 +147,13 @@ export const splitPemChain = (str) => forge.pem.decode(str).map(forge.pem.encode
173
147
  * const m3 = await acme.forge.getModulus(certificateRequest);
174
148
  * ```
175
149
  */
176
-
177
150
  export const getModulus = async (input) => {
178
151
  if (!Buffer.isBuffer(input)) {
179
152
  input = Buffer.from(input);
180
153
  }
181
-
182
154
  const obj = forgeObjectFromPem(input);
183
155
  return Buffer.from(forge.util.hexToBytes(obj.n.toString(16)), 'binary');
184
156
  };
185
-
186
157
  /**
187
158
  * Get public exponent
188
159
  *
@@ -196,16 +167,13 @@ export const getModulus = async (input) => {
196
167
  * const e3 = await acme.forge.getPublicExponent(certificateRequest);
197
168
  * ```
198
169
  */
199
-
200
170
  export const getPublicExponent = async (input) => {
201
171
  if (!Buffer.isBuffer(input)) {
202
172
  input = Buffer.from(input);
203
173
  }
204
-
205
174
  const obj = forgeObjectFromPem(input);
206
175
  return Buffer.from(forge.util.hexToBytes(obj.e.toString(16)), 'binary');
207
176
  };
208
-
209
177
  /**
210
178
  * Read domains from a Certificate Signing Request
211
179
  *
@@ -220,16 +188,13 @@ export const getPublicExponent = async (input) => {
220
188
  * console.log(`Alt names: ${altNames.join(', ')}`);
221
189
  * ```
222
190
  */
223
-
224
191
  export const readCsrDomains = async (csr) => {
225
192
  if (!Buffer.isBuffer(csr)) {
226
193
  csr = Buffer.from(csr);
227
194
  }
228
-
229
195
  const obj = forge.pki.certificationRequestFromPem(csr);
230
196
  return parseDomains(obj);
231
197
  };
232
-
233
198
  /**
234
199
  * Read information from a certificate
235
200
  *
@@ -248,15 +213,12 @@ export const readCsrDomains = async (csr) => {
248
213
  * console.log(`Alt names: ${altNames.join(', ')}`);
249
214
  * ```
250
215
  */
251
-
252
216
  export const readCertificateInfo = async (cert) => {
253
217
  if (!Buffer.isBuffer(cert)) {
254
218
  cert = Buffer.from(cert);
255
219
  }
256
-
257
220
  const obj = forge.pki.certificateFromPem(cert);
258
221
  const issuerCn = (obj.issuer.attributes || []).find((a) => a.name === 'commonName');
259
-
260
222
  return {
261
223
  issuer: {
262
224
  commonName: issuerCn ? issuerCn.value : null,
@@ -266,7 +228,6 @@ export const readCertificateInfo = async (cert) => {
266
228
  notBefore: obj.validity.notBefore,
267
229
  };
268
230
  };
269
-
270
231
  /**
271
232
  * Determine ASN.1 type for CSR subject short name
272
233
  * Note: https://datatracker.ietf.org/doc/html/rfc5280
@@ -275,7 +236,6 @@ export const readCertificateInfo = async (cert) => {
275
236
  * @param {string} shortName CSR subject short name
276
237
  * @returns {forge.asn1.Type} ASN.1 type
277
238
  */
278
-
279
239
  function getCsrValueTagClass(shortName) {
280
240
  switch (shortName) {
281
241
  case 'C':
@@ -286,7 +246,6 @@ function getCsrValueTagClass(shortName) {
286
246
  return forge.asn1.Type.UTF8;
287
247
  }
288
248
  }
289
-
290
249
  /**
291
250
  * Create array of short names and values for Certificate Signing Request subjects
292
251
  *
@@ -294,18 +253,15 @@ function getCsrValueTagClass(shortName) {
294
253
  * @param {object} subjectObj Key-value of short names and values
295
254
  * @returns {object[]} Certificate Signing Request subject array
296
255
  */
297
-
298
256
  function createCsrSubject(subjectObj) {
299
257
  return Object.entries(subjectObj).reduce((result, [shortName, value]) => {
300
258
  if (value) {
301
259
  const valueTagClass = getCsrValueTagClass(shortName);
302
260
  result.push({ shortName, value, valueTagClass });
303
261
  }
304
-
305
262
  return result;
306
263
  }, []);
307
264
  }
308
-
309
265
  /**
310
266
  * Create array of alt names for Certificate Signing Requests
311
267
  * Note: https://github.com/digitalbazaar/forge/blob/dfdde475677a8a25c851e33e8f81dca60d90cfb9/lib/x509.js#L1444-L1454
@@ -314,14 +270,12 @@ function createCsrSubject(subjectObj) {
314
270
  * @param {string[]} altNames Alt names
315
271
  * @returns {object[]} Certificate Signing Request alt names array
316
272
  */
317
-
318
273
  function formatCsrAltNames(altNames) {
319
274
  return altNames.map((value) => {
320
275
  const type = net.isIP(value) ? 7 : 2;
321
276
  return { type, value };
322
277
  });
323
278
  }
324
-
325
279
  /**
326
280
  * Create a Certificate Signing Request
327
281
  *
@@ -376,7 +330,6 @@ function formatCsrAltNames(altNames) {
376
330
  * altNames: ['test.example.com'],
377
331
  * }, certificateKey);
378
332
  */
379
-
380
333
  export const createCsr = async (data, keyType = null) => {
381
334
  let key = null;
382
335
  if (keyType === 'ec') {
@@ -388,25 +341,20 @@ export const createCsr = async (data, keyType = null) => {
388
341
  // else if (!Buffer.isBuffer(key)) {
389
342
  // key = Buffer.from(key);
390
343
  // }
391
-
392
344
  if (typeof data.altNames === 'undefined') {
393
345
  data.altNames = [];
394
346
  }
395
-
396
347
  const csr = forge.pki.createCertificationRequest();
397
-
398
348
  /* Public key */
399
349
  const privateKey = forge.pki.privateKeyFromPem(key);
400
350
  const publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e);
401
351
  csr.publicKey = publicKey;
402
352
  // const privateKey = key;
403
353
  // csr.publicKey = getPublicKey(key);
404
-
405
354
  /* Ensure subject common name is present in SAN - https://cabforum.org/wp-content/uploads/BRv1.2.3.pdf */
406
355
  if (data.commonName && !data.altNames.includes(data.commonName)) {
407
356
  data.altNames.unshift(data.commonName);
408
357
  }
409
-
410
358
  /* Subject */
411
359
  const subject = createCsrSubject({
412
360
  CN: data.commonName,
@@ -417,23 +365,19 @@ export const createCsr = async (data, keyType = null) => {
417
365
  OU: data.organizationUnit,
418
366
  E: data.emailAddress,
419
367
  });
420
-
421
368
  csr.setSubject(subject);
422
-
423
369
  /* SAN extension */
424
370
  if (data.altNames.length) {
425
371
  csr.setAttributes([{
426
- name: 'extensionRequest',
427
- extensions: [{
428
- name: 'subjectAltName',
429
- altNames: formatCsrAltNames(data.altNames),
430
- }],
431
- }]);
372
+ name: 'extensionRequest',
373
+ extensions: [{
374
+ name: 'subjectAltName',
375
+ altNames: formatCsrAltNames(data.altNames),
376
+ }],
377
+ }]);
432
378
  }
433
-
434
379
  /* Sign CSR using SHA-256 */
435
380
  csr.sign(privateKey, forge.md.sha256.create());
436
-
437
381
  /* Done */
438
382
  const pemCsr = forge.pki.certificationRequestToPem(csr);
439
383
  return [key, Buffer.from(pemCsr)];
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Generate a private RSA key
3
+ *
4
+ * @param {number} [modulusLength] Size of the keys modulus in bits, default: `2048`
5
+ * @returns {Promise<buffer>} PEM encoded private RSA key
6
+ *
7
+ * @example Generate private RSA key
8
+ * ```js
9
+ * const privateKey = await acme.crypto.createPrivateRsaKey();
10
+ * ```
11
+ *
12
+ * @example Private RSA key with modulus size 4096
13
+ * ```js
14
+ * const privateKey = await acme.crypto.createPrivateRsaKey(4096);
15
+ * ```
16
+ */
17
+ export declare function createPrivateRsaKey(modulusLength?: number, encodingType?: string): Promise<Buffer>;
18
+ /**
19
+ * Alias of `createPrivateRsaKey()`
20
+ *
21
+ * @function
22
+ */
23
+ export declare const createPrivateKey: typeof createPrivateRsaKey;
24
+ /**
25
+ * Generate a private ECDSA key
26
+ *
27
+ * @param {string} [namedCurve] ECDSA curve name (P-256, P-384 or P-521), default `P-256`
28
+ * @returns {Promise<buffer>} PEM encoded private ECDSA key
29
+ *
30
+ * @example Generate private ECDSA key
31
+ * ```js
32
+ * const privateKey = await acme.crypto.createPrivateEcdsaKey();
33
+ * ```
34
+ *
35
+ * @example Private ECDSA key using P-384 curve
36
+ * ```js
37
+ * const privateKey = await acme.crypto.createPrivateEcdsaKey('P-384');
38
+ * ```
39
+ */
40
+ export declare const createPrivateEcdsaKey: (namedCurve?: string, encodingType?: string) => Promise<Buffer>;
41
+ /**
42
+ * Get a public key derived from a RSA or ECDSA key
43
+ *
44
+ * @param {buffer|string} keyPem PEM encoded private or public key
45
+ * @returns {buffer} PEM encoded public key
46
+ *
47
+ * @example Get public key
48
+ * ```js
49
+ * const publicKey = acme.crypto.getPublicKey(privateKey);
50
+ * ```
51
+ */
52
+ export declare const getPublicKey: (keyPem: any) => Buffer;
53
+ /**
54
+ * Get a JSON Web Key derived from a RSA or ECDSA key
55
+ *
56
+ * https://datatracker.ietf.org/doc/html/rfc7517
57
+ *
58
+ * @param {buffer|string} keyPem PEM encoded private or public key
59
+ * @returns {object} JSON Web Key
60
+ *
61
+ * @example Get JWK
62
+ * ```js
63
+ * const jwk = acme.crypto.getJwk(privateKey);
64
+ * ```
65
+ */
66
+ export declare function getJwk(keyPem: any): {};
67
+ /**
68
+ * Split chain of PEM encoded objects from string into array
69
+ *
70
+ * @param {buffer|string} chainPem PEM encoded object chain
71
+ * @returns {string[]} Array of PEM objects including headers
72
+ */
73
+ export declare function splitPemChain(chainPem: any): string[];
74
+ /**
75
+ * Parse body of PEM encoded object and return a Base64URL string
76
+ * If multiple objects are chained, the first body will be returned
77
+ *
78
+ * @param {buffer|string} pem PEM encoded chain or object
79
+ * @returns {string} Base64URL-encoded body
80
+ */
81
+ export declare const getPemBodyAsB64u: (pem: any) => string;
82
+ /**
83
+ * Read domains from a Certificate Signing Request
84
+ *
85
+ * @param {buffer|string} csrPem PEM encoded Certificate Signing Request
86
+ * @returns {object} {commonName, altNames}
87
+ *
88
+ * @example Read Certificate Signing Request domains
89
+ * ```js
90
+ * const { commonName, altNames } = acme.crypto.readCsrDomains(certificateRequest);
91
+ *
92
+ * console.log(`Common name: ${commonName}`);
93
+ * console.log(`Alt names: ${altNames.join(', ')}`);
94
+ * ```
95
+ */
96
+ export declare const readCsrDomains: (csrPem: any) => {
97
+ commonName: any;
98
+ altNames: any[];
99
+ };
100
+ /**
101
+ * Read information from a certificate
102
+ * If multiple certificates are chained, the first will be read
103
+ *
104
+ * @param {buffer|string} certPem PEM encoded certificate or chain
105
+ * @returns {object} Certificate info
106
+ *
107
+ * @example Read certificate information
108
+ * ```js
109
+ * const info = acme.crypto.readCertificateInfo(certificate);
110
+ * const { commonName, altNames } = info.domains;
111
+ *
112
+ * console.log(`Not after: ${info.notAfter}`);
113
+ * console.log(`Not before: ${info.notBefore}`);
114
+ *
115
+ * console.log(`Common name: ${commonName}`);
116
+ * console.log(`Alt names: ${altNames.join(', ')}`);
117
+ * ```
118
+ */
119
+ export declare const readCertificateInfo: (certPem: any) => {
120
+ issuer: {
121
+ commonName: string;
122
+ };
123
+ domains: {
124
+ commonName: any;
125
+ altNames: any[];
126
+ };
127
+ notBefore: Date;
128
+ notAfter: Date;
129
+ };
130
+ /**
131
+ * Create a Certificate Signing Request
132
+ *
133
+ * @param {object} data
134
+ * @param {number} [data.keySize] Size of newly created RSA private key modulus in bits, default: `2048`
135
+ * @param {string} [data.commonName] FQDN of your server
136
+ * @param {string[]} [data.altNames] SAN (Subject Alternative Names), default: `[]`
137
+ * @param {string} [data.country] 2 letter country code
138
+ * @param {string} [data.state] State or province
139
+ * @param {string} [data.locality] City
140
+ * @param {string} [data.organization] Organization name
141
+ * @param {string} [data.organizationUnit] Organizational unit name
142
+ * @param {string} [data.emailAddress] Email address
143
+ * @param {buffer|string} [keyPem] PEM encoded CSR private key
144
+ * @returns {Promise<buffer[]>} [privateKey, certificateSigningRequest]
145
+ *
146
+ * @example Create a Certificate Signing Request
147
+ * ```js
148
+ * const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
149
+ * altNames: ['test.example.com'],
150
+ * });
151
+ * ```
152
+ *
153
+ * @example Certificate Signing Request with both common and alternative names
154
+ * > *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).
155
+ * ```js
156
+ * const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
157
+ * keySize: 4096,
158
+ * commonName: 'test.example.com',
159
+ * altNames: ['foo.example.com', 'bar.example.com'],
160
+ * });
161
+ * ```
162
+ *
163
+ * @example Certificate Signing Request with additional information
164
+ * ```js
165
+ * const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
166
+ * altNames: ['test.example.com'],
167
+ * country: 'US',
168
+ * state: 'California',
169
+ * locality: 'Los Angeles',
170
+ * organization: 'The Company Inc.',
171
+ * organizationUnit: 'IT Department',
172
+ * emailAddress: 'contact@example.com',
173
+ * });
174
+ * ```
175
+ *
176
+ * @example Certificate Signing Request with ECDSA private key
177
+ * ```js
178
+ * const certificateKey = await acme.crypto.createPrivateEcdsaKey();
179
+ *
180
+ * const [, certificateRequest] = await acme.crypto.createCsr({
181
+ * altNames: ['test.example.com'],
182
+ * }, certificateKey);
183
+ * ```
184
+ */
185
+ export declare const createCsr: (data: any, keyPem?: any) => Promise<any[]>;
186
+ /**
187
+ * Create a self-signed ALPN certificate for TLS-ALPN-01 challenges
188
+ *
189
+ * https://datatracker.ietf.org/doc/html/rfc8737
190
+ *
191
+ * @param {object} authz Identifier authorization
192
+ * @param {string} keyAuthorization Challenge key authorization
193
+ * @param {buffer|string} [keyPem] PEM encoded CSR private key
194
+ * @returns {Promise<buffer[]>} [privateKey, certificate]
195
+ *
196
+ * @example Create a ALPN certificate
197
+ * ```js
198
+ * const [alpnKey, alpnCertificate] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization);
199
+ * ```
200
+ *
201
+ * @example Create a ALPN certificate with ECDSA private key
202
+ * ```js
203
+ * const alpnKey = await acme.crypto.createPrivateEcdsaKey();
204
+ * const [, alpnCertificate] = await acme.crypto.createAlpnCertificate(authz, keyAuthorization, alpnKey);
205
+ * ```
206
+ */
207
+ export declare const createAlpnCertificate: (authz: any, keyAuthorization: any, keyPem?: any) => Promise<any[]>;
208
+ /**
209
+ * Validate that a ALPN certificate contains the expected key authorization
210
+ *
211
+ * @param {buffer|string} certPem PEM encoded certificate
212
+ * @param {string} keyAuthorization Expected challenge key authorization
213
+ * @returns {boolean} True when valid
214
+ */
215
+ export declare const isAlpnCertificateAuthorizationValid: (certPem: any, keyAuthorization: any) => boolean;