From 11ad744a92374ad71730cbfb7abea71fda0abb74 Mon Sep 17 00:00:00 2001 From: Stefan Budeanu Date: Tue, 10 Nov 2015 16:33:25 -0500 Subject: [PATCH] test: increase crypto strength for FIPS standard Use stronger crypto (larger keys, etc.) for arbitrary tests so they will pass in both FIPS and non-FIPS mode without altering the original intent of the test cases. PR-URL: https://github.com/nodejs/node/pull/3758 Reviewed-By: Shigeki Ohtsu Reviewed-By: James M Snell --- test/parallel/test-crypto-binary-default.js | 2 +- test/parallel/test-crypto-dh-odd-key.js | 19 +++-- test/parallel/test-crypto-dh.js | 69 ++++++++++-------- test/parallel/test-crypto-ecb.js | 4 + test/parallel/test-crypto.js | 2 +- test/parallel/test-dh-padding.js | 81 +++++++++++++++++++-- test/pummel/test-dh-regr.js | 2 +- 7 files changed, 131 insertions(+), 48 deletions(-) diff --git a/test/parallel/test-crypto-binary-default.js b/test/parallel/test-crypto-binary-default.js index bebc91dc8ed0b1..8695632727fa80 100644 --- a/test/parallel/test-crypto-binary-default.js +++ b/test/parallel/test-crypto-binary-default.js @@ -513,7 +513,7 @@ assert.throws(function() { // Test Diffie-Hellman with two parties sharing a secret, // using various encodings as we go along -var dh1 = crypto.createDiffieHellman(256); +var dh1 = crypto.createDiffieHellman(1024); var p1 = dh1.getPrime('buffer'); var dh2 = crypto.createDiffieHellman(p1, 'base64'); var key1 = dh1.generateKeys(); diff --git a/test/parallel/test-crypto-dh-odd-key.js b/test/parallel/test-crypto-dh-odd-key.js index abb4860b238a78..503ba2fe089e3e 100644 --- a/test/parallel/test-crypto-dh-odd-key.js +++ b/test/parallel/test-crypto-dh-odd-key.js @@ -8,9 +8,18 @@ if (!common.hasCrypto) { } var crypto = require('crypto'); -var odd = new Buffer(39); -odd.fill('A'); +function test() { + var odd = new Buffer(39); + odd.fill('A'); -var c = crypto.createDiffieHellman(32); -c.setPrivateKey(odd); -c.generateKeys(); + var c = crypto.createDiffieHellman(32); + c.setPrivateKey(odd); + c.generateKeys(); +} + +// FIPS requires a length of at least 1024 +if (!common.hasFipsCrypto) { + assert.doesNotThrow(function() { test(); }); +} else { + assert.throws(function() { test(); }, /key size too small/); +} diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index dfb912c0a4c9f1..d93c53e3997dae 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -11,7 +11,7 @@ var crypto = require('crypto'); // Test Diffie-Hellman with two parties sharing a secret, // using various encodings as we go along -var dh1 = crypto.createDiffieHellman(256); +var dh1 = crypto.createDiffieHellman(1024); var p1 = dh1.getPrime('buffer'); var dh2 = crypto.createDiffieHellman(p1, 'buffer'); var key1 = dh1.generateKeys(); @@ -82,9 +82,11 @@ assert.equal(aSecret, bSecret); assert.equal(alice.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); assert.equal(bob.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); -// Ensure specific generator (buffer) works as expected. -var modp1 = crypto.createDiffieHellmanGroup('modp1'); -var modp1buf = new Buffer([ +/* Ensure specific generator (buffer) works as expected. + * The values below (modp2/modp2buf) are for a 1024 bits long prime from + * RFC 2412 E.2, see https://tools.ietf.org/html/rfc2412. */ +var modp2 = crypto.createDiffieHellmanGroup('modp2'); +var modp2buf = new Buffer([ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, @@ -93,47 +95,50 @@ var modp1buf = new Buffer([ 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, - 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, + 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, 0xee, 0x38, 0x6b, 0xfb, + 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, + 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]); -var exmodp1 = crypto.createDiffieHellman(modp1buf, new Buffer([2])); -modp1.generateKeys(); -exmodp1.generateKeys(); -var modp1Secret = modp1.computeSecret(exmodp1.getPublicKey()).toString('hex'); -var exmodp1Secret = exmodp1.computeSecret(modp1.getPublicKey()).toString('hex'); -assert.equal(modp1Secret, exmodp1Secret); -assert.equal(modp1.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); -assert.equal(exmodp1.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); +var exmodp2 = crypto.createDiffieHellman(modp2buf, new Buffer([2])); +modp2.generateKeys(); +exmodp2.generateKeys(); +var modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()).toString('hex'); +var exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()).toString('hex'); +assert.equal(modp2Secret, exmodp2Secret); +assert.equal(modp2.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); +assert.equal(exmodp2.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); // Ensure specific generator (string with encoding) works as expected. -var exmodp1_2 = crypto.createDiffieHellman(modp1buf, '02', 'hex'); -exmodp1_2.generateKeys(); -modp1Secret = modp1.computeSecret(exmodp1_2.getPublicKey()).toString('hex'); -var exmodp1_2Secret = exmodp1_2.computeSecret(modp1.getPublicKey()) +var exmodp2_2 = crypto.createDiffieHellman(modp2buf, '02', 'hex'); +exmodp2_2.generateKeys(); +modp2Secret = modp2.computeSecret(exmodp2_2.getPublicKey()).toString('hex'); +var exmodp2_2Secret = exmodp2_2.computeSecret(modp2.getPublicKey()) .toString('hex'); -assert.equal(modp1Secret, exmodp1_2Secret); -assert.equal(exmodp1_2.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); +assert.equal(modp2Secret, exmodp2_2Secret); +assert.equal(exmodp2_2.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); // Ensure specific generator (string without encoding) works as expected. -var exmodp1_3 = crypto.createDiffieHellman(modp1buf, '\x02'); -exmodp1_3.generateKeys(); -modp1Secret = modp1.computeSecret(exmodp1_3.getPublicKey()).toString('hex'); -var exmodp1_3Secret = exmodp1_3.computeSecret(modp1.getPublicKey()) +var exmodp2_3 = crypto.createDiffieHellman(modp2buf, '\x02'); +exmodp2_3.generateKeys(); +modp2Secret = modp2.computeSecret(exmodp2_3.getPublicKey()).toString('hex'); +var exmodp2_3Secret = exmodp2_3.computeSecret(modp2.getPublicKey()) .toString('hex'); -assert.equal(modp1Secret, exmodp1_3Secret); -assert.equal(exmodp1_3.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); +assert.equal(modp2Secret, exmodp2_3Secret); +assert.equal(exmodp2_3.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); // Ensure specific generator (numeric) works as expected. -var exmodp1_4 = crypto.createDiffieHellman(modp1buf, 2); -exmodp1_4.generateKeys(); -modp1Secret = modp1.computeSecret(exmodp1_4.getPublicKey()).toString('hex'); -var exmodp1_4Secret = exmodp1_4.computeSecret(modp1.getPublicKey()) +var exmodp2_4 = crypto.createDiffieHellman(modp2buf, 2); +exmodp2_4.generateKeys(); +modp2Secret = modp2.computeSecret(exmodp2_4.getPublicKey()).toString('hex'); +var exmodp2_4Secret = exmodp2_4.computeSecret(modp2.getPublicKey()) .toString('hex'); -assert.equal(modp1Secret, exmodp1_4Secret); -assert.equal(exmodp1_4.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); +assert.equal(modp2Secret, exmodp2_4Secret); +assert.equal(exmodp2_4.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); var p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' + diff --git a/test/parallel/test-crypto-ecb.js b/test/parallel/test-crypto-ecb.js index 920b18a47f8ff1..d47ec8a8091f38 100644 --- a/test/parallel/test-crypto-ecb.js +++ b/test/parallel/test-crypto-ecb.js @@ -6,6 +6,10 @@ if (!common.hasCrypto) { console.log('1..0 # Skipped: missing crypto'); return; } +if (common.hasFipsCrypto) { + console.log('1..0 # Skipped: BF-ECB is not FIPS 140-2 compatible'); + return; +} var crypto = require('crypto'); crypto.DEFAULT_ENCODING = 'buffer'; diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 57191b24ae351a..e5fe8db58c132e 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -122,7 +122,7 @@ assert.throws(function() { '' ].join('\n'); crypto.createSign('RSA-SHA256').update('test').sign(priv); -}, /RSA_sign:digest too big for rsa key/); +}, /digest too big for rsa key/); assert.throws(function() { // The correct header inside `test_bad_rsa_privkey.pem` should have been diff --git a/test/parallel/test-dh-padding.js b/test/parallel/test-dh-padding.js index ef6ea0fd4d7cfd..cdb1fc75f94215 100644 --- a/test/parallel/test-dh-padding.js +++ b/test/parallel/test-dh-padding.js @@ -9,18 +9,83 @@ try { return; } -var prime = 'c51f7bf8f0e1cf899243cdf408b1bc7c09c010e33ef7f3fbe5bd5feaf906113b'; -var apub = '6fe9f37037d8d017f908378c1ee04fe60e1cd3668bfc5075fac55c2f7153dd84'; -var bpub = '31d83e167fdf956c9dae6b980140577a9f8868acbfcbdc19113e58bfb9223abc'; -var apriv = '4fbfd4661f9181bbf574537b1a78adf473e8e771eef13c605e963c0f3094b697'; -var secret = '25616eed33f1af7975bbd0a8071d98a014f538b243bef90d76c08e81a0b3c500'; +/* This test verifies padding with leading zeroes for shared + * secrets that are strictly smaller than the modulus (prime). + * See: + * RFC 4346: https://www.ietf.org/rfc/rfc4346.txt + * https://github.com/nodejs/node-v0.x-archive/issues/7906 + * https://github.com/nodejs/node-v0.x-archive/issues/5239 + * + * In FIPS mode OPENSSL_DH_FIPS_MIN_MODULUS_BITS = 1024, meaning we need + * a FIPS-friendly >= 1024 bit prime, we can use MODP 14 from RFC 3526: + * https://www.ietf.org/rfc/rfc3526.txt + * + * We can generate appropriate values with this code: + * + * crypto = require('crypto'); + * + * for (;;) { + * var a = crypto.getDiffieHellman('modp14'), + * var b = crypto.getDiffieHellman('modp14'); + * + * a.generateKeys(); + * b.generateKeys(); + * + * var aSecret = a.computeSecret(b.getPublicKey()).toString('hex'); + * console.log("A public: " + a.getPublicKey().toString('hex')); + * console.log("A private: " + a.getPrivateKey().toString('hex')); + * console.log("B public: " + b.getPublicKey().toString('hex')); + * console.log("B private: " + b.getPrivateKey().toString('hex')); + * console.log("A secret: " + aSecret); + * console.log('-------------------------------------------------'); + * if(aSecret.substring(0,2) === "00") { + * console.log("found short key!"); + * return; + * } + * } + */ -var p = crypto.createDiffieHellman(prime, 'hex'); +var apub = +'5484455905d3eff34c70980e871f27f05448e66f5a6efbb97cbcba4e927196c2bd9ea272cded91\ +10a4977afa8d9b16c9139a444ed2d954a794650e5d7cb525204f385e1af81530518563822ecd0f9\ +524a958d02b3c269e79d6d69850f0968ad567a4404fbb0b19efc8bc73e267b6136b88cafb33299f\ +f7c7cace3ffab1a88c2c9ee841f88b4c3679b4efc465f5c93cca11d487be57373e4c5926f634c4e\ +efee6721d01db91cd66321615b2522f96368dbc818875d422140d0edf30bdb97d9721feddcb9ff6\ +453741a4f687ee46fc54bf1198801f1210ac789879a5ee123f79e2d2ce1209df2445d32166bc9e4\ +8f89e944ec9c3b2e16c8066cd8eebd4e33eb941'; +var bpub = +'3fca64510e36bc7da8a3a901c7b74c2eabfa25deaf7cbe1d0c50235866136ad677317279e1fb0\ +06e9c0a07f63e14a3363c8e016fbbde2b2c7e79fed1cc3e08e95f7459f547a8cd0523ee9dc744d\ +e5a956d92b937db4448917e1f6829437f05e408ee7aea70c0362b37370c7c75d14449d8b2d2133\ +04ac972302d349975e2265ca7103cfebd019d9e91234d638611abd049014f7abf706c1c5da6c88\ +788a1fdc6cdf17f5fffaf024ce8711a2ebde0b52e9f1cb56224483826d6e5ac6ecfaae07b75d20\ +6e8ac97f5be1a5b68f20382f2a7dac189cf169325c4cf845b26a0cd616c31fec905c5d9035e5f7\ +8e9880c812374ac0f3ca3d365f06e4be526b5affd4b79'; +var apriv = +'62411e34704637d99c6c958a7db32ac22fcafafbe1c33d2cfdb76e12ded41f38fc16b792b9041\ +2e4c82755a3815ba52f780f0ee296ad46e348fc4d1dcd6b64f4eea1b231b2b7d95c5b1c2e26d34\ +83520558b9860a6eb668f01422a54e6604aa7702b4e67511397ef3ecb912bff1a83899c5a5bfb2\ +0ee29249a91b8a698e62486f7009a0e9eaebda69d77ecfa2ca6ba2db6c8aa81759c8c90c675979\ +08c3b3e6fc60668f7be81cce6784482af228dd7f489005253a165e292802cfd0399924f6c56827\ +7012f68255207722355634290acc7fddeefbba75650a85ece95b6a12de67eac016ba78960108dd\ +5dbadfaa43cc9fed515a1f307b7d90ae0623bc7b8cefb'; +var secret = +'00c37b1e06a436d6717816a40e6d72907a6f255638b93032267dcb9a5f0b4a9aa0236f3dce63b\ +1c418c60978a00acd1617dfeecf1661d8a3fafb4d0d8824386750f4853313400e7e4afd22847e4\ +fa56bc9713872021265111906673b38db83d10cbfa1dea3b6b4c97c8655f4ae82125281af7f234\ +8916a15c6f95649367d169d587697480df4d10b381479e86d5518b520d9d8fb764084eab518224\ +dc8fe984ddaf532fc1531ce43155fa0ab32532bf1ece5356b8a3447b5267798a904f16f3f4e635\ +597adc0179d011132dcffc0bbcb0dd2c8700872f8663ec7ddd897c659cc2efebccc73f38f0ec96\ +8612314311231f905f91c63a1aea52e0b60cead8b57df'; + +/* FIPS-friendly 2048 bit prime */ +var p = crypto.createDiffieHellman( + crypto.getDiffieHellman('modp14').getPrime()); p.setPublicKey(apub, 'hex'); p.setPrivateKey(apriv, 'hex'); assert.equal( - p.computeSecret(bpub, 'hex', 'hex'), - '0025616eed33f1af7975bbd0a8071d98a014f538b243bef90d76c08e81a0b3c5' + p.computeSecret(bpub, 'hex', 'hex').toString('hex'), + secret ); diff --git a/test/pummel/test-dh-regr.js b/test/pummel/test-dh-regr.js index 1b4f0090e3847e..6fdd416b183669 100644 --- a/test/pummel/test-dh-regr.js +++ b/test/pummel/test-dh-regr.js @@ -8,7 +8,7 @@ if (!common.hasCrypto) { } var crypto = require('crypto'); -var p = crypto.createDiffieHellman(256).getPrime(); +var p = crypto.createDiffieHellman(1024).getPrime(); for (var i = 0; i < 2000; i++) { var a = crypto.createDiffieHellman(p),