Skip to content

Commit db58f27

Browse files
antonstamovmaxcom
andauthored
Configure TLS protocol versions in SSLConfig (#3806)
Co-authored-by: Maxim Valyanskiy <max.valjanski@gmail.com>
1 parent 70bdebc commit db58f27

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

docs/guides/implementing-mutual-tls.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ object ServerApp extends ZIOAppDefault {
182182
),
183183
includeClientCert = false,
184184
clientAuth = Some(ClientAuth.Required),
185+
protocols = Seq("TLSv1.3", "TLSv1.2"),
185186
)
186187

187188
private val serverConfig =
@@ -201,6 +202,8 @@ Please note that we enabled the `ClientAuth.Required` option in the SSL configur
201202

202203
If we want to access the client certificate, we can enable the `includeClientCert` option in the SSL configuration. This allows us to access the client certificate via `req.remoteCertificate` in the request handler.
203204

205+
The `protocols` parameter in `SSLConfig` allows configuring supported TLS protocol versions. This is useful for disabling older protocol versions for security reasons.
206+
204207
### Client Implementation
205208

206209
Similarly, the client implementation for mTLS requires both a keystore (containing the client's certificate and private key) and a truststore (containing the CA certificate used to verify the server's certificate). The client will automatically send its certificate during the TLS handshake if configured correctly:

