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