Skip to content

src: fix crypto.privateEncrypt fails first time - #42793

Merged
aduh95 merged 3 commits into
nodejs:mainfrom
liuxingbaoyu:fix-crypto
Oct 29, 2022
Merged

src: fix crypto.privateEncrypt fails first time#42793
aduh95 merged 3 commits into
nodejs:mainfrom
liuxingbaoyu:fix-crypto

Conversation

@liuxingbaoyu

@liuxingbaoyuliuxingbaoyu commented Apr 20, 2022

Copy link
Copy Markdown
Contributor

Fix crypto.privateEncrypt fails for the first time after crypto.generateKeyPairSync with certain parameters

Because the error stack is not cleaned up when crypto.generateKeyPairSync exits.

Fixes: #40814

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/crypto

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. crypto Issues and PRs related to the crypto subsystem. needs-ci PRs that need a full CI run. labels Apr 20, 2022
crypto.privateEncrypt fails for the first time after
crypto.generateKeyPairSync with certain parameters
Because the error stack is not cleaned up
when crypto.generateKeyPairSync exits.
Fixes: nodejs#40814

@tniessentniessen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be interesting to know why some ciphers populate the OpenSSL error queue even though WritePrivateKey appears to succeed.

@@ -0,0 +1,35 @@
'use strict';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please either rename this file to better match what it tests, or add the test case to an existing test file that tests key objects.

Also, please add a comment explaining that this is a regression test for #40814.

@liuxingbaoyu

Copy link
Copy Markdown
ContributorAuthor

indeed! I'm also interested in why the exception is populated.

But I don't know about openssl and I didn't find relevant information on the documentation.

I'll show the stack for anyone with experience to investigate in depth.

Callstack:

