This is an automated email from the ASF dual-hosted git repository.

smiklosovic pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 37fe4b679c Provide keystore_password_file and truststore_password_file 
options to read credentials from a file
37fe4b679c is described below

commit 37fe4b679c28234de3ee2ac0694118d5be570300
Author: maulin-vasavada <[email protected]>
AuthorDate: Mon Feb 17 20:06:11 2025 -0800

    Provide keystore_password_file and truststore_password_file options to read 
credentials from a file
    
    patch by Maulin Vasavada; reviewed by Stefan Miklosovic, Maxwell Guo for 
CASSANDRA-13428
---
 CHANGES.txt                                        |   1 +
 conf/cassandra.yaml                                |  29 ++
 conf/cassandra_latest.yaml                         |  29 ++
 .../pages/managing/operating/security.adoc         |  52 +++-
 .../KubernetesSecretsSslContextFactory.java        |  12 +-
 .../apache/cassandra/config/EncryptionOptions.java | 305 ++++++++++++++-------
 .../apache/cassandra/config/JMXServerOptions.java  |   6 +
 .../security/FileBasedSslContextFactory.java       |  60 +++-
 .../cassandra-jmx-sslconfig-with-passwordfile.yaml |  74 +++++
 ...ra-pem-sslcontextfactory-with-passwordfile.yaml | 152 ++++++++++
 .../cassandra_ssl_test_keystore_passwordfile.txt   |   1 +
 ...ssandra_ssl_test_outbound_keystore_password.txt |   1 +
 .../cassandra_ssl_test_truststore_passwordfile.txt |   1 +
 .../config/EncryptionOptionsEqualityTest.java      |  48 ++++
 .../cassandra/config/EncryptionOptionsTest.java    |  13 +-
 .../security/FileBasedSslContextFactoryTest.java   |  45 ++-
 .../security/FileBasedStoreContextTest.java        |  80 ++++++
 ...slContextFactoryConfigWithPasswordFileTest.java |  83 ++++++
 .../apache/cassandra/transport/TlsTestUtils.java   |   3 +
 ...uredWithYamlFileOptionsAndPasswordFileTest.java |  88 ++++++
 20 files changed, 960 insertions(+), 123 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 34c1154950..9b84f503c4 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.1
+ * Provide keystore_password_file and truststore_password_file options to read 
credentials from a file (CASSANDRA-13428)
  * Unregistering a node should also remove it from tokenMap if it is there and 
recalculate the placements (CASSANDRA-20346)
  * Fix PartitionUpdate.isEmpty deserialization issue to avoid potential 
EOFException (CASSANDRA-20345)
  * Avoid adding LEFT nodes to tokenMap on upgrade from gossip (CASSANDRA-20344)
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index 9f8f24b584..6eb150f5df 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1723,6 +1723,10 @@ server_encryption_options:
   # Set to a valid keystore if internode_encryption is dc, rack or all
   keystore: conf/.keystore
   #keystore_password: cassandra
+  # Optional configuration to specify password for keystore in a separate file
+  # When keystore_password and keystore_password_file both are specified, the 
keystore_password will take precedence
+  # The password in the file should be on the first line
+  #keystore_password_file: conf/keystore_passwordfile.txt
   # Configure the way Cassandra creates SSL contexts.
   # To use PEM-based key material, see 
org.apache.cassandra.security.PEMBasedSslContextFactory
   # ssl_context_factory:
@@ -1734,11 +1738,20 @@ server_encryption_options:
   # to create SSLContext. By default, outbound_keystore is the same as 
keystore indicating mTLS is not enabled.
 #  outbound_keystore: conf/.keystore
 #  outbound_keystore_password: cassandra
+  # Optional configuration to specify password for keystore in a separate file
+  # When outbound_keystore_password and outbound_keystore_password_file both 
are specified,
+  # the outbound_keystore_password will take precedence
+  # The password in the file should be on the first line
+  #outbound_keystore_password_file: conf/outbound_keystore_passwordfile.txt
   # Verify peer server certificates
   require_client_auth: false
   # Set to a valid trustore if require_client_auth is true
   truststore: conf/.truststore
   #truststore_password: cassandra
+  # Optional configuration to specify password for truststore in a separate 
file
+  # When truststore_password and truststore_password_file both are specified, 
the truststore_password will take precedence
+  # The password in the file should be on the first line
+  #truststore_password_file: conf/truststore_passwordfile.txt
   # Verify that the host name in the certificate matches the connected host
   require_endpoint_verification: false
   # More advanced defaults:
@@ -1780,6 +1793,10 @@ client_encryption_options:
   # Set keystore and keystore_password to valid keystores if enabled is true
   keystore: conf/.keystore
   #keystore_password: cassandra
+  # Optional configuration to specify password for keystore in a separate file
+  # When keystore_password and keystore_password_file both are specified, the 
keystore_password will take precedence
+  # The password in the file should be on the first line
+  #keystore_password_file: conf/keystore_passwordfile.txt
   # Configure the way Cassandra creates SSL contexts.
   # To use PEM-based key material, see 
org.apache.cassandra.security.PEMBasedSslContextFactory
   # ssl_context_factory:
@@ -1794,6 +1811,10 @@ client_encryption_options:
   # Set trustore and truststore_password if require_client_auth is true
   # truststore: conf/.truststore
   # truststore_password: cassandra
+  # Optional configuration to specify password for truststore in a separate 
file
+  # When truststore_password and truststore_password_file both are specified, 
the truststore_password will take precedence
+  # The password in the file should be on the first line
+  #truststore_password_file: conf/truststore_passwordfile.txt
   # More advanced defaults:
   # protocol: TLS
   # store_type: JKS
@@ -1844,8 +1865,16 @@ client_encryption_options:
   #   accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
   #   keystore: conf/cassandra_ssl.keystore
   #   keystore_password: cassandra
+  #   Optional configuration to specify password for keystore in a separate 
file
+  #   When keystore_password and keystore_password_file both are specified, 
the keystore_password will take precedence
+  #   The password in the file should be on the first line
+  #   keystore_password_file: conf/keystore_passwordfile.txt
   #   truststore: conf/cassandra_ssl.truststore
   #   truststore_password: cassandra
+  #   Optional configuration to specify password for truststore in a separate 
file
+  #   When truststore_password and truststore_password_file both are 
specified, the truststore_password will take precedence
+  #   The password in the file should be on the first line
+  #   truststore_password_file: conf/truststore_passwordfile.txt
   #
   # jmx authentication and authorization options.
   # authenticate: false
diff --git a/conf/cassandra_latest.yaml b/conf/cassandra_latest.yaml
index f8d791b26f..9c86beeea8 100644
--- a/conf/cassandra_latest.yaml
+++ b/conf/cassandra_latest.yaml
@@ -1613,6 +1613,10 @@ server_encryption_options:
   # Set to a valid keystore if internode_encryption is dc, rack or all
   keystore: conf/.keystore
   #keystore_password: cassandra
+  # Optional configuration to specify password for keystore in a separate file
+  # When keystore_password and keystore_password_file both are specified, the 
keystore_password will take precedence
+  # The password in the file should be on the first line
+  #keystore_password_file: conf/keystore_passwordfile.txt
   # Configure the way Cassandra creates SSL contexts.
   # To use PEM-based key material, see 
org.apache.cassandra.security.PEMBasedSslContextFactory
   # ssl_context_factory:
@@ -1624,11 +1628,20 @@ server_encryption_options:
   # to create SSLContext. By default, outbound_keystore is the same as 
keystore indicating mTLS is not enabled.
 #  outbound_keystore: conf/.keystore
 #  outbound_keystore_password: cassandra
+  # Optional configuration to specify password for keystore in a separate file
+  # When outbound_keystore_password and outbound_keystore_password_file both 
are specified,
+  # the outbound_keystore_password will take precedence
+  # The password in the file should be on the first line
+  #outbound_keystore_password_file: conf/outbound_keystore_passwordfile.txt
   # Verify peer server certificates
   require_client_auth: false
   # Set to a valid trustore if require_client_auth is true
   truststore: conf/.truststore
   #truststore_password: cassandra
+  # Optional configuration to specify password for truststore in a separate 
file
+  # When truststore_password and truststore_password_file both are specified, 
the truststore_password will take precedence
+  # The password in the file should be on the first line
+  #truststore_password_file: conf/truststore_passwordfile.txt
   # Verify that the host name in the certificate matches the connected host
   require_endpoint_verification: false
   # More advanced defaults:
