Skip to content
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

PEM_read_bio_PrivateKey() pushes multiple errors on the error stack #18110

Closed
RaisinTen opened this issue Apr 14, 2022 · 5 comments
Closed

PEM_read_bio_PrivateKey() pushes multiple errors on the error stack #18110

RaisinTen opened this issue Apr 14, 2022 · 5 comments
Labels
branch: master Merge to master branch branch: 3.0 Merge to openssl-3.0 branch resolved: answered The issue contained a question which has been answered triaged: question The issue contains a question

Comments

@RaisinTen
Copy link
Contributor

In OpenSSL 3, when we use PEM_read_bio_PrivateKey() to read a private key with an empty passphrase, it pushes multiple errors on the stack.

opensslErrorStack: [
  'error:04800068:PEM routines::bad password read',
  'error:07880109:common libcrypto routines::interrupted or cancelled'
]

Is this a bug or is nodejs/node#42400 the right way to handle errors coming from PEM_read_bio_PrivateKey()? Or is there another way to prevent having multiple errors on the stack?

@RaisinTen RaisinTen added the issue: bug report The issue was opened to report a bug label Apr 14, 2022
@t8m t8m added branch: master Merge to master branch triaged: bug The issue/pr is/fixes a bug branch: 3.0 Merge to openssl-3.0 branch and removed issue: bug report The issue was opened to report a bug labels Apr 14, 2022
@t8m
Copy link
Member

t8m commented Apr 14, 2022

If the file really has an empty passphrase, there should not be any errors left on stack after PEM_read_bio_PrivateKey(). However in case the application callback gives an empty passphrase but the key file has some non-empty passphrase, IMO the errors should be present on the stack.

@RaisinTen
Copy link
Contributor Author

RaisinTen commented Apr 14, 2022

The thing we are trying to test is that parsing the private key (which was previously generated with '' as the passphrase) without the passphrase fails with PEM_R_BAD_PASSWORD_READ as the reason for the first error on the stack which happened in OpenSSL 1.1.1 but now in OpenSSL 3, it pushes the other error at the top and the expected one. Is that expected behavior (pushing multiple errors on the stack in one API call)?

@kaduk
Copy link
Contributor

kaduk commented Apr 18, 2022

In short, yes, that is the new expected behavior.
The "decoder" functionality for reading PEM files (among other things) was significantly revamped, and the new scheme allows for chains of component parsers (e.g., base64 plus PKCS#12)) to be assembled, with multiple different chains that could potentially go from the input type to the output type to be attempted. The multiple errors on the stack correspond to the different attemped chains, and it was at least somewhat intentional to choose to leave all the errors on the stack in case of overall failure.

@RaisinTen
Copy link
Contributor Author

@kaduk understood, so this is definitely not a bug, just a question.
In that case, I was wondering if this is the right way of handling errors coming from PEM_read_bio_PrivateKey():

ERR_clear_error();
EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, nullptr, PasswordCallback, passphrase);

unsigned long err = ERR_peek_last_error();
if (err != 0)
  key = NULL;

if (key)
  // Key parsing succeeded.
if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
    ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ) {
  if (passphrase.IsEmpty())
    // Needs passphrase, so handle this error specially by throwing a "Passphrase required for encrypted key" exception.
}
// Key parsing failed, so harvest all the error info from the error stack.

Could we somehow call PEM_read_bio_PrivateKey() differently to avoid multiple errors on the stack?
Is the current technique reliable or could the position of the PEM_R_BAD_PASSWORD_READ error change in the stack in some cases? If it can change, I guess, we would have to loop through all the errors in the stack to check if the PEM_R_BAD_PASSWORD_READ error belongs there? What's your recommendation?

@kaduk
Copy link
Contributor

kaduk commented Apr 21, 2022

I would not recommend relying on the position of the errors on the stack remaining stable over time.
I think (but have not actually checked recently) that using the native decoder APIs directly (rather than via PEM_read_bio_PrivateKey) would produce a scenario with fewer errors on the stack, possibly even being able to get it down to just the single desired error. OSSL_DECODER_CTX_new_for_pkey(3) would be a place to start for reading documentation about that approach.

@kaduk kaduk added triaged: question The issue contains a question resolved: answered The issue contained a question which has been answered and removed triaged: bug The issue/pr is/fixes a bug labels Apr 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
branch: master Merge to master branch branch: 3.0 Merge to openssl-3.0 branch resolved: answered The issue contained a question which has been answered triaged: question The issue contains a question
Projects
None yet
Development

No branches or pull requests

3 participants