node.exe!EVP_CIPHER_get_asn1_iv(evp_cipher_ctx_st * ctx, asn1_type_st * type) 行 56	C
node.exe!evp_cipher_asn1_to_param_ex(evp_cipher_ctx_st * c, asn1_type_st * type, evp_cipher_aead_asn1_params * asn1_params) 行 212	C
node.exe!EVP_CIPHER_asn1_to_param(evp_cipher_ctx_st * c, asn1_type_st * type) 行 42	C
node.exe!PKCS5_v2_PBE_keyivgen_ex(evp_cipher_ctx_st * ctx, const char * pass, int passlen, asn1_type_st * param, const evp_cipher_st * c, const evp_md_st * md, int en_de, ossl_lib_ctx_st * libctx, const char * propq) 行 160	C
node.exe!EVP_PBE_CipherInit_ex(asn1_object_st * pbe_obj, const char * pass, int passlen, asn1_type_st * param, evp_cipher_ctx_st * ctx, int en_de, ossl_lib_ctx_st * libctx, const char * propq) 行 151	C
node.exe!PKCS12_pbe_crypt_ex(const X509_algor_st * algor, const char * pass, int passlen, const unsigned char * in, int inlen, unsigned char * * data, int * datalen, int en_de, ossl_lib_ctx_st * libctx, const char * propq) 行 36	C
node.exe!PKCS12_item_i2d_encrypt_ex(X509_algor_st * algor, const ASN1_ITEM_st * it, const char * pass, int passlen, void * obj, int zbuf, ossl_lib_ctx_st * ctx, const char * propq) 行 189	C
node.exe!PKCS8_set0_pbe_ex(const char * pass, int passlen, pkcs8_priv_key_info_st * p8inf, X509_algor_st * pbe, ossl_lib_ctx_st * ctx, const char * propq) 行 76	C
node.exe!PKCS8_encrypt_ex(int pbe_nid, const evp_cipher_st * cipher, const char * pass, int passlen, unsigned char * salt, int saltlen, int iter, pkcs8_priv_key_info_st * p8inf, ossl_lib_ctx_st * libctx, const char * propq) 行 51	C
node.exe!p8info_to_encp8(pkcs8_priv_key_info_st * p8info, key2any_ctx_st * ctx) 行 120	C
node.exe!key_to_encp8(const void * key, int key_nid, void * params, int params_type, int(*)(const void *, unsigned char * *) k2d, key2any_ctx_st * ctx) 行 136	C
node.exe!key_to_epki_pem_priv_bio(bio_st * out, const void * key, int key_nid, const char * pemname, int(*)(const void *, int, int, void * *, int *) p2s, int(*)(const void *, unsigned char * *) k2d, key2any_ctx_st * ctx) 行 232	C
node.exe!key_to_pki_pem_priv_bio(bio_st * out, const void * key, int key_nid, const char * pemname, int(*)(const void *, int, int, void * *, int *) p2s, int(*)(const void *, unsigned char * *) k2d, key2any_ctx_st * ctx) 行 286	C
node.exe!key2any_encode(key2any_ctx_st * ctx, ossl_core_bio_st * cout, const void * key, int type, const char * pemname, int(*)(const void *, int) checker, int(*)(bio_st *, const void *, int, const char *, int(*)(const void *, int, int, void * *, int *), int(*)(const void *, unsigned char * *), key2any_ctx_st *) writer, int(*)(char *, unsigned __int64, unsigned __int64 *, const ossl_param_st *, void *) pwcb, void * pwcbarg, int(*)(const void *, int, int, void * *, int *) key2paramstring, int(*)(const void *, unsigned char * *) key2der) 行 1054	C
node.exe!rsa_to_PrivateKeyInfo_pem_encode(void * ctx, ossl_core_bio_st * cout, const void * key, const ossl_param_st * key_abstract, int selection, int(*)(char *, unsigned __int64, unsigned __int64 *, const ossl_param_st *, void *) cb, void * cbarg) 行 1350	C
node.exe!encoder_process(encoder_process_data_st * data) 行 635	C
node.exe!OSSL_ENCODER_to_bio(ossl_encoder_ctx_st * ctx, bio_st * out) 行 63	C
node.exe!do_pk8pkey(bio_st * bp, const evp_pkey_st * x, int isder, int nid, const evp_cipher_st * enc, const char * kstr, int klen, int(*)(char *, int, int, void *) cb, void * u, const char * propq) 行 125	C
node.exe!PEM_write_bio_PKCS8PrivateKey(bio_st * bp, const evp_pkey_st * x, const evp_cipher_st * enc, const char * kstr, int klen, int(*)(char *, int, int, void *) cb, void * u) 行 53	C
node.exe!node::crypto::`anonymous namespace'::WritePrivateKey(node::Environment * env, evp_pkey_st * pkey, const node::crypto::PrivateKeyEncodingConfig & config) 行 347	C++
node.exe!node::crypto::ManagedEVPPKey::ToEncodedPrivateKey(node::Environment * env, node::crypto::ManagedEVPPKey key, const node::crypto::PrivateKeyEncodingConfig & config, v8::Local<v8::Value> * out) 行 673	C++
node.exe!node::crypto::KeyPairGenTraits<node::crypto::RsaKeyGenTraits>::EncodeKey(node::Environment * env, node::crypto::KeyPairGenConfig<node::crypto::RsaKeyPairParams> * params, v8::Local<v8::Value> * result) 行 196	C++
node.exe!node::crypto::KeyGenJob<node::crypto::KeyPairGenTraits<node::crypto::RsaKeyGenTraits>>::ToResult(v8::Local<v8::Value> * err, v8::Local<v8::Value> * result) 行 107	C++
node.exe!node::crypto::CryptoJob<node::crypto::KeyPairGenTraits<node::crypto::RsaKeyGenTraits>>::Run(const v8::FunctionCallbackInfo<v8::Value> & args) 行 412	C++
node.exe!v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo handler) 行 153	C++
node.exe!v8::internal::`anonymous namespace'::HandleApiCallHelper<0>(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::HeapObject> function, v8::internal::Handle<v8::internal::HeapObject> new_target, v8::internal::Handle<v8::internal::FunctionTemplateInfo> fun_data, v8::internal::Handle<v8::internal::Object> receiver, v8::internal::BuiltinArguments args) 行 114	C++

@liuxingbaoyu

Copy link
Copy Markdown
ContributorAuthor

Also, do we need to add an assertion or something?

Once any method is called and the error is left, it is easy to affect other methods.

@panvapanva added the request-ci Add this label to start a Jenkins CI on a PR. label Apr 21, 2022
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Apr 21, 2022
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panva

Copy link
Copy Markdown
Member

@liuxingbaoyu I believe there's a consistent failure when using linked OpenSSL 1.1.1

@liuxingbaoyu

Copy link
Copy Markdown
ContributorAuthor

This looks to be another problem with crypto.privateEncrypt, not crypto.generateKeyPairSync.

In openssl3, the error is cleared inside openssl, but not in openssl1.1.1.

I don't know if this is a bug or a behavior change.

Exception source:

ERR_set_mark();ret=pem_read_bio_key_decoder(bp,x,ossl_pw_pem_password,&pwdata,libctx,propq,selection);if(ret==NULL&&(BIO_seek(bp,pos)<0||(ret=pem_read_bio_key_legacy(bp,x,ossl_pw_pem_password,&pwdata,libctx,propq,selection))==NULL))ERR_clear_last_mark();elseERR_pop_to_mark();

// OpenSSL can fail to parse the key but still return a non-null pointer.
unsignedlong err = ERR_peek_error(); // NOLINT(runtime/int)

Also, does anyone know what's the reason here?