@@ -1663,6 +1676,10 @@ client_encryption_options:
   # Set keystore and keystore_password to valid keystores if enabled is true
   keystore: conf/.keystore
   #keystore_password: cassandra
+  # Optional configuration to specify password for keystore in a separate file
+  # When keystore_password and keystore_password_file both are specified, the 
keystore_password will take precedence
+  # The password in the file should be on the first line
+  #keystore_password_file: conf/keystore_passwordfile.txt
   # Configure the way Cassandra creates SSL contexts.
   # To use PEM-based key material, see 
org.apache.cassandra.security.PEMBasedSslContextFactory
   # ssl_context_factory:
@@ -1677,6 +1694,10 @@ client_encryption_options:
   # Set trustore and truststore_password if require_client_auth is true
   # truststore: conf/.truststore
   # truststore_password: cassandra
+  # Optional configuration to specify password for truststore in a separate 
file
+  # When truststore_password and truststore_password_file both are specified, 
the truststore_password will take precedence
+  # The password in the file should be on the first line
+  #truststore_password_file: conf/truststore_passwordfile.txt
   # More advanced defaults:
   # protocol: TLS
   # store_type: JKS
@@ -1718,8 +1739,16 @@ client_encryption_options:
   #   accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
   #   keystore: conf/cassandra_ssl.keystore
   #   keystore_password: cassandra
+  #   Optional configuration to specify password for keystore in a separate 
file
+  #   When keystore_password and keystore_password_file both are specified, 
the keystore_password will take precedence
+  #   The password in the file should be on the first line
+  #   keystore_password_file: conf/keystore_passwordfile.txt
   #   truststore: conf/cassandra_ssl.truststore
   #   truststore_password: cassandra
+  #   Optional configuration to specify password for truststore in a separate 
file
+  #   When truststore_password and truststore_password_file both are 
specified, the truststore_password will take precedence
+  #   The password in the file should be on the first line
+  #   truststore_password_file: conf/truststore_passwordfile.txt
   #
   # jmx authentication and authorization options.
   # authenticate: false
diff --git a/doc/modules/cassandra/pages/managing/operating/security.adoc 
b/doc/modules/cassandra/pages/managing/operating/security.adoc
index e7748e93fb..cdc76a625d 100644
--- a/doc/modules/cassandra/pages/managing/operating/security.adoc
+++ b/doc/modules/cassandra/pages/managing/operating/security.adoc
@@ -100,6 +100,28 @@ YAML!)
               -----END CERTIFICATE-----
 ----
 
+* Configuration: PEM private key's password specified via a file
+
+[source,yaml]
+----
+   client/server_encryption_options:
+     ssl_context_factory:
+        class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+        parameters:
+            private_key: |
+             -----BEGIN ENCRYPTED PRIVATE KEY----- OR -----BEGIN PRIVATE 
KEY-----
+             <your base64 encoded private key>
+             -----END ENCRYPTED PRIVATE KEY----- OR -----END PRIVATE KEY-----
+             -----BEGIN CERTIFICATE-----
+             <your base64 encoded certificate chain>
+             -----END CERTIFICATE-----
+            trusted_certificates: |
+              -----BEGIN CERTIFICATE-----
+              <your base64 encoded certificate>
+              -----END CERTIFICATE-----
+     keystore_password_file: "<file having your password for the encrypted 
private key>"
+----
+
 * Configuration: PEM keys/certs defined in files
 
 [source,yaml]
@@ -112,6 +134,18 @@ YAML!)
      truststore: <file path to the truststore file in the PEM format>
 ----
 
+* Configuration: PEM private key's password specified via a file
+
+[source,yaml]
+----
+   client/server_encryption_options:
+     ssl_context_factory:
+        class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+     keystore: <file path to the keystore file in the PEM format with the 
private key and the certificate chain>
+     keystore_password_file: "<file having your password for the encrypted 
private key>"
+     truststore: <file path to the truststore file in the PEM format>
+----
+
 == SSL Certificate Hot Reloading
 
 Beginning with Cassandra 4, Cassandra supports hot reloading of SSL
@@ -590,11 +624,27 @@ jmx_encryption_options:
     truststore_password: cassandra
 ----
 
+Below is an example of configuring JMX SSL in `cassandra.yaml` with password 
files for keystore and truststore.
+[source,yaml]
+----
+jmx_encryption_options:
+    enabled: true
+    cipher_suites: 
[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
+    accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
+    keystore: test/conf/cassandra_ssl_test.keystore
+    keystore_password_file: test/conf/keystore_passwordfile.txt
+    truststore: test/conf/cassandra_ssl_test.truststore
+    truststore_password: cassandra
+    truststore_password_file: test/conf/truststore_passwordfile.txt
+----
+
 Similar to `client/server_encryption_options`, you can specify PEM-based
 key material or customize the SSL configuration using
 `ssl_context_factory` in `jmx_encryption_options`.
 
-Below is an example of configuring PEM based key material,
+Below is an example of configuring PEM based key material. You can use 
`keystore_password_file`
+configuration with in-line PEM as documented priorly in case you have stored 
the password for the
+keystore in a file.
 [source,yaml]
 ----
 jmx_encryption_options:
diff --git 
a/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
 
b/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
index ebeac6c4e8..12622d4458 100644
--- 
a/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
+++ 
b/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
@@ -150,10 +150,12 @@ public class KubernetesSecretsSslContextFactory extends 
FileBasedSslContextFacto
     public KubernetesSecretsSslContextFactory()
     {
         keystoreContext = new 
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.KEYSTORE.toString(),
 KEYSTORE_PATH_VALUE),
-                                                    
getValueFromEnv(KEYSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_KEYSTORE_PASSWORD));
+                                                    
getValueFromEnv(KEYSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_KEYSTORE_PASSWORD),
+                                                    null);
 
         trustStoreContext = new 
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.TRUSTSTORE.toString(),
 TRUSTSTORE_PATH_VALUE),
-                                                      
getValueFromEnv(TRUSTSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_TRUSTSTORE_PASSWORD));
+                                                      
getValueFromEnv(TRUSTSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_TRUSTSTORE_PASSWORD),
+                                                      null);
 
         keystoreLastUpdatedTime = System.nanoTime();
         keystoreUpdatedTimeSecretKeyPath = 
getString(ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH,
@@ -168,11 +170,13 @@ public class KubernetesSecretsSslContextFactory extends 
FileBasedSslContextFacto
         super(parameters);
         keystoreContext = new 
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.KEYSTORE.toString(),
 KEYSTORE_PATH_VALUE),
                                                     
getValueFromEnv(getString(ConfigKeys.KEYSTORE_PASSWORD_ENV_VAR,
-                                                                              
KEYSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_KEYSTORE_PASSWORD));
+                                                                              
KEYSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_KEYSTORE_PASSWORD),
+                                                    null);
 
         trustStoreContext = new 
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.TRUSTSTORE.toString(),
 TRUSTSTORE_PATH_VALUE),
                                                       
getValueFromEnv(getString(ConfigKeys.TRUSTSTORE_PASSWORD_ENV_VAR,
-                                                                               
 TRUSTSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_TRUSTSTORE_PASSWORD));
+                                                                               
 TRUSTSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_TRUSTSTORE_PASSWORD),
+                                                      null);
         keystoreLastUpdatedTime = System.nanoTime();
         keystoreUpdatedTimeSecretKeyPath = 
getString(ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH,
                                                      
KEYSTORE_UPDATED_TIMESTAMP_PATH_VALUE);
diff --git a/src/java/org/apache/cassandra/config/EncryptionOptions.java 
b/src/java/org/apache/cassandra/config/EncryptionOptions.java
index 1cd3b7addd..07f78b9a5e 100644
--- a/src/java/org/apache/cassandra/config/EncryptionOptions.java
+++ b/src/java/org/apache/cassandra/config/EncryptionOptions.java
@@ -114,9 +114,13 @@ public class EncryptionOptions
     public final String keystore;
     @Nullable
     public final String keystore_password;
+    @Nullable
+    public final String keystore_password_file;
     public final String truststore;
     @Nullable
     public final String truststore_password;
+    @Nullable
+    public final String truststore_password_file;
     public final List<String> cipher_suites;
     protected String protocol;
     protected List<String> accepted_protocols;
