1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage com.android.hotspot2.osu; 2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.net.Network; 4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.util.Base64; 5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.util.Log; 6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.Utils; 8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.pps.HomeSP; 9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.ByteArrayInputStream; 11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.IOException; 12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.net.InetAddress; 13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.net.InetSocketAddress; 14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.net.Socket; 15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.net.URL; 16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.GeneralSecurityException; 17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.KeyStore; 18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.KeyStoreException; 19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.PrivateKey; 20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.CertPath; 21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.CertPathValidator; 22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.CertPathValidatorException; 23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.Certificate; 24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.CertificateException; 25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.CertificateFactory; 26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.PKIXCertPathChecker; 27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.PKIXParameters; 28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.TrustAnchor; 29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.X509Certificate; 30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.ArrayList; 31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Arrays; 32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collection; 33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collections; 34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashSet; 35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.List; 36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map; 37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Set; 38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport javax.net.SocketFactory; 40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport javax.net.ssl.KeyManager; 41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport javax.net.ssl.SSLContext; 42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport javax.net.ssl.TrustManager; 43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport javax.net.ssl.X509TrustManager; 44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic class OSUSocketFactory { 46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final long ConnectionTimeout = 10000L; 47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final long ReconnectWait = 2000L; 48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final String SecureHTTP = "https"; 50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final String UnsecureHTTP = "http"; 51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final String EKU_ID = "2.5.29.37"; 52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final Set<String> EKU_ID_SET = new HashSet<>(Arrays.asList(EKU_ID)); 53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final EKUChecker sEKUChecker = new EKUChecker(); 54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final Network mNetwork; 56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final SocketFactory mSocketFactory; 57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final KeyManager mKeyManager; 58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final WFATrustManager mTrustManager; 59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final List<InetSocketAddress> mRemotes; 60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public static Set<X509Certificate> buildCertSet() { 62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist try { 63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Set<X509Certificate> set = new HashSet<>(); 65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (String b64 : WFACerts) { 66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist ByteArrayInputStream bis = new ByteArrayInputStream( 67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Base64.decode(b64, Base64.DEFAULT)); 68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist X509Certificate cert = (X509Certificate) certFactory.generateCertificate(bis); 69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist set.add(cert); 70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return set; 72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } catch (CertificateException ce) { 73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.e(OSUManager.TAG, "Cannot build CA cert set"); 74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return null; 75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public static OSUSocketFactory getSocketFactory(KeyStore ks, HomeSP homeSP, int flowType, 79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Network network, URL url, KeyManager km, 80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist boolean enforceSecurity) 81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws GeneralSecurityException, IOException { 82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (enforceSecurity && !url.getProtocol().equalsIgnoreCase(SecureHTTP)) { 84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new IOException("Protocol '" + url.getProtocol() + "' is not secure"); 85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return new OSUSocketFactory(ks, homeSP, flowType, network, url, km); 87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private OSUSocketFactory(KeyStore ks, HomeSP homeSP, int flowType, Network network, 90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist URL url, KeyManager km) throws GeneralSecurityException, IOException { 91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mNetwork = network; 92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mKeyManager = km; 93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTrustManager = new WFATrustManager(ks, homeSP, flowType); 94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist int port; 95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist switch (url.getProtocol()) { 96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist case UnsecureHTTP: 97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mSocketFactory = new DefaultSocketFactory(); 98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist port = url.getPort() > 0 ? url.getPort() : 80; 99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist case SecureHTTP: 101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist SSLContext tlsContext = SSLContext.getInstance("TLSv1"); 102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist tlsContext.init(km != null ? new KeyManager[]{km} : null, 103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist new TrustManager[]{mTrustManager}, null); 104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mSocketFactory = tlsContext.getSocketFactory(); 105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist port = url.getPort() > 0 ? url.getPort() : 443; 106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist default: 108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new IOException("Bad URL: " + url); 109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (OSUManager.R2_MOCK && url.getHost().endsWith(".wi-fi.org")) { 111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // !!! Warning: Ruckus hack! 112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mRemotes = new ArrayList<>(1); 113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mRemotes.add(new InetSocketAddress(InetAddress.getByName("10.123.107.107"), port)); 114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist InetAddress[] remotes = mNetwork.getAllByName(url.getHost()); 116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist android.util.Log.d(OSUManager.TAG, "'" + url.getHost() + "' resolves to " + 117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Arrays.toString(remotes)); 118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (remotes == null || remotes.length == 0) { 119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new IOException("Failed to look up host from " + url); 120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mRemotes = new ArrayList<>(remotes.length); 122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (InetAddress remote : remotes) { 123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mRemotes.add(new InetSocketAddress(remote, port)); 124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Collections.shuffle(mRemotes); 127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 128ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 129ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void reloadKeys(Map<OSUCertType, List<X509Certificate>> certs, PrivateKey key) 130ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws IOException { 131ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (mKeyManager instanceof ClientKeyManager) { 132ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist ((ClientKeyManager) mKeyManager).reloadKeys(certs, key); 133ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 134ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 135ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 136ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Socket createSocket() throws IOException { 137ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Socket socket = mSocketFactory.createSocket(); 138ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mNetwork.bindSocket(socket); 139ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 140ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist long bail = System.currentTimeMillis() + ConnectionTimeout; 141ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist boolean success = false; 142ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 143ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist while (System.currentTimeMillis() < bail) { 144ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (InetSocketAddress remote : mRemotes) { 145ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist try { 146ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist socket.connect(remote); 147ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d(OSUManager.TAG, "Connection " + socket.getLocalSocketAddress() + 148ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist " to " + socket.getRemoteSocketAddress()); 149ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist success = true; 150ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 151ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } catch (IOException ioe) { 152ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d(OSUManager.TAG, "Failed to connect to " + remote + ": " + ioe); 153ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist socket = mSocketFactory.createSocket(); 154ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mNetwork.bindSocket(socket); 155ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 156ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 157ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (success) { 158ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 159ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 160ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Utils.delay(ReconnectWait); 161ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 162ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (!success) { 163ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new IOException("No available network"); 164ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 165ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return socket; 166ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 167ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 168ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public X509Certificate getOSUCertificate(URL url) throws GeneralSecurityException { 169ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String fqdn = url.getHost(); 170ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (X509Certificate certificate : mTrustManager.getTrustChain()) { 171ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (List<?> name : certificate.getSubjectAlternativeNames()) { 172ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (name.size() >= SPVerifier.DNSName && 173ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist name.get(0).getClass() == Integer.class && 174ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist name.get(1).toString().equals(fqdn)) { 175ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return certificate; 176ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 177ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 178ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 179ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return null; 180ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 181ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 182ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist final class DefaultSocketFactory extends SocketFactory { 183ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 184ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist DefaultSocketFactory() { 185ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 186ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 187ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 188ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Socket createSocket() throws IOException { 189ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return new Socket(); 190ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 191ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 192ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 193ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Socket createSocket(String host, int port) throws IOException { 194ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return new Socket(host, port); 195ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 196ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 197ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 198ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Socket createSocket(String host, int port, InetAddress localHost, int localPort) 199ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws IOException { 200ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return new Socket(host, port, localHost, localPort); 201ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 202ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 203ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 204ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Socket createSocket(InetAddress host, int port) throws IOException { 205ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return new Socket(host, port); 206ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 207ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 208ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 209ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Socket createSocket(InetAddress address, int port, InetAddress localAddress, 210ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist int localPort) throws IOException { 211ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return new Socket(address, port, localAddress, localPort); 212ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 213ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 214ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 215ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static class WFATrustManager implements X509TrustManager { 216ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final KeyStore mKeyStore; 217ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final HomeSP mHomeSP; 218ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final int mFlowType; 219ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private X509Certificate[] mTrustChain; 220ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 221ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private WFATrustManager(KeyStore ks, HomeSP homeSP, int flowType) 222ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws CertificateException { 223ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mKeyStore = ks; 224ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mHomeSP = homeSP; 225ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mFlowType = flowType; 226ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 227ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 228ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 229ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void checkClientTrusted(X509Certificate[] chain, String authType) 230ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws CertificateException { 231ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // N/A 232ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 233ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 234ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 235ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void checkServerTrusted(X509Certificate[] chain, String authType) 236ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws CertificateException { 237ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d("TLSOSU", "Checking " + chain.length + " certs."); 238ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 239ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist try { 240ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist CertPathValidator validator = 241ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist CertPathValidator.getInstance(CertPathValidator.getDefaultType()); 242ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 243ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist CertPath path = certFactory.generateCertPath( 244ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Arrays.asList(chain)); 245ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Set<TrustAnchor> trustAnchors = new HashSet<>(); 246ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (mHomeSP == null) { 247ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (X509Certificate cert : getRootCerts(mKeyStore)) { 248ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist trustAnchors.add(new TrustAnchor(cert, null)); 249ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 250ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 251ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String prefix = mFlowType == OSUManager.FLOW_REMEDIATION ? 252ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist OSUManager.CERT_REM_ALIAS : OSUManager.CERT_POLICY_ALIAS; 253ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 254ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist X509Certificate cert = getCert(mKeyStore, prefix + mHomeSP.getFQDN()); 255ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (cert == null) { 256ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist cert = getCert(mKeyStore, OSUManager.CERT_SHARED_ALIAS + mHomeSP.getFQDN()); 257ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 258ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (cert == null) { 259ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (X509Certificate root : getRootCerts(mKeyStore)) { 260ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist trustAnchors.add(new TrustAnchor(root, null)); 261ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 262ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 263ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist trustAnchors.add(new TrustAnchor(cert, null)); 264ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 265ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 266ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist PKIXParameters params = new PKIXParameters(trustAnchors); 267ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist params.setRevocationEnabled(false); 268ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist params.addCertPathChecker(sEKUChecker); 269ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist validator.validate(path, params); 270ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTrustChain = chain; 271ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } catch (GeneralSecurityException gse) { 272ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new SecurityException(gse); 273ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 274ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTrustChain = chain; 275ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 276ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 277ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 278ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public X509Certificate[] getAcceptedIssuers() { 279ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return null; 280ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 281ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 282ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public X509Certificate[] getTrustChain() { 283ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mTrustChain != null ? mTrustChain : new X509Certificate[0]; 284ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 285ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 286ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 287ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static X509Certificate getCert(KeyStore keyStore, String alias) 288ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws KeyStoreException { 289ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Certificate cert = keyStore.getCertificate(alias); 290ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (cert != null && cert instanceof X509Certificate) { 291ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return (X509Certificate) cert; 292ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 293ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return null; 294ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 295ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 296ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public static Set<X509Certificate> getRootCerts(KeyStore keyStore) throws KeyStoreException { 297ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Set<X509Certificate> certSet = new HashSet<>(); 298ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist int index = 0; 299ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (int n = 0; n < 1000; n++) { 300ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Certificate cert = keyStore.getCertificate( 301ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String.format("%s%d", OSUManager.CERT_WFA_ALIAS, index)); 302ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (cert == null) { 303ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 304ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else if (cert instanceof X509Certificate) { 305ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist certSet.add((X509Certificate) cert); 306ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 307ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist index++; 308ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 309ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return certSet; 310ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 311ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 312ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static class EKUChecker extends PKIXCertPathChecker { 313ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 314ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void init(boolean forward) throws CertPathValidatorException { 315ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 316ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 317ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 318ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 319ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public boolean isForwardCheckingSupported() { 320ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return true; 321ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 322ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 323ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 324ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Set<String> getSupportedExtensions() { 325ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return EKU_ID_SET; 326ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 327ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 328ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 329ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void check(Certificate cert, Collection<String> unresolvedCritExts) 330ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throws CertPathValidatorException { 331ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d(OSUManager.TAG, "Checking EKU " + unresolvedCritExts); 332ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist unresolvedCritExts.remove(EKU_ID); 333ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 334ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 335ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 336ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist /* 337ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 338ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Subject: CN=osu-server.r2-testbed-rks.wi-fi.org, O=Intel Corporation CCG DRD, C=US 339ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11 340ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Validity: [From: Wed Jan 28 16:00:00 PST 2015, 341ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist To: Sat Jan 28 15:59:59 PST 2017] 342ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Issuer: CN="NetworkFX, Inc. Hotspot 2.0 Intermediate CA", OU=OSU CA - 01, O="NetworkFX, Inc.", C=US 343ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist SerialNumber: [ 312af3db 138eae19 1defbce2 e2b88b55] 344ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 345ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * 346ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Subject: CN="NetworkFX, Inc. Hotspot 2.0 Intermediate CA", OU=OSU CA - 01, O="NetworkFX, Inc.", C=US 347ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11 348ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Validity: [From: Tue Nov 19 16:00:00 PST 2013, 349ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist To: Sun Nov 19 15:59:59 PST 2023] 350ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Issuer: CN=Hotspot 2.0 Trust Root CA - 01, O=WFA Hotspot 2.0, C=US 351ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist SerialNumber: [ 4152b1b0 301495f3 8fa76428 2ef41046] 352ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */ 353ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 354ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public static final String[] WFACerts = { 355ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MIIFbDCCA1SgAwIBAgIQDLMPcPKGpDPguQmJ3gHttzANBgkqhkiG9w0BAQsFADBQ" + 356ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhvdHNwb3QgMi4wMScwJQYDVQQD" + 357ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "Ex5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0gMDMwHhcNMTMxMjA4MTIwMDAw" + 358ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "WhcNNDMxMjA4MTIwMDAwWjBQMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhv" + 359ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "dHNwb3QgMi4wMScwJQYDVQQDEx5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0g" + 360ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsdEtReIUbMlO+hR6b" + 361ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "yQk4nGVITv3meYTaDeVwZnQVal8EjHuu4Kd89g8yRYVTv3J1kq9ukE7CDrDehrXK" + 362ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "ym+8VlR7ro0lB/lwRyNk3W7yNccg3AknQ0x5fKVwcFznwD/FYg37owGmhGFtpMTB" + 363ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "cxzreQaLXvLta8YNlJU10ZkfputBpzi9bLPWsLOkIrQw7KH1Wc+Oiy4hUMUbTlSi" + 364ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "cjqacKPR188mVIoxxUoICHyVV1KvMmYZrVdc/b5dbmd0haMHxC0VSqbydXxxS7vv" + 365ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "/lCrC2d5qbKE66PiuBPkhzyU7SI9C8GU/S7akYm1MMSTn5W7lSp2AWRDnf9LQg51" + 366ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "dLvDxJ7t2fruXtSkkqG/cwY1yQI8O+WZYPDThKPcDmNbaxVE9lOizAHXFVsfYrXA" + 367ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "PbbMOkzKehYwaIikmNgcpxtQNw+wikJiZb9N8VwwtwHK71XEFi+n5DGlPa9VDYgB" + 368ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "YkBcxvVo2rbE3i3teQgHm+pWZNP08aFNWwMk9yQkm/SOGdLq1jLbQA9yd7fyR1Ct" + 369ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "W1GLzKi1Ojr/6XiB9/noL3oxP/+gb8OSgcqVfkZp4QLvrGdlKiOI2fE7Bslmzn6l" + 370ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "B3UTpApjab7BQ99rCXzDwt3Xd7IrCtAJNkxi302J7k6hnGlW8S4oPQBElkOtoH9y" + 371ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "XEhp9rNS0lZiuwtFmWW2q50fkQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G" + 372ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "A1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUZw5JLGEXnuvt4FTnhNmbrWRgc2UwDQYJ" + 373ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "KoZIhvcNAQELBQADggIBAFPoGFDyzFg9B9+jJUPGW32omftBhChVcgjllI07RCie" + 374ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "KTMBi47+auuLgiMox3xRyP7/dX7YaUeMXEQ1BMv6nlrsXWv1lH4yu+RNuehPlqRs" + 375ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "fY351mAfPtQ654SBUi0Wg++9iyTOfgF5a9IWEDt4lnSZMvA4vlw8pUCz6zpKXHnA" + 376ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "RXKrpY3bU+2dnrFDKR0XQhmAQdo7UvdsT1elVoFIxHhLpwfzx+kpEhtrXw3nGgt+" + 377ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "M4jNp684XoWpxVGaQ4Vvv00Sm2DQ8jq2sf9F+kRWszZpQOTiMGKZr0lX2CI5cww1" + 378ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "dfmd1BkAjI9cIWLkD8YSeaggZzvYe1o9d7e7lKfdJmjDlSQ0uBiG77keUK4tF2fi" + 379ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "xFTxibtPux56p3GYQ2GdRsBaKjH3A3HMJSKXwIGR+wb1sgz/bBdlyJSylG8hYD//" + 380ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "0Hyo+UrMUszAdszoPhMY+4Ol3QE3QRWzXi+W/NtKeYD2K8xUzjZM10wMdxCfoFOa" + 381ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "8bzzWnxZQlnu880ULUSHIxDPeE+DDZYYOaN1hV2Rh/hrFKvvV+gJj2eXHF5G7y9u" + 382ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "Yg7nHYCCf7Hy8UTIXDtAAeDCQNon1ReN8G+XOqhLQ9TalmnJ5U5ARtC0MdQDht7T" + 383ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "DZpWeEVv+pQHARX9GDV/T85MV2RPJWKqfZ6kK0gvQDkunADdg8IhZAjwMMx3k6B/", 384ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 385ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MIIFbDCCA1SgAwIBAgIQaAV8NQv/Xdusi4IU+tpUfjANBgkqhkiG9w0BAQsFADBQ" + 386ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhvdHNwb3QgMi4wMScwJQYDVQQD" + 387ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "Ex5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0gMDEwHhcNMTMxMTIwMDAwMDAw" + 388ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "WhcNNDMxMTE5MjM1OTU5WjBQMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhv" + 389ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "dHNwb3QgMi4wMScwJQYDVQQDEx5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0g" + 390ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/gf4CHxWjr2EcktAZ" + 391ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "pHT4z1yFYZILD3ZVqvzzXBK+YKjWhjsgZ28Z1VwXqu51JvVzwTGDalPf5m7zMcJW" + 392ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "CpPtPBdxxwQ/cBDPK4w+/sCuYYSddlMLzwZ/IgwFike12tKTR7Kk7Nk6ghrYaxCG" + 393ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "R+QEZDVrxITj79vGpgk2otVnMI4d3H9mWt1o6Lx+hVioyBgOvmo2OWHR2uKkbg5h" + 394ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "tktXqmBEtzK+qDqIIUY4WRRZHxlOaF2/EdIIGhXlf+Vlr13aPqOPiDiE08o+GARz" + 395ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "TIp8BrW2boo0+2kpEFUKiqc427vOYEkUdSMfwu4aGOcuOewc8sk6ztquL/JcPROL" + 396ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "VSFSSFR3HKhUto8EJcHEEG9wzcOi1OO/OOSVxjNwiaV/hB9Ed1wvoBhiJ+C+Q8/K" + 397ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "HXmoH/ankXDaB06yjt2Ojemt0nO45qlarRj8tO7zbpghJuJxztur47U7PJta7Zcg" + 398ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "z7kOPJPTAbzmOU2TXt1pXO1hVnSlV+M1rRwe7qivnSMMrTnkX15YWmyK27/tgJeu" + 399ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "muR2YzvPwPtF/m1N0bRKI7FW05NYg3smItFq0E/eyf/orgolcXTZ7zNRyRGnjWNs" + 400ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "/w9SDbdby0uVUfdN4V/5uC4HBmA1rikoBbGZ+nzCtesY4yW8eEwMfguVpNT3ueaU" + 401ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "q30nufeY2VnA3Rv1WH8TaeZU+wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G" + 402ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU+RjGVZbebjpzEPfthaTLqbvXMiEwDQYJ" + 403ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "KoZIhvcNAQELBQADggIBABj3LP1UXVa16HYeXC1+GU1dX/cla1n1bwpIlxRnCZ5/" + 404ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "3I3zGw/nRnsLUTkGf8q3XCgin+jX22kyzzQNrgepn0zqBsmAj+pjUUwWzYQUzphc" + 405ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "Uzmg4PJRWaEaGG3kvD+wJEC0pWvIhe48qcq8FZCCmjbvecEVn5mM0smPzPyUjf/o" + 406ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "fjUMQvVWqug/Ff5HT6kbyDWhC3nD+8IZ5PjyO85OnoBnQkr8WYwr24XJgO2HS2rs" + 407ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "W40CzQe3Kdg7HHyef+/iyLYTBJH7EUJPCHGVQtZ3q0aNqURkutXJ/CxKJYMcNTEB" + 408ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "x+a09EhZ6DOHQDqsdTuAqGh3VyrxhFk+3suNsxoh6XaRK10VslvdNB/1YKfU8DWe" + 409ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "V6XfDH/TR0NIL04exUp3rER8sERulpJGBOnaG6OQKh4bFYDB406+QfusQnvO0aYR" + 410ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "UXJzf01B15HRJgpZsggpIuex0UDcJhTTpkRfTj8L4ayUce2ZRsGn3dBaT9ZMx4o9" + 411ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "E/YsQyOpfw28gM5u+zZt4BJz4gAaRGbp4r4sk5Vm/P1/0EXJ70Du6K9d0HAHtpEv" + 412ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "Y94Ww5W6fpMDdyAKYTXZBgTX3cqtikNkLX/kHH8l4o/XW2sXqU3X7vOYqgeVYoD9" + 413ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "NnhZXYCerH4Se5Lgj8/KhXxRWtcn3XduMdkC6UTApMooA64Vs508173Z3lJn2SeQ", 414ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 415ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MIIFXTCCA0WgAwIBAgIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEY" + 416ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MBYGA1UECgwPV0ZBIEhvdHNwb3QgMi4wMScwJQYDVQQDDB5Ib3RzcG90IDIuMCBU" + 417ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "cnVzdCBSb290IENBIC0gMDIwHhcNMTMxMjAyMjA1NzU3WhcNNDMxMjAyMjA1NTAz" + 418ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "WjBQMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPV0ZBIEhvdHNwb3QgMi4wMScwJQYD" + 419ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "VQQDDB5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0gMDIwggIiMA0GCSqGSIb3" + 420ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "DQEBAQUAA4ICDwAwggIKAoICAQDCSoMqNhtTwbnIsINp6nUhx5UFuq9ZQoTv+KDk" + 421ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "vAajT0di6+cQG3sAVvZLySmJoiBAv3PizYYLOD4eGMrFQRqi7PmSJ83WqNv23ZYF" + 422ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "ryFFJiy/URXc/ALDuB3dgElPt24Mx7n2xDPAh9t82HTmuskpQRrsyg9QPoi5rRRS" + 423ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "Djm5mjFJjKChq99RWcweNV/KGH1sTwcmlDmNMScK16A+BBNiSvmZlsGJgAlP369k" + 424ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "lnNqt6UiDhepcktuKpHmSvNel+c/xqzR0gURfUnXcZhzjzS94Rx5O+CNWL4EGiJq" + 425ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "qKAfk99j/lbD0MWYo7Rh0UKQlXSdohWDiV93hxvvfugej8KUOIb+1wmd1Fi+lwDZ" + 426ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "bR2yg2f0qyxbC/tAV4JJNnuDLFb19leD78x+68eAnlbMi+xMH5lINs15+26s2H5d" + 427ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "lx9kwRDBJq02LuHnen6FLafWjejnnBQ/PuGD0ACvBegSsDKDaCuTAnTNS6MDmQr4" + 428ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "wza08iX360ZN+BbSAnCK1YGa/7J7fhyydwxLJ7s5Eo0b6SUMY87FMc5XmkAk4xxL" + 429ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "MLqS2HMtqsGBI5JQT0SgH0ghE6DjMWArBTZcD+swuzTi1/Cz5+Z9Es8xJ3MPvSZW" + 430ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "pJi6VVB2eVMAqfHOj4ozHoVpvJypIVGRwWBzVRWom76R47utuRK6uKzoLiB1jwE5" + 431ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "vwHpUQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBxjAd" + 432ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "BgNVHQ4EFgQU5C9c1OMsB+/MOwl9OKG2D/XSwrUwDQYJKoZIhvcNAQELBQADggIB" + 433ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "AGULYE/VrnA3K0ptgHrWlQoPfp5wGvScgsmy0wp9qE3b6n/4bLehBKb5w4Y3JVA9" + 434ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "gjxoQ5xE2ssDtULZ3nKnGWmMN3qOBoRZCA6KjKs1860p09tm1ScUsajDJ15Tp1nI" + 435ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "zfR0oP63+2bJx+JXM8fPKOJe245hj2rs1c3JXsGCe+UVrlGsotG+wR0PdrejaXJ8" + 436ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "HbhBQHcbhgjsD1Gb6Egm4YxRKAtcVY3q9EKKWAGhbC1qvCh1iLNKo3FeGgm2r3EG" + 437ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "L4cYJBb2fhSKltjISqCDhYq4tplOIeQSJJyJC8gfW/BnMU39lTjNgnSjjGPLQXGV" + 438ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "+Ulb/CgNMJ3RhRJdBoLcpIm/EeLx6JLq/2Erxy7CxjaSOcD0UKa14+dzLSHVsXft" + 439ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "HZuOy548X8m18KruSZsf5uAT3c7NqlXtr9YgOVUqSJykNAHTGi/BHB1dC2clKvxN" + 440ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "ElfLWWrG9yaAd5TFW0+3wsaDIwRZL584AsFwwAD3KMo1oU/2zRvtm0E+VghsuD/Z" + 441ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "IE1xaVGTPaL7ph/YgC9+0rGHieauT8SXz6Ryp3h0RtYMLFZOMTKM7xjmcbMZDwrO" + 442ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "c+J/XjK9dbiCqlx5/B8P0xWaYYHzvE5/fafiPYzoGyFVUXquu0dFCCQrvjF/y0tC" + 443ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist "TPm4hQim3k1F+5NChcbeNggN+kq+VdlSqPhQEuOY+kNv" 444ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist }; 445ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 446ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist //private static final Set<TrustAnchor> sTrustAnchors = buildCertSet(); 447ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist} 448