/******************************************************************************* * Copyright (c) 2005, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.osgi.tests.security; import java.io.*; import java.net.URL; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.ArrayList; import junit.framework.*; import org.eclipse.osgi.internal.service.security.KeyStoreTrustEngine; import org.eclipse.osgi.service.security.TrustEngine; import org.eclipse.osgi.tests.OSGiTestsActivator; public class KeyStoreTrustEngineTest extends TestCase { private static char[] PASSWORD_DEFAULT = {'c', 'h', 'a', 'n', 'g', 'e', 'i', 't'}; private static String TYPE_DEFAULT = "JKS"; //$NON-NLS-1$ private static TestCase[] s_tests = { /* findTrustAnchor tests */ new KeyStoreTrustEngineTest("findTrustAnchor positive test: self signed trusted", new String[] {"ca1_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testFindTrustAnchor0(); } }, new KeyStoreTrustEngineTest("findTrustAnchor positive test: chain with root trusted", new String[] {"ca1_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testFindTrustAnchor1(); } }, new KeyStoreTrustEngineTest("findTrustAnchor positive test: chain with intermediate trusted", new String[] {"ca1_ou"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testFindTrustAnchor2(); } }, new KeyStoreTrustEngineTest("findTrustAnchor positive test: chain with leaf trusted", new String[] {"ca1_leafb"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testFindTrustAnchor3(); } }, new KeyStoreTrustEngineTest("findTrustAnchor negative test: untrusted self signed", null) { //$NON-NLS-1$ public void runTest() { testFindTrustAnchor4(); } }, new KeyStoreTrustEngineTest("findTrustAnchor negative test: untrusted chain", null) { //$NON-NLS-1$ public void runTest() { testFindTrustAnchor5(); } }, new KeyStoreTrustEngineTest("findTrustAnchor negative test: invalid chain", null) { //$NON-NLS-1$ public void runTest() { testFindTrustAnchor6(); } }, new KeyStoreTrustEngineTest("findTrustAnchor negative test: incomplete-able chain", null) { //$NON-NLS-1$ public void runTest() { testFindTrustAnchor7(); } }, new KeyStoreTrustEngineTest("findTrustAnchor negative test: null chain", null) { //$NON-NLS-1$ public void runTest() { testFindTrustAnchor8(); } }, /* addTrustAnchor tests */ new KeyStoreTrustEngineTest("addTrustAnchor positive test: add with alias", null) { //$NON-NLS-1$ public void runTest() { testAddTrustAnchor0(); } },/*, new KeyStoreTrustEngineTest("addTrustAnchor positive test: add with autogenerated alias", null) { public void runTest() { testAddTrustAnchor1(); } }*/ new KeyStoreTrustEngineTest("addTrustAnchor negative test: null cert specified", null) { //$NON-NLS-1$ public void runTest() { testAddTrustAnchor2(); } }, new KeyStoreTrustEngineTest("addTrustAnchor negative test: existing cert specified", new String[] {"ca1_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testAddTrustAnchor3(); } }, new KeyStoreTrustEngineTest("addTrustAnchor negative test: existing alias specified", new String[] {"ca1_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testAddTrustAnchor4(); } } /* removeTrustAnchor tests */ , new KeyStoreTrustEngineTest("removeTrustAnchor positive test: remove by alias", new String[] {"ca1_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testRemoveTrustAnchor0(); } }, new KeyStoreTrustEngineTest("removeTrustAnchor positive test: remove by cert", new String[] {"ca1_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testRemoveTrustAnchor1(); } }, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: cert not found", null) { //$NON-NLS-1$ public void runTest() { testRemoveTrustAnchor2(); } }, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: by alias not found", null) { //$NON-NLS-1$ public void runTest() { testRemoveTrustAnchor3(); } }, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: remove by null alias", null) { //$NON-NLS-1$ public void runTest() { testRemoveTrustAnchor4(); } }, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: remove by null certificate", null) { //$NON-NLS-1$ public void runTest() { testRemoveTrustAnchor5(); } }, /* getTrustAnchor tests*/ new KeyStoreTrustEngineTest("getTrustAnchor positive test: get by alias", new String[] {"ca1_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ public void runTest() { testGetTrustAnchor0(); } }, new KeyStoreTrustEngineTest("getTrustAnchor negative test: get by null alias", null) { //$NON-NLS-1$ public void runTest() { testGetTrustAnchor1(); } }, new KeyStoreTrustEngineTest("getTrustAnchor negative test: does not exist", null) { //$NON-NLS-1$ public void runTest() { testGetTrustAnchor2(); } }, /* getAliases tests */ new KeyStoreTrustEngineTest("getAliases positive test: get the alias list", new String[] {"ca1_root", "ca2_root"}) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ public void runTest() { testGetAliases0(); } }}; public static Test suite() { TestSuite suite = new TestSuite("Unit tests for TrustEngine"); //$NON-NLS-1$ for (int i = 0; i < s_tests.length; i++) { suite.addTest(s_tests[i]); } return suite; } private static KeyStore supportStore; static { try { URL supportUrl = OSGiTestsActivator.getContext().getBundle().getEntry("test_files/security/keystore.jks"); //$NON-NLS-1$ supportStore = KeyStore.getInstance(TYPE_DEFAULT); supportStore.load(supportUrl.openStream(), PASSWORD_DEFAULT); } catch (Exception e) { e.printStackTrace(); } } private String[] aliases; private KeyStore testStore; private File testStoreFile; TrustEngine engine; public KeyStoreTrustEngineTest() { //placeholder } public KeyStoreTrustEngineTest(String name, String[] aliases) { super(name); this.aliases = aliases; } protected void setUp() throws Exception { if (supportStore == null) { fail("Could not open keystore with test certificates!"); //$NON-NLS-1$ } testStore = KeyStore.getInstance(TYPE_DEFAULT); testStore.load(null, PASSWORD_DEFAULT); if (aliases != null) { for (int i = 0; i < aliases.length; i++) { testStore.setCertificateEntry(aliases[i], getTestCertificate(aliases[i])); } } testStoreFile = File.createTempFile("teststore", "jks"); //$NON-NLS-1$ //$NON-NLS-2$ final FileOutputStream out = new FileOutputStream(testStoreFile); try { testStore.store(out, PASSWORD_DEFAULT); } finally { safeClose(out); } engine = new KeyStoreTrustEngine(testStoreFile.getPath(), TYPE_DEFAULT, PASSWORD_DEFAULT, "teststore", null); //$NON-NLS-1$ } /** * Closes a stream and ignores any resulting exception. This is useful * when doing stream cleanup in a finally block where secondary exceptions * are not worth logging. */ protected static void safeClose(OutputStream out) { try { if (out != null) out.close(); } catch (IOException e) { //ignore } } protected void tearDown() { engine = null; testStore = null; testStoreFile.delete(); } private static Certificate getTestCertificate(String alias) throws KeyStoreException { return supportStore.getCertificate(alias); } private static Certificate[] getTestCertificateChain(String[] aliases) throws KeyStoreException { ArrayList certs = new ArrayList(aliases.length); for (int i = 0; i < aliases.length; i++) { certs.add(getTestCertificate(aliases[i])); } return (Certificate[]) certs.toArray(new Certificate[] {}); } //findTrustAnchor positive test: self signed trusted public void testFindTrustAnchor0() { try { Certificate cert = engine.findTrustAnchor(new Certificate[] {getTestCertificate("ca1_root")}); //$NON-NLS-1$ assertNotNull("Did not return a cert for self-signed case", cert); //$NON-NLS-1$ assertEquals("Input and output certs not equal for self-signed case", cert, getTestCertificate("ca1_root")); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Throwable t) { fail("Unexpected exception testing trusted self-signed cert: " + t.getMessage()); //$NON-NLS-1$ } } //findTrustAnchor positive test: chain with root trusted public void testFindTrustAnchor1() { try { Certificate cert = engine.findTrustAnchor(getTestCertificateChain(new String[] {"ca1_leafb", "ca1_ou", "ca1_root"})); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertNotNull("Certificate did not come back in trusted root case", cert); //$NON-NLS-1$ assertEquals("Output cert is not root trusted cert", cert, getTestCertificate("ca1_root")); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Throwable t) { fail("Unexpected exception testing trusted root from complete chain: " + t.getMessage()); //$NON-NLS-1$ } } //findTrustAnchor positive test: chain with intermediate trusted public void testFindTrustAnchor2() { try { Certificate cert = engine.findTrustAnchor(getTestCertificateChain(new String[] {"ca1_leafb", "ca1_ou", "ca1_root"})); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertNotNull("Certificate did not come back in trusted intermediate case", cert); //$NON-NLS-1$ assertEquals("Output cert is not intermediate trusted cert", cert, getTestCertificate("ca1_ou")); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Throwable t) { fail("Unexpected exception testing trusted root from complete chain: " + t.getMessage()); //$NON-NLS-1$ } } //findTrustAnchor positive test: chain with leaf trusted public void testFindTrustAnchor3() { try { Certificate cert = engine.findTrustAnchor(getTestCertificateChain(new String[] {"ca1_leafb", "ca1_ou", "ca1_root"})); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertNotNull("Certificate did not come back in trusted leaf case", cert); //$NON-NLS-1$ assertEquals("Output cert is not leaf trusted cert", cert, getTestCertificate("ca1_leafb")); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Throwable t) { fail("Unexpected exception testing trusted root from complete chain: " + t.getMessage()); //$NON-NLS-1$ } } //findTrustAnchor negative test: untrusted self signed public void testFindTrustAnchor4() { try { Certificate cert = engine.findTrustAnchor(new Certificate[] {getTestCertificate("ca2_root")}); //$NON-NLS-1$ assertNull("Incorrectly returned a certificate for untrusted self-signed case", cert); //$NON-NLS-1$ } catch (Throwable t) { fail("Unexpected exception testing untrusted self-signed cert: " + t.getMessage()); //$NON-NLS-1$ } } //findTrustAnchor negative test: untrusted chain public void testFindTrustAnchor5() { try { Certificate cert = engine.findTrustAnchor(getTestCertificateChain(new String[] {"ca2_leafb", "ca2_ou", "ca2_root"})); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ assertNull("Incorrectly returned a certificate for untrusted chain case", cert); //$NON-NLS-1$ } catch (Throwable t) { fail("Unexpected exception testing untrusted chain: " + t.getMessage()); //$NON-NLS-1$ } } //findTrustAnchor negative test: invalid chain public void testFindTrustAnchor6() { try { Certificate cert = engine.findTrustAnchor(getTestCertificateChain(new String[] {"ca2_leafa", "ca1_root"})); //$NON-NLS-1$ //$NON-NLS-2$ assertNull("Incorrectly returned a certificate on invalid certificate chain", cert); //$NON-NLS-1$ } catch (Throwable t) { assertNull("Incorrectly thrown exception thrown on invalid certificate chain", t); //$NON-NLS-1$ } } //findTrustAnchor negative test: incomplete-able chain public void testFindTrustAnchor7() { try { Certificate cert = engine.findTrustAnchor(getTestCertificateChain(new String[] {"ca1_leafb", "ca1_root"})); //$NON-NLS-1$ //$NON-NLS-2$ assertNull("Incorrectly returned a certificate on incomplete-able certificate chain", cert); //$NON-NLS-1$ } catch (Throwable t) { assertNull("Incorrectly thrown exception thrown on incomplete-able certificate chain", t); //$NON-NLS-1$ } } //findTrustAnchor negative test: null chain public void testFindTrustAnchor8() { try { engine.findTrustAnchor(null); fail("Did not throw IllegalArgumentException on NULL certificate"); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on NULL certificate", t instanceof IllegalArgumentException); //$NON-NLS-1$ } } //testAddTrustAnchor positive test: add with alias public void testAddTrustAnchor0() { try { String alias = engine.addTrustAnchor(getTestCertificate("ca1_root"), "ca1_root"); //$NON-NLS-1$ //$NON-NLS-2$ assertEquals("Alias returned does not equal alias input", alias, "ca1_root"); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Throwable t) { fail("Unexpected exception adding trusted root: " + t.getMessage()); //$NON-NLS-1$ } } //testAddTrustAnchor positive test: add with autogenerated alias public void testAddTrustAnchor1() { try { String alias = engine.addTrustAnchor(getTestCertificate("ca1_root"), null); //$NON-NLS-1$ assertNotNull("Generated alias was not correctly returned", alias); //$NON-NLS-1$ } catch (Throwable t) { fail("Unexpected exception adding trusted root (autogen alias): " + t.getMessage()); //$NON-NLS-1$ } } //testAddTrustAnchor negative test: null cert specified public void testAddTrustAnchor2() { try { engine.addTrustAnchor(null, "ca1_root"); //$NON-NLS-1$ fail("Did not throw IllegalArgumentException on NULL certificate"); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on NULL certificate", t instanceof IllegalArgumentException); //$NON-NLS-1$ } } //testAddTrustAnchor negative test: existing cert specified public void testAddTrustAnchor3() { try { engine.addTrustAnchor(getTestCertificate("ca1_root"), "new_root"); //$NON-NLS-1$ //$NON-NLS-2$ assertTrue("Did not throw CertificateException on duplicate cert", false); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on duplicate cert", t instanceof CertificateException); //$NON-NLS-1$ return; } fail("Expected exception when adding trust anchor"); //$NON-NLS-1$ } //testAddTrustAnchor negative test: existing alias specified public void testAddTrustAnchor4() { try { engine.addTrustAnchor(getTestCertificate("ca2_root"), "ca1_root"); //$NON-NLS-1$ //$NON-NLS-2$ assertTrue("Did not throw CertificateException on duplicate alias", false); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on duplicate alias", t instanceof CertificateException); //$NON-NLS-1$ return; } fail("Expected exception when adding trust anchor"); //$NON-NLS-1$ } //removeTrustAnchor positive test: remove by alias public void testRemoveTrustAnchor0() { try { engine.removeTrustAnchor("ca1_root"); //$NON-NLS-1$ } catch (Throwable t) { fail("Unexpected exception thrown when removing by alias: " + t.getMessage()); //$NON-NLS-1$ } } //removeTrustAnchor positive test: remove by cert public void testRemoveTrustAnchor1() { try { engine.removeTrustAnchor(getTestCertificate("ca1_root")); //$NON-NLS-1$ } catch (Throwable t) { fail("Unexpected exception thrown when removing by cert: " + t.getMessage()); //$NON-NLS-1$ } } //removeTrustAnchor negative test: cert not found public void testRemoveTrustAnchor2() { try { engine.removeTrustAnchor(getTestCertificate("ca1_root")); //$NON-NLS-1$ fail("Did not throw CertificateException on cert not found"); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on remove by cert", t instanceof CertificateException); //$NON-NLS-1$ } } //removeTrustAnchor negative test: by alias not found public void testRemoveTrustAnchor3() { try { engine.removeTrustAnchor("ca2_root"); //$NON-NLS-1$ assertTrue("Did not throw CertificateException on alias not found", false); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on remove by alias", t instanceof CertificateException); //$NON-NLS-1$ return; } fail("Expected exception when removing trust anchor"); //$NON-NLS-1$ } //removeTrustAnchor negative test: remove by null alias public void testRemoveTrustAnchor4() { try { engine.removeTrustAnchor((String) null); fail("Did not throw CertificateException on alias null"); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on remove by null alias", t instanceof IllegalArgumentException); //$NON-NLS-1$ } } //removeTrustAnchor negative test: remove by null certificate public void testRemoveTrustAnchor5() { try { engine.removeTrustAnchor((Certificate) null); fail("Did not throw IllegalArgumentException on remove by cert null"); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on remove by null cert", t instanceof IllegalArgumentException); //$NON-NLS-1$ } } //getTrustAnchor positive test: get by alias public void testGetTrustAnchor0() { try { Certificate cert = engine.getTrustAnchor("ca1_root"); //$NON-NLS-1$ assertEquals("Did not get expected certificate", getTestCertificate("ca1_root"), cert); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Throwable t) { fail("Unexpected exception when retrieving trust anchor: " + t.getMessage()); //$NON-NLS-1$ } } //getTrustAnchor negative test: get by null alias public void testGetTrustAnchor1() { try { engine.getTrustAnchor(null); fail("Did not throw IllegalArgumentException on get by alias null"); //$NON-NLS-1$ } catch (Throwable t) { assertTrue("Incorrect exception thrown on remove by null alias", t instanceof IllegalArgumentException); //$NON-NLS-1$ } } //getTrustAnchor negative test: does not exist public void testGetTrustAnchor2() { try { Certificate cert = engine.getTrustAnchor("ca2_root"); //$NON-NLS-1$ assertNull("Incorrectly returned a certificate on certificate does not exist", cert); //$NON-NLS-1$ } catch (Throwable t) { assertNull("Incorrectly thrown exception on alias does not exist", t); //$NON-NLS-1$ return; } } //getAliases positive test: get the alias list public void testGetAliases0() { try { engine.getAliases(); } catch (Throwable t) { fail("Unexpected exception when retrieving alias list: " + t.getMessage()); //$NON-NLS-1$ } } //TODO: thread safety tests //TODO: performance tests }