@@ -153,10 +157,13 @@ public class EncryptionOptions
     {
         KEYSTORE("keystore"),
         KEYSTORE_PASSWORD("keystore_password"),
+        KEYSTORE_PASSWORD_FILE("keystore_password_file"),
         OUTBOUND_KEYSTORE("outbound_keystore"),
         OUTBOUND_KEYSTORE_PASSWORD("outbound_keystore_password"),
+        OUTBOUND_KEYSTORE_PASSWORD_FILE("outbound_keystore_password_file"),
         TRUSTSTORE("truststore"),
         TRUSTSTORE_PASSWORD("truststore_password"),
+        TRUSTSTORE_PASSWORD_FILE("truststore_password_file"),
         CIPHER_SUITES("cipher_suites"),
         PROTOCOL("protocol"),
         ACCEPTED_PROTOCOLS("accepted_protocols"),
@@ -199,8 +206,10 @@ public class EncryptionOptions
                                                      new HashMap<>());
         keystore = "conf/.keystore";
         keystore_password = null;
+        keystore_password_file = null;
         truststore = "conf/.truststore";
         truststore_password = null;
+        truststore_password_file = null;
         cipher_suites = null;
         protocol = null;
         accepted_protocols = null;
@@ -214,18 +223,22 @@ public class EncryptionOptions
         certificate_validity_warn_threshold = null;
     }
 
-    public EncryptionOptions(ParameterizedClass ssl_context_factory, String 
keystore, String keystore_password,
-                             String truststore, String truststore_password, 
List<String> cipher_suites,
-                             String protocol, List<String> accepted_protocols, 
String algorithm, String store_type,
-                             String require_client_auth, boolean 
require_endpoint_verification, Boolean enabled,
-                             Boolean optional, DurationSpec.IntMinutesBound 
max_certificate_validity_period,
+    public EncryptionOptions(ParameterizedClass ssl_context_factory,
+                             String keystore, String keystore_password, String 
keystore_password_file,
+                             String truststore, String truststore_password, 
String truststore_password_file,
+                             List<String> cipher_suites, String protocol, 
List<String> accepted_protocols,
+                             String algorithm, String store_type, String 
require_client_auth,
+                             boolean require_endpoint_verification, Boolean 
enabled, Boolean optional,
+                             DurationSpec.IntMinutesBound 
max_certificate_validity_period,
                              DurationSpec.IntMinutesBound 
certificate_validity_warn_threshold)
     {
         this.ssl_context_factory = ssl_context_factory;
         this.keystore = keystore;
         this.keystore_password = keystore_password;
+        this.keystore_password_file = keystore_password_file;
         this.truststore = truststore;
         this.truststore_password = truststore_password;
+        this.truststore_password_file = truststore_password_file;
         this.cipher_suites = cipher_suites;
         this.protocol = protocol;
         this.accepted_protocols = accepted_protocols;
@@ -244,8 +257,10 @@ public class EncryptionOptions
         ssl_context_factory = options.ssl_context_factory;
         keystore = options.keystore;
         keystore_password = options.keystore_password;
+        keystore_password_file = options.keystore_password_file;
         truststore = options.truststore;
         truststore_password = options.truststore_password;
+        truststore_password_file = options.truststore_password_file;
         cipher_suites = options.cipher_suites;
         protocol = options.protocol;
         accepted_protocols = options.accepted_protocols;
@@ -324,8 +339,10 @@ public class EncryptionOptions
          */
         putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.KEYSTORE, this.keystore);
         putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.KEYSTORE_PASSWORD, this.keystore_password);
+        putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.KEYSTORE_PASSWORD_FILE, this.keystore_password_file);
         putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.TRUSTSTORE, this.truststore);
         putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.TRUSTSTORE_PASSWORD, this.truststore_password);
+        putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.TRUSTSTORE_PASSWORD_FILE, this.truststore_password_file);
         putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.CIPHER_SUITES, this.cipher_suites);
         putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.PROTOCOL, this.protocol);
         putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.ACCEPTED_PROTOCOLS, this.accepted_protocols);
@@ -502,56 +519,72 @@ public class EncryptionOptions
 
     public EncryptionOptions withSslContextFactory(ParameterizedClass 
sslContextFactoryClass)
     {
-        return new EncryptionOptions(sslContextFactoryClass, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(sslContextFactoryClass, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withKeyStore(String keystore)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withKeyStorePassword(String keystore_password)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
+                                     store_type, require_client_auth, 
require_endpoint_verification, enabled,
+                                     optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
+    }
+
+    public EncryptionOptions withKeyStorePasswordFile(String 
keystore_password_file)
+    {
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withTrustStore(String truststore)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withTrustStorePassword(String truststore_password)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
+                                     store_type, require_client_auth, 
require_endpoint_verification, enabled,
+                                     optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
+    }
+
+    public EncryptionOptions withTrustStorePasswordFile(String 
truststore_password_file)
+    {
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withCipherSuites(List<String> cipher_suites)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withCipherSuites(String... cipher_suites)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, 
ImmutableList.copyOf(cipher_suites), protocol,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, ImmutableList.copyOf(cipher_suites), protocol,
                                      accepted_protocols, algorithm, 
store_type, require_client_auth,
                                      require_endpoint_verification, enabled, 
optional, max_certificate_validity_period,
                                      
max_certificate_validity_period).applyConfig();
@@ -559,8 +592,8 @@ public class EncryptionOptions
 
     public EncryptionOptions withProtocol(String protocol)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
@@ -568,8 +601,8 @@ public class EncryptionOptions
 
     public EncryptionOptions withAcceptedProtocols(List<String> 
accepted_protocols)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols == null ? null :
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols == null ? 
null :
                                                                                
    ImmutableList.copyOf(accepted_protocols),
                                      algorithm, store_type, 
require_client_auth, require_endpoint_verification,
                                      enabled, optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
@@ -578,64 +611,64 @@ public class EncryptionOptions
 
     public EncryptionOptions withAlgorithm(String algorithm)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withStoreType(String store_type)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withRequireClientAuth(ClientAuth 
require_client_auth)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth.value, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withRequireEndpointVerification(boolean 
require_endpoint_verification)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withEnabled(boolean enabled)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions withOptional(Boolean optional)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
     }
 
     public EncryptionOptions 
withMaxCertificateValidityPeriod(DurationSpec.IntMinutesBound 
maxCertificateValidityPeriod)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, maxCertificateValidityPeriod, 
certificate_validity_warn_threshold).applyConfig();
     }
 
     public EncryptionOptions 
withCertificateValidityWarnThreshold(DurationSpec.IntMinutesBound 
certificateValidityWarnThreshold)
     {
-        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, truststore,
-                                     truststore_password, cipher_suites, 
protocol, accepted_protocols, algorithm,
+        return new EncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file, truststore,
+                                     truststore_password, 
truststore_password_file, cipher_suites, protocol, accepted_protocols, 
algorithm,
                                      store_type, require_client_auth, 
require_endpoint_verification, enabled,
                                      optional, 
max_certificate_validity_period, 
certificateValidityWarnThreshold).applyConfig();
     }
@@ -659,8 +692,10 @@ public class EncryptionOptions
                require_endpoint_verification == 
opt.require_endpoint_verification &&
                Objects.equals(keystore, opt.keystore) &&
                Objects.equals(keystore_password, opt.keystore_password) &&
+               Objects.equals(keystore_password_file, 
opt.keystore_password_file) &&
                Objects.equals(truststore, opt.truststore) &&
                Objects.equals(truststore_password, opt.truststore_password) &&
+               Objects.equals(truststore_password_file, 
opt.truststore_password_file) &&
                Objects.equals(protocol, opt.protocol) &&
                Objects.equals(accepted_protocols, opt.accepted_protocols) &&
                Objects.equals(algorithm, opt.algorithm) &&
@@ -679,8 +714,10 @@ public class EncryptionOptions
         int result = 0;
         result += 31 * (keystore == null ? 0 : keystore.hashCode());
         result += 31 * (keystore_password == null ? 0 : 
keystore_password.hashCode());
+        result += 31 * (keystore_password_file == null ? 0 : 
keystore_password_file.hashCode());
         result += 31 * (truststore == null ? 0 : truststore.hashCode());
         result += 31 * (truststore_password == null ? 0 : 
truststore_password.hashCode());
+        result += 31 * (truststore_password_file == null ? 0 : 
truststore_password_file.hashCode());
         result += 31 * (protocol == null ? 0 : protocol.hashCode());
         result += 31 * (accepted_protocols == null ? 0 : 
accepted_protocols.hashCode());
         result += 31 * (algorithm == null ? 0 : algorithm.hashCode());
