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