• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3if (!common.hasCrypto)
4  common.skip('missing crypto');
5
6const assert = require('assert');
7const fs = require('fs');
8const path = require('path');
9const exec = require('child_process').exec;
10const crypto = require('crypto');
11const fixtures = require('../common/fixtures');
12
13// Test certificates
14const certPem = fixtures.readKey('rsa_cert.crt');
15const keyPem = fixtures.readKey('rsa_private.pem');
16const keySize = 2048;
17
18{
19  const Sign = crypto.Sign;
20  const instance = Sign('SHA256');
21  assert(instance instanceof Sign, 'Sign is expected to return a new ' +
22                                   'instance when called without `new`');
23}
24
25{
26  const Verify = crypto.Verify;
27  const instance = Verify('SHA256');
28  assert(instance instanceof Verify, 'Verify is expected to return a new ' +
29                                     'instance when called without `new`');
30}
31
32// Test handling of exceptional conditions
33{
34  const library = {
35    configurable: true,
36    set() {
37      throw new Error('bye, bye, library');
38    }
39  };
40  Object.defineProperty(Object.prototype, 'library', library);
41
42  assert.throws(() => {
43    crypto.createSign('sha1').sign(
44      `-----BEGIN RSA PRIVATE KEY-----
45      AAAAAAAAAAAA
46      -----END RSA PRIVATE KEY-----`);
47  }, { message: 'bye, bye, library' });
48
49  delete Object.prototype.library;
50
51  const errorStack = {
52    configurable: true,
53    set() {
54      throw new Error('bye, bye, error stack');
55    }
56  };
57  Object.defineProperty(Object.prototype, 'opensslErrorStack', errorStack);
58
59  assert.throws(() => {
60    crypto.createSign('SHA1')
61      .update('Test123')
62      .sign({
63        key: keyPem,
64        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
65      });
66  }, { message: common.hasOpenSSL3 ?
67    'error:1C8000A5:Provider routines::illegal or unsupported padding mode' :
68    'bye, bye, error stack' });
69
70  delete Object.prototype.opensslErrorStack;
71}
72
73assert.throws(
74  () => crypto.createVerify('SHA256').verify({
75    key: certPem,
76    padding: null,
77  }, ''),
78  {
79    code: 'ERR_INVALID_ARG_VALUE',
80    name: 'TypeError',
81    message: "The property 'options.padding' is invalid. Received null",
82  });
83
84assert.throws(
85  () => crypto.createVerify('SHA256').verify({
86    key: certPem,
87    saltLength: null,
88  }, ''),
89  {
90    code: 'ERR_INVALID_ARG_VALUE',
91    name: 'TypeError',
92    message: "The property 'options.saltLength' is invalid. Received null",
93  });
94
95// Test signing and verifying
96{
97  const s1 = crypto.createSign('SHA1')
98                   .update('Test123')
99                   .sign(keyPem, 'base64');
100  let s1stream = crypto.createSign('SHA1');
101  s1stream.end('Test123');
102  s1stream = s1stream.sign(keyPem, 'base64');
103  assert.strictEqual(s1, s1stream, `${s1} should equal ${s1stream}`);
104
105  const verified = crypto.createVerify('SHA1')
106                         .update('Test')
107                         .update('123')
108                         .verify(certPem, s1, 'base64');
109  assert.strictEqual(verified, true);
110}
111
112{
113  const s2 = crypto.createSign('SHA256')
114                   .update('Test123')
115                   .sign(keyPem, 'latin1');
116  let s2stream = crypto.createSign('SHA256');
117  s2stream.end('Test123');
118  s2stream = s2stream.sign(keyPem, 'latin1');
119  assert.strictEqual(s2, s2stream, `${s2} should equal ${s2stream}`);
120
121  let verified = crypto.createVerify('SHA256')
122                       .update('Test')
123                       .update('123')
124                       .verify(certPem, s2, 'latin1');
125  assert.strictEqual(verified, true);
126
127  const verStream = crypto.createVerify('SHA256');
128  verStream.write('Tes');
129  verStream.write('t12');
130  verStream.end('3');
131  verified = verStream.verify(certPem, s2, 'latin1');
132  assert.strictEqual(verified, true);
133}
134
135{
136  const s3 = crypto.createSign('SHA1')
137                   .update('Test123')
138                   .sign(keyPem, 'buffer');
139  let verified = crypto.createVerify('SHA1')
140                       .update('Test')
141                       .update('123')
142                       .verify(certPem, s3);
143  assert.strictEqual(verified, true);
144
145  const verStream = crypto.createVerify('SHA1');
146  verStream.write('Tes');
147  verStream.write('t12');
148  verStream.end('3');
149  verified = verStream.verify(certPem, s3);
150  assert.strictEqual(verified, true);
151}
152
153// Special tests for RSA_PKCS1_PSS_PADDING
154{
155  function testPSS(algo, hLen) {
156    // Maximum permissible salt length
157    const max = keySize / 8 - hLen - 2;
158
159    function getEffectiveSaltLength(saltLength) {
160      switch (saltLength) {
161        case crypto.constants.RSA_PSS_SALTLEN_DIGEST:
162          return hLen;
163        case crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN:
164          return max;
165        default:
166          return saltLength;
167      }
168    }
169
170    const signSaltLengths = [
171      crypto.constants.RSA_PSS_SALTLEN_DIGEST,
172      getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_DIGEST),
173      crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN,
174      getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN),
175      0, 16, 32, 64, 128,
176    ];
177
178    const verifySaltLengths = [
179      crypto.constants.RSA_PSS_SALTLEN_DIGEST,
180      getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_DIGEST),
181      getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN),
182      0, 16, 32, 64, 128,
183    ];
184    const errMessage = /^Error:.*data too large for key size$/;
185
186    const data = Buffer.from('Test123');
187
188    signSaltLengths.forEach((signSaltLength) => {
189      if (signSaltLength > max) {
190        // If the salt length is too big, an Error should be thrown
191        assert.throws(() => {
192          crypto.createSign(algo)
193            .update(data)
194            .sign({
195              key: keyPem,
196              padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
197              saltLength: signSaltLength
198            });
199        }, errMessage);
200        assert.throws(() => {
201          crypto.sign(algo, data, {
202            key: keyPem,
203            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
204            saltLength: signSaltLength
205          });
206        }, errMessage);
207      } else {
208        // Otherwise, a valid signature should be generated
209        const s4 = crypto.createSign(algo)
210                         .update(data)
211                         .sign({
212                           key: keyPem,
213                           padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
214                           saltLength: signSaltLength
215                         });
216        const s4_2 = crypto.sign(algo, data, {
217          key: keyPem,
218          padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
219          saltLength: signSaltLength
220        });
221
222        [s4, s4_2].forEach((sig) => {
223          let verified;
224          verifySaltLengths.forEach((verifySaltLength) => {
225            // Verification should succeed if and only if the salt length is
226            // correct
227            verified = crypto.createVerify(algo)
228                             .update(data)
229                             .verify({
230                               key: certPem,
231                               padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
232                               saltLength: verifySaltLength
233                             }, sig);
234            assert.strictEqual(verified, crypto.verify(algo, data, {
235              key: certPem,
236              padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
237              saltLength: verifySaltLength
238            }, sig));
239            const saltLengthCorrect = getEffectiveSaltLength(signSaltLength) ===
240                                      getEffectiveSaltLength(verifySaltLength);
241            assert.strictEqual(verified, saltLengthCorrect);
242          });
243
244          // Verification using RSA_PSS_SALTLEN_AUTO should always work
245          verified = crypto.createVerify(algo)
246                           .update(data)
247                           .verify({
248                             key: certPem,
249                             padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
250                             saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO
251                           }, sig);
252          assert.strictEqual(verified, true);
253          assert.strictEqual(verified, crypto.verify(algo, data, {
254            key: certPem,
255            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
256            saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO
257          }, sig));
258
259          // Verifying an incorrect message should never work
260          const wrongData = Buffer.from('Test1234');
261          verified = crypto.createVerify(algo)
262                           .update(wrongData)
263                           .verify({
264                             key: certPem,
265                             padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
266                             saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO
267                           }, sig);
268          assert.strictEqual(verified, false);
269          assert.strictEqual(verified, crypto.verify(algo, wrongData, {
270            key: certPem,
271            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
272            saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO
273          }, sig));
274        });
275      }
276    });
277  }
278
279  testPSS('SHA1', 20);
280  testPSS('SHA256', 32);
281}
282
283// Test vectors for RSA_PKCS1_PSS_PADDING provided by the RSA Laboratories:
284// https://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-rsa-cryptography-standard.htm
285{
286  // We only test verification as we cannot specify explicit salts when signing
287  function testVerify(cert, vector) {
288    const verified = crypto.createVerify('SHA1')
289                          .update(Buffer.from(vector.message, 'hex'))
290                          .verify({
291                            key: cert,
292                            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
293                            saltLength: vector.salt.length / 2
294                          }, vector.signature, 'hex');
295    assert.strictEqual(verified, true);
296  }
297
298  const examples = JSON.parse(fixtures.readSync('pss-vectors.json', 'utf8'));
299
300  for (const key in examples) {
301    const example = examples[key];
302    const publicKey = example.publicKey.join('\n');
303    example.tests.forEach((test) => testVerify(publicKey, test));
304  }
305}
306
307// Test exceptions for invalid `padding` and `saltLength` values
308{
309  [null, NaN, 'boom', {}, [], true, false]
310    .forEach((invalidValue) => {
311      assert.throws(() => {
312        crypto.createSign('SHA256')
313          .update('Test123')
314          .sign({
315            key: keyPem,
316            padding: invalidValue
317          });
318      }, {
319        code: 'ERR_INVALID_ARG_VALUE',
320        name: 'TypeError'
321      });
322
323      assert.throws(() => {
324        crypto.createSign('SHA256')
325          .update('Test123')
326          .sign({
327            key: keyPem,
328            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
329            saltLength: invalidValue
330          });
331      }, {
332        code: 'ERR_INVALID_ARG_VALUE',
333        name: 'TypeError'
334      });
335    });
336
337  assert.throws(() => {
338    crypto.createSign('SHA1')
339      .update('Test123')
340      .sign({
341        key: keyPem,
342        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
343      });
344  }, common.hasOpenSSL3 ? {
345    code: 'ERR_OSSL_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE',
346    message: /illegal or unsupported padding mode/,
347  } : {
348    code: 'ERR_OSSL_RSA_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE',
349    message: /illegal or unsupported padding mode/,
350    opensslErrorStack: [
351      'error:06089093:digital envelope routines:EVP_PKEY_CTX_ctrl:' +
352      'command not supported',
353    ],
354  });
355}
356
357// Test throws exception when key options is null
358{
359  assert.throws(() => {
360    crypto.createSign('SHA1').update('Test123').sign(null, 'base64');
361  }, {
362    code: 'ERR_CRYPTO_SIGN_KEY_REQUIRED',
363    name: 'Error'
364  });
365}
366
367{
368  const sign = crypto.createSign('SHA1');
369  const verify = crypto.createVerify('SHA1');
370
371  [1, [], {}, undefined, null, true, Infinity].forEach((input) => {
372    const errObj = {
373      code: 'ERR_INVALID_ARG_TYPE',
374      name: 'TypeError',
375      message: 'The "algorithm" argument must be of type string.' +
376               `${common.invalidArgTypeHelper(input)}`
377    };
378    assert.throws(() => crypto.createSign(input), errObj);
379    assert.throws(() => crypto.createVerify(input), errObj);
380
381    errObj.message = 'The "data" argument must be of type string or an ' +
382                     'instance of Buffer, TypedArray, or DataView.' +
383                     common.invalidArgTypeHelper(input);
384    assert.throws(() => sign.update(input), errObj);
385    assert.throws(() => verify.update(input), errObj);
386    assert.throws(() => sign._write(input, 'utf8', () => {}), errObj);
387    assert.throws(() => verify._write(input, 'utf8', () => {}), errObj);
388  });
389
390  [
391    Uint8Array, Uint16Array, Uint32Array, Float32Array, Float64Array,
392  ].forEach((clazz) => {
393    // These should all just work
394    sign.update(new clazz());
395    verify.update(new clazz());
396  });
397
398  [1, {}, [], Infinity].forEach((input) => {
399    const errObj = {
400      code: 'ERR_INVALID_ARG_TYPE',
401      name: 'TypeError',
402    };
403    assert.throws(() => sign.sign(input), errObj);
404    assert.throws(() => verify.verify(input), errObj);
405    assert.throws(() => verify.verify('test', input), errObj);
406  });
407}
408
409{
410  assert.throws(
411    () => crypto.createSign('sha8'),
412    /Invalid digest/);
413  assert.throws(
414    () => crypto.sign('sha8', Buffer.alloc(1), keyPem),
415    /Invalid digest/);
416}
417
418[
419  { private: fixtures.readKey('ed25519_private.pem', 'ascii'),
420    public: fixtures.readKey('ed25519_public.pem', 'ascii'),
421    algo: null,
422    sigLen: 64 },
423  { private: fixtures.readKey('ed448_private.pem', 'ascii'),
424    public: fixtures.readKey('ed448_public.pem', 'ascii'),
425    algo: null,
426    sigLen: 114 },
427  { private: fixtures.readKey('rsa_private_2048.pem', 'ascii'),
428    public: fixtures.readKey('rsa_public_2048.pem', 'ascii'),
429    algo: 'sha1',
430    sigLen: 256 },
431].forEach((pair) => {
432  const algo = pair.algo;
433
434  {
435    const data = Buffer.from('Hello world');
436    const sig = crypto.sign(algo, data, pair.private);
437    assert.strictEqual(sig.length, pair.sigLen);
438
439    assert.strictEqual(crypto.verify(algo, data, pair.private, sig),
440                       true);
441    assert.strictEqual(crypto.verify(algo, data, pair.public, sig),
442                       true);
443  }
444
445  {
446    const data = Buffer.from('Hello world');
447    const privKeyObj = crypto.createPrivateKey(pair.private);
448    const pubKeyObj = crypto.createPublicKey(pair.public);
449
450    const sig = crypto.sign(algo, data, privKeyObj);
451    assert.strictEqual(sig.length, pair.sigLen);
452
453    assert.strictEqual(crypto.verify(algo, data, privKeyObj, sig), true);
454    assert.strictEqual(crypto.verify(algo, data, pubKeyObj, sig), true);
455  }
456
457  {
458    const data = Buffer.from('Hello world');
459    const otherData = Buffer.from('Goodbye world');
460    const otherSig = crypto.sign(algo, otherData, pair.private);
461    assert.strictEqual(crypto.verify(algo, data, pair.private, otherSig),
462                       false);
463  }
464
465  [
466    Uint8Array, Uint16Array, Uint32Array, Float32Array, Float64Array,
467  ].forEach((clazz) => {
468    const data = new clazz();
469    const sig = crypto.sign(algo, data, pair.private);
470    assert.strictEqual(crypto.verify(algo, data, pair.private, sig),
471                       true);
472  });
473});
474
475[1, {}, [], true, Infinity].forEach((input) => {
476  const data = Buffer.alloc(1);
477  const sig = Buffer.alloc(1);
478  const errObj = {
479    code: 'ERR_INVALID_ARG_TYPE',
480    name: 'TypeError',
481  };
482
483  assert.throws(() => crypto.sign(null, input, 'asdf'), errObj);
484  assert.throws(() => crypto.verify(null, input, 'asdf', sig), errObj);
485
486  assert.throws(() => crypto.sign(null, data, input), errObj);
487  assert.throws(() => crypto.verify(null, data, input, sig), errObj);
488
489  errObj.message = 'The "signature" argument must be an instance of ' +
490                   'Buffer, TypedArray, or DataView.' +
491                   common.invalidArgTypeHelper(input);
492  assert.throws(() => crypto.verify(null, data, 'test', input), errObj);
493});
494
495{
496  const data = Buffer.from('Hello world');
497  const keys = [['ec-key.pem', 64], ['dsa_private_1025.pem', 40]];
498
499  for (const [file, length] of keys) {
500    const privKey = fixtures.readKey(file);
501    [
502      crypto.createSign('sha1').update(data).sign(privKey),
503      crypto.sign('sha1', data, privKey),
504      crypto.sign('sha1', data, { key: privKey, dsaEncoding: 'der' }),
505    ].forEach((sig) => {
506      // Signature length variability due to DER encoding
507      assert(sig.length >= length + 4 && sig.length <= length + 8);
508
509      assert.strictEqual(
510        crypto.createVerify('sha1').update(data).verify(privKey, sig),
511        true
512      );
513      assert.strictEqual(crypto.verify('sha1', data, privKey, sig), true);
514    });
515
516    // Test (EC)DSA signature conversion.
517    const opts = { key: privKey, dsaEncoding: 'ieee-p1363' };
518    let sig = crypto.sign('sha1', data, opts);
519    // Unlike DER signatures, IEEE P1363 signatures have a predictable length.
520    assert.strictEqual(sig.length, length);
521    assert.strictEqual(crypto.verify('sha1', data, opts, sig), true);
522    assert.strictEqual(crypto.createVerify('sha1')
523                             .update(data)
524                             .verify(opts, sig), true);
525
526    // Test invalid signature lengths.
527    for (const i of [-2, -1, 1, 2, 4, 8]) {
528      sig = crypto.randomBytes(length + i);
529      let result;
530      try {
531        result = crypto.verify('sha1', data, opts, sig);
532      } catch (err) {
533        assert.match(err.message, /asn1 encoding/);
534        assert.strictEqual(err.library, 'asn1 encoding routines');
535        continue;
536      }
537      assert.strictEqual(result, false);
538    }
539  }
540
541  // Test verifying externally signed messages.
542  const extSig = Buffer.from('494c18ab5c8a62a72aea5041966902bcfa229821af2bf65' +
543                             '0b5b4870d1fe6aebeaed9460c62210693b5b0a300033823' +
544                             '33d9529c8abd8c5948940af944828be16c', 'hex');
545  for (const ok of [true, false]) {
546    assert.strictEqual(
547      crypto.verify('sha256', data, {
548        key: fixtures.readKey('ec-key.pem'),
549        dsaEncoding: 'ieee-p1363'
550      }, extSig),
551      ok
552    );
553
554    assert.strictEqual(
555      crypto.createVerify('sha256').update(data).verify({
556        key: fixtures.readKey('ec-key.pem'),
557        dsaEncoding: 'ieee-p1363'
558      }, extSig),
559      ok
560    );
561
562    extSig[Math.floor(Math.random() * extSig.length)] ^= 1;
563  }
564
565  // Non-(EC)DSA keys should ignore the option.
566  const sig = crypto.sign('sha1', data, {
567    key: keyPem,
568    dsaEncoding: 'ieee-p1363'
569  });
570  assert.strictEqual(crypto.verify('sha1', data, certPem, sig), true);
571  assert.strictEqual(
572    crypto.verify('sha1', data, {
573      key: certPem,
574      dsaEncoding: 'ieee-p1363'
575    }, sig),
576    true
577  );
578  assert.strictEqual(
579    crypto.verify('sha1', data, {
580      key: certPem,
581      dsaEncoding: 'der'
582    }, sig),
583    true
584  );
585
586  for (const dsaEncoding of ['foo', null, {}, 5, true, NaN]) {
587    assert.throws(() => {
588      crypto.sign('sha1', data, {
589        key: certPem,
590        dsaEncoding
591      });
592    }, {
593      code: 'ERR_INVALID_ARG_VALUE'
594    });
595  }
596}
597
598
599// RSA-PSS Sign test by verifying with 'openssl dgst -verify'
600// Note: this particular test *must* be the last in this file as it will exit
601// early if no openssl binary is found
602{
603  if (!common.opensslCli)
604    common.skip('node compiled without OpenSSL CLI.');
605
606  const pubfile = fixtures.path('keys', 'rsa_public_2048.pem');
607  const privkey = fixtures.readKey('rsa_private_2048.pem');
608
609  const msg = 'Test123';
610  const s5 = crypto.createSign('SHA256')
611    .update(msg)
612    .sign({
613      key: privkey,
614      padding: crypto.constants.RSA_PKCS1_PSS_PADDING
615    });
616
617  const tmpdir = require('../common/tmpdir');
618  tmpdir.refresh();
619
620  const sigfile = path.join(tmpdir.path, 's5.sig');
621  fs.writeFileSync(sigfile, s5);
622  const msgfile = path.join(tmpdir.path, 's5.msg');
623  fs.writeFileSync(msgfile, msg);
624
625  const cmd =
626    `"${common.opensslCli}" dgst -sha256 -verify "${pubfile}" -signature "${
627      sigfile}" -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-2 "${
628      msgfile}"`;
629
630  exec(cmd, common.mustCall((err, stdout, stderr) => {
631    assert(stdout.includes('Verified OK'));
632  }));
633}
634
635{
636  // Test RSA-PSS.
637  {
638    // This key pair does not restrict the message digest algorithm or salt
639    // length.
640    const publicPem = fixtures.readKey('rsa_pss_public_2048.pem');
641    const privatePem = fixtures.readKey('rsa_pss_private_2048.pem');
642
643    const publicKey = crypto.createPublicKey(publicPem);
644    const privateKey = crypto.createPrivateKey(privatePem);
645
646    for (const key of [privatePem, privateKey]) {
647      // Any algorithm should work.
648      for (const algo of ['sha1', 'sha256']) {
649        // Any salt length should work.
650        for (const saltLength of [undefined, 8, 10, 12, 16, 18, 20]) {
651          const signature = crypto.sign(algo, 'foo', { key, saltLength });
652
653          for (const pkey of [key, publicKey, publicPem]) {
654            const okay = crypto.verify(
655              algo,
656              'foo',
657              { key: pkey, saltLength },
658              signature
659            );
660
661            assert.ok(okay);
662          }
663        }
664      }
665    }
666  }
667
668  {
669    // This key pair enforces sha256 as the message digest and the MGF1
670    // message digest and a salt length of at least 16 bytes.
671    const publicPem =
672      fixtures.readKey('rsa_pss_public_2048_sha256_sha256_16.pem');
673    const privatePem =
674      fixtures.readKey('rsa_pss_private_2048_sha256_sha256_16.pem');
675
676    const publicKey = crypto.createPublicKey(publicPem);
677    const privateKey = crypto.createPrivateKey(privatePem);
678
679    for (const key of [privatePem, privateKey]) {
680      // Signing with anything other than sha256 should fail.
681      assert.throws(() => {
682        crypto.sign('sha1', 'foo', key);
683      }, /digest not allowed/);
684
685      // Signing with salt lengths less than 16 bytes should fail.
686      for (const saltLength of [8, 10, 12]) {
687        assert.throws(() => {
688          crypto.sign('sha256', 'foo', { key, saltLength });
689        }, /pss saltlen too small/);
690      }
691
692      // Signing with sha256 and appropriate salt lengths should work.
693      for (const saltLength of [undefined, 16, 18, 20]) {
694        const signature = crypto.sign('sha256', 'foo', { key, saltLength });
695
696        for (const pkey of [key, publicKey, publicPem]) {
697          const okay = crypto.verify(
698            'sha256',
699            'foo',
700            { key: pkey, saltLength },
701            signature
702          );
703
704          assert.ok(okay);
705        }
706      }
707    }
708  }
709
710  {
711    // This key enforces sha512 as the message digest and sha256 as the MGF1
712    // message digest.
713    const publicPem =
714      fixtures.readKey('rsa_pss_public_2048_sha512_sha256_20.pem');
715    const privatePem =
716      fixtures.readKey('rsa_pss_private_2048_sha512_sha256_20.pem');
717
718    const publicKey = crypto.createPublicKey(publicPem);
719    const privateKey = crypto.createPrivateKey(privatePem);
720
721    // Node.js usually uses the same hash function for the message and for MGF1.
722    // However, when a different MGF1 message digest algorithm has been
723    // specified as part of the key, it should automatically switch to that.
724    // This behavior is required by sections 3.1 and 3.3 of RFC4055.
725    for (const key of [privatePem, privateKey]) {
726      // sha256 matches the MGF1 hash function and should be used internally,
727      // but it should not be permitted as the main message digest algorithm.
728      for (const algo of ['sha1', 'sha256']) {
729        assert.throws(() => {
730          crypto.sign(algo, 'foo', key);
731        }, /digest not allowed/);
732      }
733
734      // sha512 should produce a valid signature.
735      const signature = crypto.sign('sha512', 'foo', key);
736
737      for (const pkey of [key, publicKey, publicPem]) {
738        const okay = crypto.verify('sha512', 'foo', pkey, signature);
739
740        assert.ok(okay);
741      }
742    }
743  }
744}
745
746// The sign function should not swallow OpenSSL errors.
747// Regression test for https://github.com/nodejs/node/issues/40794.
748{
749  assert.throws(() => {
750    const { privateKey } = crypto.generateKeyPairSync('rsa', {
751      modulusLength: 512
752    });
753    crypto.sign('sha512', 'message', privateKey);
754  }, {
755    code: 'ERR_OSSL_RSA_DIGEST_TOO_BIG_FOR_RSA_KEY',
756    message: /digest too big for rsa key/
757  });
758}
759
760{
761  // This should not cause a crash: https://github.com/nodejs/node/issues/44471
762  for (const key of ['', 'foo', null, undefined, true, Boolean]) {
763    assert.throws(() => {
764      crypto.verify('sha256', 'foo', { key, format: 'jwk' }, Buffer.alloc(0));
765    }, { code: 'ERR_INVALID_ARG_TYPE', message: /The "key\.key" property must be of type object/ });
766    assert.throws(() => {
767      crypto.createVerify('sha256').verify({ key, format: 'jwk' }, Buffer.alloc(0));
768    }, { code: 'ERR_INVALID_ARG_TYPE', message: /The "key\.key" property must be of type object/ });
769    assert.throws(() => {
770      crypto.sign('sha256', 'foo', { key, format: 'jwk' });
771    }, { code: 'ERR_INVALID_ARG_TYPE', message: /The "key\.key" property must be of type object/ });
772    assert.throws(() => {
773      crypto.createSign('sha256').sign({ key, format: 'jwk' });
774    }, { code: 'ERR_INVALID_ARG_TYPE', message: /The "key\.key" property must be of type object/ });
775  }
776}
777