@@ -707,6 +744,8 @@ public class EncryptionOptions
         public final String outbound_keystore;
         @Nullable
         public final String outbound_keystore_password;
+        @Nullable
+        public final String outbound_keystore_password_file;
 
         public ServerEncryptionOptions()
         {
@@ -714,11 +753,13 @@ public class EncryptionOptions
             this.legacy_ssl_storage_port_enabled = false;
             this.outbound_keystore = null;
             this.outbound_keystore_password = null;
+            this.outbound_keystore_password_file = null;
         }
 
         public ServerEncryptionOptions(ParameterizedClass 
sslContextFactoryClass, String keystore,
-                                       String keystore_password,String 
outbound_keystore,
-                                       String outbound_keystore_password, 
String truststore, String truststore_password,
+                                       String keystore_password, String 
keystore_password_file, String outbound_keystore,
+                                       String outbound_keystore_password, 
String outbound_keystore_password_file,
+                                       String truststore, String 
truststore_password, String truststore_password_file,
                                        List<String> cipher_suites, String 
protocol, List<String> accepted_protocols,
                                        String algorithm, String store_type, 
String require_client_auth,
                                        boolean require_endpoint_verification, 
Boolean optional,
@@ -726,13 +767,15 @@ public class EncryptionOptions
                                        DurationSpec.IntMinutesBound 
maxCertificateAgeMinutes,
                                        DurationSpec.IntMinutesBound 
certificateValidityWarnThreshold)
         {
-            super(sslContextFactoryClass, keystore, keystore_password, 
truststore, truststore_password, cipher_suites,
+            super(sslContextFactoryClass, keystore, keystore_password, 
keystore_password_file,
+                  truststore, truststore_password, truststore_password_file, 
cipher_suites,
                   protocol, accepted_protocols, algorithm, store_type, 
require_client_auth, require_endpoint_verification,
                   null, optional, maxCertificateAgeMinutes, 
certificateValidityWarnThreshold);
             this.internode_encryption = internode_encryption;
             this.legacy_ssl_storage_port_enabled = 
legacy_ssl_storage_port_enabled;
             this.outbound_keystore = outbound_keystore;
             this.outbound_keystore_password = outbound_keystore_password;
+            this.outbound_keystore_password_file = 
outbound_keystore_password_file;
         }
 
         public ServerEncryptionOptions(ServerEncryptionOptions options)
@@ -742,6 +785,7 @@ public class EncryptionOptions
             this.legacy_ssl_storage_port_enabled = 
options.legacy_ssl_storage_port_enabled;
             this.outbound_keystore = options.outbound_keystore;
             this.outbound_keystore_password = 
options.outbound_keystore_password;
+            this.outbound_keystore_password_file = 
options.outbound_keystore_password_file;
         }
 
         @Override
@@ -750,6 +794,7 @@ public class EncryptionOptions
             super.fillSslContextParams(sslContextFactoryParameters);
             putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.OUTBOUND_KEYSTORE, this.outbound_keystore);
             putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.OUTBOUND_KEYSTORE_PASSWORD, this.outbound_keystore_password);
+            putSslContextFactoryParameter(sslContextFactoryParameters, 
ConfigKey.OUTBOUND_KEYSTORE_PASSWORD_FILE, 
this.outbound_keystore_password_file);
         }
 
         @Override
@@ -845,7 +890,8 @@ public class EncryptionOptions
             return internode_encryption == opt.internode_encryption &&
                    legacy_ssl_storage_port_enabled == 
opt.legacy_ssl_storage_port_enabled &&
                    Objects.equals(outbound_keystore, opt.outbound_keystore) &&
