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

Ensure error messages don't leak private key #11523

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Ericson2314
Copy link
Member

Motivation

Since #8766, invalid base64 is rendered in errors, but we don't actually want to show this in the case of an invalid private keys.

Context

#8766

Priorities and Process

Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@@ -14,6 +14,9 @@ private:
const std::string host;
bool fakeSSH;
const std::string keyFile;
/**
* Raw bytes, not Base64 encoding.
*/
const std::string sshPublicHostKey;
Copy link
Member

Choose a reason for hiding this comment

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

If it's raw bytes, then should it really still be std::string and not something like std::vector<u8> or something?

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably, but doing that better would require more changes (because we use std::string in a few places for this) so I think it's best we keep it future work.

Copy link
Member

Choose a reason for hiding this comment

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

I always felt that c++ string is just the same as a std::vector in other languages.

Comment on lines 177 to 185
std::string base64Encode(std::string_view s);
std::string base64Decode(std::string_view s);

/**
* Decode arbitrary bytes to Base64.
*
* @param hideValue Avoid displaying the raw Base64 in error messages,
* e.g. to avoid leaking private keys.
*/
std::string base64Decode(std::string_view s, bool hideValue = false);
Copy link
Member Author

@Ericson2314 Ericson2314 Sep 18, 2024

Choose a reason for hiding this comment

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

@cole-h e.g. these type signatures (strings on both sides) are also not instructive

@Mic92 Mic92 added backport 2.18-maintenance Automatically creates a PR against the branch backport 2.19-maintenance Automatically creates a PR against the branch backport 2.20-maintenance Automatically creates a PR against the branch backport 2.21-maintenance Automatically creates a PR against the branch backport 2.22-maintenance Automatically creates a PR against the branch backport 2.23-maintenance Automatically creates a PR against the branch backport 2.24-maintenance Automatically creates a PR against the branch labels Sep 18, 2024
@@ -220,7 +220,7 @@ std::string base64Encode(std::string_view s)
}


std::string base64Decode(std::string_view s)
std::string base64Decode(std::string_view s, bool hideValue)
Copy link
Member

Choose a reason for hiding this comment

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

is it normal in c++ that the default value only needs to be set in the prototype but not here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. I think it will in fact not let you put it in both places.

* @param hideValue Avoid displaying the raw Base64 in error messages,
* e.g. to avoid leaking private keys.
*/
std::string base64Decode(std::string_view s, bool hideValue = false);
Copy link
Member

@Mic92 Mic92 Sep 18, 2024

Choose a reason for hiding this comment

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

Not a strong opinion but to me this seems more intuitive:

Suggested change
std::string base64Decode(std::string_view s, bool hideValue = false);
std::string base64Decode(std::string_view s, bool sensitiveValue = false);

Copy link
Member Author

Choose a reason for hiding this comment

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

Did the rename

src/libutil/util.hh Outdated Show resolved Hide resolved
Since NixOS#8766, invalid base64 is rendered in errors, but we don't actually
want to show this in the case of an invalid private keys.
@Ericson2314 Ericson2314 force-pushed the base64Decode-no-leak-private-key-on-error branch from 18f855c to d8b3626 Compare September 18, 2024 16:09
Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

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

Still not safe enough, and please add a functional test - see comment.

try {
base64Decode(msg, true);
} catch (FormatError & e) {
EXPECT_THAT(e.msg(), testing::Not(testing::HasSubstr(msg)));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
EXPECT_THAT(e.msg(), testing::Not(testing::HasSubstr(msg)));
EXPECT_THAT(e.msg(), testing::Not(testing::HasSubstr(msg)));
EXPECT_THAT(e.what(), testing::Not(testing::HasSubstr(msg)));

Copy link
Member

Choose a reason for hiding this comment

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

This is still not future proof; please also add a functional test, which will cover the eventuality that yet another method is used for retrieving the message (e.g. something more structured than a string).

* @param sensitiveValue Avoid displaying the raw Base64 in error messages,
* e.g. to avoid leaking private keys.
*/
std::string base64Decode(std::string_view s, bool sensitiveValue = false);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
std::string base64Decode(std::string_view s, bool sensitiveValue = false);
std::string base64Decode(std::string_view s, bool sensitiveValue);

Each caller should just make a decision.

Or, if we disagree, it should fail safely:

Suggested change
std::string base64Decode(std::string_view s, bool sensitiveValue = false);
std::string base64Decode(std::string_view s, bool sensitiveValue = true);

@roberth
Copy link
Member

roberth commented Sep 19, 2024

Add release blocker label because this fixes a minor security regression that's not been released yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport 2.18-maintenance Automatically creates a PR against the branch backport 2.19-maintenance Automatically creates a PR against the branch backport 2.20-maintenance Automatically creates a PR against the branch backport 2.21-maintenance Automatically creates a PR against the branch backport 2.22-maintenance Automatically creates a PR against the branch backport 2.23-maintenance Automatically creates a PR against the branch backport 2.24-maintenance Automatically creates a PR against the branch release-blocker
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants