diff --git a/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/tls/TlsConfiguration.scala b/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/tls/TlsConfiguration.scala index fc1881a94b8..c61c21b1ed4 100644 --- a/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/tls/TlsConfiguration.scala +++ b/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/tls/TlsConfiguration.scala @@ -8,6 +8,8 @@ import java.io.File import io.grpc.netty.GrpcSslContexts import io.netty.handler.ssl.{ClientAuth, SslContext} +import scala.jdk.CollectionConverters._ + final case class TlsConfiguration( enabled: Boolean, keyCertChainFile: Option[File], // mutual auth is disabled if null @@ -16,6 +18,7 @@ final case class TlsConfiguration( clientAuth: ClientAuth = ClientAuth.REQUIRE, // Client auth setting used by the server. This is not used in the client configuration. enableCertRevocationChecking: Boolean = false, + protocols: Seq[String] = Seq.empty, ) { def keyFileOrFail: File = @@ -40,6 +43,7 @@ final case class TlsConfiguration( .forClient() .keyManager(keyCertChainFile.orNull, keyFile.orNull) .trustManager(trustCertCollectionFile.orNull) + .protocols(if (protocols.nonEmpty) protocols.asJava else null) .build() ) else None @@ -56,6 +60,7 @@ final case class TlsConfiguration( ) .trustManager(trustCertCollectionFile.orNull) .clientAuth(clientAuth) + .protocols(if (protocols.nonEmpty) protocols.asJava else null) .build ) else None @@ -67,7 +72,7 @@ final case class TlsConfiguration( } object TlsConfiguration { - val Empty = TlsConfiguration( + val Empty: TlsConfiguration = TlsConfiguration( enabled = true, keyCertChainFile = None, keyFile = None, diff --git a/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/TlsIT.scala b/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/TlsIT.scala index 8c0a840379a..ccf1dd95e33 100644 --- a/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/TlsIT.scala +++ b/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/TlsIT.scala @@ -8,6 +8,7 @@ import java.io.File import com.daml.bazeltools.BazelRunfiles._ import com.daml.ledger.api.testing.utils.SuiteResourceManagementAroundAll import com.daml.ledger.api.tls.TlsConfiguration +import com.daml.ledger.api.v1.transaction_service.GetLedgerEndResponse import com.daml.ledger.client.LedgerClient import com.daml.ledger.client.configuration.{ CommandClientConfiguration, @@ -18,6 +19,8 @@ import com.daml.platform.sandbox.config.SandboxConfig import com.daml.platform.sandbox.services.SandboxFixture import org.scalatest.wordspec.AsyncWordSpec +import scala.concurrent.Future + class TlsIT extends AsyncWordSpec with SandboxFixture with SuiteResourceManagementAroundAll { private val List( @@ -32,17 +35,24 @@ class TlsIT extends AsyncWordSpec with SandboxFixture with SuiteResourceManageme } } - private lazy val tlsEnabledConfig = LedgerClientConfiguration( - "appId", - LedgerIdRequirement.none, - CommandClientConfiguration.default, - TlsConfiguration( - enabled = true, - Some(clientCertChainFilePath), - Some(clientPrivateKeyFilePath), - Some(trustCertCollectionFilePath), - ).client, - ) + private lazy val baseConfig: LedgerClientConfiguration = + LedgerClientConfiguration( + "appId", + LedgerIdRequirement.none, + CommandClientConfiguration.default, + None, + ) + + private def tlsEnabledConfig(protocols: Seq[String]): LedgerClientConfiguration = + baseConfig.copy(sslContext = + TlsConfiguration( + enabled = true, + Some(clientCertChainFilePath), + Some(clientPrivateKeyFilePath), + Some(trustCertCollectionFilePath), + protocols = protocols, + ).client + ) override protected lazy val config: SandboxConfig = super.config.copy( @@ -56,19 +66,28 @@ class TlsIT extends AsyncWordSpec with SandboxFixture with SuiteResourceManageme ) ) - private lazy val clientF = LedgerClient.singleHost(serverHost, serverPort.value, tlsEnabledConfig) + private def clientF(protocol: String) = + LedgerClient.singleHost(serverHost, serverPort.value, tlsEnabledConfig(Seq(protocol))) "A TLS-enabled server" should { "reject ledger queries when the client connects without tls" in { recoverToSucceededIf[io.grpc.StatusRuntimeException] { LedgerClient - .singleHost(serverHost, serverPort.value, tlsEnabledConfig.copy(sslContext = None)) + .singleHost(serverHost, serverPort.value, baseConfig) .flatMap(_.transactionClient.getLedgerEnd()) } } "serve ledger queries when the client presents a valid certificate" in { - clientF.flatMap(_.transactionClient.getLedgerEnd()).map(_ => succeed) + def testWith(protocol: String): Future[GetLedgerEndResponse] = + withClue(s"Testing with $protocol") { + clientF(protocol).flatMap(_.transactionClient.getLedgerEnd()) + } + + for { + _ <- testWith("TLSv1.2") + _ <- testWith("TLSv1.3") + } yield succeed } } }