-                   Objects.equals(outbound_keystore_password, 
opt.outbound_keystore_password);
+                   Objects.equals(outbound_keystore_password, 
opt.outbound_keystore_password) &&
+                   Objects.equals(outbound_keystore_password_file, 
opt.outbound_keystore_password_file);
         }
 
         /**
@@ -861,15 +907,17 @@ public class EncryptionOptions
             result += 31 * Boolean.hashCode(legacy_ssl_storage_port_enabled);
             result += 31 * (outbound_keystore == null ? 0 : 
outbound_keystore.hashCode());
             result += 31 * (outbound_keystore_password == null ? 0 : 
outbound_keystore_password.hashCode());
+            result += 31 * (outbound_keystore_password_file == null ? 0 : 
outbound_keystore_password_file.hashCode());
             return result;
         }
 
         @Override
         public ServerEncryptionOptions 
withSslContextFactory(ParameterizedClass sslContextFactoryClass)
         {
-            return new ServerEncryptionOptions(sslContextFactoryClass, 
keystore, keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(sslContextFactoryClass, 
keystore, keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -879,9 +927,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withKeyStore(String keystore)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -891,9 +940,23 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withKeyStorePassword(String 
keystore_password)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
+                                               algorithm, store_type, 
require_client_auth,
+                                               require_endpoint_verification, 
optional, internode_encryption,
+                                               
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
+                                               
max_certificate_validity_period).applyConfigInternal();
+        }
+
+        @Override
+        public ServerEncryptionOptions withKeyStorePasswordFile(String 
keystore_password_file)
+        {
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -903,9 +966,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withTrustStore(String truststore)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -915,9 +979,23 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withTrustStorePassword(String 
truststore_password)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
+                                               algorithm, store_type, 
require_client_auth,
+                                               require_endpoint_verification, 
optional, internode_encryption,
+                                               
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
+                                               
max_certificate_validity_period).applyConfigInternal();
+        }
+
+        @Override
+        public ServerEncryptionOptions withTrustStorePasswordFile(String 
truststore_password_file)
+        {
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -927,9 +1005,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withCipherSuites(List<String> 
cipher_suites)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -939,10 +1018,11 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withCipherSuites(String... 
cipher_suites)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
Arrays.asList(cipher_suites), protocol,
-                                               accepted_protocols, algorithm, 
store_type, require_client_auth,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               Arrays.asList(cipher_suites), 
protocol, accepted_protocols,
+                                               algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
                                                
max_certificate_validity_period).applyConfigInternal();
@@ -951,9 +1031,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withProtocol(String protocol)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -963,9 +1044,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withAcceptedProtocols(List<String> 
accepted_protocols)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -975,9 +1057,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withAlgorithm(String algorithm)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -987,9 +1070,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withStoreType(String store_type)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -999,9 +1083,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withRequireClientAuth(ClientAuth 
require_client_auth)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth.value,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1011,9 +1096,10 @@ public class EncryptionOptions
         @Override
         public ServerEncryptionOptions withRequireEndpointVerification(boolean 
require_endpoint_verification)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1022,9 +1108,10 @@ public class EncryptionOptions
 
         public ServerEncryptionOptions withOptional(boolean optional)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1033,9 +1120,10 @@ public class EncryptionOptions
 
         public ServerEncryptionOptions 
withInternodeEncryption(InternodeEncryption internode_encryption)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1044,9 +1132,10 @@ public class EncryptionOptions
 
         public ServerEncryptionOptions withLegacySslStoragePort(boolean 
enable_legacy_ssl_storage_port)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                enable_legacy_ssl_storage_port, 
max_certificate_validity_period,
@@ -1055,9 +1144,10 @@ public class EncryptionOptions
 
         public ServerEncryptionOptions withOutboundKeystore(String 
outboundKeystore)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outboundKeystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outboundKeystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1066,21 +1156,34 @@ public class EncryptionOptions
 
         public ServerEncryptionOptions withOutboundKeystorePassword(String 
outboundKeystorePassword)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outboundKeystorePassword, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outboundKeystorePassword, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
                                                
max_certificate_validity_period).applyConfigInternal();
         }
 
+        public ServerEncryptionOptions withOutboundKeystorePasswordFile(String 
outboundKeystorePasswordFile)
+        {
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outboundKeystorePasswordFile,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
+                                               algorithm, store_type, 
require_client_auth,
+                                               require_endpoint_verification, 
optional, internode_encryption,
+                                               
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
+                                               
max_certificate_validity_period).applyConfigInternal();
+        }
         @Override
         public ServerEncryptionOptions 
withMaxCertificateValidityPeriod(DurationSpec.IntMinutesBound 
maxCertificateValidityPeriod)
         {
-            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password,
-                                               outbound_keystore, 
outbound_keystore_password, truststore,
-                                               truststore_password, 
cipher_suites, protocol, accepted_protocols,
+            return new ServerEncryptionOptions(ssl_context_factory, keystore, 
keystore_password, keystore_password_file,
+                                               outbound_keystore, 
outbound_keystore_password, outbound_keystore_password_file,
+                                               truststore, 
truststore_password, truststore_password_file,
+                                               cipher_suites, protocol, 
accepted_protocols,
                                                algorithm, store_type, 
require_client_auth,
                                                require_endpoint_verification, 
optional, internode_encryption,
                                                
legacy_ssl_storage_port_enabled, maxCertificateValidityPeriod,
diff --git a/src/java/org/apache/cassandra/config/JMXServerOptions.java 
b/src/java/org/apache/cassandra/config/JMXServerOptions.java
index 8b51d3b756..705ab02bb8 100644
--- a/src/java/org/apache/cassandra/config/JMXServerOptions.java
+++ b/src/java/org/apache/cassandra/config/JMXServerOptions.java
@@ -194,11 +194,17 @@ public class JMXServerOptions
 
         boolean sslEnabled = COM_SUN_MANAGEMENT_JMXREMOTE_SSL.getBoolean();
 
+        // CASSANDRA-13428: Support for specifying password file for keystores 
is only added to the `encryption_options`
+        // in the `cassandra.yaml`. Since the JMX SSL Config can also leverage 
it as per CASSANDRA-18508, password file
+        // support is not added to the JMX SSL configuration via the system 
properties. Hence, `null` is used as
+        // the password file arguments for the keystore and the truststore 
while constructing the encryption options here.
         EncryptionOptions encryptionOptions = new EncryptionOptions(new 
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory", 
new HashMap<>()),
                                                                     keystore,
                                                                     
keystorePassword,
+                                                                    null,
                                                                     truststore,
                                                                     
truststorePassword,
+                                                                    null,
                                                                     
cipherSuites,
                                                                     null, // 
protocol
                                                                     
acceptedProtocols,
diff --git 
a/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java 
b/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java
index 39e584d257..e0867493d7 100644
--- a/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java
+++ b/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java
@@ -36,9 +36,13 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.cassandra.exceptions.ConfigurationException;
 import org.apache.cassandra.io.util.File;
+import org.apache.cassandra.io.util.FileUtils;
 import org.apache.cassandra.utils.Clock;
 
+import static java.lang.String.format;
+
 /**
  * Abstract implementation for {@link ISslContextFactory} using file based, 
standard keystore format with the ability
  * to hot-reload the files upon file changes (detected by the {@code last 
modified timestamp}).
@@ -60,18 +64,19 @@ public abstract class FileBasedSslContextFactory extends 
AbstractSslContextFacto
 
     public FileBasedSslContextFactory()
     {
-        keystoreContext = new FileBasedStoreContext("conf/.keystore", 
"cassandra");
-        outboundKeystoreContext = new FileBasedStoreContext("conf/.keystore", 
"cassandra");
-        trustStoreContext = new FileBasedStoreContext("conf/.truststore", 
"cassandra");
+        keystoreContext = new FileBasedStoreContext("conf/.keystore", 
"cassandra", null);
+        outboundKeystoreContext = new FileBasedStoreContext("conf/.keystore", 
"cassandra", null);
+        trustStoreContext = new FileBasedStoreContext("conf/.truststore", 
"cassandra", null);
     }
 
     public FileBasedSslContextFactory(Map<String, Object> parameters)
     {
         super(parameters);
-        keystoreContext = new FileBasedStoreContext(getString("keystore"), 
getString("keystore_password"));
+        keystoreContext = new FileBasedStoreContext(getString("keystore"), 
getString("keystore_password"), getString("keystore_password_file"));
         outboundKeystoreContext = new 
FileBasedStoreContext(StringUtils.defaultString(getString("outbound_keystore"), 
keystoreContext.filePath),
-                                                            
StringUtils.defaultString(getString("outbound_keystore_password"), 
keystoreContext.password));
-        trustStoreContext = new FileBasedStoreContext(getString("truststore"), 
getString("truststore_password"));
+                                                            
StringUtils.defaultString(getString("outbound_keystore_password"), 
keystoreContext.password),
+                                                            
StringUtils.defaultString(getString("outbound_keystore_password_file"), 
keystoreContext.passwordFilePath));
+        trustStoreContext = new FileBasedStoreContext(getString("truststore"), 
getString("truststore_password"), getString("truststore_password_file"));
     }
 
     @Override
@@ -135,7 +140,7 @@ public abstract class FileBasedSslContextFactory extends 
AbstractSslContextFacto
         if (password == null)
         {
             String keyName = isOutboundKeystore ? "outbound_" : "";
-            final String msg = String.format("'%skeystore_password' must be 
specified", keyName);
+            final String msg = format("'%skeystore_password' must be 
specified", keyName);
             throw new IllegalArgumentException(msg);
         }
     }
@@ -278,11 +283,13 @@ public abstract class FileBasedSslContextFactory extends 
AbstractSslContextFacto
         public volatile boolean checkedExpiry = false;
         public String filePath;
         public String password;
+        public String passwordFilePath;
 
-        public FileBasedStoreContext(String keystore, String keystorePassword)
+        public FileBasedStoreContext(String keystoreFilePath, String 
keystorePassword, String keystorePasswordFilePath)
         {
-            this.filePath = keystore;
-            this.password = keystorePassword;
+            this.filePath = keystoreFilePath;
+            this.passwordFilePath = keystorePasswordFilePath;
+            this.password = resolvePassword(keystoreFilePath, 
keystorePassword, keystorePasswordFilePath);
         }
 
         protected boolean hasKeystore()
@@ -294,5 +301,38 @@ public abstract class FileBasedSslContextFactory extends 
AbstractSslContextFacto
         {
             return StringUtils.isEmpty(password) || 
keyPassword.equals(password);
         }
+
+        private static String resolvePassword(String keystoreFilePath, String 
password, String passwordFilePath)
+        {
+            if (password != null)
+                return password;
+
+            if (StringUtils.isEmpty(passwordFilePath))
+                return null;
+
+            File keystorePasswordFile = new File(passwordFilePath);
+
+            if (!keystorePasswordFile.exists())
+            {
+                final String msg = format("keystore password file %s does not 
exist", keystorePasswordFile.path());
+                throw new ConfigurationException(msg);
+            }
+
+            try
+            {
+                // we expect a password to be on the first line
+                List<String> lines = FileUtils.readLines(keystorePasswordFile);
+                if (lines.isEmpty())
+                    return "";
+
+                return lines.get(0);
+            }
+            catch (RuntimeException e)
+            {
+                throw new ConfigurationException(format("'Failed to read 
keystore password from the %s for %s",
+                                                        keystorePasswordFile, 
keystoreFilePath),
+                                                 e);
+            }
+        }
     }
 }
diff --git a/test/conf/cassandra-jmx-sslconfig-with-passwordfile.yaml 
b/test/conf/cassandra-jmx-sslconfig-with-passwordfile.yaml
new file mode 100644
index 0000000000..0b495485d1
--- /dev/null
+++ b/test/conf/cassandra-jmx-sslconfig-with-passwordfile.yaml
@@ -0,0 +1,74 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+#
+# Testing for pluggable ssl_context_factory option for client and server 
encryption options with a valid and a missing
+# implementation classes.
+#
+cluster_name: Test Cluster
+# memtable_allocation_type: heap_buffers
+memtable_allocation_type: offheap_objects
+commitlog_sync: batch
+commitlog_segment_size: 5MiB
+commitlog_directory: build/test/cassandra/commitlog
+# commitlog_compression:
+# - class_name: LZ4Compressor
+cdc_raw_directory: build/test/cassandra/cdc_raw
+cdc_enabled: false
+hints_directory: build/test/cassandra/hints
+partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
+listen_address: 127.0.0.1
+storage_port: 7012
+ssl_storage_port: 17012
+start_native_transport: true
+native_transport_port: 9042
+column_index_size: 4KiB
+saved_caches_directory: build/test/cassandra/saved_caches
+data_file_directories:
+    - build/test/cassandra/data
+disk_access_mode: mmap_index_only
+seed_provider:
+    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
+      parameters:
+          - seeds: "127.0.0.1:7012"
+endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
+dynamic_snitch: true
+jmx_server_options:
+    enabled: true
+    jmx_encryption_options:
+        enabled: true
+        cipher_suites: 
[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
+        accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
+        keystore: test/conf/cassandra_ssl_test.keystore
+        keystore_password_file: 
test/conf/cassandra_ssl_test_keystore_passwordfile.txt
+        truststore: test/conf/cassandra_ssl_test.truststore
+        truststore_password_file: 
test/conf/cassandra_ssl_test_truststore_passwordfile.txt
+incremental_backups: true
+concurrent_compactors: 4
+compaction_throughput: 0MiB/s
+row_cache_class_name: org.apache.cassandra.cache.OHCProvider
+row_cache_size: 16MiB
+user_defined_functions_enabled: true
+scripted_user_defined_functions_enabled: false
+prepared_statements_cache_size: 1MiB
+corrupted_tombstone_strategy: exception
+stream_entire_sstables: true
+stream_throughput_outbound: 24MiB/s
+sasi_indexes_enabled: true
+materialized_views_enabled: true
+file_cache_enabled: true
diff --git a/test/conf/cassandra-pem-sslcontextfactory-with-passwordfile.yaml 
b/test/conf/cassandra-pem-sslcontextfactory-with-passwordfile.yaml
new file mode 100644
index 0000000000..19ef0f3cd7
--- /dev/null
+++ b/test/conf/cassandra-pem-sslcontextfactory-with-passwordfile.yaml
@@ -0,0 +1,152 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+#
+# Testing for pluggable ssl_context_factory option for client and server 
encryption options with a valid and a missing
+# implementation classes.
+#
+cluster_name: Test Cluster
+# memtable_allocation_type: heap_buffers
+memtable_allocation_type: offheap_objects
+commitlog_sync: periodic
+commitlog_sync_period: 10s
+commitlog_segment_size: 5MiB
+commitlog_directory: build/test/cassandra/commitlog
+# commitlog_compression:
+# - class_name: LZ4Compressor
+cdc_raw_directory: build/test/cassandra/cdc_raw
+cdc_enabled: false
+hints_directory: build/test/cassandra/hints
+partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
+listen_address: 127.0.0.1
+storage_port: 7012
+ssl_storage_port: 17012
+start_native_transport: true
+native_transport_port: 9042
+column_index_size: 4KiB
+saved_caches_directory: build/test/cassandra/saved_caches
+data_file_directories:
+    - build/test/cassandra/data
+disk_access_mode: mmap_index_only
+seed_provider:
+    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
+      parameters:
+          - seeds: "127.0.0.1:7012"
+endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
+dynamic_snitch: true
+client_encryption_options:
+    ssl_context_factory:
+        class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+        parameters:
+            private_key: |
+             -----BEGIN ENCRYPTED PRIVATE KEY-----
+             MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
+             g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
+             xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
+             L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
+             sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
+             f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
+             RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
+             0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
+             evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
+             tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
+             wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
+             K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
+             zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
+             mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
+             WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
+             jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
+             eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
+             DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
+             AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
+             Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
+             Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
+             ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
+             bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
+             hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
+             RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
+             pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
+             FujZhqbKUDbYAcqTkoQ=
+             -----END ENCRYPTED PRIVATE KEY-----
+             -----BEGIN CERTIFICATE-----
+             MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
+             bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
+             VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
+             Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
+             EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
+             a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
+             FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+             MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
+             ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
+             q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
+             TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
+             TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
+             YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
+             N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
+             iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
+             IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
+             6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
+             qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
+             HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
+             n3MVF9w=
+             -----END CERTIFICATE-----
+            trusted_certificates: |
+              -----BEGIN CERTIFICATE-----
+              MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
+              bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
+              VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
+              Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
+              EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
+              a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
+              FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+              MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
+              ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
+              q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
+              TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
+              TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
+              YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
+              N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
+              iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
+              IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
+              6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
+              qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
+              HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
+              n3MVF9w=
+              -----END CERTIFICATE-----
+    keystore_password_file: 
test/conf/cassandra_ssl_test_keystore_passwordfile.txt
+server_encryption_options:
+    ssl_context_factory:
+        class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+    internode_encryption: none
+    keystore: test/conf/cassandra_ssl_test.keystore.pem
+    keystore_password_file: 
test/conf/cassandra_ssl_test_keystore_passwordfile.txt
+    truststore: test/conf/cassandra_ssl_test.truststore.pem
+incremental_backups: true
+concurrent_compactors: 4
+compaction_throughput: 0MiB/s
+row_cache_class_name: org.apache.cassandra.cache.OHCProvider
+row_cache_size: 16MiB
+user_defined_functions_enabled: true
+scripted_user_defined_functions_enabled: false
+prepared_statements_cache_size: 1MiB
+corrupted_tombstone_strategy: exception
+stream_entire_sstables: true
+stream_throughput_outbound: 24MiB/s
+sasi_indexes_enabled: true
+materialized_views_enabled: true
+file_cache_enabled: true
diff --git a/test/conf/cassandra_ssl_test_keystore_passwordfile.txt 
b/test/conf/cassandra_ssl_test_keystore_passwordfile.txt
new file mode 100644
index 0000000000..03ef327b7a
--- /dev/null
+++ b/test/conf/cassandra_ssl_test_keystore_passwordfile.txt
@@ -0,0 +1 @@
+cassandra
\ No newline at end of file
diff --git a/test/conf/cassandra_ssl_test_outbound_keystore_password.txt 
b/test/conf/cassandra_ssl_test_outbound_keystore_password.txt
new file mode 100644
index 0000000000..03ef327b7a
--- /dev/null
+++ b/test/conf/cassandra_ssl_test_outbound_keystore_password.txt
@@ -0,0 +1 @@
+cassandra
\ No newline at end of file
diff --git a/test/conf/cassandra_ssl_test_truststore_passwordfile.txt 
b/test/conf/cassandra_ssl_test_truststore_passwordfile.txt
new file mode 100644
index 0000000000..03ef327b7a
--- /dev/null
+++ b/test/conf/cassandra_ssl_test_truststore_passwordfile.txt
@@ -0,0 +1 @@
+cassandra
\ No newline at end of file
diff --git 
a/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java 
b/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java
index 317c8ec626..5e6d26b817 100644
--- a/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java
+++ b/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java
@@ -81,6 +81,54 @@ public class EncryptionOptionsEqualityTest
         assertEquals(encryptionOptions1.hashCode(), 
encryptionOptions2.hashCode());
     }
 
+    @Test
+    public void testKeystoreOptionsWithPasswordFile() {
+        EncryptionOptions encryptionOptions1 =
+        new EncryptionOptions()
+        .withStoreType("JKS")
+        .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+        .withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
+        .withTrustStore(TlsTestUtils.SERVER_TRUSTSTORE_PATH)
+        
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE)
+        .withProtocol("TLSv1.1")
+        .withRequireClientAuth(REQUIRED)
+        .withRequireEndpointVerification(false);
+
+        EncryptionOptions encryptionOptions2 =
+        new EncryptionOptions()
+        .withStoreType("JKS")
+        .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+        .withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
+        .withTrustStore(TlsTestUtils.SERVER_TRUSTSTORE_PATH)
+        
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE)
+        .withProtocol("TLSv1.1")
+        .withRequireClientAuth(REQUIRED)
+        .withRequireEndpointVerification(false);
+
+        assertEquals(encryptionOptions1, encryptionOptions2);
+        assertEquals(encryptionOptions1.hashCode(), 
encryptionOptions2.hashCode());
+    }
+
+    @Test
+    public void testMismatchForKeystoreOptionsWithPasswordFile()
+    {
+        EncryptionOptions.ServerEncryptionOptions encryptionOptions1 = 
createServerEncryptionOptions();
+        EncryptionOptions.ServerEncryptionOptions encryptionOptions2 = 
createServerEncryptionOptions();
+
+        encryptionOptions1 = encryptionOptions1
+                             .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+                             .withKeyStorePassword(null)
+                             
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE);
+
+        encryptionOptions2 = encryptionOptions2
+                             .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+                             .withKeyStorePassword(null)
+                             
.withKeyStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE);
+
+        assertNotEquals(encryptionOptions1, encryptionOptions2);
+        assertNotEquals(encryptionOptions1.hashCode(), 
encryptionOptions2.hashCode());
+    }
+
     @Test
     public void testSameCustomSslContextFactoryImplementation() {
 
diff --git a/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java 
b/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java
index a295095dbb..5ef08eb060 100644
--- a/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java
+++ b/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java
@@ -61,8 +61,8 @@ public class EncryptionOptionsTest
         {
             return new EncryptionOptionsTestCase(new EncryptionOptions(new 
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
                                                                                
               new HashMap<>()),
-                                                                       
keystorePath, "dummypass",
-                                                                       
"dummytruststore", "dummypass",
+                                                                       
keystorePath, "dummypass", null,
+                                                                       
"dummytruststore", "dummypass", null,
                                                                        
Collections.emptyList(), null, null, null, "JKS", "false", false, enabled, 
optional, null, null)
                                                  .applyConfig(),
                                                  expected,
@@ -75,8 +75,8 @@ public class EncryptionOptionsTest
         {
             return new EncryptionOptionsTestCase(new EncryptionOptions(new 
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
                                                                                
               customSslContextFactoryParams),
-                                                                       
keystorePath, "dummypass",
-                                                                       
"dummytruststore", "dummypass",
+                                                                       
keystorePath, "dummypass", null,
+                                                                       
"dummytruststore", "dummypass", null,
                                                                        
Collections.emptyList(), null, null, null, "JKS", "false", false, enabled, 
optional, null, null)
                                                  .applyConfig(),
                                                  expected,
@@ -127,7 +127,10 @@ public class EncryptionOptionsTest
                                                          
EncryptionOptions.TlsEncryptionPolicy expected)
         {
             return new ServerEncryptionOptionsTestCase(new 
EncryptionOptions.ServerEncryptionOptions(new 
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
-                                                                               
                                             new HashMap<>()), keystorePath, 
"dummypass", keystorePath, "dummypass", "dummytruststore", "dummypass",
+                                                                               
                                             new HashMap<>()),
+                                                                               
                      keystorePath, "dummypass", null,
+                                                                               
                      keystorePath, "dummypass", null,
+                                                                               
                      "dummytruststore", "dummypass", null,
                                                                                
                Collections.emptyList(), null, null, null, "JKS", "false", 
false, optional, internodeEncryption, false, null, null)
                                                        .applyConfig(),
                                                  expected,
diff --git 
a/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java 
b/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java
index 2916f0d460..d6d936ba0e 100644
--- 
a/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java
+++ 
b/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java
@@ -31,6 +31,7 @@ import org.junit.Test;
 import org.apache.cassandra.config.EncryptionOptions;
 import org.apache.cassandra.config.ParameterizedClass;
 import org.apache.cassandra.distributed.shared.WithProperties;
+import org.apache.cassandra.exceptions.ConfigurationException;
 import org.apache.cassandra.transport.TlsTestUtils;
 
 import static 
org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
@@ -89,7 +90,7 @@ public class FileBasedSslContextFactoryTest
     }
 
     /**
-     * Tests that empty {@code keystore_password} and {@code 
outbound_keystore_password} is allowed.
+     * Tests that empty {@code keystore_password} and {@code 
outbound_keystore_password} are allowed.
      */
     @Test
     public void testEmptyKeystorePasswords() throws SSLException
