1717
1818package org .apache .spark
1919
20- import java .io .File
20+ import java .io .{File , FileInputStream }
21+ import java .security .{KeyStore , NoSuchAlgorithmException }
22+ import javax .net .ssl .{KeyManager , KeyManagerFactory , SSLContext , TrustManager , TrustManagerFactory }
2123
2224import com .typesafe .config .{Config , ConfigFactory , ConfigValueFactory }
2325import org .eclipse .jetty .util .ssl .SslContextFactory
@@ -38,7 +40,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory
3840 * @param trustStore a path to the trust-store file
3941 * @param trustStorePassword a password to access the trust-store file
4042 * @param protocol SSL protocol (remember that SSLv3 was compromised) supported by Java
41- * @param enabledAlgorithms a set of encryption algorithms to use
43+ * @param enabledAlgorithms a set of encryption algorithms that may be used
4244 */
4345private [spark] case class SSLOptions (
4446 enabled : Boolean = false ,
@@ -48,7 +50,8 @@ private[spark] case class SSLOptions(
4850 trustStore : Option [File ] = None ,
4951 trustStorePassword : Option [String ] = None ,
5052 protocol : Option [String ] = None ,
51- enabledAlgorithms : Set [String ] = Set .empty) {
53+ enabledAlgorithms : Set [String ] = Set .empty)
54+ extends Logging {
5255
5356 /**
5457 * Creates a Jetty SSL context factory according to the SSL settings represented by this object.
@@ -63,7 +66,7 @@ private[spark] case class SSLOptions(
6366 trustStorePassword.foreach(sslContextFactory.setTrustStorePassword)
6467 keyPassword.foreach(sslContextFactory.setKeyManagerPassword)
6568 protocol.foreach(sslContextFactory.setProtocol)
66- sslContextFactory.setIncludeCipherSuites(enabledAlgorithms .toSeq: _* )
69+ sslContextFactory.setIncludeCipherSuites(supportedAlgorithms .toSeq: _* )
6770
6871 Some (sslContextFactory)
6972 } else {
@@ -94,14 +97,44 @@ private[spark] case class SSLOptions(
9497 .withValue(" akka.remote.netty.tcp.security.protocol" ,
9598 ConfigValueFactory .fromAnyRef(protocol.getOrElse(" " )))
9699 .withValue(" akka.remote.netty.tcp.security.enabled-algorithms" ,
97- ConfigValueFactory .fromIterable(enabledAlgorithms .toSeq))
100+ ConfigValueFactory .fromIterable(supportedAlgorithms .toSeq))
98101 .withValue(" akka.remote.netty.tcp.enable-ssl" ,
99102 ConfigValueFactory .fromAnyRef(true )))
100103 } else {
101104 None
102105 }
103106 }
104107
108+ /*
109+ * The supportedAlgorithms set is a subset of the enabledAlgorithms that
110+ * are supported by the current Java security provider for this protocol.
111+ */
112+ private val supportedAlgorithms : Set [String ] = {
113+ var context : SSLContext = null
114+ try {
115+ context = SSLContext .getInstance(protocol.orNull)
116+ /* The set of supported algorithms does not depend upon the keys, trust, or
117+ rng, although they will influence which algorithms are eventually used. */
118+ context.init(null , null , null )
119+ } catch {
120+ case npe : NullPointerException =>
121+ logDebug(" No SSL protocol specified" )
122+ context = SSLContext .getDefault
123+ case nsa : NoSuchAlgorithmException =>
124+ logDebug(s " No support for requested SSL protocol ${protocol.get}" )
125+ context = SSLContext .getDefault
126+ }
127+
128+ val providerAlgorithms = context.getServerSocketFactory.getSupportedCipherSuites.toSet
129+
130+ // Log which algorithms we are discarding
131+ (enabledAlgorithms &~ providerAlgorithms).foreach { cipher =>
132+ logDebug(s " Discarding unsupported cipher $cipher" )
133+ }
134+
135+ enabledAlgorithms & providerAlgorithms
136+ }
137+
105138 /** Returns a string representation of this SSLOptions with all the passwords masked. */
106139 override def toString : String = s " SSLOptions{enabled= $enabled, " +
107140 s " keyStore= $keyStore, keyStorePassword= ${keyStorePassword.map(_ => " xxx" )}, " +
0 commit comments