PasspointConfiguration.java revision 55078c4fa85896b395e7500b179ef60af1992c55
1/** 2 * Copyright (c) 2016, 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.hotspot2; 18 19import android.net.wifi.hotspot2.pps.Credential; 20import android.net.wifi.hotspot2.pps.HomeSP; 21import android.net.wifi.hotspot2.pps.Policy; 22import android.net.wifi.hotspot2.pps.UpdateParameter; 23import android.os.Parcelable; 24import android.text.TextUtils; 25import android.util.Log; 26import android.os.Parcel; 27 28import java.nio.charset.StandardCharsets; 29import java.util.Arrays; 30import java.util.Collections; 31import java.util.HashMap; 32import java.util.Map; 33 34/** 35 * Class representing Passpoint configuration. This contains configurations specified in 36 * PerProviderSubscription (PPS) Management Object (MO) tree. 37 * 38 * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0 39 * Release 2 Technical Specification. 40 * 41 * @hide 42 */ 43public final class PasspointConfiguration implements Parcelable { 44 private static final String TAG = "PasspointConfiguration"; 45 46 /** 47 * Number of bytes for certificate SHA-256 fingerprint byte array. 48 */ 49 private static final int CERTIFICATE_SHA256_BYTES = 32; 50 51 /** 52 * Maximum bytes for URL string. 53 */ 54 private static final int MAX_URL_BYTES = 1023; 55 56 /** 57 * Integer value used for indicating null value in the Parcel. 58 */ 59 private static final int NULL_VALUE = -1; 60 61 public HomeSP homeSp = null; 62 public Credential credential = null; 63 public Policy policy = null; 64 65 /** 66 * Meta data for performing subscription update. 67 */ 68 public UpdateParameter subscriptionUpdate = null; 69 70 /** 71 * List of HTTPS URL for retrieving trust root certificate and the corresponding SHA-256 72 * fingerprint of the certificate. The certificates are used for verifying AAA server's 73 * identity during EAP authentication. 74 */ 75 public Map<String, byte[]> trustRootCertList = null; 76 77 /** 78 * Set by the subscription server, updated every time the configuration is updated by 79 * the subscription server. 80 * 81 * Use Integer.MIN_VALUE to indicate unset value. 82 */ 83 public int updateIdentifier = Integer.MIN_VALUE; 84 85 /** 86 * The priority of the credential. 87 * 88 * Use Integer.MIN_VALUE to indicate unset value. 89 */ 90 public int credentialPriority = Integer.MIN_VALUE; 91 92 /** 93 * The time this subscription is created. It is in the format of number 94 * of milliseconds since January 1, 1970, 00:00:00 GMT. 95 * 96 * Use Long.MIN_VALUE to indicate unset value. 97 */ 98 public long subscriptionCreationTimeInMs = Long.MIN_VALUE; 99 100 /** 101 * The time this subscription will expire. It is in the format of number 102 * of milliseconds since January 1, 1970, 00:00:00 GMT. 103 * 104 * Use Long.MIN_VALUE to indicate unset value. 105 */ 106 public long subscriptionExpirationTimeInMs = Long.MIN_VALUE; 107 108 /** 109 * The type of the subscription. This is defined by the provider and the value is provider 110 * specific. 111 */ 112 public String subscriptionType = null; 113 114 /** 115 * The time period for usage statistics accumulation. A value of zero means that usage 116 * statistics are not accumulated on a periodic basis (e.g., a one-time limit for 117 * “pay as you go” - PAYG service). A non-zero value specifies the usage interval in minutes. 118 */ 119 public long usageLimitUsageTimePeriodInMinutes = Long.MIN_VALUE; 120 121 /** 122 * The time at which usage statistic accumulation begins. It is in the format of number 123 * of milliseconds since January 1, 1970, 00:00:00 GMT. 124 * 125 * Use Long.MIN_VALUE to indicate unset value. 126 */ 127 public long usageLimitStartTimeInMs = Long.MIN_VALUE; 128 129 /** 130 * The cumulative data limit in megabytes for the {@link #usageLimitUsageTimePeriodInMinutes}. 131 * A value of zero indicate unlimited data usage. 132 * 133 * Use Long.MIN_VALUE to indicate unset value. 134 */ 135 public long usageLimitDataLimit = Long.MIN_VALUE; 136 137 /** 138 * The cumulative time limit in minutes for the {@link #usageLimitUsageTimePeriodInMinutes}. 139 * A value of zero indicate unlimited time usage. 140 */ 141 public long usageLimitTimeLimitInMinutes = Long.MIN_VALUE; 142 143 144 /** 145 * Constructor for creating PasspointConfiguration with default values. 146 */ 147 public PasspointConfiguration() {} 148 149 /** 150 * Copy constructor. 151 * 152 * @param source The source to copy from 153 */ 154 public PasspointConfiguration(PasspointConfiguration source) { 155 if (source == null) { 156 return; 157 } 158 159 if (source.homeSp != null) { 160 homeSp = new HomeSP(source.homeSp); 161 } 162 if (source.credential != null) { 163 credential = new Credential(source.credential); 164 } 165 if (source.policy != null) { 166 policy = new Policy(source.policy); 167 } 168 if (source.trustRootCertList != null) { 169 trustRootCertList = Collections.unmodifiableMap(source.trustRootCertList); 170 } 171 if (source.subscriptionUpdate != null) { 172 subscriptionUpdate = new UpdateParameter(source.subscriptionUpdate); 173 } 174 updateIdentifier = source.updateIdentifier; 175 credentialPriority = source.credentialPriority; 176 subscriptionCreationTimeInMs = source.subscriptionCreationTimeInMs; 177 subscriptionExpirationTimeInMs = source.subscriptionExpirationTimeInMs; 178 subscriptionType = source.subscriptionType; 179 usageLimitDataLimit = source.usageLimitDataLimit; 180 usageLimitStartTimeInMs = source.usageLimitStartTimeInMs; 181 usageLimitTimeLimitInMinutes = source.usageLimitTimeLimitInMinutes; 182 usageLimitUsageTimePeriodInMinutes = source.usageLimitUsageTimePeriodInMinutes; 183 } 184 185 @Override 186 public int describeContents() { 187 return 0; 188 } 189 190 @Override 191 public void writeToParcel(Parcel dest, int flags) { 192 dest.writeParcelable(homeSp, flags); 193 dest.writeParcelable(credential, flags); 194 dest.writeParcelable(policy, flags); 195 dest.writeParcelable(subscriptionUpdate, flags); 196 writeTrustRootCerts(dest, trustRootCertList); 197 dest.writeInt(updateIdentifier); 198 dest.writeInt(credentialPriority); 199 dest.writeLong(subscriptionCreationTimeInMs); 200 dest.writeLong(subscriptionExpirationTimeInMs); 201 dest.writeString(subscriptionType); 202 dest.writeLong(usageLimitUsageTimePeriodInMinutes); 203 dest.writeLong(usageLimitStartTimeInMs); 204 dest.writeLong(usageLimitDataLimit); 205 dest.writeLong(usageLimitTimeLimitInMinutes); 206 } 207 208 @Override 209 public boolean equals(Object thatObject) { 210 if (this == thatObject) { 211 return true; 212 } 213 if (!(thatObject instanceof PasspointConfiguration)) { 214 return false; 215 } 216 PasspointConfiguration that = (PasspointConfiguration) thatObject; 217 return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) 218 && (credential == null ? that.credential == null 219 : credential.equals(that.credential)) 220 && (policy == null ? that.policy == null : policy.equals(that.policy)) 221 && (subscriptionUpdate == null ? that.subscriptionUpdate == null 222 : subscriptionUpdate.equals(that.subscriptionUpdate)) 223 && isTrustRootCertListEquals(trustRootCertList, that.trustRootCertList) 224 && updateIdentifier == that.updateIdentifier 225 && credentialPriority == that.credentialPriority 226 && subscriptionCreationTimeInMs == that.subscriptionCreationTimeInMs 227 && subscriptionExpirationTimeInMs == that.subscriptionExpirationTimeInMs 228 && TextUtils.equals(subscriptionType, that.subscriptionType) 229 && usageLimitUsageTimePeriodInMinutes == that.usageLimitUsageTimePeriodInMinutes 230 && usageLimitStartTimeInMs == that.usageLimitStartTimeInMs 231 && usageLimitDataLimit == that.usageLimitDataLimit 232 && usageLimitTimeLimitInMinutes == that .usageLimitTimeLimitInMinutes; 233 } 234 235 /** 236 * Validate the configuration data. 237 * 238 * @return true on success or false on failure 239 */ 240 public boolean validate() { 241 if (homeSp == null || !homeSp.validate()) { 242 return false; 243 } 244 if (credential == null || !credential.validate()) { 245 return false; 246 } 247 if (policy != null && !policy.validate()) { 248 return false; 249 } 250 if (subscriptionUpdate != null && !subscriptionUpdate.validate()) { 251 return false; 252 } 253 if (trustRootCertList != null) { 254 for (Map.Entry<String, byte[]> entry : trustRootCertList.entrySet()) { 255 String url = entry.getKey(); 256 byte[] certFingerprint = entry.getValue(); 257 if (TextUtils.isEmpty(url)) { 258 Log.d(TAG, "Empty URL"); 259 return false; 260 } 261 if (url.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) { 262 Log.d(TAG, "URL bytes exceeded the max: " 263 + url.getBytes(StandardCharsets.UTF_8).length); 264 return false; 265 } 266 267 if (certFingerprint == null) { 268 Log.d(TAG, "Fingerprint not specified"); 269 return false; 270 } 271 if (certFingerprint.length != CERTIFICATE_SHA256_BYTES) { 272 Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: " 273 + certFingerprint.length); 274 return false; 275 } 276 } 277 } 278 return true; 279 } 280 281 public static final Creator<PasspointConfiguration> CREATOR = 282 new Creator<PasspointConfiguration>() { 283 @Override 284 public PasspointConfiguration createFromParcel(Parcel in) { 285 PasspointConfiguration config = new PasspointConfiguration(); 286 config.homeSp = in.readParcelable(null); 287 config.credential = in.readParcelable(null); 288 config.policy = in.readParcelable(null); 289 config.subscriptionUpdate = in.readParcelable(null); 290 config.trustRootCertList = readTrustRootCerts(in); 291 config.updateIdentifier = in.readInt(); 292 config.credentialPriority = in.readInt(); 293 config.subscriptionCreationTimeInMs = in.readLong(); 294 config.subscriptionExpirationTimeInMs = in.readLong(); 295 config.subscriptionType = in.readString(); 296 config.usageLimitUsageTimePeriodInMinutes = in.readLong(); 297 config.usageLimitStartTimeInMs = in.readLong(); 298 config.usageLimitDataLimit = in.readLong(); 299 config.usageLimitTimeLimitInMinutes = in.readLong(); 300 return config; 301 } 302 303 @Override 304 public PasspointConfiguration[] newArray(int size) { 305 return new PasspointConfiguration[size]; 306 } 307 308 /** 309 * Helper function for reading trust root certificate info list from a Parcel. 310 * 311 * @param in The Parcel to read from 312 * @return The list of trust root certificate URL with the corresponding certificate 313 * fingerprint 314 */ 315 private Map<String, byte[]> readTrustRootCerts(Parcel in) { 316 int size = in.readInt(); 317 if (size == NULL_VALUE) { 318 return null; 319 } 320 Map<String, byte[]> trustRootCerts = new HashMap<>(size); 321 for (int i = 0; i < size; i++) { 322 String key = in.readString(); 323 byte[] value = in.createByteArray(); 324 trustRootCerts.put(key, value); 325 } 326 return trustRootCerts; 327 } 328 }; 329 330 /** 331 * Helper function for writing trust root certificate information list. 332 * 333 * @param dest The Parcel to write to 334 * @param trustRootCerts The list of trust root certificate URL with the corresponding 335 * certificate fingerprint 336 */ 337 private static void writeTrustRootCerts(Parcel dest, Map<String, byte[]> trustRootCerts) { 338 if (trustRootCerts == null) { 339 dest.writeInt(NULL_VALUE); 340 return; 341 } 342 dest.writeInt(trustRootCerts.size()); 343 for (Map.Entry<String, byte[]> entry : trustRootCerts.entrySet()) { 344 dest.writeString(entry.getKey()); 345 dest.writeByteArray(entry.getValue()); 346 } 347 } 348 349 /** 350 * Helper function for comparing two trust root certificate list. Cannot use Map#equals 351 * method since the value type (byte[]) doesn't override equals method. 352 * 353 * @param list1 The first trust root certificate list 354 * @param list2 The second trust root certificate list 355 * @return true if the two list are equal 356 */ 357 private static boolean isTrustRootCertListEquals(Map<String, byte[]> list1, 358 Map<String, byte[]> list2) { 359 if (list1 == null || list2 == null) { 360 return list1 == list2; 361 } 362 if (list1.size() != list2.size()) { 363 return false; 364 } 365 for (Map.Entry<String, byte[]> entry : list1.entrySet()) { 366 if (!Arrays.equals(entry.getValue(), list2.get(entry.getKey()))) { 367 return false; 368 } 369 } 370 return true; 371 } 372} 373