• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2017, 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.pps;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 import android.text.TextUtils;
22 import android.util.Base64;
23 import android.util.Log;
24 
25 import java.nio.charset.StandardCharsets;
26 import java.util.Arrays;
27 import java.util.Objects;
28 
29 /**
30  * Class representing configuration parameters for subscription or policy update in
31  * PerProviderSubscription (PPS) Management Object (MO) tree.  This is used by both
32  * PerProviderSubscription/Policy/PolicyUpdate and PerProviderSubscription/SubscriptionUpdate
33  * subtree.
34  *
35  * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
36  * Release 2 Technical Specification.
37  *
38  * @hide
39  */
40 public final class UpdateParameter implements Parcelable {
41     private static final String TAG = "UpdateParameter";
42 
43     /**
44      * Value indicating policy update is not applicable.  Thus, never check with policy server
45      * for updates.
46      */
47     public static final long UPDATE_CHECK_INTERVAL_NEVER = 0xFFFFFFFFL;
48 
49     /**
50      * Valid string for UpdateMethod.
51      */
52     public static final String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
53     public static final String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
54 
55     /**
56      * Valid string for Restriction.
57      */
58     public static final String UPDATE_RESTRICTION_HOMESP = "HomeSP";
59     public static final String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
60     public static final String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
61 
62     /**
63      * Maximum bytes for URI string.
64      */
65     private static final int MAX_URI_BYTES = 1023;
66 
67     /**
68      * Maximum bytes for URI string.
69      */
70     private static final int MAX_URL_BYTES = 1023;
71 
72     /**
73      * Maximum bytes for username.
74      */
75     private static final int MAX_USERNAME_BYTES = 63;
76 
77     /**
78      * Maximum bytes for password.
79      */
80     private static final int MAX_PASSWORD_BYTES = 255;
81 
82     /**
83      * Number of bytes for certificate SHA-256 fingerprint byte array.
84      */
85     private static final int CERTIFICATE_SHA256_BYTES = 32;
86 
87     /**
88      * This specifies how often the mobile device shall check with policy server for updates.
89      *
90      * Using Long.MIN_VALUE to indicate unset value.
91      */
92     private long mUpdateIntervalInMinutes = Long.MIN_VALUE;
setUpdateIntervalInMinutes(long updateIntervalInMinutes)93     public void setUpdateIntervalInMinutes(long updateIntervalInMinutes) {
94         mUpdateIntervalInMinutes = updateIntervalInMinutes;
95     }
getUpdateIntervalInMinutes()96     public long getUpdateIntervalInMinutes() {
97         return mUpdateIntervalInMinutes;
98     }
99 
100     /**
101      * The method used to update the policy.  Permitted values are "OMA-DM-ClientInitiated"
102      * and "SPP-ClientInitiated".
103      */
104     private String mUpdateMethod = null;
setUpdateMethod(String updateMethod)105     public void setUpdateMethod(String updateMethod) {
106         mUpdateMethod = updateMethod;
107     }
getUpdateMethod()108     public String getUpdateMethod() {
109         return mUpdateMethod;
110     }
111 
112     /**
113      * This specifies the hotspots at which the subscription update is permitted.  Permitted
114      * values are "HomeSP", "RoamingPartner", or "Unrestricted";
115      */
116     private String mRestriction = null;
setRestriction(String restriction)117     public void setRestriction(String restriction) {
118         mRestriction = restriction;
119     }
getRestriction()120     public String getRestriction() {
121         return mRestriction;
122     }
123 
124     /**
125      * The URI of the update server.
126      */
127     private String mServerUri = null;
setServerUri(String serverUri)128     public void setServerUri(String serverUri) {
129         mServerUri = serverUri;
130     }
getServerUri()131     public String getServerUri() {
132         return mServerUri;
133     }
134 
135     /**
136      * Username used to authenticate with the policy server.
137      */
138     private String mUsername = null;
setUsername(String username)139     public void setUsername(String username) {
140         mUsername = username;
141     }
getUsername()142     public String getUsername() {
143         return mUsername;
144     }
145 
146     /**
147      * Base64 encoded password used to authenticate with the policy server.
148      */
149     private String mBase64EncodedPassword = null;
setBase64EncodedPassword(String password)150     public void setBase64EncodedPassword(String password) {
151         mBase64EncodedPassword = password;
152     }
getBase64EncodedPassword()153     public String getBase64EncodedPassword() {
154         return mBase64EncodedPassword;
155     }
156 
157     /**
158      * HTTPS URL for retrieving certificate for trust root.  The trust root is used to validate
159      * policy server's identity.
160      */
161     private String mTrustRootCertUrl = null;
setTrustRootCertUrl(String trustRootCertUrl)162     public void setTrustRootCertUrl(String trustRootCertUrl) {
163         mTrustRootCertUrl = trustRootCertUrl;
164     }
getTrustRootCertUrl()165     public String getTrustRootCertUrl() {
166         return mTrustRootCertUrl;
167     }
168 
169     /**
170      * SHA-256 fingerprint of the certificate located at {@link #trustRootCertUrl}
171      */
172     private byte[] mTrustRootCertSha256Fingerprint = null;
setTrustRootCertSha256Fingerprint(byte[] fingerprint)173     public void setTrustRootCertSha256Fingerprint(byte[] fingerprint) {
174         mTrustRootCertSha256Fingerprint = fingerprint;
175     }
getTrustRootCertSha256Fingerprint()176     public byte[] getTrustRootCertSha256Fingerprint() {
177         return mTrustRootCertSha256Fingerprint;
178     }
179 
180     /**
181      * Constructor for creating Policy with default values.
182      */
UpdateParameter()183     public UpdateParameter() {}
184 
185     /**
186      * Copy constructor.
187      *
188      * @param source The source to copy from
189      */
UpdateParameter(UpdateParameter source)190     public UpdateParameter(UpdateParameter source) {
191         if (source == null) {
192             return;
193         }
194         mUpdateIntervalInMinutes = source.mUpdateIntervalInMinutes;
195         mUpdateMethod = source.mUpdateMethod;
196         mRestriction = source.mRestriction;
197         mServerUri = source.mServerUri;
198         mUsername = source.mUsername;
199         mBase64EncodedPassword = source.mBase64EncodedPassword;
200         mTrustRootCertUrl = source.mTrustRootCertUrl;
201         if (source.mTrustRootCertSha256Fingerprint != null) {
202             mTrustRootCertSha256Fingerprint = Arrays.copyOf(source.mTrustRootCertSha256Fingerprint,
203                     source.mTrustRootCertSha256Fingerprint.length);
204         }
205     }
206 
207     @Override
describeContents()208     public int describeContents() {
209         return 0;
210     }
211 
212     @Override
writeToParcel(Parcel dest, int flags)213     public void writeToParcel(Parcel dest, int flags) {
214         dest.writeLong(mUpdateIntervalInMinutes);
215         dest.writeString(mUpdateMethod);
216         dest.writeString(mRestriction);
217         dest.writeString(mServerUri);
218         dest.writeString(mUsername);
219         dest.writeString(mBase64EncodedPassword);
220         dest.writeString(mTrustRootCertUrl);
221         dest.writeByteArray(mTrustRootCertSha256Fingerprint);
222     }
223 
224     @Override
equals(Object thatObject)225     public boolean equals(Object thatObject) {
226         if (this == thatObject) {
227             return true;
228         }
229         if (!(thatObject instanceof UpdateParameter)) {
230             return false;
231         }
232         UpdateParameter that = (UpdateParameter) thatObject;
233 
234         return mUpdateIntervalInMinutes == that.mUpdateIntervalInMinutes
235                 && TextUtils.equals(mUpdateMethod, that.mUpdateMethod)
236                 && TextUtils.equals(mRestriction, that.mRestriction)
237                 && TextUtils.equals(mServerUri, that.mServerUri)
238                 && TextUtils.equals(mUsername, that.mUsername)
239                 && TextUtils.equals(mBase64EncodedPassword, that.mBase64EncodedPassword)
240                 && TextUtils.equals(mTrustRootCertUrl, that.mTrustRootCertUrl)
241                 && Arrays.equals(mTrustRootCertSha256Fingerprint,
242                         that.mTrustRootCertSha256Fingerprint);
243     }
244 
245     @Override
hashCode()246     public int hashCode() {
247         return Objects.hash(mUpdateIntervalInMinutes, mUpdateMethod, mRestriction, mServerUri,
248                 mUsername, mBase64EncodedPassword, mTrustRootCertUrl,
249                 mTrustRootCertSha256Fingerprint);
250     }
251 
252     @Override
toString()253     public String toString() {
254         StringBuilder builder = new StringBuilder();
255         builder.append("UpdateInterval: ").append(mUpdateIntervalInMinutes).append("\n");
256         builder.append("UpdateMethod: ").append(mUpdateMethod).append("\n");
257         builder.append("Restriction: ").append(mRestriction).append("\n");
258         builder.append("ServerURI: ").append(mServerUri).append("\n");
259         builder.append("Username: ").append(mUsername).append("\n");
260         builder.append("TrustRootCertURL: ").append(mTrustRootCertUrl).append("\n");
261         return builder.toString();
262     }
263 
264     /**
265      * Validate UpdateParameter data.
266      *
267      * @return true on success
268      * @hide
269      */
validate()270     public boolean validate() {
271         if (mUpdateIntervalInMinutes == Long.MIN_VALUE) {
272             Log.d(TAG, "Update interval not specified");
273             return false;
274         }
275         // Update not applicable.
276         if (mUpdateIntervalInMinutes == UPDATE_CHECK_INTERVAL_NEVER) {
277             return true;
278         }
279 
280         if (!TextUtils.equals(mUpdateMethod, UPDATE_METHOD_OMADM)
281                 && !TextUtils.equals(mUpdateMethod, UPDATE_METHOD_SSP)) {
282             Log.d(TAG, "Unknown update method: " + mUpdateMethod);
283             return false;
284         }
285 
286         if (!TextUtils.equals(mRestriction, UPDATE_RESTRICTION_HOMESP)
287                 && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_ROAMING_PARTNER)
288                 && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_UNRESTRICTED)) {
289             Log.d(TAG, "Unknown restriction: " + mRestriction);
290             return false;
291         }
292 
293         if (TextUtils.isEmpty(mServerUri)) {
294             Log.d(TAG, "Missing update server URI");
295             return false;
296         }
297         if (mServerUri.getBytes(StandardCharsets.UTF_8).length > MAX_URI_BYTES) {
298             Log.d(TAG, "URI bytes exceeded the max: "
299                     + mServerUri.getBytes(StandardCharsets.UTF_8).length);
300             return false;
301         }
302 
303         if (TextUtils.isEmpty(mUsername)) {
304             Log.d(TAG, "Missing username");
305             return false;
306         }
307         if (mUsername.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
308             Log.d(TAG, "Username bytes exceeded the max: "
309                     + mUsername.getBytes(StandardCharsets.UTF_8).length);
310             return false;
311         }
312 
313         if (TextUtils.isEmpty(mBase64EncodedPassword)) {
314             Log.d(TAG, "Missing username");
315             return false;
316         }
317         if (mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
318             Log.d(TAG, "Password bytes exceeded the max: "
319                     + mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length);
320             return false;
321         }
322         try {
323             Base64.decode(mBase64EncodedPassword, Base64.DEFAULT);
324         } catch (IllegalArgumentException e) {
325             Log.d(TAG, "Invalid encoding for password: " + mBase64EncodedPassword);
326             return false;
327         }
328 
329         if (TextUtils.isEmpty(mTrustRootCertUrl)) {
330             Log.d(TAG, "Missing trust root certificate URL");
331             return false;
332         }
333         if (mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
334             Log.d(TAG, "Trust root cert URL bytes exceeded the max: "
335                     + mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length);
336             return false;
337         }
338 
339         if (mTrustRootCertSha256Fingerprint == null) {
340             Log.d(TAG, "Missing trust root certificate SHA-256 fingerprint");
341             return false;
342         }
343         if (mTrustRootCertSha256Fingerprint.length != CERTIFICATE_SHA256_BYTES) {
344             Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
345                     + mTrustRootCertSha256Fingerprint.length);
346             return false;
347         }
348         return true;
349     }
350 
351     public static final Creator<UpdateParameter> CREATOR =
352         new Creator<UpdateParameter>() {
353             @Override
354             public UpdateParameter createFromParcel(Parcel in) {
355                 UpdateParameter updateParam = new UpdateParameter();
356                 updateParam.setUpdateIntervalInMinutes(in.readLong());
357                 updateParam.setUpdateMethod(in.readString());
358                 updateParam.setRestriction(in.readString());
359                 updateParam.setServerUri(in.readString());
360                 updateParam.setUsername(in.readString());
361                 updateParam.setBase64EncodedPassword(in.readString());
362                 updateParam.setTrustRootCertUrl(in.readString());
363                 updateParam.setTrustRootCertSha256Fingerprint(in.createByteArray());
364                 return updateParam;
365             }
366 
367             @Override
368             public UpdateParameter[] newArray(int size) {
369                 return new UpdateParameter[size];
370             }
371         };
372 }
373