Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a7d4cad

Browse filesBrowse files
tniessenMylesBorins
authored andcommitted
crypto: add sign/verify support for RSASSA-PSS
Adds support for the PSS padding scheme. Until now, the sign/verify functions used the old EVP_Sign*/EVP_Verify* OpenSSL API, making it impossible to change the padding scheme. Fixed by first computing the message digest and then signing/verifying with a custom EVP_PKEY_CTX, allowing us to specify options such as the padding scheme and the PSS salt length. Fixes: #1127 PR-URL: #11705 Reviewed-By: Shigeki Ohtsu <ohtsu@ohtsu.org> Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent e31ab7c commit a7d4cad
Copy full SHA for a7d4cad

File tree

Expand file treeCollapse file tree

8 files changed

+537
-18
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

8 files changed

+537
-18
lines changed
Open diff view settings
Collapse file

‎doc/api/crypto.md‎

Copy file name to clipboardExpand all lines: doc/api/crypto.md
+57-4Lines changed: 57 additions & 4 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -898,17 +898,32 @@ console.log(sign.sign(privateKey).toString('hex'));
898898
### sign.sign(private_key[, output_format])
899899
<!-- YAML
900900
added: v0.1.92
901+
changes:
902+
- version: REPLACEME
903+
pr-url: https://github.com/nodejs/node/pull/11705
904+
description: Support for RSASSA-PSS and additional options was added.
901905
-->
902906

903907
Calculates the signature on all the data passed through using either
904908
[`sign.update()`][] or [`sign.write()`][stream-writable-write].
905909

906910
The `private_key` argument can be an object or a string. If `private_key` is a
907911
string, it is treated as a raw key with no passphrase. If `private_key` is an
908-
object, it is interpreted as a hash containing two properties:
912+
object, it must contain one or more of the following properties:
909913

910-
* `key`: {string} - PEM encoded private key
914+
* `key`: {string} - PEM encoded private key (required)
911915
* `passphrase`: {string} - passphrase for the private key
916+
* `padding`: {integer} - Optional padding value for RSA, one of the following:
917+
* `crypto.constants.RSA_PKCS1_PADDING` (default)
918+
* `crypto.constants.RSA_PKCS1_PSS_PADDING`
919+
920+
Note that `RSA_PKCS1_PSS_PADDING` will use MGF1 with the same hash function
921+
used to sign the message as specified in section 3.1 of [RFC 4055][].
922+
* `saltLength`: {integer} - salt length for when padding is
923+
`RSA_PKCS1_PSS_PADDING`. The special value
924+
`crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest
925+
size, `crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN` (default) sets it to the
926+
maximum permissible value.
912927

913928
The `output_format` can specify one of `'latin1'`, `'hex'` or `'base64'`. If
914929
`output_format` is provided a string is returned; otherwise a [`Buffer`][] is
@@ -991,11 +1006,33 @@ This can be called many times with new data as it is streamed.
9911006
### verifier.verify(object, signature[, signature_format])
9921007
<!-- YAML
9931008
added: v0.1.92
1009+
changes:
1010+
- version: REPLACEME
1011+
pr-url: https://github.com/nodejs/node/pull/11705
1012+
description: Support for RSASSA-PSS and additional options was added.
9941013
-->
1014+
- `object` {string | Object}
1015+
- `signature` {string | Buffer | Uint8Array}
1016+
- `signature_format` {string}
9951017

9961018
Verifies the provided data using the given `object` and `signature`.
997-
The `object` argument is a string containing a PEM encoded object, which can be
998-
one an RSA public key, a DSA public key, or an X.509 certificate.
1019+
The `object` argument can be either a string containing a PEM encoded object,
1020+
which can be an RSA public key, a DSA public key, or an X.509 certificate,
1021+
or an object with one or more of the following properties:
1022+
1023+
* `key`: {string} - PEM encoded public key (required)
1024+
* `padding`: {integer} - Optional padding value for RSA, one of the following:
1025+
* `crypto.constants.RSA_PKCS1_PADDING` (default)
1026+
* `crypto.constants.RSA_PKCS1_PSS_PADDING`
1027+
1028+
Note that `RSA_PKCS1_PSS_PADDING` will use MGF1 with the same hash function
1029+
used to verify the message as specified in section 3.1 of [RFC 4055][].
1030+
* `saltLength`: {integer} - salt length for when padding is
1031+
`RSA_PKCS1_PSS_PADDING`. The special value
1032+
`crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest
1033+
size, `crypto.constants.RSA_PSS_SALTLEN_AUTO` (default) causes it to be
1034+
determined automatically.
1035+
9991036
The `signature` argument is the previously calculated signature for the data, in
10001037
the `signature_format` which can be `'latin1'`, `'hex'` or `'base64'`.
10011038
If a `signature_format` is specified, the `signature` is expected to be a
@@ -1902,6 +1939,21 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL.
19021939
<td><code>RSA_PKCS1_PSS_PADDING</code></td>
19031940
<td></td>
19041941
</tr>
1942+
<tr>
1943+
<td><code>RSA_PSS_SALTLEN_DIGEST</code></td>
1944+
<td>Sets the salt length for `RSA_PKCS1_PSS_PADDING` to the digest size
1945+
when signing or verifying.</td>
1946+
</tr>
1947+
<tr>
1948+
<td><code>RSA_PSS_SALTLEN_MAX_SIGN</code></td>
1949+
<td>Sets the salt length for `RSA_PKCS1_PSS_PADDING` to the maximum
1950+
permissible value when signing data.</td>
1951+
</tr>
1952+
<tr>
1953+
<td><code>RSA_PSS_SALTLEN_AUTO</code></td>
1954+
<td>Causes the salt length for `RSA_PKCS1_PSS_PADDING` to be determined
1955+
automatically when verifying a signature.</td>
1956+
</tr>
19051957
<tr>
19061958
<td><code>POINT_CONVERSION_COMPRESSED</code></td>
19071959
<td></td>
@@ -1977,6 +2029,7 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL.
19772029
[publicly trusted list of CAs]: https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt
19782030
[RFC 2412]: https://www.rfc-editor.org/rfc/rfc2412.txt
19792031
[RFC 3526]: https://www.rfc-editor.org/rfc/rfc3526.txt
2032+
[RFC 4055]: https://www.rfc-editor.org/rfc/rfc4055.txt
19802033
[stream]: stream.html
19812034
[stream-writable-write]: stream.html#stream_writable_write_chunk_encoding_callback
19822035
[Crypto Constants]: #crypto_crypto_constants_1
Collapse file

