self-sign 5.6.7

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.

Potentially problematic release.


This version of self-sign might be problematic. Click here for more details.

package/test/tests.js ADDED
@@ -0,0 +1,605 @@
1
+ var { assert } = require('chai');
2
+ var fs = require('fs');
3
+ var { promisify } = require('util');
4
+ var exec = promisify(require('child_process').exec);
5
+ var crypto = require('crypto');
6
+
7
+ describe('generate', function () {
8
+
9
+ var generate = require('../index').generate;
10
+ var { createPkcs7 } = require('../pkcs7');
11
+
12
+ it('should work without attrs/options', async function () {
13
+ var pems = await generate();
14
+ assert.ok(!!pems.private, 'has a private key');
15
+ assert.ok(!!pems.fingerprint, 'has fingerprint');
16
+ assert.ok(!!pems.public, 'has a public key');
17
+ assert.ok(!!pems.cert, 'has a certificate');
18
+ assert.ok(!pems.pkcs7, 'should not include a pkcs7 by default');
19
+ assert.ok(!pems.clientcert, 'should not include a client cert by default');
20
+ assert.ok(!pems.clientprivate, 'should not include a client private key by default');
21
+ assert.ok(!pems.clientpublic, 'should not include a client public key by default');
22
+
23
+ // Verify cert can be read by Node.js crypto
24
+ const cert = new crypto.X509Certificate(pems.cert);
25
+ assert.ok(cert.subject, 'cert has a subject');
26
+ });
27
+
28
+ it('should generate client cert', async function () {
29
+ var pems = await generate(null, {clientCertificate: true},null);
30
+
31
+ assert.ok(!!pems.clientcert, 'should include a client cert when requested');
32
+ assert.ok(!!pems.clientprivate, 'should include a client private key when requested');
33
+ assert.ok(!!pems.clientpublic, 'should include a client public key when requested');
34
+ });
35
+
36
+ it('should include pkcs7', async function () {
37
+ var pems = await generate([{ name: 'commonName', value: 'contoso.com' }]);
38
+ var pkcs7 = createPkcs7(pems.cert);
39
+
40
+ assert.ok(!!pkcs7, 'has a pkcs7');
41
+
42
+ try {
43
+ fs.unlinkSync('/tmp/tmp.pkcs7');
44
+ } catch (er) {}
45
+
46
+ fs.writeFileSync('/tmp/tmp.pkcs7', pkcs7);
47
+
48
+ const { stdout, stderr } = await exec('openssl pkcs7 -print_certs -in /tmp/tmp.pkcs7');
49
+
50
+ if (stderr && stderr.length) {
51
+ throw new Error(stderr);
52
+ }
53
+
54
+ const expected = stdout.toString();
55
+ let [ subjectLine,issuerLine, ...cert ] = expected.split(/\r?\n/).filter(c => c);
56
+ cert = cert.filter(c => c);
57
+ assert.match(subjectLine, /subject=\/?CN\s?=\s?contoso.com/i);
58
+ assert.match(issuerLine, /issuer=\/?CN\s?=\s?contoso.com/i);
59
+ // Normalize line endings for comparison
60
+ const normalizedPemCert = pems.cert.replace(/\r\n/g, '\n').trim();
61
+ const normalizedExpected = cert.join('\n').trim();
62
+ assert.strictEqual(
63
+ normalizedPemCert,
64
+ normalizedExpected
65
+ );
66
+ });
67
+
68
+ it('should support sha1 algorithm', async function () {
69
+ var pems_sha1 = await generate(null, { algorithm: 'sha1' },null);
70
+ const cert = new crypto.X509Certificate(pems_sha1.cert);
71
+ // SHA-1 with RSA signature
72
+ assert.ok(cert.publicKey, 'can generate sha1 certs');
73
+ });
74
+
75
+ it('should support sha256 algorithm', async function () {
76
+ var pems_sha256 = await generate(null, { algorithm: 'sha256' },null);
77
+ const cert = new crypto.X509Certificate(pems_sha256.cert);
78
+ // SHA-256 with RSA signature
79
+ assert.ok(cert.publicKey, 'can generate sha256 certs');
80
+ });
81
+
82
+ it('should default to 2048 bit keysize', async function () {
83
+ var pems = await generate();
84
+ const privateKey = crypto.createPrivateKey(pems.private);
85
+ const keyDetails = privateKey.asymmetricKeyDetails;
86
+ assert.strictEqual(keyDetails.modulusLength, 2048, 'default key size should be 2048 bits');
87
+ });
88
+
89
+ it('should default to 2048 bit keysize for client certificate', async function () {
90
+ var pems = await generate(null, {clientCertificate: true},null);
91
+ const clientPrivateKey = crypto.createPrivateKey(pems.clientprivate);
92
+ const keyDetails = clientPrivateKey.asymmetricKeyDetails;
93
+ assert.strictEqual(keyDetails.modulusLength, 2048, 'default client key size should be 2048 bits');
94
+ });
95
+
96
+ it('should support custom keySize', async function () {
97
+ var pems = await generate(null, { keySize: 4096 },null);
98
+ const privateKey = crypto.createPrivateKey(pems.private);
99
+ const keyDetails = privateKey.asymmetricKeyDetails;
100
+ assert.strictEqual(keyDetails.modulusLength, 4096, 'should support custom key size');
101
+ });
102
+
103
+ it('should support custom clientCertificateKeySize', async function () {
104
+ var pems = await generate(null, {
105
+ clientCertificate: true,
106
+ clientCertificateKeySize: 4096
107
+ },null);
108
+ const clientPrivateKey = crypto.createPrivateKey(pems.clientprivate);
109
+ const keyDetails = clientPrivateKey.asymmetricKeyDetails;
110
+ assert.strictEqual(keyDetails.modulusLength, 4096, 'should support custom client key size');
111
+ });
112
+
113
+ it('should support sha384 algorithm', async function () {
114
+ var pems = await generate(null, { algorithm: 'sha384' },null);
115
+ const cert = new crypto.X509Certificate(pems.cert);
116
+ assert.ok(cert.publicKey, 'can generate sha384 certs');
117
+ });
118
+
119
+ it('should support sha512 algorithm', async function () {
120
+ var pems = await generate(null, { algorithm: 'sha512' },null);
121
+ const cert = new crypto.X509Certificate(pems.cert);
122
+ assert.ok(cert.publicKey, 'can generate sha512 certs');
123
+ });
124
+
125
+ it('should default to 365 days validity', async function () {
126
+ var pems = await generate();
127
+ const cert = new crypto.X509Certificate(pems.cert);
128
+
129
+ const validFrom = new Date(cert.validFrom);
130
+ const validTo = new Date(cert.validTo);
131
+ const diffTime = Math.abs(validTo - validFrom);
132
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
133
+
134
+ assert.approximately(diffDays, 365, 1, 'certificate should default to 365 days validity');
135
+ });
136
+
137
+ it('should respect notBeforeDate option', async function () {
138
+ const customDate = new Date('2025-01-01T00:00:00Z');
139
+ var pems = await generate(null, { notBeforeDate: customDate },null);
140
+ const cert = new crypto.X509Certificate(pems.cert);
141
+
142
+ const validFrom = new Date(cert.validFrom);
143
+ // Allow small difference for processing time
144
+ assert.approximately(validFrom.getTime(), customDate.getTime(), 5000, 'should use custom notBeforeDate');
145
+ });
146
+
147
+ it('should respect notAfterDate option', async function () {
148
+ const notBefore = new Date('2025-01-01T00:00:00Z');
149
+ const notAfter = new Date('2025-02-15T00:00:00Z');
150
+ var pems = await generate(null, { notBeforeDate: notBefore, notAfterDate: notAfter },null);
151
+ const cert = new crypto.X509Certificate(pems.cert);
152
+
153
+ const validFrom = new Date(cert.validFrom);
154
+ const validTo = new Date(cert.validTo);
155
+
156
+ assert.approximately(validFrom.getTime(), notBefore.getTime(), 5000, 'should use custom notBeforeDate');
157
+ assert.approximately(validTo.getTime(), notAfter.getTime(), 5000, 'should use custom notAfterDate');
158
+ });
159
+
160
+ it('should generate valid fingerprint format', async function () {
161
+ var pems = await generate();
162
+ assert.match(pems.fingerprint, /^[0-9a-f]{2}(:[0-9a-f]{2}){19}$/i, 'fingerprint should be valid SHA-1 format');
163
+ });
164
+
165
+ it('should support custom attributes', async function () {
166
+ const attrs = [
167
+ { name: 'commonName', value: 'test.example.com' },
168
+ { name: 'countryName', value: 'GB' },
169
+ { shortName: 'ST', value: 'London' },
170
+ { name: 'localityName', value: 'Westminster' },
171
+ { name: 'organizationName', value: 'Test Corp' },
172
+ { shortName: 'OU', value: 'Engineering' }
173
+ ];
174
+
175
+ var pems = await generate(attrs);
176
+ const cert = new crypto.X509Certificate(pems.cert);
177
+
178
+ assert.include(cert.subject, 'CN=test.example.com', 'should include custom CN');
179
+ assert.include(cert.subject, 'C=GB', 'should include custom country');
180
+ assert.include(cert.subject, 'O=Test Corp', 'should include custom organization');
181
+ });
182
+
183
+ it('should support custom clientCertificateCN (deprecated)', async function () {
184
+ var pems = await generate(null, {
185
+ clientCertificate: true,
186
+ clientCertificateCN: 'Custom User CN'
187
+ });
188
+
189
+ const clientCert = new crypto.X509Certificate(pems.clientcert);
190
+ assert.include(clientCert.subject, 'CN=Custom User CN', 'should use custom client CN');
191
+ });
192
+
193
+ it('should support clientCertificate as options object with cn', async function () {
194
+ var pems = await generate(null, {
195
+ clientCertificate: {
196
+ cn: 'Client Options CN'
197
+ }
198
+ },null);
199
+
200
+ const clientCert = new crypto.X509Certificate(pems.clientcert);
201
+ assert.include(clientCert.subject, 'CN=Client Options CN', 'should use cn from clientCertificate options');
202
+ });
203
+
204
+ it('should support clientCertificate.keySize', async function () {
205
+ var pems = await generate(null, {
206
+ clientCertificate: {
207
+ keySize: 4096
208
+ }
209
+ },null);
210
+
211
+ const clientPrivateKey = crypto.createPrivateKey(pems.clientprivate);
212
+ const keyDetails = clientPrivateKey.asymmetricKeyDetails;
213
+ assert.strictEqual(keyDetails.modulusLength, 4096, 'should use keySize from clientCertificate options');
214
+ });
215
+
216
+ it('should support clientCertificate.notBeforeDate and notAfterDate', async function () {
217
+ const notBefore = new Date('2025-06-01T00:00:00Z');
218
+ const notAfter = new Date('2025-06-30T00:00:00Z');
219
+
220
+ var pems = await generate(null, {
221
+ clientCertificate: {
222
+ notBeforeDate: notBefore,
223
+ notAfterDate: notAfter
224
+ }
225
+ },null);
226
+
227
+ const clientCert = new crypto.X509Certificate(pems.clientcert);
228
+ const validFrom = new Date(clientCert.validFrom);
229
+ const validTo = new Date(clientCert.validTo);
230
+
231
+ assert.approximately(validFrom.getTime(), notBefore.getTime(), 5000, 'should use notBeforeDate from clientCertificate options');
232
+ assert.approximately(validTo.getTime(), notAfter.getTime(), 5000, 'should use notAfterDate from clientCertificate options');
233
+ });
234
+
235
+ it('should support clientCertificate.algorithm', async function () {
236
+ var pems = await generate(null, {
237
+ algorithm: 'sha1', // main cert uses sha1
238
+ clientCertificate: {
239
+ algorithm: 'sha256' // client cert uses sha256
240
+ }
241
+ },null);
242
+
243
+ // Both certs should be valid
244
+ const serverCert = new crypto.X509Certificate(pems.cert);
245
+ const clientCert = new crypto.X509Certificate(pems.clientcert);
246
+ assert.ok(serverCert.publicKey, 'server cert should be valid');
247
+ assert.ok(clientCert.publicKey, 'client cert should be valid');
248
+ });
249
+
250
+ it('clientCertificate options should take precedence over deprecated options', async function () {
251
+ var pems = await generate(null, {
252
+ clientCertificateCN: 'Deprecated CN',
253
+ clientCertificateKeySize: 2048,
254
+ clientCertificate: {
255
+ cn: 'New Options CN',
256
+ keySize: 4096
257
+ }
258
+ },null);
259
+
260
+ const clientCert = new crypto.X509Certificate(pems.clientcert);
261
+ assert.include(clientCert.subject, 'CN=New Options CN', 'clientCertificate.cn should take precedence');
262
+
263
+ const clientPrivateKey = crypto.createPrivateKey(pems.clientprivate);
264
+ const keyDetails = clientPrivateKey.asymmetricKeyDetails;
265
+ assert.strictEqual(keyDetails.modulusLength, 4096, 'clientCertificate.keySize should take precedence');
266
+ });
267
+
268
+ it('should generate valid key pair that work together', async function () {
269
+ var pems = await generate();
270
+
271
+ // Test data
272
+ const testData = 'Hello, World!';
273
+
274
+ // Create sign and verify objects
275
+ const privateKey = crypto.createPrivateKey(pems.private);
276
+ const publicKey = crypto.createPublicKey(pems.public);
277
+
278
+ // Sign with private key
279
+ const sign = crypto.createSign('SHA256');
280
+ sign.update(testData);
281
+ sign.end();
282
+ const signature = sign.sign(privateKey);
283
+
284
+ // Verify with public key
285
+ const verify = crypto.createVerify('SHA256');
286
+ verify.update(testData);
287
+ verify.end();
288
+ const isValid = verify.verify(publicKey, signature);
289
+
290
+ assert.isTrue(isValid, 'public key should verify signature from private key');
291
+ });
292
+
293
+ it('should create client cert signed by server cert', async function () {
294
+ var pems = await generate(null, { clientCertificate: true },null);
295
+
296
+ const serverCert = new crypto.X509Certificate(pems.cert);
297
+ const clientCert = new crypto.X509Certificate(pems.clientcert);
298
+
299
+ // Client cert should have different subject than server
300
+ assert.notEqual(clientCert.subject, serverCert.subject, 'client and server should have different subjects');
301
+
302
+ // Both certs should be valid
303
+ assert.ok(serverCert.publicKey, 'server cert should be valid');
304
+ assert.ok(clientCert.publicKey, 'client cert should be valid');
305
+ });
306
+
307
+ it('should support using existing keyPair', async function () {
308
+ // First generate a key pair
309
+ const firstPems = await generate();
310
+
311
+ // Reuse the key pair
312
+ const secondPems = await generate(null, {
313
+ keyPair: {
314
+ privateKey: firstPems.private,
315
+ publicKey: firstPems.public
316
+ }
317
+ },null);
318
+
319
+ // Keys should be identical
320
+ assert.strictEqual(firstPems.private, secondPems.private, 'should use provided private key');
321
+ assert.strictEqual(firstPems.public, secondPems.public, 'should use provided public key');
322
+
323
+ // Certificates will be different (different serial, dates) but keys are same
324
+ const firstCert = new crypto.X509Certificate(firstPems.cert);
325
+ const secondCert = new crypto.X509Certificate(secondPems.cert);
326
+ assert.strictEqual(firstCert.publicKey.export({ format: 'pem', type: 'spki' }),
327
+ secondCert.publicKey.export({ format: 'pem', type: 'spki' }),
328
+ 'certificates should contain the same public key');
329
+ });
330
+
331
+ it('should create PKCS#7 for client certificate', async function () {
332
+ var pems = await generate([{ name: 'commonName', value: 'server.example.com' }], {
333
+ clientCertificate: true
334
+ },null);
335
+
336
+ var clientPkcs7 = createPkcs7(pems.clientcert);
337
+ assert.ok(!!clientPkcs7, 'should create PKCS#7 for client cert');
338
+ assert.include(clientPkcs7, 'BEGIN PKCS7', 'should be valid PKCS#7 format');
339
+
340
+ // Verify with openssl
341
+ try {
342
+ fs.unlinkSync('/tmp/tmp-client.pkcs7');
343
+ } catch (er) {}
344
+
345
+ fs.writeFileSync('/tmp/tmp-client.pkcs7', clientPkcs7);
346
+ const { stdout, stderr } = await exec('openssl pkcs7 -print_certs -in /tmp/tmp-client.pkcs7');
347
+
348
+ if (stderr && stderr.length) {
349
+ throw new Error(stderr);
350
+ }
351
+
352
+ assert.ok(stdout.toString().length > 0, 'openssl should be able to read client PKCS#7');
353
+ });
354
+
355
+ it('should generate unique serial numbers', async function () {
356
+ const pems1 = await generate();
357
+ const pems2 = await generate();
358
+
359
+ const cert1 = new crypto.X509Certificate(pems1.cert);
360
+ const cert2 = new crypto.X509Certificate(pems2.cert);
361
+
362
+ assert.notEqual(cert1.serialNumber, cert2.serialNumber, 'serial numbers should be unique');
363
+ });
364
+
365
+ it('should handle minimal attributes', async function () {
366
+ const attrs = [{ name: 'commonName', value: 'minimal.test' }];
367
+ var pems = await generate(attrs);
368
+
369
+ const cert = new crypto.X509Certificate(pems.cert);
370
+ assert.include(cert.subject, 'CN=minimal.test', 'should work with minimal attributes');
371
+ });
372
+
373
+ describe('extensions', function () {
374
+ it('should support custom subjectAltName with IPv6 (issue #79)', async function () {
375
+ var pems = await generate(
376
+ [{ name: 'commonName', value: 'localhost' }],
377
+ {
378
+ algorithm: 'sha256',
379
+ extensions: [
380
+ {
381
+ name: 'basicConstraints',
382
+ cA: false
383
+ },
384
+ {
385
+ name: 'keyUsage',
386
+ digitalSignature: true,
387
+ keyEncipherment: true
388
+ },
389
+ {
390
+ name: 'subjectAltName',
391
+ altNames: [
392
+ { type: 2, value: 'localhost' }, // DNS
393
+ { type: 7, ip: '127.0.0.1' }, // IPv4
394
+ { type: 7, ip: '::1' } // IPv6
395
+ ]
396
+ }
397
+ ]
398
+ }
399
+ );
400
+
401
+ const cert = new crypto.X509Certificate(pems.cert);
402
+ assert.ok(cert.subjectAltName, 'should have subjectAltName');
403
+ assert.include(cert.subjectAltName, 'localhost', 'should include DNS name');
404
+ assert.include(cert.subjectAltName, '127.0.0.1', 'should include IPv4');
405
+ // IPv6 ::1 may be expanded to full form 0:0:0:0:0:0:0:1
406
+ const hasIPv6 = cert.subjectAltName.includes('::1') || cert.subjectAltName.includes('0:0:0:0:0:0:0:1');
407
+ assert.ok(hasIPv6, 'should include IPv6');
408
+ });
409
+
410
+ it('should support basicConstraints with cA=true', async function () {
411
+ var pems = await generate(
412
+ [{ name: 'commonName', value: 'Test CA' }],
413
+ {
414
+ extensions: [
415
+ {
416
+ name: 'basicConstraints',
417
+ cA: true,
418
+ critical: true
419
+ },
420
+ {
421
+ name: 'keyUsage',
422
+ keyCertSign: true,
423
+ cRLSign: true,
424
+ critical: true
425
+ }
426
+ ]
427
+ },null
428
+ );
429
+
430
+ const cert = new crypto.X509Certificate(pems.cert);
431
+ assert.ok(cert.ca, 'certificate should be a CA');
432
+ });
433
+
434
+ it('should support keyUsage extension', async function () {
435
+ var pems = await generate(
436
+ [{ name: 'commonName', value: 'test.example.com' }],
437
+ {
438
+ extensions: [
439
+ {
440
+ name: 'basicConstraints',
441
+ cA: false
442
+ },
443
+ {
444
+ name: 'keyUsage',
445
+ digitalSignature: true,
446
+ keyEncipherment: true,
447
+ dataEncipherment: true
448
+ }
449
+ ]
450
+ },null
451
+ );
452
+
453
+ const cert = new crypto.X509Certificate(pems.cert);
454
+ // Node.js X509Certificate doesn't expose keyUsage directly,
455
+ // but we can verify the cert is valid and can be used
456
+ assert.ok(cert.publicKey, 'should generate valid cert with keyUsage');
457
+ // Verify by using openssl to check extensions
458
+ const fs = require('fs');
459
+ fs.writeFileSync('/tmp/test-keyusage.crt', pems.cert);
460
+ const { execSync } = require('child_process');
461
+ const output = execSync('openssl x509 -in /tmp/test-keyusage.crt -text -noout').toString();
462
+ assert.include(output, 'Digital Signature', 'should have digitalSignature');
463
+ assert.include(output, 'Key Encipherment', 'should have keyEncipherment');
464
+ });
465
+
466
+ it('should support extKeyUsage extension', async function () {
467
+ var pems = await generate(
468
+ [{ name: 'commonName', value: 'test.example.com' }],
469
+ {
470
+ extensions: [
471
+ {
472
+ name: 'basicConstraints',
473
+ cA: false
474
+ },
475
+ {
476
+ name: 'extKeyUsage',
477
+ serverAuth: true,
478
+ clientAuth: true,
479
+ codeSigning: true
480
+ }
481
+ ]
482
+ },null
483
+ );
484
+
485
+ const cert = new crypto.X509Certificate(pems.cert);
486
+ // Node.js crypto doesn't expose extended key usage directly, but cert should be valid
487
+ assert.ok(cert.publicKey, 'should generate valid cert with extKeyUsage');
488
+ });
489
+
490
+ it('should support subjectAltName with DNS names', async function () {
491
+ var pems = await generate(
492
+ [{ name: 'commonName', value: 'example.com' }],
493
+ {
494
+ extensions: [
495
+ {
496
+ name: 'basicConstraints',
497
+ cA: false
498
+ },
499
+ {
500
+ name: 'subjectAltName',
501
+ altNames: [
502
+ { type: 2, value: 'example.com' },
503
+ { type: 2, value: 'www.example.com' },
504
+ { type: 2, value: '*.example.com' }
505
+ ]
506
+ }
507
+ ]
508
+ },null
509
+ );
510
+
511
+ const cert = new crypto.X509Certificate(pems.cert);
512
+ assert.include(cert.subjectAltName, 'example.com', 'should include example.com');
513
+ assert.include(cert.subjectAltName, 'www.example.com', 'should include www.example.com');
514
+ assert.include(cert.subjectAltName, '*.example.com', 'should include wildcard');
515
+ });
516
+
517
+ it('should support subjectAltName with email and URI', async function () {
518
+ var pems = await generate(
519
+ [{ name: 'commonName', value: 'test.example.com' }],
520
+ {
521
+ extensions: [
522
+ {
523
+ name: 'basicConstraints',
524
+ cA: false
525
+ },
526
+ {
527
+ name: 'subjectAltName',
528
+ altNames: [
529
+ { type: 2, value: 'test.example.com' },
530
+ { type: 1, value: 'admin@example.com' }, // email
531
+ { type: 6, value: 'http://example.com/webid#me' } // URI
532
+ ]
533
+ }
534
+ ]
535
+ },null
536
+ );
537
+
538
+ const cert = new crypto.X509Certificate(pems.cert);
539
+ assert.include(cert.subjectAltName, 'test.example.com', 'should include DNS');
540
+ assert.include(cert.subjectAltName, 'admin@example.com', 'should include email');
541
+ assert.include(cert.subjectAltName, 'http://example.com/webid#me', 'should include URI');
542
+ });
543
+
544
+ it('should use default extensions when extensions option is empty array', async function () {
545
+ var pems = await generate(
546
+ [{ name: 'commonName', value: 'localhost' }],
547
+ {
548
+ extensions: []
549
+ },null
550
+ );
551
+
552
+ const cert = new crypto.X509Certificate(pems.cert);
553
+ // Default behavior includes localhost and 127.0.0.1
554
+ assert.include(cert.subjectAltName, 'localhost', 'should use default SAN');
555
+ assert.include(cert.subjectAltName, '127.0.0.1', 'should include default IP for localhost');
556
+ });
557
+
558
+ it('should use default extensions when extensions option is not provided', async function () {
559
+ var pems = await generate([{ name: 'commonName', value: 'myhost.local' }]);
560
+
561
+ const cert = new crypto.X509Certificate(pems.cert);
562
+ assert.include(cert.subjectAltName, 'myhost.local', 'should use commonName in default SAN');
563
+ });
564
+ });
565
+
566
+ it('should support passphrase for private key encryption', async function () {
567
+ const passphrase = 'my-secret-passphrase';
568
+ var pems = await generate(null, { passphrase: passphrase },null);
569
+
570
+ assert.ok(!!pems.private, 'has a private key');
571
+ assert.include(pems.private, 'ENCRYPTED', 'private key should be encrypted');
572
+
573
+ // Verify the key can be decrypted with the correct passphrase
574
+ const privateKey = crypto.createPrivateKey({
575
+ key: pems.private,
576
+ passphrase: passphrase
577
+ });
578
+ assert.ok(privateKey, 'should be able to decrypt private key with passphrase');
579
+
580
+ // Verify signing works with decrypted key
581
+ const testData = 'Hello, World!';
582
+ const sign = crypto.createSign('SHA256');
583
+ sign.update(testData);
584
+ sign.end();
585
+ const signature = sign.sign({ key: pems.private, passphrase: passphrase });
586
+
587
+ const verify = crypto.createVerify('SHA256');
588
+ verify.update(testData);
589
+ verify.end();
590
+ const isValid = verify.verify(pems.public, signature);
591
+ assert.isTrue(isValid, 'encrypted key should work for signing');
592
+ });
593
+
594
+ it('should fail to decrypt private key with wrong passphrase', async function () {
595
+ const passphrase = 'correct-passphrase';
596
+ var pems = await generate(null, { passphrase: passphrase },null);
597
+
598
+ assert.throws(() => {
599
+ crypto.createPrivateKey({
600
+ key: pems.private,
601
+ passphrase: 'wrong-passphrase'
602
+ });
603
+ });
604
+ });
605
+ });