Skip to content

Commit a5a0f88

Browse files
authored
Merge pull request #446 from mkurz/old_pekko_akka-compat
Bring back a couple of configs and classes
2 parents 169b539 + ae4786b commit a5a0f88

File tree

6 files changed

+279
-3
lines changed

6 files changed

+279
-3
lines changed

build.sbt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ lazy val sslConfigCore = project
2121
mimaReportSignatureProblems := true,
2222
mimaPreviousArtifacts := Set("com.typesafe" %% "ssl-config-core" % "0.7.0"),
2323
mimaBinaryIssueFilters ++= Seq(
24+
ProblemFilters
25+
.exclude[IncompatibleResultTypeProblem]("com.typesafe.sslconfig.ssl.SSLConfigSettings.<init>$default$10"),
26+
ProblemFilters
27+
.exclude[IncompatibleResultTypeProblem]("com.typesafe.sslconfig.ssl.SSLConfigSettings.<init>$default$11"),
28+
ProblemFilters
29+
.exclude[IncompatibleResultTypeProblem]("com.typesafe.sslconfig.ssl.SSLConfigSettings.<init>$default$9"),
30+
ProblemFilters
31+
.exclude[IncompatibleResultTypeProblem]("com.typesafe.sslconfig.ssl.SSLConfigSettings.<init>$default$7"),
32+
ProblemFilters
33+
.exclude[IncompatibleResultTypeProblem]("com.typesafe.sslconfig.ssl.SSLConfigSettings.<init>$default$8"),
2434
),
2535
libraryDependencies ++= Dependencies.sslConfigCore,
2636
libraryDependencies ++= Dependencies.testDependencies,

