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