Search code examples
javassltruststoresni

Server provides certificate for invalid SNI host name


I encountered a Java SNI SSL behaviour that I do not understand. When using SNI in Java I would expect that Google would not provide any certificate for invalid host name, but it does.

KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("src/main/resources/empty.keystore"), "password".toCharArray());

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keystore, "password".toCharArray());

KeyStore trustStore = KeyStore.getInstance("JKS");
// truststore contains single trusted certificate with serial number: 0x72a9296669b20ad60800000000320a0a
trustStore.load(new FileInputStream("src/main/resources/client-test-cn.truststore"), "password".toCharArray());

TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(trustStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), tmf.getTrustManagers(), null);

SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket();
SSLParameters sslParameters = socket.getSSLParameters();

sslParameters.setServerNames(Arrays.asList(new SNIHostName("microsoft.com")));
// Google provides certificate with serial number:  0x72a9296669b20ad60800000000320a0a
// CN=*.google.com,O=Google LLC,L=Mountain View,ST=California,C=US
// CN=GTS CA 1O1,O=Google Trust Services,C=US
// this works as this certificate is in the trust store
// handshake log: Extension server_name, server_name: [type=host_name (0), value=microsoft.com]
// ????? why does Google provide Google certificate for invalid hostname ?????

// sslParameters.setServerNames(Arrays.asList(new SNIHostName("google.com")));
// Google provides certificate with serial number: 0xcbfd0b2561656ea202000000005c675c
// this does NOT work as intentionally this certificate is missing from truststore
// handshake log: Extension server_name, server_name: [type=host_name (0), value=google.com]

sslParameters.setProtocols(new String[] {"TLSv1.2"});
socket.setSSLParameters(sslParameters);

socket.connect(new InetSocketAddress(InetAddress.getByName("google.com"), 443));
socket.addHandshakeCompletedListener(event -> System.out.println("----- HANDSHAKE DONE -----"));
socket.startHandshake();

Why does Google provide its certificate at all when requesting invalid host name via SNI extension? Is it part of the SNI to provide random/default certificate when no matching host name?


Solution

  • Is it part of the SNI to provide random/default certificate when no matching host name?

    SNI does not dictate a specific behavior of the server. All what it provides is a way that the server can find out which domain the client wants to access.

    The Behavior of the servers is very different: some ignore SNI at all since they have only a single configuration and certificate anyway. Others have some default in case no SNI is given or does not match. And the rest usually throws some kind of error if the name given by SNI does not match a specific configuration.