@@ -103,7 +104,7 @@ public class FileBasedSslContextFactoryTest
         
Assert.assertEquals("org.apache.cassandra.security.FileBasedSslContextFactoryTest$TestFileBasedSSLContextFactory",
                             
localEncryptionOptions.ssl_context_factory.class_name);
         Assert.assertEquals("keystore_password must be empty", "", 
localEncryptionOptions.keystore_password);
-        Assert.assertEquals("outbound_keystore_password must empty", "", 
localEncryptionOptions.outbound_keystore_password);
+        Assert.assertEquals("outbound_keystore_password must be empty", "", 
localEncryptionOptions.outbound_keystore_password);
 
         TestFileBasedSSLContextFactory sslContextFactory =
         (TestFileBasedSSLContextFactory) 
localEncryptionOptions.sslContextFactoryInstance;
@@ -112,6 +113,46 @@ public class FileBasedSslContextFactoryTest
         sslContextFactory.buildTrustManagerFactory();
     }
 
+    @Test
+    public void testKeystorePasswordFile() throws SSLException
+    {
+        // Here we only override password configuration and specify 
password_file configuration since keystore paths
+        // are already loaded in the `encryptionOptions`
+        EncryptionOptions.ServerEncryptionOptions localEncryptionOptions = 
encryptionOptions
+                                                                           
.withKeyStorePassword(null)
+                                                                           
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
+                                                                           
.withOutboundKeystorePassword(null)
+                                                                           
.withOutboundKeystorePasswordFile(TlsTestUtils.SERVER_OUTBOUND_KEYSTORE_PASSWORD_FILE)
+                                                                           
.withTrustStorePassword(null)
+                                                                           
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE);
+
+        
Assert.assertEquals("org.apache.cassandra.security.FileBasedSslContextFactoryTest$TestFileBasedSSLContextFactory",
+                            
localEncryptionOptions.ssl_context_factory.class_name);
+        TestFileBasedSSLContextFactory sslContextFactory =
+        (TestFileBasedSSLContextFactory) 
localEncryptionOptions.sslContextFactoryInstance;
+
+        sslContextFactory.buildKeyManagerFactory();
+        sslContextFactory.buildTrustManagerFactory();
+    }
+
+    /**
+     * Tests for missing password configuration and non-existance file 
specified in the password_file configuration.
+     * @throws SSLException
+     */
+    @Test(expected =  ConfigurationException.class)
+    public void testBadKeystorePasswordFile() throws SSLException
+    {
+        // Here we only override password configuration and specify 
password_file configuration since keystore paths
+        // are already loaded in the `encryptionOptions`
+        encryptionOptions
+        .withKeyStorePassword(null)
+        .withKeyStorePasswordFile("/path/to/non-existance-password-file")
+        .withOutboundKeystorePassword(null)
+        
.withOutboundKeystorePasswordFile("/path/to/non-existance-password-file")
+        .withTrustStorePassword(null)
+        .withTrustStorePasswordFile("/path/to/non-existance-password-file");
+    }
+
     /**
      * Tests that an absent keystore_password for the {@code keystore} is 
disallowed.
      */
