blob: c6319ee5a9fc3c1d0b4e8788d910d2f00ec52e21 [file] [log] [blame]
/*
* Copyright 2019 The gRPC Authors
*
* Licensed 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.
*/
package io.grpc.xds.internal.security.trust;
import static com.google.common.truth.Truth.assertThat;
import static io.grpc.xds.internal.security.CommonTlsContextTestsUtil.BAD_SERVER_PEM_FILE;
import static io.grpc.xds.internal.security.CommonTlsContextTestsUtil.CA_PEM_FILE;
import static io.grpc.xds.internal.security.CommonTlsContextTestsUtil.CLIENT_PEM_FILE;
import static io.grpc.xds.internal.security.CommonTlsContextTestsUtil.SERVER_1_PEM_FILE;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext;
import io.envoyproxy.envoy.type.matcher.v3.RegexMatcher;
import io.envoyproxy.envoy.type.matcher.v3.StringMatcher;
import io.grpc.internal.testing.TestUtils;
import java.io.IOException;
import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.X509ExtendedTrustManager;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/**
* Unit tests for {@link XdsX509TrustManager}.
*/
@RunWith(JUnit4.class)
public class XdsX509TrustManagerTest {
@Rule
public final MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock
private X509ExtendedTrustManager mockDelegate;
@Mock
private SSLSession mockSession;
private XdsX509TrustManager trustManager;
@Test
public void nullCertContextTest() throws CertificateException, IOException {
trustManager = new XdsX509TrustManager(null, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void emptySanListContextTest() throws CertificateException, IOException {
CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void missingPeerCerts() {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("foo.com").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
try {
trustManager.verifySubjectAltNameInChain(null);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate(s) missing");
}
}
@Test
public void emptyArrayPeerCerts() {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("foo.com").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
try {
trustManager.verifySubjectAltNameInChain(new X509Certificate[0]);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate(s) missing");
}
}
@Test
public void noSansInPeerCerts() throws CertificateException, IOException {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("foo.com").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(CLIENT_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void oneSanInPeerCertsVerifies() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setExact("waterzooi.test.google.be")
.setIgnoreCase(false)
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCertsVerifies_differentCase_expectException()
throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setExact("waterZooi.test.Google.be")
.setIgnoreCase(false)
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void oneSanInPeerCertsVerifies_ignoreCase() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setExact("Waterzooi.Test.google.be").setIgnoreCase(true).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCerts_prefix() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setPrefix("waterzooi.") // test.google.be
.setIgnoreCase(false)
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCertsPrefix_differentCase_expectException()
throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setPrefix("waterZooi.").setIgnoreCase(false).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void oneSanInPeerCerts_prefixIgnoreCase() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setPrefix("WaterZooi.") // test.google.be
.setIgnoreCase(true)
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCerts_suffix() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setSuffix(".google.be").setIgnoreCase(false).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCertsSuffix_differentCase_expectException()
throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setSuffix(".gooGle.bE").setIgnoreCase(false).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void oneSanInPeerCerts_suffixIgnoreCase() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setSuffix(".GooGle.BE").setIgnoreCase(true).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCerts_substring() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setContains("zooi.test.google").setIgnoreCase(false).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCertsSubstring_differentCase_expectException()
throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setContains("zooi.Test.gooGle").setIgnoreCase(false).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void oneSanInPeerCerts_substringIgnoreCase() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder().setContains("zooI.Test.Google").setIgnoreCase(true).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCerts_safeRegex() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setSafeRegex(
RegexMatcher.newBuilder().setRegex("water[[:alpha:]]{1}ooi\\.test\\.google\\.be"))
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCerts_safeRegex1() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setSafeRegex(
RegexMatcher.newBuilder().setRegex("no-match-string|\\*\\.test\\.youtube\\.com"))
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCerts_safeRegex_ipAddress() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setSafeRegex(
RegexMatcher.newBuilder().setRegex("([[:digit:]]{1,3}\\.){3}[[:digit:]]{1,3}"))
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCerts_safeRegex_noMatch() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setSafeRegex(
RegexMatcher.newBuilder().setRegex("water[[:alpha:]]{2}ooi\\.test\\.google\\.be"))
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void oneSanInPeerCertsVerifiesMultipleVerifySans()
throws CertificateException, IOException {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("x.foo.com").build();
StringMatcher stringMatcher1 =
StringMatcher.newBuilder().setExact("waterzooi.test.google.be").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder()
.addMatchSubjectAltNames(stringMatcher)
.addMatchSubjectAltNames(stringMatcher1)
.build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneSanInPeerCertsNotFoundException()
throws CertificateException, IOException {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("x.foo.com").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void wildcardSanInPeerCertsVerifiesMultipleVerifySans()
throws CertificateException, IOException {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("x.foo.com").build();
StringMatcher stringMatcher1 =
StringMatcher.newBuilder().setSuffix("test.youTube.Com").setIgnoreCase(true).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder()
.addMatchSubjectAltNames(stringMatcher)
.addMatchSubjectAltNames(stringMatcher1) // should match suffix test.youTube.Com
.build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void wildcardSanInPeerCertsVerifiesMultipleVerifySans1()
throws CertificateException, IOException {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("x.foo.com").build();
StringMatcher stringMatcher1 =
StringMatcher.newBuilder().setContains("est.Google.f").setIgnoreCase(true).build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder()
.addMatchSubjectAltNames(stringMatcher)
.addMatchSubjectAltNames(stringMatcher1) // should contain est.Google.f
.build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void wildcardSanInPeerCertsSubdomainMismatch()
throws CertificateException, IOException {
// 2. Asterisk (*) cannot match across domain name labels.
// For example, *.example.com matches test.example.com but does not match
// sub.test.example.com.
StringMatcher stringMatcher =
StringMatcher.newBuilder().setExact("sub.abc.test.youtube.com").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void oneIpAddressInPeerCertsVerifies() throws CertificateException, IOException {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("x.foo.com").build();
StringMatcher stringMatcher1 = StringMatcher.newBuilder().setExact("192.168.1.3").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder()
.addMatchSubjectAltNames(stringMatcher)
.addMatchSubjectAltNames(stringMatcher1)
.build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.verifySubjectAltNameInChain(certs);
}
@Test
public void oneIpAddressInPeerCertsMismatch() throws CertificateException, IOException {
StringMatcher stringMatcher = StringMatcher.newBuilder().setExact("x.foo.com").build();
StringMatcher stringMatcher1 = StringMatcher.newBuilder().setExact("192.168.2.3").build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder()
.addMatchSubjectAltNames(stringMatcher)
.addMatchSubjectAltNames(stringMatcher1)
.build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate[] certs =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
@Test
public void checkServerTrustedSslEngine()
throws CertificateException, IOException, CertStoreException {
TestSslEngine sslEngine = buildTrustManagerAndGetSslEngine();
X509Certificate[] serverCerts =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.checkServerTrusted(serverCerts, "ECDHE_ECDSA", sslEngine);
verify(sslEngine, times(1)).getHandshakeSession();
}
@Test
public void checkServerTrustedSslEngine_untrustedServer_expectException()
throws CertificateException, IOException, CertStoreException {
TestSslEngine sslEngine = buildTrustManagerAndGetSslEngine();
X509Certificate[] badServerCert =
CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_SERVER_PEM_FILE));
try {
trustManager.checkServerTrusted(badServerCert, "ECDHE_ECDSA", sslEngine);
fail("exception expected");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat()
.endsWith("unable to find valid certification path to requested target");
}
verify(sslEngine, times(1)).getHandshakeSession();
}
@Test
public void checkServerTrustedSslSocket()
throws CertificateException, IOException, CertStoreException {
TestSslSocket sslSocket = buildTrustManagerAndGetSslSocket();
X509Certificate[] serverCerts =
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
trustManager.checkServerTrusted(serverCerts, "ECDHE_ECDSA", sslSocket);
verify(sslSocket, times(1)).isConnected();
verify(sslSocket, times(1)).getHandshakeSession();
}
@Test
public void checkServerTrustedSslSocket_untrustedServer_expectException()
throws CertificateException, IOException, CertStoreException {
TestSslSocket sslSocket = buildTrustManagerAndGetSslSocket();
X509Certificate[] badServerCert =
CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_SERVER_PEM_FILE));
try {
trustManager.checkServerTrusted(badServerCert, "ECDHE_ECDSA", sslSocket);
fail("exception expected");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat()
.endsWith("unable to find valid certification path to requested target");
}
verify(sslSocket, times(1)).isConnected();
verify(sslSocket, times(1)).getHandshakeSession();
}
@Test
public void unsupportedAltNameType() throws CertificateException, IOException {
StringMatcher stringMatcher =
StringMatcher.newBuilder()
.setExact("waterzooi.test.google.be")
.setIgnoreCase(false)
.build();
@SuppressWarnings("deprecation")
CertificateValidationContext certContext =
CertificateValidationContext.newBuilder().addMatchSubjectAltNames(stringMatcher).build();
trustManager = new XdsX509TrustManager(certContext, mockDelegate);
X509Certificate mockCert = mock(X509Certificate.class);
when(mockCert.getSubjectAlternativeNames())
.thenReturn(Collections.<List<?>>singleton(ImmutableList.of(Integer.valueOf(1), "foo")));
X509Certificate[] certs = new X509Certificate[] {mockCert};
try {
trustManager.verifySubjectAltNameInChain(certs);
fail("no exception thrown");
} catch (CertificateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed");
}
}
private TestSslEngine buildTrustManagerAndGetSslEngine()
throws CertificateException, IOException, CertStoreException {
SSLParameters sslParams = buildTrustManagerAndGetSslParameters();
TestSslEngine sslEngine = mock(TestSslEngine.class, CALLS_REAL_METHODS);
sslEngine.setSSLParameters(sslParams);
doReturn(mockSession).when(sslEngine).getHandshakeSession();
return sslEngine;
}
private TestSslSocket buildTrustManagerAndGetSslSocket()
throws CertificateException, IOException, CertStoreException {
SSLParameters sslParams = buildTrustManagerAndGetSslParameters();
TestSslSocket sslSocket = mock(TestSslSocket.class, CALLS_REAL_METHODS);
sslSocket.setSSLParameters(sslParams);
doReturn(true).when(sslSocket).isConnected();
doReturn(mockSession).when(sslSocket).getHandshakeSession();
return sslSocket;
}
private SSLParameters buildTrustManagerAndGetSslParameters()
throws CertificateException, IOException, CertStoreException {
X509Certificate[] caCerts =
CertificateUtils.toX509Certificates(TestUtils.loadCert(CA_PEM_FILE));
trustManager = XdsTrustManagerFactory.createSdsX509TrustManager(caCerts,
null);
when(mockSession.getProtocol()).thenReturn("TLSv1.2");
when(mockSession.getPeerHost()).thenReturn("peer-host-from-mock");
SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
return sslParams;
}
private abstract static class TestSslSocket extends SSLSocket {
@Override
public SSLParameters getSSLParameters() {
return sslParameters;
}
@Override
public void setSSLParameters(SSLParameters sslParameters) {
this.sslParameters = sslParameters;
}
private SSLParameters sslParameters;
}
private abstract static class TestSslEngine extends SSLEngine {
@Override
public SSLParameters getSSLParameters() {
return sslParameters;
}
@Override
public void setSSLParameters(SSLParameters sslParameters) {
this.sslParameters = sslParameters;
}
private SSLParameters sslParameters;
}
}