| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net.wifi.passpoint; |
| |
| import android.net.wifi.WifiConfiguration; |
| import android.os.Parcelable; |
| import android.os.Parcel; |
| import android.security.Credentials; |
| import android.util.Log; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| |
| |
| /** @hide */ |
| public class WifiPasspointPolicy implements Parcelable { |
| |
| private final static String TAG = "PasspointPolicy"; |
| |
| /** @hide */ |
| public static final int HOME_SP = 0; |
| |
| /** @hide */ |
| public static final int ROAMING_PARTNER = 1; |
| |
| /** @hide */ |
| public static final int UNRESTRICTED = 2; |
| |
| private String mName; |
| private int mCredentialPriority; |
| private int mRoamingPriority; |
| private String mBssid; |
| private String mSsid; |
| private WifiPasspointCredential mCredential; |
| private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted" |
| private boolean mIsHomeSp; |
| |
| private final String INT_PRIVATE_KEY = "private_key"; |
| private final String INT_PHASE2 = "phase2"; |
| private final String INT_PASSWORD = "password"; |
| private final String INT_IDENTITY = "identity"; |
| private final String INT_EAP = "eap"; |
| private final String INT_CLIENT_CERT = "client_cert"; |
| private final String INT_CA_CERT = "ca_cert"; |
| private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity"; |
| private final String INT_SIM_SLOT = "sim_slot"; |
| private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField"; |
| private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; |
| private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2"; |
| private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP"; |
| |
| /** @hide */ |
| public WifiPasspointPolicy(String name, String ssid, |
| String bssid, WifiPasspointCredential pc, |
| int restriction, boolean ishomesp) { |
| mName = name; |
| if (pc != null) { |
| mCredentialPriority = pc.getPriority(); |
| } |
| //PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>/Priority |
| mRoamingPriority = 128; //default priority value of 128 |
| mSsid = ssid; |
| mCredential = pc; |
| mBssid = bssid; |
| mRestriction = restriction; |
| mIsHomeSp = ishomesp; |
| } |
| |
| public String getSsid() { |
| return mSsid; |
| } |
| |
| /** @hide */ |
| public void setBssid(String bssid) { |
| mBssid = bssid; |
| } |
| |
| public String getBssid() { |
| return mBssid; |
| } |
| |
| /** @hide */ |
| public void setRestriction(int r) { |
| mRestriction = r; |
| } |
| |
| /** @hide */ |
| public int getRestriction() { |
| return mRestriction; |
| } |
| |
| /** @hide */ |
| public void setHomeSp(boolean b) { |
| mIsHomeSp = b; |
| } |
| |
| /** @hide */ |
| public boolean isHomeSp() { |
| return mIsHomeSp; |
| } |
| |
| /** @hide */ |
| public void setCredential(WifiPasspointCredential newCredential) { |
| mCredential = newCredential; |
| } |
| |
| public WifiPasspointCredential getCredential() { |
| // TODO: return a copy |
| return mCredential; |
| } |
| |
| /** @hide */ |
| public void setCredentialPriority(int priority) { |
| mCredentialPriority = priority; |
| } |
| |
| /** @hide */ |
| public void setRoamingPriority(int priority) { |
| mRoamingPriority = priority; |
| } |
| |
| public int getCredentialPriority() { |
| return mCredentialPriority; |
| } |
| |
| public int getRoamingPriority() { |
| return mRoamingPriority; |
| } |
| |
| public WifiConfiguration createWifiConfiguration() { |
| WifiConfiguration wfg = new WifiConfiguration(); |
| if (mBssid != null) { |
| Log.d(TAG, "create bssid:" + mBssid); |
| wfg.BSSID = mBssid; |
| } |
| |
| if (mSsid != null) { |
| Log.d(TAG, "create ssid:" + mSsid); |
| wfg.SSID = mSsid; |
| } |
| //TODO: 1. add pmf configuration |
| // 2. add ocsp configuration |
| // 3. add eap-sim configuration |
| /*Key management*/ |
| wfg.status = WifiConfiguration.Status.ENABLED; |
| wfg.allowedKeyManagement.clear(); |
| wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); |
| wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); |
| |
| /*Group Ciphers*/ |
| wfg.allowedGroupCiphers.clear(); |
| wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); |
| wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); |
| |
| /*Protocols*/ |
| wfg.allowedProtocols.clear(); |
| wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN); |
| wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA); |
| |
| Class[] enterpriseFieldArray = WifiConfiguration.class.getClasses(); |
| Class<?> enterpriseFieldClass = null; |
| |
| |
| for(Class<?> myClass : enterpriseFieldArray) { |
| if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) { |
| enterpriseFieldClass = myClass; |
| break; |
| } |
| } |
| Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() ); |
| |
| |
| Field anonymousId = null, caCert = null, clientCert = null, |
| eap = null, identity = null, password = null, |
| phase2 = null, privateKey = null; |
| |
| Field[] fields = WifiConfiguration.class.getFields(); |
| |
| |
| for (Field tempField : fields) { |
| if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) { |
| anonymousId = tempField; |
| Log.d(TAG, "field " + anonymousId.getName() ); |
| } else if (tempField.getName().trim().equals(INT_CA_CERT)) { |
| caCert = tempField; |
| } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) { |
| clientCert = tempField; |
| Log.d(TAG, "field " + clientCert.getName() ); |
| } else if (tempField.getName().trim().equals(INT_EAP)) { |
| eap = tempField; |
| Log.d(TAG, "field " + eap.getName() ); |
| } else if (tempField.getName().trim().equals(INT_IDENTITY)) { |
| identity = tempField; |
| Log.d(TAG, "field " + identity.getName() ); |
| } else if (tempField.getName().trim().equals(INT_PASSWORD)) { |
| password = tempField; |
| Log.d(TAG, "field " + password.getName() ); |
| } else if (tempField.getName().trim().equals(INT_PHASE2)) { |
| phase2 = tempField; |
| Log.d(TAG, "field " + phase2.getName() ); |
| |
| } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) { |
| privateKey = tempField; |
| } |
| } |
| |
| |
| Method setValue = null; |
| |
| for(Method m: enterpriseFieldClass.getMethods()) { |
| if(m.getName().trim().equals("setValue")) { |
| Log.d(TAG, "method " + m.getName() ); |
| setValue = m; |
| break; |
| } |
| } |
| |
| try { |
| // EAP |
| String eapmethod = mCredential.getType(); |
| Log.d(TAG, "eapmethod:" + eapmethod); |
| setValue.invoke(eap.get(wfg), eapmethod); |
| |
| // Username, password, EAP Phase 2 |
| if ("TTLS".equals(eapmethod)) { |
| setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2); |
| setValue.invoke(identity.get(wfg), mCredential.getUserName()); |
| setValue.invoke(password.get(wfg), mCredential.getPassword()); |
| setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm()); |
| } |
| |
| // EAP CA Certificate |
| String cacertificate = null; |
| String rootCA = mCredential.getCaRootCertPath(); |
| if (rootCA == null){ |
| cacertificate = null; |
| } else { |
| cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA; |
| } |
| Log.d(TAG, "cacertificate:" + cacertificate); |
| setValue.invoke(caCert.get(wfg), cacertificate); |
| |
| //User certificate |
| if ("TLS".equals(eapmethod)) { |
| String usercertificate = null; |
| String privatekey = null; |
| String clientCertPath = mCredential.getClientCertPath(); |
| if (clientCertPath != null){ |
| privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath; |
| usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath; |
| } |
| Log.d(TAG, "privatekey:" + privatekey); |
| Log.d(TAG, "usercertificate:" + usercertificate); |
| if (privatekey != null && usercertificate != null) { |
| setValue.invoke(privateKey.get(wfg), privatekey); |
| setValue.invoke(clientCert.get(wfg), usercertificate); |
| } |
| } |
| } catch (Exception e) { |
| Log.d(TAG, "createWifiConfiguration err:" + e); |
| } |
| |
| return wfg; |
| } |
| |
| /** {@inheritDoc} @hide */ |
| public int compareTo(WifiPasspointPolicy another) { |
| Log.d(TAG, "this:" + this); |
| Log.d(TAG, "another:" + another); |
| |
| if (another == null) { |
| return -1; |
| } else if (this.mIsHomeSp == true && another.isHomeSp() == false) { |
| //home sp priority is higher then roaming |
| Log.d(TAG, "compare HomeSP first, this is HomeSP, another isn't"); |
| return -1; |
| } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) { |
| Log.d(TAG, "both HomeSP"); |
| //if both home sp, compare credential priority |
| if (this.mCredentialPriority < another.getCredentialPriority()) { |
| Log.d(TAG, "this priority is higher"); |
| return -1; |
| } else if (this.mCredentialPriority == another.getCredentialPriority()) { |
| Log.d(TAG, "both priorities equal"); |
| //if priority still the same, compare name(ssid) |
| if (this.mName.compareTo(another.mName) != 0) { |
| Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName)); |
| return this.mName.compareTo(another.mName); |
| } |
| /** |
| *if name still the same, compare credential |
| *the device may has two more credentials(TLS,SIM..etc) |
| *it can associate to one AP(same ssid). so we should compare by credential |
| */ |
| if (this.mCredential != null && another.mCredential != null) { |
| if (this.mCredential.compareTo(another.mCredential) != 0) { |
| Log.d(TAG, |
| "compare mCredential return:" + this.mName.compareTo(another.mName)); |
| return this.mCredential.compareTo(another.mCredential); |
| } |
| } |
| } else { |
| return 1; |
| } |
| } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) { |
| Log.d(TAG, "both RoamingSp"); |
| //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority) |
| if (this.mRoamingPriority < another.getRoamingPriority()) { |
| Log.d(TAG, "this priority is higher"); |
| return -1; |
| } else if (this.mRoamingPriority == another.getRoamingPriority()) {//priority equals, compare name |
| Log.d(TAG, "both priorities equal"); |
| //if priority still the same, compare name(ssid) |
| if (this.mName.compareTo(another.mName) != 0) { |
| Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName)); |
| return this.mName.compareTo(another.mName); |
| } |
| //if name still the same, compare credential |
| if (this.mCredential != null && another.mCredential != null) { |
| if (this.mCredential.compareTo(another.mCredential) != 0) { |
| Log.d(TAG, |
| "compare mCredential return:" |
| + this.mCredential.compareTo(another.mCredential)); |
| return this.mCredential.compareTo(another.mCredential); |
| } |
| } |
| } else { |
| return 1; |
| } |
| } |
| |
| Log.d(TAG, "both policies equal"); |
| return 0; |
| } |
| |
| @Override |
| /** @hide */ |
| public String toString() { |
| return "PasspointPolicy: name=" + mName + " CredentialPriority=" + mCredentialPriority + |
| " mRoamingPriority" + mRoamingPriority + |
| " ssid=" + mSsid + " restriction=" + mRestriction + |
| " ishomesp=" + mIsHomeSp + " Credential=" + mCredential; |
| } |
| |
| /** Implement the Parcelable interface {@hide} */ |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** Implement the Parcelable interface {@hide} */ |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| // TODO |
| } |
| |
| /** Implement the Parcelable interface {@hide} */ |
| public static final Creator<WifiPasspointPolicy> CREATOR = |
| new Creator<WifiPasspointPolicy>() { |
| @Override |
| public WifiPasspointPolicy createFromParcel(Parcel in) { |
| return null; |
| } |
| |
| @Override |
| public WifiPasspointPolicy[] newArray(int size) { |
| return new WifiPasspointPolicy[size]; |
| } |
| }; |
| } |