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