Skip to content

Commit

Permalink
crypto: add support for RSA-PSS keys
Browse files Browse the repository at this point in the history
This commit adds support for RSA-PSS keys, including
- KeyObjects of type rsa-pss,
- key pair generation for RSA-PSS, and
- signing and verification using RSA-PSS keys.

PR-URL: #26960
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
  • Loading branch information
tniessen authored and danbev committed Apr 8, 2019
1 parent d834275 commit 969bd1e
Show file tree
Hide file tree
Showing 16 changed files with 535 additions and 89 deletions.
31 changes: 27 additions & 4 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@ passing keys as strings or `Buffer`s due to improved security features.
<!-- YAML
added: v11.6.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/26960
description: Added support for `'rsa-pss'`
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/26786
description: This property now returns `undefined` for KeyObject
Expand All @@ -1142,8 +1145,18 @@ changes:
-->
* {string}

For asymmetric keys, this property represents the type of the embedded key
(`'rsa'`, `'dsa'`, `'ec'`, `'ed25519'`, `'ed448'`, `'x25519'` or `'x448'`).
For asymmetric keys, this property represents the type of the key. Supported key
types are:

* `'rsa'` (OID 1.2.840.113549.1.1.1)
* `'rsa-pss'` (OID 1.2.840.113549.1.1.10)
* `'dsa'` (OID 1.2.840.10040.4.1)
* `'ec'` (OID 1.2.840.10045.2.1)
* `'x25519'` (OID 1.3.101.110)
* `'x448'` (OID 1.3.101.111)
* `'ed25519'` (OID 1.3.101.112)
* `'ed448'` (OID 1.3.101.113)

This property is `undefined` for unrecognized `KeyObject` types and symmetric
keys.

Expand Down Expand Up @@ -1271,6 +1284,9 @@ console.log(verify.verify(publicKey, signature));
<!-- YAML
added: v0.1.92
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/26960
description: This function now supports RSA-PSS keys.
- version: v11.6.0
pr-url: https://github.com/nodejs/node/pull/24234
description: This function now supports key objects.
Expand All @@ -1296,7 +1312,9 @@ object, the following additional properties can be passed:
* `crypto.constants.RSA_PKCS1_PSS_PADDING`

Note that `RSA_PKCS1_PSS_PADDING` will use MGF1 with the same hash function
used to sign the message as specified in section 3.1 of [RFC 4055][].
used to sign the message as specified in section 3.1 of [RFC 4055][], unless
an MGF1 hash function has been specified as part of the key in compliance with
section 3.3 of [RFC 4055][].
* `saltLength`: {integer} - salt length for when padding is
`RSA_PKCS1_PSS_PADDING`. The special value
`crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest
Expand Down Expand Up @@ -1369,6 +1387,9 @@ This can be called many times with new data as it is streamed.
<!-- YAML
added: v0.1.92
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/26960
description: This function now supports RSA-PSS keys.
- version: v11.7.0
pr-url: https://github.com/nodejs/node/pull/25217
description: The key can now be a private key.
Expand All @@ -1395,7 +1416,9 @@ object, the following additional properties can be passed:
* `crypto.constants.RSA_PKCS1_PSS_PADDING`

Note that `RSA_PKCS1_PSS_PADDING` will use MGF1 with the same hash function
used to verify the message as specified in section 3.1 of [RFC 4055][].
used to verify the message as specified in section 3.1 of [RFC 4055][], unless
an MGF1 hash function has been specified as part of the key in compliance with
section 3.3 of [RFC 4055][].
* `saltLength`: {integer} - salt length for when padding is
`RSA_PKCS1_PSS_PADDING`. The special value
`crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest
Expand Down
30 changes: 24 additions & 6 deletions lib/internal/crypto/keygen.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const { AsyncWrap, Providers } = internalBinding('async_wrap');
const {
generateKeyPairRSA,
generateKeyPairRSAPSS,
generateKeyPairDSA,
generateKeyPairEC,
generateKeyPairNid,
Expand Down Expand Up @@ -141,6 +142,7 @@ function check(type, options, callback) {
let impl;
switch (type) {
case 'rsa':
case 'rsa-pss':
{
const { modulusLength } = needOptions();
if (!isUint32(modulusLength))
Expand All @@ -153,10 +155,27 @@ function check(type, options, callback) {
throw new ERR_INVALID_OPT_VALUE('publicExponent', publicExponent);
}

impl = (wrap) => generateKeyPairRSA(modulusLength, publicExponent,
publicFormat, publicType,
privateFormat, privateType,
cipher, passphrase, wrap);
if (type === 'rsa') {
impl = (wrap) => generateKeyPairRSA(modulusLength, publicExponent,
publicFormat, publicType,
privateFormat, privateType,
cipher, passphrase, wrap);
break;
}

const { hash, mgf1Hash, saltLength } = options;
if (hash !== undefined && typeof hash !== 'string')
throw new ERR_INVALID_OPT_VALUE('hash', hash);
if (mgf1Hash !== undefined && typeof mgf1Hash !== 'string')
throw new ERR_INVALID_OPT_VALUE('mgf1Hash', mgf1Hash);
if (saltLength !== undefined && !isUint32(saltLength))
throw new ERR_INVALID_OPT_VALUE('saltLength', saltLength);

impl = (wrap) => generateKeyPairRSAPSS(modulusLength, publicExponent,
hash, mgf1Hash, saltLength,
publicFormat, publicType,
privateFormat, privateType,
cipher, passphrase, wrap);
}
break;
case 'dsa':
Expand Down Expand Up @@ -225,8 +244,7 @@ function check(type, options, callback) {
break;
default:
throw new ERR_INVALID_ARG_VALUE('type', type,
"must be one of 'rsa', 'dsa', 'ec', " +
"'ed25519', 'ed448', 'x25519', 'x448'");
'must be a supported key type');
}

if (options) {
Expand Down
12 changes: 4 additions & 8 deletions lib/internal/crypto/sig.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ const {
signOneShot: _signOneShot,
verifyOneShot: _verifyOneShot
} = internalBinding('crypto');
const {
RSA_PSS_SALTLEN_AUTO,
RSA_PKCS1_PADDING
} = internalBinding('constants').crypto;
const {
getDefaultEncoding,
kHandle,
Expand Down Expand Up @@ -56,14 +52,14 @@ Sign.prototype.update = function update(data, encoding) {
};

function getPadding(options) {
return getIntOption('padding', RSA_PKCS1_PADDING, options);
return getIntOption('padding', options);
}

function getSaltLength(options) {
return getIntOption('saltLength', RSA_PSS_SALTLEN_AUTO, options);
return getIntOption('saltLength', options);
}

function getIntOption(name, defaultValue, options) {
function getIntOption(name, options) {
const value = options[name];
if (value !== undefined) {
if (value === value >> 0) {
Expand All @@ -72,7 +68,7 @@ function getIntOption(name, defaultValue, options) {
throw new ERR_INVALID_OPT_VALUE(name, value);
}
}
return defaultValue;
return undefined;
}

Sign.prototype.sign = function sign(options, encoding) {
Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(crypto_x25519_string, "x25519") \
V(crypto_x448_string, "x448") \
V(crypto_rsa_string, "rsa") \
V(crypto_rsa_pss_string, "rsa-pss") \
V(cwd_string, "cwd") \
V(data_string, "data") \
V(dest_string, "dest") \
Expand Down
Loading

0 comments on commit 969bd1e

Please sign in to comment.