Skip to content

Commit 969bd1e

Browse files
tniessendanbev
authored andcommitted
crypto: add support for RSA-PSS keys
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 <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]>
1 parent d834275 commit 969bd1e

16 files changed

+535
-89
lines changed

doc/api/crypto.md

+27-4
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,9 @@ passing keys as strings or `Buffer`s due to improved security features.
11291129
<!-- YAML
11301130
added: v11.6.0
11311131
changes:
1132+
- version: REPLACEME
1133+
pr-url: https://github.com/nodejs/node/pull/26960
1134+
description: Added support for `'rsa-pss'`
11321135
- version: REPLACEME
11331136
pr-url: https://github.com/nodejs/node/pull/26786
11341137
description: This property now returns `undefined` for KeyObject
@@ -1142,8 +1145,18 @@ changes:
11421145
-->
11431146
* {string}
11441147

1145-
For asymmetric keys, this property represents the type of the embedded key
1146-
(`'rsa'`, `'dsa'`, `'ec'`, `'ed25519'`, `'ed448'`, `'x25519'` or `'x448'`).
1148+
For asymmetric keys, this property represents the type of the key. Supported key
1149+
types are:
1150+
1151+
* `'rsa'` (OID 1.2.840.113549.1.1.1)
1152+
* `'rsa-pss'` (OID 1.2.840.113549.1.1.10)
1153+
* `'dsa'` (OID 1.2.840.10040.4.1)
1154+
* `'ec'` (OID 1.2.840.10045.2.1)
1155+
* `'x25519'` (OID 1.3.101.110)
1156+
* `'x448'` (OID 1.3.101.111)
1157+
* `'ed25519'` (OID 1.3.101.112)
1158+
* `'ed448'` (OID 1.3.101.113)
1159+
11471160
This property is `undefined` for unrecognized `KeyObject` types and symmetric
11481161
keys.
11491162

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

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

13971418
Note that `RSA_PKCS1_PSS_PADDING` will use MGF1 with the same hash function
1398-
used to verify the message as specified in section 3.1 of [RFC 4055][].
1419+
used to verify the message as specified in section 3.1 of [RFC 4055][], unless
1420+
an MGF1 hash function has been specified as part of the key in compliance with
1421+
section 3.3 of [RFC 4055][].
13991422
* `saltLength`: {integer} - salt length for when padding is
14001423
`RSA_PKCS1_PSS_PADDING`. The special value
14011424
`crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest

lib/internal/crypto/keygen.js

+24-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const { AsyncWrap, Providers } = internalBinding('async_wrap');
44
const {
55
generateKeyPairRSA,
6+
generateKeyPairRSAPSS,
67
generateKeyPairDSA,
78
generateKeyPairEC,
89
generateKeyPairNid,
@@ -141,6 +142,7 @@ function check(type, options, callback) {
141142
let impl;
142143
switch (type) {
143144
case 'rsa':
145+
case 'rsa-pss':
144146
{
145147
const { modulusLength } = needOptions();
146148
if (!isUint32(modulusLength))
@@ -153,10 +155,27 @@ function check(type, options, callback) {
153155
throw new ERR_INVALID_OPT_VALUE('publicExponent', publicExponent);
154156
}
155157

156-
impl = (wrap) => generateKeyPairRSA(modulusLength, publicExponent,
157-
publicFormat, publicType,
158-
privateFormat, privateType,
159-
cipher, passphrase, wrap);
158+
if (type === 'rsa') {
159+
impl = (wrap) => generateKeyPairRSA(modulusLength, publicExponent,
160+
publicFormat, publicType,
161+
privateFormat, privateType,
162+
cipher, passphrase, wrap);
163+
break;
164+
}
165+
166+
const { hash, mgf1Hash, saltLength } = options;
167+
if (hash !== undefined && typeof hash !== 'string')
168+
throw new ERR_INVALID_OPT_VALUE('hash', hash);
169+
if (mgf1Hash !== undefined && typeof mgf1Hash !== 'string')
170+
throw new ERR_INVALID_OPT_VALUE('mgf1Hash', mgf1Hash);
171+
if (saltLength !== undefined && !isUint32(saltLength))
172+
throw new ERR_INVALID_OPT_VALUE('saltLength', saltLength);
173+
174+
impl = (wrap) => generateKeyPairRSAPSS(modulusLength, publicExponent,
175+
hash, mgf1Hash, saltLength,
176+
publicFormat, publicType,
177+
privateFormat, privateType,
178+
cipher, passphrase, wrap);
160179
}
161180
break;
162181
case 'dsa':
@@ -225,8 +244,7 @@ function check(type, options, callback) {
225244
break;
226245
default:
227246
throw new ERR_INVALID_ARG_VALUE('type', type,
228-
"must be one of 'rsa', 'dsa', 'ec', " +
229-
"'ed25519', 'ed448', 'x25519', 'x448'");
247+
'must be a supported key type');
230248
}
231249

232250
if (options) {

lib/internal/crypto/sig.js

+4-8
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ const {
1212
signOneShot: _signOneShot,
1313
verifyOneShot: _verifyOneShot
1414
} = internalBinding('crypto');
15-
const {
16-
RSA_PSS_SALTLEN_AUTO,
17-
RSA_PKCS1_PADDING
18-
} = internalBinding('constants').crypto;
1915
const {
2016
getDefaultEncoding,
2117
kHandle,
@@ -56,14 +52,14 @@ Sign.prototype.update = function update(data, encoding) {
5652
};
5753

5854
function getPadding(options) {
59-
return getIntOption('padding', RSA_PKCS1_PADDING, options);
55+
return getIntOption('padding', options);
6056
}
6157

6258
function getSaltLength(options) {
63-
return getIntOption('saltLength', RSA_PSS_SALTLEN_AUTO, options);
59+
return getIntOption('saltLength', options);
6460
}
6561

66-
function getIntOption(name, defaultValue, options) {
62+
function getIntOption(name, options) {
6763
const value = options[name];
6864
if (value !== undefined) {
6965
if (value === value >> 0) {
@@ -72,7 +68,7 @@ function getIntOption(name, defaultValue, options) {
7268
throw new ERR_INVALID_OPT_VALUE(name, value);
7369
}
7470
}
75-
return defaultValue;
71+
return undefined;
7672
}
7773

7874
Sign.prototype.sign = function sign(options, encoding) {

src/env.h

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
161161
V(crypto_x25519_string, "x25519") \
162162
V(crypto_x448_string, "x448") \
163163
V(crypto_rsa_string, "rsa") \
164+
V(crypto_rsa_pss_string, "rsa-pss") \
164165
V(cwd_string, "cwd") \
165166
V(data_string, "data") \
166167
V(dest_string, "dest") \

0 commit comments

Comments
 (0)