1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net.wifi.passpoint; 18 19import android.net.wifi.WifiConfiguration; 20import android.os.Parcelable; 21import android.os.Parcel; 22import android.security.Credentials; 23import android.util.Log; 24 25import java.lang.reflect.Field; 26import java.lang.reflect.Method; 27 28 29/** @hide */ 30public class WifiPasspointPolicy implements Parcelable { 31 32 private final static String TAG = "PasspointPolicy"; 33 34 /** @hide */ 35 public static final int HOME_SP = 0; 36 37 /** @hide */ 38 public static final int ROAMING_PARTNER = 1; 39 40 /** @hide */ 41 public static final int UNRESTRICTED = 2; 42 43 private String mName; 44 private int mCredentialPriority; 45 private int mRoamingPriority; 46 private String mBssid; 47 private String mSsid; 48 private WifiPasspointCredential mCredential; 49 private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted" 50 private boolean mIsHomeSp; 51 52 private final String INT_PRIVATE_KEY = "private_key"; 53 private final String INT_PHASE2 = "phase2"; 54 private final String INT_PASSWORD = "password"; 55 private final String INT_IDENTITY = "identity"; 56 private final String INT_EAP = "eap"; 57 private final String INT_CLIENT_CERT = "client_cert"; 58 private final String INT_CA_CERT = "ca_cert"; 59 private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity"; 60 private final String INT_SIM_SLOT = "sim_slot"; 61 private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField"; 62 private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; 63 private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2"; 64 private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP"; 65 66 /** @hide */ 67 public WifiPasspointPolicy(String name, String ssid, 68 String bssid, WifiPasspointCredential pc, 69 int restriction, boolean ishomesp) { 70 mName = name; 71 if (pc != null) { 72 mCredentialPriority = pc.getPriority(); 73 } 74 //PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>/Priority 75 mRoamingPriority = 128; //default priority value of 128 76 mSsid = ssid; 77 mCredential = pc; 78 mBssid = bssid; 79 mRestriction = restriction; 80 mIsHomeSp = ishomesp; 81 } 82 83 public String getSsid() { 84 return mSsid; 85 } 86 87 /** @hide */ 88 public void setBssid(String bssid) { 89 mBssid = bssid; 90 } 91 92 public String getBssid() { 93 return mBssid; 94 } 95 96 /** @hide */ 97 public void setRestriction(int r) { 98 mRestriction = r; 99 } 100 101 /** @hide */ 102 public int getRestriction() { 103 return mRestriction; 104 } 105 106 /** @hide */ 107 public void setHomeSp(boolean b) { 108 mIsHomeSp = b; 109 } 110 111 /** @hide */ 112 public boolean isHomeSp() { 113 return mIsHomeSp; 114 } 115 116 /** @hide */ 117 public void setCredential(WifiPasspointCredential newCredential) { 118 mCredential = newCredential; 119 } 120 121 public WifiPasspointCredential getCredential() { 122 // TODO: return a copy 123 return mCredential; 124 } 125 126 /** @hide */ 127 public void setCredentialPriority(int priority) { 128 mCredentialPriority = priority; 129 } 130 131 /** @hide */ 132 public void setRoamingPriority(int priority) { 133 mRoamingPriority = priority; 134 } 135 136 public int getCredentialPriority() { 137 return mCredentialPriority; 138 } 139 140 public int getRoamingPriority() { 141 return mRoamingPriority; 142 } 143 144 public WifiConfiguration createWifiConfiguration() { 145 WifiConfiguration wfg = new WifiConfiguration(); 146 if (mBssid != null) { 147 Log.d(TAG, "create bssid:" + mBssid); 148 wfg.BSSID = mBssid; 149 } 150 151 if (mSsid != null) { 152 Log.d(TAG, "create ssid:" + mSsid); 153 wfg.SSID = mSsid; 154 } 155 //TODO: 1. add pmf configuration 156 // 2. add ocsp configuration 157 // 3. add eap-sim configuration 158 /*Key management*/ 159 wfg.status = WifiConfiguration.Status.ENABLED; 160 wfg.allowedKeyManagement.clear(); 161 wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); 162 wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); 163 164 /*Group Ciphers*/ 165 wfg.allowedGroupCiphers.clear(); 166 wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); 167 wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); 168 169 /*Protocols*/ 170 wfg.allowedProtocols.clear(); 171 wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN); 172 wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA); 173 174 Class[] enterpriseFieldArray = WifiConfiguration.class.getClasses(); 175 Class<?> enterpriseFieldClass = null; 176 177 178 for(Class<?> myClass : enterpriseFieldArray) { 179 if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) { 180 enterpriseFieldClass = myClass; 181 break; 182 } 183 } 184 Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() ); 185 186 187 Field anonymousId = null, caCert = null, clientCert = null, 188 eap = null, identity = null, password = null, 189 phase2 = null, privateKey = null; 190 191 Field[] fields = WifiConfiguration.class.getFields(); 192 193 194 for (Field tempField : fields) { 195 if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) { 196 anonymousId = tempField; 197 Log.d(TAG, "field " + anonymousId.getName() ); 198 } else if (tempField.getName().trim().equals(INT_CA_CERT)) { 199 caCert = tempField; 200 } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) { 201 clientCert = tempField; 202 Log.d(TAG, "field " + clientCert.getName() ); 203 } else if (tempField.getName().trim().equals(INT_EAP)) { 204 eap = tempField; 205 Log.d(TAG, "field " + eap.getName() ); 206 } else if (tempField.getName().trim().equals(INT_IDENTITY)) { 207 identity = tempField; 208 Log.d(TAG, "field " + identity.getName() ); 209 } else if (tempField.getName().trim().equals(INT_PASSWORD)) { 210 password = tempField; 211 Log.d(TAG, "field " + password.getName() ); 212 } else if (tempField.getName().trim().equals(INT_PHASE2)) { 213 phase2 = tempField; 214 Log.d(TAG, "field " + phase2.getName() ); 215 216 } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) { 217 privateKey = tempField; 218 } 219 } 220 221 222 Method setValue = null; 223 224 for(Method m: enterpriseFieldClass.getMethods()) { 225 if(m.getName().trim().equals("setValue")) { 226 Log.d(TAG, "method " + m.getName() ); 227 setValue = m; 228 break; 229 } 230 } 231 232 try { 233 // EAP 234 String eapmethod = mCredential.getType(); 235 Log.d(TAG, "eapmethod:" + eapmethod); 236 setValue.invoke(eap.get(wfg), eapmethod); 237 238 // Username, password, EAP Phase 2 239 if ("TTLS".equals(eapmethod)) { 240 setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2); 241 setValue.invoke(identity.get(wfg), mCredential.getUserName()); 242 setValue.invoke(password.get(wfg), mCredential.getPassword()); 243 setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm()); 244 } 245 246 // EAP CA Certificate 247 String cacertificate = null; 248 String rootCA = mCredential.getCaRootCertPath(); 249 if (rootCA == null){ 250 cacertificate = null; 251 } else { 252 cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA; 253 } 254 Log.d(TAG, "cacertificate:" + cacertificate); 255 setValue.invoke(caCert.get(wfg), cacertificate); 256 257 //User certificate 258 if ("TLS".equals(eapmethod)) { 259 String usercertificate = null; 260 String privatekey = null; 261 String clientCertPath = mCredential.getClientCertPath(); 262 if (clientCertPath != null){ 263 privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath; 264 usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath; 265 } 266 Log.d(TAG, "privatekey:" + privatekey); 267 Log.d(TAG, "usercertificate:" + usercertificate); 268 if (privatekey != null && usercertificate != null) { 269 setValue.invoke(privateKey.get(wfg), privatekey); 270 setValue.invoke(clientCert.get(wfg), usercertificate); 271 } 272 } 273 } catch (Exception e) { 274 Log.d(TAG, "createWifiConfiguration err:" + e); 275 } 276 277 return wfg; 278 } 279 280 /** {@inheritDoc} @hide */ 281 public int compareTo(WifiPasspointPolicy another) { 282 Log.d(TAG, "this:" + this); 283 Log.d(TAG, "another:" + another); 284 285 if (another == null) { 286 return -1; 287 } else if (this.mIsHomeSp == true && another.isHomeSp() == false) { 288 //home sp priority is higher then roaming 289 Log.d(TAG, "compare HomeSP first, this is HomeSP, another isn't"); 290 return -1; 291 } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) { 292 Log.d(TAG, "both HomeSP"); 293 //if both home sp, compare credential priority 294 if (this.mCredentialPriority < another.getCredentialPriority()) { 295 Log.d(TAG, "this priority is higher"); 296 return -1; 297 } else if (this.mCredentialPriority == another.getCredentialPriority()) { 298 Log.d(TAG, "both priorities equal"); 299 //if priority still the same, compare name(ssid) 300 if (this.mName.compareTo(another.mName) != 0) { 301 Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName)); 302 return this.mName.compareTo(another.mName); 303 } 304 /** 305 *if name still the same, compare credential 306 *the device may has two more credentials(TLS,SIM..etc) 307 *it can associate to one AP(same ssid). so we should compare by credential 308 */ 309 if (this.mCredential != null && another.mCredential != null) { 310 if (this.mCredential.compareTo(another.mCredential) != 0) { 311 Log.d(TAG, 312 "compare mCredential return:" + this.mName.compareTo(another.mName)); 313 return this.mCredential.compareTo(another.mCredential); 314 } 315 } 316 } else { 317 return 1; 318 } 319 } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) { 320 Log.d(TAG, "both RoamingSp"); 321 //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority) 322 if (this.mRoamingPriority < another.getRoamingPriority()) { 323 Log.d(TAG, "this priority is higher"); 324 return -1; 325 } else if (this.mRoamingPriority == another.getRoamingPriority()) {//priority equals, compare name 326 Log.d(TAG, "both priorities equal"); 327 //if priority still the same, compare name(ssid) 328 if (this.mName.compareTo(another.mName) != 0) { 329 Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName)); 330 return this.mName.compareTo(another.mName); 331 } 332 //if name still the same, compare credential 333 if (this.mCredential != null && another.mCredential != null) { 334 if (this.mCredential.compareTo(another.mCredential) != 0) { 335 Log.d(TAG, 336 "compare mCredential return:" 337 + this.mCredential.compareTo(another.mCredential)); 338 return this.mCredential.compareTo(another.mCredential); 339 } 340 } 341 } else { 342 return 1; 343 } 344 } 345 346 Log.d(TAG, "both policies equal"); 347 return 0; 348 } 349 350 @Override 351 /** @hide */ 352 public String toString() { 353 return "PasspointPolicy: name=" + mName + " CredentialPriority=" + mCredentialPriority + 354 " mRoamingPriority" + mRoamingPriority + 355 " ssid=" + mSsid + " restriction=" + mRestriction + 356 " ishomesp=" + mIsHomeSp + " Credential=" + mCredential; 357 } 358 359 /** Implement the Parcelable interface {@hide} */ 360 @Override 361 public int describeContents() { 362 return 0; 363 } 364 365 /** Implement the Parcelable interface {@hide} */ 366 @Override 367 public void writeToParcel(Parcel dest, int flags) { 368 // TODO 369 } 370 371 /** Implement the Parcelable interface {@hide} */ 372 public static final Creator<WifiPasspointPolicy> CREATOR = 373 new Creator<WifiPasspointPolicy>() { 374 @Override 375 public WifiPasspointPolicy createFromParcel(Parcel in) { 376 return null; 377 } 378 379 @Override 380 public WifiPasspointPolicy[] newArray(int size) { 381 return new WifiPasspointPolicy[size]; 382 } 383 }; 384} 385