1860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root/* 2860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * Copyright (C) 2011 The Android Open Source Project 3860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * 4860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 5860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * you may not use this file except in compliance with the License. 6860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * You may obtain a copy of the License at 7860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * 8860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * http://www.apache.org/licenses/LICENSE-2.0 9860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * 10860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * Unless required by applicable law or agreed to in writing, software 11860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * distributed under the License is distributed on an "AS IS" BASIS, 12860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * See the License for the specific language governing permissions and 14860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * limitations under the License. 15860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root */ 16860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt; 18860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 19860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.io.File; 20860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.io.FileWriter; 21d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport java.security.cert.Certificate; 22860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.security.cert.CertificateException; 23860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.security.cert.X509Certificate; 24860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.security.KeyStore; 25860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.security.MessageDigest; 26d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport java.security.Principal; 27860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.util.ArrayList; 28860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.util.Arrays; 29860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.util.List; 30d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport javax.net.ssl.SSLPeerUnverifiedException; 31d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport javax.net.ssl.SSLSession; 32d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport javax.net.ssl.SSLSessionContext; 33860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport javax.net.ssl.TrustManagerFactory; 34860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport javax.net.ssl.X509TrustManager; 35860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport junit.framework.TestCase; 36860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport libcore.java.security.TestKeyStore; 37860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 38860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpublic class TrustManagerImplTest extends TestCase { 39860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 40860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private List<File> tmpFiles = new ArrayList<File>(); 41860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 42860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private String getFingerprint(X509Certificate cert) throws Exception { 43860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root MessageDigest dgst = MessageDigest.getInstance("SHA512"); 44860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root byte[] encoded = cert.getPublicKey().getEncoded(); 45860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root byte[] fingerprint = dgst.digest(encoded); 46860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return IntegralToString.bytesToHexString(fingerprint, false); 47860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 48860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 49860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private String writeTmpPinFile(String text) throws Exception { 50860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root File tmp = File.createTempFile("pins", null); 51860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root FileWriter fstream = new FileWriter(tmp); 52860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root fstream.write(text); 53860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root fstream.close(); 54860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tmpFiles.add(tmp); 55860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return tmp.getPath(); 56860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 57860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 58860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root @Override 59860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root public void tearDown() throws Exception { 60860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root try { 61860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root for (File f : tmpFiles) { 62860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root f.delete(); 63860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 64860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tmpFiles.clear(); 65860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } finally { 66860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root super.tearDown(); 67860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 68860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 69860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 70860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root /** 71860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * Ensure that our non-standard behavior of learning to trust new 72860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root * intermediate CAs does not regress. http://b/3404902 73860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root */ 74860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root public void testLearnIntermediate() throws Exception { 75860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // chain3 should be server/intermediate/root 76860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); 77860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain(); 78860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate root = chain3[2]; 79860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate intermediate = chain3[1]; 80860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate server = chain3[0]; 81860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain2 = new X509Certificate[] { server, intermediate }; 82860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain1 = new X509Certificate[] { server }; 83860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 84860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // Normal behavior 85860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain3, trustManager(root)); 86860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain2, trustManager(root)); 87860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertInvalid(chain1, trustManager(root)); 88860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain3, trustManager(intermediate)); 89860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain2, trustManager(intermediate)); 90860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain1, trustManager(intermediate)); 91860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain3, trustManager(server)); 92860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain2, trustManager(server)); 93860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain1, trustManager(server)); 94860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 95860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // non-standard behavior 96860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509TrustManager tm = trustManager(root); 97860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // fail on short chain with only root trusted 98860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertInvalid(chain1, tm); 99860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // succeed on longer chain, learn intermediate 100860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain2, tm); 101860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // now we can validate the short chain 102860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain1, tm); 103860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 104860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 105860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // We should ignore duplicate cruft in the certificate chain 106860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // See https://code.google.com/p/android/issues/detail?id=52295 http://b/8313312 107860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root public void testDuplicateInChain() throws Exception { 108860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // chain3 should be server/intermediate/root 109860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); 110860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain(); 111860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate root = chain3[2]; 112860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate intermediate = chain3[1]; 113860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate server = chain3[0]; 114860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 115860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain4 = new X509Certificate[] { server, intermediate, 116860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root server, intermediate 117860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root }; 118860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValid(chain4, trustManager(root)); 119860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 120860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 121860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root public void testGetFullChain() throws Exception { 122860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // build the trust manager 123860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); 124860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain(); 125860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate root = chain3[2]; 126860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509TrustManager tm = trustManager(root); 127860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 128860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // build the chains we'll use for testing 129860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate intermediate = chain3[1]; 130860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate server = chain3[0]; 131860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain2 = new X509Certificate[] { server, intermediate }; 132860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain1 = new X509Certificate[] { server }; 133860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 134860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertTrue(tm instanceof TrustManagerImpl); 135860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root TrustManagerImpl tmi = (TrustManagerImpl) tm; 136d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root List<X509Certificate> certs = tmi.checkServerTrusted(chain2, "RSA", new MySSLSession( 137d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root "purple.com")); 138860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertEquals(Arrays.asList(chain3), certs); 139d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root certs = tmi.checkServerTrusted(chain1, "RSA", new MySSLSession("purple.com")); 140860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertEquals(Arrays.asList(chain3), certs); 141860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 142860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 143860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root public void testCertPinning() throws Exception { 144860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // chain3 should be server/intermediate/root 145860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); 146860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain3 = (X509Certificate[]) pke.getCertificateChain(); 147860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate root = chain3[2]; 148860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate intermediate = chain3[1]; 149860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate server = chain3[0]; 150860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain2 = new X509Certificate[] { server, intermediate }; 151860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] chain1 = new X509Certificate[] { server }; 152860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 153860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // test without a hostname, expecting failure 154860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertInvalidPinned(chain1, trustManager(root, "gugle.com", root), null); 155860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // test without a hostname, expecting success 156860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValidPinned(chain3, trustManager(root, "gugle.com", root), null, chain3); 157860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // test an unpinned hostname that should fail 158860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertInvalidPinned(chain1, trustManager(root, "gugle.com", root), "purple.com"); 159860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // test an unpinned hostname that should succeed 160860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValidPinned(chain3, trustManager(root, "gugle.com", root), "purple.com", chain3); 161860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // test a pinned hostname that should fail 162860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertInvalidPinned(chain1, trustManager(intermediate, "gugle.com", root), "gugle.com"); 163860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // test a pinned hostname that should succeed 164860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertValidPinned(chain2, trustManager(intermediate, "gugle.com", server), "gugle.com", 1659be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh chain2); 1669be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh // test a pinned hostname that chains to user installed that should succeed 1679be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh assertValidPinned(chain2, trustManagerUserInstalled( 1689be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh (X509Certificate)TestKeyStore.getIntermediateCa2().getPrivateKey("RSA", "RSA") 1699be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh .getCertificateChain()[1], intermediate, "gugle.com", server), "gugle.com", 1709be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh chain2, true); 171860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 172860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 173860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private X509TrustManager trustManager(X509Certificate ca) throws Exception { 174860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root KeyStore keyStore = TestKeyStore.createKeyStore(); 175860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root keyStore.setCertificateEntry("alias", ca); 176860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 177860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root String algorithm = TrustManagerFactory.getDefaultAlgorithm(); 178860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); 179860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tmf.init(keyStore); 180860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return (X509TrustManager) tmf.getTrustManagers()[0]; 181860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 182860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 183860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private TrustManagerImpl trustManager(X509Certificate ca, String hostname, X509Certificate pin) 184860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root throws Exception { 185860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // build the cert pin manager 186860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root CertPinManager cm = certManager(hostname, pin); 187860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // insert it into the trust manager 188860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root KeyStore keyStore = TestKeyStore.createKeyStore(); 189860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root keyStore.setCertificateEntry("alias", ca); 190860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return new TrustManagerImpl(keyStore, cm); 191860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 192860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 1939be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh private TrustManagerImpl trustManagerUserInstalled( 1949be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh X509Certificate caKeyStore, X509Certificate caUserStore, String hostname, 1959be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh X509Certificate pin) throws Exception { 1969be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh // build the cert pin manager 1979be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh CertPinManager cm = certManager(hostname, pin); 1989be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh 1999be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh // install at least one cert in the store (requirement) 2009be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh KeyStore keyStore = TestKeyStore.createKeyStore(); 2019be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh keyStore.setCertificateEntry("alias", caKeyStore); 2029be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh 2039be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh // install a cert into the user installed store 2049be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh final File DIR_TEMP = new File(System.getProperty("java.io.tmpdir")); 2059be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh final File DIR_TEST = new File(DIR_TEMP, "test"); 2069be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh final File system = new File(DIR_TEST, "system-test"); 2079be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh final File added = new File(DIR_TEST, "added-test"); 2089be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh final File deleted = new File(DIR_TEST, "deleted-test"); 2099be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh 2109be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh TrustedCertificateStore tcs = new TrustedCertificateStore(system, added, deleted); 2119be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh added.mkdirs(); 2129be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh tcs.installCertificate(caUserStore); 2139be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh return new TrustManagerImpl(keyStore, cm, tcs); 2149be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh } 2159be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh 216860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private CertPinManager certManager(String hostname, X509Certificate pin) throws Exception { 217860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root String pinString = ""; 218860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (pin != null) { 219860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root pinString = hostname + "=true|" + getFingerprint(pin); 220860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 221860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // write it to a pinfile 222860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root String path = writeTmpPinFile(pinString); 223860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // build the certpinmanager 224860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return new CertPinManager(path, new TrustedCertificateStore()); 225860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 226860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 227860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private void assertValid(X509Certificate[] chain, X509TrustManager tm) throws Exception { 228860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (tm instanceof TrustManagerImpl) { 229860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root TrustManagerImpl tmi = (TrustManagerImpl) tm; 230860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tmi.checkServerTrusted(chain, "RSA"); 231860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 232860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tm.checkServerTrusted(chain, "RSA"); 233860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 234860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 235860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private void assertValidPinned(X509Certificate[] chain, X509TrustManager tm, String hostname, 236860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root X509Certificate[] fullChain) throws Exception { 2379be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh assertValidPinned(chain, tm, hostname, fullChain, false); 2389be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh } 2399be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh 2409be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh private void assertValidPinned(X509Certificate[] chain, X509TrustManager tm, String hostname, 2419be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh X509Certificate[] fullChain, boolean expectUserInstalled) 2429be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh throws Exception { 243860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (tm instanceof TrustManagerImpl) { 244860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root TrustManagerImpl tmi = (TrustManagerImpl) tm; 245d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root List<X509Certificate> checkedChain = tmi.checkServerTrusted(chain, "RSA", 246d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root new MySSLSession(hostname)); 247860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertEquals(checkedChain, Arrays.asList(fullChain)); 2489be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh boolean chainContainsUserInstalled = false; 2499be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh for (X509Certificate cert : checkedChain) { 2509be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh if (tmi.isUserAddedCertificate(cert)) { 2519be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh chainContainsUserInstalled = true; 2529be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh } 2539be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh } 2549be0a37b7d5075e879159f25dc1d5c007e9cbc18William Luh assertEquals(expectUserInstalled, chainContainsUserInstalled); 255860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 256860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tm.checkServerTrusted(chain, "RSA"); 257860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 258860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 259860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private void assertInvalid(X509Certificate[] chain, X509TrustManager tm) { 260860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root try { 261860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tm.checkClientTrusted(chain, "RSA"); 262860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root fail(); 263860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } catch (CertificateException expected) { 264860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 265860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root try { 266860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root tm.checkServerTrusted(chain, "RSA"); 267860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root fail(); 268860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } catch (CertificateException expected) { 269860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 270860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 271860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 272860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root private void assertInvalidPinned(X509Certificate[] chain, X509TrustManager tm, String hostname) 273860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root throws Exception { 274860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root assertTrue(tm.getClass().getName(), tm instanceof TrustManagerImpl); 275860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root try { 276860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root TrustManagerImpl tmi = (TrustManagerImpl) tm; 277d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root tmi.checkServerTrusted(chain, "RSA", new MySSLSession(hostname)); 278860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root fail(); 279860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } catch (CertificateException expected) { 280860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 281860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 282d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 283d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root private class MySSLSession implements SSLSession { 284d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root private final String hostname; 285d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 286d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public MySSLSession(String hostname) { 287d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root this.hostname = hostname; 288d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 289d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 290d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 291d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public int getApplicationBufferSize() { 292d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 293d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 294d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 295d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 296d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public String getCipherSuite() { 297d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 298d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 299d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 300d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 301d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public long getCreationTime() { 302d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 303d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 304d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 305d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 306d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public byte[] getId() { 307d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 308d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 309d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 310d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 311d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public long getLastAccessedTime() { 312d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 313d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 314d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 315d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 316d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public Certificate[] getLocalCertificates() { 317d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 318d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 319d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 320d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 321d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public Principal getLocalPrincipal() { 322d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 323d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 324d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 325d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 326d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public int getPacketBufferSize() { 327d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 328d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 329d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 330d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 331d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public javax.security.cert.X509Certificate[] getPeerCertificateChain() 332d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throws SSLPeerUnverifiedException { 333d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 334d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 335d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 336d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 337d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { 338d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 339d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 340d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 341d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 342d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public String getPeerHost() { 343d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root return hostname; 344d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 345d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 346d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 347d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public int getPeerPort() { 348d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 349d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 350d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 351d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 352d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { 353d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 354d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 355d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 356d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 357d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public String getProtocol() { 358d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 359d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 360d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 361d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 362d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public SSLSessionContext getSessionContext() { 363d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 364d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 365d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 366d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 367d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public Object getValue(String name) { 368d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 369d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 370d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 371d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 372d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public String[] getValueNames() { 373d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 374d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 375d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 376d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 377d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public void invalidate() { 378d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 379d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 380d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 381d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 382d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public boolean isValid() { 383d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 384d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 385d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 386d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 387d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public void putValue(String name, Object value) { 388d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 389d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 390d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 391d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 392d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public void removeValue(String name) { 393d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root throw new UnsupportedOperationException(); 394d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 395d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } 396860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root} 397