blob: b760ade764e36bf4af959e5ee53e45503d967fc4 [file] [log] [blame]
Jan Nordqvistee699a62016-02-05 15:30:26 -08001package com.android.configparse;
2
3import android.content.Context;
4import android.net.Uri;
5import android.net.wifi.WifiConfiguration;
6import android.net.wifi.WifiEnterpriseConfig;
7import android.util.Base64;
8import android.util.Log;
9
10import com.android.anqp.eap.AuthParam;
11import com.android.anqp.eap.EAP;
12import com.android.anqp.eap.EAPMethod;
13import com.android.anqp.eap.NonEAPInnerAuth;
14import com.android.hotspot2.IMSIParameter;
15import com.android.hotspot2.pps.Credential;
16import com.android.hotspot2.pps.HomeSP;
17
18import java.io.IOException;
19import java.security.GeneralSecurityException;
20import java.security.MessageDigest;
21import java.security.PrivateKey;
22import java.security.cert.X509Certificate;
23import java.util.Arrays;
24import java.util.HashSet;
25import java.util.List;
26
27public 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}