Loading wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java +58 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ import android.util.Log; import android.util.Pair; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; Loading Loading @@ -147,11 +150,21 @@ public final class PPSMOParser { * Fields under Credential subtree. */ private static final String NODE_CREDENTIAL = "Credential"; private static final String NODE_CREATION_DATE = "CreationDate"; private static final String NODE_EXPIRATION_DATE = "ExpirationDate"; private static final String NODE_USERNAME_PASSWORD = "UsernamePassword"; private static final String NODE_USERNAME = "Username"; private static final String NODE_PASSWORD = "Password"; private static final String NODE_MACHINE_MANAGED = "MachineManaged"; private static final String NODE_SOFT_TOKEN_APP = "SoftTokenApp"; private static final String NODE_ABLE_TO_SHARE = "AbleToShare"; private static final String NODE_EAP_METHOD = "EAPMethod"; private static final String NODE_EAP_TYPE = "EAPType"; private static final String NODE_VENDOR_ID = "VendorId"; private static final String NODE_VENDOR_TYPE = "VendorType"; private static final String NODE_INNER_EAP_TYPE = "InnerEAPType"; private static final String NODE_INNER_VENDOR_ID = "InnerVendorID"; private static final String NODE_INNER_VENDOR_TYPE = "InnerVendorType"; private static final String NODE_INNER_METHOD = "InnerMethod"; private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate"; private static final String NODE_CERTIFICATE_TYPE = "CertificateType"; Loading @@ -159,6 +172,7 @@ public final class PPSMOParser { private static final String NODE_REALM = "Realm"; private static final String NODE_SIM = "SIM"; private static final String NODE_SIM_IMSI = "IMSI"; private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus"; /** * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree. Loading Loading @@ -812,6 +826,12 @@ public final class PPSMOParser { Credential credential = new Credential(); for (PPSNode child: node.getChildren()) { switch (child.getName()) { case NODE_CREATION_DATE: credential.creationTimeInMs = parseDate(getPpsNodeValue(child)); break; case NODE_EXPIRATION_DATE: credential.expirationTimeInMs = parseDate(getPpsNodeValue(child)); break; case NODE_USERNAME_PASSWORD: credential.userCredential = parseUserCredential(child); break; Loading @@ -821,6 +841,10 @@ public final class PPSMOParser { case NODE_REALM: credential.realm = getPpsNodeValue(child); break; case NODE_CHECK_AAA_SERVER_CERT_STATUS: credential.checkAAAServerCertStatus = Boolean.parseBoolean(getPpsNodeValue(child)); break; case NODE_SIM: credential.simCredential = parseSimCredential(child); break; Loading Loading @@ -855,6 +879,15 @@ public final class PPSMOParser { case NODE_PASSWORD: userCred.password = getPpsNodeValue(child); break; case NODE_MACHINE_MANAGED: userCred.machineManaged = Boolean.parseBoolean(getPpsNodeValue(child)); break; case NODE_SOFT_TOKEN_APP: userCred.softTokenApp = getPpsNodeValue(child); break; case NODE_ABLE_TO_SHARE: userCred.ableToShare = Boolean.parseBoolean(getPpsNodeValue(child)); break; case NODE_EAP_METHOD: parseEAPMethod(child, userCred); break; Loading Loading @@ -889,6 +922,15 @@ public final class PPSMOParser { case NODE_INNER_METHOD: userCred.nonEapInnerMethod = getPpsNodeValue(child); break; case NODE_VENDOR_ID: case NODE_VENDOR_TYPE: case NODE_INNER_EAP_TYPE: case NODE_INNER_VENDOR_ID: case NODE_INNER_VENDOR_TYPE: // Only EAP-TTLS is currently supported for user credential, which doesn't // use any of these parameters. Log.d(TAG, "Ignore unsupported EAP method parameter: " + child.getName()); break; default: throw new ParsingException("Unknown node under EAPMethod: " + child.getName()); } Loading Loading @@ -980,6 +1022,22 @@ public final class PPSMOParser { return result; } /** * Convert a date string to the number of milliseconds since January 1, 1970, 00:00:00 GMT. * * @param dateStr String in the format of yyyy-MM-dd'T'HH:mm:ss'Z' * @return number of milliseconds * @throws ParsingException */ private static long parseDate(String dateStr) throws ParsingException { try { DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); return format.parse(dateStr).getTime(); } catch (ParseException pe) { throw new ParsingException("Badly formatted time: " + dateStr); } } /** * Parse an integer string. * Loading wifi/java/android/net/wifi/hotspot2/pps/Credential.java +95 −33 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Parcel; import android.text.TextUtils; import android.util.Log; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; Loading @@ -41,8 +42,6 @@ import java.util.Set; * In addition to the fields in the Credential subtree, this will also maintain necessary * information for the private key and certificates associated with this credential. * * Currently we only support the nodes that are used by Hotspot 2.0 Release 1. * * @hide */ public final class Credential implements Parcelable { Loading @@ -52,7 +51,21 @@ public final class Credential implements Parcelable { * Max string length for realm. Refer to Credential/Realm node in Hotspot 2.0 Release 2 * Technical Specification Section 9.1 for more info. */ private static final int MAX_REALM_LENGTH = 253; private static final int MAX_REALM_BYTES = 253; /** * The time this credential is created. It is in the format of number * of milliseconds since January 1, 1970, 00:00:00 GMT. * Using Long.MIN_VALUE to indicate unset value. */ public long creationTimeInMs = Long.MIN_VALUE; /** * The time this credential will expire. It is in the format of number * of milliseconds since January 1, 1970, 00:00:00 GMT. * Using Long.MIN_VALUE to indicate unset value. */ public long expirationTimeInMs = Long.MIN_VALUE; /** * The realm associated with this credential. It will be used to determine Loading @@ -61,6 +74,13 @@ public final class Credential implements Parcelable { */ public String realm = null; /** * When set to true, the device should check AAA (Authentication, Authorization, * and Accounting) server's certificate during EAP (Extensible Authentication * Protocol) authentication. */ public boolean checkAAAServerCertStatus = false; /** * Username-password based credential. * Contains the fields under PerProviderSubscription/Credential/UsernamePassword subtree. Loading @@ -70,13 +90,13 @@ public final class Credential implements Parcelable { * Maximum string length for username. Refer to Credential/UsernamePassword/Username * node in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info. */ private static final int MAX_USERNAME_LENGTH = 63; private static final int MAX_USERNAME_BYTES = 63; /** * Maximum string length for password. Refer to Credential/UsernamePassword/Password * in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info. */ private static final int MAX_PASSWORD_LENGTH = 255; private static final int MAX_PASSWORD_BYTES = 255; /** * Supported Non-EAP inner methods. Refer to Loading @@ -96,6 +116,21 @@ public final class Credential implements Parcelable { */ public String password = null; /** * Flag indicating if the password is machine managed. */ public boolean machineManaged = false; /** * The name of the application used to generate the password. */ public String softTokenApp = null; /** * Flag indicating if this credential is usable on other mobile devices as well. */ public boolean ableToShare = false; /** * EAP (Extensible Authentication Protocol) method type. * Refer to http://www.iana.org/assignments/eap-numbers/eap-numbers.xml#eap-numbers-4 Loading Loading @@ -123,6 +158,9 @@ public final class Credential implements Parcelable { if (source != null) { username = source.username; password = source.password; machineManaged = source.machineManaged; softTokenApp = source.softTokenApp; ableToShare = source.ableToShare; eapType = source.eapType; nonEapInnerMethod = source.nonEapInnerMethod; } Loading @@ -137,6 +175,9 @@ public final class Credential implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(username); dest.writeString(password); dest.writeInt(machineManaged ? 1 : 0); dest.writeString(softTokenApp); dest.writeInt(ableToShare ? 1 : 0); dest.writeInt(eapType); dest.writeString(nonEapInnerMethod); } Loading @@ -151,10 +192,13 @@ public final class Credential implements Parcelable { } UserCredential that = (UserCredential) thatObject; return TextUtils.equals(username, that.username) && TextUtils.equals(password, that.password) && eapType == that.eapType && TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod); return TextUtils.equals(username, that.username) && TextUtils.equals(password, that.password) && machineManaged == that.machineManaged && TextUtils.equals(softTokenApp, that.softTokenApp) && ableToShare == that.ableToShare && eapType == that.eapType && TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod); } /** Loading @@ -167,8 +211,9 @@ public final class Credential implements Parcelable { Log.d(TAG, "Missing username"); return false; } if (username.length() > MAX_USERNAME_LENGTH) { Log.d(TAG, "username exceeding maximum length: " + username.length()); if (username.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) { Log.d(TAG, "username exceeding maximum length: " + username.getBytes(StandardCharsets.UTF_8).length); return false; } Loading @@ -176,8 +221,9 @@ public final class Credential implements Parcelable { Log.d(TAG, "Missing password"); return false; } if (password.length() > MAX_PASSWORD_LENGTH) { Log.d(TAG, "password exceeding maximum length: " + password.length()); if (password.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) { Log.d(TAG, "password exceeding maximum length: " + password.getBytes(StandardCharsets.UTF_8).length); return false; } Loading @@ -202,6 +248,9 @@ public final class Credential implements Parcelable { UserCredential userCredential = new UserCredential(); userCredential.username = in.readString(); userCredential.password = in.readString(); userCredential.machineManaged = in.readInt() != 0; userCredential.softTokenApp = in.readString(); userCredential.ableToShare = in.readInt() != 0; userCredential.eapType = in.readInt(); userCredential.nonEapInnerMethod = in.readString(); return userCredential; Loading Loading @@ -281,8 +330,8 @@ public final class Credential implements Parcelable { } CertificateCredential that = (CertificateCredential) thatObject; return TextUtils.equals(certType, that.certType) && Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint); return TextUtils.equals(certType, that.certType) && Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint); } /** Loading @@ -295,8 +344,8 @@ public final class Credential implements Parcelable { Log.d(TAG, "Unsupported certificate type: " + certType); return false; } if (certSha256FingerPrint == null || certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) { if (certSha256FingerPrint == null || certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) { Log.d(TAG, "Invalid SHA-256 fingerprint"); return false; } Loading Loading @@ -378,8 +427,8 @@ public final class Credential implements Parcelable { } SimCredential that = (SimCredential) thatObject; return TextUtils.equals(imsi, that.imsi) && eapType == that.eapType; return TextUtils.equals(imsi, that.imsi) && eapType == that.eapType; } @Override Loading @@ -400,8 +449,8 @@ public final class Credential implements Parcelable { if (!verifyImsi()) { return false; } if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA && eapType != EAPConstants.EAP_AKA_PRIME) { if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA && eapType != EAPConstants.EAP_AKA_PRIME) { Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType); return false; } Loading Loading @@ -490,7 +539,10 @@ public final class Credential implements Parcelable { */ public Credential(Credential source) { if (source != null) { creationTimeInMs = source.creationTimeInMs; expirationTimeInMs = source.expirationTimeInMs; realm = source.realm; checkAAAServerCertStatus = source.checkAAAServerCertStatus; if (source.userCredential != null) { userCredential = new UserCredential(source.userCredential); } Loading @@ -516,7 +568,10 @@ public final class Credential implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(creationTimeInMs); dest.writeLong(expirationTimeInMs); dest.writeString(realm); dest.writeInt(checkAAAServerCertStatus ? 1 : 0); dest.writeParcelable(userCredential, flags); dest.writeParcelable(certCredential, flags); dest.writeParcelable(simCredential, flags); Loading @@ -535,16 +590,19 @@ public final class Credential implements Parcelable { } Credential that = (Credential) thatObject; return TextUtils.equals(realm, that.realm) && (userCredential == null ? that.userCredential == null : userCredential.equals(that.userCredential)) && (certCredential == null ? that.certCredential == null : certCredential.equals(that.certCredential)) && (simCredential == null ? that.simCredential == null : simCredential.equals(that.simCredential)) && isX509CertificateEquals(caCertificate, that.caCertificate) && isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain) && isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey); return TextUtils.equals(realm, that.realm) && creationTimeInMs == that.creationTimeInMs && expirationTimeInMs == that.expirationTimeInMs && checkAAAServerCertStatus == that.checkAAAServerCertStatus && (userCredential == null ? that.userCredential == null : userCredential.equals(that.userCredential)) && (certCredential == null ? that.certCredential == null : certCredential.equals(that.certCredential)) && (simCredential == null ? that.simCredential == null : simCredential.equals(that.simCredential)) && isX509CertificateEquals(caCertificate, that.caCertificate) && isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain) && isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey); } /** Loading @@ -557,8 +615,9 @@ public final class Credential implements Parcelable { Log.d(TAG, "Missing realm"); return false; } if (realm.length() > MAX_REALM_LENGTH) { Log.d(TAG, "realm exceeding maximum length: " + realm.length()); if (realm.getBytes(StandardCharsets.UTF_8).length > MAX_REALM_BYTES) { Log.d(TAG, "realm exceeding maximum length: " + realm.getBytes(StandardCharsets.UTF_8).length); return false; } Loading Loading @@ -588,7 +647,10 @@ public final class Credential implements Parcelable { @Override public Credential createFromParcel(Parcel in) { Credential credential = new Credential(); credential.creationTimeInMs = in.readLong(); credential.expirationTimeInMs = in.readLong(); credential.realm = in.readString(); credential.checkAAAServerCertStatus = in.readInt() != 0; credential.userCredential = in.readParcelable(null); credential.certCredential = in.readParcelable(null); credential.simCredential = in.readParcelable(null); Loading wifi/tests/assets/pps/PerProviderSubscription.xml +24 −0 Original line number Diff line number Diff line Loading @@ -86,10 +86,22 @@ </Node> <Node> <NodeName>Credential</NodeName> <Node> <NodeName>CreationDate</NodeName> <Value>2016-01-01T10:00:00Z</Value> </Node> <Node> <NodeName>ExpirationDate</NodeName> <Value>2016-02-01T10:00:00Z</Value> </Node> <Node> <NodeName>Realm</NodeName> <Value>shaken.stirred.com</Value> </Node> <Node> <NodeName>CheckAAAServerCertStatus</NodeName> <Value>true</Value> </Node> <Node> <NodeName>UsernamePassword</NodeName> <Node> Loading @@ -100,6 +112,18 @@ <NodeName>Password</NodeName> <Value>Ym9uZDAwNw==</Value> </Node> <Node> <NodeName>MachineManaged</NodeName> <Value>true</Value> </Node> <Node> <NodeName>SoftTokenApp</NodeName> <Value>TestApp</Value> </Node> <Node> <NodeName>AbleToShare</NodeName> <Value>true</Value> </Node> <Node> <NodeName>EAPMethod</NodeName> <Node> Loading wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java +10 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.HashMap; Loading Loading @@ -78,7 +80,7 @@ public class PPSMOParserTest { * * @return {@link PasspointConfiguration} */ private PasspointConfiguration generateConfigurationFromPPSMOTree() { private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception { PasspointConfiguration config = new PasspointConfiguration(); // HomeSP configuration. Loading @@ -95,11 +97,18 @@ public class PPSMOParserTest { config.homeSp.otherHomePartners = new String[] {"other.fqdn.com"}; // Credential configuration. DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); config.credential = new Credential(); config.credential.creationTimeInMs = format.parse("2016-01-01T10:00:00Z").getTime(); config.credential.expirationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime(); config.credential.realm = "shaken.stirred.com"; config.credential.checkAAAServerCertStatus = true; config.credential.userCredential = new Credential.UserCredential(); config.credential.userCredential.username = "james"; config.credential.userCredential.password = "Ym9uZDAwNw=="; config.credential.userCredential.machineManaged = true; config.credential.userCredential.softTokenApp = "TestApp"; config.credential.userCredential.ableToShare = true; config.credential.userCredential.eapType = 21; config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2"; config.credential.certCredential = new Credential.CertificateCredential(); Loading wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,17 @@ import org.junit.Test; */ @SmallTest public class CredentialTest { /** * Helper function for generating Credential for testing. * * @param userCred Instance of UserCredential * @param certCred Instance of CertificateCredential * @param simCred Instance of SimCredential * @param caCert CA certificate * @param clientCertificateChain Chain of client certificates * @param clientPrivateKey Client private key * @return {@link Credential} */ private static Credential createCredential(Credential.UserCredential userCred, Credential.CertificateCredential certCred, Credential.SimCredential simCred, Loading @@ -44,7 +55,10 @@ public class CredentialTest { X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey) { Credential cred = new Credential(); cred.creationTimeInMs = 123455L; cred.expirationTimeInMs = 2310093L; cred.realm = "realm"; cred.checkAAAServerCertStatus = true; cred.userCredential = userCred; cred.certCredential = certCred; cred.simCredential = simCred; Loading @@ -54,6 +68,11 @@ public class CredentialTest { return cred; } /** * Helper function for generating certificate credential for testing. * * @return {@link Credential} */ private static Credential createCredentialWithCertificateCredential() { Credential.CertificateCredential certCred = new Credential.CertificateCredential(); certCred.certType = "x509v3"; Loading @@ -62,6 +81,11 @@ public class CredentialTest { new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1); } /** * Helper function for generating SIM credential for testing. * * @return {@link Credential} */ private static Credential createCredentialWithSimCredential() { Credential.SimCredential simCred = new Credential.SimCredential(); simCred.imsi = "1234*"; Loading @@ -69,10 +93,18 @@ public class CredentialTest { return createCredential(null, null, simCred, null, null, null); } /** * Helper function for generating user credential for testing. * * @return {@link Credential} */ private static Credential createCredentialWithUserCredential() { Credential.UserCredential userCred = new Credential.UserCredential(); userCred.username = "username"; userCred.password = "password"; userCred.machineManaged = true; userCred.ableToShare = true; userCred.softTokenApp = "TestApp"; userCred.eapType = EAPConstants.EAP_TTLS; userCred.nonEapInnerMethod = "MS-CHAP"; return createCredential(userCred, null, null, FakeKeys.CA_CERT0, Loading Loading
wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java +58 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ import android.util.Log; import android.util.Pair; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; Loading Loading @@ -147,11 +150,21 @@ public final class PPSMOParser { * Fields under Credential subtree. */ private static final String NODE_CREDENTIAL = "Credential"; private static final String NODE_CREATION_DATE = "CreationDate"; private static final String NODE_EXPIRATION_DATE = "ExpirationDate"; private static final String NODE_USERNAME_PASSWORD = "UsernamePassword"; private static final String NODE_USERNAME = "Username"; private static final String NODE_PASSWORD = "Password"; private static final String NODE_MACHINE_MANAGED = "MachineManaged"; private static final String NODE_SOFT_TOKEN_APP = "SoftTokenApp"; private static final String NODE_ABLE_TO_SHARE = "AbleToShare"; private static final String NODE_EAP_METHOD = "EAPMethod"; private static final String NODE_EAP_TYPE = "EAPType"; private static final String NODE_VENDOR_ID = "VendorId"; private static final String NODE_VENDOR_TYPE = "VendorType"; private static final String NODE_INNER_EAP_TYPE = "InnerEAPType"; private static final String NODE_INNER_VENDOR_ID = "InnerVendorID"; private static final String NODE_INNER_VENDOR_TYPE = "InnerVendorType"; private static final String NODE_INNER_METHOD = "InnerMethod"; private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate"; private static final String NODE_CERTIFICATE_TYPE = "CertificateType"; Loading @@ -159,6 +172,7 @@ public final class PPSMOParser { private static final String NODE_REALM = "Realm"; private static final String NODE_SIM = "SIM"; private static final String NODE_SIM_IMSI = "IMSI"; private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus"; /** * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree. Loading Loading @@ -812,6 +826,12 @@ public final class PPSMOParser { Credential credential = new Credential(); for (PPSNode child: node.getChildren()) { switch (child.getName()) { case NODE_CREATION_DATE: credential.creationTimeInMs = parseDate(getPpsNodeValue(child)); break; case NODE_EXPIRATION_DATE: credential.expirationTimeInMs = parseDate(getPpsNodeValue(child)); break; case NODE_USERNAME_PASSWORD: credential.userCredential = parseUserCredential(child); break; Loading @@ -821,6 +841,10 @@ public final class PPSMOParser { case NODE_REALM: credential.realm = getPpsNodeValue(child); break; case NODE_CHECK_AAA_SERVER_CERT_STATUS: credential.checkAAAServerCertStatus = Boolean.parseBoolean(getPpsNodeValue(child)); break; case NODE_SIM: credential.simCredential = parseSimCredential(child); break; Loading Loading @@ -855,6 +879,15 @@ public final class PPSMOParser { case NODE_PASSWORD: userCred.password = getPpsNodeValue(child); break; case NODE_MACHINE_MANAGED: userCred.machineManaged = Boolean.parseBoolean(getPpsNodeValue(child)); break; case NODE_SOFT_TOKEN_APP: userCred.softTokenApp = getPpsNodeValue(child); break; case NODE_ABLE_TO_SHARE: userCred.ableToShare = Boolean.parseBoolean(getPpsNodeValue(child)); break; case NODE_EAP_METHOD: parseEAPMethod(child, userCred); break; Loading Loading @@ -889,6 +922,15 @@ public final class PPSMOParser { case NODE_INNER_METHOD: userCred.nonEapInnerMethod = getPpsNodeValue(child); break; case NODE_VENDOR_ID: case NODE_VENDOR_TYPE: case NODE_INNER_EAP_TYPE: case NODE_INNER_VENDOR_ID: case NODE_INNER_VENDOR_TYPE: // Only EAP-TTLS is currently supported for user credential, which doesn't // use any of these parameters. Log.d(TAG, "Ignore unsupported EAP method parameter: " + child.getName()); break; default: throw new ParsingException("Unknown node under EAPMethod: " + child.getName()); } Loading Loading @@ -980,6 +1022,22 @@ public final class PPSMOParser { return result; } /** * Convert a date string to the number of milliseconds since January 1, 1970, 00:00:00 GMT. * * @param dateStr String in the format of yyyy-MM-dd'T'HH:mm:ss'Z' * @return number of milliseconds * @throws ParsingException */ private static long parseDate(String dateStr) throws ParsingException { try { DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); return format.parse(dateStr).getTime(); } catch (ParseException pe) { throw new ParsingException("Badly formatted time: " + dateStr); } } /** * Parse an integer string. * Loading
wifi/java/android/net/wifi/hotspot2/pps/Credential.java +95 −33 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Parcel; import android.text.TextUtils; import android.util.Log; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; Loading @@ -41,8 +42,6 @@ import java.util.Set; * In addition to the fields in the Credential subtree, this will also maintain necessary * information for the private key and certificates associated with this credential. * * Currently we only support the nodes that are used by Hotspot 2.0 Release 1. * * @hide */ public final class Credential implements Parcelable { Loading @@ -52,7 +51,21 @@ public final class Credential implements Parcelable { * Max string length for realm. Refer to Credential/Realm node in Hotspot 2.0 Release 2 * Technical Specification Section 9.1 for more info. */ private static final int MAX_REALM_LENGTH = 253; private static final int MAX_REALM_BYTES = 253; /** * The time this credential is created. It is in the format of number * of milliseconds since January 1, 1970, 00:00:00 GMT. * Using Long.MIN_VALUE to indicate unset value. */ public long creationTimeInMs = Long.MIN_VALUE; /** * The time this credential will expire. It is in the format of number * of milliseconds since January 1, 1970, 00:00:00 GMT. * Using Long.MIN_VALUE to indicate unset value. */ public long expirationTimeInMs = Long.MIN_VALUE; /** * The realm associated with this credential. It will be used to determine Loading @@ -61,6 +74,13 @@ public final class Credential implements Parcelable { */ public String realm = null; /** * When set to true, the device should check AAA (Authentication, Authorization, * and Accounting) server's certificate during EAP (Extensible Authentication * Protocol) authentication. */ public boolean checkAAAServerCertStatus = false; /** * Username-password based credential. * Contains the fields under PerProviderSubscription/Credential/UsernamePassword subtree. Loading @@ -70,13 +90,13 @@ public final class Credential implements Parcelable { * Maximum string length for username. Refer to Credential/UsernamePassword/Username * node in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info. */ private static final int MAX_USERNAME_LENGTH = 63; private static final int MAX_USERNAME_BYTES = 63; /** * Maximum string length for password. Refer to Credential/UsernamePassword/Password * in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info. */ private static final int MAX_PASSWORD_LENGTH = 255; private static final int MAX_PASSWORD_BYTES = 255; /** * Supported Non-EAP inner methods. Refer to Loading @@ -96,6 +116,21 @@ public final class Credential implements Parcelable { */ public String password = null; /** * Flag indicating if the password is machine managed. */ public boolean machineManaged = false; /** * The name of the application used to generate the password. */ public String softTokenApp = null; /** * Flag indicating if this credential is usable on other mobile devices as well. */ public boolean ableToShare = false; /** * EAP (Extensible Authentication Protocol) method type. * Refer to http://www.iana.org/assignments/eap-numbers/eap-numbers.xml#eap-numbers-4 Loading Loading @@ -123,6 +158,9 @@ public final class Credential implements Parcelable { if (source != null) { username = source.username; password = source.password; machineManaged = source.machineManaged; softTokenApp = source.softTokenApp; ableToShare = source.ableToShare; eapType = source.eapType; nonEapInnerMethod = source.nonEapInnerMethod; } Loading @@ -137,6 +175,9 @@ public final class Credential implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(username); dest.writeString(password); dest.writeInt(machineManaged ? 1 : 0); dest.writeString(softTokenApp); dest.writeInt(ableToShare ? 1 : 0); dest.writeInt(eapType); dest.writeString(nonEapInnerMethod); } Loading @@ -151,10 +192,13 @@ public final class Credential implements Parcelable { } UserCredential that = (UserCredential) thatObject; return TextUtils.equals(username, that.username) && TextUtils.equals(password, that.password) && eapType == that.eapType && TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod); return TextUtils.equals(username, that.username) && TextUtils.equals(password, that.password) && machineManaged == that.machineManaged && TextUtils.equals(softTokenApp, that.softTokenApp) && ableToShare == that.ableToShare && eapType == that.eapType && TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod); } /** Loading @@ -167,8 +211,9 @@ public final class Credential implements Parcelable { Log.d(TAG, "Missing username"); return false; } if (username.length() > MAX_USERNAME_LENGTH) { Log.d(TAG, "username exceeding maximum length: " + username.length()); if (username.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) { Log.d(TAG, "username exceeding maximum length: " + username.getBytes(StandardCharsets.UTF_8).length); return false; } Loading @@ -176,8 +221,9 @@ public final class Credential implements Parcelable { Log.d(TAG, "Missing password"); return false; } if (password.length() > MAX_PASSWORD_LENGTH) { Log.d(TAG, "password exceeding maximum length: " + password.length()); if (password.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) { Log.d(TAG, "password exceeding maximum length: " + password.getBytes(StandardCharsets.UTF_8).length); return false; } Loading @@ -202,6 +248,9 @@ public final class Credential implements Parcelable { UserCredential userCredential = new UserCredential(); userCredential.username = in.readString(); userCredential.password = in.readString(); userCredential.machineManaged = in.readInt() != 0; userCredential.softTokenApp = in.readString(); userCredential.ableToShare = in.readInt() != 0; userCredential.eapType = in.readInt(); userCredential.nonEapInnerMethod = in.readString(); return userCredential; Loading Loading @@ -281,8 +330,8 @@ public final class Credential implements Parcelable { } CertificateCredential that = (CertificateCredential) thatObject; return TextUtils.equals(certType, that.certType) && Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint); return TextUtils.equals(certType, that.certType) && Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint); } /** Loading @@ -295,8 +344,8 @@ public final class Credential implements Parcelable { Log.d(TAG, "Unsupported certificate type: " + certType); return false; } if (certSha256FingerPrint == null || certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) { if (certSha256FingerPrint == null || certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) { Log.d(TAG, "Invalid SHA-256 fingerprint"); return false; } Loading Loading @@ -378,8 +427,8 @@ public final class Credential implements Parcelable { } SimCredential that = (SimCredential) thatObject; return TextUtils.equals(imsi, that.imsi) && eapType == that.eapType; return TextUtils.equals(imsi, that.imsi) && eapType == that.eapType; } @Override Loading @@ -400,8 +449,8 @@ public final class Credential implements Parcelable { if (!verifyImsi()) { return false; } if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA && eapType != EAPConstants.EAP_AKA_PRIME) { if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA && eapType != EAPConstants.EAP_AKA_PRIME) { Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType); return false; } Loading Loading @@ -490,7 +539,10 @@ public final class Credential implements Parcelable { */ public Credential(Credential source) { if (source != null) { creationTimeInMs = source.creationTimeInMs; expirationTimeInMs = source.expirationTimeInMs; realm = source.realm; checkAAAServerCertStatus = source.checkAAAServerCertStatus; if (source.userCredential != null) { userCredential = new UserCredential(source.userCredential); } Loading @@ -516,7 +568,10 @@ public final class Credential implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(creationTimeInMs); dest.writeLong(expirationTimeInMs); dest.writeString(realm); dest.writeInt(checkAAAServerCertStatus ? 1 : 0); dest.writeParcelable(userCredential, flags); dest.writeParcelable(certCredential, flags); dest.writeParcelable(simCredential, flags); Loading @@ -535,16 +590,19 @@ public final class Credential implements Parcelable { } Credential that = (Credential) thatObject; return TextUtils.equals(realm, that.realm) && (userCredential == null ? that.userCredential == null : userCredential.equals(that.userCredential)) && (certCredential == null ? that.certCredential == null : certCredential.equals(that.certCredential)) && (simCredential == null ? that.simCredential == null : simCredential.equals(that.simCredential)) && isX509CertificateEquals(caCertificate, that.caCertificate) && isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain) && isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey); return TextUtils.equals(realm, that.realm) && creationTimeInMs == that.creationTimeInMs && expirationTimeInMs == that.expirationTimeInMs && checkAAAServerCertStatus == that.checkAAAServerCertStatus && (userCredential == null ? that.userCredential == null : userCredential.equals(that.userCredential)) && (certCredential == null ? that.certCredential == null : certCredential.equals(that.certCredential)) && (simCredential == null ? that.simCredential == null : simCredential.equals(that.simCredential)) && isX509CertificateEquals(caCertificate, that.caCertificate) && isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain) && isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey); } /** Loading @@ -557,8 +615,9 @@ public final class Credential implements Parcelable { Log.d(TAG, "Missing realm"); return false; } if (realm.length() > MAX_REALM_LENGTH) { Log.d(TAG, "realm exceeding maximum length: " + realm.length()); if (realm.getBytes(StandardCharsets.UTF_8).length > MAX_REALM_BYTES) { Log.d(TAG, "realm exceeding maximum length: " + realm.getBytes(StandardCharsets.UTF_8).length); return false; } Loading Loading @@ -588,7 +647,10 @@ public final class Credential implements Parcelable { @Override public Credential createFromParcel(Parcel in) { Credential credential = new Credential(); credential.creationTimeInMs = in.readLong(); credential.expirationTimeInMs = in.readLong(); credential.realm = in.readString(); credential.checkAAAServerCertStatus = in.readInt() != 0; credential.userCredential = in.readParcelable(null); credential.certCredential = in.readParcelable(null); credential.simCredential = in.readParcelable(null); Loading
wifi/tests/assets/pps/PerProviderSubscription.xml +24 −0 Original line number Diff line number Diff line Loading @@ -86,10 +86,22 @@ </Node> <Node> <NodeName>Credential</NodeName> <Node> <NodeName>CreationDate</NodeName> <Value>2016-01-01T10:00:00Z</Value> </Node> <Node> <NodeName>ExpirationDate</NodeName> <Value>2016-02-01T10:00:00Z</Value> </Node> <Node> <NodeName>Realm</NodeName> <Value>shaken.stirred.com</Value> </Node> <Node> <NodeName>CheckAAAServerCertStatus</NodeName> <Value>true</Value> </Node> <Node> <NodeName>UsernamePassword</NodeName> <Node> Loading @@ -100,6 +112,18 @@ <NodeName>Password</NodeName> <Value>Ym9uZDAwNw==</Value> </Node> <Node> <NodeName>MachineManaged</NodeName> <Value>true</Value> </Node> <Node> <NodeName>SoftTokenApp</NodeName> <Value>TestApp</Value> </Node> <Node> <NodeName>AbleToShare</NodeName> <Value>true</Value> </Node> <Node> <NodeName>EAPMethod</NodeName> <Node> Loading
wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java +10 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.HashMap; Loading Loading @@ -78,7 +80,7 @@ public class PPSMOParserTest { * * @return {@link PasspointConfiguration} */ private PasspointConfiguration generateConfigurationFromPPSMOTree() { private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception { PasspointConfiguration config = new PasspointConfiguration(); // HomeSP configuration. Loading @@ -95,11 +97,18 @@ public class PPSMOParserTest { config.homeSp.otherHomePartners = new String[] {"other.fqdn.com"}; // Credential configuration. DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); config.credential = new Credential(); config.credential.creationTimeInMs = format.parse("2016-01-01T10:00:00Z").getTime(); config.credential.expirationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime(); config.credential.realm = "shaken.stirred.com"; config.credential.checkAAAServerCertStatus = true; config.credential.userCredential = new Credential.UserCredential(); config.credential.userCredential.username = "james"; config.credential.userCredential.password = "Ym9uZDAwNw=="; config.credential.userCredential.machineManaged = true; config.credential.userCredential.softTokenApp = "TestApp"; config.credential.userCredential.ableToShare = true; config.credential.userCredential.eapType = 21; config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2"; config.credential.certCredential = new Credential.CertificateCredential(); Loading
wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,17 @@ import org.junit.Test; */ @SmallTest public class CredentialTest { /** * Helper function for generating Credential for testing. * * @param userCred Instance of UserCredential * @param certCred Instance of CertificateCredential * @param simCred Instance of SimCredential * @param caCert CA certificate * @param clientCertificateChain Chain of client certificates * @param clientPrivateKey Client private key * @return {@link Credential} */ private static Credential createCredential(Credential.UserCredential userCred, Credential.CertificateCredential certCred, Credential.SimCredential simCred, Loading @@ -44,7 +55,10 @@ public class CredentialTest { X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey) { Credential cred = new Credential(); cred.creationTimeInMs = 123455L; cred.expirationTimeInMs = 2310093L; cred.realm = "realm"; cred.checkAAAServerCertStatus = true; cred.userCredential = userCred; cred.certCredential = certCred; cred.simCredential = simCred; Loading @@ -54,6 +68,11 @@ public class CredentialTest { return cred; } /** * Helper function for generating certificate credential for testing. * * @return {@link Credential} */ private static Credential createCredentialWithCertificateCredential() { Credential.CertificateCredential certCred = new Credential.CertificateCredential(); certCred.certType = "x509v3"; Loading @@ -62,6 +81,11 @@ public class CredentialTest { new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1); } /** * Helper function for generating SIM credential for testing. * * @return {@link Credential} */ private static Credential createCredentialWithSimCredential() { Credential.SimCredential simCred = new Credential.SimCredential(); simCred.imsi = "1234*"; Loading @@ -69,10 +93,18 @@ public class CredentialTest { return createCredential(null, null, simCred, null, null, null); } /** * Helper function for generating user credential for testing. * * @return {@link Credential} */ private static Credential createCredentialWithUserCredential() { Credential.UserCredential userCred = new Credential.UserCredential(); userCred.username = "username"; userCred.password = "password"; userCred.machineManaged = true; userCred.ableToShare = true; userCred.softTokenApp = "TestApp"; userCred.eapType = EAPConstants.EAP_TTLS; userCred.nonEapInnerMethod = "MS-CHAP"; return createCredential(userCred, null, null, FakeKeys.CA_CERT0, Loading