ssl-config-core/src/main/resources/reference.conf

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,40 @@ ssl-config {
2222
# The enabled protocols. If empty, uses the platform default.
2323
enabledProtocols = ["TLSv1.3", "TLSv1.2"]
2424

25+
# The hostname verifier class.
26+
# If non null, should be the fully qualify classname of a class that implements HostnameVerifier,
27+
# otherwise the default will be used.
28+
#
29+
# BE AWARE:
30+
# This config is kept for compatibilby only and is NOT used by:
31+
# - SSL Config itself
32+
# - Play WS
33+
# This config is used by the following 3rd party libraries and their versions:
34+
# - Pekko < v2, Pekko HTTP < v2
35+
# - Akka <= v2.8, Akka HTTP <= v10.5
36+
#hostnameVerifierClass = null
37+
38+
#sslParameters {
39+
#
40+
# BE AWARE:
41+
# These configs are kept for compatibilby only and are NOT used by:
42+
# - SSL Config itself
43+
# - Play WS
44+
# These config are used by the following 3rd party libraries and their versions:
45+
# - Pekko HTTP < v2
46+
# - Akka HTTP <= v10.5
47+
#
48+
# # translates to a setNeedClientAuth / setWantClientAuth calls
49+
# # "default" – leaves the (which for JDK8 means wantClientAuth and needClientAuth are set to false.)
50+
# # "none" – `setNeedClientAuth(false)`
51+
# # "want" – `setWantClientAuth(true)`
52+
# # "need" – `setNeedClientAuth(true)`
53+
# clientAuth = "default"
54+
#
55+
# # protocols (names)
56+
# protocols = []
57+
#}
58+
2559
# Configuration for the key manager
2660
keyManager {
2761
# The key manager algorithm. If empty, uses the platform default.
@@ -82,6 +116,32 @@ ssl-config {
82116
# If non null, overrides the platform default for whether unsafe renegotiation should be allowed.
83117
allowUnsafeRenegotiation = null
84118

119+
# Whether hostname verification should be disabled
120+
#
121+
# BE AWARE:
122+
# This config is kept for compatibilby only and is NOT used by:
123+
# - SSL Config itself
124+
# - Play WS
125+
# This config is used by the following 3rd party libraries and their versions:
126+
# - Pekko < v2, Pekko HTTP < v2
127+
# - Akka <= v2.8, Akka HTTP <= v10.5
128+
# - Gigahorse (https://github.com/eed3si9n/gigahorse)
129+
#disableHostnameVerification = false
130+
131+
# Whether the SNI (Server Name Indication) TLS extension should be disabled
132+
# This setting MAY be respected by client libraries.
133+
#
134+
# https://tools.ietf.org/html/rfc3546#sectiom-3.1
135+
#
136+
# BE AWARE:
137+
# This config is kept for compatibilby only and is NOT used by:
138+
# - SSL Config itself
139+
# - Play WS
140+
# This config is used by the following 3rd party libraries and their versions:
141+
# - Pekko < v2, Pekko HTTP < v2
142+
# - Akka <= v2.8, Akka HTTP <= v10.5
143+
#disableSNI = false
144+
85145
# Whether any certificate should be accepted or not
86146
acceptAnyCertificate = false
87147
}

ssl-config-core/src/main/scala/com/typesafe/sslconfig/ssl/Config.scala

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import java.net.URL
99
import java.security.KeyStore
1010
import java.security.SecureRandom
1111
import java.util.Optional
12+
import javax.net.ssl.HostnameVerifier
1213
import javax.net.ssl.KeyManagerFactory
1314
import javax.net.ssl.TrustManagerFactory
1415

1516
import scala.collection.immutable
1617
import scala.language.existentials
1718

1819
import com.typesafe.config.Config
20+
import com.typesafe.config.ConfigFactory
1921
import com.typesafe.sslconfig.util.EnrichedConfig
2022
import com.typesafe.sslconfig.util.LoggerFactory
2123

@@ -259,34 +261,40 @@ object SSLDebugConfig {
259261
* default.
260262
* @param disableHostnameVerification Whether hostname verification should be disabled. Be aware: SSL Config itself is not using this config.
261263
* However, it was kept because 3rd party libraries rely on its existence.
264+
* @param disableSNI Whether SNI should be disabled (up to client library to respect this setting or not). Be aware: SSL Config itself is not using this config.
265+
* However, it was kept because 3rd party libraries rely on its existence.
262266
* @param acceptAnyCertificate Whether any X.509 certificate should be accepted or not.
263267
*/
264268
final class SSLLooseConfig private[sslconfig] (
265269
val acceptAnyCertificate: Boolean = false,
266270
val allowLegacyHelloMessages: Option[Boolean] = None,
267271
val allowUnsafeRenegotiation: Option[Boolean] = None,
268272
val disableHostnameVerification: Boolean = false,
273+
val disableSNI: Boolean = false,
269274
) {
270275

271276
def withAcceptAnyCertificate(value: Boolean): SSLLooseConfig = copy(acceptAnyCertificate = value)
272277
def withAllowLegacyHelloMessages(value: Option[Boolean]): SSLLooseConfig = copy(allowLegacyHelloMessages = value)
273278
def withAllowUnsafeRenegotiation(value: Option[Boolean]): SSLLooseConfig = copy(allowUnsafeRenegotiation = value)
274279
def withDisableHostnameVerification(value: Boolean): SSLLooseConfig = copy(disableHostnameVerification = value)
280+
def withDisableSNI(value: Boolean): SSLLooseConfig = copy(disableSNI = value)
275281

276282
private def copy(
277283
acceptAnyCertificate: Boolean = acceptAnyCertificate,
278284
allowLegacyHelloMessages: Option[Boolean] = allowLegacyHelloMessages,
279285
allowUnsafeRenegotiation: Option[Boolean] = allowUnsafeRenegotiation,
280286
disableHostnameVerification: Boolean = disableHostnameVerification,
287+
disableSNI: Boolean = disableSNI,
281288
): SSLLooseConfig = new SSLLooseConfig(
282289
acceptAnyCertificate = acceptAnyCertificate,
283290
allowLegacyHelloMessages = allowLegacyHelloMessages,
284291
allowUnsafeRenegotiation = allowUnsafeRenegotiation,
285292
disableHostnameVerification = disableHostnameVerification,
293+
disableSNI = disableSNI,
286294
)
287295

288296
override def toString =
289-
s"""SSLLooseConfig(${acceptAnyCertificate},${allowLegacyHelloMessages},${allowUnsafeRenegotiation},${disableHostnameVerification})"""
297+
s"""SSLLooseConfig(${acceptAnyCertificate},${allowLegacyHelloMessages},${allowUnsafeRenegotiation},${disableHostnameVerification},${disableSNI})"""
290298
}
291299
object SSLLooseConfig {
292300
def apply() = new SSLLooseConfig()
@@ -295,6 +303,34 @@ object SSLLooseConfig {
295303
def getInstance() = apply()
296304
}
297305

306+
/**
307+
* Carries values which will be later set on an [[javax.net.ssl.SSLParameters]] object.
308+
*
309+
* @param clientAuth see [[ClientAuth]] for detailed docs on ClientAuth modes
310+
*/
311+
final class SSLParametersConfig private[sslconfig] (
312+
val clientAuth: ClientAuth = ClientAuth.Default,
313+
val protocols: scala.collection.immutable.Seq[String] = Nil
314+
) {
315+
316+
def withClientAuth(value: com.typesafe.sslconfig.ssl.ClientAuth): SSLParametersConfig = copy(clientAuth = value)
317+
def withProtocols(value: scala.collection.immutable.Seq[String]): SSLParametersConfig = copy(protocols = value)
318+
319+
private def copy(
320+
clientAuth: com.typesafe.sslconfig.ssl.ClientAuth = clientAuth,
321+
protocols: scala.collection.immutable.Seq[String] = protocols
322+
): SSLParametersConfig = new SSLParametersConfig(clientAuth = clientAuth, protocols = protocols)
323+
324+
override def toString =
325+
s"""SSLParametersConfig(${clientAuth},${protocols})"""
326+
}
327+
object SSLParametersConfig {
328+
def apply() = new SSLParametersConfig()
329+
330+
/** Java API */
331+
def getInstance() = apply()
332+
}
333+
298334
/**
299335
* The SSL configuration.
300336
*
@@ -304,8 +340,12 @@ object SSLLooseConfig {
304340
* @param revocationLists The revocation lists to check.
305341
* @param enabledCipherSuites If defined, override the platform default cipher suites.
306342
* @param enabledProtocols If defined, override the platform default protocols.
343+
* @param sslParametersConfig Be aware: SSL Config itself is not using this config.
344+
* However, it was kept because 3rd party libraries rely on its existence.
307345
* @param keyManagerConfig The key manager configuration.
308346
* @param trustManagerConfig The trust manager configuration.
347+
* @param hostnameVerifierClass The hostname verifier class. Be aware: SSL Config itself is not using this config.
348+
* However, it was kept because 3rd party libraries rely on its existence.
309349
* @param secureRandom The SecureRandom instance to use. Let the platform choose if None.
310350
* @param debug The debug config.
311351
* @param loose Loose configuratino parameters
@@ -317,8 +357,10 @@ final class SSLConfigSettings private[sslconfig] (
317357
val revocationLists: Option[immutable.Seq[URL]] = None,
318358
val enabledCipherSuites: Option[immutable.Seq[String]] = None,
319359
val enabledProtocols: Option[immutable.Seq[String]] = Some(List("TLSv1.3", "TLSv1.2")),
360+
val sslParametersConfig: SSLParametersConfig = SSLParametersConfig(),
320361
val keyManagerConfig: KeyManagerConfig = KeyManagerConfig(),
321362
val trustManagerConfig: TrustManagerConfig = TrustManagerConfig(),
363+
val hostnameVerifierClass: Class[? <: HostnameVerifier] = classOf[NoopHostnameVerifier],
322364
val secureRandom: Option[SecureRandom] = None,
323365
val debug: SSLDebugConfig = SSLDebugConfig(),
324366
val loose: SSLLooseConfig = SSLLooseConfig()
@@ -331,13 +373,17 @@ final class SSLConfigSettings private[sslconfig] (
331373
copy(enabledCipherSuites = value)
332374
def withEnabledProtocols(value: Option[scala.collection.immutable.Seq[String]]): SSLConfigSettings =
333375
copy(enabledProtocols = value)
376+
def withHostnameVerifierClass(value: Class[? <: javax.net.ssl.HostnameVerifier]): SSLConfigSettings =
377+
copy(hostnameVerifierClass = value)
334378
def withKeyManagerConfig(value: com.typesafe.sslconfig.ssl.KeyManagerConfig): SSLConfigSettings =
335379
copy(keyManagerConfig = value)
336380
def withLoose(value: com.typesafe.sslconfig.ssl.SSLLooseConfig): SSLConfigSettings = copy(loose = value)
337381
def withProtocol(value: String): SSLConfigSettings = copy(protocol = value)
338382
def withRevocationLists(value: Option[scala.collection.immutable.Seq[java.net.URL]]): SSLConfigSettings =
339383
copy(revocationLists = value)
340-
def withSecureRandom(value: Option[java.security.SecureRandom]): SSLConfigSettings = copy(secureRandom = value)
384+
def withSecureRandom(value: Option[java.security.SecureRandom]): SSLConfigSettings = copy(secureRandom = value)
385+
def withSslParametersConfig(value: com.typesafe.sslconfig.ssl.SSLParametersConfig): SSLConfigSettings =
386+
copy(sslParametersConfig = value)
341387
def withTrustManagerConfig(value: com.typesafe.sslconfig.ssl.TrustManagerConfig): SSLConfigSettings =
342388
copy(trustManagerConfig = value)
343389

@@ -347,28 +393,32 @@ final class SSLConfigSettings private[sslconfig] (
347393
default: Boolean = default,
348394
enabledCipherSuites: Option[scala.collection.immutable.Seq[String]] = enabledCipherSuites,
349395
enabledProtocols: Option[scala.collection.immutable.Seq[String]] = enabledProtocols,
396+
hostnameVerifierClass: Class[? <: javax.net.ssl.HostnameVerifier] = hostnameVerifierClass,
350397
keyManagerConfig: com.typesafe.sslconfig.ssl.KeyManagerConfig = keyManagerConfig,
351398
loose: com.typesafe.sslconfig.ssl.SSLLooseConfig = loose,
352399
protocol: String = protocol,
353400
revocationLists: Option[scala.collection.immutable.Seq[java.net.URL]] = revocationLists,
354401
secureRandom: Option[java.security.SecureRandom] = secureRandom,
402+
sslParametersConfig: com.typesafe.sslconfig.ssl.SSLParametersConfig = sslParametersConfig,
355403
trustManagerConfig: com.typesafe.sslconfig.ssl.TrustManagerConfig = trustManagerConfig
356404
): SSLConfigSettings = new SSLConfigSettings(
357405
checkRevocation = checkRevocation,
358406
debug = debug,
359407
default = default,
360408
enabledCipherSuites = enabledCipherSuites,
361409
enabledProtocols = enabledProtocols,
410+
hostnameVerifierClass = hostnameVerifierClass,
362411
keyManagerConfig = keyManagerConfig,
363412
loose = loose,
364413
protocol = protocol,
365414
revocationLists = revocationLists,
366415
secureRandom = secureRandom,
416+
sslParametersConfig = sslParametersConfig,
367417
trustManagerConfig = trustManagerConfig
368418
)
369419

370420
override def toString =
371-
s"""SSLConfig(${checkRevocation},${debug},${default},${enabledCipherSuites},${enabledProtocols},${keyManagerConfig},${loose},${protocol},${revocationLists},${secureRandom},${trustManagerConfig})"""
421+
s"""SSLConfig(${checkRevocation},${debug},${default},${enabledCipherSuites},${enabledProtocols},${hostnameVerifierClass},${keyManagerConfig},${loose},${protocol},${revocationLists},${secureRandom},${sslParametersConfig},${trustManagerConfig})"""
372422
}
373423
object SSLConfigSettings {
374424
def apply() = new SSLConfigSettings()
@@ -419,10 +469,19 @@ class SSLConfigParser(c: EnrichedConfig, classLoader: ClassLoader, loggerFactory
419469
val ciphers = Some(c.getSeq[String]("enabledCipherSuites")).filter(_.nonEmpty)
420470
val protocols = Some(c.getSeq[String]("enabledProtocols")).filter(_.nonEmpty)
421471

472+
val hostnameVerifierClass = c.getOptional[String]("hostnameVerifierClass") match {
473+
case None => classOf[NoopHostnameVerifier]
474+
case Some(fqcn) => classLoader.loadClass(fqcn).asSubclass(classOf[HostnameVerifier])
475+
}
476+
422477
val keyManagers = parseKeyManager(c.get[EnrichedConfig]("keyManager"))
423478

424479
val trustManagers = parseTrustManager(c.get[EnrichedConfig]("trustManager"))
425480

481+
val sslParametersConfig = parseSSLParameters(
482+
c.getOptional[EnrichedConfig]("sslParameters").getOrElse(new EnrichedConfig(ConfigFactory.empty()))
483+
)
484+
426485
new SSLConfigSettings(
427486
default = default,
428487
protocol = protocol,
@@ -431,6 +490,8 @@ class SSLConfigParser(c: EnrichedConfig, classLoader: ClassLoader, loggerFactory
431490
enabledCipherSuites = ciphers,
432491
enabledProtocols = protocols,
433492
keyManagerConfig = keyManagers,
493+
hostnameVerifierClass = hostnameVerifierClass,
494+
sslParametersConfig = sslParametersConfig,
434495
trustManagerConfig = trustManagers,
435496
secureRandom = None,
436497
debug = debug,
@@ -446,12 +507,14 @@ class SSLConfigParser(c: EnrichedConfig, classLoader: ClassLoader, loggerFactory
446507
val allowMessages = config.getOptional[Boolean]("allowLegacyHelloMessages")
447508
val allowUnsafeRenegotiation = config.getOptional[Boolean]("allowUnsafeRenegotiation")
448509
val disableHostnameVerification = config.getOptional[Boolean]("disableHostnameVerification").getOrElse(false)
510+
val disableSNI = config.getOptional[Boolean]("disableSNI").getOrElse(false)
449511
val acceptAnyCertificate = config.get[Boolean]("acceptAnyCertificate")
450512

451513
new SSLLooseConfig(
452514
allowLegacyHelloMessages = allowMessages,
453515
allowUnsafeRenegotiation = allowUnsafeRenegotiation,
454516
disableHostnameVerification = disableHostnameVerification,
517+
disableSNI = disableSNI,
455518
acceptAnyCertificate = acceptAnyCertificate
456519
)
457520
}
@@ -555,4 +618,45 @@ class SSLConfigParser(c: EnrichedConfig, classLoader: ClassLoader, loggerFactory
555618

556619
new TrustManagerConfig(algorithm, trustStoreInfos)
557620
}
621+
622+
def parseSSLParameters(config: EnrichedConfig): SSLParametersConfig = {
623+
// could instantiate SSLParameters directly, but seems less clean, here we only parse config
624+
625+
val clientAuth = config.getOptional[String]("clientAuth") match {
626+
case Some("none") => ClientAuth.None
627+
case Some("want") => ClientAuth.Want
628+
case Some("need") => ClientAuth.Need
629+
case None | Some(_) => ClientAuth.Default
630+
}
631+
632+
val protocols = if (config.underlying.hasPath("protocols")) {
633+
config.getSeq[String]("protocols")
634+
} else {
635+
immutable.Seq.empty[String]
636+
}
637+
638+
new SSLParametersConfig(clientAuth, protocols)
639+
}
640+
}
641+
642+
/**
643+
* An SSLEngine can either demand, allow or ignore its peer’s authentication
644+
* (via certificates), where `Need` will fail the handshake if the peer does
645+
* not provide valid credentials, `Want` allows the peer to send credentials
646+
* and verifies them if provided, and `None` disables peer certificate
647+
* verification.
648+
*
649+
* See the documentation for `SSLEngine::setWantClientAuth` for more information.
650+
*/
651+
sealed abstract class ClientAuth
652+
object ClientAuth {
653+
case object Default extends ClientAuth
654+
case object None extends ClientAuth
655+
case object Want extends ClientAuth
656+
case object Need extends ClientAuth
657+
658+
def none: ClientAuth = None
659+
def want: ClientAuth = Want
660+
def need: ClientAuth = Need
661+
def defaultAuth: ClientAuth = Default // since `default` is a Java keyword
558662
}

0 commit comments

Comments
 (0)