MOManager.java revision 05d2f4e6f26834a94b53187e6121379a16749088
1package com.android.server.wifi.hotspot2.omadm;
2
3import android.util.Log;
4
5import com.android.server.wifi.anqp.eap.EAP;
6import com.android.server.wifi.anqp.eap.EAPMethod;
7import com.android.server.wifi.anqp.eap.ExpandedEAPMethod;
8import com.android.server.wifi.anqp.eap.InnerAuthEAP;
9import com.android.server.wifi.anqp.eap.NonEAPInnerAuth;
10import com.android.server.wifi.hotspot2.Utils;
11import com.android.server.wifi.hotspot2.pps.Credential;
12import com.android.server.wifi.hotspot2.pps.HomeSP;
13
14import org.xml.sax.SAXException;
15
16import java.io.BufferedInputStream;
17import java.io.BufferedOutputStream;
18import java.io.File;
19import java.io.FileInputStream;
20import java.io.FileOutputStream;
21import java.io.IOException;
22import java.text.DateFormat;
23import java.text.ParseException;
24import java.text.SimpleDateFormat;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Collection;
28import java.util.Collections;
29import java.util.Date;
30import java.util.HashMap;
31import java.util.HashSet;
32import java.util.List;
33import java.util.Map;
34import java.util.Set;
35import java.util.TimeZone;
36
37/**
38 * Handles provisioning of PerProviderSubscription data.
39 */
40public class MOManager {
41
42    public static final String TAG_AAAServerTrustRoot = "AAAServerTrustRoot";
43    public static final String TAG_AbleToShare = "AbleToShare";
44    public static final String TAG_CertificateType = "CertificateType";
45    public static final String TAG_CertSHA256Fingerprint = "CertSHA256Fingerprint";
46    public static final String TAG_CertURL = "CertURL";
47    public static final String TAG_CheckAAAServerCertStatus = "CheckAAAServerCertStatus";
48    public static final String TAG_Country = "Country";
49    public static final String TAG_CreationDate = "CreationDate";
50    public static final String TAG_Credential = "Credential";
51    public static final String TAG_CredentialPriority = "CredentialPriority";
52    public static final String TAG_DataLimit = "DataLimit";
53    public static final String TAG_DigitalCertificate = "DigitalCertificate";
54    public static final String TAG_DLBandwidth = "DLBandwidth";
55    public static final String TAG_EAPMethod = "EAPMethod";
56    public static final String TAG_EAPType = "EAPType";
57    public static final String TAG_ExpirationDate = "ExpirationDate";
58    public static final String TAG_Extension = "Extension";
59    public static final String TAG_FQDN = "FQDN";
60    public static final String TAG_FQDN_Match = "FQDN_Match";
61    public static final String TAG_FriendlyName = "FriendlyName";
62    public static final String TAG_HESSID = "HESSID";
63    public static final String TAG_HomeOI = "HomeOI";
64    public static final String TAG_HomeOIList = "HomeOIList";
65    public static final String TAG_HomeOIRequired = "HomeOIRequired";
66    public static final String TAG_HomeSP = "HomeSP";
67    public static final String TAG_IconURL = "IconURL";
68    public static final String TAG_IMSI = "IMSI";
69    public static final String TAG_InnerEAPType = "InnerEAPType";
70    public static final String TAG_InnerMethod = "InnerMethod";
71    public static final String TAG_InnerVendorID = "InnerVendorID";
72    public static final String TAG_InnerVendorType = "InnerVendorType";
73    public static final String TAG_IPProtocol = "IPProtocol";
74    public static final String TAG_MachineManaged = "MachineManaged";
75    public static final String TAG_MaximumBSSLoadValue = "MaximumBSSLoadValue";
76    public static final String TAG_MinBackhaulThreshold = "MinBackhaulThreshold";
77    public static final String TAG_NetworkID = "NetworkID";
78    public static final String TAG_NetworkType = "NetworkType";
79    public static final String TAG_Other = "Other";
80    public static final String TAG_OtherHomePartners = "OtherHomePartners";
81    public static final String TAG_Password = "Password";
82    public static final String TAG_PerProviderSubscription = "PerProviderSubscription";
83    public static final String TAG_Policy = "Policy";
84    public static final String TAG_PolicyUpdate = "PolicyUpdate";
85    public static final String TAG_PortNumber = "PortNumber";
86    public static final String TAG_PreferredRoamingPartnerList = "PreferredRoamingPartnerList";
87    public static final String TAG_Priority = "Priority";
88    public static final String TAG_Realm = "Realm";
89    public static final String TAG_RequiredProtoPortTuple = "RequiredProtoPortTuple";
90    public static final String TAG_Restriction = "Restriction";
91    public static final String TAG_RoamingConsortiumOI = "RoamingConsortiumOI";
92    public static final String TAG_SIM = "SIM";
93    public static final String TAG_SoftTokenApp = "SoftTokenApp";
94    public static final String TAG_SPExclusionList = "SPExclusionList";
95    public static final String TAG_SSID = "SSID";
96    public static final String TAG_StartDate = "StartDate";
97    public static final String TAG_SubscriptionParameters = "SubscriptionParameters";
98    public static final String TAG_SubscriptionUpdate = "SubscriptionUpdate";
99    public static final String TAG_TimeLimit = "TimeLimit";
100    public static final String TAG_TrustRoot = "TrustRoot";
101    public static final String TAG_TypeOfSubscription = "TypeOfSubscription";
102    public static final String TAG_ULBandwidth = "ULBandwidth";
103    public static final String TAG_UpdateIdentifier = "UpdateIdentifier";
104    public static final String TAG_UpdateInterval = "UpdateInterval";
105    public static final String TAG_UpdateMethod = "UpdateMethod";
106    public static final String TAG_URI = "URI";
107    public static final String TAG_UsageLimits = "UsageLimits";
108    public static final String TAG_UsageTimePeriod = "UsageTimePeriod";
109    public static final String TAG_Username = "Username";
110    public static final String TAG_UsernamePassword = "UsernamePassword";
111    public static final String TAG_VendorId = "VendorId";
112    public static final String TAG_VendorType = "VendorType";
113
114    private final File mPpsFile;
115    private final Map<String, HomeSP> mSPs;
116
117    public MOManager(File ppsFile) {
118        mPpsFile = ppsFile;
119        mSPs = new HashMap<>();
120    }
121
122    public File getPpsFile() {
123        return mPpsFile;
124    }
125
126    public Map<String, HomeSP> getLoadedSPs() {
127        return mSPs;
128    }
129
130    public List<HomeSP> loadAllSPs() throws IOException {
131
132        if (!mPpsFile.exists()) {
133            return Collections.emptyList();
134        }
135
136        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
137            MOTree moTree = MOTree.unmarshal(in);
138            Log.d("HS2J", "MO Tree: " + moTree);
139            mSPs.clear();
140            if (moTree == null) {
141                return Collections.emptyList();     // Empty file
142            }
143
144            List<HomeSP> sps = buildSPs(moTree);
145            if (sps != null) {
146                for (HomeSP sp : sps) {
147                    if (mSPs.put(sp.getFQDN(), sp) != null) {
148                        throw new OMAException("Multiple SPs for FQDN '" + sp.getFQDN() + "'");
149                    } else {
150                        Log.d("PARSE-LOG", "retrieved " + sp.getFQDN() + " from PPS");
151                    }
152                }
153                return sps;
154
155            } else {
156                throw new OMAException("Failed to build HomeSP");
157            }
158        }
159    }
160
161    public static HomeSP buildSP(String xml) throws IOException, SAXException {
162        OMAParser omaParser = new OMAParser();
163        MOTree tree = omaParser.parse(xml, OMAConstants.LOC_PPS + ":1.0");
164        List<HomeSP> spList = buildSPs(tree);
165        if (spList.size() != 1) {
166            throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
167        }
168        return spList.iterator().next();
169    }
170
171    public HomeSP addSP(String xml) throws IOException, SAXException {
172        OMAParser omaParser = new OMAParser();
173        MOTree tree = omaParser.parse(xml, OMAConstants.LOC_PPS + ":1.0");
174        List<HomeSP> spList = buildSPs(tree);
175        if (spList.size() != 1) {
176            throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
177        }
178        HomeSP sp = spList.iterator().next();
179        String fqdn = sp.getFQDN();
180        if (mSPs.put(fqdn, sp) != null) {
181            throw new OMAException("SP " + fqdn + " already exists");
182        }
183
184        BufferedOutputStream out = null;
185        try {
186            out = new BufferedOutputStream(new FileOutputStream(mPpsFile, true));
187            tree.marshal(out);
188            out.flush();
189        } finally {
190            if (out != null) {
191                try {
192                    out.close();
193                } catch (IOException ioe) {
194                    /**/
195                }
196            }
197        }
198
199        return sp;
200    }
201
202    public void saveAllSps(Collection<HomeSP> homeSPs) throws IOException {
203        boolean dirty = homeSPs.size() != mSPs.size();
204
205        if (!dirty) {
206            Map<String, HomeSP> spClone = new HashMap<>(mSPs);
207            for (HomeSP homeSP : homeSPs) {
208                HomeSP existing = spClone.remove(homeSP.getFQDN());
209                if (!homeSP.deepEquals(existing)) {
210                    dirty = true;
211                    break;
212                }
213            }
214
215            if (!dirty) {
216                dirty = !spClone.isEmpty();
217            }
218        }
219
220        Log.d("HS2J", "Save all SPs: dirty: " + dirty +
221                ", update from " + mSPs.size() + " to " + homeSPs);
222        if (homeSPs.size() < mSPs.size()) {
223            return;
224        }
225
226        if (dirty) {
227            mSPs.clear();
228
229            OMAConstructed ppsNode = new OMAConstructed(null, TAG_PerProviderSubscription, null);
230            int instance = 0;
231            for (HomeSP homeSP : homeSPs) {
232                buildHomeSPTree(homeSP, ppsNode, instance++);
233                mSPs.put(homeSP.getFQDN(), homeSP);
234            }
235
236            MOTree tree = new MOTree(OMAConstants.LOC_PPS + ":1.0", "1.2", ppsNode);
237            try (BufferedOutputStream out =
238                         new BufferedOutputStream(new FileOutputStream(mPpsFile, true))) {
239                tree.marshal(out);
240                out.flush();
241            }
242        }
243    }
244
245    private static void buildHomeSPTree(HomeSP homeSP, OMAConstructed root, int spInstance)
246            throws IOException {
247        OMANode providerSubNode = root.addChild(getInstanceString(spInstance), null, null, null);
248
249        // The HomeSP:
250        OMANode homeSpNode = providerSubNode.addChild(TAG_HomeSP, null, null, null);
251        if (!homeSP.getSSIDs().isEmpty()) {
252            OMAConstructed nwkIDNode =
253                    (OMAConstructed) homeSpNode.addChild(TAG_NetworkID, null, null, null);
254            int instance = 0;
255            for (Map.Entry<String, Long> entry : homeSP.getSSIDs().entrySet()) {
256                OMAConstructed inode =
257                        (OMAConstructed) nwkIDNode.addChild(getInstanceString(instance++), null, null, null);
258                inode.addChild(TAG_SSID, null, entry.getKey(), null);
259                if (entry.getValue() != null) {
260                    inode.addChild(TAG_HESSID, null, String.format("%012x", entry.getValue()), null);
261                }
262            }
263        }
264
265        homeSpNode.addChild(TAG_FriendlyName, null, homeSP.getFriendlyName(), null);
266
267        if (homeSP.getIconURL() != null) {
268            homeSpNode.addChild(TAG_IconURL, null, homeSP.getIconURL(), null);
269        }
270
271        homeSpNode.addChild(TAG_FQDN, null, homeSP.getFQDN(), null);
272
273        if (!homeSP.getMatchAllOIs().isEmpty() || !homeSP.getMatchAnyOIs().isEmpty()) {
274            OMAConstructed homeOIList =
275                    (OMAConstructed) homeSpNode.addChild(TAG_HomeOIList, null, null, null);
276
277            int instance = 0;
278            for (Long oi : homeSP.getMatchAllOIs()) {
279                OMAConstructed inode =
280                        (OMAConstructed) homeOIList.addChild(getInstanceString(instance++),
281                                null, null, null);
282                inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null);
283                inode.addChild(TAG_HomeOIRequired, null, "TRUE", null);
284            }
285            for (Long oi : homeSP.getMatchAnyOIs()) {
286                OMAConstructed inode =
287                        (OMAConstructed) homeOIList.addChild(getInstanceString(instance++),
288                                null, null, null);
289                inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null);
290                inode.addChild(TAG_HomeOIRequired, null, "FALSE", null);
291            }
292        }
293
294        if (!homeSP.getOtherHomePartners().isEmpty()) {
295            OMAConstructed otherPartners =
296                    (OMAConstructed) homeSpNode.addChild(TAG_OtherHomePartners, null, null, null);
297            int instance = 0;
298            for (String fqdn : homeSP.getOtherHomePartners()) {
299                OMAConstructed inode =
300                        (OMAConstructed) otherPartners.addChild(getInstanceString(instance++),
301                                null, null, null);
302                inode.addChild(TAG_FQDN, null, fqdn, null);
303            }
304        }
305
306        if (!homeSP.getRoamingConsortiums().isEmpty()) {
307            homeSpNode.addChild(TAG_RoamingConsortiumOI, null, getRCList(homeSP.getRoamingConsortiums()), null);
308        }
309
310        // The Credential:
311        OMANode credentialNode = providerSubNode.addChild(TAG_Credential, null, null, null);
312        Credential cred = homeSP.getCredential();
313        EAPMethod method = cred.getEAPMethod();
314
315        if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_SIM
316                || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKA
317                || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKAPrim) {
318
319            OMANode simNode = credentialNode.addChild(TAG_SIM, null, null, null);
320            simNode.addChild(TAG_IMSI, null, cred.getImsi(), null);
321            simNode.addChild(TAG_EAPType, null,
322                    Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null);
323
324        } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TTLS) {
325
326            OMANode unpNode = credentialNode.addChild(TAG_UsernamePassword, null, null, null);
327            unpNode.addChild(TAG_Username, null, cred.getUserName(), null);
328            unpNode.addChild(TAG_Password, null, cred.getPassword(), null);
329            OMANode eapNode = unpNode.addChild(TAG_EAPMethod, null, null, null);
330            eapNode.addChild(TAG_EAPType, null,
331                    Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null);
332            eapNode.addChild(TAG_InnerMethod, null,
333                    ((NonEAPInnerAuth) method.getAuthParam()).getOMAtype(), null);
334
335        } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TLS) {
336
337            OMANode certNode = credentialNode.addChild(TAG_DigitalCertificate, null, null, null);
338            certNode.addChild(TAG_CertificateType, null, Credential.CertTypeX509, null);
339            certNode.addChild(TAG_CertSHA256Fingerprint, null,
340                    Utils.toHex(cred.getFingerPrint()), null);
341
342        } else {
343            throw new OMAException("Invalid credential on " + homeSP.getFQDN());
344        }
345
346        credentialNode.addChild(TAG_Realm, null, homeSP.getCredential().getRealm(), null);
347        // !!! Note: This node defines CRL checking through OSCP, I suspect we won't be able
348        // to do that so it is commented out:
349        //credentialNode.addChild(TAG_CheckAAAServerCertStatus, null, "TRUE", null);
350    }
351
352    private static String getInstanceString(int instance) {
353        return "i" + instance;
354    }
355
356    private static String getRCList(Collection<Long> rcs) {
357        StringBuilder builder = new StringBuilder();
358        boolean first = true;
359        for (Long roamingConsortium : rcs) {
360            if (first) {
361                first = false;
362            }
363            else {
364                builder.append(',');
365            }
366            builder.append(String.format("%x", roamingConsortium));
367        }
368        return builder.toString();
369    }
370
371    private static final DateFormat DTFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
372
373    static {
374        DTFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
375    }
376
377    private static List<HomeSP> buildSPs(MOTree moTree) throws OMAException {
378        Log.d("HS2J", "MO root: " + moTree.getRoot().getName());
379        OMAConstructed spList;
380        if (moTree.getRoot().getName().equals(TAG_PerProviderSubscription)) {
381            // The PPS file is rooted at PPS instead of MgmtTree to conserve space
382            spList = moTree.getRoot();
383        }
384        else {
385            List<String> spPath = Arrays.asList(TAG_PerProviderSubscription);
386            spList = moTree.getRoot().getListValue(spPath.iterator());
387        }
388
389        List<HomeSP> homeSPs = new ArrayList<>();
390
391        if (spList == null) {
392            return homeSPs;
393        }
394        for (OMANode spRoot : spList.getChildren()) {
395            homeSPs.add(buildHomeSP(spRoot));
396        }
397
398        return homeSPs;
399    }
400
401    private static HomeSP buildHomeSP(OMANode ppsRoot) throws OMAException {
402        OMANode spRoot = ppsRoot.getChild(TAG_HomeSP);
403
404        String fqdn = spRoot.getScalarValue(Arrays.asList(TAG_FQDN).iterator());
405        String friendlyName = spRoot.getScalarValue(Arrays.asList(TAG_FriendlyName).iterator());
406        String iconURL = spRoot.getScalarValue(Arrays.asList(TAG_IconURL).iterator());
407
408        HashSet<Long> roamingConsortiums = new HashSet<>();
409        String oiString = spRoot.getScalarValue(Arrays.asList(TAG_RoamingConsortiumOI).iterator());
410        if (oiString != null) {
411            for (String oi : oiString.split(",")) {
412                roamingConsortiums.add(Long.parseLong(oi.trim(), 16));
413            }
414        }
415
416        Map<String, Long> ssids = new HashMap<>();
417
418        OMANode ssidListNode = spRoot.getListValue(Arrays.asList(TAG_NetworkID).iterator());
419        if (ssidListNode != null) {
420            for (OMANode ssidRoot : ssidListNode.getChildren()) {
421                OMANode hessidNode = ssidRoot.getChild(TAG_HESSID);
422                ssids.put(ssidRoot.getChild(TAG_SSID).getValue(), getMac(hessidNode));
423            }
424        }
425
426        Set<Long> matchAnyOIs = new HashSet<>();
427        List<Long> matchAllOIs = new ArrayList<>();
428        OMANode homeOIListNode = spRoot.getListValue(Arrays.asList(TAG_HomeOIList).iterator());
429        if (homeOIListNode != null) {
430            for (OMANode homeOIRoot : homeOIListNode.getChildren()) {
431                String homeOI = homeOIRoot.getChild(TAG_HomeOI).getValue();
432                if (Boolean.parseBoolean(homeOIRoot.getChild(TAG_HomeOIRequired).getValue())) {
433                    matchAllOIs.add(Long.parseLong(homeOI, 16));
434                } else {
435                    matchAnyOIs.add(Long.parseLong(homeOI, 16));
436                }
437            }
438        }
439
440        Set<String> otherHomePartners = new HashSet<>();
441        OMANode otherListNode =
442                spRoot.getListValue(Arrays.asList(TAG_OtherHomePartners).iterator());
443        if (otherListNode != null) {
444            for (OMANode fqdnNode : otherListNode.getChildren()) {
445                otherHomePartners.add(fqdnNode.getChild(TAG_FQDN).getValue());
446            }
447        }
448
449        Credential credential = buildCredential(ppsRoot.getChild(TAG_Credential));
450
451        return new HomeSP(ssids, fqdn, roamingConsortiums, otherHomePartners,
452                matchAnyOIs, matchAllOIs, friendlyName, iconURL, credential);
453    }
454
455    private static Credential buildCredential(OMANode credNode) throws OMAException {
456        long ctime = getTime(credNode.getChild(TAG_CreationDate));
457        long expTime = getTime(credNode.getChild(TAG_ExpirationDate));
458        String realm = getString(credNode.getChild(TAG_Realm));
459        boolean checkAAACert = getBoolean(credNode.getChild(TAG_CheckAAAServerCertStatus));
460
461        OMANode unNode = credNode.getChild(TAG_UsernamePassword);
462        OMANode certNode = credNode.getChild(TAG_DigitalCertificate);
463        OMANode simNode = credNode.getChild(TAG_SIM);
464
465        int alternatives = 0;
466        alternatives += unNode != null ? 1 : 0;
467        alternatives += certNode != null ? 1 : 0;
468        alternatives += simNode != null ? 1 : 0;
469        if (alternatives != 1) {
470            throw new OMAException("Expected exactly one credential type, got " + alternatives);
471        }
472
473        if (unNode != null) {
474            String userName = getString(unNode.getChild(TAG_Username));
475            String password = getString(unNode.getChild(TAG_Password));
476            boolean machineManaged = getBoolean(unNode.getChild(TAG_MachineManaged));
477            String softTokenApp = getString(unNode.getChild(TAG_SoftTokenApp));
478            boolean ableToShare = getBoolean(unNode.getChild(TAG_AbleToShare));
479
480            OMANode eapMethodNode = unNode.getChild(TAG_EAPMethod);
481            int eapID = getInteger(eapMethodNode.getChild(TAG_EAPType));
482
483            EAP.EAPMethodID eapMethodID = EAP.mapEAPMethod(eapID);
484            if (eapMethodID == null) {
485                throw new OMAException("Unknown EAP method: " + eapID);
486            }
487
488            Long vid = getOptionalInteger(eapMethodNode.getChild(TAG_VendorId));
489            Long vtype = getOptionalInteger(eapMethodNode.getChild(TAG_VendorType));
490            Long innerEAPType = getOptionalInteger(eapMethodNode.getChild(TAG_InnerEAPType));
491            EAP.EAPMethodID innerEAPMethod = null;
492            if (innerEAPType != null) {
493                innerEAPMethod = EAP.mapEAPMethod(innerEAPType.intValue());
494                if (innerEAPMethod == null) {
495                    throw new OMAException("Bad inner EAP method: " + innerEAPType);
496                }
497            }
498
499            Long innerVid = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorID));
500            Long innerVtype = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorType));
501            String innerNonEAPMethod = getString(eapMethodNode.getChild(TAG_InnerMethod));
502
503            EAPMethod eapMethod;
504            if (innerEAPMethod != null) {
505                eapMethod = new EAPMethod(eapMethodID, new InnerAuthEAP(innerEAPMethod));
506            } else if (vid != null) {
507                eapMethod = new EAPMethod(eapMethodID,
508                        new ExpandedEAPMethod(EAP.AuthInfoID.ExpandedEAPMethod,
509                                vid.intValue(), vtype));
510            } else if (innerVid != null) {
511                eapMethod =
512                        new EAPMethod(eapMethodID, new ExpandedEAPMethod(EAP.AuthInfoID
513                                .ExpandedInnerEAPMethod, innerVid.intValue(), innerVtype));
514            } else if (innerNonEAPMethod != null) {
515                eapMethod = new EAPMethod(eapMethodID, new NonEAPInnerAuth(innerNonEAPMethod));
516            } else {
517                throw new OMAException("Incomplete set of EAP parameters");
518            }
519
520            return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, userName,
521                    password, machineManaged, softTokenApp, ableToShare);
522        }
523        if (certNode != null) {
524            try {
525                String certTypeString = getString(certNode.getChild(TAG_CertificateType));
526                byte[] fingerPrint = getOctets(certNode.getChild(TAG_CertSHA256Fingerprint));
527
528                EAPMethod eapMethod = new EAPMethod(EAP.EAPMethodID.EAP_TLS, null);
529
530                return new Credential(ctime, expTime, realm, checkAAACert, eapMethod,
531                        Credential.mapCertType(certTypeString), fingerPrint);
532            }
533            catch (NumberFormatException nfe) {
534                throw new OMAException("Bad hex string: " + nfe.toString());
535            }
536        }
537        if (simNode != null) {
538
539            String imsi = getString(simNode.getChild(TAG_IMSI));
540            EAPMethod eapMethod =
541                    new EAPMethod(EAP.mapEAPMethod(getInteger(simNode.getChild(TAG_EAPType))),
542                            null);
543
544            return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, imsi);
545        }
546        throw new OMAException("Missing credential parameters");
547    }
548
549    private static boolean getBoolean(OMANode boolNode) {
550        return boolNode != null && Boolean.parseBoolean(boolNode.getValue());
551    }
552
553    private static String getString(OMANode stringNode) {
554        return stringNode != null ? stringNode.getValue() : null;
555    }
556
557    private static int getInteger(OMANode intNode) throws OMAException {
558        if (intNode == null) {
559            throw new OMAException("Missing integer value");
560        }
561        try {
562            return Integer.parseInt(intNode.getValue());
563        } catch (NumberFormatException nfe) {
564            throw new OMAException("Invalid integer: " + intNode.getValue());
565        }
566    }
567
568    private static Long getMac(OMANode macNode) throws OMAException {
569        if (macNode == null) {
570            return null;
571        }
572        try {
573            return Long.parseLong(macNode.getValue(), 16);
574        } catch (NumberFormatException nfe) {
575            throw new OMAException("Invalid MAC: " + macNode.getValue());
576        }
577    }
578
579    private static Long getOptionalInteger(OMANode intNode) throws OMAException {
580        if (intNode == null) {
581            return null;
582        }
583        try {
584            return Long.parseLong(intNode.getValue());
585        } catch (NumberFormatException nfe) {
586            throw new OMAException("Invalid integer: " + intNode.getValue());
587        }
588    }
589
590    private static long getTime(OMANode timeNode) throws OMAException {
591        if (timeNode == null) {
592            return -1;
593        }
594        String timeText = timeNode.getValue();
595        try {
596            Date date = DTFormat.parse(timeText);
597            return date.getTime();
598        } catch (ParseException pe) {
599            throw new OMAException("Badly formatted time: " + timeText);
600        }
601    }
602
603    private static byte[] getOctets(OMANode octetNode) throws OMAException {
604        if (octetNode == null) {
605            throw new OMAException("Missing byte value");
606        }
607        return Utils.hexToBytes(octetNode.getValue());
608    }
609}
610