summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Qiu <zqiu@google.com>2016-11-17 15:17:34 -0800
committerPeter Qiu <zqiu@google.com>2016-12-01 09:53:56 -0800
commitae791278c9032a8b10cf818b98b571c0396add4a (patch)
tree49b23f0abb58defdf4e31fc95b5e5d42c131af36
parent818b30de68475ac6a4f55c84f2f279714d915911 (diff)
hotspot2: install Passpoint certificates and keys in keystore
When adding a Passpoint provider, install the certificates and keys specified in the configuration to the keystore. While there, move the object creation for Passpoint related objects out of the WifiInjector and into newly created PasspointObjectFactory. Bug: 32619189 Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I42ee22a31d30e2c9fa05ece8713b95ebea71256e
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java13
-rw-r--r--service/java/com/android/server/wifi/WifiKeyStore.java31
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointManager.java33
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java53
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointProvider.java162
-rw-r--r--tests/wifitests/src/com/android/server/wifi/FakeKeys.java154
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java88
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java152
8 files changed, 659 insertions, 27 deletions
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 3d1356463..fffac5d8a 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -39,8 +39,8 @@ import com.android.internal.R;
import com.android.server.am.BatteryStatsService;
import com.android.server.net.DelayedDiskWrite;
import com.android.server.net.IpConfigStore;
-import com.android.server.wifi.hotspot2.PasspointEventHandler;
import com.android.server.wifi.hotspot2.PasspointManager;
+import com.android.server.wifi.hotspot2.PasspointObjectFactory;
import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.server.wifi.util.WifiPermissionsWrapper;
@@ -170,7 +170,8 @@ public class WifiInjector {
mWifiPermissionsUtil = new WifiPermissionsUtil(mWifiPermissionsWrapper, mContext,
mSettingsStore, UserManager.get(mContext), new NetworkScorerAppManager(mContext));
mSimAccessor = new SIMAccessor(mContext);
- mPasspointManager = new PasspointManager(mContext, this, mSimAccessor);
+ mPasspointManager = new PasspointManager(mContext, mWifiNative, mWifiKeyStore, mClock,
+ mSimAccessor, new PasspointObjectFactory());
}
/**
@@ -331,14 +332,6 @@ public class WifiInjector {
}
/**
- * Create a PasspointEventHandler instance with the given callbacks.
- */
- public PasspointEventHandler makePasspointEventHandler(
- PasspointEventHandler.Callbacks callbacks) {
- return new PasspointEventHandler(mWifiNative, callbacks);
- }
-
- /**
* Obtain an instance of WifiScanner.
* If it was not already created, then obtain an instance. Note, this must be done lazily since
* WifiScannerService is separate and created later.
diff --git a/service/java/com/android/server/wifi/WifiKeyStore.java b/service/java/com/android/server/wifi/WifiKeyStore.java
index f921988a5..b667fd4c9 100644
--- a/service/java/com/android/server/wifi/WifiKeyStore.java
+++ b/service/java/com/android/server/wifi/WifiKeyStore.java
@@ -158,7 +158,14 @@ public class WifiKeyStore {
return ret;
}
- private boolean putCertInKeyStore(String name, Certificate cert) {
+ /**
+ * Install a certificate into the keystore.
+ *
+ * @param name The alias name of the certificate to be installed
+ * @param cert The certificate to be installed
+ * @return true on success
+ */
+ public boolean putCertInKeyStore(String name, Certificate cert) {
try {
byte[] certData = Credentials.convertToPem(cert);
if (mVerboseLoggingEnabled) Log.d(TAG, "putting certificate " + name + " in keystore");
@@ -171,6 +178,28 @@ public class WifiKeyStore {
}
/**
+ * Install a key into the keystore.
+ *
+ * @param name The alias name of the key to be installed
+ * @param key The key to be installed
+ * @return true on success
+ */
+ public boolean putKeyInKeyStore(String name, Key key) {
+ byte[] privKeyData = key.getEncoded();
+ return mKeyStore.importKey(name, privKeyData, Process.WIFI_UID, KeyStore.FLAG_NONE);
+ }
+
+ /**
+ * Remove a certificate or key entry specified by the alias name from the keystore.
+ *
+ * @param name The alias name of the entry to be removed
+ * @return true on success
+ */
+ public boolean removeEntryFromKeyStore(String name) {
+ return mKeyStore.delete(name, Process.WIFI_UID);
+ }
+
+ /**
* Remove enterprise keys from the network config.
*
* @param config Config corresponding to the network.
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index 3e668a76d..d130e012d 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -34,9 +34,11 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import com.android.server.wifi.Clock;
import com.android.server.wifi.IMSIParameter;
import com.android.server.wifi.SIMAccessor;
-import com.android.server.wifi.WifiInjector;
+import com.android.server.wifi.WifiKeyStore;
+import com.android.server.wifi.WifiNative;
import com.android.server.wifi.anqp.ANQPElement;
import com.android.server.wifi.anqp.Constants;
@@ -55,6 +57,9 @@ public class PasspointManager {
private final PasspointEventHandler mHandler;
private final SIMAccessor mSimAccessor;
+ private final WifiKeyStore mKeyStore;
+ private final Clock mClock;
+ private final PasspointObjectFactory mObjectFactory;
private final Map<String, PasspointProvider> mProviders;
private class CallbackHandler implements PasspointEventHandler.Callbacks {
@@ -104,9 +109,14 @@ public class PasspointManager {
}
}
- public PasspointManager(Context context, WifiInjector wifiInjector, SIMAccessor simAccessor) {
- mHandler = wifiInjector.makePasspointEventHandler(new CallbackHandler(context));
+ public PasspointManager(Context context, WifiNative wifiNative, WifiKeyStore keyStore,
+ Clock clock, SIMAccessor simAccessor, PasspointObjectFactory objectFactory) {
+ mHandler = objectFactory.makePasspointEventHandler(wifiNative,
+ new CallbackHandler(context));
+ mKeyStore = keyStore;
+ mClock = clock;
mSimAccessor = simAccessor;
+ mObjectFactory = objectFactory;
mProviders = new HashMap<>();
// TODO(zqiu): load providers from the persistent storage.
}
@@ -144,19 +154,25 @@ public class PasspointManager {
}
}
- // TODO(b/32619189): install new key and certificates to the keystore.
+ // Create a provider and install the necessary certificates and keys.
+ PasspointProvider newProvider = mObjectFactory.makePasspointProvider(
+ config, mKeyStore, mClock.getWallClockMillis());
+
+ if (!newProvider.installCertsAndKeys()) {
+ Log.e(TAG, "Failed to install certificates and keys to keystore");
+ return false;
+ }
// Detect existing configuration in the same base domain.
PasspointProvider existingProvider = findProviderInSameBaseDomain(config.homeSp.fqdn);
if (existingProvider != null) {
Log.d(TAG, "Replacing configuration for " + existingProvider.getConfig().homeSp.fqdn
+ " with " + config.homeSp.fqdn);
- // TODO(b/32619189): Remove existing key and certificates from the keystore.
-
+ existingProvider.uninstallCertsAndKeys();
mProviders.remove(existingProvider.getConfig().homeSp.fqdn);
}
- mProviders.put(config.homeSp.fqdn, new PasspointProvider(config));
+ mProviders.put(config.homeSp.fqdn, newProvider);
// TODO(b/31065385): Persist updated providers configuration to the persistent storage.
@@ -175,8 +191,7 @@ public class PasspointManager {
return false;
}
- // TODO(b/32619189): Remove key and certificates from the keystore.
-
+ mProviders.get(fqdn).uninstallCertsAndKeys();
mProviders.remove(fqdn);
return true;
}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java
new file mode 100644
index 000000000..41ec9fa73
--- /dev/null
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2;
+
+import android.net.wifi.hotspot2.PasspointConfiguration;
+
+import com.android.server.wifi.WifiKeyStore;
+import com.android.server.wifi.WifiNative;
+
+/**
+ * Factory class for creating Passpoint related objects. Useful for mocking object creations
+ * in the unit tests.
+ */
+public class PasspointObjectFactory{
+ /**
+ * Create a PasspointEventHandler instance.
+ *
+ * @param wifiNative Instance of {@link WifiNative}
+ * @param callbacks Instance of {@link PasspointEventHandler.Callbacks}
+ * @return {@link PasspointEventHandler}
+ */
+ public PasspointEventHandler makePasspointEventHandler(WifiNative wifiNative,
+ PasspointEventHandler.Callbacks callbacks) {
+ return new PasspointEventHandler(wifiNative, callbacks);
+ }
+
+ /**
+ * Create a PasspointProvider instance.
+ *
+ * @param keyStore Instance of {@link WifiKeyStore}
+ * @param config Configuration for the provider
+ * @param providerId Unique identifier for the provider
+ * @return {@link PasspointProvider}
+ */
+ public PasspointProvider makePasspointProvider(PasspointConfiguration config,
+ WifiKeyStore keyStore, long providerId) {
+ return new PasspointProvider(config, keyStore, providerId);
+ }
+}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
index 9c38ac725..6d120902a 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
@@ -17,21 +17,181 @@
package com.android.server.wifi.hotspot2;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.security.Credentials;
+import android.util.Log;
+
+import com.android.server.wifi.WifiKeyStore;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
/**
* Abstraction for Passpoint service provider. This class contains the both static
* Passpoint configuration data and the runtime data (e.g. blacklisted SSIDs, statistics).
*/
public class PasspointProvider {
+ private static final String TAG = "PasspointProvider";
+
+ // Prefix for certificates and keys aliases.
+ private static final String ALIAS_PREFIX = "HS2_";
+
private final PasspointConfiguration mConfig;
+ private final WifiKeyStore mKeyStore;
+
+ // Unique identifier for this provider. Used as part of the alias names for identifying
+ // certificates and keys installed on the keystore.
+ private final long mProviderId;
+
+ // Aliases for the private keys and certificates installed in the keystore.
+ private String mCaCertificateAlias;
+ private String mClientPrivateKeyAlias;
+ private String mClientCertificateAlias;
- public PasspointProvider(PasspointConfiguration config) {
+ public PasspointProvider(PasspointConfiguration config, WifiKeyStore keyStore,
+ long providerId) {
// Maintain a copy of the configuration to avoid it being updated by others.
mConfig = new PasspointConfiguration(config);
+ mKeyStore = keyStore;
+ mProviderId = providerId;
}
public PasspointConfiguration getConfig() {
// Return a copy of the configuration to avoid it being updated by others.
return new PasspointConfiguration(mConfig);
}
+
+ public String getCaCertificateAlias() {
+ return mCaCertificateAlias;
+ }
+
+ public String getClientPrivateKeyAlias() {
+ return mClientPrivateKeyAlias;
+ }
+
+ public String getClientCertificateAlias() {
+ return mClientCertificateAlias;
+ }
+
+ /**
+ * Install certificates and key based on current configuration.
+ * Note: the certificates and keys in the configuration will get cleared once
+ * they're installed in the keystore.
+ *
+ * @return true on success
+ */
+ public boolean installCertsAndKeys() {
+ // Install CA certificate.
+ if (mConfig.credential.caCertificate != null) {
+ String alias = formatAliasName(Credentials.CA_CERTIFICATE, mProviderId);
+ if (!mKeyStore.putCertInKeyStore(alias, mConfig.credential.caCertificate)) {
+ Log.e(TAG, "Failed to install CA Certificate");
+ uninstallCertsAndKeys();
+ return false;
+ }
+ mCaCertificateAlias = alias;
+ }
+
+ // Install the client private key.
+ if (mConfig.credential.clientPrivateKey != null) {
+ String alias = formatAliasName(Credentials.USER_PRIVATE_KEY, mProviderId);
+ if (!mKeyStore.putKeyInKeyStore(alias, mConfig.credential.clientPrivateKey)) {
+ Log.e(TAG, "Failed to install client private key");
+ uninstallCertsAndKeys();
+ return false;
+ }
+ mClientPrivateKeyAlias = alias;
+ }
+
+ // Install the client certificate.
+ if (mConfig.credential.clientCertificateChain != null) {
+ X509Certificate clientCert =
+ getClientCertificate(mConfig.credential.clientCertificateChain,
+ mConfig.credential.certCredential.certSha256FingerPrint);
+ if (clientCert == null) {
+ Log.e(TAG, "Failed to locate client certificate");
+ uninstallCertsAndKeys();
+ return false;
+ }
+ String alias = formatAliasName(Credentials.USER_CERTIFICATE, mProviderId);
+ if (!mKeyStore.putCertInKeyStore(alias, clientCert)) {
+ Log.e(TAG, "Failed to install client certificate");
+ uninstallCertsAndKeys();
+ return false;
+ }
+ mClientCertificateAlias = alias;
+ }
+
+ // Clear the keys and certificates in the configuration.
+ mConfig.credential.caCertificate = null;
+ mConfig.credential.clientPrivateKey = null;
+ mConfig.credential.clientCertificateChain = null;
+ return true;
+ }
+
+ /**
+ * Remove any installed certificates and key.
+ */
+ public void uninstallCertsAndKeys() {
+ if (mCaCertificateAlias != null) {
+ if (!mKeyStore.removeEntryFromKeyStore(mCaCertificateAlias)) {
+ Log.e(TAG, "Failed to remove entry: " + mCaCertificateAlias);
+ }
+ mCaCertificateAlias = null;
+ }
+ if (mClientPrivateKeyAlias != null) {
+ if (!mKeyStore.removeEntryFromKeyStore(mClientPrivateKeyAlias)) {
+ Log.e(TAG, "Failed to remove entry: " + mClientPrivateKeyAlias);
+ }
+ mClientPrivateKeyAlias = null;
+ }
+ if (mClientCertificateAlias != null) {
+ if (!mKeyStore.removeEntryFromKeyStore(mClientCertificateAlias)) {
+ Log.e(TAG, "Failed to remove entry: " + mClientCertificateAlias);
+ }
+ mClientCertificateAlias = null;
+ }
+ }
+
+ /**
+ * Create and return a certificate or key alias name based on the given prefix and uid.
+ *
+ * @param type The key or certificate type string
+ * @param uid The UID of the alias
+ * @return String
+ */
+ private static String formatAliasName(String type, long uid) {
+ return type + ALIAS_PREFIX + uid;
+ }
+
+ /**
+ * Retrieve the client certificate from the certificates chain. The certificate
+ * with the matching SHA256 digest is the client certificate.
+ *
+ * @param certChain The client certificates chain
+ * @param expectedSha256Fingerprint The expected SHA256 digest of the client certificate
+ * @return {@link java.security.cert.X509Certificate}
+ */
+ private static X509Certificate getClientCertificate(X509Certificate[] certChain,
+ byte[] expectedSha256Fingerprint) {
+ if (certChain == null) {
+ return null;
+ }
+ try {
+ MessageDigest digester = MessageDigest.getInstance("SHA-256");
+ for (X509Certificate certificate : certChain) {
+ digester.reset();
+ byte[] fingerprint = digester.digest(certificate.getEncoded());
+ if (Arrays.equals(expectedSha256Fingerprint, fingerprint)) {
+ return certificate;
+ }
+ }
+ } catch (CertificateEncodingException | NoSuchAlgorithmException e) {
+ return null;
+ }
+
+ return null;
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/FakeKeys.java b/tests/wifitests/src/com/android/server/wifi/FakeKeys.java
index e8694b4bd..99ce196c8 100644
--- a/tests/wifitests/src/com/android/server/wifi/FakeKeys.java
+++ b/tests/wifitests/src/com/android/server/wifi/FakeKeys.java
@@ -3,8 +3,13 @@ package com.android.server.wifi;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
/**
* A class containing test certificates.
@@ -52,6 +57,146 @@ public class FakeKeys {
"-----END CERTIFICATE-----\n";
public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING);
+ private static final String CLIENT_CERT_STR = "-----BEGIN CERTIFICATE-----\n" +
+ "MIIE/DCCAuQCAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxCzAJBgNV\n" +
+ "BAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdUZXN0aW5n\n" +
+ "MB4XDTE2MDkzMDIwNTQyOFoXDTE3MDkzMDIwNTQyOFowRDELMAkGA1UEBhMCVVMx\n" +
+ "CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdU\n" +
+ "ZXN0aW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpmcbuaeHfnJ\n" +
+ "k+2QNvxmdVFTawyFMNk0USCq5sexscwmxbewG/Rb8YnixwJWS44v2XkSujB67z5C\n" +
+ "s2qudFEhRXKdEuC6idbAuA97KjipHh0AAniWMsyv61fvbgsUC0b0canx3LiDq81p\n" +
+ "y28NNGmAvoazLZUZ4AhBRiwYZY6FKk723gmZoGbEIeG7J1dlXPusc1662rIjz4eU\n" +
+ "zlmmlvqyHfNqnNk8L14Vug6Xh+lOEGN85xhu1YHAEKGrS89kZxs5rum/cZU8KH2V\n" +
+ "v6eKnY03kxjiVLQtnLpm/7VUEoCMGHyruRj+p3my4+DgqMsmsH52RZCBsjyGlpbU\n" +
+ "NOwOTIX6xh+Rqloduz4AnrMYYIiIw2s8g+2zJM7VbcVKx0fGS26BKdrxgrXWfmNE\n" +
+ "nR0/REQ5AxDGw0jfTUvtdTkXAf+K4MDjcNLEZ+MA4rHfAfQWZtUR5BkHCQYxNpJk\n" +
+ "pA0gyk+BpKdC4WdzI14NSWsu5sRCmBCFqH6BTOSEq/V1cNorBxNwLSSTwFFqUDqx\n" +
+ "Y5nQLXygkJf9WHZWtSKeSjtOYgilz7UKzC2s3CsjmIyGFe+SwpuHJnuE4Uc8Z5Cb\n" +
+ "bjNGHPzqL6XnmzZHJp7RF8kBdKdjGC7dCUltzOfICZeKlzOOq+Kw42T/nXjuXvpb\n" +
+ "nkXNxg741Nwd6RecykXJbseFwm3EYxkCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEA\n" +
+ "Ga1mGwI9aXkL2fTPXO9YkAPzoGeX8aeuVYSQaSkNq+5vnogYCyAt3YDHjRG+ewTT\n" +
+ "WbnPA991xRAPac+biJeXWmwvgGj0YuT7e79phAiGkTTnbAjFHGfYnBy/tI/v7btO\n" +
+ "hRNElA5yTJ1m2fVbBEKXzMR83jrT9iyI+YLRN86zUZIaC86xxSbqnrdWN2jOK6MX\n" +
+ "dS8Arp9tPQjC/4gW+2Ilxv68jiYh+5auWHQZVjppWVY//iu4mAbkq1pTwQEhZ8F8\n" +
+ "Zrmh9DHh60hLFcfSuhIAwf/NMzppwdkjy1ruKVrpijhGKGp4OWu8nvOUgHSzxc7F\n" +
+ "PwpVZ5N2Ku4L8MLO6BG2VasRJK7l17TzDXlfLZHJjkuryOFxVaQKt8ZNFgTOaCXS\n" +
+ "E+gpTLksKU7riYckoiP4+H1sn9qcis0e8s4o/uf1UVc8GSdDw61ReGM5oZEDm1u8\n" +
+ "H9x20QU6igLqzyBpqvCKv7JNgU1uB2PAODHH78zJiUfnKd1y+o+J1iWzaGj3EFji\n" +
+ "T8AXksbTP733FeFXfggXju2dyBH+Z1S5BBTEOd1brWgXlHSAZGm97MKZ94r6/tkX\n" +
+ "qfv3fCos0DKz0oV7qBxYS8wiYhzrRVxG6ITAoH8uuUVVQaZF+G4nJ2jEqNbfuKyX\n" +
+ "ATQsVNjNNlDA0J33GobPMjT326wa4YAWMx8PI5PJZ3g=\n" +
+ "-----END CERTIFICATE-----\n";
+ public static final X509Certificate CLIENT_CERT = loadCertificate(CLIENT_CERT_STR);
+
+ private static final byte[] FAKE_RSA_KEY_1 = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
+ (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
+ (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
+ (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
+ (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
+ (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
+ (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
+ (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
+ (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
+ (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
+ (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
+ (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
+ (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
+ (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
+ (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
+ (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
+ (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
+ (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
+ (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
+ (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
+ (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
+ (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
+ (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
+ (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
+ (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
+ (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
+ (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
+ (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
+ (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
+ (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
+ (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
+ (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
+ (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
+ (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
+ (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
+ (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
+ (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
+ (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
+ (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
+ (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
+ (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
+ (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
+ (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
+ (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
+ (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
+ (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
+ (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
+ (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
+ (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
+ (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
+ (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
+ (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
+ (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
+ (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
+ (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
+ (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
+ (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
+ (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
+ (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
+ (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
+ (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
+ (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
+ (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
+ (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
+ (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
+ (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
+ (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
+ (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
+ (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
+ (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
+ (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
+ (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+ (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
+ (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
+ (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
+ (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
+ (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
+ (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
+ (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
+ (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
+ (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
+ (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
+ (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
+ (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
+ (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
+ (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
+ (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
+ (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
+ (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
+ (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
+ (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
+ (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
+ (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
+ (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
+ (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
+ (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
+ (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
+ (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
+ (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
+ (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
+ (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
+ (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
+ (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
+ (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
+ (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
+ };
+ public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1);
private static X509Certificate loadCertificate(String blob) {
try {
@@ -64,4 +209,13 @@ public class FakeKeys {
return null;
}
}
+
+ private static PrivateKey loadPrivateRSAKey(byte[] fakeKey) {
+ try {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(fakeKey));
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+ return null;
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index 1d9f9372d..69d7b8bc3 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -24,7 +24,9 @@ import static android.net.wifi.WifiManager.PASSPOINT_ICON_RECEIVED_ACTION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
@@ -38,10 +40,13 @@ import android.net.wifi.hotspot2.pps.HomeSP;
import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.wifi.Clock;
import com.android.server.wifi.FakeKeys;
import com.android.server.wifi.IMSIParameter;
import com.android.server.wifi.SIMAccessor;
import com.android.server.wifi.WifiInjector;
+import com.android.server.wifi.WifiKeyStore;
+import com.android.server.wifi.WifiNative;
import org.junit.Before;
import org.junit.Test;
@@ -63,21 +68,27 @@ public class PasspointManagerTest {
private static final String TEST_FRIENDLY_NAME = "friendly name";
private static final String TEST_REALM = "realm.test.com";
private static final String TEST_IMSI = "1234*";
+ private static final long PROVIDER_ID = 1L;
@Mock Context mContext;
- @Mock WifiInjector mWifiInjector;
- @Mock PasspointEventHandler.Callbacks mCallbacks;
+ @Mock WifiNative mWifiNative;
+ @Mock WifiKeyStore mWifiKeyStore;
+ @Mock Clock mClock;
@Mock SIMAccessor mSimAccessor;
+ @Mock PasspointObjectFactory mObjectFactory;
+ @Mock PasspointEventHandler.Callbacks mCallbacks;
PasspointManager mManager;
/** Sets up test. */
@Before
public void setUp() throws Exception {
initMocks(this);
- mManager = new PasspointManager(mContext, mWifiInjector, mSimAccessor);
+ mManager = new PasspointManager(mContext, mWifiNative, mWifiKeyStore, mClock,
+ mSimAccessor, mObjectFactory);
ArgumentCaptor<PasspointEventHandler.Callbacks> callbacks =
ArgumentCaptor.forClass(PasspointEventHandler.Callbacks.class);
- verify(mWifiInjector).makePasspointEventHandler(callbacks.capture());
+ verify(mObjectFactory).makePasspointEventHandler(any(WifiNative.class),
+ callbacks.capture());
mCallbacks = callbacks.getValue();
}
@@ -115,6 +126,19 @@ public class PasspointManagerTest {
}
/**
+ * Create a mock PasspointProvider with default expectations.
+ *
+ * @param config The configuration associated with the provider
+ * @return {@link com.android.server.wifi.hotspot2.PasspointProvider}
+ */
+ private PasspointProvider createMockProvider(PasspointConfiguration config) {
+ PasspointProvider provider = mock(PasspointProvider.class);
+ when(provider.installCertsAndKeys()).thenReturn(true);
+ when(provider.getConfig()).thenReturn(config);
+ return provider;
+ }
+
+ /**
* Validate the broadcast intent when icon file retrieval succeeded.
*
* @throws Exception
@@ -200,11 +224,16 @@ public class PasspointManagerTest {
config.credential.userCredential.password = "password";
config.credential.userCredential.eapType = EAPConstants.EAP_TTLS;
config.credential.userCredential.nonEapInnerMethod = "MS-CHAP";
+ PasspointProvider provider = createMockProvider(config);
+ when(mClock.getWallClockMillis()).thenReturn(PROVIDER_ID);
+ when(mObjectFactory.makePasspointProvider(config, mWifiKeyStore, PROVIDER_ID))
+ .thenReturn(provider);
assertTrue(mManager.addProvider(config));
verifyInstalledConfig(config);
// Remove the provider.
assertTrue(mManager.removeProvider(TEST_FQDN));
+ verify(provider).uninstallCertsAndKeys();
assertEquals(null, mManager.getProviderConfigs());
}
@@ -226,11 +255,16 @@ public class PasspointManagerTest {
config.credential.simCredential.eapType = EAPConstants.EAP_SIM;
when(mSimAccessor.getMatchingImsis(new IMSIParameter(TEST_IMSI)))
.thenReturn(new ArrayList<String>());
+ PasspointProvider provider = createMockProvider(config);
+ when(mClock.getWallClockMillis()).thenReturn(PROVIDER_ID);
+ when(mObjectFactory.makePasspointProvider(config, mWifiKeyStore, PROVIDER_ID))
+ .thenReturn(provider);
assertTrue(mManager.addProvider(config));
verifyInstalledConfig(config);
// Remove the provider.
assertTrue(mManager.removeProvider(TEST_FQDN));
+ verify(provider).uninstallCertsAndKeys();
assertEquals(null, mManager.getProviderConfigs());
}
@@ -276,6 +310,10 @@ public class PasspointManagerTest {
origConfig.credential.simCredential.eapType = EAPConstants.EAP_SIM;
when(mSimAccessor.getMatchingImsis(new IMSIParameter(TEST_IMSI)))
.thenReturn(new ArrayList<String>());
+ PasspointProvider origProvider = createMockProvider(origConfig);
+ when(mClock.getWallClockMillis()).thenReturn(PROVIDER_ID);
+ when(mObjectFactory.makePasspointProvider(origConfig, mWifiKeyStore, PROVIDER_ID))
+ .thenReturn(origProvider);
assertTrue(mManager.addProvider(origConfig));
verifyInstalledConfig(origConfig);
@@ -293,7 +331,49 @@ public class PasspointManagerTest {
newConfig.credential.userCredential.password = "password";
newConfig.credential.userCredential.eapType = EAPConstants.EAP_TTLS;
newConfig.credential.userCredential.nonEapInnerMethod = "MS-CHAP";
+ PasspointProvider newProvider = createMockProvider(newConfig);
+ when(mClock.getWallClockMillis()).thenReturn(PROVIDER_ID);
+ when(mObjectFactory.makePasspointProvider(newConfig, mWifiKeyStore, PROVIDER_ID))
+ .thenReturn(newProvider);
assertTrue(mManager.addProvider(newConfig));
verifyInstalledConfig(newConfig);
}
+
+ /**
+ * Verify that adding a provider will fail when failing to install certificates and
+ * key to the keystore.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void addProviderOnKeyInstallationFailiure() throws Exception {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.homeSp = new HomeSP();
+ config.homeSp.fqdn = TEST_FQDN;
+ config.homeSp.friendlyName = TEST_FRIENDLY_NAME;
+ config.credential = new Credential();
+ config.credential.realm = TEST_REALM;
+ config.credential.caCertificate = FakeKeys.CA_CERT0;
+ config.credential.userCredential = new Credential.UserCredential();
+ config.credential.userCredential.username = "username";
+ config.credential.userCredential.password = "password";
+ config.credential.userCredential.eapType = EAPConstants.EAP_TTLS;
+ config.credential.userCredential.nonEapInnerMethod = "MS-CHAP";
+ PasspointProvider provider = mock(PasspointProvider.class);
+ when(provider.installCertsAndKeys()).thenReturn(false);
+ when(mClock.getWallClockMillis()).thenReturn(PROVIDER_ID);
+ when(mObjectFactory.makePasspointProvider(config, mWifiKeyStore, PROVIDER_ID))
+ .thenReturn(provider);
+ assertFalse(mManager.addProvider(config));
+ }
+
+ /**
+ * Verify that removing a non-existing provider will fail.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void removeNonExistingProvider() throws Exception {
+ assertFalse(mManager.removeProvider(TEST_FQDN));
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java
index 3ff01bc30..db8a43a9d 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java
@@ -18,20 +18,54 @@ package com.android.server.wifi.hotspot2;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSP;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.wifi.FakeKeys;
+import com.android.server.wifi.WifiKeyStore;
+
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+
+import java.security.MessageDigest;
+import java.security.cert.X509Certificate;
/**
* Unit tests for {@link com.android.server.wifi.hotspot2.PasspointProvider}.
*/
@SmallTest
public class PasspointProviderTest {
+ private static final long PROVIDER_ID = 12L;
+ private static final String CA_CERTIFICATE_ALIAS = "CACERT_HS2_12";
+ private static final String CLIENT_CERTIFICATE_ALIAS = "USRCERT_HS2_12";
+ private static final String CLIENT_PRIVATE_KEY_ALIAS = "USRPKEY_HS2_12";
+
+ @Mock WifiKeyStore mKeyStore;
PasspointProvider mProvider;
+ /** Sets up test. */
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ }
+
+ /**
+ * Helper function for creating a provider instance for testing.
+ *
+ * @param config The configuration associated with the provider
+ * @return {@link com.android.server.wifi.hotspot2.PasspointProvider}
+ */
+ private PasspointProvider createProvider(PasspointConfiguration config) {
+ return new PasspointProvider(config, mKeyStore, PROVIDER_ID);
+ }
+
/**
* Verify that the configuration associated with the provider is the same or not the same
* as the expected configuration.
@@ -60,7 +94,7 @@ public class PasspointProviderTest {
PasspointConfiguration config = new PasspointConfiguration();
config.homeSp = new HomeSP();
config.homeSp.fqdn = "test1";
- mProvider = new PasspointProvider(config);
+ mProvider = createProvider(config);
verifyInstalledConfig(config, true);
// Modify the original configuration, the configuration maintained by the provider
@@ -81,7 +115,7 @@ public class PasspointProviderTest {
PasspointConfiguration config = new PasspointConfiguration();
config.homeSp = new HomeSP();
config.homeSp.fqdn = "test1";
- mProvider = new PasspointProvider(config);
+ mProvider = createProvider(config);
verifyInstalledConfig(config, true);
// Modify the retrieved configuration, verify the configuration maintained by the
@@ -90,4 +124,118 @@ public class PasspointProviderTest {
retrievedConfig.homeSp.fqdn = "test2";
verifyInstalledConfig(retrievedConfig, false);
}
+
+ /**
+ * Verify a successful installation of certificates and key.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void installCertsAndKeysSuccess() throws Exception {
+ // Create a dummy configuration with certificate credential.
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.credential = new Credential();
+ config.credential.certCredential = new Credential.CertificateCredential();
+ config.credential.certCredential.certSha256FingerPrint =
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
+ config.credential.caCertificate = FakeKeys.CA_CERT0;
+ config.credential.clientPrivateKey = FakeKeys.RSA_KEY1;
+ config.credential.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ mProvider = createProvider(config);
+
+ // Install client certificate and key to the keystore successfully.
+ when(mKeyStore.putCertInKeyStore(CA_CERTIFICATE_ALIAS, FakeKeys.CA_CERT0))
+ .thenReturn(true);
+ when(mKeyStore.putKeyInKeyStore(CLIENT_PRIVATE_KEY_ALIAS, FakeKeys.RSA_KEY1))
+ .thenReturn(true);
+ when(mKeyStore.putCertInKeyStore(CLIENT_CERTIFICATE_ALIAS, FakeKeys.CLIENT_CERT))
+ .thenReturn(true);
+ assertTrue(mProvider.installCertsAndKeys());
+
+ // Verify client certificate and key in the configuration gets cleared and aliases
+ // are set correctly.
+ PasspointConfiguration curConfig = mProvider.getConfig();
+ assertTrue(curConfig.credential.caCertificate == null);
+ assertTrue(curConfig.credential.clientPrivateKey == null);
+ assertTrue(curConfig.credential.clientCertificateChain == null);
+ assertTrue(mProvider.getCaCertificateAlias().equals(CA_CERTIFICATE_ALIAS));
+ assertTrue(mProvider.getClientPrivateKeyAlias().equals(CLIENT_PRIVATE_KEY_ALIAS));
+ assertTrue(mProvider.getClientCertificateAlias().equals(CLIENT_CERTIFICATE_ALIAS));
+ }
+
+ /**
+ * Verify a failure installation of certificates and key.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void installCertsAndKeysFailure() throws Exception {
+ // Create a dummy configuration with certificate credential.
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.credential = new Credential();
+ config.credential.certCredential = new Credential.CertificateCredential();
+ config.credential.certCredential.certSha256FingerPrint =
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
+ config.credential.caCertificate = FakeKeys.CA_CERT0;
+ config.credential.clientPrivateKey = FakeKeys.RSA_KEY1;
+ config.credential.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ mProvider = createProvider(config);
+
+ // Failed to install client certificate to the keystore.
+ when(mKeyStore.putCertInKeyStore(CA_CERTIFICATE_ALIAS, FakeKeys.CA_CERT0))
+ .thenReturn(true);
+ when(mKeyStore.putKeyInKeyStore(CLIENT_PRIVATE_KEY_ALIAS, FakeKeys.RSA_KEY1))
+ .thenReturn(true);
+ when(mKeyStore.putCertInKeyStore(CLIENT_CERTIFICATE_ALIAS, FakeKeys.CLIENT_CERT))
+ .thenReturn(false);
+ assertFalse(mProvider.installCertsAndKeys());
+
+ // Verify certificates and key in the configuration are not cleared and aliases
+ // are not set.
+ PasspointConfiguration curConfig = mProvider.getConfig();
+ assertTrue(curConfig.credential.caCertificate != null);
+ assertTrue(curConfig.credential.clientCertificateChain != null);
+ assertTrue(curConfig.credential.clientPrivateKey != null);
+ assertTrue(mProvider.getCaCertificateAlias() == null);
+ assertTrue(mProvider.getClientPrivateKeyAlias() == null);
+ assertTrue(mProvider.getClientCertificateAlias() == null);
+ }
+
+ /**
+ * Verify a successful uninstallation of certificates and key.
+ */
+ @Test
+ public void uninstallCertsAndKeys() throws Exception {
+ // Create a dummy configuration with certificate credential.
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.credential = new Credential();
+ config.credential.certCredential = new Credential.CertificateCredential();
+ config.credential.certCredential.certSha256FingerPrint =
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
+ config.credential.caCertificate = FakeKeys.CA_CERT0;
+ config.credential.clientPrivateKey = FakeKeys.RSA_KEY1;
+ config.credential.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ mProvider = createProvider(config);
+
+ // Install client certificate and key to the keystore successfully.
+ when(mKeyStore.putCertInKeyStore(CA_CERTIFICATE_ALIAS, FakeKeys.CA_CERT0))
+ .thenReturn(true);
+ when(mKeyStore.putKeyInKeyStore(CLIENT_PRIVATE_KEY_ALIAS, FakeKeys.RSA_KEY1))
+ .thenReturn(true);
+ when(mKeyStore.putCertInKeyStore(CLIENT_CERTIFICATE_ALIAS, FakeKeys.CLIENT_CERT))
+ .thenReturn(true);
+ assertTrue(mProvider.installCertsAndKeys());
+ assertTrue(mProvider.getCaCertificateAlias().equals(CA_CERTIFICATE_ALIAS));
+ assertTrue(mProvider.getClientPrivateKeyAlias().equals(CLIENT_PRIVATE_KEY_ALIAS));
+ assertTrue(mProvider.getClientCertificateAlias().equals(CLIENT_CERTIFICATE_ALIAS));
+
+ // Uninstall certificates and key from the keystore.
+ mProvider.uninstallCertsAndKeys();
+ verify(mKeyStore).removeEntryFromKeyStore(CA_CERTIFICATE_ALIAS);
+ verify(mKeyStore).removeEntryFromKeyStore(CLIENT_CERTIFICATE_ALIAS);
+ verify(mKeyStore).removeEntryFromKeyStore(CLIENT_PRIVATE_KEY_ALIAS);
+ assertTrue(mProvider.getCaCertificateAlias() == null);
+ assertTrue(mProvider.getClientPrivateKeyAlias() == null);
+ assertTrue(mProvider.getClientCertificateAlias() == null);
+ }
}