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 com.android.server.wifi.hotspot2;
18 
19 import android.net.wifi.hotspot2.PasspointConfiguration;
20 import android.net.wifi.hotspot2.pps.Credential;
21 import android.net.wifi.hotspot2.pps.HomeSp;
22 import android.net.wifi.hotspot2.pps.Policy;
23 import android.net.wifi.hotspot2.pps.UpdateParameter;
24 
25 import com.android.modules.utils.build.SdkLevel;
26 import com.android.server.wifi.util.XmlUtil;
27 
28 import org.xmlpull.v1.XmlPullParser;
29 import org.xmlpull.v1.XmlPullParserException;
30 import org.xmlpull.v1.XmlSerializer;
31 
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 /**
39  * Utility class for serialize and deserialize Passpoint related configurations to/from XML string.
40  */
41 public class PasspointXmlUtils {
42     // XML section header tags.
43     private static final String XML_TAG_SECTION_HEADER_HOMESP = "HomeSP";
44     private static final String XML_TAG_SECTION_HEADER_CREDENTIAL = "Credential";
45     private static final String XML_TAG_SECTION_HEADER_USER_CREDENTIAL = "UserCredential";
46     private static final String XML_TAG_SECTION_HEADER_CERT_CREDENTIAL = "CertCredential";
47     private static final String XML_TAG_SECTION_HEADER_SIM_CREDENTIAL = "SimCredential";
48     private static final String XML_TAG_SECTION_HEADER_POLICY = "Policy";
49     private static final String XML_TAG_SECTION_HEADER_PREFERRED_ROAMING_PARTNER_LIST =
50             "RoamingPartnerList";
51     private static final String XML_TAG_SECTION_HEADER_ROAMING_PARTNER = "RoamingPartner";
52     private static final String XML_TAG_SECTION_HEADER_POLICY_UPDATE = "PolicyUpdate";
53     private static final String XML_TAG_SECTION_HEADER_SUBSCRIPTION_UPDATE = "SubscriptionUpdate";
54     private static final String XML_TAG_SECTION_HEADER_REQUIRED_PROTO_PORT_MAP =
55             "RequiredProtoPortMap";
56     private static final String XML_TAG_SECTION_HEADER_PROTO_PORT = "ProtoPort";
57 
58     // XML value tags.
59     private static final String XML_TAG_FQDN = "FQDN";
60     private static final String XML_TAG_FRIENDLY_NAME = "FriendlyName";
61     private static final String XML_TAG_FRIENDLY_NAME_LIST = "FriendlyNameList";
62     private static final String XML_TAG_ICON_URL = "IconURL";
63     private static final String XML_TAG_HOME_NETWORK_IDS = "HomeNetworkIDs";
64     private static final String XML_TAG_MATCH_ALL_OIS = "MatchAllOIs";
65     private static final String XML_TAG_MATCH_ANY_OIS = "MatchAnyOIs";
66     private static final String XML_TAG_OTHER_HOME_PARTNERS = "OtherHomePartners";
67     private static final String XML_TAG_ROAMING_CONSORTIUM_OIS = "RoamingConsortiumOIs";
68     private static final String XML_TAG_CREATION_TIME = "CreationTime";
69     private static final String XML_TAG_EXPIRATION_TIME = "ExpirationTime";
70     private static final String XML_TAG_REALM = "Realm";
71     private static final String XML_TAG_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus";
72     private static final String XML_TAG_USERNAME = "Username";
73     private static final String XML_TAG_PASSWORD = "Password";
74     private static final String XML_TAG_MACHINE_MANAGED = "MachineManaged";
75     private static final String XML_TAG_SOFT_TOKEN_APP = "SoftTokenApp";
76     private static final String XML_TAG_ABLE_TO_SHARE = "AbleToShare";
77     private static final String XML_TAG_EAP_TYPE = "EAPType";
78     private static final String XML_TAG_NON_EAP_INNER_METHOD = "NonEAPInnerMethod";
79     private static final String XML_TAG_CERT_TYPE = "CertType";
80     private static final String XML_TAG_CERT_SHA256_FINGERPRINT = "CertSHA256Fingerprint";
81     private static final String XML_TAG_IMSI = "IMSI";
82     private static final String XML_TAG_MIN_HOME_DOWNLINK_BANDWIDTH = "MinHomeDownlinkBandwidth";
83     private static final String XML_TAG_MIN_HOME_UPLINK_BANDWIDTH = "MinHomeUplinkBandwidth";
84     private static final String XML_TAG_MIN_ROAMING_DOWNLINK_BANDWIDTH =
85             "MinRoamingDownlinkBandwidth";
86     private static final String XML_TAG_MIN_ROAMING_UPLINK_BANDWIDTH =
87             "MinRoamingUplinkBandwidth";
88     private static final String XML_TAG_EXCLUDED_SSID_LIST = "ExcludedSSIDList";
89     private static final String XML_TAG_PROTO = "Proto";
90     private static final String XML_TAG_PORTS = "Ports";
91     private static final String XML_TAG_MAXIMUM_BSS_LOAD_VALUE = "MaximumBSSLoadValue";
92     private static final String XML_TAG_FQDN_EXACT_MATCH = "FQDNExactMatch";
93     private static final String XML_TAG_PRIORITY = "Priority";
94     private static final String XML_TAG_COUNTRIES = "Countries";
95     private static final String XML_TAG_UPDATE_INTERVAL = "UpdateInterval";
96     private static final String XML_TAG_UPDATE_METHOD = "UpdateMethod";
97     private static final String XML_TAG_RESTRICTION = "Restriction";
98     private static final String XML_TAG_SERVER_URI = "ServerURI";
99     private static final String XML_TAG_TRUST_ROOT_CERT_URL = "TrustRootCertURL";
100     private static final String XML_TAG_TRUST_ROOT_CERT_SHA256_FINGERPRINT =
101             "TrustRootCertSHA256Fingerprint";
102     private static final String XML_TAG_TRUST_ROOT_CERT_LIST = "TrustRootCertList";
103     private static final String XML_TAG_UPDATE_IDENTIFIER = "UpdateIdentifier";
104     private static final String XML_TAG_CREDENTIAL_PRIORITY = "CredentialPriority";
105     private static final String XML_TAG_SUBSCRIPTION_CREATION_TIME = "SubscriptionCreationTime";
106     private static final String XML_TAG_SUBSCRIPTION_EXPIRATION_TIME =
107             "SubscriptionExpirationTime";
108     private static final String XML_TAG_SUBSCRIPTION_TYPE = "SubscriptionType";
109     private static final String XML_TAG_USAGE_LIMIT_TIME_PERIOD = "UsageLimitTimePeriod";
110     private static final String XML_TAG_USAGE_LIMIT_START_TIME = "UsageLimitStartTime";
111     private static final String XML_TAG_USAGE_LIMIT_DATA_LIMIT = "UsageLimitDataLimit";
112     private static final String XML_TAG_USAGE_LIMIT_TIME_LIMIT = "UsageLimitTimeLimit";
113     private static final String XML_TAG_CARRIER_ID = "CarrierId";
114     private static final String XML_TAG_SUBSCRIPTION_ID = "SubscriptionId";
115     private static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled";
116     private static final String XML_TAG_IS_MAC_RANDOMIZATION_ENABLED = "IsMacRandomizationEnabled";
117     private static final String XML_TAG_METERED_OVERRIDE = "MeteredOverride";
118     private static final String XML_TAG_IS_CARRIER_MERGED = "IsCarrierMerged";
119     private static final String XML_TAG_IS_OEM_PAID = "IsOemPaid";
120     private static final String XML_TAG_IS_OEM_PRIVATE = "IsOemPrivate";
121     private static final String XML_TAG_DECORATED_IDENTITY_PREFIX = "DecoratedIdentityPrefix";
122 
123     /**
124      * Serialize a {@link PasspointConfiguration} to the output stream as a XML block.
125      *
126      * @param out The output stream to serialize to
127      * @param config The configuration to serialize
128      * @throws XmlPullParserException
129      * @throws IOException
130      */
serializePasspointConfiguration(XmlSerializer out, PasspointConfiguration config)131     public static void serializePasspointConfiguration(XmlSerializer out,
132             PasspointConfiguration config) throws XmlPullParserException, IOException {
133         XmlUtil.writeNextValue(out, XML_TAG_UPDATE_IDENTIFIER, config.getUpdateIdentifier());
134         XmlUtil.writeNextValue(out, XML_TAG_CREDENTIAL_PRIORITY, config.getCredentialPriority());
135         XmlUtil.writeNextValue(out, XML_TAG_TRUST_ROOT_CERT_LIST, config.getTrustRootCertList());
136         XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_CREATION_TIME,
137                 config.getSubscriptionCreationTimeInMillis());
138         XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_EXPIRATION_TIME,
139                 config.getSubscriptionExpirationTimeMillis());
140         XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_TYPE, config.getSubscriptionType());
141         XmlUtil.writeNextValue(out, XML_TAG_USAGE_LIMIT_TIME_PERIOD,
142                 config.getUsageLimitUsageTimePeriodInMinutes());
143         XmlUtil.writeNextValue(out, XML_TAG_USAGE_LIMIT_START_TIME,
144                 config.getUsageLimitStartTimeInMillis());
145         XmlUtil.writeNextValue(out, XML_TAG_USAGE_LIMIT_DATA_LIMIT,
146                 config.getUsageLimitDataLimit());
147         XmlUtil.writeNextValue(out, XML_TAG_USAGE_LIMIT_TIME_LIMIT,
148                 config.getUsageLimitTimeLimitInMinutes());
149         serializeHomeSp(out, config.getHomeSp());
150         serializeCredential(out, config.getCredential());
151         serializePolicy(out, config.getPolicy());
152         serializeUpdateParameter(out, XML_TAG_SECTION_HEADER_SUBSCRIPTION_UPDATE,
153                 config.getSubscriptionUpdate());
154         if (config.getServiceFriendlyNames() != null) {
155             XmlUtil.writeNextValue(out, XML_TAG_FRIENDLY_NAME_LIST,
156                     config.getServiceFriendlyNames());
157         }
158         XmlUtil.writeNextValue(out, XML_TAG_CARRIER_ID, config.getCarrierId());
159         XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_ID, config.getSubscriptionId());
160         XmlUtil.writeNextValue(out, XML_TAG_IS_AUTO_JOIN, config.isAutojoinEnabled());
161         XmlUtil.writeNextValue(out, XML_TAG_IS_MAC_RANDOMIZATION_ENABLED,
162                 config.isMacRandomizationEnabled());
163         XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, config.getMeteredOverride());
164         XmlUtil.writeNextValue(out, XML_TAG_IS_CARRIER_MERGED, config.isCarrierMerged());
165         XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PAID, config.isOemPaid());
166         XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PRIVATE, config.isOemPrivate());
167         if (SdkLevel.isAtLeastS()) {
168             XmlUtil.writeNextValue(out, XML_TAG_DECORATED_IDENTITY_PREFIX,
169                     config.getDecoratedIdentityPrefix());
170         }
171     }
172 
173     /**
174      * Deserialize a {@link PasspointConfiguration} from an input stream containing XML block.
175      *
176      * @param in The input stream to read from
177      * @param outerTagDepth The tag depth of the current XML section
178      * @return {@link PasspointConfiguration}
179      * @throws XmlPullParserException
180      * @throws IOException
181      */
deserializePasspointConfiguration(XmlPullParser in, int outerTagDepth)182     public static PasspointConfiguration deserializePasspointConfiguration(XmlPullParser in,
183             int outerTagDepth) throws XmlPullParserException, IOException {
184         PasspointConfiguration config = new PasspointConfiguration();
185         while (XmlUtil.nextElementWithin(in, outerTagDepth)) {
186             if (isValueElement(in)) {
187                 // Value elements.
188                 String[] name = new String[1];
189                 Object value = XmlUtil.readCurrentValue(in, name);
190                 switch (name[0]) {
191                     case XML_TAG_UPDATE_IDENTIFIER:
192                         config.setUpdateIdentifier((int) value);
193                         break;
194                     case XML_TAG_CREDENTIAL_PRIORITY:
195                         config.setCredentialPriority((int) value);
196                         break;
197                     case XML_TAG_TRUST_ROOT_CERT_LIST:
198                         config.setTrustRootCertList((Map<String, byte[]>) value);
199                         break;
200                     case XML_TAG_SUBSCRIPTION_CREATION_TIME:
201                         config.setSubscriptionCreationTimeInMillis((long) value);
202                         break;
203                     case XML_TAG_SUBSCRIPTION_EXPIRATION_TIME:
204                         config.setSubscriptionExpirationTimeInMillis((long) value);
205                         break;
206                     case XML_TAG_SUBSCRIPTION_TYPE:
207                         config.setSubscriptionType((String) value);
208                         break;
209                     case XML_TAG_USAGE_LIMIT_TIME_PERIOD:
210                         config.setUsageLimitUsageTimePeriodInMinutes((long) value);
211                         break;
212                     case XML_TAG_USAGE_LIMIT_START_TIME:
213                         config.setUsageLimitStartTimeInMillis((long) value);
214                         break;
215                     case XML_TAG_USAGE_LIMIT_DATA_LIMIT:
216                         config.setUsageLimitDataLimit((long) value);
217                         break;
218                     case XML_TAG_USAGE_LIMIT_TIME_LIMIT:
219                         config.setUsageLimitTimeLimitInMinutes((long) value);
220                         break;
221                     case XML_TAG_FRIENDLY_NAME_LIST:
222                         config.setServiceFriendlyNames((Map<String, String>) value);
223                         break;
224                     case XML_TAG_CARRIER_ID:
225                         config.setCarrierId((int) value);
226                         break;
227                     case XML_TAG_SUBSCRIPTION_ID:
228                         config.setSubscriptionId((int) value);
229                         break;
230                     case XML_TAG_IS_AUTO_JOIN:
231                         config.setAutojoinEnabled((boolean) value);
232                         break;
233                     case XML_TAG_IS_MAC_RANDOMIZATION_ENABLED:
234                         config.setMacRandomizationEnabled((boolean) value);
235                         break;
236                     case XML_TAG_METERED_OVERRIDE:
237                         config.setMeteredOverride((int) value);
238                         break;
239                     case XML_TAG_IS_CARRIER_MERGED:
240                         config.setCarrierMerged((boolean) value);
241                         break;
242                     case XML_TAG_IS_OEM_PAID:
243                         config.setOemPaid((boolean) value);
244                         break;
245                     case XML_TAG_IS_OEM_PRIVATE:
246                         config.setOemPrivate((boolean) value);
247                         break;
248                     case XML_TAG_DECORATED_IDENTITY_PREFIX:
249                         if (SdkLevel.isAtLeastS()) {
250                             config.setDecoratedIdentityPrefix((String) value);
251                         }
252                         break;
253                     default:
254                         throw new XmlPullParserException("Unknown value under "
255                                 + "PasspointConfiguration: " + in.getName());
256                 }
257             } else {
258                 // Section elements.
259                 switch (in.getName()) {
260                     case XML_TAG_SECTION_HEADER_HOMESP:
261                         config.setHomeSp(deserializeHomeSP(in, outerTagDepth + 1));
262                         break;
263                     case XML_TAG_SECTION_HEADER_CREDENTIAL:
264                         config.setCredential(deserializeCredential(in, outerTagDepth + 1));
265                         break;
266                     case XML_TAG_SECTION_HEADER_POLICY:
267                         config.setPolicy(deserializePolicy(in, outerTagDepth + 1));
268                         break;
269                     case XML_TAG_SECTION_HEADER_SUBSCRIPTION_UPDATE:
270                         config.setSubscriptionUpdate(
271                                 deserializeUpdateParameter(in, outerTagDepth + 1));
272                         break;
273                     default:
274                         throw new XmlPullParserException("Unknown section under "
275                                 + "PasspointConfiguration: " + in.getName());
276                 }
277             }
278         }
279         return config;
280     }
281 
282     /**
283      * Serialize a {@link HomeSp} to an output stream as a XML block.
284      *
285      * @param out The output stream to serialize data to
286      * @param homeSp The {@link HomeSp} to serialize
287      * @throws XmlPullParserException
288      * @throws IOException
289      */
serializeHomeSp(XmlSerializer out, HomeSp homeSp)290     private static void serializeHomeSp(XmlSerializer out, HomeSp homeSp)
291             throws XmlPullParserException, IOException {
292         if (homeSp == null) {
293             return;
294         }
295         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_HOMESP);
296         XmlUtil.writeNextValue(out, XML_TAG_FQDN, homeSp.getFqdn());
297         XmlUtil.writeNextValue(out, XML_TAG_FRIENDLY_NAME, homeSp.getFriendlyName());
298         XmlUtil.writeNextValue(out, XML_TAG_ICON_URL, homeSp.getIconUrl());
299         XmlUtil.writeNextValue(out, XML_TAG_HOME_NETWORK_IDS, homeSp.getHomeNetworkIds());
300         XmlUtil.writeNextValue(out, XML_TAG_MATCH_ALL_OIS, homeSp.getMatchAllOis());
301         XmlUtil.writeNextValue(out, XML_TAG_MATCH_ANY_OIS, homeSp.getMatchAnyOis());
302         XmlUtil.writeNextValue(out, XML_TAG_OTHER_HOME_PARTNERS, homeSp.getOtherHomePartners());
303         XmlUtil.writeNextValue(out, XML_TAG_ROAMING_CONSORTIUM_OIS,
304                 homeSp.getRoamingConsortiumOis());
305         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_HOMESP);
306     }
307 
308     /**
309      * Serialize a {@link Credential} to an output stream as a XML block.
310      *
311      * @param out The output stream to serialize to
312      * @param credential The {@link Credential} to serialize
313      * @throws XmlPullParserException
314      * @throws IOException
315      */
serializeCredential(XmlSerializer out, Credential credential)316     private static void serializeCredential(XmlSerializer out, Credential credential)
317             throws XmlPullParserException, IOException {
318         if (credential == null) {
319             return;
320         }
321         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_CREDENTIAL);
322         XmlUtil.writeNextValue(out, XML_TAG_CREATION_TIME, credential.getCreationTimeInMillis());
323         XmlUtil.writeNextValue(out, XML_TAG_EXPIRATION_TIME,
324                 credential.getExpirationTimeInMillis());
325         XmlUtil.writeNextValue(out, XML_TAG_REALM, credential.getRealm());
326         XmlUtil.writeNextValue(out, XML_TAG_CHECK_AAA_SERVER_CERT_STATUS,
327                 credential.getCheckAaaServerCertStatus());
328         serializeUserCredential(out, credential.getUserCredential());
329         serializeCertCredential(out, credential.getCertCredential());
330         serializeSimCredential(out, credential.getSimCredential());
331         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_CREDENTIAL);
332     }
333 
334     /**
335      * Serialize a {@link Policy} to an output stream as a XML block.
336      *
337      * @param out The output stream to serialize to
338      * @param policy The {@link Policy} to serialize
339      * @throws XmlPullParserException
340      * @throws IOException
341      */
serializePolicy(XmlSerializer out, Policy policy)342     private static void serializePolicy(XmlSerializer out, Policy policy)
343             throws XmlPullParserException, IOException {
344         if (policy == null) {
345             return;
346         }
347         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_POLICY);
348         XmlUtil.writeNextValue(out, XML_TAG_MIN_HOME_DOWNLINK_BANDWIDTH,
349                 policy.getMinHomeDownlinkBandwidth());
350         XmlUtil.writeNextValue(out, XML_TAG_MIN_HOME_UPLINK_BANDWIDTH,
351                 policy.getMinHomeUplinkBandwidth());
352         XmlUtil.writeNextValue(out, XML_TAG_MIN_ROAMING_DOWNLINK_BANDWIDTH,
353                 policy.getMinRoamingDownlinkBandwidth());
354         XmlUtil.writeNextValue(out, XML_TAG_MIN_ROAMING_UPLINK_BANDWIDTH,
355                 policy.getMinRoamingUplinkBandwidth());
356         XmlUtil.writeNextValue(out, XML_TAG_EXCLUDED_SSID_LIST, policy.getExcludedSsidList());
357         XmlUtil.writeNextValue(out, XML_TAG_MAXIMUM_BSS_LOAD_VALUE,
358                 policy.getMaximumBssLoadValue());
359         serializeProtoPortMap(out, policy.getRequiredProtoPortMap());
360         serializeUpdateParameter(out, XML_TAG_SECTION_HEADER_POLICY_UPDATE,
361                 policy.getPolicyUpdate());
362         serializePreferredRoamingPartnerList(out, policy.getPreferredRoamingPartnerList());
363         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_POLICY);
364     }
365 
366     /**
367      * Serialize a {@link android.net.wifi.hotspot2.pps.Credential.UserCredential} to an output
368      * stream as a XML block.
369      *
370      * @param out The output stream to serialize data to
371      * @param userCredential The UserCredential to serialize
372      * @throws XmlPullParserException
373      * @throws IOException
374      */
serializeUserCredential(XmlSerializer out, Credential.UserCredential userCredential)375     private static void serializeUserCredential(XmlSerializer out,
376             Credential.UserCredential userCredential) throws XmlPullParserException, IOException {
377         if (userCredential == null) {
378             return;
379         }
380         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_USER_CREDENTIAL);
381         XmlUtil.writeNextValue(out, XML_TAG_USERNAME, userCredential.getUsername());
382         XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, userCredential.getPassword());
383         XmlUtil.writeNextValue(out, XML_TAG_MACHINE_MANAGED, userCredential.getMachineManaged());
384         XmlUtil.writeNextValue(out, XML_TAG_SOFT_TOKEN_APP, userCredential.getSoftTokenApp());
385         XmlUtil.writeNextValue(out, XML_TAG_ABLE_TO_SHARE, userCredential.getAbleToShare());
386         XmlUtil.writeNextValue(out, XML_TAG_EAP_TYPE, userCredential.getEapType());
387         XmlUtil.writeNextValue(out, XML_TAG_NON_EAP_INNER_METHOD,
388                 userCredential.getNonEapInnerMethod());
389         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_USER_CREDENTIAL);
390     }
391 
392     /**
393      * Serialize a {@link android.net.wifi.hotspot2.pps.Credential.CertificateCredential} to an
394      * output stream as a XML block.
395      *
396      * @param out The output stream to serialize data to
397      * @param certCredential The CertificateCredential to serialize
398      * @throws XmlPullParserException
399      * @throws IOException
400      */
serializeCertCredential(XmlSerializer out, Credential.CertificateCredential certCredential)401     private static void serializeCertCredential(XmlSerializer out,
402             Credential.CertificateCredential certCredential)
403                     throws XmlPullParserException, IOException {
404         if (certCredential == null) {
405             return;
406         }
407         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_CERT_CREDENTIAL);
408         XmlUtil.writeNextValue(out, XML_TAG_CERT_TYPE, certCredential.getCertType());
409         XmlUtil.writeNextValue(out, XML_TAG_CERT_SHA256_FINGERPRINT,
410                 certCredential.getCertSha256Fingerprint());
411         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_CERT_CREDENTIAL);
412     }
413 
414     /**
415      * Serialize a {@link android.net.wifi.hotspot2.pps.Credential.SimCredential} to an
416      * output stream as a XML block.
417      *
418      * @param out The output stream to serialize data to
419      * @param simCredential The SimCredential to serialize
420      * @throws XmlPullParserException
421      * @throws IOException
422      */
serializeSimCredential(XmlSerializer out, Credential.SimCredential simCredential)423     private static void serializeSimCredential(XmlSerializer out,
424             Credential.SimCredential simCredential) throws XmlPullParserException, IOException {
425         if (simCredential == null) {
426             return;
427         }
428         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_SIM_CREDENTIAL);
429         XmlUtil.writeNextValue(out, XML_TAG_IMSI, simCredential.getImsi());
430         XmlUtil.writeNextValue(out, XML_TAG_EAP_TYPE, simCredential.getEapType());
431         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_SIM_CREDENTIAL);
432     }
433 
434     /**
435      * Serialize a preferred roaming partner list to an output stream as a XML block.
436      *
437      * @param out The output stream to serialize data to
438      * @param preferredRoamingPartnerList The partner list to serialize
439      * @throws XmlPullParserException
440      * @throws IOException
441      */
serializePreferredRoamingPartnerList(XmlSerializer out, List<Policy.RoamingPartner> preferredRoamingPartnerList)442     private static void serializePreferredRoamingPartnerList(XmlSerializer out,
443             List<Policy.RoamingPartner> preferredRoamingPartnerList)
444                     throws XmlPullParserException, IOException {
445         if (preferredRoamingPartnerList == null) {
446             return;
447         }
448         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_PREFERRED_ROAMING_PARTNER_LIST);
449         for (Policy.RoamingPartner partner : preferredRoamingPartnerList) {
450             XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_ROAMING_PARTNER);
451             XmlUtil.writeNextValue(out, XML_TAG_FQDN, partner.getFqdn());
452             XmlUtil.writeNextValue(out, XML_TAG_FQDN_EXACT_MATCH, partner.getFqdnExactMatch());
453             XmlUtil.writeNextValue(out, XML_TAG_PRIORITY, partner.getPriority());
454             XmlUtil.writeNextValue(out, XML_TAG_COUNTRIES, partner.getCountries());
455             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_ROAMING_PARTNER);
456         }
457         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_PREFERRED_ROAMING_PARTNER_LIST);
458     }
459 
460     /**
461      * Serialize a {@link UpdateParameter} to an output stream as a XML block.  The
462      * {@link UpdateParameter} are used for describing Subscription Update and Policy Update.
463      *
464      * @param out The output stream to serialize data to
465      * @param type The type the {@link UpdateParameter} is used for
466      * @param param The {@link UpdateParameter} to serialize
467      * @throws XmlPullParserException
468      * @throws IOException
469      */
serializeUpdateParameter(XmlSerializer out, String type, UpdateParameter param)470     private static void serializeUpdateParameter(XmlSerializer out, String type,
471             UpdateParameter param) throws XmlPullParserException, IOException {
472         if (param == null) {
473             return;
474         }
475         XmlUtil.writeNextSectionStart(out, type);
476         XmlUtil.writeNextValue(out, XML_TAG_UPDATE_INTERVAL, param.getUpdateIntervalInMinutes());
477         XmlUtil.writeNextValue(out, XML_TAG_UPDATE_METHOD, param.getUpdateMethod());
478         XmlUtil.writeNextValue(out, XML_TAG_RESTRICTION, param.getRestriction());
479         XmlUtil.writeNextValue(out, XML_TAG_SERVER_URI, param.getServerUri());
480         XmlUtil.writeNextValue(out, XML_TAG_USERNAME, param.getUsername());
481         XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, param.getBase64EncodedPassword());
482         XmlUtil.writeNextValue(out, XML_TAG_TRUST_ROOT_CERT_URL, param.getTrustRootCertUrl());
483         XmlUtil.writeNextValue(out, XML_TAG_TRUST_ROOT_CERT_SHA256_FINGERPRINT,
484                 param.getTrustRootCertSha256Fingerprint());
485         XmlUtil.writeNextSectionEnd(out, type);
486     }
487 
488     /**
489      * Serialize a Protocol-to-Ports map to an output stream as a XML block.  We're not able
490      * to use {@link XmlUtil#writeNextValue} to write this map, since that function only works for
491      * maps with String key.
492      *
493      * @param out The output stream to serialize data to
494      * @param protoPortMap The proto port map to serialize
495      * @throws XmlPullParserException
496      * @throws IOException
497      */
serializeProtoPortMap(XmlSerializer out, Map<Integer, String> protoPortMap)498     private static void serializeProtoPortMap(XmlSerializer out, Map<Integer, String> protoPortMap)
499             throws XmlPullParserException, IOException {
500         if (protoPortMap == null) {
501             return;
502         }
503         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_REQUIRED_PROTO_PORT_MAP);
504         for (Map.Entry<Integer, String> entry : protoPortMap.entrySet()) {
505             XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_PROTO_PORT);
506             XmlUtil.writeNextValue(out, XML_TAG_PROTO, entry.getKey());
507             XmlUtil.writeNextValue(out, XML_TAG_PORTS, entry.getValue());
508             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_PROTO_PORT);
509         }
510         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_REQUIRED_PROTO_PORT_MAP);
511     }
512 
513     /**
514      * Deserialize a {@link HomeSp} from an input stream.
515      *
516      * @param in The input stream to read data from
517      * @param outerTagDepth The tag depth of the current XML section
518      * @return {@link HomeSp}
519      * @throws XmlPullParserException
520      * @throws IOException
521      */
deserializeHomeSP(XmlPullParser in, int outerTagDepth)522     private static HomeSp deserializeHomeSP(XmlPullParser in, int outerTagDepth)
523             throws XmlPullParserException, IOException {
524         HomeSp homeSp = new HomeSp();
525         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
526             String[] valueName = new String[1];
527             Object value = XmlUtil.readCurrentValue(in, valueName);
528             if (valueName[0] == null) {
529                 throw new XmlPullParserException("Missing value name");
530             }
531             switch (valueName[0]) {
532                 case XML_TAG_FQDN:
533                     homeSp.setFqdn((String) value);
534                     break;
535                 case XML_TAG_FRIENDLY_NAME:
536                     homeSp.setFriendlyName((String) value);
537                     break;
538                 case XML_TAG_ICON_URL:
539                     homeSp.setIconUrl((String) value);
540                     break;
541                 case XML_TAG_HOME_NETWORK_IDS:
542                     homeSp.setHomeNetworkIds((Map<String, Long>) value);
543                     break;
544                 case XML_TAG_MATCH_ALL_OIS:
545                     homeSp.setMatchAllOis((long[]) value);
546                     break;
547                 case XML_TAG_MATCH_ANY_OIS:
548                     homeSp.setMatchAnyOis((long[]) value);
549                     break;
550                 case XML_TAG_ROAMING_CONSORTIUM_OIS:
551                     homeSp.setRoamingConsortiumOis((long[]) value);
552                     break;
553                 case XML_TAG_OTHER_HOME_PARTNERS:
554                     homeSp.setOtherHomePartners((String[]) value);
555                     break;
556                 default:
557                     throw new XmlPullParserException("Unknown data under HomeSP: " + valueName[0]);
558             }
559         }
560         return homeSp;
561     }
562 
563     /**
564      * Deserialize a {@link Credential} from an input stream.
565      *
566      * @param in The input stream to read data from
567      * @param outerTagDepth The tag depth of the current XML section
568      * @return {@link Credential}
569      * @throws XmlPullParserException
570      * @throws IOException
571      */
deserializeCredential(XmlPullParser in, int outerTagDepth)572     private static Credential deserializeCredential(XmlPullParser in, int outerTagDepth)
573             throws XmlPullParserException, IOException {
574         Credential credential = new Credential();
575         while (XmlUtil.nextElementWithin(in, outerTagDepth)) {
576             if (isValueElement(in)) {
577                 // Value elements.
578                 String[] name = new String[1];
579                 Object value = XmlUtil.readCurrentValue(in, name);
580                 switch (name[0]) {
581                     case XML_TAG_CREATION_TIME:
582                         credential.setCreationTimeInMillis((long) value);
583                         break;
584                     case XML_TAG_EXPIRATION_TIME:
585                         credential.setExpirationTimeInMillis((long) value);
586                         break;
587                     case XML_TAG_REALM:
588                         credential.setRealm((String) value);
589                         break;
590                     case XML_TAG_CHECK_AAA_SERVER_CERT_STATUS:
591                         credential.setCheckAaaServerCertStatus((boolean) value);
592                         break;
593                     default:
594                         throw new XmlPullParserException("Unknown value under Credential: "
595                             + name[0]);
596                 }
597             } else {
598                 // Subsection elements.
599                 switch (in.getName()) {
600                     case XML_TAG_SECTION_HEADER_USER_CREDENTIAL:
601                         credential.setUserCredential(
602                                 deserializeUserCredential(in, outerTagDepth + 1));
603                         break;
604                     case XML_TAG_SECTION_HEADER_CERT_CREDENTIAL:
605                         credential.setCertCredential(
606                                 deserializeCertCredential(in, outerTagDepth + 1));
607                         break;
608                     case XML_TAG_SECTION_HEADER_SIM_CREDENTIAL:
609                         credential.setSimCredential(
610                                 deserializeSimCredential(in, outerTagDepth + 1));
611                         break;
612                     default:
613                         throw new XmlPullParserException("Unknown section under Credential: "
614                                 + in.getName());
615                 }
616             }
617         }
618         return credential;
619     }
620 
621     /**
622      * Deserialize a {@link Policy} from an input stream.
623      *
624      * @param in The input stream to read data from
625      * @param outerTagDepth The tag depth of the current XML section
626      * @return {@link Policy}
627      * @throws XmlPullParserException
628      * @throws IOException
629      */
deserializePolicy(XmlPullParser in, int outerTagDepth)630     private static Policy deserializePolicy(XmlPullParser in, int outerTagDepth)
631             throws XmlPullParserException, IOException {
632         Policy policy = new Policy();
633         while (XmlUtil.nextElementWithin(in, outerTagDepth)) {
634             if (isValueElement(in)) {
635                 // Value elements.
636                 String[] name = new String[1];
637                 Object value = XmlUtil.readCurrentValue(in, name);
638                 switch (name[0]) {
639                     case XML_TAG_MIN_HOME_DOWNLINK_BANDWIDTH:
640                         policy.setMinHomeDownlinkBandwidth((long) value);
641                         break;
642                     case XML_TAG_MIN_HOME_UPLINK_BANDWIDTH:
643                         policy.setMinHomeUplinkBandwidth((long) value);
644                         break;
645                     case XML_TAG_MIN_ROAMING_DOWNLINK_BANDWIDTH:
646                         policy.setMinRoamingDownlinkBandwidth((long) value);
647                         break;
648                     case XML_TAG_MIN_ROAMING_UPLINK_BANDWIDTH:
649                         policy.setMinRoamingUplinkBandwidth((long) value);
650                         break;
651                     case XML_TAG_EXCLUDED_SSID_LIST:
652                         policy.setExcludedSsidList((String[]) value);
653                         break;
654                     case XML_TAG_MAXIMUM_BSS_LOAD_VALUE:
655                         policy.setMaximumBssLoadValue((int) value);
656                         break;
657                 }
658             } else {
659                 // Subsection elements.
660                 switch (in.getName()) {
661                     case XML_TAG_SECTION_HEADER_REQUIRED_PROTO_PORT_MAP:
662                         policy.setRequiredProtoPortMap(
663                                 deserializeProtoPortMap(in, outerTagDepth + 1));
664                         break;
665                     case XML_TAG_SECTION_HEADER_POLICY_UPDATE:
666                         policy.setPolicyUpdate(deserializeUpdateParameter(in, outerTagDepth + 1));
667                         break;
668                     case XML_TAG_SECTION_HEADER_PREFERRED_ROAMING_PARTNER_LIST:
669                         policy.setPreferredRoamingPartnerList(
670                                 deserializePreferredRoamingPartnerList(in, outerTagDepth + 1));
671                         break;
672                     default:
673                         throw new XmlPullParserException("Unknown section under Policy: "
674                                 + in.getName());
675                 }
676             }
677         }
678         return policy;
679     }
680 
681     /**
682      * Deserialize a {@link android.net.wifi.hotspot2.pps.Credential.UserCredential} from an
683      * input stream.
684      *
685      * @param in The input stream to read data from
686      * @param outerTagDepth The tag depth of the current XML section
687      * @return {@link android.net.wifi.hotspot2.pps.Credential.UserCredential}
688      * @throws XmlPullParserException
689      * @throws IOException
690      */
deserializeUserCredential(XmlPullParser in, int outerTagDepth)691     private static Credential.UserCredential deserializeUserCredential(XmlPullParser in,
692             int outerTagDepth) throws XmlPullParserException, IOException {
693         Credential.UserCredential userCredential = new Credential.UserCredential();
694         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
695             String[] valueName = new String[1];
696             Object value = XmlUtil.readCurrentValue(in, valueName);
697             if (valueName[0] == null) {
698                 throw new XmlPullParserException("Missing value name");
699             }
700             switch (valueName[0]) {
701                 case XML_TAG_USERNAME:
702                     userCredential.setUsername((String) value);
703                     break;
704                 case XML_TAG_PASSWORD:
705                     userCredential.setPassword((String) value);
706                     break;
707                 case XML_TAG_MACHINE_MANAGED:
708                     userCredential.setMachineManaged((boolean) value);
709                     break;
710                 case XML_TAG_SOFT_TOKEN_APP:
711                     userCredential.setSoftTokenApp((String) value);
712                     break;
713                 case XML_TAG_ABLE_TO_SHARE:
714                     userCredential.setAbleToShare((boolean) value);
715                     break;
716                 case XML_TAG_EAP_TYPE:
717                     userCredential.setEapType((int) value);
718                     break;
719                 case XML_TAG_NON_EAP_INNER_METHOD:
720                     userCredential.setNonEapInnerMethod((String) value);
721                     break;
722                 default:
723                     throw new XmlPullParserException("Unknown value under UserCredential: "
724                             + valueName[0]);
725             }
726         }
727         return userCredential;
728     }
729 
730     /**
731      * Deserialize a {@link android.net.wifi.hotspot2.pps.Credential.CertificateCredential}
732      * from an input stream.
733      *
734      * @param in The input stream to read data from
735      * @param outerTagDepth The tag depth of the current XML section
736      * @return {@link android.net.wifi.hotspot2.pps.Credential.CertificateCredential}
737      * @throws XmlPullParserException
738      * @throws IOException
739      */
deserializeCertCredential(XmlPullParser in, int outerTagDepth)740     private static Credential.CertificateCredential deserializeCertCredential(XmlPullParser in,
741             int outerTagDepth) throws XmlPullParserException, IOException {
742         Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
743         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
744             String[] valueName = new String[1];
745             Object value = XmlUtil.readCurrentValue(in, valueName);
746             if (valueName[0] == null) {
747                 throw new XmlPullParserException("Missing value name");
748             }
749             switch (valueName[0]) {
750                 case XML_TAG_CERT_TYPE:
751                     certCredential.setCertType((String) value);
752                     break;
753                 case XML_TAG_CERT_SHA256_FINGERPRINT:
754                     certCredential.setCertSha256Fingerprint((byte[]) value);
755                     break;
756                 default:
757                     throw new XmlPullParserException("Unknown value under CertCredential: "
758                             + valueName[0]);
759             }
760         }
761         return certCredential;
762     }
763 
764     /**
765      * Deserialize a {@link android.net.wifi.hotspot2.pps.Credential.SimCredential} from an
766      * input stream.
767      *
768      * @param in The input stream to read data from
769      * @param outerTagDepth The tag depth of the current XML section
770      * @return {@link android.net.wifi.hotspot2.pps.Credential.SimCredential}
771      * @throws XmlPullParserException
772      * @throws IOException
773      */
deserializeSimCredential(XmlPullParser in, int outerTagDepth)774     private static Credential.SimCredential deserializeSimCredential(XmlPullParser in,
775             int outerTagDepth) throws XmlPullParserException, IOException {
776         Credential.SimCredential simCredential = new Credential.SimCredential();
777         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
778             String[] valueName = new String[1];
779             Object value = XmlUtil.readCurrentValue(in, valueName);
780             if (valueName[0] == null) {
781                 throw new XmlPullParserException("Missing value name");
782             }
783             switch (valueName[0]) {
784                 case XML_TAG_IMSI:
785                     simCredential.setImsi((String) value);
786                     break;
787                 case XML_TAG_EAP_TYPE:
788                     simCredential.setEapType((int) value);
789                     break;
790                 default:
791                     throw new XmlPullParserException("Unknown value under CertCredential: "
792                             + valueName[0]);
793             }
794         }
795         return simCredential;
796     }
797 
798     /**
799      * Deserialize a list of {@link android.net.wifi.hotspot2.pps.Policy.RoamingPartner} from an
800      * input stream.
801      *
802      * @param in The input stream to read data from
803      * @param outerTagDepth The tag depth of the current XML section
804      * @return List of {@link android.net.wifi.hotspot2.pps.Policy.RoamingPartner}
805      * @throws XmlPullParserException
806      * @throws IOException
807      */
deserializePreferredRoamingPartnerList( XmlPullParser in, int outerTagDepth)808     private static List<Policy.RoamingPartner> deserializePreferredRoamingPartnerList(
809             XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException {
810         List<Policy.RoamingPartner> roamingPartnerList = new ArrayList<>();
811         while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_ROAMING_PARTNER,
812                 outerTagDepth)) {
813             roamingPartnerList.add(deserializeRoamingPartner(in, outerTagDepth + 1));
814         }
815         return roamingPartnerList;
816     }
817 
818     /**
819      * Deserialize a {@link android.net.wifi.hotspot2.pps.Policy.RoamingPartner} from an input
820      * stream.
821      *
822      * @param in The input stream to read data from
823      * @param outerTagDepth The tag depth of the current XML section
824      * @return {@link android.net.wifi.hotspot2.pps.Policy.RoamingPartner}
825      * @throws XmlPullParserException
826      * @throws IOException
827      */
deserializeRoamingPartner(XmlPullParser in, int outerTagDepth)828     private static Policy.RoamingPartner deserializeRoamingPartner(XmlPullParser in,
829             int outerTagDepth) throws XmlPullParserException, IOException {
830         Policy.RoamingPartner partner = new Policy.RoamingPartner();
831         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
832             String[] valueName = new String[1];
833             Object value = XmlUtil.readCurrentValue(in, valueName);
834             if (valueName[0] == null) {
835                 throw new XmlPullParserException("Missing value name");
836             }
837             switch (valueName[0]) {
838                 case XML_TAG_FQDN:
839                     partner.setFqdn((String) value);
840                     break;
841                 case XML_TAG_FQDN_EXACT_MATCH:
842                     partner.setFqdnExactMatch((boolean) value);
843                     break;
844                 case XML_TAG_PRIORITY:
845                     partner.setPriority((int) value);
846                     break;
847                 case XML_TAG_COUNTRIES:
848                     partner.setCountries((String) value);
849                     break;
850                 default:
851                     throw new XmlPullParserException("Unknown value under RoamingPartner: "
852                             + valueName[0]);
853             }
854         }
855         return partner;
856     }
857 
858     /**
859      * Deserialize a {@link UpdateParameter} from an input stream.
860      *
861      * @param in The input stream to read data from
862      * @param outerTagDepth The tag depth of the current XML section
863      * @return {@link UpdateParameter}
864      * @throws XmlPullParserException
865      * @throws IOException
866      */
deserializeUpdateParameter(XmlPullParser in, int outerTagDepth)867     private static UpdateParameter deserializeUpdateParameter(XmlPullParser in,
868             int outerTagDepth) throws XmlPullParserException, IOException {
869         UpdateParameter param = new UpdateParameter();
870         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
871             String[] valueName = new String[1];
872             Object value = XmlUtil.readCurrentValue(in, valueName);
873             if (valueName[0] == null) {
874                 throw new XmlPullParserException("Missing value name");
875             }
876             switch (valueName[0]) {
877                 case XML_TAG_UPDATE_INTERVAL:
878                     param.setUpdateIntervalInMinutes((long) value);
879                     break;
880                 case XML_TAG_UPDATE_METHOD:
881                     param.setUpdateMethod((String) value);
882                     break;
883                 case XML_TAG_RESTRICTION:
884                     param.setRestriction((String) value);
885                     break;
886                 case XML_TAG_SERVER_URI:
887                     param.setServerUri((String) value);
888                     break;
889                 case XML_TAG_USERNAME:
890                     param.setUsername((String) value);
891                     break;
892                 case XML_TAG_PASSWORD:
893                     param.setBase64EncodedPassword((String) value);
894                     break;
895                 case XML_TAG_TRUST_ROOT_CERT_URL:
896                     param.setTrustRootCertUrl((String) value);
897                     break;
898                 case XML_TAG_TRUST_ROOT_CERT_SHA256_FINGERPRINT:
899                     param.setTrustRootCertSha256Fingerprint((byte[]) value);
900                     break;
901                 default:
902                     throw new XmlPullParserException("Unknown value under UpdateParameter: "
903                             + valueName[0]);
904             }
905         }
906         return param;
907     }
908 
909     /**
910      * Deserialize a Protocol-Port map from an input stream.
911      *
912      * @param in The input stream to read data from
913      * @param outerTagDepth The tag depth of the current XML section
914      * @return Proocol-Port map
915      * @throws XmlPullParserException
916      * @throws IOException
917      */
deserializeProtoPortMap(XmlPullParser in, int outerTagDepth)918     private static Map<Integer, String> deserializeProtoPortMap(XmlPullParser in,
919             int outerTagDepth) throws XmlPullParserException, IOException {
920         Map<Integer, String> protoPortMap = new HashMap<>();
921         while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_PROTO_PORT,
922                 outerTagDepth)) {
923             int proto = (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROTO);
924             String ports = (String) XmlUtil.readNextValueWithName(in, XML_TAG_PORTS);
925             protoPortMap.put(proto, ports);
926         }
927         return protoPortMap;
928     }
929 
930     /**
931      * Determine if the current element is a value or a section.  The "name" attribute of the
932      * element is used as the indicator, when it is present, the element is considered a value
933      * element.
934      *
935      * Value element:
936      * <int name="test">12</int>
937      *
938      * Section element:
939      * <Test>
940      * ...
941      * </Test>
942      *
943      * @param in XML input stream
944      * @return true if the current element is a value
945      */
isValueElement(XmlPullParser in)946     private static boolean isValueElement(XmlPullParser in) {
947         return in.getAttributeValue(null, "name") != null;
948     }
949 }
950