blob: 4c493d0dad18d2e68777de2b1286e542e2c80dda [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.
*/
package org.apache.qpid.server.ssl;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.qpid.server.transport.network.security.ssl.QpidMultipleTrustManager;
import org.apache.qpid.server.transport.network.security.ssl.QpidPeersOnlyTrustManager;
import org.apache.qpid.test.utils.UnitTestBase;
import org.apache.qpid.test.utils.tls.CertificateEntry;
import org.apache.qpid.test.utils.tls.KeyCertificatePair;
import org.apache.qpid.test.utils.tls.TlsResourceBuilder;
import org.apache.qpid.test.utils.tls.TlsResourceHelper;
public class TrustManagerTest extends UnitTestBase
{
private static final String DEFAULT_TRUST_MANAGER_ALGORITHM = TrustManagerFactory.getDefaultAlgorithm();
private static final String TEST_ALIAS = "test";
private static final String DN_CA = "CN=MyRootCA,O=ACME,ST=Ontario,C=CA";
private static final String DN_APP1 = "CN=app1@acme.org,OU=art,O=acme,L=Toronto,ST=ON,C=CA";
private static final String DN_APP2 = "CN=app2@acme.org,OU=art,O=acme,L=Toronto,ST=ON,C=CA";
private static final String DN_UNTRUSTED = "CN=untrusted_client";
private static X509Certificate _ca;
private static X509Certificate _app1;
private static X509Certificate _app2;
private static X509Certificate _untrusted;
@BeforeClass
public static void setUp() throws Exception
{
final KeyCertificatePair caPair = TlsResourceBuilder.createKeyPairAndRootCA(DN_CA);
final KeyPair keyPair1 = TlsResourceBuilder.createRSAKeyPair();
final KeyPair keyPair2 = TlsResourceBuilder.createRSAKeyPair();
final KeyCertificatePair untrustedKeyCertPair = TlsResourceBuilder.createSelfSigned(DN_UNTRUSTED);
_ca = caPair.getCertificate();
_app1 = TlsResourceBuilder.createCertificateForClientAuthorization(keyPair1, caPair, DN_APP1);
_app2 = TlsResourceBuilder.createCertificateForClientAuthorization(keyPair2, caPair, DN_APP2);
_untrusted = untrustedKeyCertPair.getCertificate();
}
/**
* Tests that the QpidPeersOnlyTrustManager gives the expected behaviour when loaded separately
* with the peer certificate and CA root certificate.
*/
@Test
public void testQpidPeersOnlyTrustManager() throws Exception
{
// peer manager is supposed to trust only clients which peers certificates
// are directly in the store. CA signing will not be considered.
X509TrustManager peerManager = createPeerManager(_app1);
try
{
// since peer manager contains the client's app1 certificate, the check should succeed
peerManager.checkClientTrusted(new X509Certificate[]{_app1, _ca }, "RSA");
}
catch (CertificateException e)
{
fail("Trusted client's validation against the broker's peer store manager failed.");
}
try
{
// since peer manager does not contain the client's app2 certificate, the check should fail
peerManager.checkClientTrusted(new X509Certificate[]{_app2, _ca }, "RSA");
fail("Untrusted client's validation against the broker's peer store manager succeeded.");
}
catch (CertificateException e)
{
//expected
}
// now let's check that peer manager loaded with the CA certificate fails because
// it does not have the clients certificate in it (though it does have a CA-cert that
// would otherwise trust the client cert when using the regular trust manager).
peerManager = createPeerManager(_ca);
try
{
// since trust manager doesn't contain the client's app1 certificate, the check should fail
// despite the fact that the truststore does have a CA that would otherwise trust the cert
peerManager.checkClientTrusted(new X509Certificate[]{_app1, _ca }, "RSA");
fail("Client's validation against the broker's peer store manager didn't fail.");
}
catch (CertificateException e)
{
// expected
}
try
{
// since trust manager doesn't contain the client's app2 certificate, the check should fail
// despite the fact that the truststore does have a CA that would otherwise trust the cert
peerManager.checkClientTrusted(new X509Certificate[]{_app2, _ca }, "RSA");
fail("Client's validation against the broker's peer store manager didn't fail.");
}
catch (CertificateException e)
{
// expected
}
}
/**
* Tests that the QpidMultipleTrustManager gives the expected behaviour when wrapping a
* regular CA root certificate.
*/
@Test
public void testQpidMultipleTrustManagerWithRegularTrustStore() throws Exception
{
final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager();
final X509TrustManager tm = createTrustManager(_ca);
assertNotNull("The regular trust manager for the trust store was not found", tm);
mulTrustManager.addTrustManager(tm);
try
{
// verify the CA-trusted app1 cert (should succeed)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_app1, _ca }, "RSA");
}
catch (CertificateException ex)
{
fail("Trusted client's validation against the broker's multi store manager failed.");
}
try
{
// verify the CA-trusted app2 cert (should succeed)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_app2, _ca }, "RSA");
}
catch (CertificateException ex)
{
fail("Trusted client's validation against the broker's multi store manager failed.");
}
try
{
// verify the untrusted cert (should fail)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_untrusted}, "RSA");
fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed.");
}
catch (CertificateException ex)
{
// expected
}
}
/**
* Tests that the QpidMultipleTrustManager gives the expected behaviour when wrapping a
* QpidPeersOnlyTrustManager against the peer certificate
*/
@Test
public void testQpidMultipleTrustManagerWithPeerStore() throws Exception
{
final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager();
final KeyStore ps = createKeyStore(_app1);
final X509TrustManager tm = getX509TrustManager(ps);
assertNotNull("The regular trust manager for the trust store was not found", tm);
mulTrustManager.addTrustManager(new QpidPeersOnlyTrustManager(ps, tm));
try
{
// verify the trusted app1 cert (should succeed as the key is in the peerstore)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_app1, _ca }, "RSA");
}
catch (CertificateException ex)
{
fail("Trusted client's validation against the broker's multi store manager failed.");
}
try
{
// verify the untrusted app2 cert (should fail as the key is not in the peerstore)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_app2, _ca }, "RSA");
fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed.");
}
catch (CertificateException ex)
{
// expected
}
try
{
// verify the untrusted cert (should fail as the key is not in the peerstore)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_untrusted }, "RSA");
fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed.");
}
catch (CertificateException ex)
{
// expected
}
}
/**
* Tests that the QpidMultipleTrustManager gives the expected behaviour when wrapping a
* QpidPeersOnlyTrustManager against the peer certificate, a regular TrustManager
* against the CA root certificate.
*/
@Test
public void testQpidMultipleTrustManagerWithTrustAndPeerStores() throws Exception
{
final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager();
final KeyStore ts = createKeyStore(_ca);
final X509TrustManager tm = getX509TrustManager(ts);
assertNotNull("The regular trust manager for the trust store was not found", tm);
mulTrustManager.addTrustManager(tm);
final KeyStore ps = createKeyStore(_app1);
final X509TrustManager tm2 = getX509TrustManager(ts);
assertNotNull("The regular trust manager for the peer store was not found", tm2);
mulTrustManager.addTrustManager(new QpidPeersOnlyTrustManager(ps, tm2));
try
{
// verify the CA-trusted app1 cert (should succeed)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_app1, _ca }, "RSA");
}
catch (CertificateException ex)
{
fail("Trusted client's validation against the broker's multi store manager failed.");
}
try
{
// verify the CA-trusted app2 cert (should succeed)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_app2, _ca }, "RSA");
}
catch (CertificateException ex)
{
fail("Trusted client's validation against the broker's multi store manager failed.");
}
try
{
// verify the untrusted cert (should fail)
mulTrustManager.checkClientTrusted(new X509Certificate[]{_untrusted }, "RSA");
fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed.");
}
catch (CertificateException ex)
{
// expected
}
}
private KeyStore createKeyStore(X509Certificate certificate)
throws Exception
{
return TlsResourceHelper.createKeyStore(KeyStore.getDefaultType(),
new char[]{},
new CertificateEntry(TEST_ALIAS, certificate));
}
private X509TrustManager createTrustManager(final X509Certificate certificate) throws Exception
{
return getX509TrustManager(createKeyStore(certificate));
}
private X509TrustManager getX509TrustManager(final KeyStore ps) throws Exception
{
final TrustManagerFactory pmf = TrustManagerFactory.getInstance(DEFAULT_TRUST_MANAGER_ALGORITHM);
pmf.init(ps);
final TrustManager[] delegateTrustManagers = pmf.getTrustManagers();
X509TrustManager trustManager = null;
for (final TrustManager tm : delegateTrustManagers)
{
if (tm instanceof X509TrustManager)
{
trustManager = (X509TrustManager) tm;
}
}
return trustManager;
}
private X509TrustManager createPeerManager(final X509Certificate certificate) throws Exception
{
final KeyStore ps = createKeyStore(certificate);
final X509TrustManager tm = createTrustManager(certificate);
return new QpidPeersOnlyTrustManager(ps, tm);
}
}