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 17 package android.net.wifi.hotspot2; 18 19 import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE; 20 import static android.net.wifi.WifiConfiguration.MeteredOverride; 21 22 import android.annotation.CurrentTimeMillisLong; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.net.wifi.WifiManager; 27 import android.net.wifi.hotspot2.pps.Credential; 28 import android.net.wifi.hotspot2.pps.HomeSp; 29 import android.net.wifi.hotspot2.pps.Policy; 30 import android.net.wifi.hotspot2.pps.UpdateParameter; 31 import android.os.Build; 32 import android.os.Bundle; 33 import android.os.Parcel; 34 import android.os.Parcelable; 35 import android.telephony.SubscriptionInfo; 36 import android.telephony.SubscriptionManager; 37 import android.telephony.TelephonyManager; 38 import android.text.TextUtils; 39 import android.util.Log; 40 41 import androidx.annotation.RequiresApi; 42 43 import com.android.modules.utils.build.SdkLevel; 44 45 import java.nio.charset.StandardCharsets; 46 import java.util.Arrays; 47 import java.util.Collections; 48 import java.util.Date; 49 import java.util.HashMap; 50 import java.util.Locale; 51 import java.util.Map; 52 import java.util.Objects; 53 54 /** 55 * Class representing Passpoint configuration. This contains configurations specified in 56 * PerProviderSubscription (PPS) Management Object (MO) tree. 57 * 58 * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0 59 * Release 2 Technical Specification. 60 */ 61 public final class PasspointConfiguration implements Parcelable { 62 private static final String TAG = "PasspointConfiguration"; 63 64 /** 65 * Number of bytes for certificate SHA-256 fingerprint byte array. 66 */ 67 private static final int CERTIFICATE_SHA256_BYTES = 32; 68 69 /** 70 * Maximum bytes for URL string. 71 */ 72 private static final int MAX_URL_BYTES = 1023; 73 74 /** 75 * Integer value used for indicating null value in the Parcel. 76 */ 77 private static final int NULL_VALUE = -1; 78 79 /** 80 * Configurations under HomeSp subtree. 81 */ 82 private HomeSp mHomeSp = null; 83 84 /** 85 * Set the Home SP (Service Provider) information. 86 * 87 * @param homeSp The Home SP information to set to 88 */ setHomeSp(HomeSp homeSp)89 public void setHomeSp(HomeSp homeSp) { mHomeSp = homeSp; } 90 /** 91 * Get the Home SP (Service Provider) information. 92 * 93 * @return Home SP information 94 */ getHomeSp()95 public HomeSp getHomeSp() { return mHomeSp; } 96 97 /** 98 * Configurations under AAAServerTrustedNames subtree. 99 */ 100 private String[] mAaaServerTrustedNames = null; 101 /** 102 * Set the AAA server trusted names information. 103 * 104 * @param aaaServerTrustedNames The AAA server trusted names information to set to 105 * @hide 106 */ setAaaServerTrustedNames(@ullable String[] aaaServerTrustedNames)107 public void setAaaServerTrustedNames(@Nullable String[] aaaServerTrustedNames) { 108 mAaaServerTrustedNames = aaaServerTrustedNames; 109 } 110 /** 111 * Get the AAA server trusted names information. 112 * 113 * @return AAA server trusted names information 114 * @hide 115 */ getAaaServerTrustedNames()116 public @Nullable String[] getAaaServerTrustedNames() { 117 return mAaaServerTrustedNames; 118 } 119 120 /** 121 * Configurations under Credential subtree. 122 */ 123 private Credential mCredential = null; 124 /** 125 * Set the credential information. 126 * 127 * @param credential The credential information to set to 128 */ setCredential(Credential credential)129 public void setCredential(Credential credential) { 130 mCredential = credential; 131 } 132 /** 133 * Get the credential information. 134 * 135 * @return credential information 136 */ getCredential()137 public Credential getCredential() { 138 return mCredential; 139 } 140 141 /** 142 * Configurations under Policy subtree. 143 */ 144 private Policy mPolicy = null; 145 /** 146 * @hide 147 */ setPolicy(Policy policy)148 public void setPolicy(Policy policy) { 149 mPolicy = policy; 150 } 151 /** 152 * @hide 153 */ getPolicy()154 public Policy getPolicy() { 155 return mPolicy; 156 } 157 158 /** 159 * Meta data for performing subscription update. 160 */ 161 private UpdateParameter mSubscriptionUpdate = null; 162 /** 163 * @hide 164 */ setSubscriptionUpdate(UpdateParameter subscriptionUpdate)165 public void setSubscriptionUpdate(UpdateParameter subscriptionUpdate) { 166 mSubscriptionUpdate = subscriptionUpdate; 167 } 168 /** 169 * @hide 170 */ getSubscriptionUpdate()171 public UpdateParameter getSubscriptionUpdate() { 172 return mSubscriptionUpdate; 173 } 174 175 /** 176 * List of HTTPS URL for retrieving trust root certificate and the corresponding SHA-256 177 * fingerprint of the certificate. The certificates are used for verifying AAA server's 178 * identity during EAP authentication. 179 */ 180 private Map<String, byte[]> mTrustRootCertList = null; 181 /** 182 * @hide 183 */ setTrustRootCertList(Map<String, byte[]> trustRootCertList)184 public void setTrustRootCertList(Map<String, byte[]> trustRootCertList) { 185 mTrustRootCertList = trustRootCertList; 186 } 187 /** 188 * @hide 189 */ getTrustRootCertList()190 public Map<String, byte[]> getTrustRootCertList() { 191 return mTrustRootCertList; 192 } 193 194 /** 195 * Set by the subscription server, updated every time the configuration is updated by 196 * the subscription server. 197 * 198 * Use Integer.MIN_VALUE to indicate unset value. 199 */ 200 private int mUpdateIdentifier = Integer.MIN_VALUE; 201 /** 202 * @hide 203 */ setUpdateIdentifier(int updateIdentifier)204 public void setUpdateIdentifier(int updateIdentifier) { 205 mUpdateIdentifier = updateIdentifier; 206 } 207 /** 208 * @hide 209 */ getUpdateIdentifier()210 public int getUpdateIdentifier() { 211 return mUpdateIdentifier; 212 } 213 214 /** 215 * The priority of the credential. 216 * 217 * Use Integer.MIN_VALUE to indicate unset value. 218 */ 219 private int mCredentialPriority = Integer.MIN_VALUE; 220 /** 221 * @hide 222 */ setCredentialPriority(int credentialPriority)223 public void setCredentialPriority(int credentialPriority) { 224 mCredentialPriority = credentialPriority; 225 } 226 /** 227 * @hide 228 */ getCredentialPriority()229 public int getCredentialPriority() { 230 return mCredentialPriority; 231 } 232 233 /** 234 * The time this subscription is created. It is in the format of number 235 * of milliseconds since January 1, 1970, 00:00:00 GMT. 236 * 237 * Use Long.MIN_VALUE to indicate unset value. 238 */ 239 private long mSubscriptionCreationTimeInMillis = Long.MIN_VALUE; 240 /** 241 * @hide 242 */ setSubscriptionCreationTimeInMillis(long subscriptionCreationTimeInMillis)243 public void setSubscriptionCreationTimeInMillis(long subscriptionCreationTimeInMillis) { 244 mSubscriptionCreationTimeInMillis = subscriptionCreationTimeInMillis; 245 } 246 /** 247 * @hide 248 */ getSubscriptionCreationTimeInMillis()249 public long getSubscriptionCreationTimeInMillis() { 250 return mSubscriptionCreationTimeInMillis; 251 } 252 253 /** 254 * The time this subscription will expire. It is in the format of number 255 * of milliseconds since January 1, 1970, 00:00:00 GMT. 256 * 257 * Use Long.MIN_VALUE to indicate unset value. 258 */ 259 private long mSubscriptionExpirationTimeMillis = Long.MIN_VALUE; 260 /** 261 * @hide 262 */ setSubscriptionExpirationTimeInMillis(long subscriptionExpirationTimeInMillis)263 public void setSubscriptionExpirationTimeInMillis(long subscriptionExpirationTimeInMillis) { 264 mSubscriptionExpirationTimeMillis = subscriptionExpirationTimeInMillis; 265 } 266 /** 267 * Utility method to get the time this subscription will expire. It is in the format of number 268 * of milliseconds since January 1, 1970, 00:00:00 GMT. 269 * 270 * @return The time this subscription will expire, or Long.MIN_VALUE to indicate unset value 271 */ 272 @CurrentTimeMillisLong getSubscriptionExpirationTimeMillis()273 public long getSubscriptionExpirationTimeMillis() { 274 return mSubscriptionExpirationTimeMillis; 275 } 276 277 /** 278 * The type of the subscription. This is defined by the provider and the value is provider 279 * specific. 280 */ 281 private String mSubscriptionType = null; 282 /** 283 * @hide 284 */ setSubscriptionType(String subscriptionType)285 public void setSubscriptionType(String subscriptionType) { 286 mSubscriptionType = subscriptionType; 287 } 288 /** 289 * @hide 290 */ getSubscriptionType()291 public String getSubscriptionType() { 292 return mSubscriptionType; 293 } 294 295 /** 296 * The time period for usage statistics accumulation. A value of zero means that usage 297 * statistics are not accumulated on a periodic basis (e.g., a one-time limit for 298 * “pay as you go” - PAYG service). A non-zero value specifies the usage interval in minutes. 299 */ 300 private long mUsageLimitUsageTimePeriodInMinutes = Long.MIN_VALUE; 301 /** 302 * @hide 303 */ setUsageLimitUsageTimePeriodInMinutes(long usageLimitUsageTimePeriodInMinutes)304 public void setUsageLimitUsageTimePeriodInMinutes(long usageLimitUsageTimePeriodInMinutes) { 305 mUsageLimitUsageTimePeriodInMinutes = usageLimitUsageTimePeriodInMinutes; 306 } 307 /** 308 * @hide 309 */ getUsageLimitUsageTimePeriodInMinutes()310 public long getUsageLimitUsageTimePeriodInMinutes() { 311 return mUsageLimitUsageTimePeriodInMinutes; 312 } 313 314 /** 315 * The time at which usage statistic accumulation begins. It is in the format of number 316 * of milliseconds since January 1, 1970, 00:00:00 GMT. 317 * 318 * Use Long.MIN_VALUE to indicate unset value. 319 */ 320 private long mUsageLimitStartTimeInMillis = Long.MIN_VALUE; 321 /** 322 * @hide 323 */ setUsageLimitStartTimeInMillis(long usageLimitStartTimeInMillis)324 public void setUsageLimitStartTimeInMillis(long usageLimitStartTimeInMillis) { 325 mUsageLimitStartTimeInMillis = usageLimitStartTimeInMillis; 326 } 327 /** 328 * @hide 329 */ getUsageLimitStartTimeInMillis()330 public long getUsageLimitStartTimeInMillis() { 331 return mUsageLimitStartTimeInMillis; 332 } 333 334 /** 335 * The cumulative data limit in megabytes for the {@link #usageLimitUsageTimePeriodInMinutes}. 336 * A value of zero indicate unlimited data usage. 337 * 338 * Use Long.MIN_VALUE to indicate unset value. 339 */ 340 private long mUsageLimitDataLimit = Long.MIN_VALUE; 341 /** 342 * @hide 343 */ setUsageLimitDataLimit(long usageLimitDataLimit)344 public void setUsageLimitDataLimit(long usageLimitDataLimit) { 345 mUsageLimitDataLimit = usageLimitDataLimit; 346 } 347 /** 348 * @hide 349 */ getUsageLimitDataLimit()350 public long getUsageLimitDataLimit() { 351 return mUsageLimitDataLimit; 352 } 353 354 /** 355 * The cumulative time limit in minutes for the {@link #usageLimitUsageTimePeriodInMinutes}. 356 * A value of zero indicate unlimited time usage. 357 */ 358 private long mUsageLimitTimeLimitInMinutes = Long.MIN_VALUE; 359 /** 360 * @hide 361 */ setUsageLimitTimeLimitInMinutes(long usageLimitTimeLimitInMinutes)362 public void setUsageLimitTimeLimitInMinutes(long usageLimitTimeLimitInMinutes) { 363 mUsageLimitTimeLimitInMinutes = usageLimitTimeLimitInMinutes; 364 } 365 /** 366 * @hide 367 */ getUsageLimitTimeLimitInMinutes()368 public long getUsageLimitTimeLimitInMinutes() { 369 return mUsageLimitTimeLimitInMinutes; 370 } 371 372 /** 373 * The map of OSU service provider names whose each element is presented in different 374 * languages for the service provider, which is used for finding a matching 375 * PasspointConfiguration with a given service provider name. 376 */ 377 private Map<String, String> mServiceFriendlyNames = null; 378 379 /** 380 * @hide 381 */ setServiceFriendlyNames(Map<String, String> serviceFriendlyNames)382 public void setServiceFriendlyNames(Map<String, String> serviceFriendlyNames) { 383 mServiceFriendlyNames = serviceFriendlyNames; 384 } 385 386 /** 387 * @hide 388 */ getServiceFriendlyNames()389 public Map<String, String> getServiceFriendlyNames() { 390 return mServiceFriendlyNames; 391 } 392 393 /** 394 * Return the friendly Name for current language from the list of friendly names of OSU 395 * provider. 396 * The string matching the default locale will be returned if it is found, otherwise the 397 * first string in the list will be returned. A null will be returned if the list is empty. 398 * 399 * @return String matching the default locale, null otherwise 400 * @hide 401 */ getServiceFriendlyName()402 public String getServiceFriendlyName() { 403 if (mServiceFriendlyNames == null || mServiceFriendlyNames.isEmpty()) return null; 404 String lang = Locale.getDefault().getLanguage(); 405 String friendlyName = mServiceFriendlyNames.get(lang); 406 if (friendlyName != null) { 407 return friendlyName; 408 } 409 friendlyName = mServiceFriendlyNames.get("en"); 410 if (friendlyName != null) { 411 return friendlyName; 412 } 413 return mServiceFriendlyNames.get(mServiceFriendlyNames.keySet().stream().findFirst().get()); 414 } 415 416 /** 417 * The carrier ID identifies the operator who provides this network configuration. 418 * see {@link TelephonyManager#getSimCarrierId()} 419 */ 420 private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 421 422 /** 423 * The subscription ID identifies the SIM card who provides this network configuration. 424 * See {@link SubscriptionInfo#getSubscriptionId()} 425 */ 426 private int mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 427 428 /** 429 * Set the carrier ID associated with current configuration. 430 * @param carrierId {@code mCarrierId} 431 * @hide 432 */ setCarrierId(int carrierId)433 public void setCarrierId(int carrierId) { 434 this.mCarrierId = carrierId; 435 } 436 437 /** 438 * Get the carrier ID associated with current configuration. 439 * @return {@code mCarrierId} 440 * @hide 441 */ getCarrierId()442 public int getCarrierId() { 443 return mCarrierId; 444 } 445 446 /** 447 * Set the subscription ID associated with current configuration. 448 * @param subscriptionId {@code mSubscriptionId} 449 * @hide 450 */ setSubscriptionId(int subscriptionId)451 public void setSubscriptionId(int subscriptionId) { 452 this.mSubscriptionId = subscriptionId; 453 } 454 455 /** 456 * Get the carrier ID associated with current configuration. 457 * @return {@code mSubscriptionId} 458 * @hide 459 */ getSubscriptionId()460 public int getSubscriptionId() { 461 return mSubscriptionId; 462 } 463 464 /** 465 * The auto-join configuration specifies whether or not the Passpoint Configuration is 466 * considered for auto-connection. If true then yes, if false then it isn't considered as part 467 * of auto-connection - but can still be manually connected to. 468 */ 469 private boolean mIsAutojoinEnabled = true; 470 471 /** 472 * The mac randomization setting specifies whether a randomized or device MAC address will 473 * be used to connect to the passpoint network. If true, a randomized MAC will be used. 474 * Otherwise, the device MAC address will be used. 475 */ 476 private boolean mIsMacRandomizationEnabled = true; 477 478 /** 479 * Whether this passpoint configuration should use enhanced MAC randomization. 480 */ 481 private boolean mIsEnhancedMacRandomizationEnabled = false; 482 483 484 /** 485 * Indicate whether the network is oem paid or not. Networks are considered oem paid 486 * if the corresponding connection is only available to system apps. 487 * @hide 488 */ 489 private boolean mIsOemPaid; 490 491 /** 492 * Indicate whether the network is oem private or not. Networks are considered oem private 493 * if the corresponding connection is only available to system apps. 494 * @hide 495 */ 496 private boolean mIsOemPrivate; 497 498 /** 499 * Indicate whether or not the network is a carrier merged network. 500 * @hide 501 */ 502 private boolean mIsCarrierMerged; 503 504 /** 505 * Indicates if the end user has expressed an explicit opinion about the 506 * meteredness of this network, such as through the Settings app. 507 * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED}, 508 * or {@link #METERED_OVERRIDE_NOT_METERED}. 509 * <p> 510 * This should always override any values from {@link WifiInfo#getMeteredHint()}. 511 * 512 * By default this field is set to {@link #METERED_OVERRIDE_NONE}. 513 */ 514 private int mMeteredOverride = METERED_OVERRIDE_NONE; 515 516 private String mDecoratedIdentityPrefix; 517 518 /** 519 * Configures the auto-association status of this Passpoint configuration. A value of true 520 * indicates that the configuration will be considered for auto-connection, a value of false 521 * indicates that only manual connection will work - the framework will not auto-associate to 522 * this Passpoint network. 523 * 524 * @param autojoinEnabled true to be considered for framework auto-connection, false otherwise. 525 * @hide 526 */ setAutojoinEnabled(boolean autojoinEnabled)527 public void setAutojoinEnabled(boolean autojoinEnabled) { 528 mIsAutojoinEnabled = autojoinEnabled; 529 } 530 531 /** 532 * Configures the MAC randomization setting for this Passpoint configuration. 533 * If set to true, the framework will use a randomized MAC address to connect to this Passpoint 534 * network. Otherwise, the framework will use the device MAC address. 535 * 536 * @param enabled true to use randomized MAC address, false to use device MAC address. 537 * @hide 538 */ setMacRandomizationEnabled(boolean enabled)539 public void setMacRandomizationEnabled(boolean enabled) { 540 mIsMacRandomizationEnabled = enabled; 541 } 542 543 /** 544 * This setting is only applicable if MAC randomization is enabled. 545 * If set to true, the framework will periodically generate new MAC addresses for new 546 * connections. 547 * If set to false (the default), the framework will use the same locally generated MAC address 548 * for connections to this passpoint configuration. 549 * @param enabled true to use enhanced MAC randomization, false to use persistent MAC 550 * randomization. 551 * @hide 552 */ setEnhancedMacRandomizationEnabled(boolean enabled)553 public void setEnhancedMacRandomizationEnabled(boolean enabled) { 554 mIsEnhancedMacRandomizationEnabled = enabled; 555 } 556 557 /** 558 * Sets the metered override setting for this Passpoint configuration. 559 * 560 * @param meteredOverride One of the values in {@link MeteredOverride} 561 * @hide 562 */ setMeteredOverride(@eteredOverride int meteredOverride)563 public void setMeteredOverride(@MeteredOverride int meteredOverride) { 564 mMeteredOverride = meteredOverride; 565 } 566 567 /** 568 * Indicates whether the Passpoint configuration may be auto-connected to by the framework. A 569 * value of true indicates that auto-connection can happen, a value of false indicates that it 570 * cannot. However, even when auto-connection is not possible manual connection by the user is 571 * possible. 572 * 573 * @return the auto-join configuration: true for auto-connection (or join) enabled, false 574 * otherwise. 575 * @hide 576 */ 577 @SystemApi isAutojoinEnabled()578 public boolean isAutojoinEnabled() { 579 return mIsAutojoinEnabled; 580 } 581 582 /** 583 * Indicates whether the user chose this configuration to be treated as metered or not. 584 * 585 * @return One of the values in {@link MeteredOverride} 586 * @hide 587 */ 588 @SystemApi 589 @MeteredOverride getMeteredOverride()590 public int getMeteredOverride() { 591 return mMeteredOverride; 592 } 593 594 /** 595 * Indicates whether a randomized MAC address or device MAC address will be used for 596 * connections to this Passpoint network. If true, a randomized MAC address will be used. 597 * Otherwise, the device MAC address will be used. 598 * 599 * @return true for MAC randomization enabled. False for disabled. 600 * @hide 601 */ 602 @SystemApi isMacRandomizationEnabled()603 public boolean isMacRandomizationEnabled() { 604 return mIsMacRandomizationEnabled; 605 } 606 607 /** 608 * When MAC randomization is enabled, this indicates whether enhanced MAC randomization or 609 * persistent MAC randomization will be used for connections to this Passpoint network. 610 * If true, the MAC address used for connections will periodically change. Otherwise, the same 611 * locally generated MAC will be used for all connections to this passpoint configuration. 612 * 613 * @return true for enhanced MAC randomization enabled. False for disabled. 614 * @hide 615 */ isEnhancedMacRandomizationEnabled()616 public boolean isEnhancedMacRandomizationEnabled() { 617 return mIsEnhancedMacRandomizationEnabled; 618 } 619 620 /** 621 * Set whether the network is oem paid or not. 622 * @hide 623 */ setOemPaid(boolean isOemPaid)624 public void setOemPaid(boolean isOemPaid) { 625 mIsOemPaid = isOemPaid; 626 } 627 628 /** 629 * Get whether the network is oem paid or not. 630 * @hide 631 */ isOemPaid()632 public boolean isOemPaid() { 633 return mIsOemPaid; 634 } 635 636 /** 637 * Set whether the network is oem private or not. 638 * @hide 639 */ setOemPrivate(boolean isOemPrivate)640 public void setOemPrivate(boolean isOemPrivate) { 641 mIsOemPrivate = isOemPrivate; 642 } 643 644 /** 645 * Get whether the network is oem private or not. 646 * @hide 647 */ isOemPrivate()648 public boolean isOemPrivate() { 649 return mIsOemPrivate; 650 } 651 652 /** 653 * Set whether the network is carrier merged or not. 654 * @hide 655 */ setCarrierMerged(boolean isCarrierMerged)656 public void setCarrierMerged(boolean isCarrierMerged) { 657 mIsCarrierMerged = isCarrierMerged; 658 } 659 660 /** 661 * Get whether the network is carrier merged or not. 662 * @hide 663 */ isCarrierMerged()664 public boolean isCarrierMerged() { 665 return mIsCarrierMerged; 666 } 667 668 /** 669 * Constructor for creating PasspointConfiguration with default values. 670 */ PasspointConfiguration()671 public PasspointConfiguration() {} 672 673 /** 674 * Copy constructor. 675 * 676 * @param source The source to copy from 677 */ PasspointConfiguration(PasspointConfiguration source)678 public PasspointConfiguration(PasspointConfiguration source) { 679 if (source == null) { 680 return; 681 } 682 683 if (source.mHomeSp != null) { 684 mHomeSp = new HomeSp(source.mHomeSp); 685 } 686 if (source.mCredential != null) { 687 mCredential = new Credential(source.mCredential); 688 } 689 if (source.mPolicy != null) { 690 mPolicy = new Policy(source.mPolicy); 691 } 692 if (source.mTrustRootCertList != null) { 693 mTrustRootCertList = Collections.unmodifiableMap(source.mTrustRootCertList); 694 } 695 if (source.mSubscriptionUpdate != null) { 696 mSubscriptionUpdate = new UpdateParameter(source.mSubscriptionUpdate); 697 } 698 mUpdateIdentifier = source.mUpdateIdentifier; 699 mCredentialPriority = source.mCredentialPriority; 700 mSubscriptionCreationTimeInMillis = source.mSubscriptionCreationTimeInMillis; 701 mSubscriptionExpirationTimeMillis = source.mSubscriptionExpirationTimeMillis; 702 mSubscriptionType = source.mSubscriptionType; 703 mUsageLimitDataLimit = source.mUsageLimitDataLimit; 704 mUsageLimitStartTimeInMillis = source.mUsageLimitStartTimeInMillis; 705 mUsageLimitTimeLimitInMinutes = source.mUsageLimitTimeLimitInMinutes; 706 mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes; 707 mServiceFriendlyNames = source.mServiceFriendlyNames; 708 mAaaServerTrustedNames = source.mAaaServerTrustedNames; 709 mCarrierId = source.mCarrierId; 710 mSubscriptionId = source.mSubscriptionId; 711 mIsAutojoinEnabled = source.mIsAutojoinEnabled; 712 mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled; 713 mIsEnhancedMacRandomizationEnabled = source.mIsEnhancedMacRandomizationEnabled; 714 mMeteredOverride = source.mMeteredOverride; 715 mIsCarrierMerged = source.mIsCarrierMerged; 716 mIsOemPaid = source.mIsOemPaid; 717 mIsOemPrivate = source.mIsOemPrivate; 718 mDecoratedIdentityPrefix = source.mDecoratedIdentityPrefix; 719 } 720 721 @Override describeContents()722 public int describeContents() { 723 return 0; 724 } 725 726 @Override writeToParcel(Parcel dest, int flags)727 public void writeToParcel(Parcel dest, int flags) { 728 dest.writeParcelable(mHomeSp, flags); 729 dest.writeParcelable(mCredential, flags); 730 dest.writeParcelable(mPolicy, flags); 731 dest.writeParcelable(mSubscriptionUpdate, flags); 732 writeTrustRootCerts(dest, mTrustRootCertList); 733 dest.writeInt(mUpdateIdentifier); 734 dest.writeInt(mCredentialPriority); 735 dest.writeLong(mSubscriptionCreationTimeInMillis); 736 dest.writeLong(mSubscriptionExpirationTimeMillis); 737 dest.writeString(mSubscriptionType); 738 dest.writeLong(mUsageLimitUsageTimePeriodInMinutes); 739 dest.writeLong(mUsageLimitStartTimeInMillis); 740 dest.writeLong(mUsageLimitDataLimit); 741 dest.writeLong(mUsageLimitTimeLimitInMinutes); 742 dest.writeStringArray(mAaaServerTrustedNames); 743 Bundle bundle = new Bundle(); 744 bundle.putSerializable("serviceFriendlyNames", 745 (HashMap<String, String>) mServiceFriendlyNames); 746 dest.writeBundle(bundle); 747 dest.writeInt(mCarrierId); 748 dest.writeBoolean(mIsAutojoinEnabled); 749 dest.writeBoolean(mIsMacRandomizationEnabled); 750 dest.writeBoolean(mIsEnhancedMacRandomizationEnabled); 751 dest.writeInt(mMeteredOverride); 752 dest.writeInt(mSubscriptionId); 753 dest.writeBoolean(mIsCarrierMerged); 754 dest.writeBoolean(mIsOemPaid); 755 dest.writeBoolean(mIsOemPrivate); 756 dest.writeString(mDecoratedIdentityPrefix); 757 } 758 759 @Override equals(Object thatObject)760 public boolean equals(Object thatObject) { 761 if (this == thatObject) { 762 return true; 763 } 764 if (!(thatObject instanceof PasspointConfiguration)) { 765 return false; 766 } 767 PasspointConfiguration that = (PasspointConfiguration) thatObject; 768 return (mHomeSp == null ? that.mHomeSp == null : mHomeSp.equals(that.mHomeSp)) 769 && (mAaaServerTrustedNames == null ? that.mAaaServerTrustedNames == null 770 : Arrays.equals(mAaaServerTrustedNames, that.mAaaServerTrustedNames)) 771 && (mCredential == null ? that.mCredential == null 772 : mCredential.equals(that.mCredential)) 773 && (mPolicy == null ? that.mPolicy == null : mPolicy.equals(that.mPolicy)) 774 && (mSubscriptionUpdate == null ? that.mSubscriptionUpdate == null 775 : mSubscriptionUpdate.equals(that.mSubscriptionUpdate)) 776 && isTrustRootCertListEquals(mTrustRootCertList, that.mTrustRootCertList) 777 && mUpdateIdentifier == that.mUpdateIdentifier 778 && mCredentialPriority == that.mCredentialPriority 779 && mSubscriptionCreationTimeInMillis == that.mSubscriptionCreationTimeInMillis 780 && mSubscriptionExpirationTimeMillis == that.mSubscriptionExpirationTimeMillis 781 && TextUtils.equals(mSubscriptionType, that.mSubscriptionType) 782 && mUsageLimitUsageTimePeriodInMinutes == that.mUsageLimitUsageTimePeriodInMinutes 783 && mUsageLimitStartTimeInMillis == that.mUsageLimitStartTimeInMillis 784 && mUsageLimitDataLimit == that.mUsageLimitDataLimit 785 && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes 786 && mCarrierId == that.mCarrierId 787 && mSubscriptionId == that.mSubscriptionId 788 && mIsOemPrivate == that.mIsOemPrivate 789 && mIsOemPaid == that.mIsOemPaid 790 && mIsCarrierMerged == that.mIsCarrierMerged 791 && mIsAutojoinEnabled == that.mIsAutojoinEnabled 792 && mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled 793 && mIsEnhancedMacRandomizationEnabled == that.mIsEnhancedMacRandomizationEnabled 794 && mMeteredOverride == that.mMeteredOverride 795 && (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null 796 : mServiceFriendlyNames.equals(that.mServiceFriendlyNames)) 797 && Objects.equals(mDecoratedIdentityPrefix, that.mDecoratedIdentityPrefix); 798 } 799 800 @Override hashCode()801 public int hashCode() { 802 return Objects.hash(mHomeSp, mCredential, mPolicy, mSubscriptionUpdate, mTrustRootCertList, 803 mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis, 804 mSubscriptionExpirationTimeMillis, mUsageLimitUsageTimePeriodInMinutes, 805 mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes, 806 mServiceFriendlyNames, mCarrierId, mIsAutojoinEnabled, mIsMacRandomizationEnabled, 807 mIsEnhancedMacRandomizationEnabled, mMeteredOverride, mSubscriptionId, 808 mIsCarrierMerged, mIsOemPaid, mIsOemPrivate, mDecoratedIdentityPrefix); 809 } 810 811 @Override toString()812 public String toString() { 813 StringBuilder builder = new StringBuilder(); 814 builder.append("UpdateIdentifier: ").append(mUpdateIdentifier).append("\n"); 815 builder.append("CredentialPriority: ").append(mCredentialPriority).append("\n"); 816 builder.append("SubscriptionCreationTime: ").append( 817 mSubscriptionCreationTimeInMillis != Long.MIN_VALUE 818 ? new Date(mSubscriptionCreationTimeInMillis) : "Not specified").append("\n"); 819 builder.append("SubscriptionExpirationTime: ").append( 820 mSubscriptionExpirationTimeMillis != Long.MIN_VALUE 821 ? new Date(mSubscriptionExpirationTimeMillis) : "Not specified").append("\n"); 822 builder.append("UsageLimitStartTime: ").append(mUsageLimitStartTimeInMillis != Long.MIN_VALUE 823 ? new Date(mUsageLimitStartTimeInMillis) : "Not specified").append("\n"); 824 builder.append("UsageTimePeriod: ").append(mUsageLimitUsageTimePeriodInMinutes) 825 .append("\n"); 826 builder.append("UsageLimitDataLimit: ").append(mUsageLimitDataLimit).append("\n"); 827 builder.append("UsageLimitTimeLimit: ").append(mUsageLimitTimeLimitInMinutes).append("\n"); 828 builder.append("Provisioned by a subscription server: ") 829 .append(isOsuProvisioned() ? "Yes" : "No").append("\n"); 830 if (mHomeSp != null) { 831 builder.append("HomeSP Begin ---\n"); 832 builder.append(mHomeSp); 833 builder.append("HomeSP End ---\n"); 834 } 835 if (mCredential != null) { 836 builder.append("Credential Begin ---\n"); 837 builder.append(mCredential); 838 builder.append("Credential End ---\n"); 839 } 840 if (mPolicy != null) { 841 builder.append("Policy Begin ---\n"); 842 builder.append(mPolicy); 843 builder.append("Policy End ---\n"); 844 } 845 if (mSubscriptionUpdate != null) { 846 builder.append("SubscriptionUpdate Begin ---\n"); 847 builder.append(mSubscriptionUpdate); 848 builder.append("SubscriptionUpdate End ---\n"); 849 } 850 if (mTrustRootCertList != null) { 851 builder.append("TrustRootCertServers: ").append(mTrustRootCertList.keySet()) 852 .append("\n"); 853 } 854 if (mAaaServerTrustedNames != null) { 855 builder.append("AAAServerTrustedNames: ") 856 .append(String.join(";", mAaaServerTrustedNames)).append("\n"); 857 } 858 if (mServiceFriendlyNames != null) { 859 builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames); 860 } 861 builder.append("CarrierId:" + mCarrierId); 862 builder.append("SubscriptionId:" + mSubscriptionId); 863 builder.append("IsAutojoinEnabled:" + mIsAutojoinEnabled); 864 builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled); 865 builder.append("mIsEnhancedMacRandomizationEnabled:" + mIsEnhancedMacRandomizationEnabled); 866 builder.append("mMeteredOverride:" + mMeteredOverride); 867 builder.append("mIsCarrierMerged:" + mIsCarrierMerged); 868 builder.append("mIsOemPaid:" + mIsOemPaid); 869 builder.append("mIsOemPrivate:" + mIsOemPrivate); 870 builder.append("mDecoratedUsernamePrefix:" + mDecoratedIdentityPrefix); 871 return builder.toString(); 872 } 873 874 /** 875 * Validate the R1 configuration data. 876 * 877 * @return true on success or false on failure 878 * @hide 879 */ validate()880 public boolean validate() { 881 // Optional: PerProviderSubscription/<X+>/SubscriptionUpdate 882 if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) { 883 return false; 884 } 885 return validateForCommonR1andR2(); 886 } 887 888 /** 889 * Validate the R2 configuration data. 890 * 891 * @return true on success or false on failure 892 * @hide 893 */ validateForR2()894 public boolean validateForR2() { 895 // Required: PerProviderSubscription/UpdateIdentifier 896 if (mUpdateIdentifier == Integer.MIN_VALUE) { 897 return false; 898 } 899 900 // Required: PerProviderSubscription/<X+>/SubscriptionUpdate 901 if (mSubscriptionUpdate == null || !mSubscriptionUpdate.validate()) { 902 return false; 903 } 904 return validateForCommonR1andR2(); 905 } 906 validateForCommonR1andR2()907 private boolean validateForCommonR1andR2() { 908 // Required: PerProviderSubscription/<X+>/HomeSP 909 if (mHomeSp == null || !mHomeSp.validate()) { 910 return false; 911 } 912 913 // Required: PerProviderSubscription/<X+>/Credential 914 if (mCredential == null || !mCredential.validate()) { 915 return false; 916 } 917 918 // Optional: PerProviderSubscription/<X+>/Policy 919 if (mPolicy != null && !mPolicy.validate()) { 920 return false; 921 } 922 923 if (mTrustRootCertList != null) { 924 for (Map.Entry<String, byte[]> entry : mTrustRootCertList.entrySet()) { 925 String url = entry.getKey(); 926 byte[] certFingerprint = entry.getValue(); 927 if (TextUtils.isEmpty(url)) { 928 Log.d(TAG, "Empty URL"); 929 return false; 930 } 931 if (url.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) { 932 Log.d(TAG, "URL bytes exceeded the max: " 933 + url.getBytes(StandardCharsets.UTF_8).length); 934 return false; 935 } 936 937 if (certFingerprint == null) { 938 Log.d(TAG, "Fingerprint not specified"); 939 return false; 940 } 941 if (certFingerprint.length != CERTIFICATE_SHA256_BYTES) { 942 Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: " 943 + certFingerprint.length); 944 return false; 945 } 946 } 947 } 948 return true; 949 } 950 951 public static final @android.annotation.NonNull Creator<PasspointConfiguration> CREATOR = 952 new Creator<PasspointConfiguration>() { 953 @Override 954 public PasspointConfiguration createFromParcel(Parcel in) { 955 PasspointConfiguration config = new PasspointConfiguration(); 956 config.setHomeSp(in.readParcelable(null)); 957 config.setCredential(in.readParcelable(null)); 958 config.setPolicy(in.readParcelable(null)); 959 config.setSubscriptionUpdate(in.readParcelable(null)); 960 config.setTrustRootCertList(readTrustRootCerts(in)); 961 config.setUpdateIdentifier(in.readInt()); 962 config.setCredentialPriority(in.readInt()); 963 config.setSubscriptionCreationTimeInMillis(in.readLong()); 964 config.setSubscriptionExpirationTimeInMillis(in.readLong()); 965 config.setSubscriptionType(in.readString()); 966 config.setUsageLimitUsageTimePeriodInMinutes(in.readLong()); 967 config.setUsageLimitStartTimeInMillis(in.readLong()); 968 config.setUsageLimitDataLimit(in.readLong()); 969 config.setUsageLimitTimeLimitInMinutes(in.readLong()); 970 config.setAaaServerTrustedNames(in.createStringArray()); 971 Bundle bundle = in.readBundle(); 972 Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable( 973 "serviceFriendlyNames"); 974 config.setServiceFriendlyNames(friendlyNamesMap); 975 config.mCarrierId = in.readInt(); 976 config.mIsAutojoinEnabled = in.readBoolean(); 977 config.mIsMacRandomizationEnabled = in.readBoolean(); 978 config.mIsEnhancedMacRandomizationEnabled = in.readBoolean(); 979 config.mMeteredOverride = in.readInt(); 980 config.mSubscriptionId = in.readInt(); 981 config.mIsCarrierMerged = in.readBoolean(); 982 config.mIsOemPaid = in.readBoolean(); 983 config.mIsOemPrivate = in.readBoolean(); 984 config.mDecoratedIdentityPrefix = in.readString(); 985 986 return config; 987 } 988 989 @Override 990 public PasspointConfiguration[] newArray(int size) { 991 return new PasspointConfiguration[size]; 992 } 993 994 /** 995 * Helper function for reading trust root certificate info list from a Parcel. 996 * 997 * @param in The Parcel to read from 998 * @return The list of trust root certificate URL with the corresponding certificate 999 * fingerprint 1000 */ 1001 private Map<String, byte[]> readTrustRootCerts(Parcel in) { 1002 int size = in.readInt(); 1003 if (size == NULL_VALUE) { 1004 return null; 1005 } 1006 Map<String, byte[]> trustRootCerts = new HashMap<>(size); 1007 for (int i = 0; i < size; i++) { 1008 String key = in.readString(); 1009 byte[] value = in.createByteArray(); 1010 trustRootCerts.put(key, value); 1011 } 1012 return trustRootCerts; 1013 } 1014 }; 1015 1016 /** 1017 * Helper function for writing trust root certificate information list. 1018 * 1019 * @param dest The Parcel to write to 1020 * @param trustRootCerts The list of trust root certificate URL with the corresponding 1021 * certificate fingerprint 1022 */ writeTrustRootCerts(Parcel dest, Map<String, byte[]> trustRootCerts)1023 private static void writeTrustRootCerts(Parcel dest, Map<String, byte[]> trustRootCerts) { 1024 if (trustRootCerts == null) { 1025 dest.writeInt(NULL_VALUE); 1026 return; 1027 } 1028 dest.writeInt(trustRootCerts.size()); 1029 for (Map.Entry<String, byte[]> entry : trustRootCerts.entrySet()) { 1030 dest.writeString(entry.getKey()); 1031 dest.writeByteArray(entry.getValue()); 1032 } 1033 } 1034 1035 /** 1036 * Helper function for comparing two trust root certificate list. Cannot use Map#equals 1037 * method since the value type (byte[]) doesn't override equals method. 1038 * 1039 * @param list1 The first trust root certificate list 1040 * @param list2 The second trust root certificate list 1041 * @return true if the two list are equal 1042 */ isTrustRootCertListEquals(Map<String, byte[]> list1, Map<String, byte[]> list2)1043 private static boolean isTrustRootCertListEquals(Map<String, byte[]> list1, 1044 Map<String, byte[]> list2) { 1045 if (list1 == null || list2 == null) { 1046 return list1 == list2; 1047 } 1048 if (list1.size() != list2.size()) { 1049 return false; 1050 } 1051 for (Map.Entry<String, byte[]> entry : list1.entrySet()) { 1052 if (!Arrays.equals(entry.getValue(), list2.get(entry.getKey()))) { 1053 return false; 1054 } 1055 } 1056 return true; 1057 } 1058 1059 /** 1060 * Indicates if the Passpoint Configuration was provisioned by a subscription (OSU) server, 1061 * which means that it's an R2 (or R3) profile. 1062 * 1063 * @return true if the Passpoint Configuration was provisioned by a subscription server. 1064 */ isOsuProvisioned()1065 public boolean isOsuProvisioned() { 1066 return getUpdateIdentifier() != Integer.MIN_VALUE; 1067 } 1068 1069 /** 1070 * Get a unique identifier for a PasspointConfiguration object. The identifier depends on the 1071 * configuration that identify the service provider under the HomeSp subtree, and on the 1072 * credential configuration under the Credential subtree. 1073 * The method throws an {@link IllegalStateException} if the configuration under HomeSp subtree 1074 * or the configuration under Credential subtree are not initialized. 1075 * 1076 * @return A unique identifier 1077 */ getUniqueId()1078 public @NonNull String getUniqueId() { 1079 if (mCredential == null || mHomeSp == null || TextUtils.isEmpty(mHomeSp.getFqdn())) { 1080 throw new IllegalStateException("Credential or HomeSP are not initialized"); 1081 } 1082 1083 StringBuilder sb = new StringBuilder(); 1084 sb.append(String.format("%s_%x%x", mHomeSp.getFqdn(), mHomeSp.getUniqueId(), 1085 mCredential.getUniqueId())); 1086 return sb.toString(); 1087 } 1088 1089 /** 1090 * Set a prefix for a decorated identity as per RFC 7542. 1091 * This prefix must contain a list of realms (could be a list of 1) delimited by a '!' 1092 * character. e.g. homerealm.example.org! or proxyrealm.example.net!homerealm.example.org! 1093 * A prefix of "homerealm.example.org!" will generate a decorated identity that 1094 * looks like: homerealm.example.org!user@otherrealm.example.net 1095 * Calling with a null parameter will clear the decorated prefix. 1096 * Note: Caller must verify that the device supports this feature by calling 1097 * {@link WifiManager#isDecoratedIdentitySupported()} 1098 * 1099 * @param decoratedIdentityPrefix The prefix to add to the outer/anonymous identity 1100 */ 1101 @RequiresApi(Build.VERSION_CODES.S) setDecoratedIdentityPrefix(@ullable String decoratedIdentityPrefix)1102 public void setDecoratedIdentityPrefix(@Nullable String decoratedIdentityPrefix) { 1103 if (!SdkLevel.isAtLeastS()) { 1104 throw new UnsupportedOperationException(); 1105 } 1106 if (!TextUtils.isEmpty(decoratedIdentityPrefix) && !decoratedIdentityPrefix.endsWith("!")) { 1107 throw new IllegalArgumentException( 1108 "Decorated identity prefix must be delimited by '!'"); 1109 } 1110 mDecoratedIdentityPrefix = decoratedIdentityPrefix; 1111 } 1112 1113 /** 1114 * Get the decorated identity prefix. 1115 * 1116 * @return The decorated identity prefix 1117 */ 1118 @RequiresApi(Build.VERSION_CODES.S) getDecoratedIdentityPrefix()1119 public @Nullable String getDecoratedIdentityPrefix() { 1120 if (!SdkLevel.isAtLeastS()) { 1121 throw new UnsupportedOperationException(); 1122 } 1123 return mDecoratedIdentityPrefix; 1124 } 1125 } 1126