node/test/parallel/test-crypto-key-objects.js
Tobias Nießen 3afa5d7ba8
crypto: improve error handling in parseKeyEncoding
This change only affects KeyObject.export().

PR-URL: https://github.com/nodejs/node/pull/26455
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
2019-03-09 12:00:23 +01:00

173 lines
5.3 KiB
JavaScript

'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const {
createCipheriv,
createDecipheriv,
createSecretKey,
createPublicKey,
createPrivateKey,
randomBytes,
publicEncrypt,
privateDecrypt
} = require('crypto');
const fixtures = require('../common/fixtures');
const publicPem = fixtures.readSync('test_rsa_pubkey.pem', 'ascii');
const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii');
{
// Attempting to create an empty key should throw.
common.expectsError(() => {
createSecretKey(Buffer.alloc(0));
}, {
type: RangeError,
code: 'ERR_OUT_OF_RANGE',
message: 'The value of "key.byteLength" is out of range. ' +
'It must be > 0. Received 0'
});
}
{
const keybuf = randomBytes(32);
const key = createSecretKey(keybuf);
assert.strictEqual(key.type, 'secret');
assert.strictEqual(key.symmetricKeySize, 32);
assert.strictEqual(key.asymmetricKeySize, undefined);
assert.strictEqual(key.asymmetricKeyType, undefined);
const exportedKey = key.export();
assert(keybuf.equals(exportedKey));
const plaintext = Buffer.from('Hello world', 'utf8');
const cipher = createCipheriv('aes-256-ecb', key, null);
const ciphertext = Buffer.concat([
cipher.update(plaintext), cipher.final()
]);
const decipher = createDecipheriv('aes-256-ecb', key, null);
const deciphered = Buffer.concat([
decipher.update(ciphertext), decipher.final()
]);
assert(plaintext.equals(deciphered));
}
{
// Passing an existing public key object to createPublicKey should throw.
const publicKey = createPublicKey(publicPem);
common.expectsError(() => createPublicKey(publicKey), {
type: TypeError,
code: 'ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE',
message: 'Invalid key object type public, expected private.'
});
// Constructing a private key from a public key should be impossible, even
// if the public key was derived from a private key.
common.expectsError(() => createPrivateKey(createPublicKey(privatePem)), {
type: TypeError,
code: 'ERR_INVALID_ARG_TYPE',
message: 'The "key" argument must be one of type string, Buffer, ' +
'TypedArray, or DataView. Received type object'
});
// Similarly, passing an existing private key object to createPrivateKey
// should throw.
const privateKey = createPrivateKey(privatePem);
common.expectsError(() => createPrivateKey(privateKey), {
type: TypeError,
code: 'ERR_INVALID_ARG_TYPE',
message: 'The "key" argument must be one of type string, Buffer, ' +
'TypedArray, or DataView. Received type object'
});
}
{
const publicKey = createPublicKey(publicPem);
assert.strictEqual(publicKey.type, 'public');
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
assert.strictEqual(publicKey.asymmetricKeySize, 128);
assert.strictEqual(publicKey.symmetricKeySize, undefined);
const privateKey = createPrivateKey(privatePem);
assert.strictEqual(privateKey.type, 'private');
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
assert.strictEqual(privateKey.asymmetricKeySize, 128);
assert.strictEqual(privateKey.symmetricKeySize, undefined);
// It should be possible to derive a public key from a private key.
const derivedPublicKey = createPublicKey(privateKey);
assert.strictEqual(derivedPublicKey.type, 'public');
assert.strictEqual(derivedPublicKey.asymmetricKeyType, 'rsa');
assert.strictEqual(derivedPublicKey.symmetricKeySize, undefined);
// Test exporting with an invalid options object, this should throw.
for (const opt of [undefined, null, 'foo', 0, NaN]) {
common.expectsError(() => publicKey.export(opt), {
type: TypeError,
code: 'ERR_INVALID_ARG_TYPE',
message: 'The "options" argument must be of type object. Received type ' +
typeof opt
});
}
const publicDER = publicKey.export({
format: 'der',
type: 'pkcs1'
});
const privateDER = privateKey.export({
format: 'der',
type: 'pkcs1'
});
assert(Buffer.isBuffer(publicDER));
assert(Buffer.isBuffer(privateDER));
const plaintext = Buffer.from('Hello world', 'utf8');
const ciphertexts = [
// Encrypt using the public key.
publicEncrypt(publicKey, plaintext),
publicEncrypt({ key: publicKey }, plaintext),
// Encrypt using the private key.
publicEncrypt(privateKey, plaintext),
publicEncrypt({ key: privateKey }, plaintext),
// Encrypt using a public key derived from the private key.
publicEncrypt(derivedPublicKey, plaintext),
publicEncrypt({ key: derivedPublicKey }, plaintext),
// Test distinguishing PKCS#1 public and private keys based on the
// DER-encoded data only.
publicEncrypt({ format: 'der', type: 'pkcs1', key: publicDER }, plaintext),
publicEncrypt({ format: 'der', type: 'pkcs1', key: privateDER }, plaintext)
];
const decryptionKeys = [
privateKey,
{ format: 'pem', key: privatePem },
{ format: 'der', type: 'pkcs1', key: privateDER }
];
for (const ciphertext of ciphertexts) {
for (const key of decryptionKeys) {
const deciphered = privateDecrypt(key, ciphertext);
assert(plaintext.equals(deciphered));
}
}
}
{
// This should not cause a crash: https://github.com/nodejs/node/issues/25247
assert.throws(() => {
createPrivateKey({ key: '' });
}, /null/);
}