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