From 355604457f54d6d89a9b93c51e330f385b20932b Mon Sep 17 00:00:00 2001 From: Viktor Kolomeyko Date: Wed, 15 May 2019 09:19:52 +0100 Subject: [PATCH] CORDA-2935: Align timeouts for CRL retrieval and TLS handshake (#5125) --- .../internal/protonwrapper/netty/SSLHelper.kt | 10 ++++- .../CertificateRevocationListNodeTests.kt | 39 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt index 75d623d278..63128f3332 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/SSLHelper.kt @@ -19,6 +19,8 @@ import java.util.* import javax.net.ssl.* private const val HOSTNAME_FORMAT = "%s.corda.net" +private const val SSL_HANDSHAKE_TIMEOUT_PROP_NAME = "corda.netty.sslHelper.handshakeTimeout" +private const val DEFAULT_SSL_TIMEOUT = 20000 // Aligned with sun.security.provider.certpath.URICertStore.DEFAULT_CRL_CONNECT_TIMEOUT internal class LoggingTrustManagerWrapper(val wrapped: X509ExtendedTrustManager) : X509ExtendedTrustManager() { companion object { @@ -123,7 +125,9 @@ internal fun createClientSslHelper(target: NetworkHostAndPort, sslParameters.serverNames = listOf(SNIHostName(x500toHostName(expectedRemoteLegalNames.single()))) sslEngine.sslParameters = sslParameters } - return SslHandler(sslEngine) + val sslHandler = SslHandler(sslEngine) + sslHandler.handshakeTimeoutMillis = Integer.getInteger(SSL_HANDSHAKE_TIMEOUT_PROP_NAME, DEFAULT_SSL_TIMEOUT).toLong() + return sslHandler } internal fun createServerSslHelper(keyManagerFactory: KeyManagerFactory, @@ -138,7 +142,9 @@ internal fun createServerSslHelper(keyManagerFactory: KeyManagerFactory, sslEngine.enabledProtocols = ArtemisTcpTransport.TLS_VERSIONS.toTypedArray() sslEngine.enabledCipherSuites = ArtemisTcpTransport.CIPHER_SUITES.toTypedArray() sslEngine.enableSessionCreation = true - return SslHandler(sslEngine) + val sslHandler = SslHandler(sslEngine) + sslHandler.handshakeTimeoutMillis = Integer.getInteger(SSL_HANDSHAKE_TIMEOUT_PROP_NAME, DEFAULT_SSL_TIMEOUT).toLong() + return sslHandler } internal fun initialiseTrustStoreAndEnableCrlChecking(trustStore: CertificateStore, crlCheckSoftFail: Boolean): ManagerFactoryParameters { diff --git a/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt b/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt index 2b760c8e93..b9ad2fd99b 100644 --- a/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt @@ -83,6 +83,9 @@ class CertificateRevocationListNodeTests { private abstract class AbstractNodeConfiguration : NodeConfiguration companion object { + + const val FORBIDDEN_CRL = "forbidden.crl" + fun createRevocationList(clrServer: CrlServer, signatureAlgorithm: String, caCertificate: X509Certificate, caPrivateKey: PrivateKey, endpoint: String, @@ -493,6 +496,13 @@ class CertificateRevocationListNodeTests { .build() } + @GET + @Path(FORBIDDEN_CRL) + @Produces("application/pkcs7-crl") + fun getNodeSlowCRL(): Response { + return Response.status(Response.Status.FORBIDDEN).build() + } + @GET @Path("intermediate.crl") @Produces("application/pkcs7-crl") @@ -588,4 +598,33 @@ class CertificateRevocationListNodeTests { ) }.withMessage("Unknown signature type requested: EC") } + + @Test + fun `AMPQ Client to Server connection succeeds when CRL retrieval is forbidden and soft fail is enabled`() { + val crlCheckSoftFail = true + val forbiddenUrl = "http://${server.hostAndPort}/crl/$FORBIDDEN_CRL" + val (amqpServer, _) = createServer( + serverPort, + crlCheckSoftFail = crlCheckSoftFail, + nodeCrlDistPoint = forbiddenUrl, + tlsCrlDistPoint = forbiddenUrl) + amqpServer.use { + amqpServer.start() + amqpServer.onReceive.subscribe { + it.complete(true) + } + val (amqpClient, _) = createClient( + serverPort, + crlCheckSoftFail, + nodeCrlDistPoint = forbiddenUrl, + tlsCrlDistPoint = forbiddenUrl) + amqpClient.use { + val serverConnected = amqpServer.onConnection.toFuture() + amqpClient.onConnection.toFuture() + amqpClient.start() + val serverConnect = serverConnected.get() + assertEquals(true, serverConnect.connected) + } + } + } }