Skip to content

Commit

Permalink
crypto: disable crypto.createCipher in FIPS mode
Browse files Browse the repository at this point in the history
FIPS 140-2 disallows use of MD5, which is used to derive the
initialization vector and key for createCipher(). Modify
all tests to expect exceptions in FIPS mode when disallowed
API is used, or to avoid testing such API in FIPS Mode.

PR-URL: #3754
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Shigeki Ohtsu <ohtsu@iij.ad.jp>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
stefanmb authored and rvagg committed Dec 5, 2015
1 parent 788541b commit def681a
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 88 deletions.
5 changes: 5 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3054,6 +3054,11 @@ void CipherBase::Init(const char* cipher_type,
int key_buf_len) {
HandleScope scope(env()->isolate());

#ifdef NODE_FIPS_MODE
return env()->ThrowError(
"crypto.createCipher() is not supported in FIPS mode.");
#endif // NODE_FIPS_MODE

CHECK_EQ(cipher_, nullptr);
cipher_ = EVP_get_cipherbyname(cipher_type);
if (cipher_ == nullptr) {
Expand Down
52 changes: 32 additions & 20 deletions test/parallel/test-crypto-authenticated.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,32 +93,44 @@ for (var i in TEST_CASES) {

(function() {
if (!test.password) return;
var encrypt = crypto.createCipher(test.algo, test.password);
if (test.aad)
encrypt.setAAD(new Buffer(test.aad, 'hex'));
var hex = encrypt.update(test.plain, 'ascii', 'hex');
hex += encrypt.final('hex');
var auth_tag = encrypt.getAuthTag();
// only test basic encryption run if output is marked as tampered.
if (!test.tampered) {
assert.equal(hex.toUpperCase(), test.ct);
assert.equal(auth_tag.toString('hex').toUpperCase(), test.tag);
if (common.hasFipsCrypto) {
assert.throws(function()
{ crypto.createCipher(test.algo, test.password); },
/not supported in FIPS mode/);
} else {
var encrypt = crypto.createCipher(test.algo, test.password);
if (test.aad)
encrypt.setAAD(new Buffer(test.aad, 'hex'));
var hex = encrypt.update(test.plain, 'ascii', 'hex');
hex += encrypt.final('hex');
var auth_tag = encrypt.getAuthTag();
// only test basic encryption run if output is marked as tampered.
if (!test.tampered) {
assert.equal(hex.toUpperCase(), test.ct);
assert.equal(auth_tag.toString('hex').toUpperCase(), test.tag);
}
}
})();

(function() {
if (!test.password) return;
var decrypt = crypto.createDecipher(test.algo, test.password);
decrypt.setAuthTag(new Buffer(test.tag, 'hex'));
if (test.aad)
decrypt.setAAD(new Buffer(test.aad, 'hex'));
var msg = decrypt.update(test.ct, 'hex', 'ascii');
if (!test.tampered) {
msg += decrypt.final('ascii');
assert.equal(msg, test.plain);
if (common.hasFipsCrypto) {
assert.throws(function()
{ crypto.createDecipher(test.algo, test.password); },
/not supported in FIPS mode/);
} else {
// assert that final throws if input data could not be verified!
assert.throws(function() { decrypt.final('ascii'); }, / auth/);
var decrypt = crypto.createDecipher(test.algo, test.password);
decrypt.setAuthTag(new Buffer(test.tag, 'hex'));
if (test.aad)
decrypt.setAAD(new Buffer(test.aad, 'hex'));
var msg = decrypt.update(test.ct, 'hex', 'ascii');
if (!test.tampered) {
msg += decrypt.final('ascii');
assert.equal(msg, test.plain);
} else {
// assert that final throws if input data could not be verified!
assert.throws(function() { decrypt.final('ascii'); }, / auth/);
}
}
})();

Expand Down
11 changes: 6 additions & 5 deletions test/parallel/test-crypto-binary-default.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,12 +496,13 @@ function testCipher4(key, iv) {
assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
}

if (!common.hasFipsCrypto) {
testCipher1('MySecretKey123');
testCipher1(new Buffer('MySecretKey123'));

testCipher1('MySecretKey123');
testCipher1(new Buffer('MySecretKey123'));

testCipher2('0123456789abcdef');
testCipher2(new Buffer('0123456789abcdef'));
testCipher2('0123456789abcdef');
testCipher2(new Buffer('0123456789abcdef'));
}

testCipher3('0123456789abcd0123456789', '12345678');
testCipher3('0123456789abcd0123456789', new Buffer('12345678'));
Expand Down
63 changes: 4 additions & 59 deletions test/parallel/test-crypto-cipher-decipher.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ if (!common.hasCrypto) {
console.log('1..0 # Skipped: missing crypto');
return;
}
if (common.hasFipsCrypto) {
console.log('1..0 # Skipped: not supported in FIPS mode');
return;
}
var crypto = require('crypto');

function testCipher1(key) {
Expand Down Expand Up @@ -62,71 +66,12 @@ function testCipher2(key) {
assert.equal(txt, plaintext, 'encryption and decryption with Base64');
}


function testCipher3(key, iv) {
// Test encyrption and decryption with explicit key and iv
var plaintext =
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
'jAfaFg**';
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
var ciph = cipher.update(plaintext, 'utf8', 'hex');
ciph += cipher.final('hex');

var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
var txt = decipher.update(ciph, 'hex', 'utf8');
txt += decipher.final('utf8');

assert.equal(txt, plaintext, 'encryption and decryption with key and iv');

// streaming cipher interface
// NB: In real life, it's not guaranteed that you can get all of it
// in a single read() like this. But in this case, we know it's
// quite small, so there's no harm.
var cStream = crypto.createCipheriv('des-ede3-cbc', key, iv);
cStream.end(plaintext);
ciph = cStream.read();

var dStream = crypto.createDecipheriv('des-ede3-cbc', key, iv);
dStream.end(ciph);
txt = dStream.read().toString('utf8');

assert.equal(txt, plaintext, 'streaming cipher iv');
}


function testCipher4(key, iv) {
// Test encyrption and decryption with explicit key and iv
var plaintext =
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
'jAfaFg**';
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
var ciph = cipher.update(plaintext, 'utf8', 'buffer');
ciph = Buffer.concat([ciph, cipher.final('buffer')]);

var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
var txt = decipher.update(ciph, 'buffer', 'utf8');
txt += decipher.final('utf8');

assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
}


testCipher1('MySecretKey123');
testCipher1(new Buffer('MySecretKey123'));

testCipher2('0123456789abcdef');
testCipher2(new Buffer('0123456789abcdef'));

testCipher3('0123456789abcd0123456789', '12345678');
testCipher3('0123456789abcd0123456789', new Buffer('12345678'));
testCipher3(new Buffer('0123456789abcd0123456789'), '12345678');
testCipher3(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));

testCipher4(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));


// Base64 padding regression test, see #4837.
(function() {
var c = crypto.createCipher('aes-256-cbc', 'secret');
Expand Down
65 changes: 65 additions & 0 deletions test/parallel/test-crypto-cipheriv-decipheriv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';
var common = require('../common');
var assert = require('assert');

if (!common.hasCrypto) {
console.log('1..0 # Skipped: missing crypto');
return;
}
var crypto = require('crypto');

function testCipher1(key, iv) {
// Test encyrption and decryption with explicit key and iv
var plaintext =
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
'jAfaFg**';
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
var ciph = cipher.update(plaintext, 'utf8', 'hex');
ciph += cipher.final('hex');

var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
var txt = decipher.update(ciph, 'hex', 'utf8');
txt += decipher.final('utf8');

assert.equal(txt, plaintext, 'encryption and decryption with key and iv');

// streaming cipher interface
// NB: In real life, it's not guaranteed that you can get all of it
// in a single read() like this. But in this case, we know it's
// quite small, so there's no harm.
var cStream = crypto.createCipheriv('des-ede3-cbc', key, iv);
cStream.end(plaintext);
ciph = cStream.read();

var dStream = crypto.createDecipheriv('des-ede3-cbc', key, iv);
dStream.end(ciph);
txt = dStream.read().toString('utf8');

assert.equal(txt, plaintext, 'streaming cipher iv');
}


function testCipher2(key, iv) {
// Test encyrption and decryption with explicit key and iv
var plaintext =
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
'jAfaFg**';
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
var ciph = cipher.update(plaintext, 'utf8', 'buffer');
ciph = Buffer.concat([ciph, cipher.final('buffer')]);

var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
var txt = decipher.update(ciph, 'buffer', 'utf8');
txt += decipher.final('utf8');

assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
}

testCipher1('0123456789abcd0123456789', '12345678');
testCipher1('0123456789abcd0123456789', new Buffer('12345678'));
testCipher1(new Buffer('0123456789abcd0123456789'), '12345678');
testCipher1(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));

testCipher2(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));
4 changes: 2 additions & 2 deletions test/parallel/test-crypto-dh.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ assert.equal(secret1, secret3);

// Run this one twice to make sure that the dh3 clears its error properly
(function() {
var c = crypto.createDecipher('aes-128-ecb', '');
var c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
assert.throws(function() { c.final('utf8'); }, /wrong final block length/);
})();

Expand All @@ -67,7 +67,7 @@ assert.throws(function() {
}, /key is too small/i);

(function() {
var c = crypto.createDecipher('aes-128-ecb', '');
var c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
assert.throws(function() { c.final('utf8'); }, /wrong final block length/);
})();

Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ assertSorted(crypto.getCurves());
// throw, not assert in C++ land.
assert.throws(function() {
crypto.createCipher('aes192', 'test').update('0', 'hex');
}, /Bad input string/);
}, common.hasFipsCrypto ? /not supported in FIPS mode/ : /Bad input string/);

assert.throws(function() {
crypto.createDecipher('aes192', 'test').update('0', 'hex');
}, /Bad input string/);
}, common.hasFipsCrypto ? /not supported in FIPS mode/ : /Bad input string/);

assert.throws(function() {
crypto.createHash('sha1').update('0', 'hex');
Expand Down

0 comments on commit def681a

Please sign in to comment.