package com.android.server.wifi.hotspot2.omadm; import android.util.Base64; import android.util.Log; import com.android.server.wifi.IMSIParameter; import com.android.server.wifi.anqp.eap.EAP; import com.android.server.wifi.anqp.eap.EAPMethod; import com.android.server.wifi.anqp.eap.ExpandedEAPMethod; import com.android.server.wifi.anqp.eap.InnerAuthEAP; import com.android.server.wifi.anqp.eap.NonEAPInnerAuth; import com.android.server.wifi.hotspot2.Utils; import com.android.server.wifi.hotspot2.pps.Credential; import com.android.server.wifi.hotspot2.pps.HomeSP; import org.xml.sax.SAXException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; /** * Handles provisioning of PerProviderSubscription data. */ public class MOManager { public static final String TAG_AAAServerTrustRoot = "AAAServerTrustRoot"; public static final String TAG_AbleToShare = "AbleToShare"; public static final String TAG_CertificateType = "CertificateType"; public static final String TAG_CertSHA256Fingerprint = "CertSHA256Fingerprint"; public static final String TAG_CertURL = "CertURL"; public static final String TAG_CheckAAAServerCertStatus = "CheckAAAServerCertStatus"; public static final String TAG_Country = "Country"; public static final String TAG_CreationDate = "CreationDate"; public static final String TAG_Credential = "Credential"; public static final String TAG_CredentialPriority = "CredentialPriority"; public static final String TAG_DataLimit = "DataLimit"; public static final String TAG_DigitalCertificate = "DigitalCertificate"; public static final String TAG_DLBandwidth = "DLBandwidth"; public static final String TAG_EAPMethod = "EAPMethod"; public static final String TAG_EAPType = "EAPType"; public static final String TAG_ExpirationDate = "ExpirationDate"; public static final String TAG_Extension = "Extension"; public static final String TAG_FQDN = "FQDN"; public static final String TAG_FQDN_Match = "FQDN_Match"; public static final String TAG_FriendlyName = "FriendlyName"; public static final String TAG_HESSID = "HESSID"; public static final String TAG_HomeOI = "HomeOI"; public static final String TAG_HomeOIList = "HomeOIList"; public static final String TAG_HomeOIRequired = "HomeOIRequired"; public static final String TAG_HomeSP = "HomeSP"; public static final String TAG_IconURL = "IconURL"; public static final String TAG_IMSI = "IMSI"; public static final String TAG_InnerEAPType = "InnerEAPType"; public static final String TAG_InnerMethod = "InnerMethod"; public static final String TAG_InnerVendorID = "InnerVendorID"; public static final String TAG_InnerVendorType = "InnerVendorType"; public static final String TAG_IPProtocol = "IPProtocol"; public static final String TAG_MachineManaged = "MachineManaged"; public static final String TAG_MaximumBSSLoadValue = "MaximumBSSLoadValue"; public static final String TAG_MinBackhaulThreshold = "MinBackhaulThreshold"; public static final String TAG_NetworkID = "NetworkID"; public static final String TAG_NetworkType = "NetworkType"; public static final String TAG_Other = "Other"; public static final String TAG_OtherHomePartners = "OtherHomePartners"; public static final String TAG_Password = "Password"; public static final String TAG_PerProviderSubscription = "PerProviderSubscription"; public static final String TAG_Policy = "Policy"; public static final String TAG_PolicyUpdate = "PolicyUpdate"; public static final String TAG_PortNumber = "PortNumber"; public static final String TAG_PreferredRoamingPartnerList = "PreferredRoamingPartnerList"; public static final String TAG_Priority = "Priority"; public static final String TAG_Realm = "Realm"; public static final String TAG_RequiredProtoPortTuple = "RequiredProtoPortTuple"; public static final String TAG_Restriction = "Restriction"; public static final String TAG_RoamingConsortiumOI = "RoamingConsortiumOI"; public static final String TAG_SIM = "SIM"; public static final String TAG_SoftTokenApp = "SoftTokenApp"; public static final String TAG_SPExclusionList = "SPExclusionList"; public static final String TAG_SSID = "SSID"; public static final String TAG_StartDate = "StartDate"; public static final String TAG_SubscriptionParameters = "SubscriptionParameters"; public static final String TAG_SubscriptionUpdate = "SubscriptionUpdate"; public static final String TAG_TimeLimit = "TimeLimit"; public static final String TAG_TrustRoot = "TrustRoot"; public static final String TAG_TypeOfSubscription = "TypeOfSubscription"; public static final String TAG_ULBandwidth = "ULBandwidth"; public static final String TAG_UpdateIdentifier = "UpdateIdentifier"; public static final String TAG_UpdateInterval = "UpdateInterval"; public static final String TAG_UpdateMethod = "UpdateMethod"; public static final String TAG_URI = "URI"; public static final String TAG_UsageLimits = "UsageLimits"; public static final String TAG_UsageTimePeriod = "UsageTimePeriod"; public static final String TAG_Username = "Username"; public static final String TAG_UsernamePassword = "UsernamePassword"; public static final String TAG_VendorId = "VendorId"; public static final String TAG_VendorType = "VendorType"; private static final DateFormat DTFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); static { DTFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } private final File mPpsFile; private final boolean mEnabled; private final Map<String, HomeSP> mSPs; public MOManager(File ppsFile, boolean hs2enabled) { mPpsFile = ppsFile; mEnabled = hs2enabled; mSPs = new HashMap<>(); } public File getPpsFile() { return mPpsFile; } public boolean isEnabled() { return mEnabled; } public boolean isConfigured() { return mEnabled && !mSPs.isEmpty(); } public Map<String, HomeSP> getLoadedSPs() { return Collections.unmodifiableMap(mSPs); } public List<HomeSP> loadAllSPs() throws IOException { if (!mEnabled || !mPpsFile.exists()) { return Collections.emptyList(); } try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) { MOTree moTree = MOTree.unmarshal(in); mSPs.clear(); if (moTree == null) { return Collections.emptyList(); // Empty file } List<HomeSP> sps = buildSPs(moTree); if (sps != null) { for (HomeSP sp : sps) { if (mSPs.put(sp.getFQDN(), sp) != null) { throw new OMAException("Multiple SPs for FQDN '" + sp.getFQDN() + "'"); } else { Log.d(Utils.hs2LogTag(getClass()), "retrieved " + sp.getFQDN() + " from PPS"); } } return sps; } else { throw new OMAException("Failed to build HomeSP"); } } } public static HomeSP buildSP(String xml) throws IOException, SAXException { OMAParser omaParser = new OMAParser(); MOTree tree = omaParser.parse(xml, OMAConstants.LOC_PPS + ":1.0"); List<HomeSP> spList = buildSPs(tree); if (spList.size() != 1) { throw new OMAException("Expected exactly one HomeSP, got " + spList.size()); } return spList.iterator().next(); } public HomeSP addSP(String xml) throws IOException, SAXException { OMAParser omaParser = new OMAParser(); MOTree tree = omaParser.parse(xml, OMAConstants.LOC_PPS + ":1.0"); List<HomeSP> spList = buildSPs(tree); if (spList.size() != 1) { throw new OMAException("Expected exactly one HomeSP, got " + spList.size()); } HomeSP sp = spList.iterator().next(); String fqdn = sp.getFQDN(); if (mSPs.put(fqdn, sp) != null) { throw new OMAException("SP " + fqdn + " already exists"); } BufferedOutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(mPpsFile, true)); tree.marshal(out); out.flush(); } finally { if (out != null) { try { out.close(); } catch (IOException ioe) { /**/ } } } return sp; } public HomeSP getHomeSP(String fqdn) { return mSPs.get(fqdn); } public void addSP(HomeSP homeSP) throws IOException { if (!mEnabled) { throw new IOException("HS2.0 not enabled on this device"); } if (mSPs.containsKey(homeSP.getFQDN())) { Log.d(Utils.hs2LogTag(getClass()), "HS20 profile for " + homeSP.getFQDN() + " already exists"); return; } Log.d(Utils.hs2LogTag(getClass()), "Adding new HS20 profile for " + homeSP.getFQDN()); mSPs.put(homeSP.getFQDN(), homeSP); writeMO(mSPs.values(), mPpsFile); } public void removeSP(String fqdn) throws IOException { if (mSPs.remove(fqdn) == null) { Log.d(Utils.hs2LogTag(getClass()), "No HS20 profile to delete for " + fqdn); return; } Log.d(Utils.hs2LogTag(getClass()), "Deleting HS20 profile for " + fqdn); writeMO(mSPs.values(), mPpsFile); } public void updateAndSaveAllSps(Collection<HomeSP> homeSPs) throws IOException { boolean dirty = false; List<HomeSP> newSet = new ArrayList<>(homeSPs.size()); Map<String, HomeSP> spClone = new HashMap<>(mSPs); for (HomeSP homeSP : homeSPs) { Log.d(Utils.hs2LogTag(getClass()), "Passed HomeSP: " + homeSP); HomeSP existing = spClone.remove(homeSP.getFQDN()); if (existing == null) { dirty = true; newSet.add(homeSP); Log.d(Utils.hs2LogTag(getClass()), "New HomeSP"); } else if (!homeSP.deepEquals(existing)) { dirty = true; newSet.add(homeSP.getClone(existing.getCredential().getPassword())); Log.d(Utils.hs2LogTag(getClass()), "Non-equal HomeSP: " + existing); } else { newSet.add(existing); Log.d(Utils.hs2LogTag(getClass()), "Keeping HomeSP: " + existing); } } Log.d(Utils.hs2LogTag(getClass()), String.format("Saving all SPs (%s): current %s (%d), new %s (%d)", dirty ? "dirty" : "clean", fqdnList(mSPs.values()), mSPs.size(), fqdnList(newSet), newSet.size())); if (!dirty && spClone.isEmpty()) { Log.d(Utils.hs2LogTag(getClass()), "Not persisting"); return; } rewriteMO(newSet, mSPs, mPpsFile); } private static void rewriteMO(Collection<HomeSP> homeSPs, Map<String, HomeSP> current, File f) throws IOException { current.clear(); OMAConstructed ppsNode = new OMAConstructed(null, TAG_PerProviderSubscription, null); int instance = 0; for (HomeSP homeSP : homeSPs) { buildHomeSPTree(homeSP, ppsNode, instance++); current.put(homeSP.getFQDN(), homeSP); } MOTree tree = new MOTree(OMAConstants.LOC_PPS + ":1.0", "1.2", ppsNode); try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(f, false))) { tree.marshal(out); out.flush(); } } private static void writeMO(Collection<HomeSP> homeSPs, File f) throws IOException { OMAConstructed ppsNode = new OMAConstructed(null, TAG_PerProviderSubscription, null); int instance = 0; for (HomeSP homeSP : homeSPs) { buildHomeSPTree(homeSP, ppsNode, instance++); } MOTree tree = new MOTree(OMAConstants.LOC_PPS + ":1.0", "1.2", ppsNode); try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(f, false))) { tree.marshal(out); out.flush(); } } private static String fqdnList(Collection<HomeSP> sps) { StringBuilder sb = new StringBuilder(); boolean first = true; for (HomeSP sp : sps) { if (first) { first = false; } else { sb.append(", "); } sb.append(sp.getFQDN()); } return sb.toString(); } private static void buildHomeSPTree(HomeSP homeSP, OMAConstructed root, int spInstance) throws IOException { OMANode providerSubNode = root.addChild(getInstanceString(spInstance), null, null, null); // The HomeSP: OMANode homeSpNode = providerSubNode.addChild(TAG_HomeSP, null, null, null); if (!homeSP.getSSIDs().isEmpty()) { OMAConstructed nwkIDNode = (OMAConstructed) homeSpNode.addChild(TAG_NetworkID, null, null, null); int instance = 0; for (Map.Entry<String, Long> entry : homeSP.getSSIDs().entrySet()) { OMAConstructed inode = (OMAConstructed) nwkIDNode.addChild(getInstanceString(instance++), null, null, null); inode.addChild(TAG_SSID, null, entry.getKey(), null); if (entry.getValue() != null) { inode.addChild(TAG_HESSID, null, String.format("%012x", entry.getValue()), null); } } } homeSpNode.addChild(TAG_FriendlyName, null, homeSP.getFriendlyName(), null); if (homeSP.getIconURL() != null) { homeSpNode.addChild(TAG_IconURL, null, homeSP.getIconURL(), null); } homeSpNode.addChild(TAG_FQDN, null, homeSP.getFQDN(), null); if (!homeSP.getMatchAllOIs().isEmpty() || !homeSP.getMatchAnyOIs().isEmpty()) { OMAConstructed homeOIList = (OMAConstructed) homeSpNode.addChild(TAG_HomeOIList, null, null, null); int instance = 0; for (Long oi : homeSP.getMatchAllOIs()) { OMAConstructed inode = (OMAConstructed) homeOIList.addChild(getInstanceString(instance++), null, null, null); inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null); inode.addChild(TAG_HomeOIRequired, null, "TRUE", null); } for (Long oi : homeSP.getMatchAnyOIs()) { OMAConstructed inode = (OMAConstructed) homeOIList.addChild(getInstanceString(instance++), null, null, null); inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null); inode.addChild(TAG_HomeOIRequired, null, "FALSE", null); } } if (!homeSP.getOtherHomePartners().isEmpty()) { OMAConstructed otherPartners = (OMAConstructed) homeSpNode.addChild(TAG_OtherHomePartners, null, null, null); int instance = 0; for (String fqdn : homeSP.getOtherHomePartners()) { OMAConstructed inode = (OMAConstructed) otherPartners.addChild(getInstanceString(instance++), null, null, null); inode.addChild(TAG_FQDN, null, fqdn, null); } } if (!homeSP.getRoamingConsortiums().isEmpty()) { homeSpNode.addChild(TAG_RoamingConsortiumOI, null, getRCList(homeSP.getRoamingConsortiums()), null); } // The Credential: OMANode credentialNode = providerSubNode.addChild(TAG_Credential, null, null, null); Credential cred = homeSP.getCredential(); EAPMethod method = cred.getEAPMethod(); if (cred.getCtime() > 0) { credentialNode.addChild(TAG_CreationDate, null, DTFormat.format(new Date(cred.getCtime())), null); } if (cred.getExpTime() > 0) { credentialNode.addChild(TAG_ExpirationDate, null, DTFormat.format(new Date(cred.getExpTime())), null); } if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_SIM || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKA || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKAPrim) { OMANode simNode = credentialNode.addChild(TAG_SIM, null, null, null); simNode.addChild(TAG_IMSI, null, cred.getImsi().toString(), null); simNode.addChild(TAG_EAPType, null, Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null); } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TTLS) { OMANode unpNode = credentialNode.addChild(TAG_UsernamePassword, null, null, null); unpNode.addChild(TAG_Username, null, cred.getUserName(), null); unpNode.addChild(TAG_Password, null, Base64.encodeToString(cred.getPassword().getBytes(StandardCharsets.UTF_8), Base64.DEFAULT), null); OMANode eapNode = unpNode.addChild(TAG_EAPMethod, null, null, null); eapNode.addChild(TAG_EAPType, null, Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null); eapNode.addChild(TAG_InnerMethod, null, ((NonEAPInnerAuth) method.getAuthParam()).getOMAtype(), null); } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TLS) { OMANode certNode = credentialNode.addChild(TAG_DigitalCertificate, null, null, null); certNode.addChild(TAG_CertificateType, null, Credential.CertTypeX509, null); certNode.addChild(TAG_CertSHA256Fingerprint, null, Utils.toHex(cred.getFingerPrint()), null); } else { throw new OMAException("Invalid credential on " + homeSP.getFQDN()); } credentialNode.addChild(TAG_Realm, null, cred.getRealm(), null); // !!! Note: This node defines CRL checking through OSCP, I suspect we won't be able // to do that so it is commented out: //credentialNode.addChild(TAG_CheckAAAServerCertStatus, null, "TRUE", null); } private static String getInstanceString(int instance) { return "i" + instance; } private static String getRCList(Collection<Long> rcs) { StringBuilder builder = new StringBuilder(); boolean first = true; for (Long roamingConsortium : rcs) { if (first) { first = false; } else { builder.append(','); } builder.append(String.format("%x", roamingConsortium)); } return builder.toString(); } private static List<HomeSP> buildSPs(MOTree moTree) throws OMAException { OMAConstructed spList; if (moTree.getRoot().getName().equals(TAG_PerProviderSubscription)) { // The PPS file is rooted at PPS instead of MgmtTree to conserve space spList = moTree.getRoot(); } else { List<String> spPath = Arrays.asList(TAG_PerProviderSubscription); spList = moTree.getRoot().getListValue(spPath.iterator()); } List<HomeSP> homeSPs = new ArrayList<>(); if (spList == null) { return homeSPs; } for (OMANode spRoot : spList.getChildren()) { homeSPs.add(buildHomeSP(spRoot)); } return homeSPs; } private static HomeSP buildHomeSP(OMANode ppsRoot) throws OMAException { OMANode spRoot = ppsRoot.getChild(TAG_HomeSP); String fqdn = spRoot.getScalarValue(Arrays.asList(TAG_FQDN).iterator()); String friendlyName = spRoot.getScalarValue(Arrays.asList(TAG_FriendlyName).iterator()); String iconURL = spRoot.getScalarValue(Arrays.asList(TAG_IconURL).iterator()); HashSet<Long> roamingConsortiums = new HashSet<>(); String oiString = spRoot.getScalarValue(Arrays.asList(TAG_RoamingConsortiumOI).iterator()); if (oiString != null) { for (String oi : oiString.split(",")) { roamingConsortiums.add(Long.parseLong(oi.trim(), 16)); } } Map<String, Long> ssids = new HashMap<>(); OMANode ssidListNode = spRoot.getListValue(Arrays.asList(TAG_NetworkID).iterator()); if (ssidListNode != null) { for (OMANode ssidRoot : ssidListNode.getChildren()) { OMANode hessidNode = ssidRoot.getChild(TAG_HESSID); ssids.put(ssidRoot.getChild(TAG_SSID).getValue(), getMac(hessidNode)); } } Set<Long> matchAnyOIs = new HashSet<>(); List<Long> matchAllOIs = new ArrayList<>(); OMANode homeOIListNode = spRoot.getListValue(Arrays.asList(TAG_HomeOIList).iterator()); if (homeOIListNode != null) { for (OMANode homeOIRoot : homeOIListNode.getChildren()) { String homeOI = homeOIRoot.getChild(TAG_HomeOI).getValue(); if (Boolean.parseBoolean(homeOIRoot.getChild(TAG_HomeOIRequired).getValue())) { matchAllOIs.add(Long.parseLong(homeOI, 16)); } else { matchAnyOIs.add(Long.parseLong(homeOI, 16)); } } } Set<String> otherHomePartners = new HashSet<>(); OMANode otherListNode = spRoot.getListValue(Arrays.asList(TAG_OtherHomePartners).iterator()); if (otherListNode != null) { for (OMANode fqdnNode : otherListNode.getChildren()) { otherHomePartners.add(fqdnNode.getChild(TAG_FQDN).getValue()); } } Credential credential = buildCredential(ppsRoot.getChild(TAG_Credential)); return new HomeSP(ssids, fqdn, roamingConsortiums, otherHomePartners, matchAnyOIs, matchAllOIs, friendlyName, iconURL, credential); } private static Credential buildCredential(OMANode credNode) throws OMAException { long ctime = getTime(credNode.getChild(TAG_CreationDate)); long expTime = getTime(credNode.getChild(TAG_ExpirationDate)); String realm = getString(credNode.getChild(TAG_Realm)); boolean checkAAACert = getBoolean(credNode.getChild(TAG_CheckAAAServerCertStatus)); OMANode unNode = credNode.getChild(TAG_UsernamePassword); OMANode certNode = credNode.getChild(TAG_DigitalCertificate); OMANode simNode = credNode.getChild(TAG_SIM); int alternatives = 0; alternatives += unNode != null ? 1 : 0; alternatives += certNode != null ? 1 : 0; alternatives += simNode != null ? 1 : 0; if (alternatives != 1) { throw new OMAException("Expected exactly one credential type, got " + alternatives); } if (unNode != null) { String userName = getString(unNode.getChild(TAG_Username)); String password = getString(unNode.getChild(TAG_Password)); boolean machineManaged = getBoolean(unNode.getChild(TAG_MachineManaged)); String softTokenApp = getString(unNode.getChild(TAG_SoftTokenApp)); boolean ableToShare = getBoolean(unNode.getChild(TAG_AbleToShare)); OMANode eapMethodNode = unNode.getChild(TAG_EAPMethod); int eapID = getInteger(eapMethodNode.getChild(TAG_EAPType)); EAP.EAPMethodID eapMethodID = EAP.mapEAPMethod(eapID); if (eapMethodID == null) { throw new OMAException("Unknown EAP method: " + eapID); } Long vid = getOptionalInteger(eapMethodNode.getChild(TAG_VendorId)); Long vtype = getOptionalInteger(eapMethodNode.getChild(TAG_VendorType)); Long innerEAPType = getOptionalInteger(eapMethodNode.getChild(TAG_InnerEAPType)); EAP.EAPMethodID innerEAPMethod = null; if (innerEAPType != null) { innerEAPMethod = EAP.mapEAPMethod(innerEAPType.intValue()); if (innerEAPMethod == null) { throw new OMAException("Bad inner EAP method: " + innerEAPType); } } Long innerVid = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorID)); Long innerVtype = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorType)); String innerNonEAPMethod = getString(eapMethodNode.getChild(TAG_InnerMethod)); EAPMethod eapMethod; if (innerEAPMethod != null) { eapMethod = new EAPMethod(eapMethodID, new InnerAuthEAP(innerEAPMethod)); } else if (vid != null) { eapMethod = new EAPMethod(eapMethodID, new ExpandedEAPMethod(EAP.AuthInfoID.ExpandedEAPMethod, vid.intValue(), vtype)); } else if (innerVid != null) { eapMethod = new EAPMethod(eapMethodID, new ExpandedEAPMethod(EAP.AuthInfoID .ExpandedInnerEAPMethod, innerVid.intValue(), innerVtype)); } else if (innerNonEAPMethod != null) { eapMethod = new EAPMethod(eapMethodID, new NonEAPInnerAuth(innerNonEAPMethod)); } else { throw new OMAException("Incomplete set of EAP parameters"); } return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, userName, password, machineManaged, softTokenApp, ableToShare); } if (certNode != null) { try { String certTypeString = getString(certNode.getChild(TAG_CertificateType)); byte[] fingerPrint = getOctets(certNode.getChild(TAG_CertSHA256Fingerprint)); EAPMethod eapMethod = new EAPMethod(EAP.EAPMethodID.EAP_TLS, null); return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, Credential.mapCertType(certTypeString), fingerPrint); } catch (NumberFormatException nfe) { throw new OMAException("Bad hex string: " + nfe.toString()); } } if (simNode != null) { try { IMSIParameter imsi = new IMSIParameter(getString(simNode.getChild(TAG_IMSI))); EAPMethod eapMethod = new EAPMethod(EAP.mapEAPMethod(getInteger(simNode.getChild(TAG_EAPType))), null); return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, imsi); } catch (IOException ioe) { throw new OMAException("Failed to parse IMSI: " + ioe); } } throw new OMAException("Missing credential parameters"); } private static boolean getBoolean(OMANode boolNode) { return boolNode != null && Boolean.parseBoolean(boolNode.getValue()); } private static String getString(OMANode stringNode) { return stringNode != null ? stringNode.getValue() : null; } private static int getInteger(OMANode intNode) throws OMAException { if (intNode == null) { throw new OMAException("Missing integer value"); } try { return Integer.parseInt(intNode.getValue()); } catch (NumberFormatException nfe) { throw new OMAException("Invalid integer: " + intNode.getValue()); } } private static Long getMac(OMANode macNode) throws OMAException { if (macNode == null) { return null; } try { return Long.parseLong(macNode.getValue(), 16); } catch (NumberFormatException nfe) { throw new OMAException("Invalid MAC: " + macNode.getValue()); } } private static Long getOptionalInteger(OMANode intNode) throws OMAException { if (intNode == null) { return null; } try { return Long.parseLong(intNode.getValue()); } catch (NumberFormatException nfe) { throw new OMAException("Invalid integer: " + intNode.getValue()); } } private static long getTime(OMANode timeNode) throws OMAException { if (timeNode == null) { return Utils.UNSET_TIME; } String timeText = timeNode.getValue(); try { Date date = DTFormat.parse(timeText); return date.getTime(); } catch (ParseException pe) { throw new OMAException("Badly formatted time: " + timeText); } } private static byte[] getOctets(OMANode octetNode) throws OMAException { if (octetNode == null) { throw new OMAException("Missing byte value"); } return Utils.hexToBytes(octetNode.getValue()); } }