@tniessentniessen added the review wanted PRs that need reviews. label Sep 11, 2022
@aduh95

Copy link
Copy Markdown
Contributor

Ping @nodejs/crypto for (re)reviews.

@bnoordhuisbnoordhuis added request-ci Add this label to start a Jenkins CI on a PR. and removed needs-ci PRs that need a full CI run. labels Oct 29, 2022
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Oct 29, 2022
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@aduh95aduh95 added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. needs-ci PRs that need a full CI run. labels Oct 29, 2022
@aduh95aduh95 added commit-queue Add this label to land a pull request using GitHub Actions. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. labels Oct 29, 2022
@nodejs-github-botnodejs-github-bot added commit-queue-failed An error occurred while landing this pull request using GitHub Actions. and removed commit-queue Add this label to land a pull request using GitHub Actions. labels Oct 29, 2022
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator
Commit Queue failed
- Loading data for nodejs/node/pull/42793
FetchError: Invalid response body while trying to fetch https://api.github.com/graphql: Premature close
at consumeBody (file:///opt/hostedtoolcache/node/18.12.0/x64/lib/node_modules/node-core-utils/node_modules/node-fetch/src/body.js:234:60)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Response.text (file:///opt/hostedtoolcache/node/18.12.0/x64/lib/node_modules/node-core-utils/node_modules/node-fetch/src/body.js:158:18)
at async Request.json (file:///opt/hostedtoolcache/node/18.12.0/x64/lib/node_modules/node-core-utils/lib/request.js:51:18)
at async Request.query (file:///opt/hostedtoolcache/node/18.12.0/x64/lib/node_modules/node-core-utils/lib/request.js:109:20)
at async Request.queryAll (file:///opt/hostedtoolcache/node/18.12.0/x64/lib/node_modules/node-core-utils/lib/request.js:136:20)
at async Request.gql (file:///opt/hostedtoolcache/node/18.12.0/x64/lib/node_modules/node-core-utils/lib/request.js:66:22)
at async PRData.getComments (file:///opt/hostedtoolcache/node/18.12.0/x64/lib/node_modules/node-core-utils/lib/pr_data.js:97:21)
at async Promise.all (index 2)
at async Promise.all (index 1) {
type: 'system',
errno: 'ERR_STREAM_PREMATURE_CLOSE',
code: 'ERR_STREAM_PREMATURE_CLOSE',
erroredSysCall: undefined
}
https://github.com/nodejs/node/actions/runs/3352810353

@aduh95
aduh95 merged commit e512786 into nodejs:mainOct 29, 2022
@aduh95

Copy link
Copy Markdown
Contributor

Landed in e512786

@liuxingbaoyu
liuxingbaoyu deleted the fix-crypto branch October 30, 2022 03:45
@liuxingbaoyu
liuxingbaoyu restored the fix-crypto branch October 30, 2022 05:49
RafaelGSS pushed a commit that referenced this pull request Nov 1, 2022
`crypto.privateEncrypt` fails for the first time after
`crypto.generateKeyPairSync` with certain parameters
because the error stack is not cleaned up
when `crypto.generateKeyPairSync` exits.
Fixes: #40814
PR-URL: #42793
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
@RafaelGSSRafaelGSS mentioned this pull request Nov 1, 2022
RafaelGSS pushed a commit that referenced this pull request Nov 10, 2022
`crypto.privateEncrypt` fails for the first time after
`crypto.generateKeyPairSync` with certain parameters
because the error stack is not cleaned up
when `crypto.generateKeyPairSync` exits.
Fixes: #40814
PR-URL: #42793
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
danielleadams pushed a commit that referenced this pull request Dec 30, 2022
`crypto.privateEncrypt` fails for the first time after
`crypto.generateKeyPairSync` with certain parameters
because the error stack is not cleaned up
when `crypto.generateKeyPairSync` exits.
Fixes: #40814
PR-URL: #42793
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
danielleadams pushed a commit that referenced this pull request Jan 3, 2023
`crypto.privateEncrypt` fails for the first time after
`crypto.generateKeyPairSync` with certain parameters
because the error stack is not cleaned up
when `crypto.generateKeyPairSync` exits.
Fixes: #40814
PR-URL: #42793
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs that have at least one approval, no pending requests for changes, and a CI started.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-failedAn error occurred while landing this pull request using GitHub Actions.commit-queue-squashAdd this label to instruct the Commit Queue to squash all the PR commits into the first one.cryptoIssues and PRs related to the crypto subsystem.needs-ciPRs that need a full CI run.review wantedPRs that need reviews.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exception when using privateEncrypt/privateDecrypt with certain encrypted keys

7 participants

@liuxingbaoyu@nodejs-github-bot@panva@aduh95@bnoordhuis@jasnell@tniessen