diff --git 
a/test/unit/org/apache/cassandra/security/FileBasedStoreContextTest.java 
b/test/unit/org/apache/cassandra/security/FileBasedStoreContextTest.java
new file mode 100644
index 0000000000..cd1e52c61f
--- /dev/null
+++ b/test/unit/org/apache/cassandra/security/FileBasedStoreContextTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cassandra.security;
+
+import org.junit.Test;
+
+import org.apache.cassandra.exceptions.ConfigurationException;
+
+import static org.junit.Assert.assertEquals;
+
+public class FileBasedStoreContextTest
+{
+    /**
+     * Tests default behavior without keystore password file specified.
+     */
+    @Test
+    public void testPasswordConfiguration()
+    {
+        FileBasedSslContextFactory.FileBasedStoreContext wrapper = new 
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
 "cassandra", null);
+        assertEquals("Password must be loaded from the direct configuration", 
"cassandra", wrapper.password);
+    }
+
+    /**
+     * Tests behavior when password for keystore is specified via a password 
file.
+     */
+    @Test
+    public void testPasswordFileConfiguration()
+    {
+        FileBasedSslContextFactory.FileBasedStoreContext wrapper = new 
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
 null, "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
+        assertEquals("Password must be loaded from the password file", 
"cassandra", wrapper.password);
+    }
+
+    /**
+     * Tests when password for keystore is specified via password 
configuration and a password file both.
+     */
+    @Test
+    public void testPasswordAndPasswordFileConfiguration()
+    {
+        String expectedPassword = "cassandra123";
+        FileBasedSslContextFactory.FileBasedStoreContext wrapper = new 
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
 expectedPassword, "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
+        assertEquals("Password configuration must take precedence", 
expectedPassword, wrapper.password);
+    }
+
+    /**
+     * Tests behavior when a non-existing password file is specified for 
keystore's password and password configuration
+     * is {@code null}.
+     */
+    @Test(expected = ConfigurationException.class)
+    public void testMissingPasswordFile()
+    {
+        new 
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
 null, "passwordfile-that-doesnotexist");
