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