passwordSupplier)
- throws GeneralSecurityException, IOException {
- byte[] keyBytes = Base64.getDecoder().decode(keyContents);
- String procType = pemHeaders.get("Proc-Type");
- if ("4,ENCRYPTED".equals(procType)) {
- // We only handle PEM encryption
- String encryptionParameters = pemHeaders.get("DEK-Info");
- if (null == encryptionParameters) {
- // malformed pem
- throw new IOException("Malformed PEM File, DEK-Info header is missing");
- }
- char[] password = passwordSupplier.get();
- if (password == null) {
- throw new IOException("cannot read encrypted key without a password");
+ throw new SslConfigException(
+ String.format(
+ Locale.ROOT,
+ "error parsing private key [%s], invalid encrypted private key class: [%s]",
+ keyPath.toAbsolutePath(),
+ object.getClass().getName()
+ )
+ );
}
- Cipher cipher = getCipherFromParameters(encryptionParameters, password);
- byte[] decryptedKeyBytes = cipher.doFinal(keyBytes);
- return decryptedKeyBytes;
}
- return keyBytes;
}
/**
- * Creates a {@link Cipher} from the contents of the DEK-Info header of a PEM file. RFC 1421 indicates that supported algorithms are
- * defined in RFC 1423. RFC 1423 only defines DES-CBS and triple DES (EDE) in CBC mode. AES in CBC mode is also widely used though ( 3
- * different variants of 128, 192, 256 bit keys )
+ * Supports PEM files that includes parameters.
*
- * @param dekHeaderValue The value of the DEK-Info PEM header
- * @param password The password with which the key is encrypted
- * @return a cipher of the appropriate algorithm and parameters to be used for decryption
- * @throws GeneralSecurityException if the algorithm is not available in the used security provider, or if the key is inappropriate
- * for the cipher
- * @throws IOException if the DEK-Info PEM header is invalid
- */
- private static Cipher getCipherFromParameters(String dekHeaderValue, char[] password) throws GeneralSecurityException, IOException {
- final String padding = "PKCS5Padding";
- final SecretKey encryptionKey;
- final String[] valueTokens = dekHeaderValue.split(",");
- if (valueTokens.length != 2) {
- throw new IOException("Malformed PEM file, DEK-Info PEM header is invalid");
- }
- final String algorithm = valueTokens[0];
- final String ivString = valueTokens[1];
- final byte[] iv;
- try {
- iv = hexStringToByteArray(ivString);
- } catch (IllegalArgumentException e) {
- throw new IOException("Malformed PEM file, DEK-Info IV is invalid", e);
- }
- if ("DES-CBC".equals(algorithm)) {
- byte[] key = generateOpenSslKey(password, iv, 8);
- encryptionKey = new SecretKeySpec(key, "DES");
- } else if ("DES-EDE3-CBC".equals(algorithm)) {
- byte[] key = generateOpenSslKey(password, iv, 24);
- encryptionKey = new SecretKeySpec(key, "DESede");
- } else if ("AES-128-CBC".equals(algorithm)) {
- byte[] key = generateOpenSslKey(password, iv, 16);
- encryptionKey = new SecretKeySpec(key, "AES");
- } else if ("AES-192-CBC".equals(algorithm)) {
- byte[] key = generateOpenSslKey(password, iv, 24);
- encryptionKey = new SecretKeySpec(key, "AES");
- } else if ("AES-256-CBC".equals(algorithm)) {
- byte[] key = generateOpenSslKey(password, iv, 32);
- encryptionKey = new SecretKeySpec(key, "AES");
- } else {
- throw new GeneralSecurityException("Private Key encrypted with unsupported algorithm [" + algorithm + "]");
- }
- String transformation = encryptionKey.getAlgorithm() + "/" + "CBC" + "/" + padding;
- Cipher cipher = Cipher.getInstance(transformation);
- cipher.init(Cipher.DECRYPT_MODE, encryptionKey, new IvParameterSpec(iv));
- return cipher;
- }
-
- /**
- * Performs key stretching in the same manner that OpenSSL does. This is basically a KDF
- * that uses n rounds of salted MD5 (as many times as needed to get the necessary number of key bytes)
- *
- * https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_PrivateKey_traditional.html
- */
- private static byte[] generateOpenSslKey(char[] password, byte[] salt, int keyLength) {
- byte[] passwordBytes = CharArrays.toUtf8Bytes(password);
- MessageDigest md5 = SslUtil.messageDigest("md5");
- byte[] key = new byte[keyLength];
- int copied = 0;
- int remaining;
- while (copied < keyLength) {
- remaining = keyLength - copied;
- md5.update(passwordBytes, 0, passwordBytes.length);
- md5.update(salt, 0, 8);// AES IV (salt) is longer but we only need 8 bytes
- byte[] tempDigest = md5.digest();
- int bytesToCopy = (remaining > 16) ? 16 : remaining; // MD5 digests are 16 bytes
- System.arraycopy(tempDigest, 0, key, copied, bytesToCopy);
- copied += bytesToCopy;
- if (remaining == 0) {
- break;
- }
- md5.update(tempDigest, 0, 16); // use previous round digest as IV
- }
- Arrays.fill(passwordBytes, (byte) 0);
- return key;
- }
-
- /**
- * Converts a hexadecimal string to a byte array
- */
- private static byte[] hexStringToByteArray(String hexString) {
- int len = hexString.length();
- if (len % 2 == 0) {
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- final int k = Character.digit(hexString.charAt(i), 16);
- final int l = Character.digit(hexString.charAt(i + 1), 16);
- if (k == -1 || l == -1) {
- throw new IllegalStateException("String [" + hexString + "] is not hexadecimal");
+ * @return high-level Object from the content
+ */
+ private static Object readObject(Path keyPath, PEMParser pemParser) throws IOException {
+ while (pemParser.ready()) {
+ try {
+ var object = pemParser.readObject();
+ if (object == null) { // ignore unknown objects;
+ continue;
}
- data[i / 2] = (byte) ((k << 4) + l);
- }
- return data;
- } else {
- throw new IllegalStateException(
- "Hexadecimal string [" + hexString + "] has odd length and cannot be converted to a byte array"
- );
- }
- }
-
- /**
- * Parses a DER encoded EC key to an {@link ECPrivateKeySpec} using a minimal {@link DerParser}
- *
- * @param keyBytes the private key raw bytes
- * @return {@link ECPrivateKeySpec}
- * @throws IOException if the DER encoded key can't be parsed
- */
- private static ECPrivateKeySpec parseEcDer(byte[] keyBytes) throws IOException, GeneralSecurityException {
- DerParser parser = new DerParser(keyBytes);
- DerParser.Asn1Object sequence = parser.readAsn1Object();
- parser = sequence.getParser();
- parser.readAsn1Object().getInteger(); // version
- String keyHex = parser.readAsn1Object().getString();
- BigInteger privateKeyInt = new BigInteger(keyHex, 16);
- DerParser.Asn1Object choice = parser.readAsn1Object();
- parser = choice.getParser();
- String namedCurve = getEcCurveNameFromOid(parser.readAsn1Object().getOid());
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
- AlgorithmParameterSpec algorithmParameterSpec = new ECGenParameterSpec(namedCurve);
- keyPairGenerator.initialize(algorithmParameterSpec);
- ECParameterSpec parameterSpec = ((ECKey) keyPairGenerator.generateKeyPair().getPrivate()).getParams();
- return new ECPrivateKeySpec(privateKeyInt, parameterSpec);
- }
-
- /**
- * Parses a DER encoded RSA key to a {@link RSAPrivateCrtKeySpec} using a minimal {@link DerParser}
- *
- * @param keyBytes the private key raw bytes
- * @return {@link RSAPrivateCrtKeySpec}
- * @throws IOException if the DER encoded key can't be parsed
- */
- private static RSAPrivateCrtKeySpec parseRsaDer(byte[] keyBytes) throws IOException {
- DerParser parser = new DerParser(keyBytes);
- DerParser.Asn1Object sequence = parser.readAsn1Object();
- parser = sequence.getParser();
- parser.readAsn1Object().getInteger(); // (version) We don't need it but must read to get to modulus
- BigInteger modulus = parser.readAsn1Object().getInteger();
- BigInteger publicExponent = parser.readAsn1Object().getInteger();
- BigInteger privateExponent = parser.readAsn1Object().getInteger();
- BigInteger prime1 = parser.readAsn1Object().getInteger();
- BigInteger prime2 = parser.readAsn1Object().getInteger();
- BigInteger exponent1 = parser.readAsn1Object().getInteger();
- BigInteger exponent2 = parser.readAsn1Object().getInteger();
- BigInteger coefficient = parser.readAsn1Object().getInteger();
- return new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, prime1, prime2, exponent1, exponent2, coefficient);
- }
-
- /**
- * Parses a DER encoded DSA key to a {@link DSAPrivateKeySpec} using a minimal {@link DerParser}
- *
- * @param keyBytes the private key raw bytes
- * @return {@link DSAPrivateKeySpec}
- * @throws IOException if the DER encoded key can't be parsed
- */
- private static DSAPrivateKeySpec parseDsaDer(byte[] keyBytes) throws IOException {
- DerParser parser = new DerParser(keyBytes);
- DerParser.Asn1Object sequence = parser.readAsn1Object();
- parser = sequence.getParser();
- parser.readAsn1Object().getInteger(); // (version) We don't need it but must read to get to p
- BigInteger p = parser.readAsn1Object().getInteger();
- BigInteger q = parser.readAsn1Object().getInteger();
- BigInteger g = parser.readAsn1Object().getInteger();
- parser.readAsn1Object().getInteger(); // we don't need x
- BigInteger x = parser.readAsn1Object().getInteger();
- return new DSAPrivateKeySpec(x, p, q, g);
- }
-
- /**
- * Parses a DER encoded private key and reads its algorithm identifier Object OID.
- *
- * @param keyBytes the private key raw bytes
- * @return A string identifier for the key algorithm (RSA, DSA, or EC)
- * @throws GeneralSecurityException if the algorithm oid that is parsed from ASN.1 is unknown
- * @throws IOException if the DER encoded key can't be parsed
- */
- private static String getKeyAlgorithmIdentifier(byte[] keyBytes) throws IOException, GeneralSecurityException {
- DerParser parser = new DerParser(keyBytes);
- DerParser.Asn1Object sequence = parser.readAsn1Object();
- parser = sequence.getParser();
- parser.readAsn1Object().getInteger(); // version
- DerParser.Asn1Object algSequence = parser.readAsn1Object();
- parser = algSequence.getParser();
- String oidString = parser.readAsn1Object().getOid();
- switch (oidString) {
- case "1.2.840.10040.4.1":
- return "DSA";
- case "1.2.840.113549.1.1.1":
- return "RSA";
- case "1.2.840.10045.2.1":
- return "EC";
- }
- throw new GeneralSecurityException(
- "Error parsing key algorithm identifier. Algorithm with OID [" + oidString + "] is not żsupported"
- );
- }
-
- static List readCertificates(Collection certPaths) throws CertificateException, IOException {
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- List certificates = new ArrayList<>(certPaths.size());
- for (Path path : certPaths) {
- try (InputStream input = Files.newInputStream(path)) {
- final Collection extends Certificate> parsed = certFactory.generateCertificates(input);
- if (parsed.isEmpty()) {
- throw new SslConfigException("failed to parse any certificates from [" + path.toAbsolutePath() + "]");
+ if (object instanceof ASN1ObjectIdentifier) { // ignore -----BEGIN EC PARAMETERS-----
+ continue;
}
- certificates.addAll(parsed);
+ return object;
+ } catch (IOException e) { // ignore -----BEGIN DSA PARAMETERS-----
+ // ignore
}
}
- return certificates;
- }
-
- private static String getEcCurveNameFromOid(String oidString) throws GeneralSecurityException {
- switch (oidString) {
- // see https://tools.ietf.org/html/rfc5480#section-2.1.1.1
- case "1.2.840.10045.3.1":
- return "secp192r1";
- case "1.3.132.0.1":
- return "sect163k1";
- case "1.3.132.0.15":
- return "sect163r2";
- case "1.3.132.0.33":
- return "secp224r1";
- case "1.3.132.0.26":
- return "sect233k1";
- case "1.3.132.0.27":
- return "sect233r1";
- case "1.2.840.10045.3.1.7":
- return "secp256r1";
- case "1.3.132.0.16":
- return "sect283k1";
- case "1.3.132.0.17":
- return "sect283r1";
- case "1.3.132.0.34":
- return "secp384r1";
- case "1.3.132.0.36":
- return "sect409k1";
- case "1.3.132.0.37":
- return "sect409r1";
- case "1.3.132.0.35":
- return "secp521r1";
- case "1.3.132.0.38":
- return "sect571k1";
- case "1.3.132.0.39":
- return "sect571r1";
- }
- throw new GeneralSecurityException(
- "Error parsing EC named curve identifier. Named curve with OID: " + oidString + " is not supported"
+ throw new SslConfigException(
+ "Error parsing Private Key [" + keyPath.toAbsolutePath() + "]. The file is empty, or does not contain expected key format."
);
}
diff --git a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfiguration.java b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfiguration.java
index 23acb0ff269e2..224699660b65b 100644
--- a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfiguration.java
+++ b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfiguration.java
@@ -32,13 +32,14 @@
package org.opensearch.common.ssl;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
-import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -66,12 +67,7 @@ public class SslConfiguration {
static final Map ORDERED_PROTOCOL_ALGORITHM_MAP;
static {
LinkedHashMap protocolAlgorithmMap = new LinkedHashMap<>();
- try {
- SSLContext.getInstance("TLSv1.3");
- protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
- } catch (NoSuchAlgorithmException e) {
- // ignore since we support JVMs (and BC JSSE in FIPS mode) that do not support TLSv1.3
- }
+ protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
protocolAlgorithmMap.put("TLSv1.2", "TLSv1.2");
protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
protocolAlgorithmMap.put("TLSv1", "TLSv1");
@@ -168,8 +164,12 @@ public SSLContext createSslContext() {
* {@link #getSupportedProtocols() configured protocols}.
*/
private String contextProtocol() {
- if (supportedProtocols.isEmpty()) {
- throw new SslConfigException("no SSL/TLS protocols have been configured");
+ if (CryptoServicesRegistrar.isInApprovedOnlyMode()) {
+ if (!new HashSet<>(SslConfigurationLoader.FIPS_APPROVED_PROTOCOLS).containsAll(supportedProtocols)) {
+ throw new SslConfigException(
+ "in FIPS mode only the following SSL/TLS protocols are allowed: " + SslConfigurationLoader.FIPS_APPROVED_PROTOCOLS
+ );
+ }
}
for (Entry entry : ORDERED_PROTOCOL_ALGORITHM_MAP.entrySet()) {
if (supportedProtocols.contains(entry.getKey())) {
diff --git a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfigurationLoader.java b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfigurationLoader.java
index 0b06a0692197e..98bc97c1c8787 100644
--- a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfigurationLoader.java
+++ b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/SslConfigurationLoader.java
@@ -32,6 +32,8 @@
package org.opensearch.common.ssl;
+import org.opensearch.common.crypto.KeyStoreType;
+
import javax.crypto.Cipher;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
@@ -40,14 +42,14 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
-import static org.opensearch.common.ssl.KeyStoreUtil.inferKeyStoreType;
-import static org.opensearch.common.ssl.SslConfiguration.ORDERED_PROTOCOL_ALGORITHM_MAP;
+import static org.opensearch.common.crypto.KeyStoreType.inferStoreType;
import static org.opensearch.common.ssl.SslConfigurationKeys.CERTIFICATE;
import static org.opensearch.common.ssl.SslConfigurationKeys.CERTIFICATE_AUTHORITIES;
import static org.opensearch.common.ssl.SslConfigurationKeys.CIPHERS;
@@ -84,11 +86,7 @@
*/
public abstract class SslConfigurationLoader {
- static final List DEFAULT_PROTOCOLS = Collections.unmodifiableList(
- ORDERED_PROTOCOL_ALGORITHM_MAP.containsKey("TLSv1.3")
- ? Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1")
- : Arrays.asList("TLSv1.2", "TLSv1.1")
- );
+ static final List FIPS_APPROVED_PROTOCOLS = List.of("TLSv1.3", "TLSv1.2");
static final List DEFAULT_CIPHERS = loadDefaultCiphers();
private static final char[] EMPTY_PASSWORD = new char[0];
@@ -119,7 +117,7 @@ public SslConfigurationLoader(String settingPrefix) {
this.defaultKeyConfig = EmptyKeyConfig.INSTANCE;
this.defaultVerificationMode = SslVerificationMode.FULL;
this.defaultClientAuth = SslClientAuthenticationMode.OPTIONAL;
- this.defaultProtocols = DEFAULT_PROTOCOLS;
+ this.defaultProtocols = FIPS_APPROVED_PROTOCOLS;
this.defaultCiphers = DEFAULT_CIPHERS;
}
@@ -167,7 +165,7 @@ public void setDefaultCiphers(List defaultCiphers) {
/**
* Change the default SSL/TLS protocol list.
- * The initial protocol list is defined by {@link #DEFAULT_PROTOCOLS}
+ * The initial protocol list is defined by {@link #FIPS_APPROVED_PROTOCOLS}
*/
public void setDefaultProtocols(List defaultProtocols) {
this.defaultProtocols = defaultProtocols;
@@ -248,7 +246,10 @@ private SslTrustConfig buildTrustConfig(Path basePath, SslVerificationMode verif
}
if (trustStorePath != null) {
final char[] password = resolvePasswordSetting(TRUSTSTORE_SECURE_PASSWORD, TRUSTSTORE_LEGACY_PASSWORD);
- final String storeType = resolveSetting(TRUSTSTORE_TYPE, Function.identity(), inferKeyStoreType(trustStorePath));
+ final Optional maybeStoreType = Optional.ofNullable(resolveSetting(TRUSTSTORE_TYPE, Function.identity(), null));
+ final KeyStoreType storeType = maybeStoreType.map(KeyStoreType::getByJcaName)
+ .orElse(inferStoreType(trustStorePath.toString().toLowerCase(Locale.ROOT)));
+
final String algorithm = resolveSetting(TRUSTSTORE_ALGORITHM, Function.identity(), TrustManagerFactory.getDefaultAlgorithm());
return new StoreTrustConfig(trustStorePath, password, storeType, algorithm);
}
@@ -287,7 +288,11 @@ private SslKeyConfig buildKeyConfig(Path basePath) {
if (keyPassword.length == 0) {
keyPassword = storePassword;
}
- final String storeType = resolveSetting(KEYSTORE_TYPE, Function.identity(), inferKeyStoreType(keyStorePath));
+
+ final Optional maybeStoreType = Optional.ofNullable(resolveSetting(KEYSTORE_TYPE, Function.identity(), null));
+ final KeyStoreType storeType = maybeStoreType.map(KeyStoreType::getByJcaName)
+ .orElse(inferStoreType(keyStorePath.toString().toLowerCase(Locale.ROOT)));
+
final String algorithm = resolveSetting(KEYSTORE_ALGORITHM, Function.identity(), KeyManagerFactory.getDefaultAlgorithm());
return new StoreKeyConfig(keyStorePath, storePassword, storeType, keyPassword, algorithm);
}
@@ -360,14 +365,11 @@ private List resolveListSetting(String key, Function parser, L
private static List loadDefaultCiphers() {
final boolean has256BitAES = has256BitAES();
- final boolean tlsV13Supported = DEFAULT_PROTOCOLS.contains("TLSv1.3");
List ciphers = new ArrayList<>();
- if (tlsV13Supported) { // TLSv1.3 cipher has PFS, AEAD, hardware support
- if (has256BitAES) {
- ciphers.add("TLS_AES_256_GCM_SHA384");
- }
- ciphers.add("TLS_AES_128_GCM_SHA256");
+ if (has256BitAES) {
+ ciphers.add("TLS_AES_256_GCM_SHA384");
}
+ ciphers.add("TLS_AES_128_GCM_SHA256");
// use GCM: PFS, AEAD, hardware support
if (has256BitAES) {
ciphers.addAll(
diff --git a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreKeyConfig.java b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreKeyConfig.java
index b3b7b7dc346a6..c60e4d1b0f65a 100644
--- a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreKeyConfig.java
+++ b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreKeyConfig.java
@@ -32,6 +32,8 @@
package org.opensearch.common.ssl;
+import org.opensearch.common.crypto.KeyStoreType;
+
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
@@ -51,7 +53,7 @@
public class StoreKeyConfig implements SslKeyConfig {
private final Path path;
private final char[] storePassword;
- private final String type;
+ private final KeyStoreType type;
private final char[] keyPassword;
private final String algorithm;
@@ -59,12 +61,12 @@ public class StoreKeyConfig implements SslKeyConfig {
* @param path The path to the keystore file
* @param storePassword The password for the keystore
* @param type The {@link KeyStore#getType() type} of the keystore (typically "PKCS12" or "jks").
- * See {@link KeyStoreUtil#inferKeyStoreType(Path)}.
+ * See {@link KeyStoreType#inferStoreType(String)}.
* @param keyPassword The password for the key(s) within the keystore
* (see {@link javax.net.ssl.KeyManagerFactory#init(KeyStore, char[])}).
* @param algorithm The algorithm to use for the Key Manager (see {@link KeyManagerFactory#getAlgorithm()}).
*/
- StoreKeyConfig(Path path, char[] storePassword, String type, char[] keyPassword, String algorithm) {
+ StoreKeyConfig(Path path, char[] storePassword, KeyStoreType type, char[] keyPassword, String algorithm) {
this.path = path;
this.storePassword = storePassword;
this.type = type;
diff --git a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreTrustConfig.java b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreTrustConfig.java
index 556cb052c4391..138fff71b8a3d 100644
--- a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreTrustConfig.java
+++ b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/StoreTrustConfig.java
@@ -32,6 +32,8 @@
package org.opensearch.common.ssl;
+import org.opensearch.common.crypto.KeyStoreType;
+
import javax.net.ssl.X509ExtendedTrustManager;
import java.nio.file.Path;
@@ -47,17 +49,17 @@
final class StoreTrustConfig implements SslTrustConfig {
private final Path path;
private final char[] password;
- private final String type;
+ private final KeyStoreType type;
private final String algorithm;
/**
* @param path The path to the keystore file
* @param password The password for the keystore
* @param type The {@link KeyStore#getType() type} of the keystore (typically "PKCS12" or "jks").
- * See {@link KeyStoreUtil#inferKeyStoreType(Path)}.
+ * See {@link KeyStoreType#inferStoreType(String)}.
* @param algorithm The algorithm to use for the Trust Manager (see {@link javax.net.ssl.TrustManagerFactory#getAlgorithm()}).
*/
- StoreTrustConfig(Path path, char[] password, String type, String algorithm) {
+ StoreTrustConfig(Path path, char[] password, KeyStoreType type, String algorithm) {
this.path = path;
this.type = type;
this.algorithm = algorithm;
diff --git a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/TrustEverythingConfig.java b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/TrustEverythingConfig.java
index c366210133687..dd58606ec44c4 100644
--- a/libs/ssl-config/src/main/java/org/opensearch/common/ssl/TrustEverythingConfig.java
+++ b/libs/ssl-config/src/main/java/org/opensearch/common/ssl/TrustEverythingConfig.java
@@ -32,6 +32,8 @@
package org.opensearch.common.ssl;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedTrustManager;
@@ -40,6 +42,7 @@
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Collections;
+import java.util.Locale;
/**
* A {@link SslTrustConfig} that trusts all certificates. Used when {@link SslVerificationMode#isCertificateVerificationEnabled()} is
@@ -90,6 +93,15 @@ public Collection getDependentFiles() {
@Override
public X509ExtendedTrustManager createTrustManager() {
+ if (CryptoServicesRegistrar.isInApprovedOnlyMode()) {
+ var message = String.format(
+ Locale.ROOT,
+ "The use of %s is not permitted in FIPS mode. This issue may be caused by the '%s' setting.",
+ TRUST_EVERYTHING.getClass().getSimpleName(),
+ "ssl.verification_mode=NONE"
+ );
+ throw new IllegalStateException(message);
+ }
return TRUST_MANAGER;
}
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemKeyConfigTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemKeyConfigTests.java
index 688f03a1e51fa..a685d0b346161 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemKeyConfigTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemKeyConfigTests.java
@@ -41,11 +41,11 @@
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
-import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.function.Supplier;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.containsInAnyOrder;
@@ -58,6 +58,7 @@
public class PemKeyConfigTests extends OpenSearchTestCase {
private static final int IP_NAME = 7;
private static final int DNS_NAME = 2;
+ private static final Supplier STRONG_PRIVATE_SECRET = "6!6428DQXwPpi7@$ggeg/="::toCharArray;
public void testBuildKeyConfigFromPkcs1PemFilesWithoutPassword() throws Exception {
final Path cert = getDataPath("/certs/cert1/cert1.crt");
@@ -68,8 +69,9 @@ public void testBuildKeyConfigFromPkcs1PemFilesWithoutPassword() throws Exceptio
}
public void testBuildKeyConfigFromPkcs1PemFilesWithPassword() throws Exception {
- final Path cert = getDataPath("/certs/cert2/cert2.crt");
- final Path key = getDataPath("/certs/cert2/cert2.key");
+ assumeFalse("Can't run in a FIPS JVM, PBKDF-OPENSSL KeySpec is not available", inFipsJvm());
+ final Path cert = getDataPath("/certs/cert2/cert2-pkcs1.crt");
+ final Path key = getDataPath("/certs/cert2/cert2-pkcs1.key");
final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, "c2-pass".toCharArray());
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert, key));
assertCertificateAndKey(keyConfig, "CN=cert2");
@@ -77,17 +79,16 @@ public void testBuildKeyConfigFromPkcs1PemFilesWithPassword() throws Exception {
public void testBuildKeyConfigFromPkcs8PemFilesWithoutPassword() throws Exception {
final Path cert = getDataPath("/certs/cert1/cert1.crt");
- final Path key = getDataPath("/certs/cert1/cert1-pkcs8.key");
+ final Path key = getDataPath("/certs/cert1/cert1.key");
final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, new char[0]);
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert, key));
assertCertificateAndKey(keyConfig, "CN=cert1");
}
public void testBuildKeyConfigFromPkcs8PemFilesWithPassword() throws Exception {
- assumeFalse("Can't run in a FIPS JVM, PBE KeySpec is not available", inFipsJvm());
final Path cert = getDataPath("/certs/cert2/cert2.crt");
- final Path key = getDataPath("/certs/cert2/cert2-pkcs8.key");
- final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, "c2-pass".toCharArray());
+ final Path key = getDataPath("/certs/cert2/cert2.key");
+ final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, STRONG_PRIVATE_SECRET.get());
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert, key));
assertCertificateAndKey(keyConfig, "CN=cert2");
}
@@ -131,7 +132,7 @@ public void testKeyConfigReloadsFileContents() throws Exception {
Files.copy(cert2, cert, StandardCopyOption.REPLACE_EXISTING);
Files.copy(key2, key, StandardCopyOption.REPLACE_EXISTING);
- assertPasswordIsIncorrect(keyConfig, key);
+ assertPasswordNotSet(keyConfig, key);
Files.copy(cert1, cert, StandardCopyOption.REPLACE_EXISTING);
Files.copy(key1, key, StandardCopyOption.REPLACE_EXISTING);
@@ -166,7 +167,15 @@ private void assertPasswordIsIncorrect(PemKeyConfig keyConfig, Path key) {
final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager);
assertThat(exception.getMessage(), containsString("private key file"));
assertThat(exception.getMessage(), containsString(key.toAbsolutePath().toString()));
- assertThat(exception.getCause(), instanceOf(GeneralSecurityException.class));
+ assertThat(exception, instanceOf(SslConfigException.class));
+ }
+
+ private void assertPasswordNotSet(PemKeyConfig keyConfig, Path key) {
+ final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager);
+ assertThat(exception.getMessage(), containsString("cannot read encrypted key"));
+ assertThat(exception.getMessage(), containsString(key.toAbsolutePath().toString()));
+ assertThat(exception.getMessage(), containsString("without a password"));
+ assertThat(exception, instanceOf(SslConfigException.class));
}
private void assertFileNotFound(PemKeyConfig keyConfig, String type, Path file) {
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemTrustConfigTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemTrustConfigTests.java
index e664e379d1e97..3d66c2157b754 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemTrustConfigTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemTrustConfigTests.java
@@ -42,7 +42,6 @@
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
-import java.security.GeneralSecurityException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Arrays;
@@ -74,7 +73,7 @@ public void testBadFileFormatFails() throws Exception {
Files.write(ca, generateRandomByteArrayOfLength(128), StandardOpenOption.APPEND);
final PemTrustConfig trustConfig = new PemTrustConfig(Collections.singletonList(ca));
assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ca));
- assertInvalidFileFormat(trustConfig, ca);
+ assertFailedToParse(trustConfig, ca);
}
public void testEmptyFileFails() throws Exception {
@@ -121,7 +120,7 @@ public void testTrustConfigReloadsFileContents() throws Exception {
assertFileNotFound(trustConfig, ca1);
Files.write(ca1, generateRandomByteArrayOfLength(128), StandardOpenOption.CREATE);
- assertInvalidFileFormat(trustConfig, ca1);
+ assertFailedToParse(trustConfig, ca1);
}
private void assertCertificateChain(PemTrustConfig trustConfig, String... caNames) {
@@ -139,20 +138,14 @@ private void assertEmptyFile(PemTrustConfig trustConfig, Path file) {
final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager);
logger.info("failure", exception);
assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString()));
- assertThat(exception.getMessage(), Matchers.containsString("failed to parse any certificates"));
+ assertThat(exception.getMessage(), Matchers.containsString("Failed to parse any certificate from"));
}
- private void assertInvalidFileFormat(PemTrustConfig trustConfig, Path file) {
+ private void assertFailedToParse(PemTrustConfig trustConfig, Path file) {
final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager);
+ logger.info("failure", exception);
assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString()));
- // When running on BC-FIPS, an invalid file format *might* just fail to parse, without any errors (just like an empty file)
- // or it might behave per the SUN provider, and throw a GSE (depending on exactly what was invalid)
- if (inFipsJvm() && exception.getMessage().contains("failed to parse any certificates")) {
- return;
- }
- assertThat(exception.getMessage(), Matchers.containsString("cannot create trust"));
- assertThat(exception.getMessage(), Matchers.containsString("PEM"));
- assertThat(exception.getCause(), Matchers.instanceOf(GeneralSecurityException.class));
+ assertThat(exception.getMessage(), Matchers.containsString("Failed to parse any certificate from"));
}
private void assertFileNotFound(PemTrustConfig trustConfig, Path file) {
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemUtilsTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemUtilsTests.java
index c7ca19bb679d3..a0d15258ed3ca 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemUtilsTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/PemUtilsTests.java
@@ -32,18 +32,19 @@
package org.opensearch.common.ssl;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
import org.opensearch.test.OpenSearchTestCase;
-import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AlgorithmParameters;
import java.security.Key;
-import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
+import java.util.Locale;
import java.util.function.Supplier;
import static org.hamcrest.Matchers.equalTo;
@@ -55,9 +56,15 @@ public class PemUtilsTests extends OpenSearchTestCase {
private static final Supplier EMPTY_PASSWORD = () -> new char[0];
private static final Supplier TESTNODE_PASSWORD = "testnode"::toCharArray;
+ private static final Supplier STRONG_PRIVATE_SECRET = "6!6428DQXwPpi7@$ggeg/="::toCharArray; // has to be at least 112 bit long.
+
+ public void testInstantiateWithDefaultConstructor() {
+ assertThrows("Utility class should not be instantiated", IllegalStateException.class, PemUtils::new);
+ }
public void testReadPKCS8RsaKey() throws Exception {
- Key key = getKeyFromKeystore("RSA");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("RSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/rsa_key_pkcs8_plain.pem"), EMPTY_PASSWORD);
@@ -66,7 +73,8 @@ public void testReadPKCS8RsaKey() throws Exception {
}
public void testReadPKCS8RsaKeyWithBagAttrs() throws Exception {
- Key key = getKeyFromKeystore("RSA");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("RSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/testnode_with_bagattrs.pem"), EMPTY_PASSWORD);
@@ -74,7 +82,8 @@ public void testReadPKCS8RsaKeyWithBagAttrs() throws Exception {
}
public void testReadPKCS8DsaKey() throws Exception {
- Key key = getKeyFromKeystore("DSA");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("DSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/dsa_key_pkcs8_plain.pem"), EMPTY_PASSWORD);
@@ -94,7 +103,8 @@ public void testReadEcKeyCurves() throws Exception {
}
public void testReadPKCS8EcKey() throws Exception {
- Key key = getKeyFromKeystore("EC");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("EC", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/ec_key_pkcs8_plain.pem"), EMPTY_PASSWORD);
@@ -104,7 +114,7 @@ public void testReadPKCS8EcKey() throws Exception {
public void testReadEncryptedPKCS8Key() throws Exception {
assumeFalse("Can't run in a FIPS JVM, PBE KeySpec is not available", inFipsJvm());
- Key key = getKeyFromKeystore("RSA");
+ Key key = getKeyFromKeystore("RSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/key_pkcs8_encrypted.pem"), TESTNODE_PASSWORD);
@@ -113,7 +123,8 @@ public void testReadEncryptedPKCS8Key() throws Exception {
}
public void testReadDESEncryptedPKCS1Key() throws Exception {
- Key key = getKeyFromKeystore("RSA");
+ assumeFalse("Can't run in a FIPS JVM, PBKDF-OPENSSL KeySpec is not available", inFipsJvm());
+ Key key = getKeyFromKeystore("RSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/testnode.pem"), TESTNODE_PASSWORD);
@@ -122,7 +133,8 @@ public void testReadDESEncryptedPKCS1Key() throws Exception {
}
public void testReadAESEncryptedPKCS1Key() throws Exception {
- Key key = getKeyFromKeystore("RSA");
+ assumeFalse("Can't run in a FIPS JVM, PBKDF-OPENSSL KeySpec is not available", inFipsJvm());
+ Key key = getKeyFromKeystore("RSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
String bits = randomFrom("128", "192", "256");
@@ -133,7 +145,8 @@ public void testReadAESEncryptedPKCS1Key() throws Exception {
}
public void testReadPKCS1RsaKey() throws Exception {
- Key key = getKeyFromKeystore("RSA");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("RSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/testnode-unprotected.pem"), TESTNODE_PASSWORD);
@@ -143,7 +156,8 @@ public void testReadPKCS1RsaKey() throws Exception {
}
public void testReadOpenSslDsaKey() throws Exception {
- Key key = getKeyFromKeystore("DSA");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("DSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/dsa_key_openssl_plain.pem"), EMPTY_PASSWORD);
@@ -153,7 +167,8 @@ public void testReadOpenSslDsaKey() throws Exception {
}
public void testReadOpenSslDsaKeyWithParams() throws Exception {
- Key key = getKeyFromKeystore("DSA");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("DSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(
@@ -166,7 +181,8 @@ public void testReadOpenSslDsaKeyWithParams() throws Exception {
}
public void testReadEncryptedOpenSslDsaKey() throws Exception {
- Key key = getKeyFromKeystore("DSA");
+ assumeFalse("Can't run in a FIPS JVM, PBKDF-OPENSSL KeySpec is not available", inFipsJvm());
+ Key key = getKeyFromKeystore("DSA", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/dsa_key_openssl_encrypted.pem"), TESTNODE_PASSWORD);
@@ -176,7 +192,8 @@ public void testReadEncryptedOpenSslDsaKey() throws Exception {
}
public void testReadOpenSslEcKey() throws Exception {
- Key key = getKeyFromKeystore("EC");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("EC", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/ec_key_openssl_plain.pem"), EMPTY_PASSWORD);
@@ -186,7 +203,8 @@ public void testReadOpenSslEcKey() throws Exception {
}
public void testReadOpenSslEcKeyWithParams() throws Exception {
- Key key = getKeyFromKeystore("EC");
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ Key key = getKeyFromKeystore("EC", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(
@@ -199,7 +217,8 @@ public void testReadOpenSslEcKeyWithParams() throws Exception {
}
public void testReadEncryptedOpenSslEcKey() throws Exception {
- Key key = getKeyFromKeystore("EC");
+ assumeFalse("Can't run in a FIPS JVM, PBKDF-OPENSSL KeySpec is not available", inFipsJvm());
+ Key key = getKeyFromKeystore("EC", KeyStoreType.JKS);
assertThat(key, notNullValue());
assertThat(key, instanceOf(PrivateKey.class));
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/ec_key_openssl_encrypted.pem"), TESTNODE_PASSWORD);
@@ -208,27 +227,54 @@ public void testReadEncryptedOpenSslEcKey() throws Exception {
assertThat(privateKey, equalTo(key));
}
+ public void testReadEncryptedPKCS8KeyWithPBKDF2() throws Exception {
+ Key key = getKeyFromKeystore("PKCS8_PBKDF2");
+ assertThat(key, notNullValue());
+ assertThat(key, instanceOf(PrivateKey.class));
+ PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/key_PKCS8_enc_pbkdf2.pem"), STRONG_PRIVATE_SECRET);
+ assertThat(privateKey, notNullValue());
+ assertThat(privateKey, equalTo(key));
+ }
+
+ public void testReadEncryptedDsaKeyWithPBKDF2() throws Exception {
+ Key key = getKeyFromKeystore("DSA_PBKDF2");
+ assertThat(key, notNullValue());
+ assertThat(key, instanceOf(PrivateKey.class));
+ PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/key_DSA_enc_pbkdf2.pem"), STRONG_PRIVATE_SECRET);
+ assertThat(privateKey, notNullValue());
+ assertThat(privateKey, equalTo(key));
+ }
+
+ public void testReadEncryptedEcKeyWithPBKDF2() throws Exception {
+ Key key = getKeyFromKeystore("EC_PBKDF2");
+ assertThat(key, notNullValue());
+ assertThat(key, instanceOf(PrivateKey.class));
+ PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/key_EC_enc_pbkdf2.pem"), STRONG_PRIVATE_SECRET);
+ assertThat(privateKey, notNullValue());
+ assertThat(privateKey, equalTo(key));
+ }
+
public void testReadUnsupportedKey() {
final Path path = getDataPath("/certs/pem-utils/key_unsupported.pem");
SslConfigException e = expectThrows(SslConfigException.class, () -> PemUtils.readPrivateKey(path, TESTNODE_PASSWORD));
- assertThat(e.getMessage(), containsString("file does not contain a supported key format"));
+ assertThat(e.getMessage(), containsString("Error parsing Private Key"));
assertThat(e.getMessage(), containsString(path.toAbsolutePath().toString()));
+ assertThat(e.getMessage(), containsString("file is empty"));
}
public void testReadPemCertificateAsKey() {
final Path path = getDataPath("/certs/pem-utils/testnode.crt");
SslConfigException e = expectThrows(SslConfigException.class, () -> PemUtils.readPrivateKey(path, TESTNODE_PASSWORD));
- assertThat(e.getMessage(), containsString("file does not contain a supported key format"));
+ assertThat(e.getMessage(), containsString("invalid encrypted private key class"));
assertThat(e.getMessage(), containsString(path.toAbsolutePath().toString()));
}
public void testReadCorruptedKey() {
final Path path = getDataPath("/certs/pem-utils/corrupted_key_pkcs8_plain.pem");
SslConfigException e = expectThrows(SslConfigException.class, () -> PemUtils.readPrivateKey(path, TESTNODE_PASSWORD));
- assertThat(e.getMessage(), containsString("private key"));
- assertThat(e.getMessage(), containsString("cannot be parsed"));
+ assertThat(e.getMessage(), containsString("Error parsing Private Key"));
assertThat(e.getMessage(), containsString(path.toAbsolutePath().toString()));
- assertThat(e.getCause().getMessage(), containsString("PEM footer is invalid or missing"));
+ assertThat(e.getMessage(), containsString("file is empty"));
}
public void testReadEmptyFile() {
@@ -239,11 +285,17 @@ public void testReadEmptyFile() {
}
private Key getKeyFromKeystore(String algo) throws Exception {
- Path keystorePath = getDataPath("/certs/pem-utils/testnode.jks");
- try (InputStream in = Files.newInputStream(keystorePath)) {
- KeyStore keyStore = KeyStore.getInstance("jks");
- keyStore.load(in, "testnode".toCharArray());
- return keyStore.getKey("testnode_" + algo, "testnode".toCharArray());
+ return getKeyFromKeystore(algo, inFipsJvm() ? KeyStoreType.BCFKS : KeyStoreType.JKS);
+ }
+
+ private Key getKeyFromKeystore(String algo, KeyStoreType keyStoreType) throws Exception {
+ var keystorePath = getDataPath("/certs/pem-utils/testnode" + KeyStoreType.TYPE_TO_EXTENSION_MAP.get(keyStoreType).get(0));
+ var alias = "testnode_" + algo.toLowerCase(Locale.ROOT);
+ var password = "testnode".toCharArray();
+ try (var in = Files.newInputStream(keystorePath)) {
+ var keyStore = KeyStoreFactory.getInstance(keyStoreType);
+ keyStore.load(in, password);
+ return keyStore.getKey(alias, password);
}
}
}
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationLoaderTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationLoaderTests.java
index 5af7ddc73e680..2aef139eba7a0 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationLoaderTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationLoaderTests.java
@@ -53,6 +53,8 @@
public class SslConfigurationLoaderTests extends OpenSearchTestCase {
+ protected static final String BCFKS = "BCFKS";
+ private final String STRONG_PRIVATE_SECRET = "6!6428DQXwPpi7@$ggeg/=";
private final Path certRoot = getDataPath("/certs/ca1/ca.crt").getParent().getParent();
private Settings settings;
@@ -98,6 +100,14 @@ public void testBasicConfigurationOptions() {
if (verificationMode == SslVerificationMode.NONE) {
final SslTrustConfig trustConfig = configuration.getTrustConfig();
assertThat(trustConfig, instanceOf(TrustEverythingConfig.class));
+
+ if (inFipsJvm()) {
+ assertThrows(
+ "The use of TrustEverythingConfig is not permitted in FIPS mode. This issue may be caused by the 'ssl.verification_mode=NONE' setting.",
+ IllegalStateException.class,
+ trustConfig::createTrustManager
+ );
+ }
}
}
@@ -113,7 +123,30 @@ public void testLoadTrustFromPemCAs() {
assertThat(trustConfig.createTrustManager(), notNullValue());
}
+ public void testLoadTrustFromBCFKS() {
+ final Settings.Builder builder = Settings.builder().put("test.ssl.truststore.path", "ca-all/ca.bcfks");
+ if (randomBoolean()) {
+ builder.put("test.ssl.truststore.password", "bcfks-pass");
+ } else {
+ secureSettings.setString("test.ssl.truststore.secure_password", "bcfks-pass");
+ }
+ if (randomBoolean()) {
+ // If this is not set, the loader will guess from the extension
+ builder.put("test.ssl.truststore.type", BCFKS);
+ }
+ if (randomBoolean()) {
+ builder.put("test.ssl.truststore.algorithm", TrustManagerFactory.getDefaultAlgorithm());
+ }
+ settings = builder.build();
+ final SslConfiguration configuration = loader.load(certRoot);
+ final SslTrustConfig trustConfig = configuration.getTrustConfig();
+ assertThat(trustConfig, instanceOf(StoreTrustConfig.class));
+ assertThat(trustConfig.getDependentFiles(), containsInAnyOrder(getDataPath("/certs/ca-all/ca.bcfks")));
+ assertThat(trustConfig.createTrustManager(), notNullValue());
+ }
+
public void testLoadTrustFromPkcs12() {
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Settings.Builder builder = Settings.builder().put("test.ssl.truststore.path", "ca-all/ca.p12");
if (randomBoolean()) {
builder.put("test.ssl.truststore.password", "p12-pass");
@@ -136,6 +169,7 @@ public void testLoadTrustFromPkcs12() {
}
public void testLoadTrustFromJKS() {
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Settings.Builder builder = Settings.builder().put("test.ssl.truststore.path", "ca-all/ca.jks");
if (randomBoolean()) {
builder.put("test.ssl.truststore.password", "jks-pass");
@@ -166,9 +200,9 @@ public void testLoadKeysFromPemFiles() {
.put("test.ssl.key", certName + "/" + certName + ".key");
if (usePassword) {
if (useLegacyPassword) {
- builder.put("test.ssl.key_passphrase", "c2-pass");
+ builder.put("test.ssl.key_passphrase", STRONG_PRIVATE_SECRET);
} else {
- secureSettings.setString("test.ssl.secure_key_passphrase", "c2-pass");
+ secureSettings.setString("test.ssl.secure_key_passphrase", STRONG_PRIVATE_SECRET);
}
}
settings = builder.build();
@@ -185,7 +219,30 @@ public void testLoadKeysFromPemFiles() {
assertThat(keyConfig.createKeyManager(), notNullValue());
}
+ public void testLoadKeysFromBCFKS() {
+ final Settings.Builder builder = Settings.builder().put("test.ssl.keystore.path", "cert-all/certs.bcfks");
+ if (randomBoolean()) {
+ builder.put("test.ssl.keystore.password", "bcfks-pass");
+ } else {
+ secureSettings.setString("test.ssl.keystore.secure_password", "bcfks-pass");
+ }
+ if (randomBoolean()) {
+ // If this is not set, the loader will guess from the extension
+ builder.put("test.ssl.keystore.type", BCFKS);
+ }
+ if (randomBoolean()) {
+ builder.put("test.ssl.keystore.algorithm", KeyManagerFactory.getDefaultAlgorithm());
+ }
+ settings = builder.build();
+ final SslConfiguration configuration = loader.load(certRoot);
+ final SslKeyConfig keyConfig = configuration.getKeyConfig();
+ assertThat(keyConfig, instanceOf(StoreKeyConfig.class));
+ assertThat(keyConfig.getDependentFiles(), containsInAnyOrder(getDataPath("/certs/cert-all/certs.bcfks")));
+ assertThat(keyConfig.createKeyManager(), notNullValue());
+ }
+
public void testLoadKeysFromPKCS12() {
+ assumeFalse("Can't use PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Settings.Builder builder = Settings.builder().put("test.ssl.keystore.path", "cert-all/certs.p12");
if (randomBoolean()) {
builder.put("test.ssl.keystore.password", "p12-pass");
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationTests.java
index ee907952c52ff..410238e57984c 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslConfigurationTests.java
@@ -42,10 +42,12 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import org.mockito.Mockito;
import static org.opensearch.common.ssl.SslConfigurationLoader.DEFAULT_CIPHERS;
+import static org.opensearch.common.ssl.SslConfigurationLoader.FIPS_APPROVED_PROTOCOLS;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@@ -166,7 +168,7 @@ public void testDependentFiles() {
randomFrom(SslVerificationMode.values()),
randomFrom(SslClientAuthenticationMode.values()),
DEFAULT_CIPHERS,
- SslConfigurationLoader.DEFAULT_PROTOCOLS
+ SslConfigurationLoader.FIPS_APPROVED_PROTOCOLS
);
final Path dir = createTempDir();
@@ -184,7 +186,7 @@ public void testDependentFiles() {
public void testBuildSslContext() {
final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class);
final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class);
- final String protocol = randomFrom(SslConfigurationLoader.DEFAULT_PROTOCOLS);
+ final String protocol = randomFrom(SslConfigurationLoader.FIPS_APPROVED_PROTOCOLS);
final SslConfiguration configuration = new SslConfiguration(
trustConfig,
keyConfig,
@@ -204,4 +206,80 @@ public void testBuildSslContext() {
Mockito.verifyNoMoreInteractions(trustConfig, keyConfig);
}
+ public void testCreateSslContextWithUnsupportedProtocols() {
+ assumeFalse("Test not in FIPS JVM", inFipsJvm());
+ final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class);
+ final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class);
+ SslConfiguration configuration = new SslConfiguration(
+ trustConfig,
+ keyConfig,
+ randomFrom(SslVerificationMode.values()),
+ randomFrom(SslClientAuthenticationMode.values()),
+ DEFAULT_CIPHERS,
+ Collections.singletonList("DTLSv1.2")
+ );
+
+ Exception e = assertThrows(SslConfigException.class, configuration::createSslContext);
+ assertThat(
+ e.getMessage(),
+ containsString("no supported SSL/TLS protocol was found in the configured supported protocols: [DTLSv1.2]")
+ );
+ }
+
+ public void testNotSupportedProtocolsInFipsJvm() {
+ assumeTrue("Test in FIPS JVM", inFipsJvm());
+ final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class);
+ final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class);
+ final String protocol = randomFrom(List.of("TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello", "SSLv2"));
+ final SslConfiguration configuration = new SslConfiguration(
+ trustConfig,
+ keyConfig,
+ randomFrom(SslVerificationMode.values()),
+ randomFrom(SslClientAuthenticationMode.values()),
+ DEFAULT_CIPHERS,
+ Collections.singletonList(protocol)
+ );
+
+ Mockito.when(trustConfig.createTrustManager()).thenReturn(null);
+ Mockito.when(keyConfig.createKeyManager()).thenReturn(null);
+ var exception = assertThrows(SslConfigException.class, configuration::createSslContext);
+ assertThat(
+ exception.getMessage(),
+ equalTo(
+ String.format(Locale.ROOT, "in FIPS mode only the following SSL/TLS protocols are allowed: %s", FIPS_APPROVED_PROTOCOLS)
+ )
+ );
+ }
+
+ public void testInitValuesExist() {
+ final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class);
+ final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class);
+
+ assertThrows(
+ "cannot configure SSL/TLS without any supported cipher suites",
+ SslConfigException.class,
+ () -> new SslConfiguration(
+ trustConfig,
+ keyConfig,
+ SslVerificationMode.CERTIFICATE,
+ SslClientAuthenticationMode.REQUIRED,
+ Collections.emptyList(),
+ List.of("SSLv2")
+ )
+ );
+
+ assertThrows(
+ "cannot configure SSL/TLS without any supported protocols",
+ SslConfigException.class,
+ () -> new SslConfiguration(
+ trustConfig,
+ keyConfig,
+ SslVerificationMode.CERTIFICATE,
+ SslClientAuthenticationMode.REQUIRED,
+ DEFAULT_CIPHERS,
+ Collections.emptyList()
+ )
+ );
+ }
+
}
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslDiagnosticsTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslDiagnosticsTests.java
index c966b4259219f..31a4082f0609a 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslDiagnosticsTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/SslDiagnosticsTests.java
@@ -52,6 +52,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -70,6 +71,17 @@ public class SslDiagnosticsTests extends OpenSearchTestCase {
private static final byte[] MOCK_ENCODING_4 = { 0x64, 0x65, 0x66, 0x67, 0x68, 0x69 };
private static final String MOCK_FINGERPRINT_4 = "5d96965bfae50bf2be0d6259eb87a6cc9f5d0b26";
+ public void testTrustEmptyStore() {
+ var fileName = "cert-all/empty.jks";
+ var exception = assertThrows(SslConfigException.class, () -> loadCertificate(fileName));
+ assertThat(
+ exception.getMessage(),
+ Matchers.equalTo(
+ String.format(Locale.ROOT, "Failed to parse any certificate from [%s]", getDataPath("/certs/" + fileName).toAbsolutePath())
+ )
+ );
+ }
+
public void testDiagnosticMessageWhenServerProvidesAFullCertChainThatIsTrusted() throws Exception {
X509Certificate[] chain = loadCertChain("cert1/cert1.crt", "ca1/ca.crt");
final SSLSession session = session("192.168.1.1");
@@ -85,7 +97,7 @@ public void testDiagnosticMessageWhenServerProvidesAFullCertChainThatIsTrusted()
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.1];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1];"
+ " the certificate is signed by"
@@ -110,7 +122,7 @@ public void testDiagnosticMessageWhenServerProvidesAFullCertChainThatIsntTrusted
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.1];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1];"
+ " the certificate is signed by (subject [CN=Test CA 1] fingerprint [2b7b0416391bdf86502505c23149022d2213dadc])"
@@ -134,7 +146,7 @@ public void testDiagnosticMessageWhenServerFullCertChainIsntTrustedButMimicIssue
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.1];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1];"
+ " the certificate is signed by (subject [CN=Test CA 1] fingerprint [2b7b0416391bdf86502505c23149022d2213dadc])"
@@ -160,7 +172,7 @@ public void testDiagnosticMessageWhenServerProvidesEndCertificateOnlyAndTheCertA
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.1];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1]"
+ " but the server did not provide a copy of the issuing certificate in the certificate chain;"
@@ -185,7 +197,7 @@ public void testDiagnosticMessageWhenServerProvidesEndCertificateOnlyButTheCertA
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.1];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1]"
+ " but the server did not provide a copy of the issuing certificate in the certificate chain;"
@@ -209,7 +221,7 @@ public void testDiagnosticMessageWhenServerProvidesEndCertificateOnlyWithMimicIs
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.1];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1]"
+ " but the server did not provide a copy of the issuing certificate in the certificate chain;"
@@ -235,7 +247,7 @@ public void testDiagnosticMessageWhenServerProvidesEndCertificateWithMultipleMim
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.9];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1]"
+ " but the server did not provide a copy of the issuing certificate in the certificate chain;"
@@ -538,7 +550,7 @@ public void testDiagnosticMessageForClientCertificate() throws Exception {
Matchers.equalTo(
"failed to establish trust with client at [192.168.1.7];"
+ " the client provided a certificate with subject name [CN=cert1]"
- + " and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate is issued by [CN=Test CA 1]"
+ " but the client did not provide a copy of the issuing certificate in the certificate chain;"
+ " the issuing certificate with fingerprint [2b7b0416391bdf86502505c23149022d2213dadc]"
@@ -571,7 +583,7 @@ public void testDiagnosticMessageWhenCaHasNewIssuingCertificate() throws Excepti
message,
Matchers.equalTo(
"failed to establish trust with server at [192.168.1.4];"
- + " the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];"
+ + " the server provided a certificate with subject name [CN=cert1] and fingerprint [7e0919348e566651a136f2a1d5974585d5b3712e];"
+ " the certificate has subject alternative names [DNS:localhost,IP:127.0.0.1];"
+ " the certificate is issued by [CN=Test CA 1];"
+ " the certificate is signed by (subject [CN=Test CA 1]"
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreKeyConfigTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreKeyConfigTests.java
index 7806671d02793..6df03f72a0be8 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreKeyConfigTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreKeyConfigTests.java
@@ -48,6 +48,10 @@
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import static org.opensearch.common.crypto.KeyStoreType.BCFKS;
+import static org.opensearch.common.crypto.KeyStoreType.JKS;
+import static org.opensearch.common.crypto.KeyStoreType.PKCS_12;
+import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
@@ -64,11 +68,12 @@ public class StoreKeyConfigTests extends OpenSearchTestCase {
private static final char[] P12_PASS = "p12-pass".toCharArray();
private static final char[] JKS_PASS = "jks-pass".toCharArray();
+ private static final char[] BCFKS_PASS = "bcfks-pass".toCharArray();
public void testLoadSingleKeyPKCS12() throws Exception {
- assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ assumeFalse("Can't use PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path p12 = getDataPath("/certs/cert1/cert1.p12");
- final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, "PKCS12", P12_PASS, KeyManagerFactory.getDefaultAlgorithm());
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, PKCS_12, P12_PASS, KeyManagerFactory.getDefaultAlgorithm());
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(p12));
assertKeysLoaded(keyConfig, "cert1");
}
@@ -76,7 +81,7 @@ public void testLoadSingleKeyPKCS12() throws Exception {
public void testLoadMultipleKeyPKCS12() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path p12 = getDataPath("/certs/cert-all/certs.p12");
- final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, "PKCS12", P12_PASS, KeyManagerFactory.getDefaultAlgorithm());
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, PKCS_12, P12_PASS, KeyManagerFactory.getDefaultAlgorithm());
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(p12));
assertKeysLoaded(keyConfig, "cert1", "cert2");
}
@@ -87,7 +92,7 @@ public void testLoadMultipleKeyJksWithSeparateKeyPassword() throws Exception {
final StoreKeyConfig keyConfig = new StoreKeyConfig(
jks,
JKS_PASS,
- "jks",
+ JKS,
"key-pass".toCharArray(),
KeyManagerFactory.getDefaultAlgorithm()
);
@@ -95,13 +100,20 @@ public void testLoadMultipleKeyJksWithSeparateKeyPassword() throws Exception {
assertKeysLoaded(keyConfig, "cert1", "cert2");
}
- public void testKeyManagerFailsWithIncorrectStorePassword() throws Exception {
+ public void testLoadMultipleKeyBcfks() throws CertificateParsingException {
+ final Path bcfks = getDataPath("/certs/cert-all/certs.bcfks");
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(bcfks, BCFKS_PASS, BCFKS, BCFKS_PASS, KeyManagerFactory.getDefaultAlgorithm());
+ assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(bcfks));
+ assertKeysLoaded(keyConfig, "cert1", "cert2");
+ }
+
+ public void testKeyManagerFailsWithIncorrectJksStorePassword() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path jks = getDataPath("/certs/cert-all/certs.jks");
final StoreKeyConfig keyConfig = new StoreKeyConfig(
jks,
P12_PASS,
- "jks",
+ JKS,
"key-pass".toCharArray(),
KeyManagerFactory.getDefaultAlgorithm()
);
@@ -109,50 +121,76 @@ public void testKeyManagerFailsWithIncorrectStorePassword() throws Exception {
assertPasswordIsIncorrect(keyConfig, jks);
}
- public void testKeyManagerFailsWithIncorrectKeyPassword() throws Exception {
+ public void testKeyManagerFailsWithIncorrectBcfksStorePassword() throws Exception {
+ final Path bcfks = getDataPath("/certs/cert-all/certs.bcfks");
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(bcfks, P12_PASS, BCFKS, BCFKS_PASS, KeyManagerFactory.getDefaultAlgorithm());
+ assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(bcfks));
+ assertPasswordIsIncorrect(keyConfig, bcfks);
+ }
+
+ public void testKeyManagerFailsWithIncorrectJksKeyPassword() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path jks = getDataPath("/certs/cert-all/certs.jks");
- final StoreKeyConfig keyConfig = new StoreKeyConfig(jks, JKS_PASS, "jks", JKS_PASS, KeyManagerFactory.getDefaultAlgorithm());
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(jks, JKS_PASS, JKS, JKS_PASS, KeyManagerFactory.getDefaultAlgorithm());
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(jks));
assertPasswordIsIncorrect(keyConfig, jks);
}
+ public void testKeyManagerFailsWithIncorrectBcfksKeyPassword() throws Exception {
+ final Path bcfks = getDataPath("/certs/cert-all/certs.bcfks");
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(
+ bcfks,
+ BCFKS_PASS,
+ BCFKS,
+ "nonsense".toCharArray(),
+ KeyManagerFactory.getDefaultAlgorithm()
+ );
+ assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(bcfks));
+ assertPasswordIsIncorrect(keyConfig, bcfks);
+ }
+
public void testKeyManagerFailsWithMissingKeystoreFile() throws Exception {
- assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path path = getDataPath("/certs/cert-all/certs.jks").getParent().resolve("dne.jks");
- final StoreKeyConfig keyConfig = new StoreKeyConfig(path, JKS_PASS, "jks", JKS_PASS, KeyManagerFactory.getDefaultAlgorithm());
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(path, JKS_PASS, JKS, JKS_PASS, KeyManagerFactory.getDefaultAlgorithm());
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(path));
assertFileNotFound(keyConfig, path);
}
- public void testMissingKeyEntriesFailsWithMeaningfulMessage() throws Exception {
+ public void testMissingKeyEntriesFailsForJksWithMeaningfulMessage() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
- final Path ks;
- final char[] password;
- final String type;
- if (randomBoolean()) {
- type = "PKCS12";
- ks = getDataPath("/certs/ca-all/ca.p12");
- password = P12_PASS;
- } else {
- type = "jks";
- ks = getDataPath("/certs/ca-all/ca.jks");
- password = JKS_PASS;
- }
- final StoreKeyConfig keyConfig = new StoreKeyConfig(ks, password, type, password, KeyManagerFactory.getDefaultAlgorithm());
+ final Path ks = getDataPath("/certs/ca-all/ca.jks");
+ final char[] password = JKS_PASS;
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(ks, password, JKS, password, KeyManagerFactory.getDefaultAlgorithm());
+ assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
+ assertNoPrivateKeyEntries(keyConfig, ks);
+ }
+
+ public void testMissingKeyEntriesFailsForP12WithMeaningfulMessage() throws Exception {
+ assumeFalse("Can't use PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ final Path ks = getDataPath("/certs/ca-all/ca.p12");
+ final char[] password = P12_PASS;
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(ks, password, PKCS_12, password, KeyManagerFactory.getDefaultAlgorithm());
+ assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
+ assertNoPrivateKeyEntries(keyConfig, ks);
+ }
+
+ public void testMissingKeyEntriesFailsForBcfksWithMeaningfulMessage() throws Exception {
+ final Path ks = getDataPath("/certs/ca-all/ca.bcfks");
+ final char[] password = BCFKS_PASS;
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(ks, password, BCFKS, password, KeyManagerFactory.getDefaultAlgorithm());
assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
assertNoPrivateKeyEntries(keyConfig, ks);
}
public void testKeyConfigReloadsFileContents() throws Exception {
- assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ assumeFalse("Can't use PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path cert1 = getDataPath("/certs/cert1/cert1.p12");
final Path cert2 = getDataPath("/certs/cert2/cert2.p12");
final Path jks = getDataPath("/certs/cert-all/certs.jks");
final Path p12 = createTempFile("cert", ".p12");
- final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, "PKCS12", P12_PASS, KeyManagerFactory.getDefaultAlgorithm());
+ final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, PKCS_12, P12_PASS, KeyManagerFactory.getDefaultAlgorithm());
Files.copy(cert1, p12, StandardCopyOption.REPLACE_EXISTING);
assertKeysLoaded(keyConfig, "cert1");
@@ -211,7 +249,10 @@ private void assertPasswordIsIncorrect(StoreKeyConfig keyConfig, Path key) {
assertThat(exception.getMessage(), containsString("password"));
} else {
assertThat(exception.getCause(), instanceOf(IOException.class));
- assertThat(exception.getCause().getMessage(), containsString("password"));
+ assertThat(
+ exception.getCause().getMessage(),
+ anyOf(containsString("Keystore was tampered with, or password was incorrect"), containsString("BCFKS KeyStore corrupted"))
+ );
}
}
diff --git a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreTrustConfigTests.java b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreTrustConfigTests.java
index 5609f0fa2c877..3ba0c39e9d7e6 100644
--- a/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreTrustConfigTests.java
+++ b/libs/ssl-config/src/test/java/org/opensearch/common/ssl/StoreTrustConfigTests.java
@@ -49,6 +49,9 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import static org.opensearch.common.crypto.KeyStoreType.BCFKS;
+import static org.opensearch.common.crypto.KeyStoreType.JKS;
+import static org.opensearch.common.crypto.KeyStoreType.PKCS_12;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.nullValue;
@@ -56,20 +59,28 @@ public class StoreTrustConfigTests extends OpenSearchTestCase {
private static final char[] P12_PASS = "p12-pass".toCharArray();
private static final char[] JKS_PASS = "jks-pass".toCharArray();
+ private static final char[] BCFKS_PASS = "bcfks-pass".toCharArray();
private static final String DEFAULT_ALGORITHM = TrustManagerFactory.getDefaultAlgorithm();
- public void testBuildTrustConfigFromPKCS12() throws Exception {
+ public void testBuildTrustConfigFromP12() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path ks = getDataPath("/certs/ca1/ca.p12");
- final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, P12_PASS, "PKCS12", DEFAULT_ALGORITHM);
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, P12_PASS, PKCS_12, DEFAULT_ALGORITHM);
assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
assertCertificateChain(trustConfig, "CN=Test CA 1");
}
- public void testBuildTrustConfigFromJKS() throws Exception {
+ public void testBuildTrustConfigFromJks() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path ks = getDataPath("/certs/ca-all/ca.jks");
- final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, JKS_PASS, "jks", DEFAULT_ALGORITHM);
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, JKS_PASS, JKS, DEFAULT_ALGORITHM);
+ assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
+ assertCertificateChain(trustConfig, "CN=Test CA 1", "CN=Test CA 2", "CN=Test CA 3");
+ }
+
+ public void testBuildTrustConfigFromBcfks() throws Exception {
+ final Path ks = getDataPath("/certs/ca-all/ca.bcfks");
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, BCFKS_PASS, BCFKS, DEFAULT_ALGORITHM);
assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
assertCertificateChain(trustConfig, "CN=Test CA 1", "CN=Test CA 2", "CN=Test CA 3");
}
@@ -78,7 +89,7 @@ public void testBadKeyStoreFormatFails() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path ks = createTempFile("ca", ".p12");
Files.write(ks, randomByteArrayOfLength(128), StandardOpenOption.APPEND);
- final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], randomFrom("PKCS12", "jks"), DEFAULT_ALGORITHM);
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], randomFrom(PKCS_12, JKS), DEFAULT_ALGORITHM);
assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
assertInvalidFileFormat(trustConfig, ks);
}
@@ -86,33 +97,50 @@ public void testBadKeyStoreFormatFails() throws Exception {
public void testMissingKeyStoreFailsWithMeaningfulMessage() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path ks = getDataPath("/certs/ca-all/ca.p12").getParent().resolve("keystore.dne");
- final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], randomFrom("PKCS12", "jks"), DEFAULT_ALGORITHM);
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], randomFrom(PKCS_12, JKS), DEFAULT_ALGORITHM);
assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
assertFileNotFound(trustConfig, ks);
}
- public void testIncorrectPasswordFailsWithMeaningfulMessage() throws Exception {
+ public void testIncorrectPasswordFailsForP12WithMeaningfulMessage() throws Exception {
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
final Path ks = getDataPath("/certs/ca1/ca.p12");
- final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], "PKCS12", DEFAULT_ALGORITHM);
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], PKCS_12, DEFAULT_ALGORITHM);
+ assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
+ assertPasswordIsIncorrect(trustConfig, ks);
+ }
+
+ public void testIncorrectPasswordFailsForBcfksWithMeaningfulMessage() throws Exception {
+ final Path ks = getDataPath("/certs/cert-all/certs.bcfks");
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(
+ ks,
+ randomAlphaOfLengthBetween(6, 8).toCharArray(),
+ BCFKS,
+ DEFAULT_ALGORITHM
+ );
assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
assertPasswordIsIncorrect(trustConfig, ks);
}
- public void testMissingTrustEntriesFailsWithMeaningfulMessage() throws Exception {
+ public void testMissingTrustEntriesFailsForJksKeystoreWithMeaningfulMessage() throws Exception {
assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
- final Path ks;
- final char[] password;
- final String type;
- if (randomBoolean()) {
- type = "PKCS12";
- ks = getDataPath("/certs/cert-all/certs.p12");
- password = P12_PASS;
- } else {
- type = "jks";
- ks = getDataPath("/certs/cert-all/certs.jks");
- password = JKS_PASS;
- }
- final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, password, type, DEFAULT_ALGORITHM);
+ final Path ks = getDataPath("/certs/cert-all/certs.jks");
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, JKS_PASS, JKS, DEFAULT_ALGORITHM);
+ assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
+ assertNoCertificateEntries(trustConfig, ks);
+ }
+
+ public void testMissingTrustEntriesFailsForP12KeystoreWithMeaningfulMessage() throws Exception {
+ assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm());
+ final Path ks = getDataPath("/certs/cert-all/certs.p12");
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, P12_PASS, PKCS_12, DEFAULT_ALGORITHM);
+ assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
+ assertNoCertificateEntries(trustConfig, ks);
+ }
+
+ public void testMissingTrustEntriesFailsForBcfksKeystoreWithMeaningfulMessage() throws Exception {
+ final Path ks = getDataPath("/certs/cert-all/certs.bcfks");
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, BCFKS_PASS, BCFKS, DEFAULT_ALGORITHM);
assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks));
assertNoCertificateEntries(trustConfig, ks);
}
@@ -124,7 +152,7 @@ public void testTrustConfigReloadsKeysStoreContents() throws Exception {
final Path ks = createTempFile("ca", "p12");
- final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, P12_PASS, "PKCS12", DEFAULT_ALGORITHM);
+ final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, P12_PASS, PKCS_12, DEFAULT_ALGORITHM);
Files.copy(ks1, ks, StandardCopyOption.REPLACE_EXISTING);
assertCertificateChain(trustConfig, "CN=Test CA 1");
diff --git a/libs/ssl-config/src/test/resources/certs/README.md b/libs/ssl-config/src/test/resources/certs/README.md
new file mode 100644
index 0000000000000..e363e287c9521
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/README.md
@@ -0,0 +1,172 @@
+#!/usr/bin/env bash
+#
+# This is README describes how the certificates in this directory were created.
+# This file can also be executed as a script
+#
+
+# 1. Create first CA PEM ("ca1")
+
+opensearch-certutil ca --pem --out ca1.zip --days 9999 --ca-dn "CN=Test CA 1"
+unzip ca1.zip
+mv ca ca1
+
+# 2. Create first CA PEM ("ca2")
+
+opensearch-certutil ca --pem --out ca2.zip --days 9999 --ca-dn "CN=Test CA 2"
+unzip ca2.zip
+mv ca ca2
+
+# 3. Create first CA PEM ("ca3")
+
+opensearch-certutil ca --pem --out ca3.zip --days 9999 --ca-dn "CN=Test CA 3"
+unzip ca3.zip
+mv ca ca3
+
+# 4. Create "cert1-pkcs1" PEM
+
+opensearch-certutil cert --pem --out cert1-pkcs1.zip --name cert1 --ip 127.0.0.1 --dns localhost --days 9999 --ca-key ca1/ca.key --ca-cert ca1/ca.crt
+unzip cert1.zip
+
+# 5. Create "cert2-pkcs1" PEM (same as cert1, but with a password)
+
+opensearch-certutil cert --pem --out cert2-pkcs1.zip --name cert2 --ip 127.0.0.1 --dns localhost --days 9999 --ca-key ca1/ca.key --ca-cert ca1/ca.crt --pass "c2-pass"
+unzip cert2.zip
+
+# 6. Create "cert1" PEM
+
+```bash
+openssl genpkey -algorithm RSA -out cert1/cert1.key
+openssl req -new \
+ -key cert1/cert1.key \
+ -subj "/CN=cert1" \
+ -out cert1/cert1.csr
+openssl x509 -req \
+ -in cert1/cert1.csr \
+ -CA ca1/ca.crt \
+ -CAkey ca1/ca.key \
+ -CAcreateserial \
+ -out cert1/cert1.crt \
+ -days 3650 \
+ -sha256 \
+ -extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1")
+rm cert1/cert1.csr
+```
+
+# 7. Create "cert2" PEM (same as cert1, but with a password)
+
+```bash
+openssl genpkey -algorithm RSA -out cert2/cert2.key -aes256 -pass pass:"$KEY_PW"
+openssl req -new \
+-key cert2/cert2.key \
+-subj "/CN=cert2" \
+-out cert2/cert2.csr \
+-passin pass:"$KEY_PW"
+openssl x509 -req \
+-in cert2/cert2.csr \
+-CA ca1/ca.crt \
+-CAkey ca1/ca.key \
+-CAcreateserial \
+-out cert2/cert2.crt \
+-days 3650 \
+-sha256 \
+-extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1") \
+-passin pass:"$KEY_PW"
+rm cert2/cert2.csr
+```
+
+# 8. Convert CAs to PKCS#12
+
+for n in 1 2 3
+do
+ keytool -importcert -file ca${n}/ca.crt -alias ca -keystore ca${n}/ca.p12 -storetype PKCS12 -storepass p12-pass -v
+ keytool -importcert -file ca${n}/ca.crt -alias ca${n} -keystore ca-all/ca.p12 -storetype PKCS12 -storepass p12-pass -v
+done
+
+# 9. Convert CAs to JKS
+
+for n in 1 2 3
+do
+ keytool -importcert -file ca${n}/ca.crt -alias ca${n} -keystore ca-all/ca.jks -storetype jks -storepass jks-pass -v
+done
+
+# 10. Convert CAs to BCFKS
+
+for n in 1 2 3
+do
+ keytool -importcert -file ca${n}/ca.crt -alias ca${n} -keystore ca-all/ca.bcfks -storetype BCFKS -storepass bcfks-pass -providername BCFIPS -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider -providerpath $LIB_PATH/bc-fips-2.0.0.jar -v
+done
+
+# 11. Convert Certs to PKCS#12
+
+for Cert in cert1 cert2
+do
+ openssl pkcs12 -export -out $Cert/$Cert.p12 -inkey $Cert/$Cert.key -in $Cert/$Cert.crt -name $Cert -passout pass:p12-pass
+done
+
+# 12. Import Certs into single PKCS#12 keystore
+
+for Cert in cert1 cert2
+do
+ keytool -importkeystore -noprompt \
+ -srckeystore $Cert/$Cert.p12 -srcstoretype PKCS12 -srcstorepass p12-pass \
+ -destkeystore cert-all/certs.p12 -deststoretype PKCS12 -deststorepass p12-pass
+done
+
+# 13. Import Certs into single JKS keystore with separate key-password
+
+for Cert in cert1 cert2
+do
+ keytool -importkeystore -noprompt \
+ -srckeystore $Cert/$Cert.p12 -srcstoretype PKCS12 -srcstorepass p12-pass \
+ -destkeystore cert-all/certs.jks -deststoretype jks -deststorepass jks-pass
+ keytool -keypasswd -keystore cert-all/certs.jks -alias $Cert -keypass p12-pass -new key-pass -storepass jks-pass
+done
+
+# 14. Import Certs into single BCFKS keystore with separate key-password
+
+for Cert in cert1 cert2
+do
+ keytool -importkeystore -noprompt \
+ -srckeystore $Cert/$Cert.p12 \
+ -srcstoretype PKCS12 \
+ -srcstorepass p12-pass \
+ -destkeystore cert-all/certs.bcfks \
+ -deststoretype BCFKS \
+ -deststorepass bcfks-pass \
+ -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath $LIB_PATH/bc-fips-2.0.0.jar
+ keytool -keypasswd -noprompt \
+ -keystore cert-all/certs.bcfks \
+ -alias $Cert \
+ -keypass p12-pass \
+ -new bcfks-pass \
+ -storepass bcfks-pass \
+ -storetype BCFKS \
+ -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath $LIB_PATH/bc-fips-2.0.0.jar
+done
+
+# 15. Create a mimic of the first CA ("ca1b") for testing certificates with the same name but different keys
+
+opensearch-certutil ca --pem --out ${PWD}/ca1-b.zip --days 9999 --ca-dn "CN=Test CA 1"
+unzip ca1-b.zip
+mv ca ca1-b
+
+# 16. Create empty KeyStore
+
+```bash
+keytool -genkeypair \
+ -alias temp \
+ -storetype JKS \
+ -keyalg rsa \
+ -storepass storePassword \
+ -keypass secretPassword \
+ -keystore cert-all/empty.jks \
+ -dname "CN=foo,DC=example,DC=com"
+keytool -delete \
+ -alias temp \
+ -storepass storePassword \
+ -keystore cert-all/empty.jks
+```
diff --git a/libs/ssl-config/src/test/resources/certs/README.txt b/libs/ssl-config/src/test/resources/certs/README.txt
deleted file mode 100644
index 09910e99a132e..0000000000000
--- a/libs/ssl-config/src/test/resources/certs/README.txt
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env bash
-#
-# This is README describes how the certificates in this directory were created.
-# This file can also be executed as a script
-#
-
-# 1. Create first CA PEM ("ca1")
-
-opensearch-certutil ca --pem --out ca1.zip --days 9999 --ca-dn "CN=Test CA 1"
-unzip ca1.zip
-mv ca ca1
-
-# 2. Create first CA PEM ("ca2")
-
-opensearch-certutil ca --pem --out ca2.zip --days 9999 --ca-dn "CN=Test CA 2"
-unzip ca2.zip
-mv ca ca2
-
-# 3. Create first CA PEM ("ca3")
-
-opensearch-certutil ca --pem --out ca3.zip --days 9999 --ca-dn "CN=Test CA 3"
-unzip ca3.zip
-mv ca ca3
-
-# 4. Create "cert1" PEM
-
-opensearch-certutil cert --pem --out cert1.zip --name cert1 --ip 127.0.0.1 --dns localhost --days 9999 --ca-key ca1/ca.key --ca-cert ca1/ca.crt
-unzip cert1.zip
-
-# 5. Create "cert2" PEM (same as cert1, but with a password)
-
-opensearch-certutil cert --pem --out cert2.zip --name cert2 --ip 127.0.0.1 --dns localhost --days 9999 --ca-key ca1/ca.key --ca-cert ca1/ca.crt --pass "c2-pass"
-unzip cert2.zip
-
-# 6. Convert CAs to PKCS#12
-
-for n in 1 2 3
-do
- keytool -importcert -file ca${n}/ca.crt -alias ca -keystore ca${n}/ca.p12 -storetype PKCS12 -storepass p12-pass -v
- keytool -importcert -file ca${n}/ca.crt -alias ca${n} -keystore ca-all/ca.p12 -storetype PKCS12 -storepass p12-pass -v
-done
-
-# 7. Convert CAs to JKS
-
-for n in 1 2 3
-do
- keytool -importcert -file ca${n}/ca.crt -alias ca${n} -keystore ca-all/ca.jks -storetype jks -storepass jks-pass -v
-done
-
-# 8. Convert Certs to PKCS#12
-
-for Cert in cert1 cert2
-do
- openssl pkcs12 -export -out $Cert/$Cert.p12 -inkey $Cert/$Cert.key -in $Cert/$Cert.crt -name $Cert -passout pass:p12-pass
-done
-
-# 9. Import Certs into single PKCS#12 keystore
-
-for Cert in cert1 cert2
-do
- keytool -importkeystore -noprompt \
- -srckeystore $Cert/$Cert.p12 -srcstoretype PKCS12 -srcstorepass p12-pass \
- -destkeystore cert-all/certs.p12 -deststoretype PKCS12 -deststorepass p12-pass
-done
-
-# 10. Import Certs into single JKS keystore with separate key-password
-
-for Cert in cert1 cert2
-do
- keytool -importkeystore -noprompt \
- -srckeystore $Cert/$Cert.p12 -srcstoretype PKCS12 -srcstorepass p12-pass \
- -destkeystore cert-all/certs.jks -deststoretype jks -deststorepass jks-pass
- keytool -keypasswd -keystore cert-all/certs.jks -alias $Cert -keypass p12-pass -new key-pass -storepass jks-pass
-done
-
-# 11. Create a mimic of the first CA ("ca1b") for testing certificates with the same name but different keys
-
-opensearch-certutil ca --pem --out ${PWD}/ca1-b.zip --days 9999 --ca-dn "CN=Test CA 1"
-unzip ca1-b.zip
-mv ca ca1-b
-
-# 12. Convert certifcate keys to pkcs8
-
-openssl pkcs8 -topk8 -inform PEM -in cert1/cert1.key -outform PEM -out cert1/cert1-pkcs8.key -nocrypt
-openssl pkcs8 -topk8 -inform PEM -in cert2/cert2.key -outform PEM -out cert2/cert2-pkcs8.key -passin pass:"c2-pass" -passout pass:"c2-pass"
diff --git a/libs/ssl-config/src/test/resources/certs/ca-all/ca.bcfks b/libs/ssl-config/src/test/resources/certs/ca-all/ca.bcfks
new file mode 100644
index 0000000000000..f27717d0ce67a
Binary files /dev/null and b/libs/ssl-config/src/test/resources/certs/ca-all/ca.bcfks differ
diff --git a/libs/ssl-config/src/test/resources/certs/cert-all/certs.bcfks b/libs/ssl-config/src/test/resources/certs/cert-all/certs.bcfks
new file mode 100644
index 0000000000000..1eab5af506b2c
Binary files /dev/null and b/libs/ssl-config/src/test/resources/certs/cert-all/certs.bcfks differ
diff --git a/libs/ssl-config/src/test/resources/certs/cert-all/certs.p12 b/libs/ssl-config/src/test/resources/certs/cert-all/certs.p12
index b971a1e39c83b..73912976ca7cc 100644
Binary files a/libs/ssl-config/src/test/resources/certs/cert-all/certs.p12 and b/libs/ssl-config/src/test/resources/certs/cert-all/certs.p12 differ
diff --git a/libs/ssl-config/src/test/resources/certs/cert-all/empty.jks b/libs/ssl-config/src/test/resources/certs/cert-all/empty.jks
new file mode 100644
index 0000000000000..1327d550f61fd
Binary files /dev/null and b/libs/ssl-config/src/test/resources/certs/cert-all/empty.jks differ
diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs1.crt b/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs1.crt
new file mode 100644
index 0000000000000..51f39295f62e3
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs1.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAgOgAwIBAgIUCYPL1cogC+8WOfSZytklHmrHQh4wDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTE5MDEwMzA3NDA0MloXDTQ2MDUy
+MDA3NDA0MlowEDEOMAwGA1UEAxMFY2VydDEwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCWz6ITDTlkTLueB30Jx0+7sWHdlM5ObZjWhMQ1eyJD0gYU/gkH
+2C88IN/PtSv04tzFS6PA4KPDLIyaAhczPlGElSansiui//CpieCI4tt5c2BgVo3X
+dJaylYoW3CRILUrlSBOMUmJCQEokverxMrz8DeppNxRfj99pQkoxUkmFMZj/C7XN
+VYrTttdF1li5FUtWJxw234OUfum3PQIzz6YTmoPtLrJ2fB8I4CH8R5hwGcryhBSA
+qq8pgy61aTPCgEBZ1c4Dvl65X8dG2QEVPjwMZnnbGjvlZefOgkmAWJ1VjihA3GVg
+O2mx4tB4D2x5K/OAxh2foZkDVhqJfBkOblLnAgMBAAGjaTBnMB0GA1UdDgQWBBRM
+RZ6Qlozj5hWTqf3+oTznFyZTsDAfBgNVHSMEGDAWgBSHd+NjwqkE6hVMEnltx6cT
++D11lzAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCQYDVR0TBAIwADANBgkq
+hkiG9w0BAQsFAAOCAQEAOTUJ64T6kO2H51j2bKIof4ij4yoDD86gLmUF7qXB2Wt4
+tMDCqs9+5VnRzSWY1652mpwPClcK/MfE26PR6DUunoES+8VSbARWh0OB6zsAAWyp
+WJ4RxlfYdNpJZjpx3umLGj4yeCh0iOhfoArBUT3vaJJrea+rTro4UFE2Z29uWALr
+NvjKZ0Qrn1DMP3N9b7y81dR9RMlzeqk5tlPhAqhHzQM0hDdFKA5uIFn71QQpd5SI
+y8MpllWFGGq/+5m7FD0t71GQ/m5xCyfUiqQU31Nj3ThU21SPHBqZIZvQ/na/OaAf
+GySn+0ZHAvyNRTL2y2Fk/YAY68kgx2E44H5YSqbFJA==
+-----END CERTIFICATE-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs1.key b/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs1.key
new file mode 100644
index 0000000000000..461ae5ee31ba7
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs1.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAls+iEw05ZEy7ngd9CcdPu7Fh3ZTOTm2Y1oTENXsiQ9IGFP4J
+B9gvPCDfz7Ur9OLcxUujwOCjwyyMmgIXMz5RhJUmp7Irov/wqYngiOLbeXNgYFaN
+13SWspWKFtwkSC1K5UgTjFJiQkBKJL3q8TK8/A3qaTcUX4/faUJKMVJJhTGY/wu1
+zVWK07bXRdZYuRVLViccNt+DlH7ptz0CM8+mE5qD7S6ydnwfCOAh/EeYcBnK8oQU
+gKqvKYMutWkzwoBAWdXOA75euV/HRtkBFT48DGZ52xo75WXnzoJJgFidVY4oQNxl
+YDtpseLQeA9seSvzgMYdn6GZA1YaiXwZDm5S5wIDAQABAoIBABCilJEfa045/JQA
+5XT3rD7a4R2s9VjHVA2NlYsEqxHqD8uu/dYEraknQyjJJjEb+Rg2MLjszoOP3W57
+fo2jeSBzx1DGIXQYYTaCQ+c1htoNtPrLcVfrv1exkQrWe5YOkO1blvRqffYq20LU
+RB8Y5qmy60Fx1uh3mUAmFML9/agYVJo4yCxnNDrMg9UjF4bn/39uOf6C7mEVJRTl
+7ET5wcbdl10EOWW2m60hJOQLSOY9N1eafFEO+V2Xb80PC2t3Mqt5+T7n0CKCx/p9
+4F7QAz+hsfksY3oTUUXwL0KoJTLdJrjCoG4mWJ/Re3qEKJqmMfT4XpJKrF7HfgcK
+RCyH06kCgYEA/5TVQK4G1Dc4LnSCmCb+ECQvmGRBtK6Alh3Txb4IwGHDGMfC8W4O
+gt03A8ZE92pjITHd1+cLykKBsmaVmEtiyD7YL5G3mumR1YdMFEBSZdxOTeD95+aL
+YxTofPsDIUIPSFecRWwri7TyYcvUGyDchL0vDc6Gp95/ZFFgt26uxAsCgYEAlw7e
+g2McHws9cSAfouULbKbf6jXzy21t6CeqJGID/kjdUws63prcQvmFtFHWrv3rKO09
+hgb3Kd3gUz8t9tAD3F718bSZwzLASwO5ujPHZQVRTotutgCGeKPgXqzyVWeo45ji
+4DfQl53jG0aA1DzoZSA3/owcuX6CVGPLzQnhehUCgYAHe9UuuqnKhv9nJNQ6HlIs
+KNMX9D+USdPMEX2E+caJ05MB47+KkD1uiYm125VjZUMX0rz7OHG472+ayLQyrGpt
+EKIF6o9kwtgZV4fbw/Jltyi30RG+O5rzQMZ5+mOiEqwd4yrZQYyY36iFQpGoZbLv
+VBbPoa+BtNsoFdXuKRiG9wKBgBjJhdXFc53ceE6R2N8f+onvsBp8k+6znC9WIuMp
+ekJFrpur4hMZEj+jNj9qlnHMlMP4efn+NpyWHfNLEL3JUHje1Di/S+Pt9gPZLqbR
+TEzVXIwo8RfIakhti6m9c150ThBazA/C2OWoMNYO8aDiBbhiWw3X6/a8PaKfZZfV
+oTwpAoGASCTx55uThl9rN+XDKFXN500K4r+Q9OBOEkfDuDUERpBohUfoy8dO5eiT
+mGiqx5P0hoxEC70vnw5fJz4ZpSJ7LcpCfq2TezknJP3MZKwTdBM/pODSPMU5YCW4
+T9ocEQui5PKOTLlVo1QKrG8w6f/YMfZuGa9zP/LmTLZEado9nuk=
+-----END RSA PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs8.key b/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs8.key
deleted file mode 100644
index 1e8f219eecee7..0000000000000
--- a/libs/ssl-config/src/test/resources/certs/cert1/cert1-pkcs8.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCWz6ITDTlkTLue
-B30Jx0+7sWHdlM5ObZjWhMQ1eyJD0gYU/gkH2C88IN/PtSv04tzFS6PA4KPDLIya
-AhczPlGElSansiui//CpieCI4tt5c2BgVo3XdJaylYoW3CRILUrlSBOMUmJCQEok
-verxMrz8DeppNxRfj99pQkoxUkmFMZj/C7XNVYrTttdF1li5FUtWJxw234OUfum3
-PQIzz6YTmoPtLrJ2fB8I4CH8R5hwGcryhBSAqq8pgy61aTPCgEBZ1c4Dvl65X8dG
-2QEVPjwMZnnbGjvlZefOgkmAWJ1VjihA3GVgO2mx4tB4D2x5K/OAxh2foZkDVhqJ
-fBkOblLnAgMBAAECggEAEKKUkR9rTjn8lADldPesPtrhHaz1WMdUDY2ViwSrEeoP
-y6791gStqSdDKMkmMRv5GDYwuOzOg4/dbnt+jaN5IHPHUMYhdBhhNoJD5zWG2g20
-+stxV+u/V7GRCtZ7lg6Q7VuW9Gp99irbQtREHxjmqbLrQXHW6HeZQCYUwv39qBhU
-mjjILGc0OsyD1SMXhuf/f245/oLuYRUlFOXsRPnBxt2XXQQ5ZbabrSEk5AtI5j03
-V5p8UQ75XZdvzQ8La3cyq3n5PufQIoLH+n3gXtADP6Gx+SxjehNRRfAvQqglMt0m
-uMKgbiZYn9F7eoQomqYx9PhekkqsXsd+BwpELIfTqQKBgQD/lNVArgbUNzgudIKY
-Jv4QJC+YZEG0roCWHdPFvgjAYcMYx8Lxbg6C3TcDxkT3amMhMd3X5wvKQoGyZpWY
-S2LIPtgvkbea6ZHVh0wUQFJl3E5N4P3n5otjFOh8+wMhQg9IV5xFbCuLtPJhy9Qb
-INyEvS8Nzoan3n9kUWC3bq7ECwKBgQCXDt6DYxwfCz1xIB+i5Qtspt/qNfPLbW3o
-J6okYgP+SN1TCzremtxC+YW0Udau/eso7T2GBvcp3eBTPy320APcXvXxtJnDMsBL
-A7m6M8dlBVFOi262AIZ4o+BerPJVZ6jjmOLgN9CXneMbRoDUPOhlIDf+jBy5foJU
-Y8vNCeF6FQKBgAd71S66qcqG/2ck1DoeUiwo0xf0P5RJ08wRfYT5xonTkwHjv4qQ
-PW6JibXblWNlQxfSvPs4cbjvb5rItDKsam0QogXqj2TC2BlXh9vD8mW3KLfREb47
-mvNAxnn6Y6ISrB3jKtlBjJjfqIVCkahlsu9UFs+hr4G02ygV1e4pGIb3AoGAGMmF
-1cVzndx4TpHY3x/6ie+wGnyT7rOcL1Yi4yl6QkWum6viExkSP6M2P2qWccyUw/h5
-+f42nJYd80sQvclQeN7UOL9L4+32A9kuptFMTNVcjCjxF8hqSG2Lqb1zXnROEFrM
-D8LY5agw1g7xoOIFuGJbDdfr9rw9op9ll9WhPCkCgYBIJPHnm5OGX2s35cMoVc3n
-TQriv5D04E4SR8O4NQRGkGiFR+jLx07l6JOYaKrHk/SGjEQLvS+fDl8nPhmlInst
-ykJ+rZN7OSck/cxkrBN0Ez+k4NI8xTlgJbhP2hwRC6Lk8o5MuVWjVAqsbzDp/9gx
-9m4Zr3M/8uZMtkRp2j2e6Q==
------END PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1.crt b/libs/ssl-config/src/test/resources/certs/cert1/cert1.crt
index 51f39295f62e3..576de3bb28fb4 100644
--- a/libs/ssl-config/src/test/resources/certs/cert1/cert1.crt
+++ b/libs/ssl-config/src/test/resources/certs/cert1/cert1.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDGzCCAgOgAwIBAgIUCYPL1cogC+8WOfSZytklHmrHQh4wDQYJKoZIhvcNAQEL
-BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTE5MDEwMzA3NDA0MloXDTQ2MDUy
-MDA3NDA0MlowEDEOMAwGA1UEAxMFY2VydDEwggEiMA0GCSqGSIb3DQEBAQUAA4IB
-DwAwggEKAoIBAQCWz6ITDTlkTLueB30Jx0+7sWHdlM5ObZjWhMQ1eyJD0gYU/gkH
-2C88IN/PtSv04tzFS6PA4KPDLIyaAhczPlGElSansiui//CpieCI4tt5c2BgVo3X
-dJaylYoW3CRILUrlSBOMUmJCQEokverxMrz8DeppNxRfj99pQkoxUkmFMZj/C7XN
-VYrTttdF1li5FUtWJxw234OUfum3PQIzz6YTmoPtLrJ2fB8I4CH8R5hwGcryhBSA
-qq8pgy61aTPCgEBZ1c4Dvl65X8dG2QEVPjwMZnnbGjvlZefOgkmAWJ1VjihA3GVg
-O2mx4tB4D2x5K/OAxh2foZkDVhqJfBkOblLnAgMBAAGjaTBnMB0GA1UdDgQWBBRM
-RZ6Qlozj5hWTqf3+oTznFyZTsDAfBgNVHSMEGDAWgBSHd+NjwqkE6hVMEnltx6cT
-+D11lzAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCQYDVR0TBAIwADANBgkq
-hkiG9w0BAQsFAAOCAQEAOTUJ64T6kO2H51j2bKIof4ij4yoDD86gLmUF7qXB2Wt4
-tMDCqs9+5VnRzSWY1652mpwPClcK/MfE26PR6DUunoES+8VSbARWh0OB6zsAAWyp
-WJ4RxlfYdNpJZjpx3umLGj4yeCh0iOhfoArBUT3vaJJrea+rTro4UFE2Z29uWALr
-NvjKZ0Qrn1DMP3N9b7y81dR9RMlzeqk5tlPhAqhHzQM0hDdFKA5uIFn71QQpd5SI
-y8MpllWFGGq/+5m7FD0t71GQ/m5xCyfUiqQU31Nj3ThU21SPHBqZIZvQ/na/OaAf
-GySn+0ZHAvyNRTL2y2Fk/YAY68kgx2E44H5YSqbFJA==
+MIIDEDCCAfigAwIBAgIULU6478tMe6npOywF6dj4+azLeJEwDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTI0MDgyOTA5MzE0OFoXDTM0MDgy
+NzA5MzE0OFowEDEOMAwGA1UEAwwFY2VydDEwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC+9V4E9sliTrt7NgkpG95rrXntGcybvp/EwDjaHbVyagQ34aMT
+gjhKRhzmGzwX7YkeYpob8JmMOwyurxur0KOpSQZMcUM7QneO16EV/8otRwWfyApF
+AzD7gANdTyRcnO9h3aUEBJvvve4fDFleqnj9AexGBIqyHRcA8hjYTjIIKGQbgFIi
+7DvS/405AinDU6sAQt70+pZ3P5pHF6AsHhEhma5+cX/I7q4XIJxaLwpsh8ySWq2P
+FMaJxMKoLXhuNALZ/n5Ur1grDZG91cPF+vpJu4qV9zjalLHASM6u+CK+roFT8P3n
+P98viKDLaFzEwjqoKkVoIY/73ESiuHOi7KQVAgMBAAGjXjBcMBoGA1UdEQQTMBGC
+CWxvY2FsaG9zdIcEfwAAATAdBgNVHQ4EFgQUL0u1Ps+kFvjYsf0T6rXPc7H0ls8w
+HwYDVR0jBBgwFoAUh3fjY8KpBOoVTBJ5bcenE/g9dZcwDQYJKoZIhvcNAQELBQAD
+ggEBAGRPhduypDVICV0q7nEaK6MUsF//W826rYvy9ePZzAAcx99si1UyAyLFFKRA
+GtmkTiyO98AWqO7g5ztSuaN+5RxzSjPtcmOIgO2lu7nWLHO2Mr5uG1m6ssjGvQBz
+IjXL9F2+oJeiOllQ/kSvTO8J0nUnz5EJi9JVwHMIb0GCfHrB01rp1UKfbPzXYnFz
+t3oWro4idhgVpoBp+RNxRV6Z/7fMNBdc5acZFLTpRThs88CQRx5XqRl/X9FSrsbR
+nuFwg8jc7taHhMOxMPQ+GPM9hZ4fGLfF3WSqRuyypMR8ztxXi3VmnSgvLhQ8OSz8
+yM3mR4IpH+oys6uyqvcxvtY7Qk8=
-----END CERTIFICATE-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1.key b/libs/ssl-config/src/test/resources/certs/cert1/cert1.key
index 461ae5ee31ba7..b7ad0d595d7b7 100644
--- a/libs/ssl-config/src/test/resources/certs/cert1/cert1.key
+++ b/libs/ssl-config/src/test/resources/certs/cert1/cert1.key
@@ -1,27 +1,28 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAls+iEw05ZEy7ngd9CcdPu7Fh3ZTOTm2Y1oTENXsiQ9IGFP4J
-B9gvPCDfz7Ur9OLcxUujwOCjwyyMmgIXMz5RhJUmp7Irov/wqYngiOLbeXNgYFaN
-13SWspWKFtwkSC1K5UgTjFJiQkBKJL3q8TK8/A3qaTcUX4/faUJKMVJJhTGY/wu1
-zVWK07bXRdZYuRVLViccNt+DlH7ptz0CM8+mE5qD7S6ydnwfCOAh/EeYcBnK8oQU
-gKqvKYMutWkzwoBAWdXOA75euV/HRtkBFT48DGZ52xo75WXnzoJJgFidVY4oQNxl
-YDtpseLQeA9seSvzgMYdn6GZA1YaiXwZDm5S5wIDAQABAoIBABCilJEfa045/JQA
-5XT3rD7a4R2s9VjHVA2NlYsEqxHqD8uu/dYEraknQyjJJjEb+Rg2MLjszoOP3W57
-fo2jeSBzx1DGIXQYYTaCQ+c1htoNtPrLcVfrv1exkQrWe5YOkO1blvRqffYq20LU
-RB8Y5qmy60Fx1uh3mUAmFML9/agYVJo4yCxnNDrMg9UjF4bn/39uOf6C7mEVJRTl
-7ET5wcbdl10EOWW2m60hJOQLSOY9N1eafFEO+V2Xb80PC2t3Mqt5+T7n0CKCx/p9
-4F7QAz+hsfksY3oTUUXwL0KoJTLdJrjCoG4mWJ/Re3qEKJqmMfT4XpJKrF7HfgcK
-RCyH06kCgYEA/5TVQK4G1Dc4LnSCmCb+ECQvmGRBtK6Alh3Txb4IwGHDGMfC8W4O
-gt03A8ZE92pjITHd1+cLykKBsmaVmEtiyD7YL5G3mumR1YdMFEBSZdxOTeD95+aL
-YxTofPsDIUIPSFecRWwri7TyYcvUGyDchL0vDc6Gp95/ZFFgt26uxAsCgYEAlw7e
-g2McHws9cSAfouULbKbf6jXzy21t6CeqJGID/kjdUws63prcQvmFtFHWrv3rKO09
-hgb3Kd3gUz8t9tAD3F718bSZwzLASwO5ujPHZQVRTotutgCGeKPgXqzyVWeo45ji
-4DfQl53jG0aA1DzoZSA3/owcuX6CVGPLzQnhehUCgYAHe9UuuqnKhv9nJNQ6HlIs
-KNMX9D+USdPMEX2E+caJ05MB47+KkD1uiYm125VjZUMX0rz7OHG472+ayLQyrGpt
-EKIF6o9kwtgZV4fbw/Jltyi30RG+O5rzQMZ5+mOiEqwd4yrZQYyY36iFQpGoZbLv
-VBbPoa+BtNsoFdXuKRiG9wKBgBjJhdXFc53ceE6R2N8f+onvsBp8k+6znC9WIuMp
-ekJFrpur4hMZEj+jNj9qlnHMlMP4efn+NpyWHfNLEL3JUHje1Di/S+Pt9gPZLqbR
-TEzVXIwo8RfIakhti6m9c150ThBazA/C2OWoMNYO8aDiBbhiWw3X6/a8PaKfZZfV
-oTwpAoGASCTx55uThl9rN+XDKFXN500K4r+Q9OBOEkfDuDUERpBohUfoy8dO5eiT
-mGiqx5P0hoxEC70vnw5fJz4ZpSJ7LcpCfq2TezknJP3MZKwTdBM/pODSPMU5YCW4
-T9ocEQui5PKOTLlVo1QKrG8w6f/YMfZuGa9zP/LmTLZEado9nuk=
------END RSA PRIVATE KEY-----
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+9V4E9sliTrt7
+NgkpG95rrXntGcybvp/EwDjaHbVyagQ34aMTgjhKRhzmGzwX7YkeYpob8JmMOwyu
+rxur0KOpSQZMcUM7QneO16EV/8otRwWfyApFAzD7gANdTyRcnO9h3aUEBJvvve4f
+DFleqnj9AexGBIqyHRcA8hjYTjIIKGQbgFIi7DvS/405AinDU6sAQt70+pZ3P5pH
+F6AsHhEhma5+cX/I7q4XIJxaLwpsh8ySWq2PFMaJxMKoLXhuNALZ/n5Ur1grDZG9
+1cPF+vpJu4qV9zjalLHASM6u+CK+roFT8P3nP98viKDLaFzEwjqoKkVoIY/73ESi
+uHOi7KQVAgMBAAECggEABuyt3p82WUbCnKqudVup2py9TaBAX6tvbrqLtTkbkc0P
+XxljCPuRX/wf4yY8rR9zd/MaZIX6g2/Gu3TlG3ti2+omfNIknnsAC+F82WffpHmt
+VghyeuMtPQl81b7fci5Mre9UIwupve1Uu7J+cSTcY0xVDYrvnprYcTPWO83GGa6R
+NbYqZFMwqFer/emaIzLAVb4LWmmgpLN9Ki28s05j9CVyRvobevg3HLikhJKziEj/
+hq6RVY7wavdqGmWD20nRzTLVlwb3xLhd041oFhRxGd/KwWFzBqgfJCDEo31KeKJu
+8h1YMX93NRP01Ny1l4HNOr1T/GvcJ4FbBn/EMFeq5wKBgQDrV13/A1i1yCFsCBee
+kDblk3RpAwRo4w7+BJKpiX+6K+ZqT0mH+KaNtDd9MulxaJqFEeVsblKB4ILbIWhV
+EcihGpdN43hED69r/bBpFSYmWAptzSRJ8sAn3X6n4p0TJ4yHSOi249/Y/yZ8lO1f
+FepcYSI9R8Io8Tm/yp9ECzwnQwKBgQDPuJ8OEy3xtN7ZAjV1aFa4xLheFumDxkQf
+VrpMbkGQQ3xj+GRngy+cbzef9wr8Y8uwx7SlkItVNOHqx0hQyWoiIt6DdN8XlmzK
+5XJAn6WSk7dmcoRcSQhtotAZ86C1ATHbZCP7hHZM50bYBPpgYuk9ZBwmvxAcg0gj
+KAzU4R31xwKBgCesSsQ6pDHA0yGLG7A3T4nUGcO6JnwoCtb3nmHGNCoGTImPZC3v
+1OP+hXwtoPzlTWcxZSOqVW5fkq+uKhBtNw0xlmAjAJs4qbHiymJslknQfbGU65Er
+wwj1ZeyXXzNjb2U+/TwXnhzOpoZJ9Noar69zEHqUJj8Qq1ORrNejrThRAoGAciwy
+EJRuLmqSColyRMRC1nAaPm0tkOaLTwZmg9geZWMSnghLd7Hdm4ht9JjfCvb3YIWE
+P3SBgSX9/wPmNbFfir/Lukmkzdw6lBMlh2u4oCZdKgxLwEXMQia5Z2pHrPWpJ8OV
+G4wlUgPVJqsly5DSTpIV/x4JhwKJxfkfhGrwAsUCgYALt60wjxSkhFKTMB6+jViY
+Nso8Tdn4VIxCd6LsMpGgIyfbYyEsBgs3HypjfkSurAfW7VgsLoZqfIgTPSG9RVhY
+7I87ST2/qVa0Hd6i4SeoB6PQwiowkplkdN6486tGev1lbWpMAeQAkJ2NPmSDNL4M
+0j367yIVK4mvUArXQZhEqA==
+-----END PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1.p12 b/libs/ssl-config/src/test/resources/certs/cert1/cert1.p12
index 2635a887bc87e..af4918e031995 100644
Binary files a/libs/ssl-config/src/test/resources/certs/cert1/cert1.p12 and b/libs/ssl-config/src/test/resources/certs/cert1/cert1.p12 differ
diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs1.crt b/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs1.crt
new file mode 100644
index 0000000000000..3b7ca01e48bae
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs1.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAgOgAwIBAgIULGiQ5jnAntO91sS7Al5aUv8/jg8wDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTE5MDEwMzA3NDE1NVoXDTQ2MDUy
+MDA3NDE1NVowEDEOMAwGA1UEAxMFY2VydDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDQbV6x3P9sstd5zKkjOylk+/X1j0vI6C93HwkF3d9NwhMoV1zq
+aSj2SmAQCz4mIjMlAFR9mm6F+3sb8xkMFJD2Mypc5dW6TS5krhbhJdMpoVbceZtS
+yuIsvQi1GT2Uwyu89doDiUNBIANqaexrK5x2S/Fy4L8dNl1x2k6PJi6zVpvbnNLV
+TSbuSMp3oY23PpX/m6wzJlCYicO8ucMhPwmC0OL9WJNKny4vuEPdiV6/LwCVS4Vr
+UpfNqgXLzRMJEbx7C2QEG7T6o2g2101oANBuPaDZcwIQ//EI3IkT10JcABIbwsdj
+/Oqj0cf7iEW1IfJWx+kRVT8NfEA5QjL1KQ4HAgMBAAGjaTBnMB0GA1UdDgQWBBS+
+/gUxdwfGB0XcPHsbM6Qw50S2OTAfBgNVHSMEGDAWgBSHd+NjwqkE6hVMEnltx6cT
++D11lzAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCQYDVR0TBAIwADANBgkq
+hkiG9w0BAQsFAAOCAQEAiztFGa3uZVb6Fs8evN4CU+hPFYdhF57lEfT6Xa1OUD1B
+5e5rDOZfVloy4gzLdtNCS9lieTgB7Yc3wDUCm0cS48JCMxykSRTI6M0Fmofsgd5d
+OKR7CB+jR1Egj6nZren62XCgqjuJ+dbP4DinY6TifFzFX1vOD4RTb0mEn2WHL/JB
+DnDxOETmBtKFyueprMtXkTO23dXsYXQeo2Gyih+t5ksqMnxCW2GFkkOqrOUQY8CF
+6CVmmb9UCYk3f3Av9TedqJ8Cmoe+HSP0R2oxpnc7cd1v37QPxWgHETro9zS4FBrt
+6KgNTP99b+aLxeeuMKJuRVR+TCZPuyYbBzUfp2ZZOg==
+-----END CERTIFICATE-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs1.key b/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs1.key
new file mode 100644
index 0000000000000..1384b2daf309a
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs1.key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,68F4EFD94D4D9BDF
+
+TL01d1JqaN0P1sb8284jOGpLn42cubkLY7JPj+bmpL2PEH9cT2xo7MM5cwvNSbPX
+nuZ1CMFSFqAyxulh/rfZwU1BumKLiwM+ep0A/lWwKJEor+ancCBdkIHWfSg3Jc0i
++nHhL3e7+W+XRfSlafQQkhFkeOXs0hSa4WYX6tymvMAf8OLAenKB/0MOvKjd6EOu
+ZIvnBxAjAaDoRr4X4izIVlNmsIbvYARW9WjjcK2FZhNn+WLLTkfwEkl0glRl440L
+ET9qAjoH7j5KL5yKw5h2HhALSLaXdiAfCGvhpU4K0Afpb225mvR/uL3HLpJEGKKb
+DuoK99zvjHqReq1YndIR688ioc0O4dUvujZKgn8OR2JvGJVSc+mgaIWadfs2aADz
+CJIlqnSJa1EW6qm6knLJwieEBoNHbeFszrCKrYdy7uicys9PR1XsoMrOly+HhVnR
+PChA3gV6AVIjyMAUkFLg4NAHjgDbb81lu8ENFmlJcjgVeXDMykrpBmhzmhSPtOEb
+6bdQCKuA7zXIpJCmP66ZSuNHxikrfqLJjXW3PojLuCx5nfO0akpxjSeyLHzv/YXV
+YxnpLJxMybG1KUHyDHRmDrd+UPzLnh52O/g9NoiAlluUcblH+BKer18dJdGSl95G
+P+Ted08S0yP2niNz6XHv5KbztzsP73n0w82akCQB8ZAsGJ0CNw7S7N6tWam/UkMN
+tvM9nFCjvwah1funu8nj9QyWrzac6ngPP0s8tcKG0ahLEJYn7Hx2Oqn7K39fbMkX
+UOJVNEBQP2Anf5dJMfYPEI0xihv3ec1RxpipOm9DKQ878jxnqxgZxa+Pab9j/JxQ
+j+BGaoOnYj2jHBnt4nCP75F0BEZaGxsZX2MjJySK+5jy2WW3JRC/E0qPkL6oBvT2
+3e37fep4XKSjqR9lSYjW+AlAVw2uPkwxDp5sD7XFGsH3SM1qj54NWwljpKXnOTbQ
+Xws18VEiWsQ3kD7ft11w8/67Bb27TsWEJRo1vCC4KsYBCyjEOrp13aJxpSiNI24W
+oSmrQTsCco1Yrxfs0noNu0FzfJHV6qmHR7ps0fj+AWJyquYbIEK1762+r2uutgSg
+ZVaPWLkm9uq5K5rNXsj3w1L1CK4YcDre0yt+Kg4Pt3OQR2lF8CpABguA3gR9kO2g
+9N8hAfiOq5MDliU+9r6Cr/dPkdzV0Eo971HdfaLD7S/pjSP37fcTcOpDhwNt3UcK
+amhR/Zm8Ll414zc/iNiVTcu6+chzSY9Yhwfa8A/XuIfoqMrTiaBMPlxe0tNKaKVs
+09d6U5JoTQJcnei/4ODkIIYOzsmMtHgKtmeg86AB8yeLNgqWCrJi+Fxnha+cJ9No
++STMQP4vS8qgRe5XkRGaAZBHyPAwxOou1Iu167LjlFFl0YSYUZTChha5XBG2Uhm8
+FeIH1Ip+83fxMoyiYROOdeMuLXtQIndA3fmjduBEO0kPtAwQ2xfH4g59XnnSL97S
+9AslnPnUWzDR0zBr4GQBNAKLaMIFGzhDZEzaooYetoeDYSczil/Rf1D6wyM6Cgjq
+BK7c0kNum9uXaDbYCh6spzYua0j1noqsBTm9V25178lNbkQ6yAPdeYCxRmUXHtXk
+-----END RSA PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs8.key b/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs8.key
deleted file mode 100644
index 5463978f1c885..0000000000000
--- a/libs/ssl-config/src/test/resources/certs/cert2/cert2-pkcs8.key
+++ /dev/null
@@ -1,29 +0,0 @@
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIE6TAbBgkqhkiG9w0BBQMwDgQI3LMAczRe1pICAggABIIEyIfF+k/Z7mEPN+gu
-rrV4slxmFjnIzyjoOsWbFBN9j5W8kZGewzWvjnYAzVMVeMUXXW27EMOC818aF8Ry
-20BUVkmGNAUFVEslayeF0/S2sYR9xBPqYGLF0DI2VDTBIn8zrTdvQ0DYuuLf4g3W
-nY69paCGSVjP24xrnEck+X6PjwIQ89MsJlVLn2chPEetvgu2jB+OdRneSA+lqBSW
-2sDuKeXAmYdm3nCVz9do6T22OC9PUkzICGUvMyhYO4CD9dI3FFHa4ncKsr4+htfp
-p3eppDczSneDKTPmGJg41UrEVdfENvqYLbYrX2ZZRnWUeuLsGbZUsWyfMT5TT2yz
-sZXSS9+WRF8IDDhzKjsoSpsuNwMj8KMmc4oIrBNPysI+Bv0sQzPBlMJkHJ+Swb+W
-I2wWC7NS7cwGFEEzwXKYAYI/34e/fAa+oOHd/aNdpGDhhnRyG+Eut3GbojlODiXN
-ntLhDIZ+lQclJEkmxP2QfhIvjqkNBkPv+8Xt2Ami3ueF2iNj9PxQHUdx3aht1VMg
-uVNLc0qLl98fDYx7+U2q5Y4L1mViZrCwGW+lcaY6a8hscPuasqW9aolFTE95YLVU
-yFeUOZlUh1g5FYepISESR5jm5k9wf/WV2cp/KyAzCftdx2iRQtgvyQtSITFtthDa
-kR7jI/T/HE2aPqiEcd0Sx+66aSH2JspseJ4VsLGkpg2lU0FPtPaAsl8lIhlfdoDA
-43kOPKe5q2YT4QaUNZJROAuyJAlRbE8+LNlfAlZCm0UTQhgiXPzkEuVQFM4DNplq
-FkBZnW4R/hD2rP81oy/SISxIANTyAB0FfCRxrvSRP6xe0XMYTIqsUVt9gpszI6AY
-B+KTKlJR68cI8Gs1Jq6otn1ExAlCX45mwfaFO6Be89U0YNCZXdJ0X66SFNPmsMrg
-eNbRLGziUhyoVUuPEhLXrxtuaGUO0LdHDSCQQGVNKCwNKbcWOE1clYWcJ1Lj0a7T
-BTb4y1Nqt7LOHm5En5RtSaourgEKvi6PS2EcemBSUG4xSSP1pEoV/nQnvl2PFsG7
-182571HDc7FRZplzE4fhRKetS5WUuKax2FIqljQXS0CJZwV65boJwfJ2FosxdHj4
-eZK/wYHxi8R8LQB478bLqp3xZt28/EhsMjtLy/nO9SZfSy7Ajgq2mk2w4HZke23K
-qv6JY8/ofu5nBp0QSJIPQj35arkxXnEYjzgqJD1IIDNckt3jRSpeX3OMfmVWDXus
-a/wEwNaBACo5lgUYAwzXiPFyLEa6RkbD04z55GqsIjwZhIKrC1glyb0gmtxyY/N8
-QfPaSc4aXgUQK2mrgsR22eKf735MhM0pHOykErJzrIV92lRfSuQvfIoqTeFV0fWY
-Yxns7HEIBln7/9udgZpf+EWnzM3kpPjRX1iYNtAsMAKEMrK/lnt3jZTkKY2Drem5
-NGjtEWNmzKOLH/S0TLcpHldoDJGdno7CytNGasrkFTaDLEhF68QI85zbMmyotKiZ
-FKooG78oyxWCYqqPJ9vVBGwsMNfDMJP56T9UNhL72FwNqzSCaEcAUlDm2zCiQWKd
-NpOfYzRx8uLp7UyzXbl959GjHWfTA74Yidug13eSHRgKwLXLuro05awG8yNXeDeL
-wDswgDyKmlV7JDJjQw==
------END ENCRYPTED PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2.crt b/libs/ssl-config/src/test/resources/certs/cert2/cert2.crt
index 3b7ca01e48bae..6438d1e56e906 100644
--- a/libs/ssl-config/src/test/resources/certs/cert2/cert2.crt
+++ b/libs/ssl-config/src/test/resources/certs/cert2/cert2.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDGzCCAgOgAwIBAgIULGiQ5jnAntO91sS7Al5aUv8/jg8wDQYJKoZIhvcNAQEL
-BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTE5MDEwMzA3NDE1NVoXDTQ2MDUy
-MDA3NDE1NVowEDEOMAwGA1UEAxMFY2VydDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
-DwAwggEKAoIBAQDQbV6x3P9sstd5zKkjOylk+/X1j0vI6C93HwkF3d9NwhMoV1zq
-aSj2SmAQCz4mIjMlAFR9mm6F+3sb8xkMFJD2Mypc5dW6TS5krhbhJdMpoVbceZtS
-yuIsvQi1GT2Uwyu89doDiUNBIANqaexrK5x2S/Fy4L8dNl1x2k6PJi6zVpvbnNLV
-TSbuSMp3oY23PpX/m6wzJlCYicO8ucMhPwmC0OL9WJNKny4vuEPdiV6/LwCVS4Vr
-UpfNqgXLzRMJEbx7C2QEG7T6o2g2101oANBuPaDZcwIQ//EI3IkT10JcABIbwsdj
-/Oqj0cf7iEW1IfJWx+kRVT8NfEA5QjL1KQ4HAgMBAAGjaTBnMB0GA1UdDgQWBBS+
-/gUxdwfGB0XcPHsbM6Qw50S2OTAfBgNVHSMEGDAWgBSHd+NjwqkE6hVMEnltx6cT
-+D11lzAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCQYDVR0TBAIwADANBgkq
-hkiG9w0BAQsFAAOCAQEAiztFGa3uZVb6Fs8evN4CU+hPFYdhF57lEfT6Xa1OUD1B
-5e5rDOZfVloy4gzLdtNCS9lieTgB7Yc3wDUCm0cS48JCMxykSRTI6M0Fmofsgd5d
-OKR7CB+jR1Egj6nZren62XCgqjuJ+dbP4DinY6TifFzFX1vOD4RTb0mEn2WHL/JB
-DnDxOETmBtKFyueprMtXkTO23dXsYXQeo2Gyih+t5ksqMnxCW2GFkkOqrOUQY8CF
-6CVmmb9UCYk3f3Av9TedqJ8Cmoe+HSP0R2oxpnc7cd1v37QPxWgHETro9zS4FBrt
-6KgNTP99b+aLxeeuMKJuRVR+TCZPuyYbBzUfp2ZZOg==
+MIIDEDCCAfigAwIBAgIULU6478tMe6npOywF6dj4+azLeJIwDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTI0MDgyOTA5MzE0OFoXDTM0MDgy
+NzA5MzE0OFowEDEOMAwGA1UEAwwFY2VydDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCKWDmVjvSYQmq5bY2XX9HIJajm9ly5hm9iG+M8pxWLtzH4FNYX
+2VlwoP/aROMmbAPL4EH1jdKaD0hUKDRZOJAr33zm9qGsIB16dAk47HY7mR6OwObC
+VVhVMgVPBDLb8rgwKThlET+Hos3E6a3oUU1mVqur+EGu5wlXYyR+b9d0fl/oizV1
+uEtFLLvGVhBg5Md0vAjgE2JRidBzFRXUaAPSwmxZHFMwcZSTAd3Jfn8OE8TizkE6
+NVh9jrsQMTubp9eMbRaYZBzscKxGKU2/+IC99UENVJg09LGa4wg+96lpDx3bNQxN
+HbXBVcaNufjWNtofHZ8Yxzl9w+tooftvAvVdAgMBAAGjXjBcMBoGA1UdEQQTMBGC
+CWxvY2FsaG9zdIcEfwAAATAdBgNVHQ4EFgQUfw8Izdeensd4lhKbY8hzG655o3ow
+HwYDVR0jBBgwFoAUh3fjY8KpBOoVTBJ5bcenE/g9dZcwDQYJKoZIhvcNAQELBQAD
+ggEBAAC2tOJGQUCfMnRZA+sX4mX8F6oxpAwsBEgTN9dY6JqJkmx7rFpTXVi170Md
+VUascZdRXVlvBVfMt3rulDO1LWU7+LeWYLXp6EHhvGiPO8+3bwEwfGFpovLgvYmT
+kdCa9km83w7qreuQTayu9ZoU5UbLKTygdQCs3wwgq/td744/moLgbiUQJL3P5r8f
+RSPTID9XsdVo5qFSdFLXm8VaJExfcsvxZRL1KX+76WWNI77zo/uWnqnIvlFiLWSD
+UXUfX1ItcaeeNLA++gI+hC1Rfx/jeH77AcyEIuVIRIN89+9vxer9KBVhE3F7xQ8d
+iWSLz1sb6baSGdvkDhbzkuA8Y/I=
-----END CERTIFICATE-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2.key b/libs/ssl-config/src/test/resources/certs/cert2/cert2.key
index 1384b2daf309a..6d631e7ddffdd 100644
--- a/libs/ssl-config/src/test/resources/certs/cert2/cert2.key
+++ b/libs/ssl-config/src/test/resources/certs/cert2/cert2.key
@@ -1,30 +1,30 @@
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,68F4EFD94D4D9BDF
-
-TL01d1JqaN0P1sb8284jOGpLn42cubkLY7JPj+bmpL2PEH9cT2xo7MM5cwvNSbPX
-nuZ1CMFSFqAyxulh/rfZwU1BumKLiwM+ep0A/lWwKJEor+ancCBdkIHWfSg3Jc0i
-+nHhL3e7+W+XRfSlafQQkhFkeOXs0hSa4WYX6tymvMAf8OLAenKB/0MOvKjd6EOu
-ZIvnBxAjAaDoRr4X4izIVlNmsIbvYARW9WjjcK2FZhNn+WLLTkfwEkl0glRl440L
-ET9qAjoH7j5KL5yKw5h2HhALSLaXdiAfCGvhpU4K0Afpb225mvR/uL3HLpJEGKKb
-DuoK99zvjHqReq1YndIR688ioc0O4dUvujZKgn8OR2JvGJVSc+mgaIWadfs2aADz
-CJIlqnSJa1EW6qm6knLJwieEBoNHbeFszrCKrYdy7uicys9PR1XsoMrOly+HhVnR
-PChA3gV6AVIjyMAUkFLg4NAHjgDbb81lu8ENFmlJcjgVeXDMykrpBmhzmhSPtOEb
-6bdQCKuA7zXIpJCmP66ZSuNHxikrfqLJjXW3PojLuCx5nfO0akpxjSeyLHzv/YXV
-YxnpLJxMybG1KUHyDHRmDrd+UPzLnh52O/g9NoiAlluUcblH+BKer18dJdGSl95G
-P+Ted08S0yP2niNz6XHv5KbztzsP73n0w82akCQB8ZAsGJ0CNw7S7N6tWam/UkMN
-tvM9nFCjvwah1funu8nj9QyWrzac6ngPP0s8tcKG0ahLEJYn7Hx2Oqn7K39fbMkX
-UOJVNEBQP2Anf5dJMfYPEI0xihv3ec1RxpipOm9DKQ878jxnqxgZxa+Pab9j/JxQ
-j+BGaoOnYj2jHBnt4nCP75F0BEZaGxsZX2MjJySK+5jy2WW3JRC/E0qPkL6oBvT2
-3e37fep4XKSjqR9lSYjW+AlAVw2uPkwxDp5sD7XFGsH3SM1qj54NWwljpKXnOTbQ
-Xws18VEiWsQ3kD7ft11w8/67Bb27TsWEJRo1vCC4KsYBCyjEOrp13aJxpSiNI24W
-oSmrQTsCco1Yrxfs0noNu0FzfJHV6qmHR7ps0fj+AWJyquYbIEK1762+r2uutgSg
-ZVaPWLkm9uq5K5rNXsj3w1L1CK4YcDre0yt+Kg4Pt3OQR2lF8CpABguA3gR9kO2g
-9N8hAfiOq5MDliU+9r6Cr/dPkdzV0Eo971HdfaLD7S/pjSP37fcTcOpDhwNt3UcK
-amhR/Zm8Ll414zc/iNiVTcu6+chzSY9Yhwfa8A/XuIfoqMrTiaBMPlxe0tNKaKVs
-09d6U5JoTQJcnei/4ODkIIYOzsmMtHgKtmeg86AB8yeLNgqWCrJi+Fxnha+cJ9No
-+STMQP4vS8qgRe5XkRGaAZBHyPAwxOou1Iu167LjlFFl0YSYUZTChha5XBG2Uhm8
-FeIH1Ip+83fxMoyiYROOdeMuLXtQIndA3fmjduBEO0kPtAwQ2xfH4g59XnnSL97S
-9AslnPnUWzDR0zBr4GQBNAKLaMIFGzhDZEzaooYetoeDYSczil/Rf1D6wyM6Cgjq
-BK7c0kNum9uXaDbYCh6spzYua0j1noqsBTm9V25178lNbkQ6yAPdeYCxRmUXHtXk
------END RSA PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQmZ6ZHPPGAIJiIR8A
+rWSsNQICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEDnJhtyOur+FM/85
+ikBGVwMEggTQADlZDyF6ebcLYgXSJI2rCmtDoeHM8Fan9o8gu3zru3ISPtKTxijl
+l0pyj+CPR56kk4RAGQSUwyYt3itWFKmXcZuTQLIJOKaKYJsSgwoIq3rkU6hU1qYE
+TNTALBvfeokGrw9RT/ODfKUd8GmTWQqPEZbZGfj57uV029x4x8zf4CayDdS+7ABW
+d9ulWAcjauE/+n4xAlUoch/rcostqt0/ZVZnHSQ39DLtB9u5OCCO4Fv9x5VGnutL
+yAAWYxrhupwlHkY9gz7hgpKle0VIrfdZUaHQBz0he2w/t6Iv9Y69wTuimKOqtI35
+v68Xo3qwiIaklnf7GkqNoDZ3O4uvaMlapqQ9Pv0w8dFRcf3MfOkXZTut1qWuJBz/
+8WdbmCKp6jq8hjTXeX1xb5/9zFd0N7VtmEwwx+K5FwLHjSc0Xd5sgWe24wcB3Xkt
+fwCO+vLAZ0kaYeqj171BH+d4wyhaVH6YOviHI6vbs95Eb0jA8fjsf6PMZkL69dcC
+vWT3Tda9OOVfMhNRzhR8rAOPMOkAbFNYggxrPyaaEQrEs9wEFBLzHwub6n79n1qm
+u54BariExLxwBbr8GgLc6NlD8/a2ycwHKHO3qTLt+lX1RK8lFvoktdMbWUCZKVQz
+jt02eYfVadNzF2F0atFMnOHYsP6txSKbgF5pcK4FRrdkkEf8N5zR6YHGmlwjBMxi
+xdbCVU2AbsFpDhQ5rLJDQFwo9KfuefUTWBKLAboqtSzpwY/g3svD8mu0vcJWnSIy
+SrNJTgjxsWSOkVFKYmYLLYgnAD3zToeVVmnvfyaG6NjH7Zb+PFher8LwXW7CwFYt
+sNhBaGyAn2DXqD/gVvbr6V8zNYEYQ3wVdLyORYRbYV3ds02sYUpxperGqSIbxMUn
+Wm3Rw6GsYrqIQ7p5ZSQ0l54sNaTHAIUXlDa/R4uISpUu7td/SquUM4a9N1r5hDRw
+s/TK+eCBFQZweGrk+rsUpXxfJ+EYpUtUPkOH5d3QSpqqWdGxmwDBQlvMX5N6JKiu
+5bRhnH7ntoysdDqOoDmg8IZM7BCf9dFzie3wvieBB1plfZubz++Nyuzc1OA9k3r0
+68BYTYKrfrj46rQq1XoIusl36Xn1bIWK2peoIzazdZC7wB0ZeAd+8BvPp2FkBnrI
+YyJm4nuyw/TlI9wIkX9CkJI4keVRvQzRPFe6WtSpB80PKEzJ22Hq7CemRdHMxuBG
+KUkuyAACmJcJJ1UwOiPL9kGjVwgm0RRVwpZswvU8IFA2CfpiyhANOd4U3TtuMxz4
+SnRc86f21oL5dZ8HPg5rKSzOlEo8qzI4bvXyrNoyTSAuQcarveFpgURo+ocMkNlm
+p7DaVVfjjAbjEmmPl8eKy7ssLT1NO2FEwedbhDkcsvG3UIy5TvfJcifXwi8ovRiJ
++MAPJ47jv+y7D1MXPw+0uZRPgDG8czYaNKeEl4xLaJY0O7rLDYaQyqerTVg/vaqS
+IE+um0LE0Yg/pEFpniFI/HUv7TmPdpX1GnTj10+KOY6xwgyZQMmPxQ0FbI3cydAe
++MQtCzTQYVrKDOVOH3GE6OM0e7/xn9vkjrKFI8Yqe2ZFCR8mZ91Wj9O7Pyp9Vw+9
+N1FKCq3aqnS3UroPPWdz0hP2FsKwOf6Pxpj3j52QTnpx7gyLGoAqcaU=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2.p12 b/libs/ssl-config/src/test/resources/certs/cert2/cert2.p12
index 269e855f77098..5222f8cf3c691 100644
Binary files a/libs/ssl-config/src/test/resources/certs/cert2/cert2.p12 and b/libs/ssl-config/src/test/resources/certs/cert2/cert2.p12 differ
diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/README.md b/libs/ssl-config/src/test/resources/certs/pem-utils/README.md
index 28602ac097f78..f116410329c81 100644
--- a/libs/ssl-config/src/test/resources/certs/pem-utils/README.md
+++ b/libs/ssl-config/src/test/resources/certs/pem-utils/README.md
@@ -98,7 +98,7 @@ Create a `CA` keypair for testing
Generate Certificates signed with our CA for testing
- Â openssl req -new -newkey rsa:2048 -keyout n2.c2.key -reqexts SAN -extensions SAN \
+ openssl req -new -newkey rsa:2048 -keyout n2.c2.key -reqexts SAN -extensions SAN \
-config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node2.cluster2"))\
-out n2.c2.csr
@@ -123,3 +123,71 @@ and the respective certificates
openssl req -x509 -extensions v3_req -key private_secp256r1.pem -out certificate_secp256r1.pem -days 1460 -config openssl_config.cnf
openssl req -x509 -extensions v3_req -key private_secp384r1.pem -out certificate_secp384r1.pem -days 1460 -config openssl_config.cnf
openssl req -x509 -extensions v3_req -key private_secp521r1.pem -out certificate_secp521r1.pem -days 1460 -config openssl_config.cnf
+
+# Generate encrypted keys with PBKDF2 standard (OpenSSL v3.3.1)
+In approved-only mode BC-FIPS supports PBKDF2 standard only.
+PKCS#12 (requires PBE), JKS or JCEKS keystores are supported in general operation mode.
+
+## RSA PKCS#8
+openssl genrsa -out key-temp.pem 2048
+openssl pkcs8 -in key-temp.pem -topk8 -v2 aes-256-cbc -v2prf hmacWithSHA512 -out key_PKCS8_enc_pbkdf2.pem
+
+## DSA
+openssl genpkey -genparam -algorithm DSA -out param_temp.pem -pkeyopt pbits:2048 -pkeyopt qbits:224 -pkeyopt digest:SHA256 -pkeyopt gindex:1 -text
+openssl genpkey -paramfile param_temp.pem -out key_DSA_enc_pbkdf2.pem -aes256 -pass stdin
+
+## EC
+openssl genpkey -algorithm EC -out key_EC_enc_pbkdf2.pem -pkeyopt ec_paramgen_curve:secp384r1 -pkeyopt ec_param_enc:named_curve -pass stdin
+
+```bash
+export KEY_PW='6!6428DQXwPpi7@$ggeg/='
+export LIB_PATH="/path/to/lib/folder"
+
+for key_file in key*pbkdf2.pem; do
+ # generate self-signed certificate
+ openssl req -x509 -key "$key_file" -sha256 -days 3650 -subj "/CN=OpenSearch Test Node" -passin pass:"$KEY_PW" \
+ -addext "subjectAltName=DNS:localhost,DNS:localhost.localdomain,DNS:localhost4,DNS:localhost4.localdomain4,DNS:localhost6,DNS:localhost6.localdomain6,IP:127.0.0.1,IP:0:0:0:0:0:0:0:1" \
+ -out ca_temp.pem
+ if [ $? -ne 0 ]; then
+ echo "An error occurred while generating cert for $key_file"
+ exit 1
+ fi
+ # create a new P12 keystore with key + cert
+ algo=$(echo "$key_file" | sed -n 's/key_\(.*\)_enc_pbkdf2.pem/\1/p')
+ openssl pkcs12 -export -inkey "$key_file" -in ca_temp.pem -name "testnode_${algo}_pbkdf2" -out testnode.p12 \
+ -passin pass:"$KEY_PW" \
+ -passout pass:"$STORE_PW"
+ if [ $? -ne 0 ]; then
+ echo "An error occurred while adding key + cert to P12 keystore for $key_file"
+ exit 1
+ fi
+ # migrate from P12 to BCFKS keystore (keytool 21.0.2)
+ keytool -importkeystore -noprompt \
+ -srckeystore testnode.p12 \
+ -srcstoretype PKCS12 \
+ -srcstorepass "$STORE_PW" \
+ -destkeystore testnode.bcfks \
+ -deststoretype BCFKS \
+ -deststorepass "$STORE_PW" \
+ -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath $LIB_PATH/bc-fips-2.0.0.jar
+ if [ $? -ne 0 ]; then
+ echo "An error occurred while migrating to BCFKS for $key_file"
+ exit 1
+ fi
+ # import from P12 to JKS keystore (keytool 21.0.2)
+ keytool -importkeystore -noprompt \
+ -srckeystore testnode.p12 \
+ -srcstoretype PKCS12 \
+ -srcstorepass "$STORE_PW" \
+ -destkeystore testnode.jks \
+ -deststoretype JKS \
+ -deststorepass "$STORE_PW"
+ if [ $? -ne 0 ]; then
+ echo "An error occurred while migrating to JKS for $key_file"
+ exit 1
+ fi
+done
+rm ca_temp.pem testnode.p12
+```
diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/key_DSA_enc_pbkdf2.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/key_DSA_enc_pbkdf2.pem
new file mode 100644
index 0000000000000..bb1655d2e9548
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/pem-utils/key_DSA_enc_pbkdf2.pem
@@ -0,0 +1,18 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIC1TBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQ9WLcmXfK4mQgb8z0
+VEFgnAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEGUh9m77oFyis8j5
+VedmDqIEggJwymDZJmHaNgIiJAI/psd+hR4n03oMwUaV72DmQewEdMhI2sEy36WU
+Pup7X8VmRLb4tyiSiEUlh8FIX3cMpQ11e1j/lwW7wF+W3Qb6CHcMu8FCz3LN/CS4
+M+sQttfXiHh70qZvRx0SNaJo8A+e8HRGmYrbz6VqdlslSdB4fDT8Igls45rDZbch
+LJlHQfy9XQSgCFR6J+6/6Q8GyW07+WnkuYnbixN8ZdZ4jPE5mrZYMMQrQY0l4ThG
+vpb7U6VnWepDnXgeNWZTjHVLSAx3bbLUpbwotJnZISyTlRCxFSnunrRIkgaWPNMr
+qE78FfE8I8Y/3Ft3AURgM+o/AvgyNCNM9g6DCqjaYpuaK0aJpdvaez9BiiANosBq
+Powto+vuaDyYVIEhZ+GbokkvXx9muzvyA3KpqN1dg18au7Mqpkrenrw7Z5J8TnS2
+Pv686vSxCmisInC7c7uQYVxhze7fYMDUsyvWNPNUUrYnqrVtZtjD+VjkuZHJrBnL
+haz5xQ0cw7pPY9r8R1y5jxMCVKxMBvbOsQJ+MBqGXseYmeB8qBBMYVdC+bNdEzga
+rWD6FCX/k0PH2nP6KaU3qWLh3ueEtwTh0KO4yXgKyiLzF1KXoF93+4i9hX2w+t/W
+Y5jgNErriqrW5WOQFDrSlVmMx1dLNFzM1cB7TKygZrzytULAYAg/0el8Gjbw7nKP
+HInVUFKWhpNipEhDCGnGKoBvSz88AYAHS2I4fnFg3AfZCWEkkKJg++Y4Wip4+KTC
+XjECqMqv6hwNbvMf3JkmqTPZVh8MtLIAiR1rUIWdZMq18+4vnHtW0FXzLb2nYn3u
+ZrtXtOGxpBUY
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/key_EC_enc_pbkdf2.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/key_EC_enc_pbkdf2.pem
new file mode 100644
index 0000000000000..b851058d17217
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/pem-utils/key_EC_enc_pbkdf2.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDA0+sj4ekT4h5OgmLaj
+idCmLthqOUDdUNf67bBLjRSapUedsBIqSCx2u5E9ca2uGXKhZANiAAS6mhP+8zyk
+CYIaOgF35O1KeRxrPsvWfm8tb5+KjuepPI+WR33xiBQcnYfeNrYMgP000Ifk8gfS
+mv5aCHa5dBdgTzixsupMng0R8/jLPtS73Fzhi6G+KlRIe58c0xcVB5o=
+-----END PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/key_PKCS8_enc_pbkdf2.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/key_PKCS8_enc_pbkdf2.pem
new file mode 100644
index 0000000000000..445d50f1cafe2
--- /dev/null
+++ b/libs/ssl-config/src/test/resources/certs/pem-utils/key_PKCS8_enc_pbkdf2.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQ86A6gbRa4DZIX+cz
+TSf/DAICCAAwDAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEEABJ5byRdWBpd1Ho
+U/5ukYAEggTQoJkyyzwsns3QvYy4hIuwge7G867QPSCnHXhKInOYNDgbTnf36ia/
+eO5PELfEW0sW6ZZt/D9h28vssT0RI4PTyCQCv3DaVym6f9JbmnfvJePlaWkheieN
+j2Y1gth4fEFWKQK6Px3hkZCCjc1LGrSSKoqy3YhWlxbjrj0UfCpF60MY0TLcegZ1
+Zdl4HVjROcDpSBC/OyWb9LXtyUM5NJVEjHqr138iP/S/qtkn7kovJEVqUSIZd2T9
+BQwzCDzZD8Rl3W/ivZnCn/3lHkDl2JgQ9gVXrk1QhtKy0XF8z1lrKbYPkCL4nXR7
+2qOScFSvF/JjbmhxlnfjyrpCv4ckcvT/+KFvbNQP1p8/OFfIsapG6wTz2XGcwgA/
+c4uxrnB/110KO2m1zexsasxRTfvyHaTIPHl6NNh565cjieqdvp5KbzZBs9eJA19e
+NTeLVbXYZA5Ols0FF9cG5eeU7NPVFVMS7UILHnq9v+i1eKO1VPUWmCZhR8Sje0M2
+DpzSnQmrErVaH/lbZ9ZOklFhpL+UvW+g8IBSLLdCo+MlyOr/Ydr0HiADBb5zSiUo
+iWOrzgA9lLDG7VSHrpTU0I+PE+QctLVTPX2f+S+/pErnQ7Y+DE+OOsM37jGt8Zsi
+r+XcxxTZUmiakr6fUDEVG0NxbErTRgpHdSoT3RFgcs37MlrC88JbOs1cOiwma7/e
+56gqx/3uHJWyPKjVC/RUfIqsSpTx1EjqHeGYnJ9DTW+Yft+d7/HEZOr0Nl+3Qmoa
+b6Bxw+5c6Of7HYhEKoi37l7O1//bmrs0pURPWPmawPZtlfwd03ifFTZDOvn8cKEL
+TUFHBYd3V8kNmqRI/oUq28gk7uFd0Wby4epXcSVgSX2hAloSMYGfzcUU5u38v18J
+JxYgg3DyJAMH3V/GHV98XU0zscbaTKreKMUaXduDS3ktk9maq6Mne/fpI/ZZP7pr
+C7c1RJWKbSSdwAchQCMcIHUSZjA0iI7dIde9VP8e1DlErdWch3i7wdJQV4YqMM8v
+3sR3fV31vkZcSUDRCcBJPlNd/j6+AaIU0zVt3yWUUSCExSAOCybrlu0JPCSjjyOu
+Kkp0xEa6xt240QA+PyeUl7aov1wKZ1P95aek0y1AJy9SmcBUwBBVaeG+ETO/C5gv
+g6VqjG18BX6ulzJsOsLnQCxvbQajB/eF7dvex2OzU+jPUPuvZ1IRu4SHw88eyGz6
+r8RzQ1d7sCr+kV6pWXrEaNnwyFhOhwdNMxaYwSUItrfb3+4jPDoHa/di0sJ4Dkr/
+UVuqnc7TAdW9x+PTtUWMQfaX7S8o6XDNXkhcWznhNP7OmkQpT2K5kkaGfLeHKRbz
+7NHCwRXEm49ZPfDCnI9kddnejU60vDHW1uBGH2S5kn71noAe7R07s9qeKW50eLOf
+Pe9BlOPb205gnibRYjjj0pUZ1YJwD4rkiXaX/fXHkPpgpyUEbw3tAZW+FqXUZSaW
+TwAj41oXms0VoaUi/TcvsIDjnldVvZ0MkHUwMtfOvHb/lbrafHKoTHIuBbRAHSNf
+uQXvBDwiq2uv3v0EZdz4mouqcp8aNZmunVHu7c22HCaf4s608BIq4FBqrq6XRdqo
+cAOcq+WGk+F/helMKaRWo737062tq3dlhtRpGLXbZUcYThUNY4SjR6Q=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.bcfks b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.bcfks
new file mode 100644
index 0000000000000..8d1a016d790b1
Binary files /dev/null and b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.bcfks differ
diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.jks b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.jks
index ebe6146124e8f..25363b6d8a5a4 100644
Binary files a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.jks and b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.jks differ
diff --git a/modules/ingest-common/src/test/java/org/opensearch/ingest/common/DateProcessorTests.java b/modules/ingest-common/src/test/java/org/opensearch/ingest/common/DateProcessorTests.java
index 8a4f3b4a898b4..eeb942166eeec 100644
--- a/modules/ingest-common/src/test/java/org/opensearch/ingest/common/DateProcessorTests.java
+++ b/modules/ingest-common/src/test/java/org/opensearch/ingest/common/DateProcessorTests.java
@@ -164,7 +164,6 @@ public void testInvalidJavaPattern() {
}
public void testJavaPatternLocale() {
- assumeFalse("Can't run in a FIPS JVM, Joda parse date error", inFipsJvm());
DateProcessor dateProcessor = new DateProcessor(
randomAlphaOfLength(10),
null,
diff --git a/modules/reindex/build.gradle b/modules/reindex/build.gradle
index cad7d67f3ef84..4d2ff68d16460 100644
--- a/modules/reindex/build.gradle
+++ b/modules/reindex/build.gradle
@@ -87,11 +87,6 @@ thirdPartyAudit.ignoreMissingClasses(
'org.apache.log.Logger',
)
-forbiddenPatterns {
- // PKCS#12 file are not UTF-8
- exclude '**/*.p12'
-}
-
tasks.named("bundlePlugin").configure {
dependsOn("copyParentJoinMetadata")
dependsOn("copyTransportNetty4Metadata")
diff --git a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexRestClientSslTests.java b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexRestClientSslTests.java
index 1123ae4623300..35fdcd07626d1 100644
--- a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexRestClientSslTests.java
+++ b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexRestClientSslTests.java
@@ -56,7 +56,6 @@
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedKeyManager;
@@ -65,11 +64,15 @@
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
+import java.security.cert.CertPathBuilderException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
@@ -84,6 +87,7 @@
@SuppressForbidden(reason = "use http server")
public class ReindexRestClientSslTests extends OpenSearchTestCase {
+ private static final String STRONG_PRIVATE_SECRET = "6!6428DQXwPpi7@$ggeg/="; // has to be at least 112 bit long.
private static HttpsServer server;
private static Consumer handler = ignore -> {};
@@ -108,18 +112,31 @@ public static void setupHttpServer() throws Exception {
@AfterClass
public static void shutdownHttpServer() {
- server.stop(0);
- server = null;
- handler = null;
+ if (server != null) {
+ server.stop(0); // Stop the server
+ Executor executor = server.getExecutor();
+ if (executor instanceof ExecutorService) {
+ ((ExecutorService) executor).shutdown(); // Shutdown the executor
+ try {
+ if (!((ExecutorService) executor).awaitTermination(15, TimeUnit.SECONDS)) {
+ ((ExecutorService) executor).shutdownNow(); // Force shutdown if not terminated
+ }
+ } catch (InterruptedException ex) {
+ ((ExecutorService) executor).shutdownNow(); // Force shutdown on interruption
+ Thread.currentThread().interrupt();
+ }
+ }
+ server = null;
+ handler = null;
+ }
}
private static SSLContext buildServerSslContext() throws Exception {
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
- final char[] password = "http-password".toCharArray();
final Path cert = PathUtils.get(ReindexRestClientSslTests.class.getResource("http/http.crt").toURI());
final Path key = PathUtils.get(ReindexRestClientSslTests.class.getResource("http/http.key").toURI());
- final X509ExtendedKeyManager keyManager = new PemKeyConfig(cert, key, password).createKeyManager();
+ final X509ExtendedKeyManager keyManager = new PemKeyConfig(cert, key, STRONG_PRIVATE_SECRET.toCharArray()).createKeyManager();
final Path ca = PathUtils.get(ReindexRestClientSslTests.class.getResource("ca.pem").toURI());
final X509ExtendedTrustManager trustManager = new PemTrustConfig(Collections.singletonList(ca)).createTrustManager();
@@ -129,7 +146,6 @@ private static SSLContext buildServerSslContext() throws Exception {
}
public void testClientFailsWithUntrustedCertificate() throws IOException {
- assumeFalse("https://github.com/elastic/elasticsearch/issues/49094", inFipsJvm());
final List threads = new ArrayList<>();
final Settings settings = Settings.builder()
.put("path.home", createTempDir())
@@ -138,7 +154,13 @@ public void testClientFailsWithUntrustedCertificate() throws IOException {
final Environment environment = TestEnvironment.newEnvironment(settings);
final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
try (RestClient client = Reindexer.buildRestClient(getRemoteInfo(), ssl, 1L, threads)) {
- expectThrows(SSLHandshakeException.class, () -> client.performRequest(new Request("GET", "/")));
+ var exception = expectThrows(Exception.class, () -> client.performRequest(new Request("GET", "/")));
+ var rootCause = exception.getCause().getCause().getCause().getCause();
+ assertThat(rootCause, Matchers.instanceOf(CertPathBuilderException.class));
+ assertThat(
+ rootCause.getMessage(),
+ Matchers.containsString("No issuer certificate for certificate in certification path found")
+ );
}
}
@@ -159,7 +181,6 @@ public void testClientSucceedsWithCertificateAuthorities() throws IOException {
}
public void testClientSucceedsWithVerificationDisabled() throws IOException {
- assumeFalse("Cannot disable verification in FIPS JVM", inFipsJvm());
final List threads = new ArrayList<>();
final Settings settings = Settings.builder()
.put("path.home", createTempDir())
@@ -167,10 +188,21 @@ public void testClientSucceedsWithVerificationDisabled() throws IOException {
.put("reindex.ssl.supported_protocols", "TLSv1.2")
.build();
final Environment environment = TestEnvironment.newEnvironment(settings);
- final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
- try (RestClient client = Reindexer.buildRestClient(getRemoteInfo(), ssl, 1L, threads)) {
- final Response response = client.performRequest(new Request("GET", "/"));
- assertThat(response.getStatusLine().getStatusCode(), Matchers.is(200));
+
+ if (inFipsJvm()) {
+ try {
+ new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
+ fail("expected IllegalStateException");
+ } catch (Exception e) {
+ assertThat(e, Matchers.instanceOf(IllegalStateException.class));
+ assertThat(e.getMessage(), Matchers.containsString("The use of TrustEverythingConfig is not permitted in FIPS mode"));
+ }
+ } else {
+ final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
+ try (RestClient client = Reindexer.buildRestClient(getRemoteInfo(), ssl, 1L, threads)) {
+ final Response response = client.performRequest(new Request("GET", "/"));
+ assertThat(response.getStatusLine().getStatusCode(), Matchers.is(200));
+ }
}
}
@@ -184,7 +216,7 @@ public void testClientPassesClientCertificate() throws IOException {
.putList("reindex.ssl.certificate_authorities", ca.toString())
.put("reindex.ssl.certificate", cert)
.put("reindex.ssl.key", key)
- .put("reindex.ssl.key_passphrase", "client-password")
+ .put("reindex.ssl.key_passphrase", STRONG_PRIVATE_SECRET)
.put("reindex.ssl.supported_protocols", "TLSv1.2")
.build();
AtomicReference clientCertificates = new AtomicReference<>();
@@ -206,8 +238,8 @@ public void testClientPassesClientCertificate() throws IOException {
assertThat(certs, Matchers.arrayWithSize(1));
assertThat(certs[0], Matchers.instanceOf(X509Certificate.class));
final X509Certificate clientCert = (X509Certificate) certs[0];
- assertThat(clientCert.getSubjectDN().getName(), Matchers.is("CN=client"));
- assertThat(clientCert.getIssuerDN().getName(), Matchers.is("CN=Elastic Certificate Tool Autogenerated CA"));
+ assertThat(clientCert.getSubjectDN().getName(), Matchers.is("CN=localhost,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA"));
+ assertThat(clientCert.getIssuerDN().getName(), Matchers.is("CN=OpenSearch Test Node"));
}
}
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/README.md b/modules/reindex/src/test/resources/org/opensearch/index/reindex/README.md
new file mode 100644
index 0000000000000..f2ff25d41a890
--- /dev/null
+++ b/modules/reindex/src/test/resources/org/opensearch/index/reindex/README.md
@@ -0,0 +1,48 @@
+# generate self-signed CA key + cert
+```bash
+export KEY_PW='6!6428DQXwPpi7@$ggeg/='
+openssl genpkey -algorithm RSA -out ca.key -aes256 -pass pass:"$KEY_PW"
+openssl req -x509 -key ca.key -sha256 -days 3650 -subj "/CN=OpenSearch Test Node" -passin pass:"$KEY_PW" \
+ -addext "subjectAltName=DNS:localhost,DNS:localhost.localdomain,DNS:localhost4,DNS:localhost4.localdomain4,DNS:localhost6,DNS:localhost6.localdomain6,IP:127.0.0.1,IP:0:0:0:0:0:0:0:1" \
+ -out ca.pem
+```
+# generate client key + cert
+```bash
+export NAME='client'
+openssl genpkey -algorithm RSA -out "$NAME".key -aes256 -pass pass:"$KEY_PW"
+openssl req -new \
+ -key "$NAME".key \
+ -subj "/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=localhost" \
+ -out "$NAME".csr \
+ -passin pass:"$KEY_PW"
+openssl x509 -req \
+ -in "$NAME".csr \
+ -CA ../ca.pem \
+ -CAkey ../ca.key \
+ -CAcreateserial \
+ -out "$NAME".crt \
+ -days 3650 \
+ -sha256 \
+ -passin pass:"$KEY_PW"
+rm "$NAME".csr
+```
+# repeat the same for server key + cert
+```bash
+export NAME='http'
+openssl genpkey -algorithm RSA -out "$NAME".key -aes256 -pass pass:"$KEY_PW"
+openssl req -new \
+ -key "$NAME".key \
+ -subj "/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=localhost" \
+ -out "$NAME".csr \
+ -passin pass:"$KEY_PW"
+openssl x509 -req \
+ -in "$NAME".csr \
+ -CA ../ca.pem \
+ -CAkey ../ca.key \
+ -CAcreateserial \
+ -out "$NAME".crt \
+ -days 3650 \
+ -sha256 \
+ -passin pass:"$KEY_PW"
+rm "$NAME".csr
+```
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/README.txt b/modules/reindex/src/test/resources/org/opensearch/index/reindex/README.txt
deleted file mode 100644
index efd5e4c20ffd3..0000000000000
--- a/modules/reindex/src/test/resources/org/opensearch/index/reindex/README.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-# ca.p12
-
-
-# ca.pem
-
-openssl pkcs12 -info -in ./ca.p12 -nokeys -out ca.pem -passin "pass:ca-password"
-
-# http.p12
-
-unzip http.zip
-rm http.zip
-
-# client.p12
-
-unzip client.zip
-rm client.zip
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/ca.key b/modules/reindex/src/test/resources/org/opensearch/index/reindex/ca.key
new file mode 100644
index 0000000000000..a04c18c994359
--- /dev/null
+++ b/modules/reindex/src/test/resources/org/opensearch/index/reindex/ca.key
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQ8TSOq343U8BV3rEt
+vOpSPQICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEFXKi3C3VJzsGiCw
+Lh2zY40EggTQwtBoa+e+J/UAA/mVv50rVH7oqvs5t9wRfznrldPtUgTR7r06TxNB
+DXN1spBSmJjrohC3RbEO4169YqCwAk2HsptENM3MV5A9EwTuXPVBW/ic2SDOwmiP
+wvRRKUujjaYZTfVeVJi0LqnCtyv7/hc33MJ3IMeNefEwmYRH3u/ktp+NBXZPEp1G
+sdbPLpCxUqtq8zE84ev+RyURbErWVvjI8ma20Hn2gACkQazYTSVMVMxvj4+m0oBd
+hzQ54GjRypm6Tc+CkJXGbCp+3sCONUqKARZYo+oiL5wEdGTLOcCwaCZxVkftDZ4V
+oGrHVlgFrYgADaOuokjMf178ymMJX1+kTYze/k/ajXHd8qBKRD1X49dDhrHjnlhV
+2sGOTKk16fBXSoM/q4vfmBKkd+BxDcdbsDkLDdT266XBy9hdRnL6e3Qk6ag6i0dB
+faJwyXHIhiS87nFLpYeXY47DABBvmKVqafdHJDab7GYmLb+2J33EbmQX+tMgKrI+
+l5FjPX0Lz6/c74M6jYGHhbii3fZKGzb9BwWCEG7eIMONfv7IoaP2HI/P5G1WheQ+
+Ocd4lsb+pCmy+tzQcB7+GtWX0sG4ugCTsKIofN9ZmkvdQsvQvjT/oubDtBXUMgIL
+/6GpYr7f535wD8jp4qHjSNyiNf93XiepxUsKBh0xvcGRRfhEjrZhnDm8DYP014bL
+HhWzPVUgQwDJMa92wzsqFpXCujhLDb3BzLZLCGWDUkDsPjX2hUzNRWw+nN0FEwkD
+ezxZOpK7m/ZfZi0rI94oYpmanwLNH5tvwr7pKLJ2SAP2WTNYRtff7vgeKOmgDG97
+pSm49phrSdM/VbwWgoPHpGxn6De5mfp+52dz5sCZMP0tsYMa947z2VDAU9f7+AQL
+V73HGQKu8eny2ofOvQiKMK7sVo9dDvf6O4fGUCZh55YmQYzNq1cYh5lgQgPJ/CDb
+c2mUVhwPfd4gvmKzBQ+nxjo5Jbh0vJwqOxk0SMCwWqQW5+Y9mdcDseyJwL7iyiTd
+xyN9rUdro86foF85Xja+MZ0hVW/q1xwrZSiunWuvg0uaGMdSuknn7skLnKrdbfIU
+RocweZPetFxzCm7XeikCaKucoNLNSPjAKW13doZSOc4OxS4hXep211dGVvK43XwX
+B6xp8WtquZaGk01J789H1XU/sz6AssuCrMvql0Gd/GeFz+Ql9dMd4bH2ZzjpRcWL
+FMZvsxXzqp5zodsn/j26h+WKZYmLSnxvE+WjQHyECt1JgSyYD2I84CxKj9I5ezX7
+1PIc3/OPl14p+ni/lfx6UM5WmbrHcuLM5a2ml/9e+HQci2xDNflkCiRQ1jcXYSB4
+p5mAaxSPbC33mi7jvBtUF1Yk9CiIRW941pKhn5YSj4bEMs6h8tB4M9wfXn9HPe/X
+0KdYFMzf5sc9nmDZt2A1EoZexYwMk56wVQ7gnekw9ECCs6OLUmXkAmKojvbNXG0C
++t0W3LSoFsMM6vnINVooK+dQgRLqXFe57HY8j7zTmFh69Kh3/Cv24gQ21xwPYB6y
+A9AVrrxRUV4Nlqkw5A4kVKXRry9/xj5DGgZ4SI2rJZ3vhfD2jiLFnl+JBT/Cw2xL
+NL32subXNGqY4ymnq1HSG3SO/Jgh21XZL8rl2kZ+QiT7QvRVFWefRdA=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/ca.pem b/modules/reindex/src/test/resources/org/opensearch/index/reindex/ca.pem
index ee758ca3e6370..615f00e468ae6 100644
--- a/modules/reindex/src/test/resources/org/opensearch/index/reindex/ca.pem
+++ b/modules/reindex/src/test/resources/org/opensearch/index/reindex/ca.pem
@@ -1,25 +1,22 @@
-Bag Attributes
- friendlyName: ca
- localKeyID: 54 69 6D 65 20 31 35 34 37 30 38 36 32 32 39 31 30 37
-subject=/CN=Elastic Certificate Tool Autogenerated CA
-issuer=/CN=Elastic Certificate Tool Autogenerated CA
-----BEGIN CERTIFICATE-----
-MIIDSTCCAjGgAwIBAgIUacmv5ElKJ1cs9n61tEpy5KM3Dv0wDQYJKoZIhvcNAQEL
-BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
-cmF0ZWQgQ0EwHhcNMTkwMTEwMDIxMDI5WhcNNDYwNTI3MDIxMDI5WjA0MTIwMAYD
-VQQDEylFbGFzdGljIENlcnRpZmljYXRlIFRvb2wgQXV0b2dlbmVyYXRlZCBDQTCC
-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0rA35tPl0FN+BPk2YfmET9
-MvDWFLvfL2Z1aw1q1vnd12K9zumjN6veilHA2Iw/P4LG/mkQZvY4bDPgibRD7hbE
-vwPoju4vr614tw60+FlkpO6HezYo2I3cni1//Gehhs5EW2P3g7Lw7UNCOAfcR2QQ
-p/dtwXYWzXHY9jTevQSv2q/x5jWKZT4ltaQExzvXAcxRGqyWV6d5vol3KH/GpCSI
-SQvRmRVNQGXhxi66MjCglGAM2oicd1qCUDCrljdFD/RQ1UzqIJRTXZQKOno1/Em9
-xR0Cd5KQapqttPusAO6uZblMO2Ru+XjCD6Y0o41eCDbkd0xA3/wgP3MD5n41yncC
-AwEAAaNTMFEwHQYDVR0OBBYEFJTry9da5RZbbELYCaWVVFllSm8DMB8GA1UdIwQY
-MBaAFJTry9da5RZbbELYCaWVVFllSm8DMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBADA6qhC35PwuL7LRddbhjjW8U/cCmG9m7AIvH6N+Mw/k76gt
-tJkEDxztMHUG+A2IPyEcYm7MLr1D8xEQYsq0x4pzFcQnMSQDv4WTK35vRxMtaqwA
-WZTyA+DibBknbaP1z3gNhR9A0TKx4cPagN3OYFvAi/24abf8qS6D/bcOiPDQ4oPb
-DVhmhqt5zduDM+Xsf6d4nsA6sf9+4AzneaZKGAMgCXgo4mYeP7M4nMQk0L3ao9Ts
-+Usr8WRxc4xHGyb09fsXWSz7ZmiJ6iXK2NvRUq46WCINLONLzNkx29WEKQpI3wh4
-kyx6wF9lwBF06P1raFIBMeMOCkqDc+nj7A91PEA=
+MIIDszCCApugAwIBAgIUOpUOL6Dz5+T+y+SIDknp8nOB2x4wDQYJKoZIhvcNAQEL
+BQAwHzEdMBsGA1UEAwwUT3BlblNlYXJjaCBUZXN0IE5vZGUwHhcNMjQwODI3MTgy
+MDE2WhcNMzQwODI1MTgyMDE2WjAfMR0wGwYDVQQDDBRPcGVuU2VhcmNoIFRlc3Qg
+Tm9kZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2bmzHyMB705hS2
+Vu02WaTz7iWU11aVlNwAEVWIpjarDsk1IeICYe2vtv7e9qAp5IAMC6y9Db4XAx6A
+PKJHZ5XcrWKpJqanMUwMi7dJ7wLWauMlx4WdyWSdJ3KRVO0Xzdr6My6dV+LCiiYX
+cQCFYzEQYX02kU8M8NZ3J9t5OK3MF8/f0gta5vMs/1akPJzTMYyLva+hcNyGC9pW
+Ly0w2kWxqze00KjT8wnmUz3h6gxxRwwdocsyZ1AE635anRu2MuAo94sA8kwQdl6z
+cKtTzlzbLmrBQzusnuQtJCKGzvH+uBGodFpQhi5JpYVbuSvqI1Lumg7RA524cb0t
+OKnijBECAwEAAaOB5jCB4zAdBgNVHQ4EFgQU41fNVZMW0Kc5nmv53kKTINZT0CMw
+HwYDVR0jBBgwFoAU41fNVZMW0Kc5nmv53kKTINZT0CMwDwYDVR0TAQH/BAUwAwEB
+/zCBjwYDVR0RBIGHMIGEgglsb2NhbGhvc3SCFWxvY2FsaG9zdC5sb2NhbGRvbWFp
+boIKbG9jYWxob3N0NIIXbG9jYWxob3N0NC5sb2NhbGRvbWFpbjSCCmxvY2FsaG9z
+dDaCF2xvY2FsaG9zdDYubG9jYWxkb21haW42hwR/AAABhxAAAAAAAAAAAAAAAAAA
+AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBObbHtMsaa0XTJAlJk4DE9kHgZoxF8ImFI
+c1huhnCr2X+XkKxYDF/QUA1XRDWI9S4/6xBDKZdD+RhZ6ds3CbG4JVtoJa1Vvjla
+dk11uirkKCqbYrdyc/+KeLS4ruYhG/JoqycTp/G5aCrThZgIgf0jm4peJwd9nqaz
++yjP4L4sDR4rfdLIsk96hPKDImD+5uuJ9KqMj8DO589uqJwhTehfPcNfL4hVdQ66
+IEKK6HM5DMXYzRFr7yAseKZbXngn5QJ+ZBldikP0hgGFYbT1kbNtFOqwpYNvgGvr
+ptei46poM3WCB04puszm62E4Jora6rxaLwWGp+6TWELLwUUs9so7
-----END CERTIFICATE-----
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.crt b/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.crt
index 337d24e2493ac..9111fb215a448 100644
--- a/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.crt
+++ b/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.crt
@@ -1,19 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDIDCCAgigAwIBAgIUNOREYZadZ2EVkJ1m8Y9jnVmWmtAwDQYJKoZIhvcNAQEL
-BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
-cmF0ZWQgQ0EwHhcNMTkwMTEwMDIxMDMyWhcNNDYwNTI3MDIxMDMyWjARMQ8wDQYD
-VQQDEwZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCCP2LE
-nws2+ZIwSQ3IvIhVfrueUmNt7Y5TdhhwO32p2wC4ZA62J9L8klAzt7R+izcL/qbF
-65inbXM0A7ge/2wZ09kbqBk5uS8jDetJS8lQmWVZDHfVi8g/yDMWklz2mQYleYmU
-HPyIplai3P3KBoT8HurzHw2C953EZ2HiANFnGoEPZZ5ytcT2WenxuU5kSXSxuDyn
-8/dCVHEQL1Yipr2LQKYQAHotjo56OhyL9KS5YPjzSFREeyRfQinssTmpGFsua/PK
-Vqj+hRdkaqRfiqPq3wxn8oOSpZLQe58O1e7OlqgjkPuZdjZ0pQ7KJj7N3fUQNSeg
-2VC2tk8zv/C/Qr2bAgMBAAGjTTBLMB0GA1UdDgQWBBQziDNuD83ZLwEt1e1txYJu
-oSseEDAfBgNVHSMEGDAWgBSU68vXWuUWW2xC2AmllVRZZUpvAzAJBgNVHRMEAjAA
-MA0GCSqGSIb3DQEBCwUAA4IBAQAPpyWyR4w6GvfvPmA1nk1qd7fsQ1AucrYweIJx
-dTeXg3Ps1bcgNq9Us9xtsKmsoKD8UhtPN6e8W8MkMmri+MSzlEemE+pJZrjHEudi
-Sj0AFVOK6jaE0lerbCnTQZvYH+J9Eb1i9RP7XHRShkR4MWgy2BzlENk9/LRbr84W
-Yf5TuM9+ApiiiOoX9UfSGBzNnqwhJNpG9yJ+HnQSqTnJJc/wL0211zLme9I/nhf0
-kQx6mPedJ3gGoJ8gqz38djIrhJDxq+0Bd9SsdlR6yT+1+bY7hinYx2eLV91AybZ4
-x07Kyl174DD41PYaE1AtoLlrMrQ5BG7Md50Am+XXOR1X1dkZ
+MIIDUTCCAjmgAwIBAgIURxNp9ImDloxqOPNAP0ySBZN/BDQwDQYJKoZIhvcNAQEL
+BQAwHzEdMBsGA1UEAwwUT3BlblNlYXJjaCBUZXN0IE5vZGUwHhcNMjQwODI4MTA0
+MzUwWhcNMzQwODI2MTA0MzUwWjBiMQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT05U
+QVJJTzEQMA4GA1UEBwwHVE9ST05UTzEMMAoGA1UECgwDT1JHMQ0wCwYDVQQLDARV
+TklUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCp7qyGufu1cQYWJJGZ04XulVdwsKytMeLNSDHT90ratfsAy5WP3CRy
+fug0E6nB7eykSHnE8aYomrghJIL0oP3v7b7vV/iasZ17Q2uiY67fQb4s6Rvrcov5
+R7ak5/B22uslDrDY0BaSWKCxHREb55rMhVWlVTXpm91kdGvo4Q61Gcxe45mweKR8
+UMbUlNuXrW/xwTwYI4pdDxha2ZXgTBrBJXppEh/KQp0rdy4Be3KG5IbqrH/Bh6cG
+4CZ/di0i6xWxAhQOlOKlcTHpMAtXx0eBjha/Y9+p3/7z9fmE/JsYozw56r75CPDG
+VpNiSDoPMPed4uhpbXQVYeCTUe3Hh8WRAgMBAAGjQjBAMB0GA1UdDgQWBBTm5Cel
+/aWnBGFDUnZKNYs+BVFHFzAfBgNVHSMEGDAWgBTjV81VkxbQpzmea/neQpMg1lPQ
+IzANBgkqhkiG9w0BAQsFAAOCAQEAjaXJN+NyS74cDTAtjVqo4e+h2K/LfYyIpdYp
+mTDi+wRBlprJUDl18TK26c0hV6T4MN8QxqoqCXoEVJZWDjBYOUsl3OfSgPpT0aww
+3Z/mIPOLb9mR1zOO9tXZhgNdFCLRRepiLyPRsRVQ3K3klle42DHaEIOUlwtqAArF
+d9MKg9PShrRjqJwlm8vL3E8KjNeC8gAvebF3e7ADIatXjRK5Rc/LQhgPCaCZKSDF
+w36AhGBnXsCgi3IR00E9CWOsC2UVeAhgHHaN1oJjuLfFupG/2Vx6Ii+PAgueE7ec
+VWQeasxHihc0VjEYtSiNlYO6A8rcH7lg+0OCzGr97DC+zfFZwQ==
-----END CERTIFICATE-----
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.key b/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.key
index 95e11f79cea24..ca0c6ba868047 100644
--- a/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.key
+++ b/modules/reindex/src/test/resources/org/opensearch/index/reindex/client/client.key
@@ -1,30 +1,30 @@
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,81AB10154C04B38F
-
-0L6Buvpeg6QHh/mbYp/3bXDCsu0k0j5xPdIGWd6NCOdb24OQFsOjeA2WuPqs0WWF
-gzVrjh984biS3IqeglEr6X6PfVJ0QOgBkq0XgSBXhuoRJL/302N9oPGsf8T8oW9t
-pqR/JIB2L7lMbJlJYSjMl0YQT3hWpo2BlrtSIc/GWOKfjDNWc9BL+oHvKJwql1lb
-n4yMvYFYJDqgzgxa3r4IIQNsCn3SP+gqbTx9vF6StOIroV51BdSL4IGWRvqnMJrh
-ybk1EHSLR1oGcONLU4Ksi33UxdImG70SsnoH/NnInDvV2bxmxmgf5SfYKtxFhoxz
-0hISKTMTerPGtRQ5p8wtEi/ULKyInK+qF3tLgZa+S5VbByjDnUo2dCcbDDSkH5pO
-uczJ2bs1kJegpCrUueJdbi9OX2upmF+tJb9+5hzFTvey8dUWTEpdiN0xbp4BLfNd
-Yp4sMHZovsDJKIjDb0NbXRgLeFh1ijlLPhKwIXWTF3BaCKcSw34Qv22YPwn3qNuw
-0KuUPAo0B65R/hoJguvtks8QAXe0S1jZS/fAlQCoIB0TIduy1qkyje+AnSW+1RL0
-ysBxLqbvRUqWlgnu7/28V4FD8JNu3O+UGBEelXlfokLgCBZ6lSys2d3Zy/XVBnG0
-cPl59if+fxKaMWlhFvMLFBup1Y4a/1zA7Sx6kkhvawekHr40NcG4kLHJ+O6UoM4d
-/ibnbfIksLNkuo/nwoEcKp7W6SxafV0hROdxClkGKild66rnHtk4IGATjaBqt9nr
-FuO3vRtLuUMS+/4kpvhMwl0RhX2/i6xgV+klWNYNu1JTGDFvdG3qfiY2w88EIbGe
-rn8JEvRtaH/XNeGdhBwbuObvTifiHyYzA1i5Zh8zvE2+Dthlk19jbBoOUx//LOi2
-JrNkAsqQCF4HXh7n9HWA/ZrKTP7Xvkig6Vf7M2Y/tO361LSJfzKcRFLpl0P2ntEv
-XwFOqTvOURERTVr4sBLOVPRAhIs3yvkI5xfurXzbRWtSeLgrMoDgJlXIQbuXd8sq
-zIBLqvYf2bcroB66XJqX1IFWEstym/NHGcbrwjR5Fn2p3YAtXnIbw8VhHwV+LIOl
-ky/wH9vbnML/DE81qFqRe8vNZw2sGn9skOyU/QvKeV1NRHYZSV3hMx82bPnjgFeB
-ilzkb8FEPOAOJ0m44Q3C9eUoazJT8aCuRIAgSL43se1E2pFlIXQTfYRARaWEkSf9
-0hXqQJc17b+Hj0ire3PUqbG3+/l1qMhhIHwq7Kuyy2neTuW/DXbXp2AMv/bLcnHH
-apVeRZaYXVSnGXJNk2CeRnCs8OGir8g5zkH+fmVb9knt6TL2oFIsQqULyrLolhfe
-6Q8mLzq/sd+w+VuN1n/5+RQqOJZWEkLFzQPx8wTqeTB19OE0gjncrqzCHq7INqRe
-tGClWOj/yL0Sciu3ctVGz1VAbgeBKnLdKm2TX4oFB4OG4E7GMXIL7hGxjtjLAVMW
-XNc3ZYNQra+iPqJtFxnmbrF2Sn0Wr0hcAT1V0A0TRKe/n0lpUrfhTy/q4DUlOVKG
-qdCsTGoYXObpUWU5G9GyCVWWRJyrTxJcBZ9KWJu9Y/aMFzoa2n0HQw==
------END RSA PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQO04hOVF1REJsgAkP
+xkFZ/gICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEENoXPnjByIDKjwqz
+3+WRgNsEggTQuv3EOfjFwF8f0fac2GjJJxN3L2b88CeKxbjTL/6kQ1bvWSI1+L45
+0zP6CQ+5lI3N9/0YFoCWX5y57e+OXafAWivkUp/LiGkYWcRnqGVhZgSQTFQP9rly
++3PUDLlM5FuGylKvoqYmTIBud1puBiChYj0FKImOyHgPH3/GEGbTSrtvCSZkCw72
+XkkF32/OtSbqTuGlGgl+pGLTtnS2+RhgiCzXMCtvHJqjhAh22J7uoYYqk02QKEme
+GMWM4anxmLPBr/Rw04NrlEfgRl8mTIhgrgwKV/mwfK++kqboWpzfXPs/S4KHJxmv
+WvVcxHovoyovBA87C8cY4Qz/PZzm9vZr/+hQCF0OJgvZejWiUiuRJ9HgeteKTEMo
+CrOlyZXcaMHPCa8CK6U+lUBwTZbAAzMYSazfaf8524yDGksOA4J/KGC3uvviYW09
+hTaqhq0yGqBUe5mrgEEhSV2vIpjK6MKxMtvjKvc1fjfrYIL9BGiiHOCGaljQTQAA
+yLZqQwlj//v4om3onR6HOfZeYsQxzH5zNFSIJa96/kBBWG9Q0ZMmqEqB52rNUT28
+ZapjaqqRkos/rBdvzDQzlyx+NjZnOsueEkC+cX/1psIoE+6vLbonMrlzl+SSqtxB
+EuSD7dekZ7o3eQLzRI13ohRtzMv4ojWMpr769WsQ4KKflK7pLVdIYFZbL0Q44s/w
+Bc9ByiwSGymhEO6uqqfBT1baj19yTrc3FU/jaJyIsRNs/EAc7c6nPejiiwxtE7Ex
+oVSwbKoD2CXB/DYlenenBGvuP1jyHSkQqv2YWdL1bm9Rp8DNJ+HG0OP913fTuE3V
+7ScOt2ZnR2B+VWN3Eu8MdiX16vi/ub/4H1HihANw/W5HSwuW88V7fGcbSzRWxyCN
+5Od7b5y2zAD/tl+x4GXFZ9k+di2sZc7W6zzVqHr55nfxvsFvHt5dWipTxZFdVhRh
+tXhGnYCfr1gKN4FdTW/MuYa3otHL4gVpnVdQ10C48bCljCaVdep/AhC5dj0GaTyx
+VJBzzD5vp6zt6jsfjI059+zVyR5zxhEKeotURVTqzhz08TOHCkyQP0KRQ+U5ve80
+9cj1odt43JBXFq5w9/aUQWG6ZnBJQup/zlDdGncPd0+3Eh0WoQyDh/XlFosrxt7L
+QF9SqN9oTIp9Fgr6yOFrDOamQAb6f+5Ms5XNegHmlqSkGcpJxf2JBNinrY4drrQ8
+GuVCQ94GhjdGMdSM8Vv8Yi+8RHyqn6R2hjiY4PX+86J+xFNOGr5RiXk8NUp5kM5s
+ZfffpB0ELlgBQzEv2PV9hdh66M8EGjyQl4ItzXg3JhbiXOKAQLbpPOD22zcZsmm2
+r5E4vgRwYfHnmwqJsrIcvMK1m4USlGuwJYP5ExuwE4xdsaUNwKEd3gZAXzhV1YKn
+HyBfJFwYJsBR+l9G9kt/ZWpEd2DNnfss7ujQYTHGQ6WT1zbKbCsb8aE1CNXXs93C
+DtuMUvG+BRTwuSAtvWTf+XPcTjgTrrAKQq2tmsbDe3CEgW5r/4+OL6s3nxI/mVVg
+4jOcUZ0bePBvu+4/jIRqlx2MZIFRp+vvR4RiQ0wYBcihW7Wed8y+ZWdHxg6eUlJP
+WXwdmXsz+NFMXpJvBX0OgntVzxEdJAyGEeBArBJPAKmcbR3JfDWMQ8M=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.crt b/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.crt
index 309ade87fbd78..317991a707a16 100644
--- a/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.crt
+++ b/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.crt
@@ -1,22 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDsjCCApqgAwIBAgIUXxlg/0/g3UYekXWBRpkHM84EYfIwDQYJKoZIhvcNAQEL
-BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
-cmF0ZWQgQ0EwHhcNMTkwMTEwMDIxMDMwWhcNNDYwNTI3MDIxMDMwWjAPMQ0wCwYD
-VQQDEwRodHRwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi8VQaSR6
-uqgT1Rkw+a39OSXcXuhJBVdoO+AyYPK7hdUTxj1aqnXkKeAiNGpe/J+uXZ837Spy
-rmBZS3k6S5hLEceF2xug8yrR7RYEZ+JvGlRgg/jj+61gGbHAD314+vvu0YUo06YG
-wbz9AnjJA/sMbsCp3iSzWIkwZBZcCoZ/YsG4I89LSjYL3YmRi2193WMX6/OfQYMN
-Fkv61r/iwBEkgJ14cUSYe3norGuQfZuXSh5kI5D5R7q7Bmb0um+jzY/l62kj3oR1
-YWo3g6DdU/Bc/3/KmEEVXIfdTonMBMyL8PvYORoMKrYdph3E8e39ZQhPeBJNJKw0
-XzsZFzIUlTw0kQIDAQABo4HgMIHdMB0GA1UdDgQWBBTiqknjZLa5E1BneHRvTkNa
-Bm4nNTAfBgNVHSMEGDAWgBSU68vXWuUWW2xC2AmllVRZZUpvAzCBjwYDVR0RBIGH
-MIGEgglsb2NhbGhvc3SCF2xvY2FsaG9zdDYubG9jYWxkb21haW42hwR/AAABhxAA
-AAAAAAAAAAAAAAAAAAABggpsb2NhbGhvc3Q0ggpsb2NhbGhvc3Q2ghVsb2NhbGhv
-c3QubG9jYWxkb21haW6CF2xvY2FsaG9zdDQubG9jYWxkb21haW40MAkGA1UdEwQC
-MAAwDQYJKoZIhvcNAQELBQADggEBAIZr8EhhCbNyc6iHzUJ/NrUGht5RDHUKN9WU
-2fd+SJlWijQYGoFW6LfabmYxIVPAFtYzUiA378NFoOZZ4kdC3gQng8izvS2UDcO6
-cAG5q/dxop3VXqcLeK3NpH2jd83M8VZaOThPj/F07eTkVX+sGu+7VL5Lc/XPe8JS
-HhH2QtcTPGPpzPnWOUMLpRy4mh5sDyeftWr2PTFgMXFD6dtzDvaklGJvr1TmcOVb
-BFYyVyXRq6v8YsrRPp0GIl+X3zd3KgwUMuEzRKkJgeI1lZRjmHMIyFcqxlwMaHpv
-r1XUmz02ycy6t3n+2kCgfU6HnjbeFh55KzNCEv8TXQFg8Z8YpDA=
+MIIDUTCCAjmgAwIBAgIURxNp9ImDloxqOPNAP0ySBZN/BDUwDQYJKoZIhvcNAQEL
+BQAwHzEdMBsGA1UEAwwUT3BlblNlYXJjaCBUZXN0IE5vZGUwHhcNMjQwODI4MTA0
+NDE1WhcNMzQwODI2MTA0NDE1WjBiMQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT05U
+QVJJTzEQMA4GA1UEBwwHVE9ST05UTzEMMAoGA1UECgwDT1JHMQ0wCwYDVQQLDARV
+TklUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCk1Ot2RGbUS3yJchvdtrcGJPoR8cTTUfVVMMRT+btXayllbLQd/cHV
+jP1DxauXiLQs77R3NGfPs/Sk7fGQh6p/4F52F5wlNqG/Hq0MquqjXEo/ey8i+p5Y
+zTB8v2Hv6RwN0HLB2uiAUOWjHvddiz36nfPmQ5jlF+IsR36KMb6AWHaB60kUabZL
+vPOrtw7KZMkHRC+3tXvvepNe3uAKTIOEeHJneNNc76ShPnjANev7ONpNHgvMTJDY
+nbNtDL2WnHvnyEwIgWLOnJ1WgOAsiSpebPqibi+25FirFKGTB2qp2NfU+tCoK7hG
+1nPfPSCxBEqhwoJOywft2AxhDoicvo+HAgMBAAGjQjBAMB0GA1UdDgQWBBQ2Dr4v
+2/aWi1JSmXfRITKOTlwa+DAfBgNVHSMEGDAWgBTjV81VkxbQpzmea/neQpMg1lPQ
+IzANBgkqhkiG9w0BAQsFAAOCAQEAXEmxgNViixLWVQx9EgWscxaiI4d4OFd7Dfb/
+11qRtKoobEuSK5lOhDim8hZfs+iueKHuT/bRJ59Yu/p4GS+ZeJRgEXfCdY9S3Zeb
+qGCi/IBRT1oq4vD3OSWA88C3I+pGXRb7R3fvtIcfy42o1FdHAg3MOlRx7fZHtAdE
+GJ4SRsKTex7phWvKZ14R+wj45B8dA8Ty6/6nzPqb5+SLa5w37jU/gdew2cW2lEaN
+tZb/aj1l5LmxXje3mvVag5SR2ussDrARcRu+uW7qYq0IzzQDxyzwpEWPC/QsgEme
+9GFPd3xNu4tSoM0arrK8xjNtEh4P2gokhNJwy+vDGvKMrrWjVg==
-----END CERTIFICATE-----
diff --git a/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.key b/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.key
index 8b8d3b4083c67..68b61c6d6e03e 100644
--- a/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.key
+++ b/modules/reindex/src/test/resources/org/opensearch/index/reindex/http/http.key
@@ -1,30 +1,30 @@
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,127A4142FA81C5A1
-
-dP6oSAUl47KCnP0YZSX108qcX5s2nVGpD0qtnVQg89mLVFd7IxpKQaIuODSadRTo
-AD0KINITy3ZwUr/TTJgERu88baBsTHv3PLEe7TpQI2DGGDz3aZfO9e6Jvglbdi5b
-CBLaxRXGGhhH9YH0E87Lp3JEwg4udWmlNahGIhbqNheZNTtDKt+Lx80TyyIml2r/
-GAhjT4UPvIRrATFAcL/3EKOjRqvb6SeGnZu21n2TSmsBEr02gC0Ox3qmsnRM3kvU
-jCuUzWTzJSQLXZwZuMtv5srOSFAbU8EklFXNhWJU/7GBy215aAAW48hCzkPMVEbg
-oeH4nuze/Uulih9UxJGCBIpvfTnksyMRGP/zdy1mnKuqQk+yI0n7JWMJL8QoDQc8
-XvzqOmKLdBVezmzOVP/PyMAhYWetILh/1UesjyJot2hwSXPAxqBHPVA9bnmel6CQ
-VccNSwaK120yT5YhkUMFc0AmUpztzNMQzJ10g1dW+Qsr+n4vtFmAuTvBgogNNVXn
-eX1hbbiXGO1Fw4OMu6qTJ4T/P+VFb0CxoxETWeqdjcs4LGbeqF68nayEsW0ZzhbI
-W5c+JAbW18Kb+k/KzKZTtJEXBw6B/2FMe9x9z3BIpVhplM2KsNk7joWnumD8LfUT
-ORRHUPV7bkdiDsn2CRaevubDQiChcjsdLWhG7JLm54ttyif7/X7htGOXPZLDLK8B
-Vxe09B006f7lM0tXEx8BLFDNroMLlrxB4K5MlwWpS3LLqy4zDbHka2I3s/ST/BD4
-0EURHefiXJkR6bRsfGCl3JDk0EakcUXM+Ob5/2rC/rPXO2pC0ksiQ2DSBm7ak9om
-vlC7dIzVipL0LZTd4SUDJyvmK4Ws6V98O5b+79To6oZnVs5CjvcmpSFVePZa5gm/
-DB8LOpW4jklz+ybJtHJRbEIzmpfwpizThto/zLbhPRyvJkagJfWgXI0j+jjKZj+w
-sy1V8S44aXJ3GX9p4d/Grnx6WGvEJSV0na7m3YQCPEi5sUgr+EMizGUYstSSUPtU
-XhxQRZ95K2cKORul9vzG3zZqqvi73Ju5vu9DLmmlI00sLzyVGFtvkuhrF2p7XclM
-GU/rMOeMClMb6qyCzldSs84Anhlh/6mYri6uYPhIGvxqtH44FTbu1APvZp0s2rVm
-ueClHG78lat+oqWFpbA8+peT0dMPdSKDAFDiHsGoeWCIoCF44a84bJX35OZk+Y4a
-+fDFuSiKYBMfAgqf/ZNzV4+ySka7dWdRQ2TDgIuxnvFV1NgC/ir3/mPgkf0xZU5d
-w8T+TW6T8PmJfHnW4nxgHaqgxMoEoPm8zn0HNpRFKwsDYRFfobpCXnoyx50JXxa4
-jg095zlp8X0JwconlGJB1gfeqvS2I50WEDR+2ZtDf7fUEnQ3LYJzP4lSwiSKiQsQ
-MPjy0SMQnqmWijylLYKunTl3Uh2DdYg4MOON662H3TxQW8TCYwK2maKujwS9VFLN
-GtRGlLrOtrOfHBSwDCujFjqEmQBsF/y2C6XfMoNq6xi5NzREGmNXYrHbLvl2Njwm
-WB1ouB4JzmEmb1QNwxkllBAaUp1SJGhW2+fYOe0zjWOP9R4sUq4rRw==
------END RSA PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQprhRDFFTnmWmHgAB
+ULpI4wICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEEuzT8itQgHZfKb/
+ReywEdIEggTQD117YFYRhSSivErIhTKQSuofhH/ZgW6nYnKlcDT08bgNQjbEg94a
+QZqsPl9D6tfcmg7XlNTEiQpnSnsh6LrrhQbNkt3PvJxfUUy0ATVXXdH538RcPLAC
+K2NHi1iwSbnqdcBU+/Be8M1F9e9P5hx6HbJGEF/JIkpWDDmOoCGvlwfH0PSiliY4
+uqxsmekvNgz2GBhELZj4sEJ7C7/I26vOuzS6suDn6xGF8JZIg8i7upamUgLoBtG/
+waxlmfTx+hkYFDQGcy9jvkV043sK/hLTOycUGhmS1ybQSf9ANbsM8RjOIq6QxpIZ
+wtV/7EzqDWYradQBRrhAP24yzEj6H1cTr8yMmD6JuxvGZ7uQpTCRiFopB6TgK+x+
+2HqEgeRyBz4hU0i22kyGHC9sSG9WwKhmXhfcBtzJi3JABbkeg9LarwOzbh51DaxN
+/gTop4UYRTYbJB9bhcIU0Y5xPSSphphCWmGuBU6CinsBj1w+UBP137GzgnXvV6PL
+S8tai963P38Oafw/T2IyFTyAkuHJJ5MjVc71Q+vYLzfu4SfBdSIb1oFPT4otNwHP
+NbPvTYq0DWnHFNeIc5vmLJJTWVemBTkxvHr+WfU8meFsjxZT05gzgOk+5BZFya5h
+oV53mYQYPSyJiBUz0icHyyzUWaEHQLXHrmE6i+kW7+b4lrhi7KV1AMGRSJXUS9/Q
+I7NuCQG3+iCyMd+CupvsiK7xjOytgCstwWIGeHlSmYwS+txi1wpbBJ4X6NQLlHyy
+KZoFxyWTKtEdX1QKioBxeoKVy5G5LOh7S/jd9jEsZ2C8snFnDbNHALBmXIH3fshA
+bo4keel427V6W3f9/u0nT1RWrYiBK12XJiS3/kXg8krln1Xb/MkgTKmLEZF+VDXO
+Y3QwAICNM6/235siHuQG+uJ/WoL9xd1R22/+2mxNy1Rdhd49n8GFg0Kjsbmd+hL9
+aMwRU09SNNPCwdAIHmoMCIYS6uTX1bcGSzMir16JepmIYQllwdOoLk2nxtBCaHwj
+ZLYO21W+iFgo4TwXzkuaI2q3Ll0n79BJUVdOnz8hBCq0Ox7sTEY7g1vQGHIsBx98
+PYZmaaXVh+u2chHKrwp6L9mRikXQiNWwtqTH/kp7BydRnYIcaP27SCM8HbaYfV/x
+02FjBbpZ7u1PwS3jlGmcxE/qTd+cLkk3pm7WPPMlOnMh/X5N3/OpznUgJnVRtGqk
+uDy4HSE5vEhHDp0F67R0ph8/HfIBamvJIoonYzoC2iEMgL4yqL0x44SOCioXScgz
+hluYX1kQRfyXWjoP+vBBOUapwYDwk1gGXap5iQjtiVq6FN8DspckHRVI5B1voVIC
+37Mn2OXH9JloObouLYMRa1dDm7h+/3Cb9UAhKpOjpLc1apA49+Rjtq1gBExhac74
+9SwrcQJdRx0NDJjoMHKrGUFkg/W+R7OTad7+l98M473nWuV3mzJDXcuxmam9llRI
+2O+1QsV5hjd4/zCtIka+pOALp+cVSmktTjKNh105asX7d4XIxtg3M+FJWTEODZfy
+VulvKri/rkrbCBwMQyj3TpF4AkVjhSM2P5j7LRsivfGc8VL00OqYJp9pYfav38gs
+EpYOmaDEV/Ls744WSJJo5Qq0EpDclBTFjky6kZx7RDfySUzfN/Nhv6A=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/modules/transport-netty4/build.gradle b/modules/transport-netty4/build.gradle
index cdaf8350055f0..3c10ac6ccb96b 100644
--- a/modules/transport-netty4/build.gradle
+++ b/modules/transport-netty4/build.gradle
@@ -147,17 +147,6 @@ thirdPartyAudit {
'io.netty.internal.tcnative.SSLContext',
'io.netty.internal.tcnative.SSLPrivateKeyMethod',
- // from io.netty.handler.ssl.util.BouncyCastleSelfSignedCertGenerator (netty)
- 'org.bouncycastle.cert.X509v3CertificateBuilder',
- 'org.bouncycastle.cert.jcajce.JcaX509CertificateConverter',
- 'org.bouncycastle.operator.jcajce.JcaContentSignerBuilder',
- 'org.bouncycastle.openssl.PEMEncryptedKeyPair',
- 'org.bouncycastle.openssl.PEMParser',
- 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter',
- 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder',
- 'org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder',
- 'org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo',
-
// from io.netty.handler.ssl.JettyNpnSslEngine (netty)
'org.eclipse.jetty.npn.NextProtoNego$ClientProvider',
'org.eclipse.jetty.npn.NextProtoNego$ServerProvider',
diff --git a/modules/transport-netty4/src/test/java/org/opensearch/http/netty4/ssl/SecureNetty4HttpServerTransportTests.java b/modules/transport-netty4/src/test/java/org/opensearch/http/netty4/ssl/SecureNetty4HttpServerTransportTests.java
index f80ad901ce765..0a801a0f58f02 100644
--- a/modules/transport-netty4/src/test/java/org/opensearch/http/netty4/ssl/SecureNetty4HttpServerTransportTests.java
+++ b/modules/transport-netty4/src/test/java/org/opensearch/http/netty4/ssl/SecureNetty4HttpServerTransportTests.java
@@ -10,6 +10,8 @@
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.opensearch.OpenSearchException;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
import org.opensearch.common.network.NetworkAddress;
import org.opensearch.common.network.NetworkService;
import org.opensearch.common.settings.ClusterSettings;
@@ -121,13 +123,13 @@ public Optional buildHttpServerExceptionHandler(Setti
@Override
public Optional buildSecureHttpServerEngine(Settings settings, HttpServerTransport transport) throws SSLException {
try {
- final KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ final KeyStore keyStore = KeyStoreFactory.getInstance(KeyStoreType.BCFKS);
keyStore.load(
- SecureNetty4HttpServerTransportTests.class.getResourceAsStream("/netty4-secure.jks"),
+ SecureNetty4HttpServerTransportTests.class.getResourceAsStream("/netty4-secure.bcfks"),
"password".toCharArray()
);
- final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
+ final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "password".toCharArray());
SSLEngine engine = SslContextBuilder.forServer(keyManagerFactory)
diff --git a/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java b/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java
index e0600aebd90e5..2502a77af50e0 100644
--- a/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java
+++ b/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java
@@ -8,8 +8,11 @@
package org.opensearch.transport.netty4.ssl;
+import org.apache.lucene.tests.util.LuceneTestCase;
import org.opensearch.Version;
import org.opensearch.cluster.node.DiscoveryNode;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
import org.opensearch.common.network.NetworkService;
import org.opensearch.common.settings.ClusterSettings;
import org.opensearch.common.settings.Settings;
@@ -64,6 +67,7 @@
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
+@LuceneTestCase.AwaitsFix(bugUrl = "")
public class SimpleSecureNetty4TransportTests extends AbstractSimpleTransportTestCase {
@Override
protected Transport build(Settings settings, final Version version, ClusterSettings clusterSettings, boolean doHandshake) {
@@ -77,13 +81,13 @@ public Optional buildServerTransportExceptionHandler(
@Override
public Optional buildSecureServerTransportEngine(Settings settings, Transport transport) throws SSLException {
try {
- final KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ final KeyStore keyStore = KeyStoreFactory.getInstance(KeyStoreType.JKS);
keyStore.load(
SimpleSecureNetty4TransportTests.class.getResourceAsStream("/netty4-secure.jks"),
"password".toCharArray()
);
- final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
+ final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "password".toCharArray());
SSLEngine engine = SslContextBuilder.forServer(keyManagerFactory)
diff --git a/modules/transport-netty4/src/test/resources/README.md b/modules/transport-netty4/src/test/resources/README.md
new file mode 100644
index 0000000000000..5b74bd85e7c4a
--- /dev/null
+++ b/modules/transport-netty4/src/test/resources/README.md
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+#
+# This is README describes how the certificates in this directory were created.
+# This file can also be executed as a script
+#
+
+# 1. Create certificate key
+
+`openssl req -x509 -sha256 -newkey rsa:2048 -keyout certificate.key -out certificate.crt -days 1024 -nodes`
+
+# 2. Export the certificate in pkcs12 format
+
+`openssl pkcs12 -export -in certificate.crt -inkey certificate.key -out netty4-secure.p12 -name netty4-secure -password pass:password`
+
+# 3. Migrate from P12 to JKS keystore
+
+```
+keytool -importkeystore -noprompt \
+ -srckeystore netty4-secure.p12 \
+ -srcstoretype PKCS12 \
+ -srcstorepass password \
+ -alias netty4-secure \
+ -destkeystore netty4-secure.jks \
+ -deststoretype JKS \
+ -deststorepass password
+```
+
+# 4. Migrate from P12 to BCFIPS keystore
+
+```
+keytool -importkeystore -noprompt \
+ -srckeystore netty4-secure.p12 \
+ -srcstoretype PKCS12 \
+ -srcstorepass password \
+ -alias netty4-secure \
+ -destkeystore netty4-secure.bcfks \
+ -deststoretype BCFKS \
+ -deststorepass password \
+ -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath $LIB_PATH/bc-fips-2.0.0.jar
+```
diff --git a/modules/transport-netty4/src/test/resources/README.txt b/modules/transport-netty4/src/test/resources/README.txt
deleted file mode 100644
index c8cec5d3803a4..0000000000000
--- a/modules/transport-netty4/src/test/resources/README.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-#
-# This is README describes how the certificates in this directory were created.
-# This file can also be executed as a script
-#
-
-# 1. Create certificate key
-
-openssl req -x509 -sha256 -newkey rsa:2048 -keyout certificate.key -out certificate.crt -days 1024 -nodes
-
-# 2. Export the certificate in pkcs12 format
-
-openssl pkcs12 -export -in certificate.crt -inkey certificate.key -out server.p12 -name netty4-secure -password pass:password
-
-# 3. Import the certificate into JDK keystore (PKCS12 type)
-
-keytool -importkeystore -srcstorepass password -destkeystore netty4-secure.jks -srckeystore server.p12 -srcstoretype PKCS12 -alias netty4-secure -deststorepass password
\ No newline at end of file
diff --git a/modules/transport-netty4/src/test/resources/netty4-secure.bcfks b/modules/transport-netty4/src/test/resources/netty4-secure.bcfks
new file mode 100644
index 0000000000000..034f2a1331729
Binary files /dev/null and b/modules/transport-netty4/src/test/resources/netty4-secure.bcfks differ
diff --git a/modules/transport-netty4/src/test/resources/netty4-secure.jks b/modules/transport-netty4/src/test/resources/netty4-secure.jks
index 59dfd31c2a156..d158f1fe60ef7 100644
Binary files a/modules/transport-netty4/src/test/resources/netty4-secure.jks and b/modules/transport-netty4/src/test/resources/netty4-secure.jks differ
diff --git a/modules/transport-netty4/src/test/resources/netty4-secure.p12 b/modules/transport-netty4/src/test/resources/netty4-secure.p12
new file mode 100644
index 0000000000000..822d7ff8236f3
Binary files /dev/null and b/modules/transport-netty4/src/test/resources/netty4-secure.p12 differ
diff --git a/modules/transport-netty4/src/yamlRestTest/java/org/opensearch/http/netty4/Netty4ClientYamlTestSuiteIT.java b/modules/transport-netty4/src/yamlRestTest/java/org/opensearch/http/netty4/Netty4ClientYamlTestSuiteIT.java
index 45693078174a8..9c10dc98202eb 100644
--- a/modules/transport-netty4/src/yamlRestTest/java/org/opensearch/http/netty4/Netty4ClientYamlTestSuiteIT.java
+++ b/modules/transport-netty4/src/yamlRestTest/java/org/opensearch/http/netty4/Netty4ClientYamlTestSuiteIT.java
@@ -39,15 +39,10 @@
import org.apache.lucene.tests.util.TimeUnits;
import org.opensearch.test.rest.yaml.ClientYamlTestCandidate;
import org.opensearch.test.rest.yaml.OpenSearchClientYamlSuiteTestCase;
-import org.junit.BeforeClass;
//TODO: This is a *temporary* workaround to ensure a timeout does not mask other problems
@TimeoutSuite(millis = 30 * TimeUnits.MINUTE)
public class Netty4ClientYamlTestSuiteIT extends OpenSearchClientYamlSuiteTestCase {
- @BeforeClass
- public static void muteInFips() {
- assumeFalse("We run with DEFAULT distribution in FIPS mode and default to security4 instead of netty4", inFipsJvm());
- }
public Netty4ClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
diff --git a/plugins/analysis-icu/src/test/java/org/opensearch/index/analysis/IcuAnalyzerTests.java b/plugins/analysis-icu/src/test/java/org/opensearch/index/analysis/IcuAnalyzerTests.java
index c363bc6eb43f8..c74dbb22bc21e 100644
--- a/plugins/analysis-icu/src/test/java/org/opensearch/index/analysis/IcuAnalyzerTests.java
+++ b/plugins/analysis-icu/src/test/java/org/opensearch/index/analysis/IcuAnalyzerTests.java
@@ -35,6 +35,7 @@
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.tests.analysis.BaseTokenStreamTestCase;
import org.opensearch.Version;
+import org.opensearch.bootstrap.SecureRandomInitializer;
import org.opensearch.cluster.metadata.IndexMetadata;
import org.opensearch.common.settings.Settings;
import org.opensearch.index.IndexSettings;
@@ -47,6 +48,10 @@
public class IcuAnalyzerTests extends BaseTokenStreamTestCase {
+ static {
+ SecureRandomInitializer.init();
+ }
+
public void testMixedAlphabetTokenization() throws IOException {
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT).build();
diff --git a/plugins/discovery-azure-classic/src/internalClusterTest/java/org/opensearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java b/plugins/discovery-azure-classic/src/internalClusterTest/java/org/opensearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java
index a4b733ec7d894..f48b20d52f601 100644
--- a/plugins/discovery-azure-classic/src/internalClusterTest/java/org/opensearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java
+++ b/plugins/discovery-azure-classic/src/internalClusterTest/java/org/opensearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java
@@ -41,6 +41,8 @@
import org.apache.logging.log4j.LogManager;
import org.opensearch.cloud.azure.classic.management.AzureComputeService;
import org.opensearch.common.SuppressForbidden;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
import org.opensearch.common.settings.Setting;
import org.opensearch.common.settings.Settings;
import org.opensearch.core.util.FileSystemUtils;
@@ -278,14 +280,14 @@ public static void startHttpd() throws Exception {
private static SSLContext getSSLContext() throws Exception {
char[] passphrase = "keypass".toCharArray();
- KeyStore ks = KeyStore.getInstance("JKS");
+ KeyStore ks = KeyStoreFactory.getInstance(KeyStoreType.JKS);
try (InputStream stream = AzureDiscoveryClusterFormationTests.class.getResourceAsStream("/test-node.jks")) {
assertNotNull("can't find keystore file", stream);
ks.load(stream, passphrase);
}
- KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, passphrase);
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
SSLContext ssl = SSLContext.getInstance(getProtocol());
ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
diff --git a/plugins/identity-shiro/build.gradle b/plugins/identity-shiro/build.gradle
index 222443efcb214..2d0d8f27f46b0 100644
--- a/plugins/identity-shiro/build.gradle
+++ b/plugins/identity-shiro/build.gradle
@@ -28,7 +28,8 @@ dependencies {
implementation 'org.passay:passay:1.6.3'
- implementation "org.bouncycastle:bcprov-jdk18on:${versions.bouncycastle}"
+ // Bcrypt hash matching
+ implementation 'com.password4j:password4j:1.8.2'
testImplementation project(path: ':modules:transport-netty4') // for http
testImplementation project(path: ':plugins:transport-nio') // for http
diff --git a/plugins/identity-shiro/licenses/bcprov-jdk18on-1.78.jar.sha1 b/plugins/identity-shiro/licenses/bcprov-jdk18on-1.78.jar.sha1
deleted file mode 100644
index 47fb5fd5e5f5d..0000000000000
--- a/plugins/identity-shiro/licenses/bcprov-jdk18on-1.78.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-619aafb92dc0b4c6cc4cf86c487ca48ee2d67a8e
\ No newline at end of file
diff --git a/plugins/identity-shiro/licenses/bcprov-jdk18on-LICENSE.txt b/plugins/identity-shiro/licenses/bcprov-jdk18on-LICENSE.txt
deleted file mode 100644
index 9f27bafe96885..0000000000000
--- a/plugins/identity-shiro/licenses/bcprov-jdk18on-LICENSE.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc.
- (http://www.bouncycastle.org)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/plugins/identity-shiro/licenses/password4j-1.8.2.jar.sha1 b/plugins/identity-shiro/licenses/password4j-1.8.2.jar.sha1
new file mode 100644
index 0000000000000..bee14467d32a2
--- /dev/null
+++ b/plugins/identity-shiro/licenses/password4j-1.8.2.jar.sha1
@@ -0,0 +1 @@
+f8ac106c667c0b081075e81a90dc92861b9bb66e
\ No newline at end of file
diff --git a/plugins/identity-shiro/licenses/password4j-LICENSE.txt b/plugins/identity-shiro/licenses/password4j-LICENSE.txt
new file mode 100644
index 0000000000000..261eeb9e9f8b2
--- /dev/null
+++ b/plugins/identity-shiro/licenses/password4j-LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/plugins/identity-shiro/licenses/bcprov-jdk18on-NOTICE.txt b/plugins/identity-shiro/licenses/password4j-NOTICE.txt
similarity index 100%
rename from plugins/identity-shiro/licenses/bcprov-jdk18on-NOTICE.txt
rename to plugins/identity-shiro/licenses/password4j-NOTICE.txt
diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcher.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcher.java
index f8113101deb70..45bf634de1ec1 100644
--- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcher.java
+++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcher.java
@@ -12,7 +12,16 @@
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
-import org.bouncycastle.crypto.generators.OpenBSDBCrypt;
+import org.opensearch.SpecialPermission;
+
+import java.nio.CharBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import com.password4j.BcryptFunction;
+import com.password4j.Password;
+
+import static org.opensearch.core.common.Strings.isNullOrEmpty;
/**
* Password matcher for BCrypt
@@ -28,7 +37,24 @@ public class BCryptPasswordMatcher implements CredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
final UsernamePasswordToken userToken = (UsernamePasswordToken) token;
- return OpenBSDBCrypt.checkPassword((String) info.getCredentials(), userToken.getPassword());
+ return check(userToken.getPassword(), (String) info.getCredentials());
+ }
+
+ private boolean check(char[] password, String hash) {
+ if (password == null || password.length == 0) {
+ throw new IllegalStateException("Password cannot be empty or null");
+ }
+ if (isNullOrEmpty(hash)) {
+ throw new IllegalStateException("Hash cannot be empty or null");
+ }
+ CharBuffer passwordBuffer = CharBuffer.wrap(password);
+ SecurityManager securityManager = System.getSecurityManager();
+ if (securityManager != null) {
+ securityManager.checkPermission(new SpecialPermission());
+ }
+ return AccessController.doPrivileged(
+ (PrivilegedAction) () -> Password.check(passwordBuffer, hash).with(BcryptFunction.getInstanceFromHash(hash))
+ );
}
}
diff --git a/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcherTests.java b/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcherTests.java
index 91e88ed1bf701..304903e27c953 100644
--- a/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcherTests.java
+++ b/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcherTests.java
@@ -41,4 +41,23 @@ public void testCredentialDoNotMatch() {
assertThat(result, equalTo(false));
}
+
+ public void testEmptyPassword() {
+ final UsernamePasswordToken token = mock(UsernamePasswordToken.class);
+ when(token.getPassword()).thenReturn(randomFrom("".toCharArray(), null));
+ final AuthenticationInfo info = mock(AuthenticationInfo.class);
+
+ Exception e = assertThrows(IllegalStateException.class, () -> new BCryptPasswordMatcher().doCredentialsMatch(token, info));
+ assertThat(e.getMessage(), equalTo("Password cannot be empty or null"));
+ }
+
+ public void testEmptyHash() {
+ final UsernamePasswordToken token = mock(UsernamePasswordToken.class);
+ when(token.getPassword()).thenReturn("HashedPassword".toCharArray());
+ final AuthenticationInfo info = mock(AuthenticationInfo.class);
+ when(info.getCredentials()).thenReturn(randomFrom("", null));
+
+ Exception e = assertThrows(IllegalStateException.class, () -> new BCryptPasswordMatcher().doCredentialsMatch(token, info));
+ assertThat(e.getMessage(), equalTo("Hash cannot be empty or null"));
+ }
}
diff --git a/plugins/ingest-attachment/build.gradle b/plugins/ingest-attachment/build.gradle
index 4f30ea9ea7e22..c2f87825b0f14 100644
--- a/plugins/ingest-attachment/build.gradle
+++ b/plugins/ingest-attachment/build.gradle
@@ -81,9 +81,6 @@ dependencies {
api "org.apache.pdfbox:fontbox:${versions.pdfbox}"
api "org.apache.pdfbox:jempbox:1.8.17"
api "commons-logging:commons-logging:${versions.commonslogging}"
- api "org.bouncycastle:bcmail-jdk18on:${versions.bouncycastle}"
- api "org.bouncycastle:bcprov-jdk18on:${versions.bouncycastle}"
- api "org.bouncycastle:bcpkix-jdk18on:${versions.bouncycastle}"
// OpenOffice
api "org.apache.poi:poi-ooxml:${versions.poi}"
api "org.apache.poi:poi:${versions.poi}"
@@ -145,12 +142,3 @@ thirdPartyAudit {
'com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper$1'
)
}
-
-if (BuildParams.inFipsJvm) {
- // FIPS JVM includes many classes from bouncycastle which count as jar hell for the third party audit,
- // rather than provide a long list of exclusions, disable the check on FIPS.
- jarHell.enabled = false
- test.enabled = false
- yamlRestTest.enabled = false;
- testingConventions.enabled = false;
-}
diff --git a/plugins/ingest-attachment/licenses/bcmail-jdk18on-1.78.jar.sha1 b/plugins/ingest-attachment/licenses/bcmail-jdk18on-1.78.jar.sha1
deleted file mode 100644
index eb7e650306f73..0000000000000
--- a/plugins/ingest-attachment/licenses/bcmail-jdk18on-1.78.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d26f5514b8c54f2878f8d49e0bc8e2acaab3c8bd
\ No newline at end of file
diff --git a/plugins/ingest-attachment/licenses/bcmail-jdk18on-LICENSE.txt b/plugins/ingest-attachment/licenses/bcmail-jdk18on-LICENSE.txt
deleted file mode 100644
index dbba1dd7829c7..0000000000000
--- a/plugins/ingest-attachment/licenses/bcmail-jdk18on-LICENSE.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc.
- (http://www.bouncycastle.org)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
diff --git a/plugins/ingest-attachment/licenses/bcmail-jdk18on-NOTICE.txt b/plugins/ingest-attachment/licenses/bcmail-jdk18on-NOTICE.txt
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/plugins/ingest-attachment/licenses/bcpkix-jdk18on-1.78.jar.sha1 b/plugins/ingest-attachment/licenses/bcpkix-jdk18on-1.78.jar.sha1
deleted file mode 100644
index 385a9d930eede..0000000000000
--- a/plugins/ingest-attachment/licenses/bcpkix-jdk18on-1.78.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-dd61bcdb87678451dd42d42e267979bd4b4451a1
\ No newline at end of file
diff --git a/plugins/ingest-attachment/licenses/bcpkix-jdk18on-LICENSE.txt b/plugins/ingest-attachment/licenses/bcpkix-jdk18on-LICENSE.txt
deleted file mode 100644
index e1fc4a1506db5..0000000000000
--- a/plugins/ingest-attachment/licenses/bcpkix-jdk18on-LICENSE.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc.
- (http://www.bouncycastle.org)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
diff --git a/plugins/ingest-attachment/licenses/bcpkix-jdk18on-NOTICE.txt b/plugins/ingest-attachment/licenses/bcpkix-jdk18on-NOTICE.txt
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/plugins/ingest-attachment/licenses/bcprov-jdk18on-1.78.jar.sha1 b/plugins/ingest-attachment/licenses/bcprov-jdk18on-1.78.jar.sha1
deleted file mode 100644
index 47fb5fd5e5f5d..0000000000000
--- a/plugins/ingest-attachment/licenses/bcprov-jdk18on-1.78.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-619aafb92dc0b4c6cc4cf86c487ca48ee2d67a8e
\ No newline at end of file
diff --git a/plugins/ingest-attachment/licenses/bcprov-jdk18on-LICENSE.txt b/plugins/ingest-attachment/licenses/bcprov-jdk18on-LICENSE.txt
deleted file mode 100644
index 9f27bafe96885..0000000000000
--- a/plugins/ingest-attachment/licenses/bcprov-jdk18on-LICENSE.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc.
- (http://www.bouncycastle.org)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/plugins/ingest-attachment/licenses/bcprov-jdk18on-NOTICE.txt b/plugins/ingest-attachment/licenses/bcprov-jdk18on-NOTICE.txt
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/plugins/repository-azure/build.gradle b/plugins/repository-azure/build.gradle
index d419f6fafeb30..dd12e0fd6ce73 100644
--- a/plugins/repository-azure/build.gradle
+++ b/plugins/repository-azure/build.gradle
@@ -214,16 +214,6 @@ thirdPartyAudit {
// Worth nothing that, the latest dependency "net.shibboleth.utilities:java-support:8.0.0" has many vulnerabilities.
// Hence ignored.
'net.shibboleth.utilities.java.support.xml.SerializeSupport',
- 'org.bouncycastle.asn1.pkcs.PrivateKeyInfo',
- 'org.bouncycastle.asn1.x509.AlgorithmIdentifier',
- 'org.bouncycastle.asn1.x509.SubjectPublicKeyInfo',
- 'org.bouncycastle.cert.X509CertificateHolder',
- 'org.bouncycastle.cert.jcajce.JcaX509CertificateHolder',
- 'org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder',
- 'org.bouncycastle.openssl.PEMKeyPair',
- 'org.bouncycastle.openssl.PEMParser',
- 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter',
- 'org.bouncycastle.operator.jcajce.JcaContentSignerBuilder',
'org.cryptomator.siv.SivMode',
'org.opensaml.core.config.InitializationException',
'org.opensaml.core.config.InitializationService',
@@ -314,6 +304,10 @@ Map expansions = [
'base_path': azureBasePath + "_integration_tests"
]
+tasks.withType(Test).configureEach {
+ onlyIf { BuildParams.inFipsJvm == false }
+}
+
processYamlRestTestResources {
inputs.properties(expansions)
MavenFilteringHack.filter(it, expansions)
diff --git a/plugins/repository-gcs/build.gradle b/plugins/repository-gcs/build.gradle
index 97ae88aac5485..b2baeada0dd6b 100644
--- a/plugins/repository-gcs/build.gradle
+++ b/plugins/repository-gcs/build.gradle
@@ -246,7 +246,7 @@ def encodedCredentials = {
task createServiceAccountFile() {
doLast {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA")
- keyPairGenerator.initialize(1024)
+ keyPairGenerator.initialize(2048)
KeyPair keyPair = keyPairGenerator.generateKeyPair()
String encodedKey = Base64.getEncoder().encodeToString(keyPair.private.getEncoded())
diff --git a/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java b/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java
index 83a4146c99b99..80d3f70614ea1 100644
--- a/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java
+++ b/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java
@@ -32,10 +32,10 @@
package org.opensearch.repositories.gcs;
-import com.google.api.client.googleapis.GoogleUtils;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.util.SecurityUtils;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.ServiceOptions;
@@ -46,10 +46,13 @@
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.opensearch.common.collect.MapBuilder;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
import org.opensearch.common.unit.TimeValue;
import org.opensearch.core.common.Strings;
import java.io.IOException;
+import java.io.InputStream;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.Proxy;
@@ -185,9 +188,12 @@ public HttpRequestInitializer getHttpRequestInitializer(ServiceOptions, ?> ser
private HttpTransport createHttpTransport(final GoogleCloudStorageClientSettings clientSettings) throws IOException {
return SocketAccess.doPrivilegedIOException(() -> {
final NetHttpTransport.Builder builder = new NetHttpTransport.Builder();
- // requires java.lang.RuntimePermission "setFactory"
- // Pin the TLS trust certificates.
- builder.trustCertificates(GoogleUtils.getCertificateTrustStore());
+ // use the BCFIPS trustStore format instead of PKCS#12 to ensure compatibility with BC-FIPS
+ var certTrustStore = KeyStoreFactory.getInstance(KeyStoreType.BCFKS);
+ InputStream keyStoreStream = getClass().getResourceAsStream("/google.bcfks");
+ SecurityUtils.loadKeyStore(certTrustStore, keyStoreStream, "notasecret");
+
+ builder.trustCertificates(certTrustStore);
final ProxySettings proxySettings = clientSettings.getProxySettings();
if (proxySettings != ProxySettings.NO_PROXY_SETTINGS) {
if (proxySettings.isAuthenticated()) {
diff --git a/plugins/repository-gcs/src/main/resources/README.md b/plugins/repository-gcs/src/main/resources/README.md
new file mode 100644
index 0000000000000..bda781bcea537
--- /dev/null
+++ b/plugins/repository-gcs/src/main/resources/README.md
@@ -0,0 +1,19 @@
+#
+# This is README describes how the certificates in this directory were created.
+# This file can also be executed as a script.
+# google-api-java-client provides its own trusted certificates inside google keystore which comes in JKS or PKCS#12 formats.
+# Since BCFIPS requires its own BCFKS format this script creates it.
+#
+
+```
+keytool -importkeystore -noprompt \
+ -srckeystore $KEY_STORE_PATH/google.p12 \
+ -srcstoretype PKCS12 \
+ -srcstorepass notasecret \
+ -destkeystore google.bcfks \
+ -deststoretype BCFKS \
+ -deststorepass notasecret \
+ -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath $LIB_PATH/bc-fips-2.0.0.jar
+```
diff --git a/plugins/repository-gcs/src/main/resources/google.bcfks b/plugins/repository-gcs/src/main/resources/google.bcfks
new file mode 100644
index 0000000000000..13202c5c21eb3
Binary files /dev/null and b/plugins/repository-gcs/src/main/resources/google.bcfks differ
diff --git a/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java b/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java
index b620f212df413..5406e41e5f03d 100644
--- a/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java
+++ b/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java
@@ -188,7 +188,7 @@ public void testClientsAreNotSharedAcrossRepositories() throws Exception {
private byte[] serviceAccountFileContent(String projectId) throws Exception {
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(1024);
+ keyPairGenerator.initialize(2048);
final KeyPair keyPair = keyPairGenerator.generateKeyPair();
final String encodedKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
final XContentBuilder serviceAccountBuilder = jsonBuilder().startObject()
diff --git a/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/TestUtils.java b/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/TestUtils.java
index 648955c079b3e..ba7422e6cf811 100644
--- a/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/TestUtils.java
+++ b/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/TestUtils.java
@@ -50,7 +50,7 @@ private TestUtils() {}
static byte[] createServiceAccount(final Random random) {
try {
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(1024);
+ keyPairGenerator.initialize(2048);
final String privateKey = Base64.getEncoder().encodeToString(keyPairGenerator.generateKeyPair().getPrivate().getEncoded());
final ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/plugins/repository-s3/build.gradle b/plugins/repository-s3/build.gradle
index 398611a016ed2..cdb9fe15e831c 100644
--- a/plugins/repository-s3/build.gradle
+++ b/plugins/repository-s3/build.gradle
@@ -34,6 +34,7 @@ import org.opensearch.gradle.test.RestIntegTestTask
import org.opensearch.gradle.test.TestTask
import org.opensearch.gradle.test.rest.YamlRestTestPlugin
import org.opensearch.gradle.test.InternalClusterTestPlugin
+import org.opensearch.gradle.testclusters.OpenSearchCluster
import static org.opensearch.gradle.PropertyNormalization.IGNORE_VALUE
@@ -143,6 +144,13 @@ def fixtureAddress = { fixture, name, port ->
'http://127.0.0.1:' + ephemeralPort
}
+def applyFipsConfig(OpenSearchCluster cluster) {
+ if (System.getenv('OPENSEARCH_CRYPTO_STANDARD') == 'FIPS-140-3') {
+ cluster.keystorePassword 'notarealpasswordphrase'
+ cluster.environment 'OPENSEARCH_CRYPTO_STANDARD', 'FIPS-140-3'
+ }
+}
+
// We test against two repositories, one which uses the usual two-part "permanent" credentials and
// the other which uses three-part "temporary" or "session" credentials.
@@ -260,6 +268,7 @@ yamlRestTest {
}
testClusters.yamlRestTest {
+ applyFipsConfig(delegate)
keystore 's3.client.integration_test_permanent.access_key', s3PermanentAccessKey
keystore 's3.client.integration_test_permanent.secret_key', s3PermanentSecretKey
@@ -292,7 +301,7 @@ testClusters.yamlRestTest {
setting 's3.client.integration_test_eks.region', { "us-east-2" }, IGNORE_VALUE
// to redirect InstanceProfileCredentialsProvider to custom auth point
- systemProperty "aws.ec2MetadataServiceEndpointOverride", { "${-> fixtureAddress('s3-fixture', 's3-fixture-with-ec2', '80')}" }, IGNORE_VALUE
+ systemProperty "aws.ec2MetadataServiceEndpoint", { "${-> fixtureAddress('s3-fixture', 's3-fixture-with-ec2', '80')}" }, IGNORE_VALUE
// to redirect AWSSecurityTokenServiceClient to custom auth point
systemProperty "aws.stsEndpointOverride", { "${-> fixtureAddress('s3-fixture', 's3-fixture-with-eks', '80')}/eks_credentials_endpoint" }, IGNORE_VALUE
} else {
@@ -323,6 +332,7 @@ if (useFixture) {
check.dependsOn(yamlRestTestMinio)
testClusters.yamlRestTestMinio {
+ applyFipsConfig(delegate)
keystore 's3.client.integration_test_permanent.access_key', s3PermanentAccessKey
keystore 's3.client.integration_test_permanent.secret_key', s3PermanentSecretKey
setting 's3.client.integration_test_permanent.endpoint', { "${-> fixtureAddress('minio-fixture', 'minio-fixture', '9000')}" }, IGNORE_VALUE
@@ -351,6 +361,7 @@ if (useFixture) {
check.dependsOn(yamlRestTestECS)
testClusters.yamlRestTestECS {
+ applyFipsConfig(delegate)
setting 's3.client.integration_test_ecs.endpoint', { "${-> fixtureAddress('s3-fixture', 's3-fixture-with-ecs', '80')}" }, IGNORE_VALUE
plugin tasks.bundlePlugin.archiveFile
environment 'AWS_CONTAINER_CREDENTIALS_FULL_URI', { "${-> fixtureAddress('s3-fixture', 's3-fixture-with-ecs', '80')}/ecs_credentials_endpoint" }, IGNORE_VALUE
@@ -378,6 +389,7 @@ if (useFixture) {
check.dependsOn(yamlRestTestEKS)
testClusters.yamlRestTestEKS {
+ applyFipsConfig(delegate)
keystore 's3.client.integration_test_eks.role_arn', "arn:aws:iam::000000000000:role/test"
keystore 's3.client.integration_test_eks.role_session_name', "s3-test"
keystore 's3.client.integration_test_eks.access_key', "access_key"
@@ -474,17 +486,6 @@ thirdPartyAudit {
'net.jpountz.xxhash.XXHash32',
'net.jpountz.xxhash.XXHashFactory',
- // from io.netty.handler.ssl.util.BouncyCastleSelfSignedCertGenerator (netty)
- 'org.bouncycastle.cert.X509v3CertificateBuilder',
- 'org.bouncycastle.cert.jcajce.JcaX509CertificateConverter',
- 'org.bouncycastle.operator.jcajce.JcaContentSignerBuilder',
- 'org.bouncycastle.openssl.PEMEncryptedKeyPair',
- 'org.bouncycastle.openssl.PEMParser',
- 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter',
- 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder',
- 'org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder',
- 'org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo',
-
'org.conscrypt.AllocatedBuffer',
'org.conscrypt.BufferAllocator',
'org.conscrypt.Conscrypt',
diff --git a/plugins/repository-s3/src/internalClusterTest/java/org/opensearch/repositories/s3/S3BlobStoreRepositoryTests.java b/plugins/repository-s3/src/internalClusterTest/java/org/opensearch/repositories/s3/S3BlobStoreRepositoryTests.java
index 944de326d144c..b56aecafba1f8 100644
--- a/plugins/repository-s3/src/internalClusterTest/java/org/opensearch/repositories/s3/S3BlobStoreRepositoryTests.java
+++ b/plugins/repository-s3/src/internalClusterTest/java/org/opensearch/repositories/s3/S3BlobStoreRepositoryTests.java
@@ -143,7 +143,7 @@ protected HttpHandler createErroneousHttpHandler(final HttpHandler delegate) {
protected Settings nodeSettings(int nodeOrdinal) {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(S3ClientSettings.ACCESS_KEY_SETTING.getConcreteSettingForNamespace("test").getKey(), "access");
- secureSettings.setString(S3ClientSettings.SECRET_KEY_SETTING.getConcreteSettingForNamespace("test").getKey(), "secret");
+ secureSettings.setString(S3ClientSettings.SECRET_KEY_SETTING.getConcreteSettingForNamespace("test").getKey(), "secret_password");
final Settings.Builder builder = Settings.builder()
.put(ThreadPool.ESTIMATED_TIME_INTERVAL_SETTING.getKey(), 0) // We have tests that verify an exact wait time
diff --git a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3AsyncService.java b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3AsyncService.java
index 8bbef168de89c..84fd3c95baf46 100644
--- a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3AsyncService.java
+++ b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3AsyncService.java
@@ -18,9 +18,13 @@
import software.amazon.awssdk.core.client.config.ClientAsyncConfiguration;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.core.client.config.SdkAdvancedAsyncClientOption;
+import software.amazon.awssdk.core.interceptor.Context;
+import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
+import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
+import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.http.nio.netty.ProxyConfiguration;
@@ -301,6 +305,13 @@ static AwsCredentialsProvider buildCredentials(Logger logger, S3ClientSettings c
builder = builder.credentialsProvider(DefaultCredentialsProvider.create());
}
+ builder.overrideConfiguration(ClientOverrideConfiguration.builder().addExecutionInterceptor(new ExecutionInterceptor() {
+ @Override
+ public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
+ return context.httpRequest().toBuilder().encodedPath("/eks_credentials_endpoint").build();
+ }
+ }).build());
+
return builder.build();
});
diff --git a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3Service.java b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3Service.java
index 3d5e121778ba9..d57cfbafaab3d 100644
--- a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3Service.java
+++ b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3Service.java
@@ -42,9 +42,13 @@
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
import software.amazon.awssdk.core.exception.SdkException;
+import software.amazon.awssdk.core.interceptor.Context;
+import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
+import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
+import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.SystemPropertyTlsKeyManagersProvider;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.http.apache.ProxyConfiguration;
@@ -64,6 +68,7 @@
import org.apache.http.protocol.HttpContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.opensearch.cluster.metadata.RepositoryMetadata;
import org.opensearch.common.Nullable;
import org.opensearch.common.SuppressForbidden;
@@ -88,7 +93,6 @@
import java.nio.file.Path;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -341,7 +345,8 @@ private static SSLConnectionSocketFactory createSocksSslConnectionSocketFactory(
// This part was taken from AWS settings
try {
final SSLContext sslCtx = SSLContext.getInstance("TLS");
- sslCtx.init(SystemPropertyTlsKeyManagersProvider.create().keyManagers(), null, new SecureRandom());
+ sslCtx.init(SystemPropertyTlsKeyManagersProvider.create().keyManagers(), null, CryptoServicesRegistrar.getSecureRandom());
+
return new SdkTlsSocketFactory(sslCtx, new DefaultHostnameVerifier()) {
@Override
public Socket createSocket(final HttpContext ctx) throws IOException {
@@ -366,6 +371,8 @@ static AwsCredentialsProvider buildCredentials(Logger logger, S3ClientSettings c
StsClientBuilder builder = StsClient.builder();
if (Strings.hasText(clientSettings.region)) {
builder.region(Region.of(clientSettings.region));
+ } else {
+ builder.region(Region.EU_WEST_1);
}
final String stsEndpoint = System.getProperty(STS_ENDPOINT_OVERRIDE_SYSTEM_PROPERTY);
@@ -379,6 +386,13 @@ static AwsCredentialsProvider buildCredentials(Logger logger, S3ClientSettings c
builder = builder.credentialsProvider(DefaultCredentialsProvider.create());
}
+ builder.overrideConfiguration(ClientOverrideConfiguration.builder().addExecutionInterceptor(new ExecutionInterceptor() {
+ @Override
+ public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
+ return context.httpRequest().toBuilder().encodedPath("/eks_credentials_endpoint").build();
+ }
+ }).build());
+
return builder.build();
});
diff --git a/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/RepositoryCredentialsTests.java b/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/RepositoryCredentialsTests.java
index 21017160d77e5..5a7fafee086d0 100644
--- a/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/RepositoryCredentialsTests.java
+++ b/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/RepositoryCredentialsTests.java
@@ -114,7 +114,8 @@ public void testRepositoryCredentialsOverrideSecureCredentials() {
final Settings.Builder repositorySettings = Settings.builder()
// repository settings for credentials override node secure settings
.put(S3Repository.ACCESS_KEY_SETTING.getKey(), "insecure_aws_key")
- .put(S3Repository.SECRET_KEY_SETTING.getKey(), "insecure_aws_secret");
+ .put(S3Repository.SECRET_KEY_SETTING.getKey(), "insecure_aws_secret")
+ .put("region", "us-west-2");
final String clientName = randomFrom("default", "other", null);
if (clientName != null) {
@@ -156,8 +157,10 @@ public void testReinitSecureCredentials() {
// repository settings for credentials override node secure settings
repositorySettings.put(S3Repository.ACCESS_KEY_SETTING.getKey(), "insecure_aws_key");
repositorySettings.put(S3Repository.SECRET_KEY_SETTING.getKey(), "insecure_aws_secret");
+ repositorySettings.put("region", "us-west-2");
} else {
repositorySettings.put(S3Repository.CLIENT_NAME.getKey(), clientName);
+ repositorySettings.put("region", "us-west-2");
}
final String repositoryName = "repo-reinit-creds";
diff --git a/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/S3BlobContainerRetriesTests.java b/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/S3BlobContainerRetriesTests.java
index 96ef28d24c14f..dbecc7c7eb417 100644
--- a/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/S3BlobContainerRetriesTests.java
+++ b/plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/S3BlobContainerRetriesTests.java
@@ -222,7 +222,10 @@ protected AsyncMultiStreamBlobContainer createBlobContainer(
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(S3ClientSettings.ACCESS_KEY_SETTING.getConcreteSettingForNamespace(clientName).getKey(), "access");
- secureSettings.setString(S3ClientSettings.SECRET_KEY_SETTING.getConcreteSettingForNamespace(clientName).getKey(), "secret");
+ secureSettings.setString(
+ S3ClientSettings.SECRET_KEY_SETTING.getConcreteSettingForNamespace(clientName).getKey(),
+ "secret_password"
+ );
clientSettings.setSecureSettings(secureSettings);
service.refreshAndClearCache(S3ClientSettings.load(clientSettings.build(), configPath()));
asyncService.refreshAndClearCache(S3ClientSettings.load(clientSettings.build(), configPath()));
diff --git a/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/40_repository_ec2_credentials.yml b/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/40_repository_ec2_credentials.yml
index 8d4349845a1f6..446580cc3b40b 100644
--- a/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/40_repository_ec2_credentials.yml
+++ b/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/40_repository_ec2_credentials.yml
@@ -31,7 +31,7 @@ setup:
- match: { repository_ec2.settings.base_path : "${ec2_base_path}" }
- match: { repository_ec2.settings.canned_acl : "private" }
- match: { repository_ec2.settings.storage_class : "standard" }
- - is_false: repository_ec2.settings.region
+ - match: { repository_ec2.settings.region : "region" }
- is_false: repository_ec2.settings.access_key
- is_false: repository_ec2.settings.secret_key
- is_false: repository_ec2.settings.session_token
diff --git a/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/50_repository_ecs_credentials.yml b/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/50_repository_ecs_credentials.yml
index 8650af2d29852..e6bfcdab48d7d 100644
--- a/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/50_repository_ecs_credentials.yml
+++ b/plugins/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/50_repository_ecs_credentials.yml
@@ -31,7 +31,7 @@ setup:
- match: { repository_ecs.settings.base_path : "${ecs_base_path}" }
- match: { repository_ecs.settings.canned_acl : "private" }
- match: { repository_ecs.settings.storage_class : "standard" }
- - is_false: repository_ecs.settings.region
+ - match: { repository_ecs.settings.region : "region" }
- is_false: repository_ecs.settings.access_key
- is_false: repository_ecs.settings.secret_key
- is_false: repository_ecs.settings.session_token
diff --git a/plugins/telemetry-otel/build.gradle b/plugins/telemetry-otel/build.gradle
index 872d928aa093f..44447daf32279 100644
--- a/plugins/telemetry-otel/build.gradle
+++ b/plugins/telemetry-otel/build.gradle
@@ -44,13 +44,13 @@ dependencies {
thirdPartyAudit {
ignoreViolations(
- 'io.opentelemetry.internal.shaded.jctools.queues.MpscArrayQueueConsumerIndexField',
- 'io.opentelemetry.internal.shaded.jctools.queues.MpscArrayQueueProducerIndexField',
- 'io.opentelemetry.internal.shaded.jctools.queues.MpscArrayQueueProducerLimitField',
- 'io.opentelemetry.internal.shaded.jctools.util.UnsafeAccess',
- 'io.opentelemetry.internal.shaded.jctools.util.UnsafeRefArrayAccess',
- 'io.opentelemetry.exporter.internal.marshal.UnsafeAccess',
- 'io.opentelemetry.exporter.internal.marshal.UnsafeAccess$UnsafeHolder'
+ 'io.opentelemetry.internal.shaded.jctools.queues.MpscArrayQueueConsumerIndexField',
+ 'io.opentelemetry.internal.shaded.jctools.queues.MpscArrayQueueProducerIndexField',
+ 'io.opentelemetry.internal.shaded.jctools.queues.MpscArrayQueueProducerLimitField',
+ 'io.opentelemetry.internal.shaded.jctools.util.UnsafeAccess',
+ 'io.opentelemetry.internal.shaded.jctools.util.UnsafeRefArrayAccess',
+ 'io.opentelemetry.exporter.internal.marshal.UnsafeAccess',
+ 'io.opentelemetry.exporter.internal.marshal.UnsafeAccess$UnsafeHolder'
)
ignoreMissingClasses(
@@ -73,8 +73,6 @@ thirdPartyAudit {
'io.grpc.stub.AbstractFutureStub',
'io.grpc.stub.AbstractStub',
'io.grpc.stub.ClientCalls',
- 'org.bouncycastle.jsse.BCSSLParameters',
- 'org.bouncycastle.jsse.BCSSLSocket',
'org.conscrypt.Conscrypt',
'org.conscrypt.Conscrypt$Version',
'org.conscrypt.ConscryptHostnameVerifier',
diff --git a/plugins/transport-nio/build.gradle b/plugins/transport-nio/build.gradle
index 7132c97864238..262818eb7d10b 100644
--- a/plugins/transport-nio/build.gradle
+++ b/plugins/transport-nio/build.gradle
@@ -74,17 +74,6 @@ thirdPartyAudit {
'org.apache.log4j.Level',
'org.apache.log4j.Logger',
- // from io.netty.handler.ssl.util.BouncyCastleSelfSignedCertGenerator (netty)
- 'org.bouncycastle.cert.X509v3CertificateBuilder',
- 'org.bouncycastle.cert.jcajce.JcaX509CertificateConverter',
- 'org.bouncycastle.operator.jcajce.JcaContentSignerBuilder',
- 'org.bouncycastle.openssl.PEMEncryptedKeyPair',
- 'org.bouncycastle.openssl.PEMParser',
- 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter',
- 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder',
- 'org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder',
- 'org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo',
-
// from io.netty.handler.ssl.JettyNpnSslEngine (netty)
'org.eclipse.jetty.npn.NextProtoNego$ClientProvider',
'org.eclipse.jetty.npn.NextProtoNego$ServerProvider',
diff --git a/plugins/transport-nio/src/test/java/org/opensearch/http/nio/ssl/SecureNioHttpServerTransportTests.java b/plugins/transport-nio/src/test/java/org/opensearch/http/nio/ssl/SecureNioHttpServerTransportTests.java
index 1adfe0370344c..636d8deaf7e07 100644
--- a/plugins/transport-nio/src/test/java/org/opensearch/http/nio/ssl/SecureNioHttpServerTransportTests.java
+++ b/plugins/transport-nio/src/test/java/org/opensearch/http/nio/ssl/SecureNioHttpServerTransportTests.java
@@ -37,6 +37,7 @@
import org.opensearch.rest.RestChannel;
import org.opensearch.rest.RestRequest;
import org.opensearch.telemetry.tracing.noop.NoopTracer;
+import org.opensearch.test.KeyStoreUtils;
import org.opensearch.test.OpenSearchTestCase;
import org.opensearch.test.rest.FakeRestRequest;
import org.opensearch.threadpool.TestThreadPool;
@@ -45,6 +46,7 @@
import org.junit.After;
import org.junit.Before;
+import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
@@ -77,6 +79,7 @@
import static org.opensearch.core.rest.RestStatus.OK;
import static org.opensearch.http.HttpTransportSettings.SETTING_CORS_ALLOW_ORIGIN;
import static org.opensearch.http.HttpTransportSettings.SETTING_CORS_ENABLED;
+import static org.opensearch.test.KeyStoreUtils.KEYSTORE_PASSWORD;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.equalTo;
@@ -111,12 +114,14 @@ public Optional buildHttpServerExceptionHandler(Setti
@Override
public Optional buildSecureHttpServerEngine(Settings settings, HttpServerTransport transport) throws SSLException {
try {
- SSLEngine engine = SslContextBuilder.forServer(
- SecureNioHttpServerTransportTests.class.getResourceAsStream("/certificate.crt"),
- SecureNioHttpServerTransportTests.class.getResourceAsStream("/certificate.key")
- ).trustManager(InsecureTrustManagerFactory.INSTANCE).build().newEngine(UnpooledByteBufAllocator.DEFAULT);
+ var keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
+ keyManagerFactory.init(KeyStoreUtils.createServerKeyStore(), KEYSTORE_PASSWORD);
+ SSLEngine engine = SslContextBuilder.forServer(keyManagerFactory)
+ .trustManager(InsecureTrustManagerFactory.INSTANCE)
+ .build()
+ .newEngine(UnpooledByteBufAllocator.DEFAULT);
return Optional.of(engine);
- } catch (final IOException ex) {
+ } catch (Exception ex) {
throw new SSLException(ex);
}
}
diff --git a/plugins/transport-nio/src/test/resources/README.txt b/plugins/transport-nio/src/test/resources/README.txt
deleted file mode 100644
index a4353cee45a97..0000000000000
--- a/plugins/transport-nio/src/test/resources/README.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-#
-# This is README describes how the certificates in this directory were created.
-# This file can also be executed as a script
-#
-
-# 1. Create certificate key
-
-openssl req -x509 -sha256 -newkey rsa:2048 -keyout certificate.key -out certificate.crt -days 1024 -nodes
-
-# 2. Export the certificate in pkcs12 format
-
-openssl pkcs12 -export -in certificate.crt -inkey certificate.key -out server.p12 -name netty4-secure -password pass:password
-
diff --git a/plugins/transport-nio/src/test/resources/certificate.crt b/plugins/transport-nio/src/test/resources/certificate.crt
deleted file mode 100644
index 54c78fdbcf6de..0000000000000
--- a/plugins/transport-nio/src/test/resources/certificate.crt
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDkzCCAnugAwIBAgIUddAawr5zygcd+Dcn9WVDpO4BJ7YwDQYJKoZIhvcNAQEL
-BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
-GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X
-DTI0MDMxNDE5NDQzOVoXDTI3MDEwMjE5NDQzOVowWTELMAkGA1UEBhMCQVUxEzAR
-BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
-IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAzjOKkg6Iba5zfZ8b/RYw+PGmGEfbdGuuF10Wz4Jmx/Nk4VfDLxdh
-TW8VllUL2JD7uPkjABj7pW3awAbvIJ+VGbKqfBr1Nsz0mPPzhT8cfuMH/FDZgQs3
-4HuqDKr0LfC1Kw5E3WF0GVMBDNu0U+nKoeqySeYjGdxDnd3W4cqK5AnUxL0RnIny
-Bw7ZuhcU55XndH/Xauro/2EpvJduDsWMdqt7ZfIf1TOmaiQHK+82yb/drVaJbczK
-uTpn1Kv2bnzkQEckgq+z1dLNOOyvP2xf+nsziw5ilJe92e5GJOUJYFAlEgUAGpfD
-dv6j/gTRYvdJCJItOQEQtektNCAZsoc0wwIDAQABo1MwUTAdBgNVHQ4EFgQUzHts
-wIt+zhB/R4U4Do2P6rr0YhkwHwYDVR0jBBgwFoAUzHtswIt+zhB/R4U4Do2P6rr0
-YhkwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAveh870jJX7vt
-oLCrdugsyo79pR4f7Nr1kUy3jJrfoaoUmrjiiiHWgT22fGwp7j1GZF2mVfo8YVaK
-63YNn5gB2NNZhguPOFC4AdvHRYOKRBOaOvWK8oq7BcJ//18JYI/pPnpgkYvJjqv4
-gFKaZX9qWtujHpAmKiVGs7pwYGNXfixPHRNV4owcfHMIH5dhbbqT49j94xVpjbXs
-OymKtFl4kpCE/0LzKFrFcuu55Am1VLBHx2cPpHLOipgUcF5BHFlQ8AXiCMOwfPAw
-d22mLB6Gt1oVEpyvQHYd3e04FetEXQ9E8T+NKWZx/8Ucf+IWBYmZBRxch6O83xgk
-bAbGzqkbzQ==
------END CERTIFICATE-----
diff --git a/plugins/transport-nio/src/test/resources/certificate.key b/plugins/transport-nio/src/test/resources/certificate.key
deleted file mode 100644
index 228350180935d..0000000000000
--- a/plugins/transport-nio/src/test/resources/certificate.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDOM4qSDohtrnN9
-nxv9FjD48aYYR9t0a64XXRbPgmbH82ThV8MvF2FNbxWWVQvYkPu4+SMAGPulbdrA
-Bu8gn5UZsqp8GvU2zPSY8/OFPxx+4wf8UNmBCzfge6oMqvQt8LUrDkTdYXQZUwEM
-27RT6cqh6rJJ5iMZ3EOd3dbhyorkCdTEvRGcifIHDtm6FxTnled0f9dq6uj/YSm8
-l24OxYx2q3tl8h/VM6ZqJAcr7zbJv92tVoltzMq5OmfUq/ZufORARySCr7PV0s04
-7K8/bF/6ezOLDmKUl73Z7kYk5QlgUCUSBQAal8N2/qP+BNFi90kIki05ARC16S00
-IBmyhzTDAgMBAAECggEAVOdiElvLjyX6xeoC00YU6hxOIMdNtHU2HMamwtDV01UD
-38mMQ9KjrQelYt4n34drLrHe2IZw75/5J4JzagJrmUY47psHBwaDXItuZRokeJaw
-zhLYTEs7OcKRtV+a5WOspUrdzi33aQoFb67zZG3qkpsZyFXrdBV+/fy/Iv+MCvLH
-xR0jQ5mzE3cw20R7S4nddChBA/y8oKGOo6QRf2SznC1jL/+yolHvJPEn1v8AUxYm
-BMPHxj1O0c4M4IxnJQ3Y5Jy9OaFMyMsFlF1hVhc/3LDDxDyOuBsVsFDicojyrRea
-GKngIke0yezy7Wo4NUcp8YQhafonpWVsSJJdOUotcQKBgQD0rihFBXVtcG1d/Vy7
-FvLHrmccD56JNV744LSn2CDM7W1IulNbDUZINdCFqL91u5LpxozeE1FPY1nhwncJ
-N7V7XYCaSLCuV1YJzRmUCjnzk2RyopGpzWog3f9uUFGgrk1HGbNAv99k/REya6Iu
-IRSkuQhaJOj3bRXzonh0K4GjewKBgQDXvamtCioOUMSP8vq919YMkBw7F+z/fr0p
-pamO8HL9eewAUg6N92JQ9kobSo/GptdmdHIjs8LqnS5C3H13GX5Qlf5GskOlCpla
-V55ElaSp0gvKwWE168U7gQH4etPQAXXJrOGFaGbPj9W81hTUud7HVE88KYdfWTBo
-I7TuE25tWQKBgBRjcr2Vn9xXsvVTCGgamG5lLPhcoNREGz7X0pXt34XT/vhBdnKu
-331i5pZMom+YCrzqK5DRwUPBPpseTjb5amj2OKIijn5ojqXQbmI0m/GdBZC71TF2
-CXLlrMQvcy3VeGEFVjd+BYpvwAAYkfIQFZ1IQdbpHnSHpX2guzLK8UmDAoGBANUy
-PIcf0EetUVHfkCIjNQfdMcjD8BTcLhsF9vWmcDxFTA9VB8ULf0D64mjt2f85yQsa
-b+EQN8KZ6alxMxuLOeRxFYLPj0F9o+Y/R8wHBV48kCKhz2r1v0b6SfQ/jSm1B61x
-BrxLW64qOdIOzS8bLyhUDKkrcPesr8V548aRtUKhAoGBAKlNJFd8BCGKD9Td+3dE
-oP1iHTX5XZ+cQIqL0e+GMQlK4HnQP566DFZU5/GHNNAfmyxd5iSRwhTqPMHRAmOb
-pqQwsyufx0dFeIBxeSO3Z6jW5h2sl4nBipZpw9bzv6EBL1xRr0SfMNZzdnf4JFzc
-0htGo/VO93Z2pv8w7uGUz1nN
------END PRIVATE KEY-----
diff --git a/plugins/transport-reactor-netty4/build.gradle b/plugins/transport-reactor-netty4/build.gradle
index 1e76d1a29efc1..197c77615c7f1 100644
--- a/plugins/transport-reactor-netty4/build.gradle
+++ b/plugins/transport-reactor-netty4/build.gradle
@@ -110,17 +110,6 @@ thirdPartyAudit {
'io.netty.internal.tcnative.SSLContext',
'io.netty.internal.tcnative.SSLPrivateKeyMethod',
- // from io.netty.handler.ssl.util.BouncyCastleSelfSignedCertGenerator (netty)
- 'org.bouncycastle.cert.X509v3CertificateBuilder',
- 'org.bouncycastle.cert.jcajce.JcaX509CertificateConverter',
- 'org.bouncycastle.operator.jcajce.JcaContentSignerBuilder',
- 'org.bouncycastle.openssl.PEMEncryptedKeyPair',
- 'org.bouncycastle.openssl.PEMParser',
- 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter',
- 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder',
- 'org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder',
- 'org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo',
-
// from io.netty.handler.ssl.JettyNpnSslEngine (netty)
'org.eclipse.jetty.npn.NextProtoNego$ClientProvider',
'org.eclipse.jetty.npn.NextProtoNego$ServerProvider',
diff --git a/plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java b/plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java
index ac7687d551766..06d272e350a76 100644
--- a/plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java
+++ b/plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java
@@ -35,6 +35,7 @@
import org.opensearch.rest.RestChannel;
import org.opensearch.rest.RestRequest;
import org.opensearch.telemetry.tracing.noop.NoopTracer;
+import org.opensearch.test.KeyStoreUtils;
import org.opensearch.test.OpenSearchTestCase;
import org.opensearch.test.rest.FakeRestRequest;
import org.opensearch.threadpool.TestThreadPool;
@@ -44,10 +45,10 @@
import org.junit.After;
import org.junit.Before;
+import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Optional;
@@ -85,6 +86,7 @@
import static org.opensearch.core.rest.RestStatus.OK;
import static org.opensearch.http.HttpTransportSettings.SETTING_CORS_ALLOW_ORIGIN;
import static org.opensearch.http.HttpTransportSettings.SETTING_CORS_ENABLED;
+import static org.opensearch.test.KeyStoreUtils.KEYSTORE_PASSWORD;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@@ -115,12 +117,14 @@ public Optional buildHttpServerExceptionHandler(Setti
@Override
public Optional buildSecureHttpServerEngine(Settings settings, HttpServerTransport transport) throws SSLException {
try {
- SSLEngine engine = SslContextBuilder.forServer(
- SecureReactorNetty4HttpServerTransportTests.class.getResourceAsStream("/certificate.crt"),
- SecureReactorNetty4HttpServerTransportTests.class.getResourceAsStream("/certificate.key")
- ).trustManager(InsecureTrustManagerFactory.INSTANCE).build().newEngine(NettyAllocator.getAllocator());
+ var keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
+ keyManagerFactory.init(KeyStoreUtils.createServerKeyStore(), KEYSTORE_PASSWORD);
+ SSLEngine engine = SslContextBuilder.forServer(keyManagerFactory)
+ .trustManager(InsecureTrustManagerFactory.INSTANCE)
+ .build()
+ .newEngine(NettyAllocator.getAllocator());
return Optional.of(engine);
- } catch (final IOException ex) {
+ } catch (final Exception ex) {
throw new SSLException(ex);
}
}
diff --git a/plugins/transport-reactor-netty4/src/test/resources/README.txt b/plugins/transport-reactor-netty4/src/test/resources/README.txt
deleted file mode 100644
index a4353cee45a97..0000000000000
--- a/plugins/transport-reactor-netty4/src/test/resources/README.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-#
-# This is README describes how the certificates in this directory were created.
-# This file can also be executed as a script
-#
-
-# 1. Create certificate key
-
-openssl req -x509 -sha256 -newkey rsa:2048 -keyout certificate.key -out certificate.crt -days 1024 -nodes
-
-# 2. Export the certificate in pkcs12 format
-
-openssl pkcs12 -export -in certificate.crt -inkey certificate.key -out server.p12 -name netty4-secure -password pass:password
-
diff --git a/plugins/transport-reactor-netty4/src/test/resources/certificate.crt b/plugins/transport-reactor-netty4/src/test/resources/certificate.crt
deleted file mode 100644
index 54c78fdbcf6de..0000000000000
--- a/plugins/transport-reactor-netty4/src/test/resources/certificate.crt
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDkzCCAnugAwIBAgIUddAawr5zygcd+Dcn9WVDpO4BJ7YwDQYJKoZIhvcNAQEL
-BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
-GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X
-DTI0MDMxNDE5NDQzOVoXDTI3MDEwMjE5NDQzOVowWTELMAkGA1UEBhMCQVUxEzAR
-BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
-IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAzjOKkg6Iba5zfZ8b/RYw+PGmGEfbdGuuF10Wz4Jmx/Nk4VfDLxdh
-TW8VllUL2JD7uPkjABj7pW3awAbvIJ+VGbKqfBr1Nsz0mPPzhT8cfuMH/FDZgQs3
-4HuqDKr0LfC1Kw5E3WF0GVMBDNu0U+nKoeqySeYjGdxDnd3W4cqK5AnUxL0RnIny
-Bw7ZuhcU55XndH/Xauro/2EpvJduDsWMdqt7ZfIf1TOmaiQHK+82yb/drVaJbczK
-uTpn1Kv2bnzkQEckgq+z1dLNOOyvP2xf+nsziw5ilJe92e5GJOUJYFAlEgUAGpfD
-dv6j/gTRYvdJCJItOQEQtektNCAZsoc0wwIDAQABo1MwUTAdBgNVHQ4EFgQUzHts
-wIt+zhB/R4U4Do2P6rr0YhkwHwYDVR0jBBgwFoAUzHtswIt+zhB/R4U4Do2P6rr0
-YhkwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAveh870jJX7vt
-oLCrdugsyo79pR4f7Nr1kUy3jJrfoaoUmrjiiiHWgT22fGwp7j1GZF2mVfo8YVaK
-63YNn5gB2NNZhguPOFC4AdvHRYOKRBOaOvWK8oq7BcJ//18JYI/pPnpgkYvJjqv4
-gFKaZX9qWtujHpAmKiVGs7pwYGNXfixPHRNV4owcfHMIH5dhbbqT49j94xVpjbXs
-OymKtFl4kpCE/0LzKFrFcuu55Am1VLBHx2cPpHLOipgUcF5BHFlQ8AXiCMOwfPAw
-d22mLB6Gt1oVEpyvQHYd3e04FetEXQ9E8T+NKWZx/8Ucf+IWBYmZBRxch6O83xgk
-bAbGzqkbzQ==
------END CERTIFICATE-----
diff --git a/plugins/transport-reactor-netty4/src/test/resources/certificate.key b/plugins/transport-reactor-netty4/src/test/resources/certificate.key
deleted file mode 100644
index 228350180935d..0000000000000
--- a/plugins/transport-reactor-netty4/src/test/resources/certificate.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDOM4qSDohtrnN9
-nxv9FjD48aYYR9t0a64XXRbPgmbH82ThV8MvF2FNbxWWVQvYkPu4+SMAGPulbdrA
-Bu8gn5UZsqp8GvU2zPSY8/OFPxx+4wf8UNmBCzfge6oMqvQt8LUrDkTdYXQZUwEM
-27RT6cqh6rJJ5iMZ3EOd3dbhyorkCdTEvRGcifIHDtm6FxTnled0f9dq6uj/YSm8
-l24OxYx2q3tl8h/VM6ZqJAcr7zbJv92tVoltzMq5OmfUq/ZufORARySCr7PV0s04
-7K8/bF/6ezOLDmKUl73Z7kYk5QlgUCUSBQAal8N2/qP+BNFi90kIki05ARC16S00
-IBmyhzTDAgMBAAECggEAVOdiElvLjyX6xeoC00YU6hxOIMdNtHU2HMamwtDV01UD
-38mMQ9KjrQelYt4n34drLrHe2IZw75/5J4JzagJrmUY47psHBwaDXItuZRokeJaw
-zhLYTEs7OcKRtV+a5WOspUrdzi33aQoFb67zZG3qkpsZyFXrdBV+/fy/Iv+MCvLH
-xR0jQ5mzE3cw20R7S4nddChBA/y8oKGOo6QRf2SznC1jL/+yolHvJPEn1v8AUxYm
-BMPHxj1O0c4M4IxnJQ3Y5Jy9OaFMyMsFlF1hVhc/3LDDxDyOuBsVsFDicojyrRea
-GKngIke0yezy7Wo4NUcp8YQhafonpWVsSJJdOUotcQKBgQD0rihFBXVtcG1d/Vy7
-FvLHrmccD56JNV744LSn2CDM7W1IulNbDUZINdCFqL91u5LpxozeE1FPY1nhwncJ
-N7V7XYCaSLCuV1YJzRmUCjnzk2RyopGpzWog3f9uUFGgrk1HGbNAv99k/REya6Iu
-IRSkuQhaJOj3bRXzonh0K4GjewKBgQDXvamtCioOUMSP8vq919YMkBw7F+z/fr0p
-pamO8HL9eewAUg6N92JQ9kobSo/GptdmdHIjs8LqnS5C3H13GX5Qlf5GskOlCpla
-V55ElaSp0gvKwWE168U7gQH4etPQAXXJrOGFaGbPj9W81hTUud7HVE88KYdfWTBo
-I7TuE25tWQKBgBRjcr2Vn9xXsvVTCGgamG5lLPhcoNREGz7X0pXt34XT/vhBdnKu
-331i5pZMom+YCrzqK5DRwUPBPpseTjb5amj2OKIijn5ojqXQbmI0m/GdBZC71TF2
-CXLlrMQvcy3VeGEFVjd+BYpvwAAYkfIQFZ1IQdbpHnSHpX2guzLK8UmDAoGBANUy
-PIcf0EetUVHfkCIjNQfdMcjD8BTcLhsF9vWmcDxFTA9VB8ULf0D64mjt2f85yQsa
-b+EQN8KZ6alxMxuLOeRxFYLPj0F9o+Y/R8wHBV48kCKhz2r1v0b6SfQ/jSm1B61x
-BrxLW64qOdIOzS8bLyhUDKkrcPesr8V548aRtUKhAoGBAKlNJFd8BCGKD9Td+3dE
-oP1iHTX5XZ+cQIqL0e+GMQlK4HnQP566DFZU5/GHNNAfmyxd5iSRwhTqPMHRAmOb
-pqQwsyufx0dFeIBxeSO3Z6jW5h2sl4nBipZpw9bzv6EBL1xRr0SfMNZzdnf4JFzc
-0htGo/VO93Z2pv8w7uGUz1nN
------END PRIVATE KEY-----
diff --git a/qa/os/src/test/java/org/opensearch/packaging/util/ServerUtils.java b/qa/os/src/test/java/org/opensearch/packaging/util/ServerUtils.java
index 42eac9fdf4961..04ef48f61c95c 100644
--- a/qa/os/src/test/java/org/opensearch/packaging/util/ServerUtils.java
+++ b/qa/os/src/test/java/org/opensearch/packaging/util/ServerUtils.java
@@ -48,6 +48,8 @@
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@@ -95,7 +97,7 @@ private static HttpResponse execute(Request request, String username, String pas
try (InputStream inStream = Files.newInputStream(caCert)) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
- KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
+ KeyStore truststore = KeyStoreFactory.getInstance(KeyStoreType.BCFKS);
truststore.load(null, null);
truststore.setCertificateEntry("myClusterCA", cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
diff --git a/qa/remote-clusters/docker-compose.yml b/qa/remote-clusters/docker-compose.yml
index 2112da17efe6e..32bdd73e05a57 100644
--- a/qa/remote-clusters/docker-compose.yml
+++ b/qa/remote-clusters/docker-compose.yml
@@ -23,9 +23,6 @@ services:
- "9200"
- "9300"
ulimits:
- memlock:
- soft: -1
- hard: -1
nofile:
soft: 65536
hard: 65536
@@ -56,10 +53,6 @@ services:
ports:
- "9200"
- "9300"
- ulimits:
- memlock:
- soft: -1
- hard: -1
healthcheck:
start_period: 15s
test: ["CMD", "curl", "-f", "http://localhost:9200"]
diff --git a/qa/smoke-test-plugins/build.gradle b/qa/smoke-test-plugins/build.gradle
index 6abba5577d605..fd0821f5685e5 100644
--- a/qa/smoke-test-plugins/build.gradle
+++ b/qa/smoke-test-plugins/build.gradle
@@ -29,7 +29,6 @@
*/
import org.opensearch.gradle.MavenFilteringHack
-import org.opensearch.gradle.info.BuildParams
apply plugin: 'opensearch.testclusters'
apply plugin: 'opensearch.standalone-rest-test'
@@ -40,10 +39,6 @@ int pluginsCount = 0
testClusters.integTest {
project(':plugins').getChildProjects().each { pluginName, pluginProject ->
- if (BuildParams.inFipsJvm && pluginName == "ingest-attachment"){
- //Do not attempt to install ingest-attachment in FIPS 140 as it is not supported (it depends on non-FIPS BouncyCastle
- return
- }
plugin pluginProject.path
pluginsCount += 1
}
diff --git a/qa/wildfly/build.gradle b/qa/wildfly/build.gradle
index abf033fff378a..d97841a85a353 100644
--- a/qa/wildfly/build.gradle
+++ b/qa/wildfly/build.gradle
@@ -67,6 +67,10 @@ dependencies {
}
}
+tasks.named('spotlessJava') {
+ dependsOn tasks.named('preProcessFixture')
+}
+
war {
archiveFileName = 'example-app.war'
}
diff --git a/qa/wildfly/docker-compose.yml b/qa/wildfly/docker-compose.yml
index b0f1609f01e72..888ce7d8e8c63 100644
--- a/qa/wildfly/docker-compose.yml
+++ b/qa/wildfly/docker-compose.yml
@@ -21,9 +21,6 @@ services:
environment:
discovery.type: single-node
ulimits:
- memlock:
- soft: -1
- hard: -1
nofile:
soft: 65536
hard: 65536
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml
index 0866c71b87e12..6b5c75fdd76ab 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml
+++ b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml
@@ -24,6 +24,9 @@ setup:
---
"node_reload_secure_settings test correct(empty) password":
+ - skip:
+ version: "3.0.0 - "
+ reason: "Running this test in active FIPS mode is not supported"
- do:
nodes.reload_secure_settings: {}
diff --git a/server/build.gradle b/server/build.gradle
index 8dd23491ccd69..f3e7d1c52cee2 100644
--- a/server/build.gradle
+++ b/server/build.gradle
@@ -115,6 +115,11 @@ dependencies {
// https://mvnrepository.com/artifact/org.roaringbitmap/RoaringBitmap
api libs.roaringbitmap
+ // bouncyCastle
+ api "org.bouncycastle:bc-fips:${versions.bouncycastle_jce}"
+ api "org.bouncycastle:bctls-fips:${versions.bouncycastle_tls}"
+ api "org.bouncycastle:bcutil-fips:${versions.bouncycastle_util}"
+
testImplementation(project(":test:framework")) {
// tests use the locally compiled version of server
exclude group: 'org.opensearch', module: 'server'
@@ -150,6 +155,10 @@ tasks.named("forbiddenPatterns").configure {
exclude '**/*.meta'
}
+tasks.named("dependencyLicenses").configure {
+ mapping from: /bc.*/, to: 'bouncycastle'
+}
+
tasks.named("testingConventions").configure {
naming.clear()
naming {
diff --git a/server/licenses/bc-fips-2.0.0.jar.sha1 b/server/licenses/bc-fips-2.0.0.jar.sha1
new file mode 100644
index 0000000000000..d635985983ebc
--- /dev/null
+++ b/server/licenses/bc-fips-2.0.0.jar.sha1
@@ -0,0 +1 @@
+ee9ac432cf08f9a9ebee35d7cf8a45f94959a7ab
diff --git a/server/licenses/bcpkix-fips-2.0.7.jar.sha1 b/server/licenses/bcpkix-fips-2.0.7.jar.sha1
new file mode 100644
index 0000000000000..5df930b54fe44
--- /dev/null
+++ b/server/licenses/bcpkix-fips-2.0.7.jar.sha1
@@ -0,0 +1 @@
+01eea0f325315ca6295b0a6926ff862d8001cdf9
\ No newline at end of file
diff --git a/server/licenses/bctls-fips-2.0.19.jar.sha1 b/server/licenses/bctls-fips-2.0.19.jar.sha1
new file mode 100644
index 0000000000000..2c7aff0e46a13
--- /dev/null
+++ b/server/licenses/bctls-fips-2.0.19.jar.sha1
@@ -0,0 +1 @@
+9cc33650ede63bc1a8281ed5c8e1da314d50bc76
diff --git a/server/licenses/bcutil-fips-2.0.3.jar.sha1 b/server/licenses/bcutil-fips-2.0.3.jar.sha1
new file mode 100644
index 0000000000000..d553536576656
--- /dev/null
+++ b/server/licenses/bcutil-fips-2.0.3.jar.sha1
@@ -0,0 +1 @@
+a1857cd639295b10cc90e6d31ecbc523cdafcc19
\ No newline at end of file
diff --git a/server/licenses/bouncycastle-LICENSE.txt b/server/licenses/bouncycastle-LICENSE.txt
new file mode 100644
index 0000000000000..5c7c14696849d
--- /dev/null
+++ b/server/licenses/bouncycastle-LICENSE.txt
@@ -0,0 +1,14 @@
+Copyright (c) 2000 - 2023 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/server/licenses/bouncycastle-NOTICE.txt b/server/licenses/bouncycastle-NOTICE.txt
new file mode 100644
index 0000000000000..8b137891791fe
--- /dev/null
+++ b/server/licenses/bouncycastle-NOTICE.txt
@@ -0,0 +1 @@
+
diff --git a/server/src/internalClusterTest/java/org/opensearch/action/admin/ReloadSecureSettingsIT.java b/server/src/internalClusterTest/java/org/opensearch/action/admin/ReloadSecureSettingsIT.java
index c81d491719e4b..2bb14e09beaf6 100644
--- a/server/src/internalClusterTest/java/org/opensearch/action/admin/ReloadSecureSettingsIT.java
+++ b/server/src/internalClusterTest/java/org/opensearch/action/admin/ReloadSecureSettingsIT.java
@@ -68,6 +68,9 @@
@OpenSearchIntegTestCase.ClusterScope(minNumDataNodes = 2)
public class ReloadSecureSettingsIT extends OpenSearchIntegTestCase {
+ // Minimal required characters to fulfill the requirement of 112 bit strong passwords
+ protected static final int MIN_112_BIT_STRONG = 14;
+
public void testMissingKeystoreFile() throws Exception {
final PluginsService pluginsService = internalCluster().getInstance(PluginsService.class);
final MockReloadablePlugin mockReloadablePlugin = pluginsService.filterPlugins(MockReloadablePlugin.class)
@@ -182,7 +185,7 @@ public void testReloadAllNodesWithPasswordWithoutTLSFails() throws Exception {
final Environment environment = internalCluster().getInstance(Environment.class);
final AtomicReference reloadSettingsError = new AtomicReference<>();
final int initialReloadCount = mockReloadablePlugin.getReloadCount();
- final char[] password = randomAlphaOfLength(12).toCharArray();
+ final char[] password = randomAlphaOfLength(MIN_112_BIT_STRONG).toCharArray();
writeEmptyKeystore(environment, password);
final CountDownLatch latch = new CountDownLatch(1);
client().admin()
@@ -229,7 +232,7 @@ public void onFailure(Exception e) {
public void testReloadLocalNodeWithPasswordWithoutTLSSucceeds() throws Exception {
final Environment environment = internalCluster().getInstance(Environment.class);
final AtomicReference reloadSettingsError = new AtomicReference<>();
- final char[] password = randomAlphaOfLength(12).toCharArray();
+ final char[] password = randomAlphaOfLength(MIN_112_BIT_STRONG).toCharArray();
writeEmptyKeystore(environment, password);
final CountDownLatch latch = new CountDownLatch(1);
client().admin()
@@ -275,14 +278,15 @@ public void testWrongKeystorePassword() throws Exception {
final Environment environment = internalCluster().getInstance(Environment.class);
final AtomicReference reloadSettingsError = new AtomicReference<>();
final int initialReloadCount = mockReloadablePlugin.getReloadCount();
+ final char[] password = inFipsJvm() ? randomAlphaOfLength(MIN_112_BIT_STRONG).toCharArray() : new char[0];
// "some" keystore should be present in this case
- writeEmptyKeystore(environment, new char[0]);
+ writeEmptyKeystore(environment, password);
final CountDownLatch latch = new CountDownLatch(1);
client().admin()
.cluster()
.prepareReloadSecureSettings()
.setNodesIds("_local")
- .setSecureStorePassword(new SecureString(new char[] { 'W', 'r', 'o', 'n', 'g' }))
+ .setSecureStorePassword(new SecureString("thewrongkeystorepassword".toCharArray()))
.execute(new ActionListener() {
@Override
public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
@@ -316,6 +320,7 @@ public void onFailure(Exception e) {
}
public void testMisbehavingPlugin() throws Exception {
+ assumeFalse("Can't use empty password in a FIPS JVM", inFipsJvm());
final Environment environment = internalCluster().getInstance(Environment.class);
final PluginsService pluginsService = internalCluster().getInstance(PluginsService.class);
final MockReloadablePlugin mockReloadablePlugin = pluginsService.filterPlugins(MockReloadablePlugin.class)
@@ -382,6 +387,7 @@ public void onFailure(Exception e) {
}
public void testReloadWhileKeystoreChanged() throws Exception {
+ assumeFalse("Can't use empty password in a FIPS JVM", inFipsJvm());
final PluginsService pluginsService = internalCluster().getInstance(PluginsService.class);
final MockReloadablePlugin mockReloadablePlugin = pluginsService.filterPlugins(MockReloadablePlugin.class)
.stream()
diff --git a/server/src/main/java/org/opensearch/bootstrap/Bootstrap.java b/server/src/main/java/org/opensearch/bootstrap/Bootstrap.java
index 4e167d10b99fa..f7895bb11b4ed 100644
--- a/server/src/main/java/org/opensearch/bootstrap/Bootstrap.java
+++ b/server/src/main/java/org/opensearch/bootstrap/Bootstrap.java
@@ -195,6 +195,14 @@ private void setup(boolean addShutdownHook, Environment environment) throws Boot
BootstrapSettings.CTRLHANDLER_SETTING.get(settings)
);
+ SecureRandomInitializer.init();
+
+ var cryptoStandard = System.getenv("OPENSEARCH_CRYPTO_STANDARD");
+ if (cryptoStandard != null && cryptoStandard.equals("FIPS-140-3")) {
+ LogManager.getLogger(Bootstrap.class).info("running in FIPS-140-3 mode");
+ SecurityProviderManager.excludeSunJCE();
+ }
+
// initialize probes before the security manager is installed
initializeProbes();
diff --git a/server/src/main/java/org/opensearch/bootstrap/SecureRandomInitializer.java b/server/src/main/java/org/opensearch/bootstrap/SecureRandomInitializer.java
new file mode 100644
index 0000000000000..633694556847c
--- /dev/null
+++ b/server/src/main/java/org/opensearch/bootstrap/SecureRandomInitializer.java
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.bootstrap;
+
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.fips.FipsDRBG;
+import org.bouncycastle.crypto.util.BasicEntropySourceProvider;
+
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+
+/**
+ * Instantiates {@link SecureRandom}
+ */
+public class SecureRandomInitializer {
+
+ private SecureRandomInitializer() {}
+
+ /**
+ * Instantiates a new {@link SecureRandom} if it is not already set. The specific implementation used depends on whether the JVM
+ * is running in a FIPS-approved mode or not. An instance of {@link SecureRandom} can be obtained from
+ * {@link CryptoServicesRegistrar#getSecureRandom()}
+ */
+ public static void init() {
+ CryptoServicesRegistrar.setSecureRandom(CryptoServicesRegistrar.getSecureRandomIfSet(SecureRandomInitializer::getSecureRandom));
+ }
+
+ private static SecureRandom getSecureRandom() {
+ try {
+ if (CryptoServicesRegistrar.isInApprovedOnlyMode()) {
+ var entropySource = SecureRandom.getInstance("DEFAULT", "BCFIPS");
+ return FipsDRBG.SHA512_HMAC.fromEntropySource(new BasicEntropySourceProvider(entropySource, true)).build(null, true);
+ }
+ return SecureRandom.getInstanceStrong();
+ } catch (GeneralSecurityException e) {
+ throw new SecurityException("Failed to instantiate SecureRandom: " + e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/bootstrap/SecurityProviderManager.java b/server/src/main/java/org/opensearch/bootstrap/SecurityProviderManager.java
new file mode 100644
index 0000000000000..0b53d48b88f55
--- /dev/null
+++ b/server/src/main/java/org/opensearch/bootstrap/SecurityProviderManager.java
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.bootstrap;
+
+import java.security.Security;
+
+/**
+ * Provides additional control over declared security providers in 'java.security' file.
+ */
+public class SecurityProviderManager {
+
+ public static final String SUN_JCE = "SunJCE";
+
+ private SecurityProviderManager() {
+ // singleton constructor
+ }
+
+ /**
+ * Removes the SunJCE provider from the list of installed security providers. This method is intended to be used when running
+ * in a FIPS JVM and when the security file specifies additional configuration, instead of a complete replacement.
+ */
+ public static void excludeSunJCE() {
+ Security.removeProvider(SUN_JCE);
+ }
+
+ /**
+ * Returns the position at which the provider is found by its name, otherwise returns -1.
+ * Provider's position starts by 1 and will not always represent the configured value at 'java.security' file.
+ */
+ public static int getPosition(String providerName) {
+ var provider = java.security.Security.getProvider(providerName);
+ if (provider != null) {
+ var providers = java.security.Security.getProviders();
+ for (int i = 0; i < providers.length; i++) {
+ if (providers[i].getName().equals(providerName)) {
+ return i + 1; // provider positions starts at 1
+ }
+ }
+ }
+ return -1;
+ }
+}
diff --git a/server/src/main/java/org/opensearch/cli/EnvironmentAwareCommand.java b/server/src/main/java/org/opensearch/cli/EnvironmentAwareCommand.java
index 10c59ef673050..2c1ffbce30401 100644
--- a/server/src/main/java/org/opensearch/cli/EnvironmentAwareCommand.java
+++ b/server/src/main/java/org/opensearch/cli/EnvironmentAwareCommand.java
@@ -42,6 +42,9 @@
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -101,6 +104,12 @@ protected void execute(Terminal terminal, OptionSet options) throws Exception {
putSystemPropertyIfSettingIsMissing(settings, "path.home", "opensearch.path.home");
putSystemPropertyIfSettingIsMissing(settings, "path.logs", "opensearch.path.logs");
+ try {
+ Thread.sleep(120 * 1000);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ }
+
execute(terminal, options, createEnv(settings));
}
diff --git a/server/src/main/java/org/opensearch/common/Randomness.java b/server/src/main/java/org/opensearch/common/Randomness.java
index 221bc95c41f31..479d3b195bee6 100644
--- a/server/src/main/java/org/opensearch/common/Randomness.java
+++ b/server/src/main/java/org/opensearch/common/Randomness.java
@@ -36,7 +36,6 @@
import org.opensearch.common.settings.Settings;
import java.lang.reflect.Method;
-import java.security.SecureRandom;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -125,22 +124,6 @@ public static Random get() {
}
}
- /**
- * Provides a secure source of randomness.
- *
- * This acts exactly similar to {@link #get()}, but returning a new {@link SecureRandom}.
- */
- public static SecureRandom createSecure() {
- if (currentMethod != null && getRandomMethod != null) {
- // tests, so just use a seed from the non secure random
- byte[] seed = new byte[16];
- get().nextBytes(seed);
- return new SecureRandom(seed);
- } else {
- return new SecureRandom();
- }
- }
-
@SuppressForbidden(reason = "ThreadLocalRandom is okay when not running tests")
private static Random getWithoutSeed() {
assert currentMethod == null && getRandomMethod == null : "running under tests but tried to create non-reproducible random";
diff --git a/server/src/main/java/org/opensearch/common/settings/KeyStoreWrapper.java b/server/src/main/java/org/opensearch/common/settings/KeyStoreWrapper.java
index 1ad3b7ab8875a..967a8ff6682ac 100644
--- a/server/src/main/java/org/opensearch/common/settings/KeyStoreWrapper.java
+++ b/server/src/main/java/org/opensearch/common/settings/KeyStoreWrapper.java
@@ -40,10 +40,13 @@
import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.store.NIOFSDirectory;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.opensearch.bootstrap.SecureRandomInitializer;
import org.opensearch.cli.ExitCodes;
import org.opensearch.cli.UserException;
-import org.opensearch.common.Randomness;
import org.opensearch.common.SetOnce;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
import org.opensearch.common.hash.MessageDigests;
import org.opensearch.core.common.settings.SecureString;
@@ -75,7 +78,6 @@
import java.nio.file.attribute.PosixFilePermissions;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
-import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import java.util.Enumeration;
@@ -119,6 +121,11 @@ private static class Entry {
}
}
+ static {
+ // Instantiates new SecureRandom if caller is KeyStoreCli, otherwise obtains the existent.
+ SecureRandomInitializer.init();
+ }
+
/**
* A regex for the valid characters that a setting name in the keystore may use.
*/
@@ -218,11 +225,10 @@ public static KeyStoreWrapper create() {
/** Add the bootstrap seed setting, which may be used as a unique, secure, random value by the node */
public static void addBootstrapSeed(KeyStoreWrapper wrapper) {
assert wrapper.getSettingNames().contains(SEED_SETTING.getKey()) == false;
- SecureRandom random = Randomness.createSecure();
int passwordLength = 20; // Generate 20 character passwords
char[] characters = new char[passwordLength];
for (int i = 0; i < passwordLength; ++i) {
- characters[i] = SEED_CHARS[random.nextInt(SEED_CHARS.length)];
+ characters[i] = SEED_CHARS[CryptoServicesRegistrar.getSecureRandom().nextInt(SEED_CHARS.length)];
}
wrapper.setString(SEED_SETTING.getKey(), characters);
Arrays.fill(characters, (char) 0);
@@ -448,8 +454,11 @@ private byte[] encrypt(char[] password, byte[] salt, byte[] iv) throws GeneralSe
}
private void decryptLegacyEntries() throws GeneralSecurityException, IOException {
+ if (CryptoServicesRegistrar.isInApprovedOnlyMode()) {
+ throw new SecurityException("Legacy KeyStore formats v1 & v2 are not supported in FIPS JVM");
+ }
// v1 and v2 keystores never had passwords actually used, so we always use an empty password
- KeyStore keystore = KeyStore.getInstance("PKCS12");
+ KeyStore keystore = KeyStoreFactory.getInstance(KeyStoreType.PKCS_12, "SUN");
Map settingTypes = new HashMap<>();
ByteArrayInputStream inputBytes = new ByteArrayInputStream(dataBytes);
try (DataInputStream input = new DataInputStream(inputBytes)) {
@@ -488,7 +497,7 @@ private void decryptLegacyEntries() throws GeneralSecurityException, IOException
// fill in the entries now that we know all the types to expect
this.entries.set(new HashMap<>());
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBE");
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBE", "SunJCE");
KeyStore.PasswordProtection password = new KeyStore.PasswordProtection("".toCharArray());
for (Map.Entry settingEntry : settingTypes.entrySet()) {
@@ -532,15 +541,14 @@ public synchronized void save(Path configDir, char[] password) throws Exception
output.writeByte(password.length == 0 ? (byte) 0 : (byte) 1);
// new cipher params
- SecureRandom random = Randomness.createSecure();
// use 64 bytes salt, which surpasses that recommended by OWASP
// see https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
byte[] salt = new byte[64];
- random.nextBytes(salt);
+ CryptoServicesRegistrar.getSecureRandom().nextBytes(salt);
// use 96 bits (12 bytes) for IV as recommended by NIST
// see http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf section 5.2.1.1
byte[] iv = new byte[12];
- random.nextBytes(iv);
+ CryptoServicesRegistrar.getSecureRandom().nextBytes(iv);
// encrypted data
byte[] encryptedBytes = encrypt(password, salt, iv);
diff --git a/server/src/main/resources/org/opensearch/bootstrap/security.policy b/server/src/main/resources/org/opensearch/bootstrap/security.policy
index 22e445f7d9022..5411ab96f0fcd 100644
--- a/server/src/main/resources/org/opensearch/bootstrap/security.policy
+++ b/server/src/main/resources/org/opensearch/bootstrap/security.policy
@@ -92,6 +92,26 @@ grant codeBase "${codebase.reactor-core}" {
permission java.net.SocketPermission "*", "connect,resolve";
};
+// security
+grant {
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.security.internal.spec";
+ permission java.lang.RuntimePermission "accessDeclaredMembers";
+ permission java.lang.RuntimePermission "closeClassLoader";
+ permission java.lang.RuntimePermission "getProtectionDomain";
+ permission java.io.FilePermission "${java.home}/lib/security/cacerts", "read";
+ permission java.io.FilePermission "${java.home}/lib/security/jssecacerts", "read";
+ permission java.security.SecurityPermission "getProperty.jdk.certpath.disabledAlgorithms";
+ permission java.security.SecurityPermission "getProperty.jdk.tls.disabledAlgorithms";
+ permission java.security.SecurityPermission "getProperty.jdk.tls.server.defaultDHEParameters";
+ permission java.security.SecurityPermission "getProperty.keystore.type.compat";
+ permission java.security.SecurityPermission "getProperty.org.bouncycastle.*";
+ permission java.security.SecurityPermission "removeProvider.SunJCE";
+ permission java.util.PropertyPermission "java.runtime.name", "read";
+ permission org.bouncycastle.crypto.CryptoServicesPermission "defaultRandomConfig";
+ permission org.bouncycastle.crypto.CryptoServicesPermission "exportSecretKey";
+ permission org.bouncycastle.crypto.CryptoServicesPermission "exportPrivateKey";
+};
+
//// Everything else:
grant {
diff --git a/server/src/test/java/org/opensearch/bootstrap/SecureRandomInitializerTests.java b/server/src/test/java/org/opensearch/bootstrap/SecureRandomInitializerTests.java
new file mode 100644
index 0000000000000..865347438c8e5
--- /dev/null
+++ b/server/src/test/java/org/opensearch/bootstrap/SecureRandomInitializerTests.java
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.bootstrap;
+
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.fips.FipsSecureRandom;
+import org.opensearch.test.OpenSearchTestCase;
+import org.junit.BeforeClass;
+
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+public class SecureRandomInitializerTests extends OpenSearchTestCase {
+
+ @BeforeClass
+ public static void setup() {
+ // Reset the global state if your CryptoServicesRegistrar allows it.
+ // If there's a method to unset or reset the SecureRandom, call it here.
+ // If not, the following lines are hypothetical and depend on your actual implementation.
+ CryptoServicesRegistrar.setSecureRandom(null);
+ }
+
+ public void testInitInNonFipsMode() {
+ // given
+ assertThrows(IllegalStateException.class, CryptoServicesRegistrar::getSecureRandom);
+
+ // when
+ SecureRandomInitializer.init();
+ SecureRandom secureRandom = CryptoServicesRegistrar.getSecureRandom();
+
+ // then
+ assertNotNull("SecureRandom should be initialized in non-FIPS mode", secureRandom);
+ byte[] randomBytes = new byte[16];
+ secureRandom.nextBytes(randomBytes);
+ assertEquals(inFipsJvm() ? "BCFIPS_RNG" : "SUN", secureRandom.getProvider().getName());
+ // BCFIPS 'DEFAULT' RNG algorithm defaults to 'HMAC-DRBG-SHA512'
+ assertEquals(inFipsJvm() ? "HMAC-DRBG-SHA512" : "NativePRNGBlocking", secureRandom.getAlgorithm());
+ assertEquals(inFipsJvm() ? FipsSecureRandom.class : SecureRandom.class, secureRandom.getClass());
+ assertFalse("Random bytes should not be all zeros", allZeros(randomBytes));
+
+ byte[] seed1 = secureRandom.generateSeed(16);
+ byte[] seed2 = secureRandom.generateSeed(16);
+ assertNotNull(seed1);
+ assertNotNull(seed2);
+ assertFalse("Seeds should not be identical", Arrays.equals(seed1, seed2));
+ }
+
+ private boolean allZeros(byte[] data) {
+ for (byte b : data) {
+ if (b != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/server/src/test/java/org/opensearch/bootstrap/SecurityProviderManagerTests.java b/server/src/test/java/org/opensearch/bootstrap/SecurityProviderManagerTests.java
new file mode 100644
index 0000000000000..d46f3bbcc9c42
--- /dev/null
+++ b/server/src/test/java/org/opensearch/bootstrap/SecurityProviderManagerTests.java
@@ -0,0 +1,171 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.bootstrap;
+
+import org.opensearch.test.OpenSearchTestCase;
+import org.junit.AfterClass;
+import org.junit.Before;
+
+import javax.crypto.Cipher;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Locale;
+
+import static org.opensearch.bootstrap.BootstrapForTesting.sunJceInsertFunction;
+
+public class SecurityProviderManagerTests extends OpenSearchTestCase {
+
+ private static final String BC_FIPS = "BCFIPS";
+ private static final String SUN_JCE = "SunJCE";
+
+ // BCFIPS will only provide legacy ciphers when running in general mode, otherwise approved-only mode forbids the use.
+ private static final String MODE_DEPENDENT_CIPHER_PROVIDER = inFipsJvm() ? SUN_JCE : BC_FIPS;
+
+ private static final String AES = "AES";
+ private static final String RC_4 = "RC4";
+ private static final String TRIPLE_DES = "DESedeWrap";
+ private static final String DES = "DES";
+ private static final String PBE = "PBE";
+ private static final String BLOWFISH = "Blowfish";
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ var notInstalled = Arrays.stream(Security.getProviders()).noneMatch(provider -> SUN_JCE.equals(provider.getName()));
+ if (notInstalled && sunJceInsertFunction != null) {
+ sunJceInsertFunction.get();
+ }
+ assumeTrue(
+ String.format(
+ Locale.ROOT,
+ "SunJCE provider has to be initially installed through '%s' file",
+ System.getProperty("java.security.properties", "UNDEFINED")
+ ),
+ Arrays.stream(Security.getProviders()).anyMatch(provider -> SUN_JCE.equals(provider.getName()))
+ );
+ }
+
+ @AfterClass
+ // restore the same state as before running the tests.
+ public static void removeSunJCE() {
+ if (inFipsJvm()) {
+ SecurityProviderManager.excludeSunJCE();
+ }
+ }
+
+ public void testCipherRC4() throws Exception {
+ // given
+ var cipher = Cipher.getInstance(RC_4);
+ assertEquals(RC_4, cipher.getAlgorithm());
+ assertEquals(MODE_DEPENDENT_CIPHER_PROVIDER, cipher.getProvider().getName());
+
+ // when
+ SecurityProviderManager.excludeSunJCE();
+
+ // then
+ if (inFipsJvm()) {
+ expectThrows(NoSuchAlgorithmException.class, () -> Cipher.getInstance(RC_4));
+ } else {
+ cipher = Cipher.getInstance(RC_4);
+ assertEquals(RC_4, cipher.getAlgorithm());
+ assertEquals(BC_FIPS, cipher.getProvider().getName());
+ }
+ }
+
+ public void testCipherAES() throws Exception {
+ // given
+ var cipher = Cipher.getInstance(AES);
+ assertEquals(AES, cipher.getAlgorithm());
+ assertEquals(BC_FIPS, cipher.getProvider().getName());
+
+ // when
+ SecurityProviderManager.excludeSunJCE();
+
+ // then
+ cipher = Cipher.getInstance(AES);
+ assertEquals(AES, cipher.getAlgorithm());
+ assertEquals(BC_FIPS, cipher.getProvider().getName());
+ }
+
+ public void testCipher3Des() throws Exception {
+ // given
+ var cipher = Cipher.getInstance(TRIPLE_DES);
+ assertEquals(TRIPLE_DES, cipher.getAlgorithm());
+ assertEquals(BC_FIPS, cipher.getProvider().getName());
+
+ // when
+ SecurityProviderManager.excludeSunJCE();
+
+ // then
+ cipher = Cipher.getInstance(TRIPLE_DES);
+ assertEquals(TRIPLE_DES, cipher.getAlgorithm());
+ assertEquals(BC_FIPS, cipher.getProvider().getName());
+ }
+
+ public void testCipherDes() throws Exception {
+ // given
+ var cipher = Cipher.getInstance(DES);
+ assertEquals(DES, cipher.getAlgorithm());
+ assertEquals(MODE_DEPENDENT_CIPHER_PROVIDER, cipher.getProvider().getName());
+
+ // when
+ SecurityProviderManager.excludeSunJCE();
+
+ // then
+ if (inFipsJvm()) {
+ expectThrows(NoSuchAlgorithmException.class, () -> Cipher.getInstance(DES));
+ } else {
+ cipher = Cipher.getInstance(DES);
+ assertEquals(DES, cipher.getAlgorithm());
+ assertEquals(BC_FIPS, cipher.getProvider().getName());
+ }
+ }
+
+ public void testCipherPBE() throws Exception {
+ // given
+ var cipher = Cipher.getInstance(PBE);
+ assertEquals(PBE, cipher.getAlgorithm());
+ assertEquals(SUN_JCE, cipher.getProvider().getName());
+
+ // when
+ SecurityProviderManager.excludeSunJCE();
+
+ // then
+ expectThrows(NoSuchAlgorithmException.class, () -> Cipher.getInstance(PBE));
+ }
+
+ public void testCipherBlowfish() throws Exception {
+ // given
+ var cipher = Cipher.getInstance(BLOWFISH);
+ assertEquals(BLOWFISH, cipher.getAlgorithm());
+ assertEquals(MODE_DEPENDENT_CIPHER_PROVIDER, cipher.getProvider().getName());
+
+ // when
+ SecurityProviderManager.excludeSunJCE();
+
+ // then
+ if (inFipsJvm()) {
+ expectThrows(NoSuchAlgorithmException.class, () -> Cipher.getInstance(BLOWFISH));
+ } else {
+ cipher = Cipher.getInstance(BLOWFISH);
+ assertEquals(BLOWFISH, cipher.getAlgorithm());
+ assertEquals(BC_FIPS, cipher.getProvider().getName());
+ }
+ }
+
+ public void testGetPosition() {
+ assertTrue(SUN_JCE + " is installed", SecurityProviderManager.getPosition(SUN_JCE) > 0);
+ removeSunJCE();
+ assertTrue(SUN_JCE + " is uninstalled", SecurityProviderManager.getPosition(SUN_JCE) < 0);
+ }
+
+}
diff --git a/server/src/test/resources/org/opensearch/bootstrap/test.policy b/server/src/test/resources/org/opensearch/bootstrap/test.policy
index c2b5a8e9c0a4e..fe319686c38a6 100644
--- a/server/src/test/resources/org/opensearch/bootstrap/test.policy
+++ b/server/src/test/resources/org/opensearch/bootstrap/test.policy
@@ -10,4 +10,5 @@ grant {
// allow to test Security policy and codebases
permission java.util.PropertyPermission "*", "read,write";
permission java.security.SecurityPermission "createPolicy.JavaPolicy";
+ permission java.security.SecurityPermission "insertProvider";
};
diff --git a/test/fixtures/azure-fixture/docker-compose.yml b/test/fixtures/azure-fixture/docker-compose.yml
index 85e073e1803c1..66c4116ff4d67 100644
--- a/test/fixtures/azure-fixture/docker-compose.yml
+++ b/test/fixtures/azure-fixture/docker-compose.yml
@@ -1,6 +1,7 @@
version: '3'
services:
azure-fixture:
+ image: azure-fixture
build:
context: .
dockerfile: Dockerfile
@@ -10,6 +11,7 @@ services:
- "8091"
azure-fixture-other:
+ image: azure-fixture-other
build:
context: .
dockerfile: Dockerfile
@@ -19,6 +21,7 @@ services:
- "8091"
azure-fixture-repositories-metering:
+ image: azure-fixture-repositories-metering
build:
context: .
dockerfile: Dockerfile
diff --git a/test/fixtures/gcs-fixture/docker-compose.yml b/test/fixtures/gcs-fixture/docker-compose.yml
index 30a362e7caa8d..793a483aaff4a 100644
--- a/test/fixtures/gcs-fixture/docker-compose.yml
+++ b/test/fixtures/gcs-fixture/docker-compose.yml
@@ -1,6 +1,7 @@
version: '3'
services:
gcs-fixture:
+ image: "gcs-fixture"
build:
context: .
args:
@@ -13,6 +14,7 @@ services:
ports:
- "80"
gcs-fixture-third-party:
+ image: "gcs-fixture-third-party"
build:
context: .
args:
@@ -25,6 +27,7 @@ services:
ports:
- "80"
gcs-fixture-other:
+ image: "gcs-fixture-other"
build:
context: .
args:
@@ -37,6 +40,7 @@ services:
ports:
- "80"
gcs-fixture-repositories-metering:
+ image: "gcs-fixture-repositories-metering"
build:
context: .
args:
diff --git a/test/fixtures/krb5kdc-fixture/docker-compose.yml b/test/fixtures/krb5kdc-fixture/docker-compose.yml
index a178ea576e87c..364fafaa859bc 100644
--- a/test/fixtures/krb5kdc-fixture/docker-compose.yml
+++ b/test/fixtures/krb5kdc-fixture/docker-compose.yml
@@ -1,6 +1,7 @@
version: '3'
services:
peppa:
+ image: "peppa"
hostname: kerberos.build.opensearch.org
build:
context: .
@@ -14,6 +15,7 @@ services:
- "4444"
- "88/udp"
hdfs:
+ image: "hdfs"
hostname: kerberos.build.opensearch.org
build:
context: .
diff --git a/test/fixtures/krb5kdc-fixture/src/main/resources/provision/kdc.conf.template b/test/fixtures/krb5kdc-fixture/src/main/resources/provision/kdc.conf.template
index 22909ddf60013..69be28f4548c3 100644
--- a/test/fixtures/krb5kdc-fixture/src/main/resources/provision/kdc.conf.template
+++ b/test/fixtures/krb5kdc-fixture/src/main/resources/provision/kdc.conf.template
@@ -16,8 +16,8 @@
# under the License.
[kdcdefaults]
- kdc_listen = 88
- kdc_tcp_listen = 88
+ kdc_ports = 88
+ kdc_tcp_ports = 88
[realms]
${REALM_NAME} = {
@@ -25,8 +25,7 @@
max_life = 12h 0m 0s
max_renewable_life = 7d 0h 0m 0s
master_key_type = aes256-cts
- # remove aes256-cts:normal since unlimited strength policy needs installed for java to use it.
- supported_enctypes = aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
+ supported_enctypes = aes256-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:normal
}
[logging]
diff --git a/test/fixtures/krb5kdc-fixture/src/main/resources/provision/krb5.conf.template b/test/fixtures/krb5kdc-fixture/src/main/resources/provision/krb5.conf.template
index 207fe939fb7a5..a87c5b50d5cf3 100644
--- a/test/fixtures/krb5kdc-fixture/src/main/resources/provision/krb5.conf.template
+++ b/test/fixtures/krb5kdc-fixture/src/main/resources/provision/krb5.conf.template
@@ -33,18 +33,15 @@
dns_canonicalize_hostname = false
dns_lookup_kdc = false
dns_lookup_realm = false
- dns_uri_lookup = false
forwardable = true
ignore_acceptor_hostname = true
rdns = false
- default_tgs_enctypes = rc4-hmac
- default_tkt_enctypes = rc4-hmac
- permitted_enctypes = rc4-hmac
+ default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
+ default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
+ permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
# udp_preference_limit = 1
- kdc_timeout = 3000
canonicalize = true
- # See please https://seanjmullan.org/blog/2021/09/14/jdk17 (deprecate 3DES and RC4 in Kerberos)
- allow_weak_crypto = true
+ allow_weak_crypto = false
[realms]
${REALM_NAME} = {
@@ -52,6 +49,8 @@
kdc = 127.0.0.1:${MAPPED_PORT}
admin_server = ${KDC_NAME}:749
default_domain = ${BUILD_ZONE}
+ master_key_type = aes256-cts
+ supported_enctypes = aes256-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:normal
}
[domain_realm]
diff --git a/test/fixtures/minio-fixture/Dockerfile b/test/fixtures/minio-fixture/Dockerfile
index 81655aa545afd..4b714ade872ce 100644
--- a/test/fixtures/minio-fixture/Dockerfile
+++ b/test/fixtures/minio-fixture/Dockerfile
@@ -4,6 +4,12 @@ ARG bucket
ARG accessKey
ARG secretKey
-RUN mkdir -p /minio/data/${bucket}
ENV MINIO_ROOT_USER=${accessKey}
ENV MINIO_ROOT_PASSWORD=${secretKey}
+ENV bucket=${bucket}
+
+COPY entrypoint.sh /usr/bin/entrypoint.sh
+RUN chmod +x /usr/bin/entrypoint.sh
+
+ENTRYPOINT ["/usr/bin/entrypoint.sh"]
+CMD ["server", "--console-address", ":9001", "/minio/data"]
diff --git a/test/fixtures/minio-fixture/docker-compose.yml b/test/fixtures/minio-fixture/docker-compose.yml
index 539ca9471fa04..698dce65ce11a 100644
--- a/test/fixtures/minio-fixture/docker-compose.yml
+++ b/test/fixtures/minio-fixture/docker-compose.yml
@@ -1,6 +1,7 @@
version: '3.2'
services:
minio-fixture:
+ image: "minio-fixture"
build:
context: .
args:
@@ -14,6 +15,7 @@ services:
soft: 4096
ports:
- "9000"
+ - "9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
@@ -24,6 +26,7 @@ services:
target: /minio/data
command: ["server", "--console-address", ":9001", "/minio/data"]
minio-fixture-other:
+ image: "minio-fixture-other"
build:
context: .
args:
@@ -37,6 +40,7 @@ services:
soft: 4096
ports:
- "9000"
+ - "9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
@@ -47,6 +51,7 @@ services:
target: /minio/data
command: ["server", "--console-address", ":9001", "/minio/data"]
minio-fixture-for-snapshot-tool:
+ image: "minio-fixture-for-snapshot-tool"
build:
context: .
args:
diff --git a/test/fixtures/minio-fixture/entrypoint.sh b/test/fixtures/minio-fixture/entrypoint.sh
new file mode 100644
index 0000000000000..905b09d3f17e0
--- /dev/null
+++ b/test/fixtures/minio-fixture/entrypoint.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+set -e
+
+# Create the bucket directory after tmpfs is mounted
+mkdir -p /minio/data/bucket
+
+# Start MinIO server
+exec minio "$@"
diff --git a/test/fixtures/s3-fixture/docker-compose.yml b/test/fixtures/s3-fixture/docker-compose.yml
index d2b44f13c9530..98953b61761ba 100644
--- a/test/fixtures/s3-fixture/docker-compose.yml
+++ b/test/fixtures/s3-fixture/docker-compose.yml
@@ -1,6 +1,6 @@
-version: '3'
services:
s3-fixture:
+ image: "s3-fixture"
build:
context: .
args:
@@ -16,6 +16,7 @@ services:
- "80"
s3-fixture-other:
+ image: "s3-fixture-other"
build:
context: .
args:
@@ -31,6 +32,7 @@ services:
- "80"
s3-fixture-repositories-metering:
+ image: "s3-fixture-repositories-metering"
build:
context: .
args:
@@ -46,6 +48,7 @@ services:
- "80"
s3-fixture-with-session-token:
+ image: "s3-fixture-with-session-token"
build:
context: .
args:
@@ -62,6 +65,7 @@ services:
- "80"
s3-fixture-with-ec2:
+ image: "s3-fixture-with-ec2"
build:
context: .
args:
@@ -78,6 +82,7 @@ services:
- "80"
s3-fixture-with-ecs:
+ image: "s3-fixture-with-ecs"
build:
context: .
args:
@@ -94,6 +99,7 @@ services:
- "80"
s3-fixture-with-eks:
+ image: "s3-fixture-with-eks"
build:
context: .
args:
diff --git a/test/fixtures/s3-fixture/src/main/java/fixture/s3/S3HttpFixtureWithEC2.java b/test/fixtures/s3-fixture/src/main/java/fixture/s3/S3HttpFixtureWithEC2.java
index 9e02f9ee86744..cf6ce7d014199 100644
--- a/test/fixtures/s3-fixture/src/main/java/fixture/s3/S3HttpFixtureWithEC2.java
+++ b/test/fixtures/s3-fixture/src/main/java/fixture/s3/S3HttpFixtureWithEC2.java
@@ -90,9 +90,9 @@ protected HttpHandler createHandler(final String[] args) {
protected String buildCredentialResponse(final String ec2AccessKey, final String ec2SessionToken) {
return "{"
+ "\"AccessKeyId\": \"" + ec2AccessKey + "\","
- + "\"Expiration\": \"" + ZonedDateTime.now().plusDays(1L).format(DateTimeFormatter.ISO_DATE_TIME) + "\","
+ + "\"Expiration\": \"" + ZonedDateTime.now().plusDays(1L).format(DateTimeFormatter.ISO_INSTANT) + "\","
+ "\"RoleArn\": \"arn\","
- + "\"SecretAccessKey\": \"secret\","
+ + "\"SecretAccessKey\": \"secret_key\","
+ "\"Token\": \"" + ec2SessionToken + "\""
+ "}";
}
diff --git a/test/framework/src/main/java/org/opensearch/bootstrap/BootstrapForTesting.java b/test/framework/src/main/java/org/opensearch/bootstrap/BootstrapForTesting.java
index 933385dedcf49..b4cb2657e8dc3 100644
--- a/test/framework/src/main/java/org/opensearch/bootstrap/BootstrapForTesting.java
+++ b/test/framework/src/main/java/org/opensearch/bootstrap/BootstrapForTesting.java
@@ -37,6 +37,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.tests.util.LuceneTestCase;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.opensearch.common.Booleans;
import org.opensearch.common.SuppressForbidden;
import org.opensearch.common.io.PathUtils;
@@ -72,8 +73,10 @@
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
+import static org.opensearch.bootstrap.SecurityProviderManager.SUN_JCE;
import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean;
/**
@@ -124,6 +127,20 @@ public class BootstrapForTesting {
// Log ifconfig output before SecurityManager is installed
IfConfig.logIfNecessary();
+ SecureRandomInitializer.init();
+
+ var sunJceProvider = java.security.Security.getProvider(SUN_JCE);
+ if (sunJceProvider != null) {
+ sunJceInsertFunction = () -> java.security.Security.insertProviderAt(
+ sunJceProvider,
+ SecurityProviderManager.getPosition(SUN_JCE)
+ );
+
+ if (CryptoServicesRegistrar.isInApprovedOnlyMode()) {
+ SecurityProviderManager.excludeSunJCE();
+ }
+ }
+
// install security manager if requested
if (systemPropertyAsBoolean("tests.security.manager", true)) {
try {
@@ -201,6 +218,8 @@ public boolean implies(ProtectionDomain domain, Permission permission) {
}
}
+ static Supplier sunJceInsertFunction;
+
/** Add the codebase url of the given classname to the codebases map, if the class exists. */
private static void addClassCodebase(Map codebases, String name, String classname) {
try {
diff --git a/test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java b/test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java
new file mode 100644
index 0000000000000..90a5ce2768a30
--- /dev/null
+++ b/test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java
@@ -0,0 +1,70 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.test;
+
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.opensearch.common.crypto.KeyStoreFactory;
+import org.opensearch.common.crypto.KeyStoreType;
+
+import javax.security.auth.x500.X500Principal;
+import javax.security.auth.x500.X500PrivateCredential;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+public class KeyStoreUtils {
+
+ public static final char[] KEYSTORE_PASSWORD = "keystore_password".toCharArray();
+
+ public static KeyStore createServerKeyStore() throws Exception {
+ var serverCred = createCredential();
+ var keyStore = KeyStoreFactory.getInstance(KeyStoreType.BCFKS);
+ keyStore.load(null, null);
+ keyStore.setKeyEntry(
+ serverCred.getAlias(),
+ serverCred.getPrivateKey(),
+ KEYSTORE_PASSWORD,
+ new X509Certificate[] { serverCred.getCertificate() }
+ );
+ return keyStore;
+ }
+
+ private static X500PrivateCredential createCredential() throws Exception {
+ var keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ var keyPair = keyPairGenerator.generateKeyPair();
+ var rootCert = new JcaX509CertificateConverter().getCertificate(generateCert(keyPair));
+ return new X500PrivateCredential(rootCert, keyPair.getPrivate(), "server-ca");
+ }
+
+ private static X509CertificateHolder generateCert(KeyPair pair) throws Exception {
+ var baseTime = System.currentTimeMillis();
+ // 10 years in milliseconds
+ var validityPeriod = 10L * 365 * 24 * 60 * 60 * 1000;
+
+ var certBuilder = new JcaX509v1CertificateBuilder(
+ new X500Principal("CN=Test CA Certificate"),
+ BigInteger.valueOf(1),
+ new Date(baseTime),
+ new Date(baseTime + validityPeriod),
+ new X500Principal("CN=Test CA Certificate"),
+ pair.getPublic()
+ );
+ var signer = new JcaContentSignerBuilder("SHA256withRSA").build(pair.getPrivate());
+ return certBuilder.build(signer);
+ }
+
+}
diff --git a/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java b/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java
index 1c26ea4ca2c91..9dfe657eb5e3b 100644
--- a/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java
+++ b/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java
@@ -2389,10 +2389,6 @@ public static String resolveCustomDataPath(String index) {
return getIndexResponse.getSettings().get(index).get(IndexMetadata.SETTING_DATA_PATH);
}
- public static boolean inFipsJvm() {
- return Boolean.parseBoolean(System.getProperty(FIPS_SYSPROP));
- }
-
/**
* On Debian 8 the "memory" subsystem is not mounted by default
* when cgroups are enabled, and this confuses many versions of
diff --git a/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java b/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java
index b180187303a60..153a64a23642c 100644
--- a/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java
+++ b/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java
@@ -61,6 +61,7 @@
import org.apache.lucene.tests.util.TestRuleMarkFailure;
import org.apache.lucene.tests.util.TestUtil;
import org.apache.lucene.tests.util.TimeUnits;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.opensearch.Version;
import org.opensearch.bootstrap.BootstrapForTesting;
import org.opensearch.client.Client;
@@ -253,8 +254,6 @@ public void tearDown() throws Exception {
public static final String DEFAULT_TEST_WORKER_ID = "--not-gradle--";
- public static final String FIPS_SYSPROP = "tests.fips.enabled";
-
static {
TEST_WORKER_VM_ID = System.getProperty(TEST_WORKER_SYS_PROPERTY, DEFAULT_TEST_WORKER_ID);
setTestSysProps();
@@ -1758,7 +1757,7 @@ private static boolean isUnusableLocale() {
}
public static boolean inFipsJvm() {
- return Boolean.parseBoolean(System.getProperty(FIPS_SYSPROP));
+ return CryptoServicesRegistrar.isInApprovedOnlyMode();
}
/**
diff --git a/test/framework/src/main/java/org/opensearch/test/junit/listeners/ReproduceInfoPrinter.java b/test/framework/src/main/java/org/opensearch/test/junit/listeners/ReproduceInfoPrinter.java
index e2d59773a76cb..42ae6a57b829a 100644
--- a/test/framework/src/main/java/org/opensearch/test/junit/listeners/ReproduceInfoPrinter.java
+++ b/test/framework/src/main/java/org/opensearch/test/junit/listeners/ReproduceInfoPrinter.java
@@ -193,7 +193,6 @@ private ReproduceErrorMessageBuilder appendESProperties() {
appendOpt("tests.locale", Locale.getDefault().toLanguageTag());
appendOpt("tests.timezone", TimeZone.getDefault().getID());
appendOpt("runtime.java", Integer.toString(Runtime.version().version().get(0)));
- appendOpt(OpenSearchTestCase.FIPS_SYSPROP, System.getProperty(OpenSearchTestCase.FIPS_SYSPROP));
return this;
}
diff --git a/test/framework/src/main/java/org/opensearch/test/rest/OpenSearchRestTestCase.java b/test/framework/src/main/java/org/opensearch/test/rest/OpenSearchRestTestCase.java
index 8c612d258f183..d7b29b57f3934 100644
--- a/test/framework/src/main/java/org/opensearch/test/rest/OpenSearchRestTestCase.java
+++ b/test/framework/src/main/java/org/opensearch/test/rest/OpenSearchRestTestCase.java
@@ -60,6 +60,7 @@
import org.opensearch.client.WarningsHandler;
import org.opensearch.common.CheckedRunnable;
import org.opensearch.common.SetOnce;
+import org.opensearch.common.crypto.KeyStoreFactory;
import org.opensearch.common.io.PathUtils;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.unit.TimeValue;
@@ -841,8 +842,7 @@ protected static void configureClient(RestClientBuilder builder, Settings settin
throw new IllegalStateException(TRUSTSTORE_PATH + " is set but points to a non-existing file");
}
try {
- final String keyStoreType = keystorePath.endsWith(".p12") ? "PKCS12" : "jks";
- KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+ KeyStore keyStore = KeyStoreFactory.getInstanceBasedOnFileExtension(keystorePath);
try (InputStream is = Files.newInputStream(path)) {
keyStore.load(is, keystorePass.toCharArray());
}