‎lib/crypto.js‎

Copy file name to clipboardExpand all lines: lib/crypto.js
+46-3Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,28 @@ Sign.prototype.sign = function sign(options, encoding) {
283283

284284
var key = options.key || options;
285285
var passphrase = options.passphrase || null;
286-
var ret = this._handle.sign(toBuf(key), null, passphrase);
286+
287+
// Options specific to RSA
288+
var rsaPadding = constants.RSA_PKCS1_PADDING;
289+
if (options.hasOwnProperty('padding')) {
290+
if (options.padding === options.padding >> 0) {
291+
rsaPadding = options.padding;
292+
} else {
293+
throw new TypeError('padding must be an integer');
294+
}
295+
}
296+
297+
var pssSaltLength = constants.RSA_PSS_SALTLEN_AUTO;
298+
if (options.hasOwnProperty('saltLength')) {
299+
if (options.saltLength === options.saltLength >> 0) {
300+
pssSaltLength = options.saltLength;
301+
} else {
302+
throw new TypeError('saltLength must be an integer');
303+
}
304+
}
305+
306+
var ret = this._handle.sign(toBuf(key), null, passphrase, rsaPadding,
307+
pssSaltLength);
287308

288309
encoding = encoding || exports.DEFAULT_ENCODING;
289310
if (encoding && encoding !== 'buffer')
@@ -309,9 +330,31 @@ util.inherits(Verify, stream.Writable);
309330
Verify.prototype._write = Sign.prototype._write;
310331
Verify.prototype.update = Sign.prototype.update;
311332

312-
Verify.prototype.verify = function verify(object, signature, sigEncoding) {
333+
Verify.prototype.verify = function verify(options, signature, sigEncoding) {
334+
var key = options.key || options;
313335
sigEncoding = sigEncoding || exports.DEFAULT_ENCODING;
314-
return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding));
336+
337+
// Options specific to RSA
338+
var rsaPadding = constants.RSA_PKCS1_PADDING;
339+
if (options.hasOwnProperty('padding')) {
340+
if (options.padding === options.padding >> 0) {
341+
rsaPadding = options.padding;
342+
} else {
343+
throw new TypeError('padding must be an integer');
344+
}
345+
}
346+
347+
var pssSaltLength = constants.RSA_PSS_SALTLEN_AUTO;
348+
if (options.hasOwnProperty('saltLength')) {
349+
if (options.saltLength === options.saltLength >> 0) {
350+
pssSaltLength = options.saltLength;
351+
} else {
352+
throw new TypeError('saltLength must be an integer');
353+
}
354+
}
355+
356+
return this._handle.verify(toBuf(key), toBuf(signature, sigEncoding), null,
357+
rsaPadding, pssSaltLength);
315358
};
316359

317360
function rsaPublic(method, defaultPadding) {
Collapse file

‎src/node_constants.cc‎

Copy file name to clipboardExpand all lines: src/node_constants.cc
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,18 @@ void DefineOpenSSLConstants(Local<Object> target) {
974974
NODE_DEFINE_CONSTANT(target, RSA_PKCS1_PSS_PADDING);
975975
#endif
976976

977+
#ifdef RSA_PSS_SALTLEN_DIGEST
978+
NODE_DEFINE_CONSTANT(target, RSA_PSS_SALTLEN_DIGEST);
979+
#endif
980+
981+
#ifdef RSA_PSS_SALTLEN_MAX_SIGN
982+
NODE_DEFINE_CONSTANT(target, RSA_PSS_SALTLEN_MAX_SIGN);
983+
#endif
984+
985+
#ifdef RSA_PSS_SALTLEN_AUTO
986+
NODE_DEFINE_CONSTANT(target, RSA_PSS_SALTLEN_AUTO);
987+
#endif
988+
977989
#if HAVE_OPENSSL
978990
// NOTE: These are not defines
979991
NODE_DEFINE_CONSTANT(target, POINT_CONVERSION_COMPRESSED);
Collapse file

‎src/node_constants.h‎

Copy file name to clipboardExpand all lines: src/node_constants.h
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@
77
#include "v8.h"
88

99
#if HAVE_OPENSSL
10+
11+
#ifndef RSA_PSS_SALTLEN_DIGEST
12+
#define RSA_PSS_SALTLEN_DIGEST -1
13+
#endif
14+
15+
#ifndef RSA_PSS_SALTLEN_MAX_SIGN
16+
#define RSA_PSS_SALTLEN_MAX_SIGN -2
17+
#endif
18+
19+
#ifndef RSA_PSS_SALTLEN_AUTO
20+
#define RSA_PSS_SALTLEN_AUTO -2
21+
#endif
22+
1023
#define DEFAULT_CIPHER_LIST_CORE "ECDHE-RSA-AES128-GCM-SHA256:" \
1124
"ECDHE-ECDSA-AES128-GCM-SHA256:" \
1225
"ECDHE-RSA-AES256-GCM-SHA384:" \

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.