Skip to content

DefaultUserInfo empty password hash #64018

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

Merged
merged 3 commits into from
Oct 22, 2020

Conversation

jkakavas
Copy link
Member

Use an empty char array in place of the hash of the empty string
for defaultEnabledReservedUser, defaultDisabledReservedUser and
bootstrapUserInfo ReservedUserInfo objects, when the password is
empty. In these cases, the hasEmptyPassword property is set to
true and so the actual password hash is not ever checked or
verified in ReservedRealm#doAuthenticate so this change has no
functional effect on existing logic. If anything, it is more
consistent with the logic in NativeUsersStore#setReservedUserEnabled
when the user document didn't already exist.
Even if there is / will be code that attempts to verify the hash,
this would still work as intended as Hasher#resolve would resolve
the NOOP Hasher from the empty string and its verify method would
compare the char arrays.

The reason for this change is that when in FIPS 140 approved only
mode, the security provider's implementation of PBKDF2 might
forbid operations when the password is smaller than 112 bits so
the existing implementation would cause elasticsearch to fail.

Use an empty char array in place of the hash of the empty string
for defaultEnabledReservedUser, defaultDisabledReservedUser and
bootstrapUserInfo ReservedUserInfo objects, when the password is
empty. In these cases, the hasEmptyPassword property is set to
true and so the actual password hash is not ever checked or
verified in ReservedRealm#doAuthenticate so this change has no
functional effect on existing logic. If anything, it is more
consistent with the logic in NativeUsersStore#setReservedUserEnabled
when the user document didn't already exist.
Even if there is / will be code that attempts to verify the hash,
this would still work as intended as Hasher#resolve would resolve
the NOOP Hasher from the empty string and its verify method would
compare the char arrays.

The reason for this change is that when in FIPS 140 approved only
mode, the security provider's implementation of PBKDF2 might
forbid operations when the password is smaller than 112 bits so
the existing implementation would cause elasticsearch to fail.
@jkakavas jkakavas added >bug :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) v8.0.0 v7.11.0 labels Oct 21, 2020
@jkakavas jkakavas requested a review from tvernum October 21, 2020 20:12
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security (:Security/Authentication)

@elasticmachine elasticmachine added the Team:Security Meta label for security team label Oct 21, 2020
@@ -697,5 +691,13 @@ ReservedUserInfo deepClone() {
boolean verifyPassword(SecureString data) {
return hasher.verify(data, this.passwordHash);
}

static ReservedUserInfo defaultEnabledUserInfo(){
return new ReservedUserInfo(new char[0], true, true);
Copy link
Member

Choose a reason for hiding this comment

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

With this PR, the empty passwordHash now has a deterministic value, new char[0]. It would be better to remove hasEmptyPassword from the constructor parameters of ReservedUserInfo because it can be safely derived. It is more consistent to derive it than manually passing it into the constructor. We can also replace the hasEmptyPassword field with a method call which internally returns passwordHash.length == 0.

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense, will do

@@ -697,5 +691,13 @@ ReservedUserInfo deepClone() {
boolean verifyPassword(SecureString data) {
return hasher.verify(data, this.passwordHash);
}

static ReservedUserInfo defaultEnabledUserInfo(){
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:

Suggested change
static ReservedUserInfo defaultEnabledUserInfo(){
static ReservedUserInfo defaultEnabledUserInfo() {

@jkakavas jkakavas merged commit 0e0fb73 into elastic:master Oct 22, 2020
jkakavas added a commit to jkakavas/elasticsearch that referenced this pull request Dec 1, 2020
Use an empty char array in place of the hash of the empty string
for defaultEnabledReservedUser, defaultDisabledReservedUser and
bootstrapUserInfo ReservedUserInfo objects, when the password is
empty. In these cases, the hasEmptyPassword property is set to
true and so the actual password hash is not ever checked or
verified in ReservedRealm#doAuthenticate so this change has no
functional effect on existing logic. If anything, it is more
consistent with the logic in NativeUsersStore#setReservedUserEnabled
when the user document didn't already exist.
Even if there is / will be code that attempts to verify the hash,
this would still work as intended as Hasher#resolve would resolve
the NOOP Hasher from the empty string and its verify method would
compare the char arrays.

The reason for this change is that when in FIPS 140 approved only
mode, the security provider's implementation of PBKDF2 might
forbid operations when the password is smaller than 112 bits so
the existing implementation would cause elasticsearch to fail.
jkakavas added a commit that referenced this pull request Dec 1, 2020
Use an empty char array in place of the hash of the empty string
for defaultEnabledReservedUser, defaultDisabledReservedUser and
bootstrapUserInfo ReservedUserInfo objects, when the password is
empty. In these cases, the hasEmptyPassword property is set to
true and so the actual password hash is not ever checked or
verified in ReservedRealm#doAuthenticate so this change has no
functional effect on existing logic. If anything, it is more
consistent with the logic in NativeUsersStore#setReservedUserEnabled
when the user document didn't already exist.
Even if there is / will be code that attempts to verify the hash,
this would still work as intended as Hasher#resolve would resolve
the NOOP Hasher from the empty string and its verify method would
compare the char arrays.

The reason for this change is that when in FIPS 140 approved only
mode, the security provider's implementation of PBKDF2 might
forbid operations when the password is smaller than 112 bits so
the existing implementation would cause elasticsearch to fail.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>bug :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) Team:Security Meta label for security team v7.11.0 v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants