0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/test/parallel/test-crypto.js
Rich Trott 56950674d6 crypto,tls: fix mutability of return values
If you alter the array returned by `tls.getCiphers()`,
`crypto.getCiphers()`, `crypto.getHashes()`, or `crypto.getCurves()`, it
will alter subsequent return values from those functions.

```js
'use strict';

const crypto = require('crypto');

var hashes = crypto.getHashes();

hashes.splice(0, hashes.length);

hashes.push('some-arbitrary-value');

console.log(crypto.getHashes()); // "['some-arbitrary-value']"
```

This is surprising. Change functions to return copy of array instead.

PR-URL: https://github.com/nodejs/node/pull/10795
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
2017-01-16 20:32:23 -08:00

171 lines
5.8 KiB
JavaScript

'use strict';
const common = require('../common');
if (!common.hasCrypto) {
common.skip('missing crypto');
return;
}
const assert = require('assert');
const crypto = require('crypto');
const fs = require('fs');
const tls = require('tls');
crypto.DEFAULT_ENCODING = 'buffer';
// Test Certificates
const caPem = fs.readFileSync(common.fixturesDir + '/test_ca.pem', 'ascii');
const certPem = fs.readFileSync(common.fixturesDir + '/test_cert.pem', 'ascii');
const certPfx = fs.readFileSync(common.fixturesDir + '/test_cert.pfx');
const keyPem = fs.readFileSync(common.fixturesDir + '/test_key.pem', 'ascii');
// 'this' safety
// https://github.com/joyent/node/issues/6690
assert.throws(function() {
const options = {key: keyPem, cert: certPem, ca: caPem};
const credentials = tls.createSecureContext(options);
const context = credentials.context;
const notcontext = { setOptions: context.setOptions, setKey: context.setKey };
tls.createSecureContext({ secureOptions: 1 }, notcontext);
}, /^TypeError: Illegal invocation$/);
// PFX tests
assert.doesNotThrow(function() {
tls.createSecureContext({pfx: certPfx, passphrase: 'sample'});
});
assert.throws(function() {
tls.createSecureContext({pfx: certPfx});
}, /^Error: mac verify failure$/);
assert.throws(function() {
tls.createSecureContext({pfx: certPfx, passphrase: 'test'});
}, /^Error: mac verify failure$/);
assert.throws(function() {
tls.createSecureContext({pfx: 'sample', passphrase: 'test'});
}, /^Error: not enough data$/);
// update() should only take buffers / strings
assert.throws(function() {
crypto.createHash('sha1').update({foo: 'bar'});
}, /^TypeError: Data must be a string or a buffer$/);
function validateList(list) {
// The list must not be empty
assert(list.length > 0);
// The list should be sorted.
// Array#sort() modifies the list in place so make a copy.
const sorted = [...list].sort();
assert.deepStrictEqual(list, sorted);
// Each element should be unique.
assert.strictEqual([...new Set(list)].length, list.length);
// Each element should be a string.
assert(list.every((value) => typeof value === 'string'));
}
// Assume that we have at least AES-128-CBC.
const cryptoCiphers = crypto.getCiphers();
assert(crypto.getCiphers().includes('aes-128-cbc'));
validateList(cryptoCiphers);
// Assume that we have at least AES256-SHA.
const tlsCiphers = tls.getCiphers();
assert(tls.getCiphers().includes('aes256-sha'));
// There should be no capital letters in any element.
assert(tlsCiphers.every((value) => /^[^A-Z]+$/.test(value)));
validateList(tlsCiphers);
// Assert that we have sha and sha1 but not SHA and SHA1.
assert.notStrictEqual(0, crypto.getHashes().length);
assert(crypto.getHashes().includes('sha1'));
assert(crypto.getHashes().includes('sha'));
assert(!crypto.getHashes().includes('SHA1'));
assert(!crypto.getHashes().includes('SHA'));
assert(crypto.getHashes().includes('RSA-SHA1'));
assert(!crypto.getHashes().includes('rsa-sha1'));
validateList(crypto.getHashes());
// Assume that we have at least secp384r1.
assert.notStrictEqual(0, crypto.getCurves().length);
assert(crypto.getCurves().includes('secp384r1'));
assert(!crypto.getCurves().includes('SECP384R1'));
validateList(crypto.getCurves());
// Modifying return value from get* functions should not mutate subsequent
// return values.
function testImmutability(fn) {
const list = fn();
const copy = [...list];
list.push('some-arbitrary-value');
assert.deepStrictEqual(fn(), copy);
}
testImmutability(crypto.getCiphers);
testImmutability(tls.getCiphers);
testImmutability(crypto.getHashes);
testImmutability(crypto.getCurves);
// Regression tests for #5725: hex input that's not a power of two should
// throw, not assert in C++ land.
assert.throws(function() {
crypto.createCipher('aes192', 'test').update('0', 'hex');
}, common.hasFipsCrypto ? /not supported in FIPS mode/ : /Bad input string/);
assert.throws(function() {
crypto.createDecipher('aes192', 'test').update('0', 'hex');
}, common.hasFipsCrypto ? /not supported in FIPS mode/ : /Bad input string/);
assert.throws(function() {
crypto.createHash('sha1').update('0', 'hex');
}, /^TypeError: Bad input string$/);
assert.throws(function() {
crypto.createSign('RSA-SHA1').update('0', 'hex');
}, /^TypeError: Bad input string$/);
assert.throws(function() {
crypto.createVerify('RSA-SHA1').update('0', 'hex');
}, /^TypeError: Bad input string$/);
assert.throws(function() {
const priv = [
'-----BEGIN RSA PRIVATE KEY-----',
'MIGrAgEAAiEA+3z+1QNF2/unumadiwEr+C5vfhezsb3hp4jAnCNRpPcCAwEAAQIgQNriSQK4',
'EFwczDhMZp2dvbcz7OUUyt36z3S4usFPHSECEQD/41K7SujrstBfoCPzwC1xAhEA+5kt4BJy',
'eKN7LggbF3Dk5wIQN6SL+fQ5H/+7NgARsVBp0QIRANxYRukavs4QvuyNhMx+vrkCEQCbf6j/',
'Ig6/HueCK/0Jkmp+',
'-----END RSA PRIVATE KEY-----',
''
].join('\n');
crypto.createSign('RSA-SHA256').update('test').sign(priv);
}, /digest too big for rsa key$/);
assert.throws(function() {
// The correct header inside `test_bad_rsa_privkey.pem` should have been
// -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----
// instead of
// -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----
// It is generated in this way:
// $ openssl genrsa -out mykey.pem 512;
// $ openssl pkcs8 -topk8 -inform PEM -outform PEM -in mykey.pem \
// -out private_key.pem -nocrypt;
// Then open private_key.pem and change its header and footer.
const sha1_privateKey = fs.readFileSync(common.fixturesDir +
'/test_bad_rsa_privkey.pem', 'ascii');
// this would inject errors onto OpenSSL's error stack
crypto.createSign('sha1').sign(sha1_privateKey);
}, /asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag/);
// Make sure memory isn't released before being returned
console.log(crypto.randomBytes(16));
assert.throws(function() {
tls.createSecureContext({ crl: 'not a CRL' });
}, /^Error: Failed to parse CRL$/);