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

mridulm80 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 83434af22284 [SPARK-46132][CORE] Support key password for JKS keys for 
RPC SSL
83434af22284 is described below

commit 83434af22284482d4e805d8be625f733b074928b
Author: Hasnain Lakhani <hasnain.lakh...@databricks.com>
AuthorDate: Tue Dec 12 23:35:13 2023 -0600

    [SPARK-46132][CORE] Support key password for JKS keys for RPC SSL
    
    ### What changes were proposed in this pull request?
    
    Add support for a separate key password in addition to the key store 
password for JKS keys. This is needed for keys which may have a key password in 
addition to a key store password. We already had this support for the UI SSL 
support, so for compatibility we should have it here.
    
    This wasn't done earlier as I wasn't sure how to implement it but the 
discussion in https://github.com/apache/spark/pull/43998#discussion_r1406993411 
suggested the right way.
    
    ### Why are the changes needed?
    
    These are needed to support users who may have such keys configured.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No
    
    ### How was this patch tested?
    
    Added some unit tests
    
    ```
    build/sbt
    > project network-common
    > testOnly
    ```
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    No
    
    Closes #44264 from hasnain-db/separate-pw.
    
    Authored-by: Hasnain Lakhani <hasnain.lakh...@databricks.com>
    Signed-off-by: Mridul Muralidharan <mridul<at>gmail.com>
---
 .../org/apache/spark/network/ssl/SSLFactory.java   |  11 ++-
 .../apache/spark/network/ssl/SSLFactorySuite.java  | 104 +++++++++++++++++++++
 2 files changed, 111 insertions(+), 4 deletions(-)

diff --git 
a/common/network-common/src/main/java/org/apache/spark/network/ssl/SSLFactory.java
 
b/common/network-common/src/main/java/org/apache/spark/network/ssl/SSLFactory.java
index 0ae83eb5fd68..82951d213011 100644
--- 
a/common/network-common/src/main/java/org/apache/spark/network/ssl/SSLFactory.java
+++ 
b/common/network-common/src/main/java/org/apache/spark/network/ssl/SSLFactory.java
@@ -89,7 +89,7 @@ public class SSLFactory {
 
   private void initJdkSslContext(final Builder b)
           throws IOException, GeneralSecurityException {
-    this.keyManagers = keyManagers(b.keyStore, b.keyStorePassword);
+    this.keyManagers = keyManagers(b.keyStore, b.keyPassword, 
b.keyStorePassword);
     this.trustManagers = trustStoreManagers(
       b.trustStore, b.trustStorePassword,
       b.trustStoreReloadingEnabled, b.trustStoreReloadIntervalMs
@@ -391,13 +391,16 @@ public class SSLFactory {
     }
   }
 
-  private static KeyManager[] keyManagers(File keyStore, String 
keyStorePassword)
+  private static KeyManager[] keyManagers(
+    File keyStore, String keyPassword, String keyStorePassword)
       throws NoSuchAlgorithmException, CertificateException,
           KeyStoreException, IOException, UnrecoverableKeyException {
     KeyManagerFactory factory = KeyManagerFactory.getInstance(
       KeyManagerFactory.getDefaultAlgorithm());
-    char[] passwordCharacters = keyStorePassword != null? 
keyStorePassword.toCharArray() : null;
-    factory.init(loadKeyStore(keyStore, passwordCharacters), 
passwordCharacters);
+    char[] keyStorePasswordChars = keyStorePassword != null? 
keyStorePassword.toCharArray() : null;
+    char[] keyPasswordChars = keyPassword != null?
+      keyPassword.toCharArray() : keyStorePasswordChars;
+    factory.init(loadKeyStore(keyStore, keyStorePasswordChars), 
keyPasswordChars);
     return factory.getKeyManagers();
   }
 
diff --git 
a/common/network-common/src/test/java/org/apache/spark/network/ssl/SSLFactorySuite.java
 
b/common/network-common/src/test/java/org/apache/spark/network/ssl/SSLFactorySuite.java
new file mode 100644
index 000000000000..922d0f22c25c
--- /dev/null
+++ 
b/common/network-common/src/test/java/org/apache/spark/network/ssl/SSLFactorySuite.java
@@ -0,0 +1,104 @@
+/*
+ * 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.spark.network.ssl;
+
+import java.io.File;
+
+import io.netty.buffer.ByteBufAllocator;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import static org.apache.spark.network.ssl.SslSampleConfigs.*;
+
+public class SSLFactorySuite {
+
+  @Test
+  public void testBuildWithJKSAndPEMWithPasswords() throws Exception {
+    SSLFactory factory = new SSLFactory.Builder()
+      .openSslEnabled(true)
+      .requestedProtocol("TLSv1.3")
+      .keyStore(new File(SslSampleConfigs.keyStorePath), "password")
+      .privateKey(new File(SslSampleConfigs.privateKeyPath))
+      .privateKeyPassword("password")
+      .keyPassword("password")
+      .certChain(new File(SslSampleConfigs.certChainPath))
+      .trustStore(
+        new File(SslSampleConfigs.trustStorePath),
+        "password",
+        true,
+        10000
+      )
+      .build();
+    factory.createSSLEngine(true, ByteBufAllocator.DEFAULT);
+  }
+
+  @Test
+  public void testBuildWithJKSAndPEMWithOnlyJKSPassword() throws Exception {
+    SSLFactory factory = new SSLFactory.Builder()
+      .openSslEnabled(true)
+      .requestedProtocol("TLSv1.3")
+      .keyStore(new File(SslSampleConfigs.keyStorePath), "password")
+      .privateKey(new File(SslSampleConfigs.unencryptedPrivateKeyPath))
+      .keyPassword("password")
+      .certChain(new File(SslSampleConfigs.unencryptedCertChainPath))
+      .trustStore(
+        new File(SslSampleConfigs.trustStorePath),
+        "password",
+        true,
+        10000
+      )
+      .build();
+    factory.createSSLEngine(true, ByteBufAllocator.DEFAULT);
+  }
+
+  @Test
+  public void testBuildWithJKSKeyStorePassword() throws Exception {
+    // if key password is null, fall back to keystore password
+    SSLFactory factory = new SSLFactory.Builder()
+      .requestedProtocol("TLSv1.3")
+      .keyStore(new File(SslSampleConfigs.keyStorePath), "password")
+      .trustStore(
+        new File(SslSampleConfigs.trustStorePath),
+        "password",
+        true,
+        10000
+      )
+      .build();
+    factory.createSSLEngine(true, ByteBufAllocator.DEFAULT);
+  }
+
+  @Test
+  public void testKeyAndKeystorePasswordsAreDistinct() throws Exception {
+    assertThrows(RuntimeException.class, () -> {
+      // Set the wrong password, validate we fail
+      SSLFactory factory = new SSLFactory.Builder()
+        .requestedProtocol("TLSv1.3")
+        .keyStore(new File(SslSampleConfigs.keyStorePath), "password")
+        .keyPassword("wrong")
+        .trustStore(
+          new File(SslSampleConfigs.trustStorePath),
+          "password",
+          true,
+          10000
+        )
+        .build();
+      factory.createSSLEngine(true, ByteBufAllocator.DEFAULT);
+    });
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@spark.apache.org
For additional commands, e-mail: commits-h...@spark.apache.org

Reply via email to