zio-http/jvm/src/main/scala/zio/http/netty/server/ServerSSLDecoder.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ private[netty] object SSLUtil {
5252
clientAuthConfig.foreach(ca => self.clientAuth(getClientAuth(ca)))
5353
self
5454
.sslProvider(toNettyProvider(sslConfig.provider))
55+
.protocols(sslConfig.protocols: _*)
5556
.applicationProtocolConfig(
5657
new ApplicationProtocolConfig(
5758
Protocol.ALPN,

zio-http/shared/src/main/scala/zio/http/SSLConfig.scala

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package zio.http
1818

19+
import scala.annotation.unroll
20+
1921
import zio.Config
2022
import zio.Config.Secret
2123

@@ -36,7 +38,35 @@ final case class SSLConfig(
3638
provider: Provider,
3739
clientAuth: Option[ClientAuth] = None,
3840
includeClientCert: Boolean = false,
39-
)
41+
protocols: Seq[String] = Seq("TLSv1.3", "TLSv1.2"),
42+
) {
43+
// @unroll annotation does not work here, doing manual unroll for binary compatibility
44+
45+
def this(
46+
behaviour: HttpBehaviour,
47+
data: Data,
48+
provider: Provider,
49+
clientAuth: Option[ClientAuth],
50+
includeClientCert: Boolean,
51+
) = this(behaviour, data, provider, clientAuth, includeClientCert, Seq("TLSv1.3", "TLSv1.2"))
52+
53+
def copy(
54+
behaviour: HttpBehaviour = this.behaviour,
55+
data: Data = this.data,
56+
provider: Provider = this.provider,
57+
clientAuth: Option[ClientAuth] = this.clientAuth,
58+
includeClientCert: Boolean = this.includeClientCert,
59+
protocols: Seq[String] = this.protocols,
60+
): SSLConfig = SSLConfig(behaviour, data, provider, clientAuth, includeClientCert, protocols)
61+
62+
def copy(
63+
behaviour: HttpBehaviour,
64+
data: Data,
65+
provider: Provider,
66+
clientAuth: Option[ClientAuth],
67+
includeClientCert: Boolean,
68+
): SSLConfig = SSLConfig(behaviour, data, provider, clientAuth, includeClientCert, this.protocols)
69+
}
4070

4171
object SSLConfig {
4272

@@ -46,6 +76,14 @@ object SSLConfig {
4676
def apply(data: Data, clientAuth: ClientAuth): SSLConfig =
4777
new SSLConfig(HttpBehaviour.Redirect, data, Provider.JDK, Some(clientAuth))
4878

79+
def apply(
80+
behaviour: HttpBehaviour,
81+
data: Data,
82+
provider: Provider,
83+
clientAuth: Option[ClientAuth],
84+
includeClientCert: Boolean,
85+
): SSLConfig = new SSLConfig(behaviour, data, provider, clientAuth, includeClientCert)
86+
4987
val config: Config[SSLConfig] =
5088
(
5189
HttpBehaviour.config.nested("behaviour") ++
@@ -68,13 +106,16 @@ object SSLConfig {
68106
clientAuth: Option[ClientAuth] = None,
69107
trustCertCollectionPath: Option[String] = None,
70108
includeClientCert: Boolean = false,
109+
@unroll
110+
protocols: Seq[String] = Seq("TLSv1.3", "TLSv1.2"),
71111
): SSLConfig =
72112
new SSLConfig(
73113
behaviour,
74114
Data.FromFile(certPath, keyPath, trustCertCollectionPath),
75115
Provider.JDK,
76116
clientAuth,
77117
includeClientCert,
118+
protocols,
78119
)
79120

80121
def fromResource(certPath: String, keyPath: String): SSLConfig =
@@ -90,13 +131,16 @@ object SSLConfig {
90131
clientAuth: Option[ClientAuth] = None,
91132
trustCertCollectionPath: Option[String] = None,
92133
includeClientCert: Boolean = false,
134+
@unroll
135+
protocols: Seq[String] = Seq("TLSv1.3", "TLSv1.2"),
93136
): SSLConfig =
94137
new SSLConfig(
95138
behaviour,
96139
Data.FromResource(certPath, keyPath, trustCertCollectionPath),
97140
Provider.JDK,
98141
clientAuth,
99142
includeClientCert,
143+
protocols,
100144
)
101145

102146
def fromJavaxNetSslKeyStoreFile(
@@ -107,6 +151,8 @@ object SSLConfig {
107151
trustManagerKeyStore: Option[Data.TrustManagerKeyStore] = None,
108152
clientAuth: Option[ClientAuth] = None,
109153
includeClientCert: Boolean = false,
154+
@unroll
155+
protocols: Seq[String] = Seq("TLSv1.3", "TLSv1.2"),
110156
): SSLConfig =
111157
new SSLConfig(
112158
behaviour,
@@ -119,6 +165,7 @@ object SSLConfig {
119165
Provider.JDK,
120166
clientAuth,
121167
includeClientCert,
168+
protocols,
122169
)
123170

124171
def fromJavaxNetSslKeyStoreFile(keyManagerFile: String, keyManagerPassword: Secret): SSLConfig =
@@ -131,6 +178,8 @@ object SSLConfig {
131178
trustManagerKeyStore: Option[Data.TrustManagerKeyStore] = None,
132179
clientAuth: Option[ClientAuth] = None,
133180
includeClientCert: Boolean = false,
181+
@unroll
182+
protocols: Seq[String] = Seq("TLSv1.3", "TLSv1.2"),
134183
): SSLConfig = {
135184
fromJavaxNetSsl(
136185
Data.FromJavaxNetSsl(
@@ -142,6 +191,7 @@ object SSLConfig {
142191
HttpBehaviour.Redirect,
143192
clientAuth,
144193
includeClientCert,
194+
protocols,
145195
)
146196
}
147197

@@ -150,13 +200,16 @@ object SSLConfig {
150200
behaviour: HttpBehaviour = HttpBehaviour.Redirect,
151201
clientAuth: Option[ClientAuth] = None,
152202
includeClientCert: Boolean = false,
203+
@unroll
204+
protocols: Seq[String] = Seq("TLSv1.3", "TLSv1.2"),
153205
): SSLConfig =
154206
new SSLConfig(
155207
behaviour,
156208
data,
157209
Provider.JDK,
158210
clientAuth,
159211
includeClientCert,
212+
protocols,
160213
)
161214

162215
def fromJavaxNetSslKeyStoreResource(keyManagerResource: String, keyManagerPassword: Secret): SSLConfig =

0 commit comments

Comments
 (0)