Skip to content

Commit 3c69d34

Browse files
Validate password hashing algorithm for FIPS (opensearch-project#6126)
Signed-off-by: Terry Quigley <terry.quigley@sas.com>
1 parent 651e72c commit 3c69d34

2 files changed

Lines changed: 113 additions & 0 deletions

File tree

src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,24 @@ private boolean sslCertificatesHotReloadEnabled(final Settings settings) {
357357
return settings.getAsBoolean(SECURITY_SSL_CERTIFICATES_HOT_RELOAD_ENABLED, false);
358358
}
359359

360+
static void validateFipsMode(final String fipsModeEnvValue, final Settings settings) {
361+
if ("true".equalsIgnoreCase(fipsModeEnvValue)) {
362+
String hashingAlgorithm = settings.get(
363+
ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM,
364+
ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM_DEFAULT
365+
);
366+
if (!ConfigConstants.PBKDF2.equalsIgnoreCase(hashingAlgorithm)) {
367+
throw new IllegalStateException(
368+
"FIPS mode is enabled (OPENSEARCH_FIPS_MODE=true) but password hashing algorithm is set to '"
369+
+ hashingAlgorithm
370+
+ "'. Only PBKDF2 is allowed in FIPS mode. Set '"
371+
+ ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM
372+
+ "' to 'pbkdf2'. Note: changing the hashing algorithm requires all existing passwords to be rehashed."
373+
);
374+
}
375+
}
376+
}
377+
360378
public OpenSearchSecurityPlugin(final Settings settings, final Path configPath) {
361379
super(settings, configPath, isDisabled(settings));
362380

@@ -489,6 +507,8 @@ public OpenSearchSecurityPlugin(final Settings settings, final Path configPath)
489507
);
490508
}
491509

510+
validateFipsMode(System.getenv("OPENSEARCH_FIPS_MODE"), settings);
511+
492512
if (!client && !settings.getAsBoolean(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, false)) {
493513
// check for demo certificates
494514
final List<String> files = AccessController.doPrivileged(() -> {
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*
8+
* Modifications Copyright OpenSearch Contributors. See
9+
* GitHub history for details.
10+
*/
11+
12+
package org.opensearch.security;
13+
14+
import org.junit.Test;
15+
16+
import org.opensearch.common.settings.Settings;
17+
import org.opensearch.security.support.ConfigConstants;
18+
19+
import static org.hamcrest.MatcherAssert.assertThat;
20+
import static org.hamcrest.Matchers.containsString;
21+
import static org.junit.Assert.assertThrows;
22+
23+
public class OpenSearchSecurityPluginFIPSValidationTest {
24+
25+
@Test
26+
public void testFipsModeWithDefaultAlgorithmThrows() {
27+
// Default algorithm is bcrypt, which is not FIPS-compliant
28+
Settings settings = Settings.builder().build();
29+
30+
IllegalStateException ex = assertThrows(
31+
IllegalStateException.class,
32+
() -> OpenSearchSecurityPlugin.validateFipsMode("true", settings)
33+
);
34+
assertThat(ex.getMessage(), containsString("FIPS mode is enabled"));
35+
assertThat(ex.getMessage(), containsString("Only PBKDF2 is allowed in FIPS mode"));
36+
assertThat(ex.getMessage(), containsString("changing the hashing algorithm requires all existing passwords to be rehashed"));
37+
}
38+
39+
@Test
40+
public void testFipsModeWithBcryptThrows() {
41+
Settings settings = Settings.builder().put(ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM, "bcrypt").build();
42+
43+
IllegalStateException ex = assertThrows(
44+
IllegalStateException.class,
45+
() -> OpenSearchSecurityPlugin.validateFipsMode("true", settings)
46+
);
47+
assertThat(ex.getMessage(), containsString("bcrypt"));
48+
assertThat(ex.getMessage(), containsString("FIPS mode is enabled"));
49+
}
50+
51+
@Test
52+
public void testFipsModeWithArgon2Throws() {
53+
Settings settings = Settings.builder().put(ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM, "argon2").build();
54+
55+
IllegalStateException ex = assertThrows(
56+
IllegalStateException.class,
57+
() -> OpenSearchSecurityPlugin.validateFipsMode("true", settings)
58+
);
59+
assertThat(ex.getMessage(), containsString("argon2"));
60+
}
61+
62+
@Test
63+
public void testFipsModeWithPbkdf2Succeeds() {
64+
Settings settings = Settings.builder().put(ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM, "pbkdf2").build();
65+
66+
// Should not throw
67+
OpenSearchSecurityPlugin.validateFipsMode("true", settings);
68+
}
69+
70+
@Test
71+
public void testFipsModeWithPbkdf2UpperCaseSucceeds() {
72+
Settings settings = Settings.builder().put(ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM, "PBKDF2").build();
73+
74+
// Should not throw
75+
OpenSearchSecurityPlugin.validateFipsMode("true", settings);
76+
}
77+
78+
@Test
79+
public void testFipsModeDisabledAllowsAnyAlgorithm() {
80+
Settings settings = Settings.builder().put(ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM, "bcrypt").build();
81+
82+
// Should not throw when FIPS mode is not enabled
83+
OpenSearchSecurityPlugin.validateFipsMode("false", settings);
84+
}
85+
86+
@Test
87+
public void testFipsModeNullEnvAllowsAnyAlgorithm() {
88+
Settings settings = Settings.builder().put(ConfigConstants.SECURITY_PASSWORD_HASHING_ALGORITHM, "bcrypt").build();
89+
90+
// Should not throw when env var is null
91+
OpenSearchSecurityPlugin.validateFipsMode(null, settings);
92+
}
93+
}

0 commit comments

Comments
 (0)