mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
test: split test-crypto-keygen.js
To avoid timing out on ARM machines in the CI. PR-URL: https://github.com/nodejs/node/pull/49221 Refs: https://github.com/nodejs/node/issues/49202 Refs: https://github.com/nodejs/node/issues/41206 Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
This commit is contained in:
parent
a81d5e11f3
commit
7224940e54
|
|
@ -6,6 +6,14 @@ if (!common.hasCrypto)
|
|||
|
||||
const assert = require('assert');
|
||||
const crypto = require('crypto');
|
||||
const {
|
||||
createSign,
|
||||
createVerify,
|
||||
publicEncrypt,
|
||||
privateDecrypt,
|
||||
sign,
|
||||
verify,
|
||||
} = crypto;
|
||||
|
||||
// The values below (modp2/modp2buf) are for a 1024 bits long prime from
|
||||
// RFC 2412 E.2, see https://tools.ietf.org/html/rfc2412. */
|
||||
|
|
@ -42,7 +50,83 @@ function testDH({ publicKey: alicePublicKey, privateKey: alicePrivateKey },
|
|||
assert.deepStrictEqual(buf1, expectedValue);
|
||||
}
|
||||
|
||||
// Asserts that the size of the given key (in chars or bytes) is within 10% of
|
||||
// the expected size.
|
||||
function assertApproximateSize(key, expectedSize) {
|
||||
const u = typeof key === 'string' ? 'chars' : 'bytes';
|
||||
const min = Math.floor(0.9 * expectedSize);
|
||||
const max = Math.ceil(1.1 * expectedSize);
|
||||
assert(key.length >= min,
|
||||
`Key (${key.length} ${u}) is shorter than expected (${min} ${u})`);
|
||||
assert(key.length <= max,
|
||||
`Key (${key.length} ${u}) is longer than expected (${max} ${u})`);
|
||||
}
|
||||
|
||||
// Tests that a key pair can be used for encryption / decryption.
|
||||
function testEncryptDecrypt(publicKey, privateKey) {
|
||||
const message = 'Hello Node.js world!';
|
||||
const plaintext = Buffer.from(message, 'utf8');
|
||||
for (const key of [publicKey, privateKey]) {
|
||||
const ciphertext = publicEncrypt(key, plaintext);
|
||||
const received = privateDecrypt(privateKey, ciphertext);
|
||||
assert.strictEqual(received.toString('utf8'), message);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that a key pair can be used for signing / verification.
|
||||
function testSignVerify(publicKey, privateKey) {
|
||||
const message = Buffer.from('Hello Node.js world!');
|
||||
|
||||
function oldSign(algo, data, key) {
|
||||
return createSign(algo).update(data).sign(key);
|
||||
}
|
||||
|
||||
function oldVerify(algo, data, key, signature) {
|
||||
return createVerify(algo).update(data).verify(key, signature);
|
||||
}
|
||||
|
||||
for (const signFn of [sign, oldSign]) {
|
||||
const signature = signFn('SHA256', message, privateKey);
|
||||
for (const verifyFn of [verify, oldVerify]) {
|
||||
for (const key of [publicKey, privateKey]) {
|
||||
const okay = verifyFn('SHA256', message, key, signature);
|
||||
assert(okay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Constructs a regular expression for a PEM-encoded key with the given label.
|
||||
function getRegExpForPEM(label, cipher) {
|
||||
const head = `\\-\\-\\-\\-\\-BEGIN ${label}\\-\\-\\-\\-\\-`;
|
||||
const rfc1421Header = cipher == null ? '' :
|
||||
`\nProc-Type: 4,ENCRYPTED\nDEK-Info: ${cipher},[^\n]+\n`;
|
||||
const body = '([a-zA-Z0-9\\+/=]{64}\n)*[a-zA-Z0-9\\+/=]{1,64}';
|
||||
const end = `\\-\\-\\-\\-\\-END ${label}\\-\\-\\-\\-\\-`;
|
||||
return new RegExp(`^${head}${rfc1421Header}\n${body}\n${end}\n$`);
|
||||
}
|
||||
|
||||
const pkcs1PubExp = getRegExpForPEM('RSA PUBLIC KEY');
|
||||
const pkcs1PrivExp = getRegExpForPEM('RSA PRIVATE KEY');
|
||||
const pkcs1EncExp = (cipher) => getRegExpForPEM('RSA PRIVATE KEY', cipher);
|
||||
const spkiExp = getRegExpForPEM('PUBLIC KEY');
|
||||
const pkcs8Exp = getRegExpForPEM('PRIVATE KEY');
|
||||
const pkcs8EncExp = getRegExpForPEM('ENCRYPTED PRIVATE KEY');
|
||||
const sec1Exp = getRegExpForPEM('EC PRIVATE KEY');
|
||||
const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
|
||||
module.exports = {
|
||||
modp2buf,
|
||||
testDH,
|
||||
assertApproximateSize,
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
pkcs1PubExp,
|
||||
pkcs1PrivExp,
|
||||
pkcs1EncExp, // used once
|
||||
spkiExp,
|
||||
pkcs8Exp, // used once
|
||||
pkcs8EncExp, // used once
|
||||
sec1Exp,
|
||||
sec1EncExp,
|
||||
};
|
||||
|
|
|
|||
32
test/parallel/test-crypto-keygen-async-dsa-key-object.js
Normal file
32
test/parallel/test-crypto-keygen-async-dsa-key-object.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// Test async DSA key object generation.
|
||||
{
|
||||
generateKeyPair('dsa', {
|
||||
modulusLength: common.hasOpenSSL3 ? 2048 : 512,
|
||||
divisorLength: 256
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, 'dsa');
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, {
|
||||
modulusLength: common.hasOpenSSL3 ? 2048 : 512,
|
||||
divisorLength: 256
|
||||
});
|
||||
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, 'dsa');
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, {
|
||||
modulusLength: common.hasOpenSSL3 ? 2048 : 512,
|
||||
divisorLength: 256
|
||||
});
|
||||
}));
|
||||
}
|
||||
64
test/parallel/test-crypto-keygen-async-dsa.js
Normal file
64
test/parallel/test-crypto-keygen-async-dsa.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
assertApproximateSize,
|
||||
testSignVerify,
|
||||
spkiExp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async DSA key generation.
|
||||
{
|
||||
const privateKeyEncoding = {
|
||||
type: 'pkcs8',
|
||||
format: 'der'
|
||||
};
|
||||
|
||||
generateKeyPair('dsa', {
|
||||
modulusLength: common.hasOpenSSL3 ? 2048 : 512,
|
||||
divisorLength: 256,
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
cipher: 'aes-128-cbc',
|
||||
passphrase: 'secret',
|
||||
...privateKeyEncoding
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKeyDER) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, spkiExp);
|
||||
// The private key is DER-encoded.
|
||||
assert(Buffer.isBuffer(privateKeyDER));
|
||||
|
||||
assertApproximateSize(publicKey, common.hasOpenSSL3 ? 1194 : 440);
|
||||
assertApproximateSize(privateKeyDER, common.hasOpenSSL3 ? 721 : 336);
|
||||
|
||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||
assert.throws(() => {
|
||||
return testSignVerify(publicKey, {
|
||||
key: privateKeyDER,
|
||||
...privateKeyEncoding
|
||||
});
|
||||
}, {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
});
|
||||
|
||||
// Signing should work with the correct password.
|
||||
testSignVerify(publicKey, {
|
||||
key: privateKeyDER,
|
||||
...privateKeyEncoding,
|
||||
passphrase: 'secret'
|
||||
});
|
||||
}));
|
||||
}
|
||||
100
test/parallel/test-crypto-keygen-async-elliptic-curve-jwk.js
Normal file
100
test/parallel/test-crypto-keygen-async-elliptic-curve-jwk.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// Test async elliptic curve key generation with 'jwk' encoding
|
||||
{
|
||||
[
|
||||
['ec', ['P-384', 'P-256', 'P-521', 'secp256k1']],
|
||||
['rsa'],
|
||||
['ed25519'],
|
||||
['ed448'],
|
||||
['x25519'],
|
||||
['x448'],
|
||||
].forEach((types) => {
|
||||
const [type, options] = types;
|
||||
switch (type) {
|
||||
case 'ec': {
|
||||
return options.forEach((curve) => {
|
||||
generateKeyPair(type, {
|
||||
namedCurve: curve,
|
||||
publicKeyEncoding: {
|
||||
format: 'jwk'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
format: 'jwk'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'object');
|
||||
assert.strictEqual(typeof privateKey, 'object');
|
||||
assert.strictEqual(publicKey.x, privateKey.x);
|
||||
assert.strictEqual(publicKey.y, privateKey.y);
|
||||
assert(!publicKey.d);
|
||||
assert(privateKey.d);
|
||||
assert.strictEqual(publicKey.kty, 'EC');
|
||||
assert.strictEqual(publicKey.kty, privateKey.kty);
|
||||
assert.strictEqual(publicKey.crv, curve);
|
||||
assert.strictEqual(publicKey.crv, privateKey.crv);
|
||||
}));
|
||||
});
|
||||
}
|
||||
case 'rsa': {
|
||||
return generateKeyPair(type, {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
format: 'jwk'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
format: 'jwk'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'object');
|
||||
assert.strictEqual(typeof privateKey, 'object');
|
||||
assert.strictEqual(publicKey.kty, 'RSA');
|
||||
assert.strictEqual(publicKey.kty, privateKey.kty);
|
||||
assert.strictEqual(typeof publicKey.n, 'string');
|
||||
assert.strictEqual(publicKey.n, privateKey.n);
|
||||
assert.strictEqual(typeof publicKey.e, 'string');
|
||||
assert.strictEqual(publicKey.e, privateKey.e);
|
||||
assert.strictEqual(typeof privateKey.d, 'string');
|
||||
assert.strictEqual(typeof privateKey.p, 'string');
|
||||
assert.strictEqual(typeof privateKey.q, 'string');
|
||||
assert.strictEqual(typeof privateKey.dp, 'string');
|
||||
assert.strictEqual(typeof privateKey.dq, 'string');
|
||||
assert.strictEqual(typeof privateKey.qi, 'string');
|
||||
}));
|
||||
}
|
||||
case 'ed25519':
|
||||
case 'ed448':
|
||||
case 'x25519':
|
||||
case 'x448': {
|
||||
generateKeyPair(type, {
|
||||
publicKeyEncoding: {
|
||||
format: 'jwk'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
format: 'jwk'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'object');
|
||||
assert.strictEqual(typeof privateKey, 'object');
|
||||
assert.strictEqual(publicKey.x, privateKey.x);
|
||||
assert(!publicKey.d);
|
||||
assert(privateKey.d);
|
||||
assert.strictEqual(publicKey.kty, 'OKP');
|
||||
assert.strictEqual(publicKey.kty, privateKey.kty);
|
||||
const expectedCrv = `${type.charAt(0).toUpperCase()}${type.slice(1)}`;
|
||||
assert.strictEqual(publicKey.crv, expectedCrv);
|
||||
assert.strictEqual(publicKey.crv, privateKey.crv);
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
assertApproximateSize,
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async RSA key generation with an encrypted private key, but encoded as DER.
|
||||
{
|
||||
generateKeyPair('rsa', {
|
||||
publicExponent: 0x10001,
|
||||
modulusLength: 512,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'der'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs8',
|
||||
format: 'der'
|
||||
}
|
||||
}, common.mustSucceed((publicKeyDER, privateKeyDER) => {
|
||||
assert(Buffer.isBuffer(publicKeyDER));
|
||||
assertApproximateSize(publicKeyDER, 74);
|
||||
|
||||
assert(Buffer.isBuffer(privateKeyDER));
|
||||
|
||||
const publicKey = {
|
||||
key: publicKeyDER,
|
||||
type: 'pkcs1',
|
||||
format: 'der',
|
||||
};
|
||||
const privateKey = {
|
||||
key: privateKeyDER,
|
||||
format: 'der',
|
||||
type: 'pkcs8',
|
||||
passphrase: 'secret'
|
||||
};
|
||||
testEncryptDecrypt(publicKey, privateKey);
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
assertApproximateSize,
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async RSA key generation with an encrypted private key, but encoded as DER.
|
||||
{
|
||||
generateKeyPair('rsa', {
|
||||
publicExponent: 0x10001,
|
||||
modulusLength: 512,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'der'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs8',
|
||||
format: 'der',
|
||||
cipher: 'aes-256-cbc',
|
||||
passphrase: 'secret'
|
||||
}
|
||||
}, common.mustSucceed((publicKeyDER, privateKeyDER) => {
|
||||
assert(Buffer.isBuffer(publicKeyDER));
|
||||
assertApproximateSize(publicKeyDER, 74);
|
||||
|
||||
assert(Buffer.isBuffer(privateKeyDER));
|
||||
|
||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||
const publicKey = {
|
||||
key: publicKeyDER,
|
||||
type: 'pkcs1',
|
||||
format: 'der',
|
||||
};
|
||||
assert.throws(() => {
|
||||
testSignVerify(publicKey, {
|
||||
key: privateKeyDER,
|
||||
format: 'der',
|
||||
type: 'pkcs8'
|
||||
});
|
||||
}, {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
});
|
||||
|
||||
// Signing should work with the correct password.
|
||||
|
||||
const privateKey = {
|
||||
key: privateKeyDER,
|
||||
format: 'der',
|
||||
type: 'pkcs8',
|
||||
passphrase: 'secret'
|
||||
};
|
||||
testEncryptDecrypt(publicKey, privateKey);
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testSignVerify,
|
||||
spkiExp,
|
||||
pkcs8EncExp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async elliptic curve key generation, e.g. for ECDSA, with an encrypted
|
||||
// private key with paramEncoding explicit.
|
||||
{
|
||||
generateKeyPair('ec', {
|
||||
namedCurve: 'P-256',
|
||||
paramEncoding: 'explicit',
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs8',
|
||||
format: 'pem',
|
||||
cipher: 'aes-128-cbc',
|
||||
passphrase: 'top secret'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, spkiExp);
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, pkcs8EncExp);
|
||||
|
||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||
common.hasOpenSSL3 ? {
|
||||
message: 'error:07880109:common libcrypto ' +
|
||||
'routines::interrupted or cancelled'
|
||||
} : {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
});
|
||||
|
||||
testSignVerify(publicKey, {
|
||||
key: privateKey,
|
||||
passphrase: 'top secret'
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testSignVerify,
|
||||
spkiExp,
|
||||
sec1EncExp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
{
|
||||
// Test async explicit elliptic curve key generation with an encrypted
|
||||
// private key.
|
||||
generateKeyPair('ec', {
|
||||
namedCurve: 'prime256v1',
|
||||
paramEncoding: 'explicit',
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'sec1',
|
||||
format: 'pem',
|
||||
cipher: 'aes-128-cbc',
|
||||
passphrase: 'secret'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, spkiExp);
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, sec1EncExp('AES-128-CBC'));
|
||||
|
||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||
common.hasOpenSSL3 ? {
|
||||
message: 'error:07880109:common libcrypto ' +
|
||||
'routines::interrupted or cancelled'
|
||||
} : {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
});
|
||||
|
||||
testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' });
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testSignVerify,
|
||||
spkiExp,
|
||||
sec1Exp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async explicit elliptic curve key generation, e.g. for ECDSA,
|
||||
// with a SEC1 private key with paramEncoding explicit.
|
||||
{
|
||||
generateKeyPair('ec', {
|
||||
namedCurve: 'prime256v1',
|
||||
paramEncoding: 'explicit',
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'sec1',
|
||||
format: 'pem'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, spkiExp);
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, sec1Exp);
|
||||
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testSignVerify,
|
||||
spkiExp,
|
||||
pkcs8EncExp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async elliptic curve key generation, e.g. for ECDSA, with an encrypted
|
||||
// private key.
|
||||
{
|
||||
generateKeyPair('ec', {
|
||||
namedCurve: 'P-256',
|
||||
paramEncoding: 'named',
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs8',
|
||||
format: 'pem',
|
||||
cipher: 'aes-128-cbc',
|
||||
passphrase: 'top secret'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, spkiExp);
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, pkcs8EncExp);
|
||||
|
||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||
common.hasOpenSSL3 ? {
|
||||
message: 'error:07880109:common libcrypto ' +
|
||||
'routines::interrupted or cancelled'
|
||||
} : {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
});
|
||||
|
||||
testSignVerify(publicKey, {
|
||||
key: privateKey,
|
||||
passphrase: 'top secret'
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testSignVerify,
|
||||
spkiExp,
|
||||
sec1EncExp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
{
|
||||
// Test async named elliptic curve key generation with an encrypted
|
||||
// private key.
|
||||
generateKeyPair('ec', {
|
||||
namedCurve: 'prime256v1',
|
||||
paramEncoding: 'named',
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'sec1',
|
||||
format: 'pem',
|
||||
cipher: 'aes-128-cbc',
|
||||
passphrase: 'secret'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, spkiExp);
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, sec1EncExp('AES-128-CBC'));
|
||||
|
||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||
common.hasOpenSSL3 ? {
|
||||
message: 'error:07880109:common libcrypto ' +
|
||||
'routines::interrupted or cancelled'
|
||||
} : {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
});
|
||||
|
||||
testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' });
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testSignVerify,
|
||||
spkiExp,
|
||||
sec1Exp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async named elliptic curve key generation, e.g. for ECDSA,
|
||||
// with a SEC1 private key.
|
||||
{
|
||||
generateKeyPair('ec', {
|
||||
namedCurve: 'prime256v1',
|
||||
paramEncoding: 'named',
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'sec1',
|
||||
format: 'pem'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, spkiExp);
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, sec1Exp);
|
||||
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
61
test/parallel/test-crypto-keygen-async-rsa.js
Normal file
61
test/parallel/test-crypto-keygen-async-rsa.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
assertApproximateSize,
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
pkcs1EncExp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test async RSA key generation with an encrypted private key.
|
||||
{
|
||||
generateKeyPair('rsa', {
|
||||
publicExponent: 0x10001,
|
||||
modulusLength: 512,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'der'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem',
|
||||
cipher: 'aes-256-cbc',
|
||||
passphrase: 'secret'
|
||||
}
|
||||
}, common.mustSucceed((publicKeyDER, privateKey) => {
|
||||
assert(Buffer.isBuffer(publicKeyDER));
|
||||
assertApproximateSize(publicKeyDER, 74);
|
||||
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, pkcs1EncExp('AES-256-CBC'));
|
||||
|
||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||
const publicKey = {
|
||||
key: publicKeyDER,
|
||||
type: 'pkcs1',
|
||||
format: 'der',
|
||||
};
|
||||
const expectedError = common.hasOpenSSL3 ? {
|
||||
name: 'Error',
|
||||
message: 'error:07880109:common libcrypto routines::interrupted or ' +
|
||||
'cancelled'
|
||||
} : {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
};
|
||||
assert.throws(() => testSignVerify(publicKey, privateKey), expectedError);
|
||||
|
||||
const key = { key: privateKey, passphrase: 'secret' };
|
||||
testEncryptDecrypt(publicKey, key);
|
||||
testSignVerify(publicKey, key);
|
||||
}));
|
||||
}
|
||||
39
test/parallel/test-crypto-keygen-bit-length.js
Normal file
39
test/parallel/test-crypto-keygen-bit-length.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// This tests check that generateKeyPair returns correct bit length in
|
||||
// KeyObject's asymmetricKeyDetails.
|
||||
// https://github.com/nodejs/node/issues/46102#issuecomment-1372153541
|
||||
{
|
||||
generateKeyPair('rsa', {
|
||||
modulusLength: 513,
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(privateKey.asymmetricKeyDetails.modulusLength, 513);
|
||||
assert.strictEqual(publicKey.asymmetricKeyDetails.modulusLength, 513);
|
||||
}));
|
||||
|
||||
generateKeyPair('rsa-pss', {
|
||||
modulusLength: 513,
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(privateKey.asymmetricKeyDetails.modulusLength, 513);
|
||||
assert.strictEqual(publicKey.asymmetricKeyDetails.modulusLength, 513);
|
||||
}));
|
||||
|
||||
if (common.hasOpenSSL3) {
|
||||
generateKeyPair('dsa', {
|
||||
modulusLength: 2049,
|
||||
divisorLength: 256,
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(privateKey.asymmetricKeyDetails.modulusLength, 2049);
|
||||
assert.strictEqual(publicKey.asymmetricKeyDetails.modulusLength, 2049);
|
||||
}));
|
||||
}
|
||||
}
|
||||
23
test/parallel/test-crypto-keygen-dh-classic.js
Normal file
23
test/parallel/test-crypto-keygen-dh-classic.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// Test classic Diffie-Hellman key generation.
|
||||
{
|
||||
generateKeyPair('dh', {
|
||||
primeLength: 1024
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, 'dh');
|
||||
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, 'dh');
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// This test makes sure deprecated and new options may be used
|
||||
// simultaneously so long as they're identical values.
|
||||
{
|
||||
generateKeyPair('rsa-pss', {
|
||||
modulusLength: 512,
|
||||
saltLength: 16,
|
||||
hash: 'sha256',
|
||||
hashAlgorithm: 'sha256',
|
||||
mgf1Hash: 'sha256',
|
||||
mgf1HashAlgorithm: 'sha256'
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa-pss');
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n,
|
||||
hashAlgorithm: 'sha256',
|
||||
mgf1HashAlgorithm: 'sha256',
|
||||
saltLength: 16
|
||||
});
|
||||
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa-pss');
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n,
|
||||
hashAlgorithm: 'sha256',
|
||||
mgf1HashAlgorithm: 'sha256',
|
||||
saltLength: 16
|
||||
});
|
||||
}));
|
||||
}
|
||||
27
test/parallel/test-crypto-keygen-eddsa.js
Normal file
27
test/parallel/test-crypto-keygen-eddsa.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// Test EdDSA key generation.
|
||||
{
|
||||
if (!/^1\.1\.0/.test(process.versions.openssl)) {
|
||||
['ed25519', 'ed448', 'x25519', 'x448'].forEach((keyType) => {
|
||||
generateKeyPair(keyType, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, keyType);
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, {});
|
||||
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, keyType);
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, {});
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// Passing an empty passphrase string should not throw ERR_OSSL_CRYPTO_MALLOC_FAILURE even on OpenSSL 3.
|
||||
// Regression test for https://github.com/nodejs/node/issues/41428.
|
||||
generateKeyPair('rsa', {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
type: 'spki',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs8',
|
||||
format: 'pem',
|
||||
cipher: 'aes-256-cbc',
|
||||
passphrase: ''
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
}));
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
createPrivateKey,
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testSignVerify,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Passing an empty passphrase string should not cause OpenSSL's default
|
||||
// passphrase prompt in the terminal.
|
||||
// See https://github.com/nodejs/node/issues/35898.
|
||||
for (const type of ['pkcs1', 'pkcs8']) {
|
||||
generateKeyPair('rsa', {
|
||||
modulusLength: 1024,
|
||||
privateKeyEncoding: {
|
||||
type,
|
||||
format: 'pem',
|
||||
cipher: 'aes-256-cbc',
|
||||
passphrase: ''
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
|
||||
for (const passphrase of ['', Buffer.alloc(0)]) {
|
||||
const privateKeyObject = createPrivateKey({
|
||||
passphrase,
|
||||
key: privateKey
|
||||
});
|
||||
assert.strictEqual(privateKeyObject.asymmetricKeyType, 'rsa');
|
||||
}
|
||||
|
||||
// Encrypting with an empty passphrase is not the same as not encrypting
|
||||
// the key, and not specifying a passphrase should fail when decoding it.
|
||||
assert.throws(() => {
|
||||
return testSignVerify(publicKey, privateKey);
|
||||
}, common.hasOpenSSL3 ? {
|
||||
name: 'Error',
|
||||
code: 'ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED',
|
||||
message: 'error:07880109:common libcrypto routines::interrupted or cancelled'
|
||||
} : {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_MISSING_PASSPHRASE',
|
||||
message: 'Passphrase required for encrypted key'
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
const {
|
||||
generateKeyPairSync,
|
||||
} = require('crypto');
|
||||
|
||||
// Test invalid parameter encoding.
|
||||
{
|
||||
assert.throws(() => generateKeyPairSync('dsa', {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
format: 'jwk'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
format: 'jwk'
|
||||
}
|
||||
}), {
|
||||
name: 'Error',
|
||||
code: 'ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE',
|
||||
message: 'Unsupported JWK Key Type.'
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
const {
|
||||
generateKeyPairSync,
|
||||
} = require('crypto');
|
||||
|
||||
{
|
||||
assert.throws(() => generateKeyPairSync('ec', {
|
||||
namedCurve: 'secp224r1',
|
||||
publicKeyEncoding: {
|
||||
format: 'jwk'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
format: 'jwk'
|
||||
}
|
||||
}), {
|
||||
name: 'Error',
|
||||
code: 'ERR_CRYPTO_JWK_UNSUPPORTED_CURVE',
|
||||
message: 'Unsupported JWK EC curve: secp224r1.'
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Tests key objects are returned when key encodings are not specified.
|
||||
{
|
||||
// If no publicKeyEncoding is specified, a key object should be returned.
|
||||
generateKeyPair('rsa', {
|
||||
modulusLength: 1024,
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(typeof publicKey, 'object');
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
|
||||
|
||||
// The private key should still be a string.
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
|
||||
testEncryptDecrypt(publicKey, privateKey);
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
|
||||
// If no privateKeyEncoding is specified, a key object should be returned.
|
||||
generateKeyPair('rsa', {
|
||||
modulusLength: 1024,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem'
|
||||
}
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
// The public key should still be a string.
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
|
||||
assert.strictEqual(typeof privateKey, 'object');
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
|
||||
|
||||
testEncryptDecrypt(publicKey, privateKey);
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
33
test/parallel/test-crypto-keygen-key-objects.js
Normal file
33
test/parallel/test-crypto-keygen-key-objects.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPairSync,
|
||||
} = require('crypto');
|
||||
|
||||
// Test sync key generation with key objects.
|
||||
{
|
||||
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
|
||||
modulusLength: 512
|
||||
});
|
||||
|
||||
assert.strictEqual(typeof publicKey, 'object');
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n
|
||||
});
|
||||
|
||||
assert.strictEqual(typeof privateKey, 'object');
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n
|
||||
});
|
||||
}
|
||||
43
test/parallel/test-crypto-keygen-missing-oid.js
Normal file
43
test/parallel/test-crypto-keygen-missing-oid.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
generateKeyPairSync,
|
||||
getCurves,
|
||||
} = require('crypto');
|
||||
|
||||
// This test creates EC key pairs on curves without associated OIDs.
|
||||
// Specifying a key encoding should not crash.
|
||||
{
|
||||
if (process.versions.openssl >= '1.1.1i') {
|
||||
for (const namedCurve of ['Oakley-EC2N-3', 'Oakley-EC2N-4']) {
|
||||
if (!getCurves().includes(namedCurve))
|
||||
continue;
|
||||
|
||||
const expectedErrorCode =
|
||||
common.hasOpenSSL3 ? 'ERR_OSSL_MISSING_OID' : 'ERR_OSSL_EC_MISSING_OID';
|
||||
const params = {
|
||||
namedCurve,
|
||||
publicKeyEncoding: {
|
||||
format: 'der',
|
||||
type: 'spki'
|
||||
}
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
generateKeyPairSync('ec', params);
|
||||
}, {
|
||||
code: expectedErrorCode
|
||||
});
|
||||
|
||||
generateKeyPair('ec', params, common.mustCall((err) => {
|
||||
assert.strictEqual(err.code, expectedErrorCode);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
32
test/parallel/test-crypto-keygen-no-rsassa-pss-params.js
Normal file
32
test/parallel/test-crypto-keygen-no-rsassa-pss-params.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// 'rsa-pss' should not add a RSASSA-PSS-params sequence by default.
|
||||
// Regression test for: https://github.com/nodejs/node/issues/39936
|
||||
{
|
||||
generateKeyPair('rsa-pss', {
|
||||
modulusLength: 512
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
const expectedKeyDetails = {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n
|
||||
};
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
|
||||
// To allow backporting the fix to versions that do not support
|
||||
// asymmetricKeyDetails for RSA-PSS params, also verify that the exported
|
||||
// AlgorithmIdentifier member of the SubjectPublicKeyInfo has the expected
|
||||
// length of 11 bytes (as opposed to > 11 bytes if node added params).
|
||||
const spki = publicKey.export({ format: 'der', type: 'spki' });
|
||||
assert.strictEqual(spki[3], 11, spki.toString('hex'));
|
||||
}));
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPairSync,
|
||||
} = require('crypto');
|
||||
|
||||
// Test sync key generation with key objects with a non-standard
|
||||
// publicExponent
|
||||
{
|
||||
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
|
||||
publicExponent: 3,
|
||||
modulusLength: 512
|
||||
});
|
||||
|
||||
assert.strictEqual(typeof publicKey, 'object');
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 3n
|
||||
});
|
||||
|
||||
assert.strictEqual(typeof privateKey, 'object');
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 3n
|
||||
});
|
||||
}
|
||||
46
test/parallel/test-crypto-keygen-promisify.js
Normal file
46
test/parallel/test-crypto-keygen-promisify.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
assertApproximateSize,
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
pkcs1PubExp,
|
||||
pkcs1PrivExp,
|
||||
} = require('../common/crypto');
|
||||
const { promisify } = require('util');
|
||||
|
||||
// Test the util.promisified API with async RSA key generation.
|
||||
{
|
||||
promisify(generateKeyPair)('rsa', {
|
||||
publicExponent: 0x10001,
|
||||
modulusLength: 512,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem'
|
||||
}
|
||||
}).then(common.mustCall((keys) => {
|
||||
const { publicKey, privateKey } = keys;
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, pkcs1PubExp);
|
||||
assertApproximateSize(publicKey, 180);
|
||||
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, pkcs1PrivExp);
|
||||
assertApproximateSize(privateKey, 512);
|
||||
|
||||
testEncryptDecrypt(publicKey, privateKey);
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
32
test/parallel/test-crypto-keygen-rfc8017-9-1.js
Normal file
32
test/parallel/test-crypto-keygen-rfc8017-9-1.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// RFC 8017, 9.1.: "Assuming that the mask generation function is based on a
|
||||
// hash function, it is RECOMMENDED that the hash function be the same as the
|
||||
// one that is applied to the message."
|
||||
{
|
||||
|
||||
generateKeyPair('rsa-pss', {
|
||||
modulusLength: 512,
|
||||
hashAlgorithm: 'sha256',
|
||||
saltLength: 16
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
const expectedKeyDetails = {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n,
|
||||
hashAlgorithm: 'sha256',
|
||||
mgf1HashAlgorithm: 'sha256',
|
||||
saltLength: 16
|
||||
};
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
}));
|
||||
}
|
||||
46
test/parallel/test-crypto-keygen-rfc8017-a-2-3.js
Normal file
46
test/parallel/test-crypto-keygen-rfc8017-a-2-3.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
|
||||
// RFC 8017, A.2.3.: "For a given hashAlgorithm, the default value of
|
||||
// saltLength is the octet length of the hash value."
|
||||
{
|
||||
generateKeyPair('rsa-pss', {
|
||||
modulusLength: 512,
|
||||
hashAlgorithm: 'sha512'
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
const expectedKeyDetails = {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n,
|
||||
hashAlgorithm: 'sha512',
|
||||
mgf1HashAlgorithm: 'sha512',
|
||||
saltLength: 64
|
||||
};
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
}));
|
||||
|
||||
// It is still possible to explicitly set saltLength to 0.
|
||||
generateKeyPair('rsa-pss', {
|
||||
modulusLength: 512,
|
||||
hashAlgorithm: 'sha512',
|
||||
saltLength: 0
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
const expectedKeyDetails = {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n,
|
||||
hashAlgorithm: 'sha512',
|
||||
mgf1HashAlgorithm: 'sha512',
|
||||
saltLength: 0
|
||||
};
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, expectedKeyDetails);
|
||||
}));
|
||||
}
|
||||
64
test/parallel/test-crypto-keygen-rsa-pss.js
Normal file
64
test/parallel/test-crypto-keygen-rsa-pss.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
constants,
|
||||
generateKeyPair,
|
||||
} = require('crypto');
|
||||
const {
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// Test RSA-PSS.
|
||||
{
|
||||
generateKeyPair('rsa-pss', {
|
||||
modulusLength: 512,
|
||||
saltLength: 16,
|
||||
hashAlgorithm: 'sha256',
|
||||
mgf1HashAlgorithm: 'sha256'
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa-pss');
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n,
|
||||
hashAlgorithm: 'sha256',
|
||||
mgf1HashAlgorithm: 'sha256',
|
||||
saltLength: 16
|
||||
});
|
||||
|
||||
assert.strictEqual(privateKey.type, 'private');
|
||||
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa-pss');
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, {
|
||||
modulusLength: 512,
|
||||
publicExponent: 65537n,
|
||||
hashAlgorithm: 'sha256',
|
||||
mgf1HashAlgorithm: 'sha256',
|
||||
saltLength: 16
|
||||
});
|
||||
|
||||
// Unlike RSA, RSA-PSS does not allow encryption.
|
||||
assert.throws(() => {
|
||||
testEncryptDecrypt(publicKey, privateKey);
|
||||
}, /operation not supported for this keytype/);
|
||||
|
||||
// RSA-PSS also does not permit signing with PKCS1 padding.
|
||||
assert.throws(() => {
|
||||
testSignVerify({
|
||||
key: publicKey,
|
||||
padding: constants.RSA_PKCS1_PADDING
|
||||
}, {
|
||||
key: privateKey,
|
||||
padding: constants.RSA_PKCS1_PADDING
|
||||
});
|
||||
}, /illegal or unsupported padding mode/);
|
||||
|
||||
// The padding should correctly default to RSA_PKCS1_PSS_PADDING now.
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
47
test/parallel/test-crypto-keygen-sync.js
Normal file
47
test/parallel/test-crypto-keygen-sync.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
generateKeyPairSync,
|
||||
} = require('crypto');
|
||||
const {
|
||||
assertApproximateSize,
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
pkcs1PubExp,
|
||||
pkcs8Exp,
|
||||
} = require('../common/crypto');
|
||||
|
||||
// To make the test faster, we will only test sync key generation once and
|
||||
// with a relatively small key.
|
||||
{
|
||||
const ret = generateKeyPairSync('rsa', {
|
||||
publicExponent: 3,
|
||||
modulusLength: 512,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs8',
|
||||
format: 'pem'
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(Object.keys(ret).length, 2);
|
||||
const { publicKey, privateKey } = ret;
|
||||
|
||||
assert.strictEqual(typeof publicKey, 'string');
|
||||
assert.match(publicKey, pkcs1PubExp);
|
||||
assertApproximateSize(publicKey, 162);
|
||||
assert.strictEqual(typeof privateKey, 'string');
|
||||
assert.match(privateKey, pkcs8Exp);
|
||||
assertApproximateSize(privateKey, 512);
|
||||
|
||||
testEncryptDecrypt(publicKey, privateKey);
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user