+    }
+
+    /**
+     * Tests behavior when non-null empty password is specified in the 
password configuration.
+     * The empty password via the configuration must take precedence in this 
case.
+     */
+    @Test
+    public void testBlankPasswordConfiguration()
+    {
+        FileBasedSslContextFactory.FileBasedStoreContext wrapper = new 
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
 "", "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
+        assertEquals("Password must be loaded from the direct configuration", 
"", wrapper.password);
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryConfigWithPasswordFileTest.java
 
b/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryConfigWithPasswordFileTest.java
new file mode 100644
index 0000000000..fc837a3729
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryConfigWithPasswordFileTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cassandra.security;
+
+import javax.net.ssl.SSLException;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.config.Config;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.distributed.shared.WithProperties;
+
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
+import static org.junit.Assert.assertEquals;
+
+public class PEMBasedSslContextFactoryConfigWithPasswordFileTest
+{
+    static WithProperties properties;
+
+    @BeforeClass
+    public static void setupDatabaseDescriptor()
+    {
+        properties = new WithProperties().set(CASSANDRA_CONFIG, 
"cassandra-pem-sslcontextfactory-with-passwordfile.yaml");
+    }
+
+    @AfterClass
+    public static void tearDownDatabaseDescriptor()
+    {
+        properties.close();
+    }
+
+    @Test
+    public void testHappyPathInlinePEM() throws SSLException
+    {
+
+        Config config = DatabaseDescriptor.loadConfig();
+        config.client_encryption_options.applyConfig();
+
+        assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
+                            
config.client_encryption_options.ssl_context_factory.class_name);
+        
assertEquals(config.client_encryption_options.ssl_context_factory.class_name,
+                            
config.client_encryption_options.sslContextFactoryInstance.getClass().getName());
+        PEMBasedSslContextFactory sslContextFactory =
+        (PEMBasedSslContextFactory) 
config.client_encryption_options.sslContextFactoryInstance;
+        sslContextFactory.buildKeyManagerFactory();
+        sslContextFactory.buildTrustManagerFactory();
+    }
+
+    @Test
+    public void testHappyPathFileBasedPEM() throws SSLException
+    {
+
+        Config config = DatabaseDescriptor.loadConfig();
+        config.server_encryption_options.applyConfig();
+
+        assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
+                            
config.server_encryption_options.ssl_context_factory.class_name);
+        
assertEquals(config.server_encryption_options.ssl_context_factory.class_name,
+                            
config.server_encryption_options.sslContextFactoryInstance.getClass().getName());
+        PEMBasedSslContextFactory sslContextFactory =
+        (PEMBasedSslContextFactory) 
config.server_encryption_options.sslContextFactoryInstance;
+        sslContextFactory.buildKeyManagerFactory();
+        sslContextFactory.buildTrustManagerFactory();
+    }
+}
diff --git a/test/unit/org/apache/cassandra/transport/TlsTestUtils.java 
b/test/unit/org/apache/cassandra/transport/TlsTestUtils.java
index f3994e7613..30a6054127 100644
--- a/test/unit/org/apache/cassandra/transport/TlsTestUtils.java
+++ b/test/unit/org/apache/cassandra/transport/TlsTestUtils.java
@@ -58,16 +58,19 @@ public class TlsTestUtils
     public static String SERVER_KEYSTORE_PATH_PEM = 
"test/conf/cassandra_ssl_test.keystore.pem";
     public static String SERVER_KEYSTORE_PATH_UNENCRYPTED_PEM = 
"test/conf/cassandra_ssl_test.unencrypted_keystore.pem";
     public static String SERVER_KEYSTORE_PASSWORD = "cassandra";
+    public static String SERVER_KEYSTORE_PASSWORD_FILE = 
"test/conf/cassandra_ssl_test_keystore_passwordfile.txt";
 
     public static String SERVER_KEYSTORE_ENDPOINT_VERIFY_PATH = 
"test/conf/cassandra_ssl_test_endpoint_verify.keystore";
     public static String SERVER_KEYSTORE_ENDPOINT_VERIFY_PASSWORD = 
"cassandra";
 
     public static String SERVER_OUTBOUND_KEYSTORE_PATH = 
"test/conf/cassandra_ssl_test_outbound.keystore";
     public static String SERVER_OUTBOUND_KEYSTORE_PASSWORD = "cassandra";
+    public static String SERVER_OUTBOUND_KEYSTORE_PASSWORD_FILE = 
"test/conf/cassandra_ssl_test_outbound_keystore_password.txt";
 
     public static String SERVER_TRUSTSTORE_PATH = 
"test/conf/cassandra_ssl_test.truststore";
     public static String SERVER_TRUSTSTORE_PEM_PATH = 
"test/conf/cassandra_ssl_test.truststore.pem";
     public static String SERVER_TRUSTSTORE_PASSWORD = "cassandra";
+    public static String SERVER_TRUSTSTORE_PASSWORD_FILE = 
"test/conf/cassandra_ssl_test_truststore_passwordfile.txt";
 
     // To regenerate:
     // 1. generate keystore
diff --git 
a/test/unit/org/apache/cassandra/utils/jmx/JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest.java
 
b/test/unit/org/apache/cassandra/utils/jmx/JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest.java
new file mode 100644
index 0000000000..ae2b7e6128
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/utils/jmx/JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cassandra.utils.jmx;
+
+import java.net.InetAddress;
+import java.util.Map;
+import javax.management.remote.rmi.RMIConnectorServer;
+import javax.net.ssl.SSLException;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.JMXServerOptions;
+import org.apache.cassandra.distributed.shared.WithProperties;
+import org.apache.cassandra.utils.JMXServerUtils;
+
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.COM_SUN_MANAGEMENT_JMXREMOTE_SSL;
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.JAVAX_RMI_SSL_CLIENT_ENABLED_CIPHER_SUITES;
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.JAVAX_RMI_SSL_CLIENT_ENABLED_PROTOCOLS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for JMX SSL configuration specified in the cassandra.yaml using 
jmx_encryption_options with password files for
+ * keystore and truststores as applicable.
+ * @see JMXSslConfiguredWithYamlFileOptionsTest
+ */
+public class JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest
+{
+    static WithProperties properties;
+
+    @BeforeClass
+    public static void setupDatabaseDescriptor()
+    {
+        properties = new WithProperties().set(CASSANDRA_CONFIG, 
"cassandra-jmx-sslconfig-with-passwordfile.yaml");
+        DatabaseDescriptor.daemonInitialization();
+    }
+
+    @AfterClass
+    public static void tearDownDatabaseDescriptor()
+    {
+        properties.close();
+    }
+
+    @Test
+    public void testYamlFileJmxEncryptionOptions() throws SSLException
+    {
+        JMXServerOptions serverOptions = 
DatabaseDescriptor.getJmxServerOptions();
+        String expectedProtocols = 
StringUtils.join(serverOptions.jmx_encryption_options.getAcceptedProtocols(), 
",");
+        String expectedCipherSuites = 
StringUtils.join(serverOptions.jmx_encryption_options.cipherSuitesArray(), ",");
+
+        InetAddress serverAddress = InetAddress.getLoopbackAddress();
+
+        try (WithProperties ignored = JMXSslPropertiesUtil.use(false))
+        {
+            Map<String, Object> env = 
JMXServerUtils.configureJmxSocketFactories(serverAddress, serverOptions);
+            assertTrue("com.sun.management.jmxremote.ssl must be true", 
COM_SUN_MANAGEMENT_JMXREMOTE_SSL.getBoolean());
+            assertNotNull("ServerSocketFactory must not be null", 
env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE));
+            assertTrue("RMI_SERVER_SOCKET_FACTORY must be of 
JMXSslRMIServerSocketFactory type", 
env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE) instanceof 
SslRMIServerSocketFactory);
+            assertNotNull("ClientSocketFactory must not be null", 
env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE));
+            assertNotNull("com.sun.jndi.rmi.factory.socket must be set in the 
env", env.get("com.sun.jndi.rmi.factory.socket"));
+            assertEquals("javax.rmi.ssl.client.enabledProtocols must match", 
expectedProtocols, JAVAX_RMI_SSL_CLIENT_ENABLED_PROTOCOLS.getString());
+            assertEquals("javax.rmi.ssl.client.enabledCipherSuites must 
match", expectedCipherSuites, 
JAVAX_RMI_SSL_CLIENT_ENABLED_CIPHER_SUITES.getString());
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to