Merge "wifi: hotspot2: add support for validating passpoint configuration"
am: ebb722d04a
Change-Id: Ic20a77103961bd9ff61b6af90130c25ad19c451a
This commit is contained in:
@@ -61,6 +61,21 @@ public final class PasspointConfiguration implements Parcelable {
|
||||
credential.equals(that.credential));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration data.
|
||||
*
|
||||
* @return true on success or false on failure
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (homeSp == null || !homeSp.validate()) {
|
||||
return false;
|
||||
}
|
||||
if (credential == null || !credential.validate()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<PasspointConfiguration> CREATOR =
|
||||
new Creator<PasspointConfiguration>() {
|
||||
@Override
|
||||
|
||||
@@ -16,15 +16,21 @@
|
||||
|
||||
package android.net.wifi.hotspot2.pps;
|
||||
|
||||
import android.net.wifi.EAPConstants;
|
||||
import android.net.wifi.ParcelUtil;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class representing Credential subtree in the PerProviderSubscription (PPS)
|
||||
@@ -40,6 +46,14 @@ import java.util.Arrays;
|
||||
* @hide
|
||||
*/
|
||||
public final class Credential implements Parcelable {
|
||||
private static final String TAG = "Credential";
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The realm associated with this credential. It will be used to determine
|
||||
* if this credential can be used to authenticate with a given hotspot by
|
||||
@@ -52,6 +66,26 @@ public final class Credential implements Parcelable {
|
||||
* Contains the fields under PerProviderSubscription/Credential/UsernamePassword subtree.
|
||||
*/
|
||||
public static final class UserCredential 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Supported Non-EAP inner methods. Refer to
|
||||
* Credential/UsernamePassword/EAPMethod/InnerEAPType in Hotspot 2.0 Release 2 Technical
|
||||
* Specification Section 9.1 for more info.
|
||||
*/
|
||||
private static final Set<String> SUPPORTED_AUTH =
|
||||
new HashSet<String>(Arrays.asList("PAP", "CHAP", "MS-CHAP", "MS-CHAP-V2"));
|
||||
|
||||
/**
|
||||
* Username of the credential.
|
||||
*/
|
||||
@@ -104,6 +138,44 @@ public final class Credential implements Parcelable {
|
||||
TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration data.
|
||||
*
|
||||
* @return true on success or false on failure
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (TextUtils.isEmpty(username)) {
|
||||
Log.d(TAG, "Missing username");
|
||||
return false;
|
||||
}
|
||||
if (username.length() > MAX_USERNAME_LENGTH) {
|
||||
Log.d(TAG, "username exceeding maximum length: " + username.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(password)) {
|
||||
Log.d(TAG, "Missing password");
|
||||
return false;
|
||||
}
|
||||
if (password.length() > MAX_PASSWORD_LENGTH) {
|
||||
Log.d(TAG, "password exceeding maximum length: " + password.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only supports EAP-TTLS for user credential.
|
||||
if (eapType != EAPConstants.EAP_TTLS) {
|
||||
Log.d(TAG, "Invalid EAP Type for user credential: " + eapType);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify Non-EAP inner method for EAP-TTLS.
|
||||
if (!SUPPORTED_AUTH.contains(nonEapInnerMethod)) {
|
||||
Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + nonEapInnerMethod);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<UserCredential> CREATOR =
|
||||
new Creator<UserCredential>() {
|
||||
@Override
|
||||
@@ -125,12 +197,22 @@ public final class Credential implements Parcelable {
|
||||
public UserCredential userCredential = null;
|
||||
|
||||
/**
|
||||
* Certificate based credential.
|
||||
* Certificate based credential. This is used for EAP-TLS.
|
||||
* Contains fields under PerProviderSubscription/Credential/DigitalCertificate subtree.
|
||||
*/
|
||||
public static final class CertificateCredential implements Parcelable {
|
||||
/**
|
||||
* Certificate type. Valid values are "802.1ar" and "x509v3".
|
||||
* Supported certificate types.
|
||||
*/
|
||||
private static final String CERT_TYPE_X509V3 = "x509v3";
|
||||
|
||||
/**
|
||||
* Certificate SHA-256 fingerprint length.
|
||||
*/
|
||||
private static final int CERT_SHA256_FINGER_PRINT_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* Certificate type.
|
||||
*/
|
||||
public String certType = null;
|
||||
|
||||
@@ -164,6 +246,24 @@ public final class Credential implements Parcelable {
|
||||
Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration data.
|
||||
*
|
||||
* @return true on success or false on failure
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (!TextUtils.equals(CERT_TYPE_X509V3, certType)) {
|
||||
Log.d(TAG, "Unsupported certificate type: " + certType);
|
||||
return false;
|
||||
}
|
||||
if (certSha256FingerPrint == null ||
|
||||
certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
|
||||
Log.d(TAG, "Invalid SHA-256 fingerprint");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<CertificateCredential> CREATOR =
|
||||
new Creator<CertificateCredential>() {
|
||||
@Override
|
||||
@@ -188,7 +288,14 @@ public final class Credential implements Parcelable {
|
||||
*/
|
||||
public static final class SimCredential implements Parcelable {
|
||||
/**
|
||||
* International Mobile device Subscriber Identity.
|
||||
* Maximum string length for IMSI.
|
||||
*/
|
||||
public static final int MAX_IMSI_LENGTH = 15;
|
||||
|
||||
/**
|
||||
* International Mobile Subscriber Identity, is used to identify the user
|
||||
* of a cellular network and is a unique identification associated with all
|
||||
* cellular networks
|
||||
*/
|
||||
public String imsi = null;
|
||||
|
||||
@@ -225,6 +332,26 @@ public final class Credential implements Parcelable {
|
||||
dest.writeInt(eapType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration data.
|
||||
*
|
||||
* @return true on success or false on failure
|
||||
*/
|
||||
public boolean validate() {
|
||||
// Note: this only validate the format of IMSI string itself. Additional verification
|
||||
// will be done by WifiService at the time of provisioning to verify against the IMSI
|
||||
// of the SIM card installed in the device.
|
||||
if (!verifyImsi()) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<SimCredential> CREATOR =
|
||||
new Creator<SimCredential>() {
|
||||
@Override
|
||||
@@ -240,6 +367,43 @@ public final class Credential implements Parcelable {
|
||||
return new SimCredential[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify the IMSI (International Mobile Subscriber Identity) string. The string
|
||||
* should contain zero or more numeric digits, and might ends with a "*" for prefix
|
||||
* matching.
|
||||
*
|
||||
* @return true if IMSI is valid, false otherwise.
|
||||
*/
|
||||
private boolean verifyImsi() {
|
||||
if (TextUtils.isEmpty(imsi)) {
|
||||
Log.d(TAG, "Missing IMSI");
|
||||
return false;
|
||||
}
|
||||
if (imsi.length() > MAX_IMSI_LENGTH) {
|
||||
Log.d(TAG, "IMSI exceeding maximum length: " + imsi.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Locate the first non-digit character.
|
||||
int nonDigit;
|
||||
char stopChar = '\0';
|
||||
for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
|
||||
stopChar = imsi.charAt(nonDigit);
|
||||
if (stopChar < '0' || stopChar > '9') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nonDigit == imsi.length()) {
|
||||
return true;
|
||||
}
|
||||
else if (nonDigit == imsi.length()-1 && stopChar == '*') {
|
||||
// Prefix matching.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public SimCredential simCredential = null;
|
||||
|
||||
@@ -296,6 +460,42 @@ public final class Credential implements Parcelable {
|
||||
isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration data.
|
||||
*
|
||||
* @return true on success or false on failure
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (TextUtils.isEmpty(realm)) {
|
||||
Log.d(TAG, "Missing realm");
|
||||
return false;
|
||||
}
|
||||
if (realm.length() > MAX_REALM_LENGTH) {
|
||||
Log.d(TAG, "realm exceeding maximum length: " + realm.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the credential.
|
||||
if (userCredential != null) {
|
||||
if (!verifyUserCredential()) {
|
||||
return false;
|
||||
}
|
||||
} else if (certCredential != null) {
|
||||
if (!verifyCertCredential()) {
|
||||
return false;
|
||||
}
|
||||
} else if (simCredential != null) {
|
||||
if (!verifySimCredential()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Missing required credential");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<Credential> CREATOR =
|
||||
new Creator<Credential>() {
|
||||
@Override
|
||||
@@ -317,6 +517,91 @@ public final class Credential implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify user credential.
|
||||
*
|
||||
* @return true if user credential is valid, false otherwise.
|
||||
*/
|
||||
private boolean verifyUserCredential() {
|
||||
if (userCredential == null) {
|
||||
Log.d(TAG, "Missing user credential");
|
||||
return false;
|
||||
}
|
||||
if (certCredential != null || simCredential != null) {
|
||||
Log.d(TAG, "Contained more than one type of credential");
|
||||
return false;
|
||||
}
|
||||
if (!userCredential.validate()) {
|
||||
return false;
|
||||
}
|
||||
if (caCertificate == null) {
|
||||
Log.d(TAG, "Missing CA Certificate for user credential");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify certificate credential, which is used for EAP-TLS. This will verify
|
||||
* that the necessary client key and certificates are provided.
|
||||
*
|
||||
* @return true if certificate credential is valid, false otherwise.
|
||||
*/
|
||||
private boolean verifyCertCredential() {
|
||||
if (certCredential == null) {
|
||||
Log.d(TAG, "Missing certificate credential");
|
||||
return false;
|
||||
}
|
||||
if (userCredential != null || simCredential != null) {
|
||||
Log.d(TAG, "Contained more than one type of credential");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!certCredential.validate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify required key and certificates for certificate credential.
|
||||
if (caCertificate == null) {
|
||||
Log.d(TAG, "Missing CA Certificate for certificate credential");
|
||||
return false;
|
||||
}
|
||||
if (clientPrivateKey == null) {
|
||||
Log.d(TAG, "Missing client private key for certificate credential");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
// Verify SHA-256 fingerprint for client certificate.
|
||||
if (!verifySha256Fingerprint(clientCertificateChain,
|
||||
certCredential.certSha256FingerPrint)) {
|
||||
Log.d(TAG, "SHA-256 fingerprint mismatch");
|
||||
return false;
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
|
||||
Log.d(TAG, "Failed to verify SHA-256 fingerprint: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify SIM credential.
|
||||
*
|
||||
* @return true if SIM credential is valid, false otherwise.
|
||||
*/
|
||||
private boolean verifySimCredential() {
|
||||
if (simCredential == null) {
|
||||
Log.d(TAG, "Missing SIM credential");
|
||||
return false;
|
||||
}
|
||||
if (userCredential != null || certCredential != null) {
|
||||
Log.d(TAG, "Contained more than one type of credential");
|
||||
return false;
|
||||
}
|
||||
return simCredential.validate();
|
||||
}
|
||||
|
||||
private static boolean isPrivateKeyEquals(PrivateKey key1, PrivateKey key2) {
|
||||
if (key1 == null && key2 == null) {
|
||||
return true;
|
||||
@@ -373,4 +658,31 @@ public final class Credential implements Parcelable {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the digest for a certificate in the certificate chain matches expected
|
||||
* fingerprint. The certificate that matches the fingerprint is the client certificate.
|
||||
*
|
||||
* @param certChain Chain of certificates
|
||||
* @param expectedFingerprint The expected SHA-256 digest of the client certificate
|
||||
* @return true if the certificate chain contains a matching certificate, false otherwise
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws CertificateEncodingException
|
||||
*/
|
||||
private static boolean verifySha256Fingerprint(X509Certificate[] certChain,
|
||||
byte[] expectedFingerprint)
|
||||
throws NoSuchAlgorithmException, CertificateEncodingException {
|
||||
if (certChain == null) {
|
||||
return false;
|
||||
}
|
||||
MessageDigest digester = MessageDigest.getInstance("SHA-256");
|
||||
for (X509Certificate certificate : certChain) {
|
||||
digester.reset();
|
||||
byte[] fingerprint = digester.digest(certificate.getEncoded());
|
||||
if (Arrays.equals(expectedFingerprint, fingerprint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.net.wifi.hotspot2.pps;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -34,6 +35,8 @@ import java.util.Arrays;
|
||||
* @hide
|
||||
*/
|
||||
public final class HomeSP implements Parcelable {
|
||||
private static final String TAG = "HomeSP";
|
||||
|
||||
/**
|
||||
* FQDN (Fully Qualified Domain Name) of this home service provider.
|
||||
*/
|
||||
@@ -77,6 +80,23 @@ public final class HomeSP implements Parcelable {
|
||||
Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate HomeSP data.
|
||||
*
|
||||
* @return true on success or false on failure
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (TextUtils.isEmpty(fqdn)) {
|
||||
Log.d(TAG, "Missing FQDN");
|
||||
return false;
|
||||
}
|
||||
if (TextUtils.isEmpty(friendlyName)) {
|
||||
Log.d(TAG, "Missing friendly name");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<HomeSP> CREATOR =
|
||||
new Creator<HomeSP>() {
|
||||
@Override
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package android.net.wifi.hotspot2;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.net.wifi.EAPConstants;
|
||||
import android.net.wifi.hotspot2.pps.Credential;
|
||||
import android.net.wifi.hotspot2.pps.HomeSP;
|
||||
import android.os.Parcel;
|
||||
@@ -44,7 +46,9 @@ public class PasspointConfigurationTest {
|
||||
cred.realm = "realm";
|
||||
cred.userCredential = null;
|
||||
cred.certCredential = null;
|
||||
cred.simCredential = null;
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.imsi = "1234*";
|
||||
cred.simCredential.eapType = EAPConstants.EAP_SIM;
|
||||
cred.caCertificate = null;
|
||||
cred.clientCertificateChain = null;
|
||||
cred.clientPrivateKey = null;
|
||||
@@ -61,11 +65,20 @@ public class PasspointConfigurationTest {
|
||||
assertTrue(readConfig.equals(writeConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a default configuration.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithDefault() throws Exception {
|
||||
verifyParcel(new PasspointConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a configuration that contained both HomeSP and Credential.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithHomeSPAndCredential() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
@@ -74,6 +87,11 @@ public class PasspointConfigurationTest {
|
||||
verifyParcel(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a configuration that contained only HomeSP.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithHomeSPOnly() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
@@ -81,10 +99,63 @@ public class PasspointConfigurationTest {
|
||||
verifyParcel(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a configuration that contained only Credential.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithCredentialOnly() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.credential = createCredential();
|
||||
verifyParcel(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a default/empty configuration is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateDefaultConfig() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
assertFalse(config.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a configuration without Credential is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateConfigWithoutCredential() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = createHomeSp();
|
||||
assertFalse(config.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a a configuration without HomeSP is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateConfigWithoutHomeSp() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.credential = createCredential();
|
||||
assertFalse(config.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a valid configuration.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateValidConfig() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = createHomeSp();
|
||||
config.credential = createCredential();
|
||||
assertTrue(config.validate());
|
||||
}
|
||||
}
|
||||
@@ -16,14 +16,19 @@
|
||||
|
||||
package android.net.wifi.hotspot2.pps;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.net.wifi.EAPConstants;
|
||||
import android.net.wifi.FakeKeys;
|
||||
import android.os.Parcel;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Log;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -52,15 +57,15 @@ public class CredentialTest {
|
||||
private static Credential createCredentialWithCertificateCredential() {
|
||||
Credential.CertificateCredential certCred = new Credential.CertificateCredential();
|
||||
certCred.certType = "x509v3";
|
||||
certCred.certSha256FingerPrint = new byte[256];
|
||||
certCred.certSha256FingerPrint = new byte[32];
|
||||
return createCredential(null, certCred, null, FakeKeys.CA_CERT0,
|
||||
new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
|
||||
}
|
||||
|
||||
private static Credential createCredentialWithSimCredential() {
|
||||
Credential.SimCredential simCred = new Credential.SimCredential();
|
||||
simCred.imsi = "imsi";
|
||||
simCred.eapType = 1;
|
||||
simCred.imsi = "1234*";
|
||||
simCred.eapType = EAPConstants.EAP_SIM;
|
||||
return createCredential(null, null, simCred, null, null, null);
|
||||
}
|
||||
|
||||
@@ -68,7 +73,7 @@ public class CredentialTest {
|
||||
Credential.UserCredential userCred = new Credential.UserCredential();
|
||||
userCred.username = "username";
|
||||
userCred.password = "password";
|
||||
userCred.eapType = 1;
|
||||
userCred.eapType = EAPConstants.EAP_TTLS;
|
||||
userCred.nonEapInnerMethod = "MS-CHAP";
|
||||
return createCredential(userCred, null, null, FakeKeys.CA_CERT0,
|
||||
new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
|
||||
@@ -83,23 +88,386 @@ public class CredentialTest {
|
||||
assertTrue(readCred.equals(writeCred));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a default/empty credential.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithDefault() throws Exception {
|
||||
verifyParcel(new Credential());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a certificate credential.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithCertificateCredential() throws Exception {
|
||||
verifyParcel(createCredentialWithCertificateCredential());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a SIM credential.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithSimCredential() throws Exception {
|
||||
verifyParcel(createCredentialWithSimCredential());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for an user credential.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithUserCredential() throws Exception {
|
||||
verifyParcel(createCredentialWithUserCredential());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a valid user credential.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUserCredential() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.username = "username";
|
||||
cred.userCredential.password = "password";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TTLS;
|
||||
cred.userCredential.nonEapInnerMethod = "MS-CHAP";
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
assertTrue(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an user credential without CA Certificate is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUserCredentialWithoutCaCert() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.username = "username";
|
||||
cred.userCredential.password = "password";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TTLS;
|
||||
cred.userCredential.nonEapInnerMethod = "MS-CHAP";
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an user credential with EAP type other than EAP-TTLS is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUserCredentialWithEapTls() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.username = "username";
|
||||
cred.userCredential.password = "password";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TLS;
|
||||
cred.userCredential.nonEapInnerMethod = "MS-CHAP";
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify that an user credential without realm is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUserCredentialWithoutRealm() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.username = "username";
|
||||
cred.userCredential.password = "password";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TTLS;
|
||||
cred.userCredential.nonEapInnerMethod = "MS-CHAP";
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an user credential without username is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUserCredentialWithoutUsername() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.password = "password";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TTLS;
|
||||
cred.userCredential.nonEapInnerMethod = "MS-CHAP";
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an user credential without password is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUserCredentialWithoutPassword() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.username = "username";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TTLS;
|
||||
cred.userCredential.nonEapInnerMethod = "MS-CHAP";
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an user credential without auth methoh (non-EAP inner method) is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUserCredentialWithoutAuthMethod() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.username = "username";
|
||||
cred.userCredential.password = "password";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TTLS;
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a certificate credential. CA Certificate, client certificate chain,
|
||||
* and client private key are all required. Also the digest for client
|
||||
* certificate must match the fingerprint specified in the certificate credential.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateCertCredential() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup certificate credential.
|
||||
cred.certCredential = new Credential.CertificateCredential();
|
||||
cred.certCredential.certType = "x509v3";
|
||||
cred.certCredential.certSha256FingerPrint =
|
||||
MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
|
||||
// Setup certificates and private key.
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
|
||||
cred.clientPrivateKey = FakeKeys.RSA_KEY1;
|
||||
assertTrue(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an certificate credential without CA Certificate is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void validateCertCredentialWithoutCaCert() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup certificate credential.
|
||||
cred.certCredential = new Credential.CertificateCredential();
|
||||
cred.certCredential.certType = "x509v3";
|
||||
cred.certCredential.certSha256FingerPrint =
|
||||
MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
|
||||
// Setup certificates and private key.
|
||||
cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
|
||||
cred.clientPrivateKey = FakeKeys.RSA_KEY1;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a certificate credential without client certificate chain is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateCertCredentialWithoutClientCertChain() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup certificate credential.
|
||||
cred.certCredential = new Credential.CertificateCredential();
|
||||
cred.certCredential.certType = "x509v3";
|
||||
cred.certCredential.certSha256FingerPrint =
|
||||
MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
|
||||
// Setup certificates and private key.
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
cred.clientPrivateKey = FakeKeys.RSA_KEY1;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a certificate credential without client private key is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateCertCredentialWithoutClientPrivateKey() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup certificate credential.
|
||||
cred.certCredential = new Credential.CertificateCredential();
|
||||
cred.certCredential.certType = "x509v3";
|
||||
cred.certCredential.certSha256FingerPrint =
|
||||
MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
|
||||
// Setup certificates and private key.
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a certificate credential with mismatch client certificate fingerprint
|
||||
* is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateCertCredentialWithMismatchFingerprint() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup certificate credential.
|
||||
cred.certCredential = new Credential.CertificateCredential();
|
||||
cred.certCredential.certType = "x509v3";
|
||||
cred.certCredential.certSha256FingerPrint = new byte[32];
|
||||
Arrays.fill(cred.certCredential.certSha256FingerPrint, (byte)0);
|
||||
// Setup certificates and private key.
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
|
||||
cred.clientPrivateKey = FakeKeys.RSA_KEY1;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a SIM credential using EAP-SIM.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateSimCredentialWithEapSim() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup SIM credential.
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.imsi = "1234*";
|
||||
cred.simCredential.eapType = EAPConstants.EAP_SIM;
|
||||
assertTrue(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a SIM credential using EAP-AKA.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateSimCredentialWithEapAka() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup SIM credential.
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.imsi = "1234*";
|
||||
cred.simCredential.eapType = EAPConstants.EAP_AKA;
|
||||
assertTrue(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a SIM credential using EAP-AKA-PRIME.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateSimCredentialWithEapAkaPrime() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup SIM credential.
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.imsi = "1234*";
|
||||
cred.simCredential.eapType = EAPConstants.EAP_AKA_PRIME;
|
||||
assertTrue(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a SIM credential without IMSI is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateSimCredentialWithoutIMSI() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup SIM credential.
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.eapType = EAPConstants.EAP_SIM;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a SIM credential with an invalid IMSI is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateSimCredentialWithInvalidIMSI() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup SIM credential.
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.imsi = "dummy";
|
||||
cred.simCredential.eapType = EAPConstants.EAP_SIM;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a SIM credential with invalid EAP type is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateSimCredentialWithEapTls() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup SIM credential.
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.imsi = "1234*";
|
||||
cred.simCredential.eapType = EAPConstants.EAP_TLS;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a credential contained both an user and a SIM credential is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateCredentialWithUserAndSimCredential() throws Exception {
|
||||
Credential cred = new Credential();
|
||||
cred.realm = "realm";
|
||||
// Setup user credential with EAP-TTLS.
|
||||
cred.userCredential = new Credential.UserCredential();
|
||||
cred.userCredential.username = "username";
|
||||
cred.userCredential.password = "password";
|
||||
cred.userCredential.eapType = EAPConstants.EAP_TTLS;
|
||||
cred.userCredential.nonEapInnerMethod = "MS-CHAP";
|
||||
cred.caCertificate = FakeKeys.CA_CERT0;
|
||||
// Setup SIM credential.
|
||||
cred.simCredential = new Credential.SimCredential();
|
||||
cred.simCredential.imsi = "1234*";
|
||||
cred.simCredential.eapType = EAPConstants.EAP_SIM;
|
||||
assertFalse(cred.validate());
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,12 @@
|
||||
|
||||
package android.net.wifi.hotspot2.pps;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@@ -47,13 +46,76 @@ public class HomeSPTest {
|
||||
assertTrue(readHomeSp.equals(writeHomeSp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for an empty HomeSP.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithEmptyHomeSP() throws Exception {
|
||||
verifyParcel(new HomeSP());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a valid HomeSP.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithValidHomeSP() throws Exception {
|
||||
verifyParcel(createHomeSp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a HomeSP is valid when both FQDN and Friendly Name
|
||||
* are provided.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateValidHomeSP() throws Exception {
|
||||
HomeSP homeSp = new HomeSP();
|
||||
homeSp.fqdn = "fqdn";
|
||||
homeSp.friendlyName = "friendly name";
|
||||
assertTrue(homeSp.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a HomeSP is not valid when FQDN is not provided
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateHomeSpWithoutFqdn() throws Exception {
|
||||
HomeSP homeSp = new HomeSP();
|
||||
homeSp.friendlyName = "friendly name";
|
||||
assertFalse(homeSp.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a HomeSP is not valid when Friendly Name is not provided
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateHomeSpWithoutFriendlyName() throws Exception {
|
||||
HomeSP homeSp = new HomeSP();
|
||||
homeSp.fqdn = "fqdn";
|
||||
assertFalse(homeSp.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a HomeSP is valid when the optional Roaming Consortium OIs are
|
||||
* provided.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateHomeSpWithRoamingConsoritums() throws Exception {
|
||||
HomeSP homeSp = new HomeSP();
|
||||
homeSp.fqdn = "fqdn";
|
||||
homeSp.friendlyName = "friendly name";
|
||||
homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
|
||||
assertTrue(homeSp.validate());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user