-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
crypto: add sign/verify support for RSASSA-PSS #11705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
a361f53
e467227
5a874a5
8a23882
15abaae
d75601e
5e78d9c
5e5f2e4
b9a6779
fcd7053
287e2d6
8dc383e
1679e0c
8b64c04
44b71e9
4f695aa
8772278
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
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
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -961,7 +961,7 @@ pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng== | |
| console.log(sign.sign(privateKey).toString('hex')); | ||
| ``` | ||
|
|
||
| ### sign.sign(private_key[, output_format]) | ||
| ### sign.sign(private_key[, output_format][, options]) | ||
| <!-- YAML | ||
| added: v0.1.92 | ||
| --> | ||
|
|
@@ -984,6 +984,15 @@ The `output_format` can specify one of `'latin1'`, `'hex'` or `'base64'`. If | |
| `output_format` is provided a string is returned; otherwise a [`Buffer`][] is | ||
| returned. | ||
|
|
||
| The optional `options` argument is an object which specifies additional | ||
| cryptographic parameters. Currently, the following options are supported: | ||
|
|
||
| * `padding` : {String} - RSA padding, either `'pkcs1'` for RSASSA-PKCS1-v1_5 | ||
| (default) or `'pss'` for RSASSA-PSS | ||
| * `saltLength` : {number} - salt length for RSASSA-PSS. If this is set to `-1`, | ||
| the salt length will be set to the digest size. If this is set to `-2` | ||
| (default), the salt length will be set to the maximum permissible value. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be nice to have these two values exposed as named constants on
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great, will do so! What is the best way to define a constant which is not
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don’t see any problem with that. :) It’s quite possible that somebody else here comes up with a better suggestion, but for the time being, I’d recommend just doing it the way you just described.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Latest OpenSSL (1.1.1-dev) changes its definitions as
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. named constants would be better, or perhaps strings ( |
||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no descriptions for mgf1 and its hash. The default behavior is that the mgf1 hash is the same as the sign/verify hash. I think it needs to not to add an additional option parameter for mgf1 but its spec should be described in the doc. |
||
| The `Sign` object can not be again used after `sign.sign()` method has been | ||
| called. Multiple calls to `sign.sign()` will result in an error being thrown. | ||
|
|
||
|
|
@@ -1070,7 +1079,7 @@ then `input_encoding` is ignored. | |
|
|
||
| This can be called many times with new data as it is streamed. | ||
|
|
||
| ### verifier.verify(object, signature[, signature_format]) | ||
| ### verifier.verify(object, signature[, signature_format][, options]) | ||
| <!-- YAML | ||
| added: v0.1.92 | ||
| --> | ||
|
|
@@ -1087,6 +1096,16 @@ If a `signature_format` is specified, the `signature` is expected to be a | |
| string; otherwise `signature` is expected to be a [`Buffer`][] or | ||
| `Uint8Array`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @shigeki Yes, I can fix that while landing.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tniessen Actually, can you address this and also add short
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @addaleax Okay, please take care of this with your approval. Thanks. |
||
|
|
||
| The optional `options` argument is an object which specifies additional | ||
| cryptographic parameters. Currently, the following options are supported: | ||
|
|
||
| * `padding` : {String} - RSA padding, either `'pkcs1'` for RSASSA-PKCS1-v1_5 | ||
| (default) or `'pss'` for RSASSA-PSS | ||
| * `saltLength` : {number} - salt length for RSASSA-PSS. If this is set to `-1`, | ||
| the salt length will be set to the digest size. A value of `-2` (default) | ||
| causes the salt length to be automatically determined based on the PSS block | ||
| structure. | ||
|
|
||
| Returns `true` or `false` depending on the validity of the signature for | ||
| the data and public key. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -297,13 +297,18 @@ Sign.prototype._write = function _write(chunk, encoding, callback) { | |
|
|
||
| Sign.prototype.update = Hash.prototype.update; | ||
|
|
||
| Sign.prototype.sign = function sign(options, encoding) { | ||
| if (!options) | ||
| Sign.prototype.sign = function sign(privateKey, encoding, options) { | ||
| if (!privateKey) | ||
| throw new Error('No key provided to sign'); | ||
|
|
||
| var key = options.key || options; | ||
| var passphrase = options.passphrase || null; | ||
| var ret = this._handle.sign(toBuf(key), null, passphrase); | ||
| if (typeof encoding == 'object' && !options) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it does not make a difference when using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, doesn't make a difference, but node style is currently to always use
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if typeof encoding == object, && there are also options, that should be an error |
||
| options = encoding; | ||
| encoding = null; | ||
| } | ||
|
|
||
| var key = privateKey.key || privateKey; | ||
| var passphrase = privateKey.passphrase || null; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about when privateKey is passed in
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this still relevant when changing the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, it would not be, if there is only one options object, there can be no inconsistency between the options allowed in the various options objects |
||
| var ret = this._handle.sign(toBuf(key), null, passphrase, options); | ||
|
|
||
| encoding = encoding || exports.DEFAULT_ENCODING; | ||
| if (encoding && encoding !== 'buffer') | ||
|
|
@@ -329,9 +334,16 @@ util.inherits(Verify, stream.Writable); | |
| Verify.prototype._write = Sign.prototype._write; | ||
| Verify.prototype.update = Sign.prototype.update; | ||
|
|
||
| Verify.prototype.verify = function verify(object, signature, sigEncoding) { | ||
| Verify.prototype.verify = function verify(object, signature, sigEncoding, | ||
| options) { | ||
| if (typeof sigEncoding == 'object' && !options) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
| options = sigEncoding; | ||
| sigEncoding = null; | ||
| } | ||
|
|
||
| sigEncoding = sigEncoding || exports.DEFAULT_ENCODING; | ||
| return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding)); | ||
| return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding), | ||
| null, options); | ||
| }; | ||
|
|
||
| function rsaPublic(method, defaultPadding) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -101,6 +101,7 @@ using v8::HandleScope; | |
| using v8::Integer; | ||
| using v8::Isolate; | ||
| using v8::Local; | ||
| using v8::MaybeLocal; | ||
| using v8::Null; | ||
| using v8::Object; | ||
| using v8::Persistent; | ||
|
|
@@ -3972,6 +3973,41 @@ void SignBase::CheckThrow(SignBase::Error error) { | |
| } | ||
| } | ||
|
|
||
| int SignBase::GetRSAOptions(Environment *env, v8::Local<v8::Object> options, | ||
| int *padding, int *saltlen) { | ||
| Local<Value> key = String::NewFromUtf8(env->isolate(), "padding"); | ||
| MaybeLocal<Value> maybePadding = options->Get(key); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might want to add this to the |
||
| if (!maybePadding.IsEmpty()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considering that I
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In the case where If the property is missing, you’ll get an
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Oh, that makes it clear. I did not know that, sorry! |
||
| Local<Value> paddingValue = maybePadding.ToLocalChecked(); | ||
| if (paddingValue->IsString()) { | ||
| v8::String::Utf8Value paddingUtf8(paddingValue); | ||
| const char *paddingName = *paddingUtf8; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style nit:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually…
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice, must have missed those when I skimmed through the constants. I just noticed that the asymmetric encrypt/decrypt API allows to specify
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sam-github @addaleax @bnoordhuis Thoughts on this? I have no problem keeping it as it is, with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it should be like publicEncrypt, etc, with |
||
| if (strcmp(paddingName, "pkcs1") == 0) { | ||
| *padding = RSA_PKCS1_PADDING; | ||
| } | ||
| else if (strcmp(paddingName, "pss") == 0) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lint error. |
||
| *padding = RSA_PKCS1_PSS_PADDING; | ||
| } | ||
| else { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style nit:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto. |
||
| env->ThrowError("Padding must be 'pkcs1' or 'pss'"); | ||
| return 0; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (*padding == RSA_PKCS1_PSS_PADDING) { | ||
| key = String::NewFromUtf8(env->isolate(), "saltLength"); | ||
| MaybeLocal<Value> maybeSaltlen = options->Get(key); | ||
| if (!maybeSaltlen.IsEmpty()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto, |
||
| Local<Value> saltlenValue = maybeSaltlen.ToLocalChecked(); | ||
| if (saltlenValue->IsNumber()) { | ||
| *saltlen = saltlenValue->Int32Value(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return 1; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
@@ -4001,7 +4037,7 @@ SignBase::Error Sign::SignInit(const char* sign_type) { | |
| return kSignUnknownDigest; | ||
|
|
||
| EVP_MD_CTX_init(&mdctx_); | ||
| if (!EVP_SignInit_ex(&mdctx_, md, nullptr)) | ||
| if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) | ||
| return kSignInit; | ||
| initialised_ = true; | ||
|
|
||
|
|
@@ -4028,7 +4064,7 @@ void Sign::SignInit(const FunctionCallbackInfo<Value>& args) { | |
| SignBase::Error Sign::SignUpdate(const char* data, int len) { | ||
| if (!initialised_) | ||
| return kSignNotInitialised; | ||
| if (!EVP_SignUpdate(&mdctx_, data, len)) | ||
| if (!EVP_DigestUpdate(&mdctx_, data, len)) | ||
| return kSignUpdate; | ||
| return kSignOk; | ||
| } | ||
|
|
@@ -4058,12 +4094,59 @@ void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args) { | |
| sign->CheckThrow(err); | ||
| } | ||
|
|
||
| static int Node_SignFinal(EVP_MD_CTX *mdctx, unsigned char *md, unsigned int *s, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| EVP_PKEY *pkey, int padding, int pss_saltlen) { | ||
| unsigned char m[EVP_MAX_MD_SIZE]; | ||
| unsigned int m_len; | ||
| int i = 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this isn't an index, node_crypto.cc usually calls this usage |
||
| EVP_PKEY_CTX *pkctx = nullptr; | ||
|
|
||
| *s = 0; | ||
| if (!EVP_DigestFinal_ex(mdctx, &(m[0]), &m_len)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’d personally prefer just |
||
| goto err; | ||
|
|
||
| if (mdctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) { | ||
| size_t sltmp = (size_t)EVP_PKEY_size(pkey); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style nit:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This causes s cross initialization error during build. Move its definition before goto. ../src/node_crypto.cc: In function ‘int node::crypto::Node_SignFinal(EVP_MD_CTX*, unsigned char*, unsigned int*, EVP_PKEY*, int, int)’:
../src/node_crypto.cc:4109:4: error: jump to label ‘err’ [-fpermissive]
err:
^
../src/node_crypto.cc:4086:10: note: from here
goto err;
^
../src/node_crypto.cc:4089:12: note: crosses initialization of ‘size_t sltmp’
size_t sltmp = (size_t)EVP_PKEY_size(pkey);
^ |
||
| i = 0; | ||
| pkctx = EVP_PKEY_CTX_new(pkey, nullptr); | ||
| if (!pkctx) | ||
| goto err; | ||
| if (EVP_PKEY_sign_init(pkctx) <= 0) | ||
| goto err; | ||
| if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA2) { | ||
| if (EVP_PKEY_CTX_set_rsa_padding(pkctx, padding) <= 0) | ||
| goto err; | ||
| if (padding == RSA_PKCS1_PSS_PADDING) | ||
| if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, pss_saltlen) <= 0) | ||
| goto err; | ||
| } | ||
| if (EVP_PKEY_CTX_set_signature_md(pkctx, mdctx->digest) <= 0) | ||
| goto err; | ||
| if (EVP_PKEY_sign(pkctx, md, &sltmp, m, m_len) <= 0) | ||
| goto err; | ||
| *s = sltmp; | ||
| i = 1; | ||
| err: | ||
| EVP_PKEY_CTX_free(pkctx); | ||
| return i; | ||
| } | ||
|
|
||
| if (!mdctx->digest->sign) { | ||
| EVPerr(EVP_F_EVP_SIGNFINAL, EVP_R_NO_SIGN_FUNCTION_CONFIGURED); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would this be a bug in our javascript layer, defensively being checked for in the binding layer, or is it something that happens occaisonally?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I know, this can occur if a hash algorithm is used that does not support signing. When signing with RSA etc., this code will not even be reached (
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good to add a test for this, if its possible to reach from calling the js API. If not, defensive code is still good. |
||
| return 0; | ||
| } | ||
|
|
||
| return (mdctx->digest->sign(mdctx->digest->type, m, m_len, md, s, | ||
| pkey->pkey.ptr)); | ||
| } | ||
|
|
||
| SignBase::Error Sign::SignFinal(const char* key_pem, | ||
| int key_pem_len, | ||
| const char* passphrase, | ||
| unsigned char** sig, | ||
| unsigned int *sig_len) { | ||
| unsigned int *sig_len, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pre-existing, but can you move the |
||
| int padding, | ||
| int saltlen) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if (!initialised_) | ||
| return kSignNotInitialised; | ||
|
|
||
|
|
@@ -4109,7 +4192,7 @@ SignBase::Error Sign::SignFinal(const char* key_pem, | |
| } | ||
| #endif // NODE_FIPS_MODE | ||
|
|
||
| if (EVP_SignFinal(&mdctx_, *sig, sig_len, pkey)) | ||
| if (Node_SignFinal(&mdctx_, *sig, sig_len, pkey, padding, saltlen)) | ||
| fatal = false; | ||
|
|
||
| initialised_ = false; | ||
|
|
@@ -4152,6 +4235,12 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) { | |
| size_t buf_len = Buffer::Length(args[0]); | ||
| char* buf = Buffer::Data(args[0]); | ||
|
|
||
| int padding = RSA_PKCS1_PADDING; | ||
| int saltlen = -2; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mh, sorry if I wasn’t clear, but my idea was that you could add |
||
| if (len >= 4 && args[3]->IsObject()) { | ||
| sign->GetRSAOptions(env, Local<Object>::Cast(args[3]), &padding, &saltlen); | ||
| } | ||
|
|
||
| md_len = 8192; // Maximum key size is 8192 bits | ||
| md_value = new unsigned char[md_len]; | ||
|
|
||
|
|
@@ -4163,7 +4252,9 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) { | |
| buf_len, | ||
| len >= 3 && !args[2]->IsNull() ? *passphrase : nullptr, | ||
| &md_value, | ||
| &md_len); | ||
| &md_len, | ||
| padding, | ||
| saltlen); | ||
| if (err != kSignOk) { | ||
| delete[] md_value; | ||
| md_value = nullptr; | ||
|
|
@@ -4207,7 +4298,7 @@ SignBase::Error Verify::VerifyInit(const char* verify_type) { | |
| return kSignUnknownDigest; | ||
|
|
||
| EVP_MD_CTX_init(&mdctx_); | ||
| if (!EVP_VerifyInit_ex(&mdctx_, md, nullptr)) | ||
| if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) | ||
| return kSignInit; | ||
| initialised_ = true; | ||
|
|
||
|
|
@@ -4235,7 +4326,7 @@ SignBase::Error Verify::VerifyUpdate(const char* data, int len) { | |
| if (!initialised_) | ||
| return kSignNotInitialised; | ||
|
|
||
| if (!EVP_VerifyUpdate(&mdctx_, data, len)) | ||
| if (!EVP_DigestUpdate(&mdctx_, data, len)) | ||
| return kSignUpdate; | ||
|
|
||
| return kSignOk; | ||
|
|
@@ -4271,6 +4362,8 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, | |
| int key_pem_len, | ||
| const char* sig, | ||
| int siglen, | ||
| int padding, | ||
| int saltlen, | ||
| bool* verify_result) { | ||
| if (!initialised_) | ||
| return kSignNotInitialised; | ||
|
|
@@ -4282,7 +4375,10 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, | |
| BIO* bp = nullptr; | ||
| X509* x509 = nullptr; | ||
| bool fatal = true; | ||
| unsigned char m[EVP_MAX_MD_SIZE]; | ||
| unsigned int m_len; | ||
| int r = 0; | ||
| EVP_PKEY_CTX *pkctx = nullptr; | ||
|
|
||
| bp = BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len); | ||
| if (bp == nullptr) | ||
|
|
@@ -4317,11 +4413,35 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, | |
| goto exit; | ||
| } | ||
|
|
||
| if (!EVP_DigestFinal_ex(&mdctx_, m, &m_len)) { | ||
| goto exit; | ||
| } | ||
|
|
||
| fatal = false; | ||
| r = EVP_VerifyFinal(&mdctx_, | ||
| reinterpret_cast<const unsigned char*>(sig), | ||
| siglen, | ||
| pkey); | ||
|
|
||
| pkctx = EVP_PKEY_CTX_new(pkey, nullptr); | ||
| if (!pkctx) | ||
| goto err; | ||
| if (EVP_PKEY_verify_init(pkctx) <= 0) | ||
| goto err; | ||
| if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA2) { | ||
| if (EVP_PKEY_CTX_set_rsa_padding(pkctx, padding) <= 0) | ||
| goto err; | ||
| if (padding == RSA_PKCS1_PSS_PADDING) | ||
| if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) <= 0) | ||
| goto err; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style nit: can you add |
||
| } | ||
| if (EVP_PKEY_CTX_set_signature_md(pkctx, mdctx_.digest) <= 0) | ||
| goto err; | ||
| r = EVP_PKEY_verify(pkctx, | ||
| reinterpret_cast<const unsigned char*>(sig), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. node_crypto.cc is a bit schismatic, but style is either to have all the args aligned four spaces from start of line, or to align |
||
| siglen, | ||
| m, | ||
| m_len); | ||
| fatal = false; | ||
|
|
||
| err: | ||
| EVP_PKEY_CTX_free(pkctx); | ||
|
|
||
| exit: | ||
| if (pkey != nullptr) | ||
|
|
@@ -4377,8 +4497,15 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) { | |
| hbuf = Buffer::Data(args[1]); | ||
| } | ||
|
|
||
| int padding = RSA_PKCS1_PADDING; | ||
| int saltlen = -2; | ||
| if (args.Length() >= 4 && args[3]->IsObject()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fwiw you don’t need the |
||
| verify->GetRSAOptions(env, args[3]->ToObject(), &padding, &saltlen); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forgot to comment … can you check the return value here and return from the function if there was an error? |
||
| } | ||
|
|
||
| bool verify_result; | ||
| Error err = verify->VerifyFinal(kbuf, klen, hbuf, hlen, &verify_result); | ||
| Error err = verify->VerifyFinal(kbuf, klen, hbuf, hlen, padding, saltlen, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| &verify_result); | ||
| if (args[1]->IsString()) | ||
| delete[] hbuf; | ||
| if (err != kSignOk) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -577,6 +577,8 @@ class SignBase : public BaseObject { | |
|
|
||
| protected: | ||
| void CheckThrow(Error error); | ||
| int GetRSAOptions(Environment *env, v8::Local<v8::Object> options, | ||
| int *padding, int *saltlen); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| EVP_MD_CTX mdctx_; /* coverity[member_decl] */ | ||
| bool initialised_; | ||
|
|
@@ -592,7 +594,9 @@ class Sign : public SignBase { | |
| int key_pem_len, | ||
| const char* passphrase, | ||
| unsigned char** sig, | ||
| unsigned int *sig_len); | ||
| unsigned int *sig_len, | ||
| int padding, | ||
| int saltlen); | ||
|
|
||
| protected: | ||
| static void New(const v8::FunctionCallbackInfo<v8::Value>& args); | ||
|
|
@@ -615,6 +619,8 @@ class Verify : public SignBase { | |
| int key_pem_len, | ||
| const char* sig, | ||
| int siglen, | ||
| int padding, | ||
| int saltlen, | ||
| bool* verify_result); | ||
|
|
||
| protected: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you use lowercase
stringhere and drop the space before the:?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but note that the rest of the document seems to use the uppercase variant and has a space before the colon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tniessen Thanks for pointing that out – we’re moving to consistenly using lowercase in #11697, so it would be good if this PR was in line with that. I’ll comment that I’d prefer to have the space before the colon dropped there, too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that an options object is introduced, it seems the current positional parameter,
output_format, should be possible to express as an option.encodingwould be the more common name for it, I think.