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.pps.HomeSP;
      9 
     10 import java.io.ByteArrayInputStream;
     11 import java.io.IOException;
     12 import java.net.InetAddress;
     13 import java.net.InetSocketAddress;
     14 import java.net.Socket;
     15 import java.net.URL;
     16 import java.security.GeneralSecurityException;
     17 import java.security.KeyStore;
     18 import java.security.KeyStoreException;
     19 import java.security.PrivateKey;
     20 import java.security.cert.CertPath;
     21 import java.security.cert.CertPathValidator;
     22 import java.security.cert.CertPathValidatorException;
     23 import java.security.cert.Certificate;
     24 import java.security.cert.CertificateException;
     25 import java.security.cert.CertificateFactory;
     26 import java.security.cert.PKIXCertPathChecker;
     27 import java.security.cert.PKIXParameters;
     28 import java.security.cert.TrustAnchor;
     29 import java.security.cert.X509Certificate;
     30 import java.util.ArrayList;
     31 import java.util.Arrays;
     32 import java.util.Collection;
     33 import java.util.Collections;
     34 import java.util.HashSet;
     35 import java.util.List;
     36 import java.util.Map;
     37 import java.util.Set;
     38 
     39 import javax.net.SocketFactory;
     40 import javax.net.ssl.KeyManager;
     41 import javax.net.ssl.SSLContext;
     42 import javax.net.ssl.TrustManager;
     43 import javax.net.ssl.X509TrustManager;
     44 
     45 public 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