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