From 145dc19675d23fefcbb1eb63504226fd609882ee Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 22 Apr 2025 09:02:53 +0900 Subject: [PATCH] Remove SSLCertificateSocketFactoryTest @hide usage Include verifyHostname in the test instead of calling the hidden API. This removes a bit of coverage as verifyHostname itself is not tested anymore, but it still verifies behavior of the verification and state of the SSL session on socket creation. verifyHostname is @hide API so it should not be exercised directly by CTS. Bug: 410435307 Flag: TEST_ONLY Test: atest Change-Id: I11f56e21ba242b7fcc5b84f6de992dc94d90ddee --- .../cts/SSLCertificateSocketFactoryTest.java | 62 +++++++++++++------ 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 1a780a7eb5..2fda685ee6 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -22,6 +22,15 @@ import static org.junit.Assert.fail; import android.net.SSLCertificateSocketFactory; import android.platform.test.annotations.AppModeFull; + +import libcore.javax.net.ssl.SSLConfigurationAsserts; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -31,16 +40,13 @@ import java.net.UnknownHostException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; + import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; -import libcore.javax.net.ssl.SSLConfigurationAsserts; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; +import javax.net.ssl.SSLSocket; @RunWith(JUnit4.class) public class SSLCertificateSocketFactoryTest { @@ -151,8 +157,7 @@ public class SSLCertificateSocketFactoryTest { * {@link HttpsURLConnection#getDefaultHostnameVerifier}, so this test connects twice, * once with the system default {@link HostnameVerifier} which is expected to succeed, * and once after installing a {@link NegativeHostnameVerifier} which will cause - * {@link SSLCertificateSocketFactory#verifyHostname} to throw a - * {@link SSLPeerUnverifiedException}. + * {@link #verifyHostname} to throw a {@link SSLPeerUnverifiedException}. * *

These tests only test the hostname verification logic in SSLCertificateSocketFactory, * other TLS failure modes and the default HostnameVerifier are tested elsewhere, see @@ -251,16 +256,16 @@ public class SSLCertificateSocketFactoryTest { * *

Behaviour is tested by installing a {@link NegativeHostnameVerifier} and by calling * {@link #assertConnectedSocket} to ensure TLS handshaking but no hostname verification takes - * place. Next, {@link SSLCertificateSocketFactory#verifyHostname} is called to ensure - * that hostname verification is using the {@link HostnameVerifier} returned by + * place. Next, {@link #verifyHostname} is called to ensure that hostname verification is using + * the {@link HostnameVerifier} returned by * {@link HttpsURLConnection#getDefaultHostnameVerifier} as documented. * *

Tests the following behaviour:- *

*/ @Test @@ -272,13 +277,13 @@ public class SSLCertificateSocketFactoryTest { mSocketFactory.setHostname(socket, TEST_HOST); assertConnectedSocket(socket); try { - SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); - fail(); + verifyHostname(socket, TEST_HOST); + fail(); } catch (SSLPeerUnverifiedException expected) { // expected } HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier); - SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + verifyHostname(socket, TEST_HOST); socket.close(); } @@ -306,16 +311,37 @@ public class SSLCertificateSocketFactoryTest { mSocketFactory.setHostname(socket, TEST_HOST); assertConnectedSocket(socket); try { - SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); - fail(); + verifyHostname(socket, TEST_HOST); + fail(); } catch (SSLPeerUnverifiedException expected) { // expected } HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier); - SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST); + verifyHostname(socket, TEST_HOST); socket.close(); } + // This is copied from SSLCertificateSocketFactory#verifyHostname given that + // the method is @hide. + private static void verifyHostname(Socket socket, String hostname) throws Exception { + if (!(socket instanceof SSLSocket)) { + throw new IllegalArgumentException("Attempt to verify non-SSL socket"); + } + + // The code at the start of OpenSSLSocketImpl.startHandshake() + // ensures that the call is idempotent, so we can safely call it. + SSLSocket ssl = (SSLSocket) socket; + ssl.startHandshake(); + + SSLSession session = ssl.getSession(); + if (session == null) { + throw new SSLException("Cannot verify SSL socket without session"); + } + if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) { + throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname); + } + } + /** * Asserts a socket is fully connected to the expected peer. *