Home | History | Annotate | Download | only in configparse
      1 package com.android.configparse;
      2 
      3 import android.content.Context;
      4 import android.net.Uri;
      5 import android.net.wifi.WifiConfiguration;
      6 import android.net.wifi.WifiEnterpriseConfig;
      7 import android.util.Base64;
      8 import android.util.Log;
      9 
     10 import com.android.anqp.eap.AuthParam;
     11 import com.android.anqp.eap.EAP;
     12 import com.android.anqp.eap.EAPMethod;
     13 import com.android.anqp.eap.NonEAPInnerAuth;
     14 import com.android.hotspot2.IMSIParameter;
     15 import com.android.hotspot2.pps.Credential;
     16 import com.android.hotspot2.pps.HomeSP;
     17 
     18 import java.io.IOException;
     19 import java.security.GeneralSecurityException;
     20 import java.security.MessageDigest;
     21 import java.security.PrivateKey;
     22 import java.security.cert.X509Certificate;
     23 import java.util.Arrays;
     24 import java.util.HashSet;
     25 import java.util.List;
     26 
     27 public class ConfigBuilder {
     28     private static final String TAG = "WCFG";
     29 
     30     private static void dropFile(Uri uri, Context context) {
     31         context.getContentResolver().delete(uri, null, null);
     32     }
     33 
     34     public static WifiConfiguration buildConfig(HomeSP homeSP, X509Certificate caCert,
     35                                                  List<X509Certificate> clientChain, PrivateKey key)
     36             throws IOException, GeneralSecurityException {
     37 
     38         Credential credential = homeSP.getCredential();
     39 
     40         WifiConfiguration config;
     41 
     42         EAP.EAPMethodID eapMethodID = credential.getEAPMethod().getEAPMethodID();
     43         switch (eapMethodID) {
     44             case EAP_TTLS:
     45                 if (key != null || clientChain != null) {
     46                     Log.w(TAG, "Client cert and/or key included with EAP-TTLS profile");
     47                 }
     48                 config = buildTTLSConfig(homeSP);
     49                 break;
     50             case EAP_TLS:
     51                 config = buildTLSConfig(homeSP, clientChain, key);
     52                 break;
     53             case EAP_AKA:
     54             case EAP_AKAPrim:
     55             case EAP_SIM:
     56                 if (key != null || clientChain != null || caCert != null) {
     57                     Log.i(TAG, "Client/CA cert and/or key included with " +
     58                             eapMethodID + " profile");
     59                 }
     60                 config = buildSIMConfig(homeSP);
     61                 break;
     62             default:
     63                 throw new IOException("Unsupported EAP Method: " + eapMethodID);
     64         }
     65 
     66         WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
     67 
     68         enterpriseConfig.setCaCertificate(caCert);
     69         enterpriseConfig.setAnonymousIdentity("anonymous@" + credential.getRealm());
     70 
     71         return config;
     72     }
     73 
     74     // Retain for debugging purposes
     75     /*
     76     private static void xIterateCerts(KeyStore ks, X509Certificate caCert)
     77             throws GeneralSecurityException {
     78         Enumeration<String> aliases = ks.aliases();
     79         while (aliases.hasMoreElements()) {
     80             String alias = aliases.nextElement();
     81             Certificate cert = ks.getCertificate(alias);
     82             Log.d("HS2J", "Checking " + alias);
     83             if (cert instanceof X509Certificate) {
     84                 X509Certificate x509Certificate = (X509Certificate) cert;
     85                 boolean sm = x509Certificate.getSubjectX500Principal().equals(
     86                         caCert.getSubjectX500Principal());
     87                 boolean eq = false;
     88                 if (sm) {
     89                     eq = Arrays.equals(x509Certificate.getEncoded(), caCert.getEncoded());
     90                 }
     91                 Log.d("HS2J", "Subject: " + x509Certificate.getSubjectX500Principal() +
     92                         ": " + sm + "/" + eq);
     93             }
     94         }
     95     }
     96     */
     97 
     98     private static WifiConfiguration buildTTLSConfig(HomeSP homeSP)
     99             throws IOException {
    100         Credential credential = homeSP.getCredential();
    101 
    102         if (credential.getUserName() == null || credential.getPassword() == null) {
    103             throw new IOException("EAP-TTLS provisioned without user name or password");
    104         }
    105 
    106         EAPMethod eapMethod = credential.getEAPMethod();
    107 
    108         AuthParam authParam = eapMethod.getAuthParam();
    109         if (authParam == null ||
    110                 authParam.getAuthInfoID() != EAP.AuthInfoID.NonEAPInnerAuthType) {
    111             throw new IOException("Bad auth parameter for EAP-TTLS: " + authParam);
    112         }
    113 
    114         WifiConfiguration config = buildBaseConfiguration(homeSP);
    115         NonEAPInnerAuth ttlsParam = (NonEAPInnerAuth) authParam;
    116         WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
    117         enterpriseConfig.setPhase2Method(remapInnerMethod(ttlsParam.getType()));
    118         enterpriseConfig.setIdentity(credential.getUserName());
    119         enterpriseConfig.setPassword(credential.getPassword());
    120 
    121         return config;
    122     }
    123 
    124     private static WifiConfiguration buildTLSConfig(HomeSP homeSP,
    125                                                     List<X509Certificate> clientChain,
    126                                                     PrivateKey clientKey)
    127             throws IOException, GeneralSecurityException {
    128 
    129         Credential credential = homeSP.getCredential();
    130 
    131         X509Certificate clientCertificate = null;
    132 
    133         if (clientKey == null || clientChain == null) {
    134             throw new IOException("No key and/or cert passed for EAP-TLS");
    135         }
    136         if (credential.getCertType() != Credential.CertType.x509v3) {
    137             throw new IOException("Invalid certificate type for TLS: " +
    138                     credential.getCertType());
    139         }
    140 
    141         byte[] reference = credential.getFingerPrint();
    142         MessageDigest digester = MessageDigest.getInstance("SHA-256");
    143         for (X509Certificate certificate : clientChain) {
    144             digester.reset();
    145             byte[] fingerprint = digester.digest(certificate.getEncoded());
    146             if (Arrays.equals(reference, fingerprint)) {
    147                 clientCertificate = certificate;
    148                 break;
    149             }
    150         }
    151         if (clientCertificate == null) {
    152             throw new IOException("No certificate in chain matches supplied fingerprint");
    153         }
    154 
    155         String alias = Base64.encodeToString(reference, Base64.DEFAULT);
    156 
    157         WifiConfiguration config = buildBaseConfiguration(homeSP);
    158         WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
    159         enterpriseConfig.setClientCertificateAlias(alias);
    160         enterpriseConfig.setClientKeyEntry(clientKey, clientCertificate);
    161 
    162         return config;
    163     }
    164 
    165     private static WifiConfiguration buildSIMConfig(HomeSP homeSP)
    166             throws IOException {
    167 
    168         Credential credential = homeSP.getCredential();
    169         IMSIParameter credImsi = credential.getImsi();
    170 
    171         /*
    172          * Uncomment to enforce strict IMSI matching with currently installed SIM cards.
    173          *
    174         TelephonyManager tm = TelephonyManager.from(context);
    175         SubscriptionManager sub = SubscriptionManager.from(context);
    176         boolean match = false;
    177 
    178         for (int subId : sub.getActiveSubscriptionIdList()) {
    179             String imsi = tm.getSubscriberId(subId);
    180             if (credImsi.matches(imsi)) {
    181                 match = true;
    182                 break;
    183             }
    184         }
    185         if (!match) {
    186             throw new IOException("Supplied IMSI does not match any SIM card");
    187         }
    188         */
    189 
    190         WifiConfiguration config = buildBaseConfiguration(homeSP);
    191         config.enterpriseConfig.setPlmn(credImsi.toString());
    192         return config;
    193     }
    194 
    195     private static WifiConfiguration buildBaseConfiguration(HomeSP homeSP) throws IOException {
    196         EAP.EAPMethodID eapMethodID = homeSP.getCredential().getEAPMethod().getEAPMethodID();
    197 
    198         WifiConfiguration config = new WifiConfiguration();
    199 
    200         config.FQDN = homeSP.getFQDN();
    201 
    202         HashSet<Long> roamingConsortiumIds = homeSP.getRoamingConsortiums();
    203         config.roamingConsortiumIds = new long[roamingConsortiumIds.size()];
    204         int i = 0;
    205         for (long id : roamingConsortiumIds) {
    206             config.roamingConsortiumIds[i] = id;
    207             i++;
    208         }
    209         config.providerFriendlyName = homeSP.getFriendlyName();
    210 
    211         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
    212         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
    213 
    214         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
    215         enterpriseConfig.setEapMethod(remapEAPMethod(eapMethodID));
    216         enterpriseConfig.setRealm(homeSP.getCredential().getRealm());
    217         if (homeSP.getUpdateIdentifier() >= 0) {
    218             config.updateIdentifier = Integer.toString(homeSP.getUpdateIdentifier());
    219         }
    220         config.enterpriseConfig = enterpriseConfig;
    221         if (homeSP.getUpdateIdentifier() >= 0) {
    222             config.updateIdentifier = Integer.toString(homeSP.getUpdateIdentifier());
    223         }
    224 
    225         return config;
    226     }
    227 
    228     private static int remapEAPMethod(EAP.EAPMethodID eapMethodID) throws IOException {
    229         switch (eapMethodID) {
    230             case EAP_TTLS:
    231                 return WifiEnterpriseConfig.Eap.TTLS;
    232             case EAP_TLS:
    233                 return WifiEnterpriseConfig.Eap.TLS;
    234             case EAP_SIM:
    235                 return WifiEnterpriseConfig.Eap.SIM;
    236             case EAP_AKA:
    237                 return WifiEnterpriseConfig.Eap.AKA;
    238             case EAP_AKAPrim:
    239                 return WifiEnterpriseConfig.Eap.AKA_PRIME;
    240             default:
    241                 throw new IOException("Bad EAP method: " + eapMethodID);
    242         }
    243     }
    244 
    245     private static int remapInnerMethod(NonEAPInnerAuth.NonEAPType type) throws IOException {
    246         switch (type) {
    247             case PAP:
    248                 return WifiEnterpriseConfig.Phase2.PAP;
    249             case MSCHAP:
    250                 return WifiEnterpriseConfig.Phase2.MSCHAP;
    251             case MSCHAPv2:
    252                 return WifiEnterpriseConfig.Phase2.MSCHAPV2;
    253             case CHAP:
    254             default:
    255                 throw new IOException("Inner method " + type + " not supported");
    256         }
    257     }
    258 }
    259