From 780ea9ab5842abf3c02887560116f3e6e99499af Mon Sep 17 00:00:00 2001 From: bhashinee Date: Tue, 3 Dec 2024 10:28:38 +0530 Subject: [PATCH 1/4] Add configurations to add SNI host name --- .../http-security-tests/tests/http2_ssl_test.bal | 3 ++- .../tests/ssl_sni_host_name_test.bal | 0 ballerina/http_client_config.bal | 2 ++ .../java/io/ballerina/stdlib/http/api/HttpUtil.java | 5 +++++ .../stdlib/http/transport/contract/Constants.java | 1 + .../transport/contract/config/SslConfiguration.java | 4 ++++ .../http/transport/contractimpl/common/Util.java | 12 ++++++++++-- .../transport/contractimpl/common/ssl/SSLConfig.java | 9 +++++++++ .../sender/HttpClientChannelInitializer.java | 6 +++++- 9 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal diff --git a/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal b/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal index 6f37dbb363..897b2ab180 100644 --- a/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal +++ b/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal @@ -36,7 +36,8 @@ http:ClientConfiguration http2SslClientConf1 = { cert: { path: common:TRUSTSTORE_PATH, password: "ballerina" - } + }, + sniHostName: "localhost2" } }; diff --git a/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal b/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ballerina/http_client_config.bal b/ballerina/http_client_config.bal index c427cd87bf..1735b9fe08 100644 --- a/ballerina/http_client_config.bal +++ b/ballerina/http_client_config.bal @@ -96,6 +96,7 @@ public type RetryConfig record {| # + shareSession - Enable/disable new SSL session creation # + handshakeTimeout - SSL handshake time out # + sessionTimeout - SSL session time out +# + sniHostName - Server name indication(SNI) to be used. If this is not present, hostname from the target URL will be used public type ClientSecureSocket record {| boolean enable = true; crypto:TrustStore|string cert?; @@ -114,6 +115,7 @@ public type ClientSecureSocket record {| boolean shareSession = true; decimal handshakeTimeout?; decimal sessionTimeout?; + string sniHostName?; |}; # Provides configurations for controlling the endpoint's behaviour in response to HTTP redirect related responses. diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java index 65fa4efeed..defdadd137 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java @@ -1898,6 +1898,11 @@ private static void evaluateCommonFields(BMap secureSocket, Ssl Parameter enableSessionCreationParam = new Parameter(HttpConstants.SECURESOCKET_CONFIG_SHARE_SESSION.getValue(), enableSessionCreation); paramList.add(enableSessionCreationParam); + if (secureSocket.containsKey(HttpConstants.SECURESOCKET_CONFIG_SNI_HOST_NAME)) { + Parameter sniHostNameParam = new Parameter(HttpConstants.SECURESOCKET_CONFIG_SNI_HOST_NAME.getValue(), + String.valueOf(secureSocket.getStringValue(HttpConstants.SECURESOCKET_CONFIG_SNI_HOST_NAME))); + paramList.add(sniHostNameParam); + } } private static BMap getBMapValueIfPresent(BMap map, BString key) { diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java index 5f9f282e7a..f1972206f5 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java @@ -43,6 +43,7 @@ public final class Constants { public static final String CLIENT_SUPPORT_CIPHERS = "ciphers"; public static final String CLIENT_SUPPORT_SSL_PROTOCOLS = "sslEnabledProtocols"; public static final String CLIENT_ENABLE_SESSION_CREATION = "shareSession"; + public static final String SNI_SERVER_NAME = "sniHostName"; public static final String MUTUAL_SSL_PASSED = "passed"; public static final String MUTUAL_SSL_FAILED = "failed"; public static final String MUTUAL_SSL_DISABLED = "disabled"; diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java index 858596da6c..0db8ffdeb8 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java @@ -39,6 +39,7 @@ import static io.ballerina.stdlib.http.transport.contract.Constants.SERVER_SUPPORTED_SNIMATCHERS; import static io.ballerina.stdlib.http.transport.contract.Constants.SERVER_SUPPORT_CIPHERS; import static io.ballerina.stdlib.http.transport.contract.Constants.SERVER_SUPPORT_SSL_PROTOCOLS; +import static io.ballerina.stdlib.http.transport.contract.Constants.SNI_SERVER_NAME; import static io.ballerina.stdlib.http.transport.contract.Constants.TLS_PROTOCOL; /** * SSL configuration for HTTP connection. @@ -277,6 +278,9 @@ private SSLConfig getSSLConfigForSender() { case CLIENT_ENABLE_SESSION_CREATION: sslConfig.setEnableSessionCreation(Boolean.parseBoolean(parameter.getValue())); break; + case SNI_SERVER_NAME: + sslConfig.setSniHostName(parameter.getValue()); + break; default: //do nothing break; diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java index b5b1349d20..a229dc2b52 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java @@ -412,7 +412,7 @@ private static SSLEngine getSslEngineForCerts(SocketChannel socketChannel, Strin SslHandler sslHandler = sslContext.newHandler(socketChannel.alloc(), host, port); SSLEngine sslEngine = sslHandler.engine(); sslHandlerFactory.addCommonConfigs(sslEngine); - sslHandlerFactory.setSNIServerNames(sslEngine, host); + setSniServerName(sslConfig, host, sslHandlerFactory, sslEngine); if (sslConfig.isHostNameVerificationEnabled()) { setHostNameVerfication(sslEngine); } @@ -507,7 +507,7 @@ private static SSLEngine instantiateAndConfigSSL(SSLConfig sslConfig, String hos if (sslConfig != null) { sslEngine = sslHandlerFactory.buildClientSSLEngine(host, port); sslEngine.setUseClientMode(true); - sslHandlerFactory.setSNIServerNames(sslEngine, host); + setSniServerName(sslConfig, host, sslHandlerFactory, sslEngine); if (hostNameVerificationEnabled) { sslHandlerFactory.setHostNameVerfication(sslEngine); } @@ -515,6 +515,14 @@ private static SSLEngine instantiateAndConfigSSL(SSLConfig sslConfig, String hos return sslEngine; } + private static void setSniServerName(SSLConfig sslConfig, String host, SSLHandlerFactory sslHandlerFactory, SSLEngine sslEngine) { + if (sslConfig.getSniHostName().isEmpty()) { + sslHandlerFactory.setSNIServerNames(sslEngine, host); + } else { + sslHandlerFactory.setSNIServerNames(sslEngine, sslConfig.getSniHostName()); + } + } + /** * Get integer type property value from a property map. *

diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/ssl/SSLConfig.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/ssl/SSLConfig.java index 9085f6c69b..ed9768ef73 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/ssl/SSLConfig.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/ssl/SSLConfig.java @@ -64,6 +64,7 @@ public class SSLConfig { private long handshakeTimeOut; private boolean disableSsl = false; private boolean useJavaDefaults = false; + private String sniHostName; public SSLConfig() {} @@ -179,6 +180,14 @@ public void setEnableSessionCreation(boolean enableSessionCreation) { this.enableSessionCreation = enableSessionCreation; } + public void setSniHostName(String sniHostName) { + this.sniHostName = sniHostName; + } + + public String getSniHostName() { + return sniHostName; + } + public String[] getEnableProtocols() { return enableProtocols == null ? null : enableProtocols.clone(); } diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java index 20734fbfe5..2b1724b2be 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java @@ -209,7 +209,11 @@ private void configureSslForHttp2(SocketChannel ch, ChannelPipeline clientPipeli SslContext sslCtx = sslHandlerFactory.createHttp2TLSContextForClient(false); SslHandler sslHandler = sslCtx.newHandler(ch.alloc(), httpRoute.getHost(), httpRoute.getPort()); SSLEngine sslEngine = sslHandler.engine(); - sslHandlerFactory.setSNIServerNames(sslEngine, httpRoute.getHost()); + if (sslConfig.getSniHostName().isEmpty()) { + sslHandlerFactory.setSNIServerNames(sslEngine, httpRoute.getHost()); + } else { + sslHandlerFactory.setSNIServerNames(sslEngine, sslConfig.getSniHostName()); + } if (sslConfig.isHostNameVerificationEnabled()) { setHostNameVerfication(sslEngine); } From ebeb5b718f7239f3e5b6223748ca0d0df75e40f2 Mon Sep 17 00:00:00 2001 From: bhashinee Date: Wed, 4 Dec 2024 08:20:12 +0530 Subject: [PATCH 2/4] Add test cases for sni host name configuration --- .../tests/http2_ssl_test.bal | 3 +- .../tests/ssl_sni_host_name_test.bal | 108 ++++++++++++++++++ .../tests/test_service_ports.bal | 3 + ballerina/http_client_config.bal | 4 +- changelog.md | 4 +- .../stdlib/http/api/HttpConstants.java | 1 + .../http/transport/contract/Constants.java | 2 +- .../transport/contractimpl/common/Util.java | 14 +-- .../sender/HttpClientChannelInitializer.java | 7 +- 9 files changed, 126 insertions(+), 20 deletions(-) diff --git a/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal b/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal index 897b2ab180..6f37dbb363 100644 --- a/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal +++ b/ballerina-tests/http-security-tests/tests/http2_ssl_test.bal @@ -36,8 +36,7 @@ http:ClientConfiguration http2SslClientConf1 = { cert: { path: common:TRUSTSTORE_PATH, password: "ballerina" - }, - sniHostName: "localhost2" + } } }; diff --git a/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal b/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal index e69de29bb2..7b341472c5 100644 --- a/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal +++ b/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal @@ -0,0 +1,108 @@ +// Copyright (c) 2024 WSO2 Inc. (http://www.wso2.org). +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; +import ballerina/test; +import ballerina/http_test_common as common; + +listener http:Listener http2SniListener = new (http2SniListenerPort, http2SslServiceConf); + +http:ListenerConfiguration http1SniServiceConf = { + httpVersion: http:HTTP_1_1, + secureSocket: { + key: { + path: common:KEYSTORE_PATH, + password: "ballerina" + } + } +}; + +listener http:Listener http1SniListener = new (http1SniListenerPort, http1SniServiceConf); + +service /http2SniService on http2SniListener { + resource function get .() returns string { + return "Sni works with HTTP_2!"; + } +} + +service /http1SniService on http1SniListener { + resource function get .() returns string { + return "Sni works with HTTP_1.1!"; + } +} + +http:ClientConfiguration http2SniClientConf = { + secureSocket: { + cert: { + path: common:TRUSTSTORE_PATH, + password: "ballerina" + }, + serverName: "localhost" + } +}; + +http:ClientConfiguration http1SniClientConf = { + httpVersion: http:HTTP_1_1, + secureSocket: { + cert: { + path: common:TRUSTSTORE_PATH, + password: "ballerina" + }, + serverName: "localhost" + } +}; + +http:ClientConfiguration http1SniClientConf2 = { + httpVersion: http:HTTP_1_1, + secureSocket: { + cert: { + path: common:TRUSTSTORE_PATH, + password: "ballerina" + }, + serverName: "xxxx" + } +}; + +http:ClientConfiguration http2SniClientConf3 = { + secureSocket: { + serverName: "localhost" + } +}; + +@test:Config {} +public function testHttp2WithSni() returns error? { + http:Client clientEP = check new ("https://127.0.0.1:9207", http2SniClientConf); + string resp = check clientEP->get("/http2SniService/"); + common:assertTextPayload(resp, "Sni works with HTTP_2!"); +} + +@test:Config {} +public function testHttp1WithSni() returns error? { + http:Client clientEP = check new ("https://127.0.0.1:9208", http1SniClientConf); + string resp = check clientEP->get("/http1SniService/"); + common:assertTextPayload(resp, "Sni works with HTTP_1.1!"); +} + +@test:Config {} +public function testSniFailure() returns error? { + http:Client clientEP = check new ("https://127.0.0.1:9208", http1SniClientConf2); + string|error resp = clientEP->get("/http1SniService/"); + if resp is error { + test:assertEquals(resp.message(), "SSL connection failed:No subject alternative names present /127.0.0.1:9208"); + } else { + test:assertFail("Test `testSniFailure` is expecting an error. But received a success response"); + } +} diff --git a/ballerina-tests/http-security-tests/tests/test_service_ports.bal b/ballerina-tests/http-security-tests/tests/test_service_ports.bal index d261826807..2812fa3537 100644 --- a/ballerina-tests/http-security-tests/tests/test_service_ports.bal +++ b/ballerina-tests/http-security-tests/tests/test_service_ports.bal @@ -19,3 +19,6 @@ const int stsPort = 9445; const int http2GeneralPort = 9100; const int http2SslGeneralPort = 9107; + +const int http2SniListenerPort = 9207; +const int http1SniListenerPort = 9208; diff --git a/ballerina/http_client_config.bal b/ballerina/http_client_config.bal index 1735b9fe08..ebf6ea9a58 100644 --- a/ballerina/http_client_config.bal +++ b/ballerina/http_client_config.bal @@ -96,7 +96,7 @@ public type RetryConfig record {| # + shareSession - Enable/disable new SSL session creation # + handshakeTimeout - SSL handshake time out # + sessionTimeout - SSL session time out -# + sniHostName - Server name indication(SNI) to be used. If this is not present, hostname from the target URL will be used +# + serverName - Server name indication(SNI) to be used. If this is not present, hostname from the target URL will be used public type ClientSecureSocket record {| boolean enable = true; crypto:TrustStore|string cert?; @@ -115,7 +115,7 @@ public type ClientSecureSocket record {| boolean shareSession = true; decimal handshakeTimeout?; decimal sessionTimeout?; - string sniHostName?; + string serverName?; |}; # Provides configurations for controlling the endpoint's behaviour in response to HTTP redirect related responses. diff --git a/changelog.md b/changelog.md index 4d1514229b..9e2d0b3ba4 100644 --- a/changelog.md +++ b/changelog.md @@ -2,7 +2,7 @@ # Change Log This file contains all the notable changes done to the Ballerina HTTP package through the releases. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [2.11.6] - 2024-11-26 @@ -381,7 +381,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - [Fix missing error of invalid inbound request parameter for forward() method](https://github.com/ballerina-platform/ballerina-standard-library/issues/311) - [Fix HTTP Circuit Breaker failure when status codes are not provided in the configuration](https://github.com/ballerina-platform/ballerina-standard-library/issues/339) - [Fix HTTP FailOver client failure when status codes are overridden by an empty array](https://github.com/ballerina-platform/ballerina-standard-library/issues/1598) -- [Fix already built incompatible payload thrown error](https://github.com/ballerina-platform/ballerina-standard-library/issues/1600) +- [Fix already built incompatible payload thrown error](https://github.com/ballerina-platform/ballerina-standard-library/issues/1600) - [Optional Types Not Supported in HTTP Client Request Operation Target Type](https://github.com/ballerina-platform/ballerina-standard-library/issues/1433) ### Changed diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java index 84af585f01..371b7778e5 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java @@ -461,6 +461,7 @@ public final class HttpConstants { public static final BString SECURESOCKET_CONFIG_VERIFY_CLIENT = StringUtils.fromString("verifyClient"); public static final BString SECURESOCKET_CONFIG_CERT_VALIDATION_TYPE_OCSP_STAPLING = StringUtils.fromString("OCSP_STAPLING"); + public static final BString SECURESOCKET_CONFIG_SNI_HOST_NAME = StringUtils.fromString("serverName"); //Socket Config public static final BString SOCKET_CONFIG = StringUtils.fromString("socketConfig"); diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java index f1972206f5..e9e8802bbb 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java @@ -43,7 +43,7 @@ public final class Constants { public static final String CLIENT_SUPPORT_CIPHERS = "ciphers"; public static final String CLIENT_SUPPORT_SSL_PROTOCOLS = "sslEnabledProtocols"; public static final String CLIENT_ENABLE_SESSION_CREATION = "shareSession"; - public static final String SNI_SERVER_NAME = "sniHostName"; + public static final String SNI_SERVER_NAME = "serverName"; public static final String MUTUAL_SSL_PASSED = "passed"; public static final String MUTUAL_SSL_FAILED = "failed"; public static final String MUTUAL_SSL_DISABLED = "disabled"; diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java index a229dc2b52..046f153bd6 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/Util.java @@ -412,7 +412,7 @@ private static SSLEngine getSslEngineForCerts(SocketChannel socketChannel, Strin SslHandler sslHandler = sslContext.newHandler(socketChannel.alloc(), host, port); SSLEngine sslEngine = sslHandler.engine(); sslHandlerFactory.addCommonConfigs(sslEngine); - setSniServerName(sslConfig, host, sslHandlerFactory, sslEngine); + configureSniServerName(sslConfig, host, sslHandlerFactory, sslEngine); if (sslConfig.isHostNameVerificationEnabled()) { setHostNameVerfication(sslEngine); } @@ -507,7 +507,7 @@ private static SSLEngine instantiateAndConfigSSL(SSLConfig sslConfig, String hos if (sslConfig != null) { sslEngine = sslHandlerFactory.buildClientSSLEngine(host, port); sslEngine.setUseClientMode(true); - setSniServerName(sslConfig, host, sslHandlerFactory, sslEngine); + configureSniServerName(sslConfig, host, sslHandlerFactory, sslEngine); if (hostNameVerificationEnabled) { sslHandlerFactory.setHostNameVerfication(sslEngine); } @@ -515,12 +515,10 @@ private static SSLEngine instantiateAndConfigSSL(SSLConfig sslConfig, String hos return sslEngine; } - private static void setSniServerName(SSLConfig sslConfig, String host, SSLHandlerFactory sslHandlerFactory, SSLEngine sslEngine) { - if (sslConfig.getSniHostName().isEmpty()) { - sslHandlerFactory.setSNIServerNames(sslEngine, host); - } else { - sslHandlerFactory.setSNIServerNames(sslEngine, sslConfig.getSniHostName()); - } + private static void configureSniServerName(SSLConfig sslConfig, String host, SSLHandlerFactory sslHandlerFactory, + SSLEngine sslEngine) { + sslHandlerFactory.setSNIServerNames(sslEngine, + sslConfig.getSniHostName() != null ? sslConfig.getSniHostName() : host); } /** diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java index 2b1724b2be..49e5933c5f 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/HttpClientChannelInitializer.java @@ -209,11 +209,8 @@ private void configureSslForHttp2(SocketChannel ch, ChannelPipeline clientPipeli SslContext sslCtx = sslHandlerFactory.createHttp2TLSContextForClient(false); SslHandler sslHandler = sslCtx.newHandler(ch.alloc(), httpRoute.getHost(), httpRoute.getPort()); SSLEngine sslEngine = sslHandler.engine(); - if (sslConfig.getSniHostName().isEmpty()) { - sslHandlerFactory.setSNIServerNames(sslEngine, httpRoute.getHost()); - } else { - sslHandlerFactory.setSNIServerNames(sslEngine, sslConfig.getSniHostName()); - } + sslHandlerFactory.setSNIServerNames(sslEngine, + sslConfig.getSniHostName() != null ? sslConfig.getSniHostName() : httpRoute.getHost()); if (sslConfig.isHostNameVerificationEnabled()) { setHostNameVerfication(sslEngine); } From f57474a8857d6180855e4f78e65709037a29f5d7 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Dec 2024 17:34:24 +0530 Subject: [PATCH 3/4] Fix the SNI for default certs --- .../tests/ssl_disable_ssl_test.bal | 16 -------------- .../tests/ssl_sni_host_name_test.bal | 22 +++++++++++++++++++ .../ballerina/stdlib/http/api/HttpUtil.java | 8 +------ .../contract/config/SslConfiguration.java | 5 ++++- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/ballerina-tests/http-security-tests/tests/ssl_disable_ssl_test.bal b/ballerina-tests/http-security-tests/tests/ssl_disable_ssl_test.bal index 21bf5b34f6..f1b003b61c 100644 --- a/ballerina-tests/http-security-tests/tests/ssl_disable_ssl_test.bal +++ b/ballerina-tests/http-security-tests/tests/ssl_disable_ssl_test.bal @@ -61,19 +61,3 @@ public function testSslDisabledClient1() returns error? { test:assertFail(msg = "Found unexpected output: " + resp.message()); } } - -http:ClientConfiguration disableSslClientConf2 = { - secureSocket: { - } -}; - -@test:Config {} -public function testSslDisabledClient2() { - http:Client|error httpClient = new ("https://localhost:9238", disableSslClientConf2); - string expectedErrMsg = "Need to configure cert with client SSL certificates file"; - if (httpClient is error) { - test:assertEquals(httpClient.message(), expectedErrMsg); - } else { - test:assertFail(msg = "Expected mutual SSL error not found"); - } -} diff --git a/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal b/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal index 7b341472c5..7eaa52b7ea 100644 --- a/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal +++ b/ballerina-tests/http-security-tests/tests/ssl_sni_host_name_test.bal @@ -106,3 +106,25 @@ public function testSniFailure() returns error? { test:assertFail("Test `testSniFailure` is expecting an error. But received a success response"); } } + +@test:Config {} +public function testSniWhenUsingDefaultCerts() returns error? { + http:Client httpClient = check new("https://www.google.com", http2SniClientConf3); + string|error resp = httpClient->get("/"); + // This response is success because even though we send a wrong server name, google.com sends the default cert which + // is valid and trusted by the client. + if resp is error { + test:assertFail("Found unexpected output: " + resp.message()); + } +} + +@test:Config {} +public function testSniFailureWhenUsingDefaultCerts() returns error? { + http:Client clientEP = check new ("https://127.0.0.1:9208", http2SniClientConf3); + string|error resp = clientEP->get("/http1SniService/"); + if resp is error { + common:assertTrueTextPayload(resp.message(), "SSL connection failed:javax.net.ssl.SSLHandshakeException:"); + } else { + test:assertFail("Test `testSniFailureWhenUsingDefaultCerts` is expecting an error. But received a success response"); + } +} diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java index defdadd137..970c857701 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java @@ -1407,13 +1407,7 @@ public static void populateSSLConfiguration(SslConfiguration senderConfiguration } Object cert = secureSocket.get(HttpConstants.SECURESOCKET_CONFIG_CERT); if (cert == null) { - BMap key = getBMapValueIfPresent(secureSocket, HttpConstants.SECURESOCKET_CONFIG_KEY); - if (key != null) { - senderConfiguration.useJavaDefaults(); - } else { - throw createHttpError("Need to configure cert with client SSL certificates file", - HttpErrorType.SSL_ERROR); - } + senderConfiguration.useJavaDefaults(); } else { evaluateCertField(cert, senderConfiguration); } diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java index 0db8ffdeb8..23975cbc82 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/config/SslConfiguration.java @@ -245,6 +245,7 @@ private SSLConfig getSSLConfigForListener() { } private SSLConfig getSSLConfigForSender() { + setSslParameters(); if (sslConfig.isDisableSsl() || sslConfig.useJavaDefaults()) { return sslConfig; } @@ -265,7 +266,10 @@ private SSLConfig getSSLConfigForSender() { sslConfig.setSSLProtocol(sslProtocol); String tlsStoreType = sslConfig.getTLSStoreType() != null ? sslConfig.getTLSStoreType() : JKS; sslConfig.setTLSStoreType(tlsStoreType); + return sslConfig; + } + private void setSslParameters() { if (parameters != null) { for (Parameter parameter : parameters) { switch (parameter.getName()) { @@ -287,6 +291,5 @@ private SSLConfig getSSLConfigForSender() { } } } - return sslConfig; } } From de5a8ba9e36b2b0a120110d406170aeaaff63675 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Dec 2024 17:34:34 +0530 Subject: [PATCH 4/4] Update change log --- changelog.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/changelog.md b/changelog.md index 9e2d0b3ba4..9bdb4d85fd 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,14 @@ This file contains all the notable changes done to the Ballerina HTTP package th The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added +- [Add support for configuring server name to be used in the SSL SNI extension](https://github.com/ballerina-platform/ballerina-library/issues/7435) + +### Fixed +- [Fix the issue of not being able to configure only server name in the secureSocket config](https://github.com/ballerina-platform/ballerina-library/issues/7443) + ## [2.11.6] - 2024-11-26 ### Fixed