hotspot2: added remaining parameters to PasspointConfiguration
Added remaining parameters to PasspointConfiguration to support complete PerProviderSubscription tree for Release 2 support. The new parameters include: - Update identifier - Credential priority - AAA server trust root - Subscription update - Subscription parameters Bug: 34198926 Test: frameworks/base/wifi/test/runtests.sh Change-Id: If50253612f7777b3b693a344378a2e4810b3ff47
This commit is contained in:
@@ -19,9 +19,18 @@ package android.net.wifi.hotspot2;
|
|||||||
import android.net.wifi.hotspot2.pps.Credential;
|
import android.net.wifi.hotspot2.pps.Credential;
|
||||||
import android.net.wifi.hotspot2.pps.HomeSP;
|
import android.net.wifi.hotspot2.pps.HomeSP;
|
||||||
import android.net.wifi.hotspot2.pps.Policy;
|
import android.net.wifi.hotspot2.pps.Policy;
|
||||||
|
import android.net.wifi.hotspot2.pps.UpdateParameter;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing Passpoint configuration. This contains configurations specified in
|
* Class representing Passpoint configuration. This contains configurations specified in
|
||||||
* PerProviderSubscription (PPS) Management Object (MO) tree.
|
* PerProviderSubscription (PPS) Management Object (MO) tree.
|
||||||
@@ -32,10 +41,106 @@ import android.os.Parcel;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public final class PasspointConfiguration implements Parcelable {
|
public final class PasspointConfiguration implements Parcelable {
|
||||||
|
private static final String TAG = "PasspointConfiguration";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of bytes for certificate SHA-256 fingerprint byte array.
|
||||||
|
*/
|
||||||
|
private static final int CERTIFICATE_SHA256_BYTES = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum bytes for URL string.
|
||||||
|
*/
|
||||||
|
private static final int MAX_URL_BYTES = 1023;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integer value used for indicating null value in the Parcel.
|
||||||
|
*/
|
||||||
|
private static final int NULL_VALUE = -1;
|
||||||
|
|
||||||
public HomeSP homeSp = null;
|
public HomeSP homeSp = null;
|
||||||
public Credential credential = null;
|
public Credential credential = null;
|
||||||
public Policy policy = null;
|
public Policy policy = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meta data for performing subscription update.
|
||||||
|
*/
|
||||||
|
public UpdateParameter subscriptionUpdate = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of HTTPS URL for retrieving trust root certificate and the corresponding SHA-256
|
||||||
|
* fingerprint of the certificate. The certificates are used for verifying AAA server's
|
||||||
|
* identity during EAP authentication.
|
||||||
|
*/
|
||||||
|
public Map<String, byte[]> trustRootCertList = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set by the subscription server, updated every time the configuration is updated by
|
||||||
|
* the subscription server.
|
||||||
|
*
|
||||||
|
* Use Integer.MIN_VALUE to indicate unset value.
|
||||||
|
*/
|
||||||
|
public int updateIdentifier = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The priority of the credential.
|
||||||
|
*
|
||||||
|
* Use Integer.MIN_VALUE to indicate unset value.
|
||||||
|
*/
|
||||||
|
public int credentialPriority = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time this subscription is created. It is in the format of number
|
||||||
|
* of milliseconds since January 1, 1970, 00:00:00 GMT.
|
||||||
|
*
|
||||||
|
* Use Long.MIN_VALUE to indicate unset value.
|
||||||
|
*/
|
||||||
|
public long subscriptionCreationTimeInMs = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time this subscription will expire. It is in the format of number
|
||||||
|
* of milliseconds since January 1, 1970, 00:00:00 GMT.
|
||||||
|
*
|
||||||
|
* Use Long.MIN_VALUE to indicate unset value.
|
||||||
|
*/
|
||||||
|
public long subscriptionExpirationTimeInMs = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the subscription. This is defined by the provider and the value is provider
|
||||||
|
* specific.
|
||||||
|
*/
|
||||||
|
public String subscriptionType = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time period for usage statistics accumulation. A value of zero means that usage
|
||||||
|
* statistics are not accumulated on a periodic basis (e.g., a one-time limit for
|
||||||
|
* “pay as you go” - PAYG service). A non-zero value specifies the usage interval in minutes.
|
||||||
|
*/
|
||||||
|
public long usageLimitUsageTimePeriodInMinutes = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time at which usage statistic accumulation begins. It is in the format of number
|
||||||
|
* of milliseconds since January 1, 1970, 00:00:00 GMT.
|
||||||
|
*
|
||||||
|
* Use Long.MIN_VALUE to indicate unset value.
|
||||||
|
*/
|
||||||
|
public long usageLimitStartTimeInMs = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cumulative data limit in megabytes for the {@link #usageLimitUsageTimePeriodInMinutes}.
|
||||||
|
* A value of zero indicate unlimited data usage.
|
||||||
|
*
|
||||||
|
* Use Long.MIN_VALUE to indicate unset value.
|
||||||
|
*/
|
||||||
|
public long usageLimitDataLimit = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cumulative time limit in minutes for the {@link #usageLimitUsageTimePeriodInMinutes}.
|
||||||
|
* A value of zero indicate unlimited time usage.
|
||||||
|
*/
|
||||||
|
public long usageLimitTimeLimitInMinutes = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for creating PasspointConfiguration with default values.
|
* Constructor for creating PasspointConfiguration with default values.
|
||||||
*/
|
*/
|
||||||
@@ -47,17 +152,34 @@ public final class PasspointConfiguration implements Parcelable {
|
|||||||
* @param source The source to copy from
|
* @param source The source to copy from
|
||||||
*/
|
*/
|
||||||
public PasspointConfiguration(PasspointConfiguration source) {
|
public PasspointConfiguration(PasspointConfiguration source) {
|
||||||
if (source != null) {
|
if (source == null) {
|
||||||
if (source.homeSp != null) {
|
return;
|
||||||
homeSp = new HomeSP(source.homeSp);
|
|
||||||
}
|
|
||||||
if (source.credential != null) {
|
|
||||||
credential = new Credential(source.credential);
|
|
||||||
}
|
|
||||||
if (source.policy != null) {
|
|
||||||
policy = new Policy(source.policy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source.homeSp != null) {
|
||||||
|
homeSp = new HomeSP(source.homeSp);
|
||||||
|
}
|
||||||
|
if (source.credential != null) {
|
||||||
|
credential = new Credential(source.credential);
|
||||||
|
}
|
||||||
|
if (source.policy != null) {
|
||||||
|
policy = new Policy(source.policy);
|
||||||
|
}
|
||||||
|
if (source.trustRootCertList != null) {
|
||||||
|
trustRootCertList = Collections.unmodifiableMap(source.trustRootCertList);
|
||||||
|
}
|
||||||
|
if (source.subscriptionUpdate != null) {
|
||||||
|
subscriptionUpdate = new UpdateParameter(source.subscriptionUpdate);
|
||||||
|
}
|
||||||
|
updateIdentifier = source.updateIdentifier;
|
||||||
|
credentialPriority = source.credentialPriority;
|
||||||
|
subscriptionCreationTimeInMs = source.subscriptionCreationTimeInMs;
|
||||||
|
subscriptionExpirationTimeInMs = source.subscriptionExpirationTimeInMs;
|
||||||
|
subscriptionType = source.subscriptionType;
|
||||||
|
usageLimitDataLimit = source.usageLimitDataLimit;
|
||||||
|
usageLimitStartTimeInMs = source.usageLimitStartTimeInMs;
|
||||||
|
usageLimitTimeLimitInMinutes = source.usageLimitTimeLimitInMinutes;
|
||||||
|
usageLimitUsageTimePeriodInMinutes = source.usageLimitUsageTimePeriodInMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,6 +192,17 @@ public final class PasspointConfiguration implements Parcelable {
|
|||||||
dest.writeParcelable(homeSp, flags);
|
dest.writeParcelable(homeSp, flags);
|
||||||
dest.writeParcelable(credential, flags);
|
dest.writeParcelable(credential, flags);
|
||||||
dest.writeParcelable(policy, flags);
|
dest.writeParcelable(policy, flags);
|
||||||
|
dest.writeParcelable(subscriptionUpdate, flags);
|
||||||
|
writeTrustRootCerts(dest, trustRootCertList);
|
||||||
|
dest.writeInt(updateIdentifier);
|
||||||
|
dest.writeInt(credentialPriority);
|
||||||
|
dest.writeLong(subscriptionCreationTimeInMs);
|
||||||
|
dest.writeLong(subscriptionExpirationTimeInMs);
|
||||||
|
dest.writeString(subscriptionType);
|
||||||
|
dest.writeLong(usageLimitUsageTimePeriodInMinutes);
|
||||||
|
dest.writeLong(usageLimitStartTimeInMs);
|
||||||
|
dest.writeLong(usageLimitDataLimit);
|
||||||
|
dest.writeLong(usageLimitTimeLimitInMinutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,9 +215,21 @@ public final class PasspointConfiguration implements Parcelable {
|
|||||||
}
|
}
|
||||||
PasspointConfiguration that = (PasspointConfiguration) thatObject;
|
PasspointConfiguration that = (PasspointConfiguration) thatObject;
|
||||||
return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp))
|
return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp))
|
||||||
&& (credential == null ? that.credential == null :
|
&& (credential == null ? that.credential == null
|
||||||
credential.equals(that.credential))
|
: credential.equals(that.credential))
|
||||||
&& (policy == null) ? that.policy == null : policy.equals(that.policy);
|
&& (policy == null) ? that.policy == null : policy.equals(that.policy)
|
||||||
|
&& (subscriptionUpdate == null) ? that.subscriptionUpdate == null
|
||||||
|
: subscriptionUpdate.equals(that.subscriptionUpdate)
|
||||||
|
&& isTrustRootCertListEquals(trustRootCertList, that.trustRootCertList)
|
||||||
|
&& updateIdentifier == that.updateIdentifier
|
||||||
|
&& credentialPriority == that.credentialPriority
|
||||||
|
&& subscriptionCreationTimeInMs == that.subscriptionCreationTimeInMs
|
||||||
|
&& subscriptionExpirationTimeInMs == that.subscriptionExpirationTimeInMs
|
||||||
|
&& TextUtils.equals(subscriptionType, that.subscriptionType)
|
||||||
|
&& usageLimitUsageTimePeriodInMinutes == that.usageLimitUsageTimePeriodInMinutes
|
||||||
|
&& usageLimitStartTimeInMs == that.usageLimitStartTimeInMs
|
||||||
|
&& usageLimitDataLimit == that.usageLimitDataLimit
|
||||||
|
&& usageLimitTimeLimitInMinutes == that .usageLimitTimeLimitInMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,6 +247,34 @@ public final class PasspointConfiguration implements Parcelable {
|
|||||||
if (policy != null && !policy.validate()) {
|
if (policy != null && !policy.validate()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (subscriptionUpdate != null && !subscriptionUpdate.validate()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (trustRootCertList != null) {
|
||||||
|
for (Map.Entry<String, byte[]> entry : trustRootCertList.entrySet()) {
|
||||||
|
String url = entry.getKey();
|
||||||
|
byte[] certFingerprint = entry.getValue();
|
||||||
|
if (TextUtils.isEmpty(url)) {
|
||||||
|
Log.d(TAG, "Empty URL");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (url.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
|
||||||
|
Log.d(TAG, "URL bytes exceeded the max: "
|
||||||
|
+ url.getBytes(StandardCharsets.UTF_8).length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (certFingerprint == null) {
|
||||||
|
Log.d(TAG, "Fingerprint not specified");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (certFingerprint.length != CERTIFICATE_SHA256_BYTES) {
|
||||||
|
Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
|
||||||
|
+ certFingerprint.length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,11 +286,87 @@ public final class PasspointConfiguration implements Parcelable {
|
|||||||
config.homeSp = in.readParcelable(null);
|
config.homeSp = in.readParcelable(null);
|
||||||
config.credential = in.readParcelable(null);
|
config.credential = in.readParcelable(null);
|
||||||
config.policy = in.readParcelable(null);
|
config.policy = in.readParcelable(null);
|
||||||
|
config.subscriptionUpdate = in.readParcelable(null);
|
||||||
|
config.trustRootCertList = readTrustRootCerts(in);
|
||||||
|
config.updateIdentifier = in.readInt();
|
||||||
|
config.credentialPriority = in.readInt();
|
||||||
|
config.subscriptionCreationTimeInMs = in.readLong();
|
||||||
|
config.subscriptionExpirationTimeInMs = in.readLong();
|
||||||
|
config.subscriptionType = in.readString();
|
||||||
|
config.usageLimitUsageTimePeriodInMinutes = in.readLong();
|
||||||
|
config.usageLimitStartTimeInMs = in.readLong();
|
||||||
|
config.usageLimitDataLimit = in.readLong();
|
||||||
|
config.usageLimitTimeLimitInMinutes = in.readLong();
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PasspointConfiguration[] newArray(int size) {
|
public PasspointConfiguration[] newArray(int size) {
|
||||||
return new PasspointConfiguration[size];
|
return new PasspointConfiguration[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for reading trust root certificate info list from a Parcel.
|
||||||
|
*
|
||||||
|
* @param in The Parcel to read from
|
||||||
|
* @return The list of trust root certificate URL with the corresponding certificate
|
||||||
|
* fingerprint
|
||||||
|
*/
|
||||||
|
private Map<String, byte[]> readTrustRootCerts(Parcel in) {
|
||||||
|
int size = in.readInt();
|
||||||
|
if (size == NULL_VALUE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, byte[]> trustRootCerts = new HashMap<>(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
String key = in.readString();
|
||||||
|
byte[] value = in.createByteArray();
|
||||||
|
trustRootCerts.put(key, value);
|
||||||
|
}
|
||||||
|
return trustRootCerts;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for writing trust root certificate information list.
|
||||||
|
*
|
||||||
|
* @param dest The Parcel to write to
|
||||||
|
* @param trustRootCerts The list of trust root certificate URL with the corresponding
|
||||||
|
* certificate fingerprint
|
||||||
|
*/
|
||||||
|
private static void writeTrustRootCerts(Parcel dest, Map<String, byte[]> trustRootCerts) {
|
||||||
|
if (trustRootCerts == null) {
|
||||||
|
dest.writeInt(NULL_VALUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dest.writeInt(trustRootCerts.size());
|
||||||
|
for (Map.Entry<String, byte[]> entry : trustRootCerts.entrySet()) {
|
||||||
|
dest.writeString(entry.getKey());
|
||||||
|
dest.writeByteArray(entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for comparing two trust root certificate list. Cannot use Map#equals
|
||||||
|
* method since the value type (byte[]) doesn't override equals method.
|
||||||
|
*
|
||||||
|
* @param list1 The first trust root certificate list
|
||||||
|
* @param list2 The second trust root certificate list
|
||||||
|
* @return true if the two list are equal
|
||||||
|
*/
|
||||||
|
private static boolean isTrustRootCertListEquals(Map<String, byte[]> list1,
|
||||||
|
Map<String, byte[]> list2) {
|
||||||
|
if (list1 == null || list2 == null) {
|
||||||
|
return list1 == list2;
|
||||||
|
}
|
||||||
|
if (list1.size() != list2.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, byte[]> entry : list1.entrySet()) {
|
||||||
|
if (!Arrays.equals(entry.getValue(), list2.get(entry.getKey()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,20 @@ public final class PPSMOParser {
|
|||||||
*/
|
*/
|
||||||
private static final String NODE_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription";
|
private static final String NODE_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fields under PerProviderSubscription.
|
||||||
|
*/
|
||||||
|
private static final String NODE_UPDATE_IDENTIFIER = "UpdateIdentifier";
|
||||||
|
private static final String NODE_AAA_SERVER_TRUST_ROOT = "AAAServerTrustRoot";
|
||||||
|
private static final String NODE_SUBSCRIPTION_UPDATE = "SubscriptionUpdate";
|
||||||
|
private static final String NODE_SUBSCRIPTION_PARAMETER = "SubscriptionParameter";
|
||||||
|
private static final String NODE_TYPE_OF_SUBSCRIPTION = "TypeOfSubscription";
|
||||||
|
private static final String NODE_USAGE_LIMITS = "UsageLimits";
|
||||||
|
private static final String NODE_DATA_LIMIT = "DataLimit";
|
||||||
|
private static final String NODE_START_DATE = "StartDate";
|
||||||
|
private static final String NODE_TIME_LIMIT = "TimeLimit";
|
||||||
|
private static final String NODE_USAGE_TIME_PERIOD = "UsageTimePeriod";
|
||||||
|
private static final String NODE_CREDENTIAL_PRIORITY = "CredentialPriority";
|
||||||
/**
|
/**
|
||||||
* Fields under HomeSP subtree.
|
* Fields under HomeSP subtree.
|
||||||
*/
|
*/
|
||||||
@@ -378,6 +392,10 @@ public final class PPSMOParser {
|
|||||||
* ...
|
* ...
|
||||||
* </RTPProperties>
|
* </RTPProperties>
|
||||||
* <Node>
|
* <Node>
|
||||||
|
* <NodeName>UpdateIdentifier</NodeName>
|
||||||
|
* <Value>...</Value>
|
||||||
|
* </Node>
|
||||||
|
* <Node>
|
||||||
* ...
|
* ...
|
||||||
* </Node>
|
* </Node>
|
||||||
* </Node>
|
* </Node>
|
||||||
@@ -390,11 +408,12 @@ public final class PPSMOParser {
|
|||||||
throws ParsingException {
|
throws ParsingException {
|
||||||
PasspointConfiguration config = null;
|
PasspointConfiguration config = null;
|
||||||
String nodeName = null;
|
String nodeName = null;
|
||||||
|
int updateIdentifier = Integer.MIN_VALUE;
|
||||||
for (XMLNode child : node.getChildren()) {
|
for (XMLNode child : node.getChildren()) {
|
||||||
switch (child.getTag()) {
|
switch (child.getTag()) {
|
||||||
case TAG_NODE_NAME:
|
case TAG_NODE_NAME:
|
||||||
if (nodeName != null) {
|
if (nodeName != null) {
|
||||||
throw new ParsingException("Duplicant NodeName: " + child.getText());
|
throw new ParsingException("Duplicate NodeName: " + child.getText());
|
||||||
}
|
}
|
||||||
nodeName = child.getText();
|
nodeName = child.getText();
|
||||||
if (!TextUtils.equals(nodeName, NODE_PER_PROVIDER_SUBSCRIPTION)) {
|
if (!TextUtils.equals(nodeName, NODE_PER_PROVIDER_SUBSCRIPTION)) {
|
||||||
@@ -402,13 +421,22 @@ public final class PPSMOParser {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TAG_NODE:
|
case TAG_NODE:
|
||||||
// Only one PerProviderSubscription instance is expected and allowed.
|
// A node can be either an UpdateIdentifier node or a PerProviderSubscription
|
||||||
if (config != null) {
|
// instance node. Flatten out the XML tree first by converting it to a PPS
|
||||||
throw new ParsingException("Multiple PPS instance");
|
// tree to reduce the complexity of the parsing code.
|
||||||
|
PPSNode ppsNodeRoot = buildPpsNode(child);
|
||||||
|
if (TextUtils.equals(ppsNodeRoot.getName(), NODE_UPDATE_IDENTIFIER)) {
|
||||||
|
if (updateIdentifier != Integer.MIN_VALUE) {
|
||||||
|
throw new ParsingException("Multiple node for UpdateIdentifier");
|
||||||
|
}
|
||||||
|
updateIdentifier = parseInteger(getPpsNodeValue(ppsNodeRoot));
|
||||||
|
} else {
|
||||||
|
// Only one PerProviderSubscription instance is expected and allowed.
|
||||||
|
if (config != null) {
|
||||||
|
throw new ParsingException("Multiple PPS instance");
|
||||||
|
}
|
||||||
|
config = parsePpsInstance(ppsNodeRoot);
|
||||||
}
|
}
|
||||||
// Convert the XML tree to a PPS tree.
|
|
||||||
PPSNode ppsInstanceRoot = buildPpsNode(child);
|
|
||||||
config = parsePpsInstance(ppsInstanceRoot);
|
|
||||||
break;
|
break;
|
||||||
case TAG_RT_PROPERTIES:
|
case TAG_RT_PROPERTIES:
|
||||||
// Parse and verify URN stored in the RT (Run Time) Properties.
|
// Parse and verify URN stored in the RT (Run Time) Properties.
|
||||||
@@ -421,6 +449,9 @@ public final class PPSMOParser {
|
|||||||
throw new ParsingException("Unknown tag under PPS node: " + child.getTag());
|
throw new ParsingException("Unknown tag under PPS node: " + child.getTag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (config != null && updateIdentifier != Integer.MIN_VALUE) {
|
||||||
|
config.updateIdentifier = updateIdentifier;
|
||||||
|
}
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,6 +614,18 @@ public final class PPSMOParser {
|
|||||||
case NODE_POLICY:
|
case NODE_POLICY:
|
||||||
config.policy = parsePolicy(child);
|
config.policy = parsePolicy(child);
|
||||||
break;
|
break;
|
||||||
|
case NODE_AAA_SERVER_TRUST_ROOT:
|
||||||
|
config.trustRootCertList = parseAAAServerTrustRootList(child);
|
||||||
|
break;
|
||||||
|
case NODE_SUBSCRIPTION_UPDATE:
|
||||||
|
config.subscriptionUpdate = parseUpdateParameter(child);
|
||||||
|
break;
|
||||||
|
case NODE_SUBSCRIPTION_PARAMETER:
|
||||||
|
parseSubscriptionParameter(child, config);
|
||||||
|
break;
|
||||||
|
case NODE_CREDENTIAL_PRIORITY:
|
||||||
|
config.credentialPriority = parseInteger(getPpsNodeValue(child));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ParsingException("Unknown node: " + child.getName());
|
throw new ParsingException("Unknown node: " + child.getName());
|
||||||
}
|
}
|
||||||
@@ -648,11 +691,7 @@ public final class PPSMOParser {
|
|||||||
String[] oiStrArray = oiStr.split(",");
|
String[] oiStrArray = oiStr.split(",");
|
||||||
long[] oiArray = new long[oiStrArray.length];
|
long[] oiArray = new long[oiStrArray.length];
|
||||||
for (int i = 0; i < oiStrArray.length; i++) {
|
for (int i = 0; i < oiStrArray.length; i++) {
|
||||||
try {
|
oiArray[i] = parseLong(oiStrArray[i], 16);
|
||||||
oiArray[i] = Long.parseLong(oiStrArray[i], 16);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new ParsingException("Invalid OI: " + oiStrArray[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return oiArray;
|
return oiArray;
|
||||||
}
|
}
|
||||||
@@ -703,11 +742,7 @@ public final class PPSMOParser {
|
|||||||
ssid = getPpsNodeValue(child);
|
ssid = getPpsNodeValue(child);
|
||||||
break;
|
break;
|
||||||
case NODE_HESSID:
|
case NODE_HESSID:
|
||||||
try {
|
hessid = parseLong(getPpsNodeValue(child), 16);
|
||||||
hessid = Long.parseLong(getPpsNodeValue(child), 16);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new ParsingException("Invalid HESSID: " + getPpsNodeValue(child));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ParsingException("Unknown node under NetworkID instance: " +
|
throw new ParsingException("Unknown node under NetworkID instance: " +
|
||||||
@@ -1184,20 +1219,10 @@ public final class PPSMOParser {
|
|||||||
networkType = getPpsNodeValue(child);
|
networkType = getPpsNodeValue(child);
|
||||||
break;
|
break;
|
||||||
case NODE_DOWNLINK_BANDWIDTH:
|
case NODE_DOWNLINK_BANDWIDTH:
|
||||||
try {
|
downlinkBandwidth = parseLong(getPpsNodeValue(child), 10);
|
||||||
downlinkBandwidth = Long.parseLong(getPpsNodeValue(child));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new ParsingException("Invalid value for downlink bandwidth: "
|
|
||||||
+ getPpsNodeValue(child));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case NODE_UPLINK_BANDWIDTH:
|
case NODE_UPLINK_BANDWIDTH:
|
||||||
try {
|
uplinkBandwidth = parseLong(getPpsNodeValue(child), 10);
|
||||||
uplinkBandwidth = Long.parseLong(getPpsNodeValue(child));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new ParsingException("Invalid value for downlink bandwidth: "
|
|
||||||
+ getPpsNodeValue(child));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ParsingException("Unknown node under MinBackhaulThreshold instance "
|
throw new ParsingException("Unknown node under MinBackhaulThreshold instance "
|
||||||
@@ -1239,13 +1264,7 @@ public final class PPSMOParser {
|
|||||||
for (PPSNode child : node.getChildren()) {
|
for (PPSNode child : node.getChildren()) {
|
||||||
switch(child.getName()) {
|
switch(child.getName()) {
|
||||||
case NODE_UPDATE_INTERVAL:
|
case NODE_UPDATE_INTERVAL:
|
||||||
try {
|
updateParam.updateIntervalInMinutes = parseLong(getPpsNodeValue(child), 10);
|
||||||
updateParam.updateIntervalInMinutes =
|
|
||||||
Long.parseLong(getPpsNodeValue(child));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new ParsingException("Invalid value for update interval: "
|
|
||||||
+ getPpsNodeValue(child));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case NODE_UPDATE_METHOD:
|
case NODE_UPDATE_METHOD:
|
||||||
updateParam.updateMethod = getPpsNodeValue(child);
|
updateParam.updateMethod = getPpsNodeValue(child);
|
||||||
@@ -1262,7 +1281,7 @@ public final class PPSMOParser {
|
|||||||
updateParam.base64EncodedPassword = usernamePassword.second;
|
updateParam.base64EncodedPassword = usernamePassword.second;
|
||||||
break;
|
break;
|
||||||
case NODE_TRUST_ROOT:
|
case NODE_TRUST_ROOT:
|
||||||
Pair<String, byte[]> trustRoot = parseUpdateTrustRoot(child);
|
Pair<String, byte[]> trustRoot = parseTrustRoot(child);
|
||||||
updateParam.trustRootCertUrl = trustRoot.first;
|
updateParam.trustRootCertUrl = trustRoot.first;
|
||||||
updateParam.trustRootCertSha256Fingerprint = trustRoot.second;
|
updateParam.trustRootCertSha256Fingerprint = trustRoot.second;
|
||||||
break;
|
break;
|
||||||
@@ -1312,16 +1331,19 @@ public final class PPSMOParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the trust root parameters associated with policy or subscription update.
|
* Parse the trust root parameters associated with policy update, subscription update, or AAA
|
||||||
|
* server trust root.
|
||||||
|
*
|
||||||
* This contained configurations under either
|
* This contained configurations under either
|
||||||
* PerProviderSubscription/Policy/PolicyUpdate/TrustRoot or
|
* PerProviderSubscription/Policy/PolicyUpdate/TrustRoot or
|
||||||
* PerProviderSubscription/SubscriptionUpdate/TrustRoot subtree.
|
* PerProviderSubscription/SubscriptionUpdate/TrustRoot or
|
||||||
|
* PerProviderSubscription/AAAServerTrustRoot/<X+> subtree.
|
||||||
*
|
*
|
||||||
* @param node PPSNode representing the root of the TrustRoot subtree
|
* @param node PPSNode representing the root of the TrustRoot subtree
|
||||||
* @return Pair of Certificate URL and fingerprint
|
* @return Pair of Certificate URL and fingerprint
|
||||||
* @throws ParsingException
|
* @throws ParsingException
|
||||||
*/
|
*/
|
||||||
private static Pair<String, byte[]> parseUpdateTrustRoot(PPSNode node)
|
private static Pair<String, byte[]> parseTrustRoot(PPSNode node)
|
||||||
throws ParsingException {
|
throws ParsingException {
|
||||||
if (node.isLeaf()) {
|
if (node.isLeaf()) {
|
||||||
throw new ParsingException("Leaf node not expected for TrustRoot");
|
throw new ParsingException("Leaf node not expected for TrustRoot");
|
||||||
@@ -1449,6 +1471,97 @@ public final class PPSMOParser {
|
|||||||
return Pair.create(proto, ports);
|
return Pair.create(proto, ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse configurations under PerProviderSubscription/AAAServerTrustRoot subtree.
|
||||||
|
*
|
||||||
|
* @param node PPSNode representing the root of PerProviderSubscription/AAAServerTrustRoot
|
||||||
|
* subtree
|
||||||
|
* @return Map of certificate URL with the corresponding certificate fingerprint
|
||||||
|
* @throws ParsingException
|
||||||
|
*/
|
||||||
|
private static Map<String, byte[]> parseAAAServerTrustRootList(PPSNode node)
|
||||||
|
throws ParsingException {
|
||||||
|
if (node.isLeaf()) {
|
||||||
|
throw new ParsingException("Leaf node not expected for AAAServerTrustRoot");
|
||||||
|
}
|
||||||
|
Map<String, byte[]> certList = new HashMap<>();
|
||||||
|
for (PPSNode child : node.getChildren()) {
|
||||||
|
Pair<String, byte[]> certTuple = parseTrustRoot(child);
|
||||||
|
certList.put(certTuple.first, certTuple.second);
|
||||||
|
}
|
||||||
|
return certList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse configurations under PerProviderSubscription/SubscriptionParameter subtree.
|
||||||
|
*
|
||||||
|
* @param node PPSNode representing the root of PerProviderSubscription/SubscriptionParameter
|
||||||
|
* subtree
|
||||||
|
* @param config Instance of {@link PasspointConfiguration}
|
||||||
|
* @throws ParsingException
|
||||||
|
*/
|
||||||
|
private static void parseSubscriptionParameter(PPSNode node, PasspointConfiguration config)
|
||||||
|
throws ParsingException {
|
||||||
|
if (node.isLeaf()) {
|
||||||
|
throw new ParsingException("Leaf node not expected for SubscriptionParameter");
|
||||||
|
}
|
||||||
|
for (PPSNode child : node.getChildren()) {
|
||||||
|
switch (child.getName()) {
|
||||||
|
case NODE_CREATION_DATE:
|
||||||
|
config.subscriptionCreationTimeInMs = parseDate(getPpsNodeValue(child));
|
||||||
|
break;
|
||||||
|
case NODE_EXPIRATION_DATE:
|
||||||
|
config.subscriptionExpirationTimeInMs = parseDate(getPpsNodeValue(child));
|
||||||
|
break;
|
||||||
|
case NODE_TYPE_OF_SUBSCRIPTION:
|
||||||
|
config.subscriptionType = getPpsNodeValue(child);
|
||||||
|
break;
|
||||||
|
case NODE_USAGE_LIMITS:
|
||||||
|
parseUsageLimits(child, config);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParsingException("Unknown node under SubscriptionParameter"
|
||||||
|
+ child.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse configurations under PerProviderSubscription/SubscriptionParameter/UsageLimits
|
||||||
|
* subtree.
|
||||||
|
*
|
||||||
|
* @param node PPSNode representing the root of
|
||||||
|
* PerProviderSubscription/SubscriptionParameter/UsageLimits subtree
|
||||||
|
* @param config Instance of {@link PasspointConfiguration}
|
||||||
|
* @throws ParsingException
|
||||||
|
*/
|
||||||
|
private static void parseUsageLimits(PPSNode node, PasspointConfiguration config)
|
||||||
|
throws ParsingException {
|
||||||
|
if (node.isLeaf()) {
|
||||||
|
throw new ParsingException("Leaf node not expected for UsageLimits");
|
||||||
|
}
|
||||||
|
for (PPSNode child : node.getChildren()) {
|
||||||
|
switch (child.getName()) {
|
||||||
|
case NODE_DATA_LIMIT:
|
||||||
|
config.usageLimitDataLimit = parseLong(getPpsNodeValue(child), 10);
|
||||||
|
break;
|
||||||
|
case NODE_START_DATE:
|
||||||
|
config.usageLimitStartTimeInMs = parseDate(getPpsNodeValue(child));
|
||||||
|
break;
|
||||||
|
case NODE_TIME_LIMIT:
|
||||||
|
config.usageLimitTimeLimitInMinutes = parseLong(getPpsNodeValue(child), 10);
|
||||||
|
break;
|
||||||
|
case NODE_USAGE_TIME_PERIOD:
|
||||||
|
config.usageLimitUsageTimePeriodInMinutes =
|
||||||
|
parseLong(getPpsNodeValue(child), 10);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParsingException("Unknown node under UsageLimits"
|
||||||
|
+ child.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a hex string to a byte array.
|
* Convert a hex string to a byte array.
|
||||||
*
|
*
|
||||||
@@ -1504,6 +1617,21 @@ public final class PPSMOParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a string representing a long integer.
|
||||||
|
*
|
||||||
|
* @param value String of long integer value
|
||||||
|
* @return long
|
||||||
|
* @throws ParsingException
|
||||||
|
*/
|
||||||
|
private static long parseLong(String value, int radix) throws ParsingException {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(value, radix);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new ParsingException("Invalid long integer value: " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a List<Long> to a primitive long array long[].
|
* Convert a List<Long> to a primitive long array long[].
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
<DDFName>urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0</DDFName>
|
<DDFName>urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0</DDFName>
|
||||||
</Type>
|
</Type>
|
||||||
</RTProperties>
|
</RTProperties>
|
||||||
|
<Node>
|
||||||
|
<NodeName>UpdateIdentifier</NodeName>
|
||||||
|
<Value>12</Value>
|
||||||
|
</Node>
|
||||||
<Node>
|
<Node>
|
||||||
<NodeName>i001</NodeName>
|
<NodeName>i001</NodeName>
|
||||||
<Node>
|
<Node>
|
||||||
@@ -297,6 +301,99 @@
|
|||||||
<Value>23</Value>
|
<Value>23</Value>
|
||||||
</Node>
|
</Node>
|
||||||
</Node>
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>CredentialPriority</NodeName>
|
||||||
|
<Value>99</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>AAAServerTrustRoot</NodeName>
|
||||||
|
<Node>
|
||||||
|
<NodeName>a001</NodeName>
|
||||||
|
<Node>
|
||||||
|
<NodeName>CertURL</NodeName>
|
||||||
|
<Value>server1.trust.root.com</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>CertSHA256Fingerprint</NodeName>
|
||||||
|
<Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
|
||||||
|
</Node>
|
||||||
|
</Node>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>SubscriptionUpdate</NodeName>
|
||||||
|
<Node>
|
||||||
|
<NodeName>UpdateInterval</NodeName>
|
||||||
|
<Value>120</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>UpdateMethod</NodeName>
|
||||||
|
<Value>SSP-ClientInitiated</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>Restriction</NodeName>
|
||||||
|
<Value>RoamingPartner</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>URI</NodeName>
|
||||||
|
<Value>subscription.update.com</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>UsernamePassword</NodeName>
|
||||||
|
<Node>
|
||||||
|
<NodeName>Username</NodeName>
|
||||||
|
<Value>subscriptionUser</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>Password</NodeName>
|
||||||
|
<Value>subscriptionPass</Value>
|
||||||
|
</Node>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>TrustRoot</NodeName>
|
||||||
|
<Node>
|
||||||
|
<NodeName>CertURL</NodeName>
|
||||||
|
<Value>subscription.update.cert.com</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>CertSHA256Fingerprint</NodeName>
|
||||||
|
<Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
|
||||||
|
</Node>
|
||||||
|
</Node>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>SubscriptionParameter</NodeName>
|
||||||
|
<Node>
|
||||||
|
<NodeName>CreationDate</NodeName>
|
||||||
|
<Value>2016-02-01T10:00:00Z</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>ExpirationDate</NodeName>
|
||||||
|
<Value>2016-03-01T10:00:00Z</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>TypeOfSubscription</NodeName>
|
||||||
|
<Value>Gold</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>UsageLimits</NodeName>
|
||||||
|
<Node>
|
||||||
|
<NodeName>DataLimit</NodeName>
|
||||||
|
<Value>921890</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>StartDate</NodeName>
|
||||||
|
<Value>2016-12-01T10:00:00Z</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>TimeLimit</NodeName>
|
||||||
|
<Value>120</Value>
|
||||||
|
</Node>
|
||||||
|
<Node>
|
||||||
|
<NodeName>UsageTimePeriod</NodeName>
|
||||||
|
<Value>99910</Value>
|
||||||
|
</Node>
|
||||||
|
</Node>
|
||||||
|
</Node>
|
||||||
</Node>
|
</Node>
|
||||||
</Node>
|
</Node>
|
||||||
</MgmtTree>
|
</MgmtTree>
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ import android.util.Base64;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,6 +40,8 @@ import java.util.HashMap;
|
|||||||
*/
|
*/
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public class PasspointConfigurationTest {
|
public class PasspointConfigurationTest {
|
||||||
|
private static final int MAX_URL_BYTES = 1023;
|
||||||
|
private static final int CERTIFICATE_FINGERPRINT_BYTES = 32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
|
* Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
|
||||||
@@ -111,11 +115,25 @@ public class PasspointConfigurationTest {
|
|||||||
policy.policyUpdate.base64EncodedPassword =
|
policy.policyUpdate.base64EncodedPassword =
|
||||||
Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
|
Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
|
||||||
policy.policyUpdate.trustRootCertUrl = "trust.cert.com";
|
policy.policyUpdate.trustRootCertUrl = "trust.cert.com";
|
||||||
policy.policyUpdate.trustRootCertSha256Fingerprint = new byte[32];
|
policy.policyUpdate.trustRootCertSha256Fingerprint =
|
||||||
|
new byte[CERTIFICATE_FINGERPRINT_BYTES];
|
||||||
|
|
||||||
return policy;
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static UpdateParameter createSubscriptionUpdate() {
|
||||||
|
UpdateParameter subUpdate = new UpdateParameter();
|
||||||
|
subUpdate.updateIntervalInMinutes = 9021;
|
||||||
|
subUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_SSP;
|
||||||
|
subUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER;
|
||||||
|
subUpdate.serverUri = "subscription.update.com";
|
||||||
|
subUpdate.username = "subUsername";
|
||||||
|
subUpdate.base64EncodedPassword =
|
||||||
|
Base64.encodeToString("subPassword".getBytes(), Base64.DEFAULT);
|
||||||
|
subUpdate.trustRootCertUrl = "subscription.trust.cert.com";
|
||||||
|
subUpdate.trustRootCertSha256Fingerprint = new byte[CERTIFICATE_FINGERPRINT_BYTES];
|
||||||
|
return subUpdate;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Helper function for creating a {@link PasspointConfiguration} for testing.
|
* Helper function for creating a {@link PasspointConfiguration} for testing.
|
||||||
*
|
*
|
||||||
@@ -126,6 +144,21 @@ public class PasspointConfigurationTest {
|
|||||||
config.homeSp = createHomeSp();
|
config.homeSp = createHomeSp();
|
||||||
config.credential = createCredential();
|
config.credential = createCredential();
|
||||||
config.policy = createPolicy();
|
config.policy = createPolicy();
|
||||||
|
config.subscriptionUpdate = createSubscriptionUpdate();
|
||||||
|
config.trustRootCertList = new HashMap<>();
|
||||||
|
config.trustRootCertList.put("trustRoot.cert1.com",
|
||||||
|
new byte[CERTIFICATE_FINGERPRINT_BYTES]);
|
||||||
|
config.trustRootCertList.put("trustRoot.cert2.com",
|
||||||
|
new byte[CERTIFICATE_FINGERPRINT_BYTES]);
|
||||||
|
config.updateIdentifier = 1;
|
||||||
|
config.credentialPriority = 120;
|
||||||
|
config.subscriptionCreationTimeInMs = 231200;
|
||||||
|
config.subscriptionExpirationTimeInMs = 2134232;
|
||||||
|
config.subscriptionType = "Gold";
|
||||||
|
config.usageLimitUsageTimePeriodInMinutes = 3600;
|
||||||
|
config.usageLimitStartTimeInMs = 124214213;
|
||||||
|
config.usageLimitDataLimit = 14121;
|
||||||
|
config.usageLimitTimeLimitInMinutes = 78912;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +234,31 @@ public class PasspointConfigurationTest {
|
|||||||
verifyParcel(config);
|
verifyParcel(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify parcel read/write for a configuration that doesn't contain subscription update.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void verifyParcelWithoutSubscriptionUpdate() throws Exception {
|
||||||
|
PasspointConfiguration config = createConfig();
|
||||||
|
config.subscriptionUpdate = null;
|
||||||
|
verifyParcel(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify parcel read/write for a configuration that doesn't contain trust root certificate
|
||||||
|
* list.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void verifyParcelWithoutTrustRootCertList() throws Exception {
|
||||||
|
PasspointConfiguration config = createConfig();
|
||||||
|
config.trustRootCertList = null;
|
||||||
|
verifyParcel(config);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that a default/empty configuration is invalid.
|
* Verify that a default/empty configuration is invalid.
|
||||||
*
|
*
|
||||||
@@ -260,6 +318,60 @@ public class PasspointConfigurationTest {
|
|||||||
assertTrue(config.validate());
|
assertTrue(config.validate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a configuration without subscription update is valid, since subscription
|
||||||
|
* update configurations are optional (applied for Hotspot 2.0 Release only).
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void validateConfigWithoutSubscriptionUpdate() throws Exception {
|
||||||
|
PasspointConfiguration config = createConfig();
|
||||||
|
config.subscriptionUpdate = null;
|
||||||
|
assertTrue(config.validate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a configuration with a trust root certificate URL exceeding the max size
|
||||||
|
* is invalid.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void validateConfigWithInvalidTrustRootCertUrl() throws Exception {
|
||||||
|
PasspointConfiguration config = createConfig();
|
||||||
|
byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
|
||||||
|
Arrays.fill(rawUrlBytes, (byte) 'a');
|
||||||
|
config.trustRootCertList.put(new String(rawUrlBytes, StandardCharsets.UTF_8),
|
||||||
|
new byte[CERTIFICATE_FINGERPRINT_BYTES]);
|
||||||
|
assertFalse(config.validate());
|
||||||
|
|
||||||
|
config.trustRootCertList = new HashMap<>();
|
||||||
|
config.trustRootCertList.put(null, new byte[CERTIFICATE_FINGERPRINT_BYTES]);
|
||||||
|
assertFalse(config.validate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a configuration with an invalid trust root certificate fingerprint is invalid.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void validateConfigWithInvalidTrustRootCertFingerprint() throws Exception {
|
||||||
|
PasspointConfiguration config = createConfig();
|
||||||
|
config.trustRootCertList = new HashMap<>();
|
||||||
|
config.trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES + 1]);
|
||||||
|
assertFalse(config.validate());
|
||||||
|
|
||||||
|
config.trustRootCertList = new HashMap<>();
|
||||||
|
config.trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES - 1]);
|
||||||
|
assertFalse(config.validate());
|
||||||
|
|
||||||
|
config.trustRootCertList = new HashMap<>();
|
||||||
|
config.trustRootCertList.put("test.cert.com", null);
|
||||||
|
assertFalse(config.validate());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that copy constructor works when pass in a null source.
|
* Verify that copy constructor works when pass in a null source.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -85,7 +85,38 @@ public class PPSMOParserTest {
|
|||||||
* @return {@link PasspointConfiguration}
|
* @return {@link PasspointConfiguration}
|
||||||
*/
|
*/
|
||||||
private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception {
|
private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception {
|
||||||
|
DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||||
|
|
||||||
PasspointConfiguration config = new PasspointConfiguration();
|
PasspointConfiguration config = new PasspointConfiguration();
|
||||||
|
config.updateIdentifier = 12;
|
||||||
|
config.credentialPriority = 99;
|
||||||
|
|
||||||
|
// AAA Server trust root.
|
||||||
|
config.trustRootCertList = new HashMap<>();
|
||||||
|
byte[] certFingerprint = new byte[32];
|
||||||
|
Arrays.fill(certFingerprint, (byte) 0x1f);
|
||||||
|
config.trustRootCertList.put("server1.trust.root.com", certFingerprint);
|
||||||
|
|
||||||
|
// Subscription update.
|
||||||
|
config.subscriptionUpdate = new UpdateParameter();
|
||||||
|
config.subscriptionUpdate.updateIntervalInMinutes = 120;
|
||||||
|
config.subscriptionUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_SSP;
|
||||||
|
config.subscriptionUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER;
|
||||||
|
config.subscriptionUpdate.serverUri = "subscription.update.com";
|
||||||
|
config.subscriptionUpdate.username = "subscriptionUser";
|
||||||
|
config.subscriptionUpdate.base64EncodedPassword = "subscriptionPass";
|
||||||
|
config.subscriptionUpdate.trustRootCertUrl = "subscription.update.cert.com";
|
||||||
|
config.subscriptionUpdate.trustRootCertSha256Fingerprint = new byte[32];
|
||||||
|
Arrays.fill(config.subscriptionUpdate.trustRootCertSha256Fingerprint, (byte) 0x1f);
|
||||||
|
|
||||||
|
// Subscription parameters.
|
||||||
|
config.subscriptionCreationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime();
|
||||||
|
config.subscriptionExpirationTimeInMs = format.parse("2016-03-01T10:00:00Z").getTime();
|
||||||
|
config.subscriptionType = "Gold";
|
||||||
|
config.usageLimitDataLimit = 921890;
|
||||||
|
config.usageLimitStartTimeInMs = format.parse("2016-12-01T10:00:00Z").getTime();
|
||||||
|
config.usageLimitTimeLimitInMinutes = 120;
|
||||||
|
config.usageLimitUsageTimePeriodInMinutes = 99910;
|
||||||
|
|
||||||
// HomeSP configuration.
|
// HomeSP configuration.
|
||||||
config.homeSp = new HomeSP();
|
config.homeSp = new HomeSP();
|
||||||
@@ -101,7 +132,6 @@ public class PPSMOParserTest {
|
|||||||
config.homeSp.otherHomePartners = new String[] {"other.fqdn.com"};
|
config.homeSp.otherHomePartners = new String[] {"other.fqdn.com"};
|
||||||
|
|
||||||
// Credential configuration.
|
// Credential configuration.
|
||||||
DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
|
||||||
config.credential = new Credential();
|
config.credential = new Credential();
|
||||||
config.credential.creationTimeInMs = format.parse("2016-01-01T10:00:00Z").getTime();
|
config.credential.creationTimeInMs = format.parse("2016-01-01T10:00:00Z").getTime();
|
||||||
config.credential.expirationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime();
|
config.credential.expirationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime();
|
||||||
@@ -161,8 +191,7 @@ public class PPSMOParserTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse and verify all supported fields under PPS MO tree (currently only fields under
|
* Parse and verify all supported fields under PPS MO tree.
|
||||||
* HomeSP and Credential subtree).
|
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user