• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dropFile(Uri uri, Context context)30     private static void dropFile(Uri uri, Context context) {
31         context.getContentResolver().delete(uri, null, null);
32     }
33 
buildConfig(HomeSP homeSP, X509Certificate caCert, List<X509Certificate> clientChain, PrivateKey key)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 
buildTTLSConfig(HomeSP homeSP)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 
buildTLSConfig(HomeSP homeSP, List<X509Certificate> clientChain, PrivateKey clientKey)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 
buildSIMConfig(HomeSP homeSP)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 
buildBaseConfiguration(HomeSP homeSP)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 
remapEAPMethod(EAP.EAPMethodID eapMethodID)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 
remapInnerMethod(NonEAPInnerAuth.NonEAPType type)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