mirror of https://github.com/grpc/grpc-java.git
xds: SdsTrustManagerFactory implementation - uses SdsX509TrustManager (#6267)
This commit is contained in:
parent
9eca2dcc4f
commit
4fc41bd0e1
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.sds.trust;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext;
|
||||
import io.grpc.Internal;
|
||||
import io.netty.handler.ssl.util.SimpleTrustManagerFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.net.ssl.ManagerFactoryParameters;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
|
||||
/**
|
||||
* Factory class used by providers of {@link io.grpc.xds.sds.TlsContextManager} to provide a {@link
|
||||
* SdsX509TrustManager} for trust and SAN checks.
|
||||
*/
|
||||
@Internal
|
||||
public final class SdsTrustManagerFactory extends SimpleTrustManagerFactory {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SdsTrustManagerFactory.class.getName());
|
||||
private SdsX509TrustManager sdsX509TrustManager;
|
||||
|
||||
/** Constructor that loads certs from a file. */
|
||||
public SdsTrustManagerFactory(
|
||||
String certsFile, @Nullable CertificateValidationContext certContext)
|
||||
throws CertificateException, IOException, CertStoreException {
|
||||
this(CertificateUtils.toX509Certificates(new File(certsFile)), certContext);
|
||||
}
|
||||
|
||||
/** Constructor that takes array of certs. */
|
||||
public SdsTrustManagerFactory(
|
||||
X509Certificate[] certs, @Nullable CertificateValidationContext certContext)
|
||||
throws CertStoreException {
|
||||
checkNotNull(certs, "certs");
|
||||
createSdsX509TrustManager(certs, certContext);
|
||||
}
|
||||
|
||||
private void createSdsX509TrustManager(
|
||||
X509Certificate[] certs, CertificateValidationContext certContext) throws CertStoreException {
|
||||
TrustManagerFactory tmf = null;
|
||||
try {
|
||||
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
KeyStore ks = KeyStore.getInstance("PKCS12");
|
||||
// perform a load to initialize KeyStore
|
||||
ks.load(/* stream= */ null, /* password= */ null);
|
||||
int i = 1;
|
||||
for (X509Certificate cert : certs) {
|
||||
// note: alias lookup uses toLowerCase(Locale.ENGLISH)
|
||||
// so our alias needs to be all lower-case and unique
|
||||
ks.setCertificateEntry("alias" + Integer.toString(i), cert);
|
||||
i++;
|
||||
}
|
||||
tmf.init(ks);
|
||||
} catch (NoSuchAlgorithmException | KeyStoreException | IOException | CertificateException e) {
|
||||
logger.log(Level.SEVERE, "createSdsX509TrustManager", e);
|
||||
throw new CertStoreException(e);
|
||||
}
|
||||
TrustManager[] tms = tmf.getTrustManagers();
|
||||
X509ExtendedTrustManager myDelegate = null;
|
||||
if (tms != null) {
|
||||
for (TrustManager tm : tms) {
|
||||
if (tm instanceof X509ExtendedTrustManager) {
|
||||
myDelegate = (X509ExtendedTrustManager) tm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (myDelegate == null) {
|
||||
throw new CertStoreException("Native X509 TrustManager not found.");
|
||||
}
|
||||
sdsX509TrustManager = new SdsX509TrustManager(certContext, myDelegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInit(KeyStore keyStore) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInit(ManagerFactoryParameters managerFactoryParameters) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrustManager[] engineGetTrustManagers() {
|
||||
return new TrustManager[] {sdsX509TrustManager};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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.sds.trust;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
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 javax.net.ssl.TrustManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link SdsTrustManagerFactory}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class SdsTrustManagerFactoryTest {
|
||||
|
||||
/** Trust store cert. */
|
||||
private static final String CA_PEM_FILE = "ca.pem";
|
||||
|
||||
/** server cert. */
|
||||
private static final String SERVER_1_PEM_FILE = "server1.pem";
|
||||
|
||||
/** client cert. */
|
||||
private static final String CLIENT_PEM_FILE = "client.pem";
|
||||
|
||||
/** bad server cert. */
|
||||
private static final String BAD_SERVER_PEM_FILE = "badserver.pem";
|
||||
|
||||
/** bad client cert. */
|
||||
private static final String BAD_CLIENT_PEM_FILE = "badclient.pem";
|
||||
|
||||
@Test
|
||||
public void constructor_fromFile() throws CertificateException, IOException, CertStoreException {
|
||||
SdsTrustManagerFactory factory =
|
||||
new SdsTrustManagerFactory(
|
||||
TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null);
|
||||
assertThat(factory).isNotNull();
|
||||
TrustManager[] tms = factory.getTrustManagers();
|
||||
assertThat(tms).isNotNull();
|
||||
assertThat(tms).hasLength(1);
|
||||
TrustManager myTm = tms[0];
|
||||
assertThat(myTm).isInstanceOf(SdsX509TrustManager.class);
|
||||
SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) myTm;
|
||||
X509Certificate[] acceptedIssuers = sdsX509TrustManager.getAcceptedIssuers();
|
||||
assertThat(acceptedIssuers).isNotNull();
|
||||
assertThat(acceptedIssuers).hasLength(1);
|
||||
X509Certificate caCert = acceptedIssuers[0];
|
||||
assertThat(caCert)
|
||||
.isEqualTo(CertificateUtils.toX509Certificates(TestUtils.loadCert(CA_PEM_FILE))[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkServerTrusted_goodCert()
|
||||
throws CertificateException, IOException, CertStoreException {
|
||||
SdsTrustManagerFactory factory =
|
||||
new SdsTrustManagerFactory(
|
||||
TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null);
|
||||
SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0];
|
||||
X509Certificate[] serverChain =
|
||||
CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE));
|
||||
sdsX509TrustManager.checkServerTrusted(serverChain, "RSA");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkClientTrusted_goodCert()
|
||||
throws CertificateException, IOException, CertStoreException {
|
||||
SdsTrustManagerFactory factory =
|
||||
new SdsTrustManagerFactory(
|
||||
TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null);
|
||||
SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0];
|
||||
X509Certificate[] clientChain =
|
||||
CertificateUtils.toX509Certificates(TestUtils.loadCert(CLIENT_PEM_FILE));
|
||||
sdsX509TrustManager.checkClientTrusted(clientChain, "RSA");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkServerTrusted_badCert_throwsException()
|
||||
throws CertificateException, IOException, CertStoreException {
|
||||
SdsTrustManagerFactory factory =
|
||||
new SdsTrustManagerFactory(
|
||||
TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null);
|
||||
SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0];
|
||||
X509Certificate[] serverChain =
|
||||
CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_SERVER_PEM_FILE));
|
||||
try {
|
||||
sdsX509TrustManager.checkServerTrusted(serverChain, "RSA");
|
||||
Assert.fail("no exception thrown");
|
||||
} catch (CertificateException expected) {
|
||||
assertThat(expected)
|
||||
.hasMessageThat()
|
||||
.contains("unable to find valid certification path to requested target");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkClientTrusted_badCert_throwsException()
|
||||
throws CertificateException, IOException, CertStoreException {
|
||||
SdsTrustManagerFactory factory =
|
||||
new SdsTrustManagerFactory(
|
||||
TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null);
|
||||
SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0];
|
||||
X509Certificate[] clientChain =
|
||||
CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_CLIENT_PEM_FILE));
|
||||
try {
|
||||
sdsX509TrustManager.checkClientTrusted(clientChain, "RSA");
|
||||
Assert.fail("no exception thrown");
|
||||
} catch (CertificateException expected) {
|
||||
assertThat(expected)
|
||||
.hasMessageThat()
|
||||
.contains("unable to find valid certification path to requested target");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue