diff options
author | Tobias Nießen <tniessen@tnie.de> | 2018-09-28 23:06:00 +0200 |
---|---|---|
committer | Tobias Nießen <tniessen@tnie.de> | 2018-10-02 11:32:16 +0200 |
commit | 0a1c65079a4bcf76cf4ebf47aa24384f62a022e7 (patch) | |
tree | c85234039de9164e541cca1d9618af9888cccb3c /test/parallel/test-crypto-keygen.js | |
parent | 6117af349041834bfe844d32beeac86152031023 (diff) | |
download | android-node-v8-0a1c65079a4bcf76cf4ebf47aa24384f62a022e7.tar.gz android-node-v8-0a1c65079a4bcf76cf4ebf47aa24384f62a022e7.tar.bz2 android-node-v8-0a1c65079a4bcf76cf4ebf47aa24384f62a022e7.zip |
crypto: add support for PEM-level encryption
This adds support for PEM-level encryption as defined in RFC 1421.
PEM-level encryption is intentionally unsupported for PKCS#8 private
keys since PKCS#8 defines a newer encryption format.
PR-URL: https://github.com/nodejs/node/pull/23151
Refs: https://github.com/nodejs/node/pull/22660
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'test/parallel/test-crypto-keygen.js')
-rw-r--r-- | test/parallel/test-crypto-keygen.js | 78 |
1 files changed, 74 insertions, 4 deletions
diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 08e37e2ac0..af60c662f9 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -47,19 +47,23 @@ function testSignVerify(publicKey, privateKey) { } // Constructs a regular expression for a PEM-encoded key with the given label. -function getRegExpForPEM(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}\n${body}\n${end}\n$`); + 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); // Since our own APIs only accept PEM, not DER, we need to convert DER to PEM // for testing. @@ -137,6 +141,42 @@ function convertDERToPEM(label, der) { testEncryptDecrypt(publicKey, privateKey); testSignVerify(publicKey, privateKey); })); + + // Now do the same with an encrypted private key. + generateKeyPair('rsa', { + publicExponent: 0x10001, + modulusLength: 4096, + publicKeyEncoding: { + type: 'pkcs1', + format: 'der' + }, + privateKeyEncoding: { + type: 'pkcs1', + format: 'pem', + cipher: 'aes-256-cbc', + passphrase: 'secret' + } + }, common.mustCall((err, publicKeyDER, privateKey) => { + assert.ifError(err); + + // The public key is encoded as DER (which is binary) instead of PEM. We + // will still need to convert it to PEM for testing. + assert(Buffer.isBuffer(publicKeyDER)); + const publicKey = convertDERToPEM('RSA PUBLIC KEY', publicKeyDER); + assertApproximateSize(publicKey, 720); + + assert.strictEqual(typeof privateKey, 'string'); + assert(pkcs1EncExp('AES-256-CBC').test(privateKey)); + + // Since the private key is encrypted, signing shouldn't work anymore. + assert.throws(() => { + testSignVerify(publicKey, privateKey); + }, /bad decrypt|asn1 encoding routines/); + + const key = { key: privateKey, passphrase: 'secret' }; + testEncryptDecrypt(publicKey, key); + testSignVerify(publicKey, key); + })); } { @@ -203,6 +243,36 @@ function convertDERToPEM(label, der) { testSignVerify(publicKey, privateKey); })); + + // Do the same 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.mustCall((err, publicKey, privateKey) => { + assert.ifError(err); + + assert.strictEqual(typeof publicKey, 'string'); + assert(spkiExp.test(publicKey)); + assert.strictEqual(typeof privateKey, 'string'); + assert(sec1EncExp('AES-128-CBC').test(privateKey)); + + // Since the private key is encrypted, signing shouldn't work anymore. + assert.throws(() => { + testSignVerify(publicKey, privateKey); + }, /bad decrypt|asn1 encoding routines/); + + testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' }); + })); } { @@ -640,7 +710,7 @@ function convertDERToPEM(label, der) { }); } - // Attempting to encrypt a non-PKCS#8 key. + // Attempting to encrypt a DER-encoded, non-PKCS#8 key. for (const type of ['pkcs1', 'sec1']) { common.expectsError(() => { generateKeyPairSync(type === 'pkcs1' ? 'rsa' : 'ec', { @@ -649,7 +719,7 @@ function convertDERToPEM(label, der) { publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type, - format: 'pem', + format: 'der', cipher: 'aes-128-cbc', passphrase: 'hello' } |