blob: aea0a0f61bf750b3a8b110ed4bbc80ce5147bc30 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.tests.security;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
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.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
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", "ca1_root") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testFindTrustAnchor0();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor positive test: chain with root trusted", "ca1_root") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testFindTrustAnchor1();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor positive test: chain with intermediate trusted", "ca1_ou") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testFindTrustAnchor2();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor positive test: chain with leaf trusted", "ca1_leafb") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testFindTrustAnchor3();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor negative test: untrusted self signed") { //$NON-NLS-1$
public void runTest() {
testFindTrustAnchor4();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor negative test: untrusted chain") { //$NON-NLS-1$
public void runTest() {
testFindTrustAnchor5();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor negative test: invalid chain") { //$NON-NLS-1$
public void runTest() {
testFindTrustAnchor6();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor negative test: incomplete-able chain") { //$NON-NLS-1$
public void runTest() {
testFindTrustAnchor7();
}
}, new KeyStoreTrustEngineTest("findTrustAnchor negative test: null chain") { //$NON-NLS-1$
public void runTest() {
testFindTrustAnchor8();
}
},
/* addTrustAnchor tests */
new KeyStoreTrustEngineTest("addTrustAnchor positive test: add with alias") { //$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") { //$NON-NLS-1$
public void runTest() {
testAddTrustAnchor2();
}
}, new KeyStoreTrustEngineTest("addTrustAnchor negative test: existing cert specified", "ca1_root") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testAddTrustAnchor3();
}
}, new KeyStoreTrustEngineTest("addTrustAnchor negative test: existing alias specified", "ca1_root") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testAddTrustAnchor4();
}
}
/* removeTrustAnchor tests */
, new KeyStoreTrustEngineTest("removeTrustAnchor positive test: remove by alias", "ca1_root") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testRemoveTrustAnchor0();
}
}, new KeyStoreTrustEngineTest("removeTrustAnchor positive test: remove by cert", "ca1_root") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testRemoveTrustAnchor1();
}
}, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: cert not found") { //$NON-NLS-1$
public void runTest() {
testRemoveTrustAnchor2();
}
}, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: by alias not found") { //$NON-NLS-1$
public void runTest() {
testRemoveTrustAnchor3();
}
}, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: remove by null alias") { //$NON-NLS-1$
public void runTest() {
testRemoveTrustAnchor4();
}
}, new KeyStoreTrustEngineTest("removeTrustAnchor negative test: remove by null certificate") { //$NON-NLS-1$
public void runTest() {
testRemoveTrustAnchor5();
}
},
/* getTrustAnchor tests*/
new KeyStoreTrustEngineTest("getTrustAnchor positive test: get by alias", "ca1_root") { //$NON-NLS-1$ //$NON-NLS-2$
public void runTest() {
testGetTrustAnchor0();
}
}, new KeyStoreTrustEngineTest("getTrustAnchor negative test: get by null alias") { //$NON-NLS-1$
public void runTest() {
testGetTrustAnchor1();
}
}, new KeyStoreTrustEngineTest("getTrustAnchor negative test: does not exist") { //$NON-NLS-1$
public void runTest() {
testGetTrustAnchor2();
}
},
/* getAliases tests */
new KeyStoreTrustEngineTest("getAliases positive test: get the alias list", "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 (TestCase s_test : s_tests) {
suite.addTest(s_test);
}
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 (String alias : aliases) {
testStore.setCertificateEntry(alias, getTestCertificate(alias));
}
}
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<Certificate> certs = new ArrayList<>(aliases.length);
for (String alias : aliases) {
certs.add(getTestCertificate(alias));
}
return 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("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("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("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("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("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("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
}