Merge cherrypicks of ['googleplex-android-review.googlesource.com/22633469', 'googleplex-android-review.googlesource.com/22438869', 'googleplex-android-review.googlesource.com/22625067', 'googleplex-android-review.googlesource.com/22772854'] into tm-qpr3-c-release.
Change-Id: Ie1f4af32048525c35915605dcfdb4c4ab41a2878
diff --git a/framework/java/android/net/wifi/WifiEnterpriseConfig.java b/framework/java/android/net/wifi/WifiEnterpriseConfig.java
index 2a53e35..af51a8c 100644
--- a/framework/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/framework/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -126,6 +126,11 @@
public static final String KEYSTORES_URI = "keystores://";
/**
+ * String representing a SHA-256 certificate hash used for wpa_supplicant.
+ */
+ private static final String CERT_HASH_PREFIX = "hash://server/sha256/";
+
+ /**
* String to set the engine value to when it should be enabled.
* @hide
*/
@@ -707,6 +712,16 @@
}
/**
+ * Set a server certificate hash instead of a CA certificate for a TOFU connection
+ *
+ * @param certHash Server certificate hash to match against in subsequent connections
+ * @hide
+ */
+ public void setServerCertificateHash(String certHash) {
+ setFieldValue(CA_CERT_KEY, certHash, CERT_HASH_PREFIX);
+ }
+
+ /**
* Set CA certificate alias.
*
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
diff --git a/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 60c8133..f9ebd2b 100644
--- a/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -996,12 +996,12 @@
}
String[] decoratedIdentityPrefixArray = mDecoratedIdentityPrefix.split("!");
if (decoratedIdentityPrefixArray.length > MAX_NUMBER_OF_ENTRIES) {
- Log.d(TAG, "too many decoratedIdentityPrefix");
+ Log.e(TAG, "too many decoratedIdentityPrefix");
return false;
}
for (String prefix : decoratedIdentityPrefixArray) {
if (prefix.length() > MAX_STRING_LENGTH) {
- Log.d(TAG, "The decoratedIdentityPrefix is too long: " + prefix);
+ Log.e(TAG, "The decoratedIdentityPrefix is too long: " + prefix);
return false;
}
}
@@ -1009,52 +1009,70 @@
if (mAaaServerTrustedNames != null) {
if (mAaaServerTrustedNames.length > MAX_NUMBER_OF_ENTRIES) {
- Log.d(TAG, "Too many AaaServerTrustedNames");
+ Log.e(TAG, "Too many AaaServerTrustedNames");
return false;
}
for (String fqdn : mAaaServerTrustedNames) {
if (fqdn.getBytes(StandardCharsets.UTF_8).length > MAX_STRING_LENGTH) {
- Log.d(TAG, "AaaServerTrustedNames is too long");
+ Log.e(TAG, "AaaServerTrustedNames is too long");
return false;
}
}
}
if (mSubscriptionType != null) {
if (mSubscriptionType.getBytes(StandardCharsets.UTF_8).length > MAX_STRING_LENGTH) {
- Log.d(TAG, "SubscriptionType is too long");
+ Log.e(TAG, "SubscriptionType is too long");
return false;
}
}
if (mTrustRootCertList != null) {
if (mTrustRootCertList.size() > MAX_NUMBER_OF_ENTRIES) {
- Log.d(TAG, "Too many TrustRootCert");
+ Log.e(TAG, "Too many TrustRootCert");
return false;
}
for (Map.Entry<String, byte[]> entry : mTrustRootCertList.entrySet()) {
String url = entry.getKey();
byte[] certFingerprint = entry.getValue();
if (TextUtils.isEmpty(url)) {
- Log.d(TAG, "Empty URL");
+ Log.e(TAG, "Empty URL");
return false;
}
if (url.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
- Log.d(TAG, "URL bytes exceeded the max: "
+ Log.e(TAG, "URL bytes exceeded the max: "
+ url.getBytes(StandardCharsets.UTF_8).length);
return false;
}
if (certFingerprint == null) {
- Log.d(TAG, "Fingerprint not specified");
+ Log.e(TAG, "Fingerprint not specified");
return false;
}
if (certFingerprint.length != CERTIFICATE_SHA256_BYTES) {
- Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
+ Log.e(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
+ certFingerprint.length);
return false;
}
}
}
+
+ if (mServiceFriendlyNames != null) {
+ if (mServiceFriendlyNames.size() > MAX_NUMBER_OF_ENTRIES) {
+ Log.e(TAG, "ServiceFriendlyNames exceed the max!");
+ return false;
+ }
+ for (Map.Entry<String, String> names : mServiceFriendlyNames.entrySet()) {
+ if (names.getKey() == null || names.getValue() == null) {
+ Log.e(TAG, "Service friendly name entry should not be null");
+ return false;
+ }
+ if (names.getKey().length() > MAX_STRING_LENGTH
+ || names.getValue().length() > MAX_STRING_LENGTH) {
+ Log.e(TAG, "Service friendly name is to long");
+ return false;
+ }
+ }
+ }
return true;
}
diff --git a/framework/java/android/net/wifi/hotspot2/pps/Policy.java b/framework/java/android/net/wifi/hotspot2/pps/Policy.java
index b0a2cc3..4bdaceb 100644
--- a/framework/java/android/net/wifi/hotspot2/pps/Policy.java
+++ b/framework/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -16,6 +16,9 @@
package android.net.wifi.hotspot2.pps;
+import static android.net.wifi.hotspot2.PasspointConfiguration.MAX_NUMBER_OF_ENTRIES;
+import static android.net.wifi.hotspot2.PasspointConfiguration.MAX_STRING_LENGTH;
+
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -269,11 +272,19 @@
*/
public boolean validate() {
if (TextUtils.isEmpty(mFqdn)) {
- Log.d(TAG, "Missing FQDN");
+ Log.e(TAG, "Missing FQDN");
+ return false;
+ }
+ if (mFqdn.getBytes(StandardCharsets.UTF_8).length > MAX_STRING_LENGTH) {
+ Log.e(TAG, "FQDN is too long");
return false;
}
if (TextUtils.isEmpty(mCountries)) {
- Log.d(TAG, "Missing countries");
+ Log.e(TAG, "Missing countries");
+ return false;
+ }
+ if (mCountries.getBytes(StandardCharsets.UTF_8).length > MAX_STRING_LENGTH) {
+ Log.e(TAG, "country is too long");
return false;
}
return true;
@@ -449,7 +460,7 @@
}
for (String ssid : mExcludedSsidList) {
if (ssid.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
- Log.d(TAG, "Invalid SSID: " + ssid);
+ Log.e(TAG, "Invalid SSID: " + ssid);
return false;
}
}
@@ -457,15 +468,24 @@
// Validate required protocol to port map.
if (mRequiredProtoPortMap != null) {
for (Map.Entry<Integer, String> entry : mRequiredProtoPortMap.entrySet()) {
+ int protocol = entry.getKey();
+ if (protocol < 0 || protocol > 255) {
+ Log.e(TAG, "Invalid IP protocol: " + protocol);
+ return false;
+ }
String portNumber = entry.getValue();
if (portNumber.getBytes(StandardCharsets.UTF_8).length > MAX_PORT_STRING_BYTES) {
- Log.d(TAG, "PortNumber string bytes exceeded the max: " + portNumber);
+ Log.e(TAG, "PortNumber string bytes exceeded the max: " + portNumber);
return false;
}
}
}
// Validate preferred roaming partner list.
if (mPreferredRoamingPartnerList != null) {
+ if (mPreferredRoamingPartnerList.size() > MAX_NUMBER_OF_ENTRIES) {
+ Log.e(TAG, "Number of the Preferred Roaming Partner exceed the limit");
+ return false;
+ }
for (RoamingPartner partner : mPreferredRoamingPartnerList) {
if (!partner.validate()) {
return false;
diff --git a/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 8318de3..4d80cf4 100644
--- a/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -741,5 +741,12 @@
homeSp.setRoamingConsortiumOis(ois);
assertFalse(homeSp.validate());
homeSp.setRoamingConsortiumOis(null);
+ // ServiceFriendlyNames exceed the limit
+ HashMap<String, String> friendlyNames = new HashMap<>();
+ for (int i = 0; i < MAX_NUMBER_OF_ENTRIES + 1; i++) {
+ friendlyNames.put(String.valueOf(i), String.valueOf(i));
+ }
+ passpointConfiguration.setServiceFriendlyNames(friendlyNames);
+ assertFalse(passpointConfiguration.validate());
}
}
diff --git a/framework/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java b/framework/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
index 980b199..bd6864b 100644
--- a/framework/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
+++ b/framework/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
@@ -16,6 +16,8 @@
package android.net.wifi.hotspot2.pps;
+import static android.net.wifi.hotspot2.PasspointConfiguration.MAX_NUMBER_OF_ENTRIES;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -309,4 +311,32 @@
policy.setExcludedSsidList(excludedSsidList);
assertFalse(policy.validate());
}
+
+ @Test
+ public void validatePolicyWithInvalidRequiredProtoPortMap() {
+ Policy policy = createPolicy();
+ Map<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(-1, "23,342,123");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+ assertFalse(policy.validate());
+ requiredProtoPortMap.put(256, "23,342,123");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+ assertFalse(policy.validate());
+ }
+
+ @Test
+ public void validatePolicyWithPreferRoamingPartner() {
+ Policy policy = createPolicy();
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ for (int i = 0; i < MAX_NUMBER_OF_ENTRIES + 1; i++) {
+ Policy.RoamingPartner partner = new Policy.RoamingPartner();
+ partner.setFqdn("partner1.com");
+ partner.setFqdnExactMatch(true);
+ partner.setPriority(12);
+ partner.setCountries("us,jp");
+ preferredRoamingPartnerList.add(partner);
+ }
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+ assertFalse(policy.validate());
+ }
}
diff --git a/service/java/com/android/server/wifi/CertificateEventInfo.java b/service/java/com/android/server/wifi/CertificateEventInfo.java
new file mode 100644
index 0000000..f688e4d
--- /dev/null
+++ b/service/java/com/android/server/wifi/CertificateEventInfo.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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;
+
+import android.annotation.NonNull;
+
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+
+/**
+ * Stores supplicant certificate event information
+ */
+public class CertificateEventInfo {
+ CertificateEventInfo(@NonNull X509Certificate cert, @NonNull String certHash) {
+ this.mCert = Objects.requireNonNull(cert);
+ this.mCertHash = Objects.requireNonNull(certHash);
+ }
+ @NonNull private final X509Certificate mCert;
+ @NonNull private final String mCertHash;
+
+ /**
+ * Get the X509 certificate stored in this object
+ *
+ * @return X509 certificate
+ */
+ public X509Certificate getCert() {
+ return mCert;
+ }
+
+ /**
+ * Get the certificate hash of the stored certificate
+ *
+ * @return certificate hash
+ */
+ public String getCertHash() {
+ return mCertHash;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(" Certificate Hash: ").append(mCertHash);
+ sb.append(" X509Certificate: ").append(mCert);
+ return sb.toString();
+ }
+}
+
+
+
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index c4c0823..987bb93 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -164,7 +164,6 @@
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URL;
-import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
@@ -426,6 +425,7 @@
private final RestrictedWifiNetworkFactory mRestrictedWifiNetworkFactory;
@VisibleForTesting
InsecureEapNetworkHandler mInsecureEapNetworkHandler;
+ boolean mLeafCertSent;
@VisibleForTesting
InsecureEapNetworkHandler.InsecureEapNetworkHandlerCallbacks
mInsecureEapNetworkHandlerCallbacksImpl;
@@ -829,9 +829,9 @@
mInsecureEapNetworkHandlerCallbacksImpl =
new InsecureEapNetworkHandler.InsecureEapNetworkHandlerCallbacks() {
@Override
- public void onAccept(String ssid) {
+ public void onAccept(String ssid, int networkId) {
log("Accept Root CA cert for " + ssid);
- sendMessage(CMD_ACCEPT_EAP_SERVER_CERTIFICATE, ssid);
+ sendMessage(CMD_ACCEPT_EAP_SERVER_CERTIFICATE, networkId);
}
@Override
@@ -905,7 +905,7 @@
WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE,
WifiMonitor.TRANSITION_DISABLE_INDICATION,
WifiMonitor.NETWORK_NOT_FOUND_EVENT,
- WifiMonitor.TOFU_ROOT_CA_CERTIFICATE,
+ WifiMonitor.TOFU_CERTIFICATE_EVENT,
WifiMonitor.AUXILIARY_SUPPLICANT_EVENT,
WifiMonitor.QOS_POLICY_RESET_EVENT,
WifiMonitor.QOS_POLICY_REQUEST_EVENT,
@@ -2307,8 +2307,8 @@
return "BLOCK_DISCOVERY";
case WifiMonitor.NETWORK_NOT_FOUND_EVENT:
return "NETWORK_NOT_FOUND_EVENT";
- case WifiMonitor.TOFU_ROOT_CA_CERTIFICATE:
- return "TOFU_ROOT_CA_CERTIFICATE";
+ case WifiMonitor.TOFU_CERTIFICATE_EVENT:
+ return "TOFU_CERTIFICATE_EVENT";
default:
return "what:" + what;
}
@@ -4025,6 +4025,7 @@
// TOFU flow for devices that do not support this feature
mInsecureEapNetworkHandler.prepareConnection(mTargetWifiConfiguration);
+ mLeafCertSent = false;
if (!isTrustOnFirstUseSupported()) {
mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected);
}
@@ -4271,6 +4272,13 @@
break;
}
case CMD_ACCEPT_EAP_SERVER_CERTIFICATE:
+ // If TOFU is not supported, then we are already connected
+ if (!isTrustOnFirstUseSupported()) break;
+ // Got an approval for a TOFU network. Disconnect (if connected) and trigger
+ // a connection to the new approved network.
+ logd("User accepted TOFU provided certificate");
+ startConnectToNetwork(message.arg1, Process.WIFI_UID, SUPPLICANT_BSSID_ANY);
+ break;
case CMD_REJECT_EAP_INSECURE_CONNECTION:
case CMD_START_ROAM:
case CMD_START_RSSI_MONITORING_OFFLOAD:
@@ -5388,22 +5396,24 @@
handleStatus = NOT_HANDLED;
break;
}
- case WifiMonitor.TOFU_ROOT_CA_CERTIFICATE:
+ case WifiMonitor.TOFU_CERTIFICATE_EVENT: {
if (null == mTargetWifiConfiguration) break;
- int certificateDepth = message.arg2;
+ final int certificateDepth = message.arg2;
+ final CertificateEventInfo eventInfo = (CertificateEventInfo) message.obj;
if (!mInsecureEapNetworkHandler.addPendingCertificate(
- mTargetWifiConfiguration.SSID, message.arg2,
- (X509Certificate) message.obj)) {
+ mTargetWifiConfiguration.SSID, certificateDepth, eventInfo)) {
Log.d(TAG, "Cannot set pending cert.");
}
// Launch user approval upon receiving the server certificate and disconnect
- if (certificateDepth == 0 && mInsecureEapNetworkHandler
+ if (certificateDepth == 0 && !mLeafCertSent && mInsecureEapNetworkHandler
.startUserApprovalIfNecessary(mIsUserSelected)) {
// In the TOFU flow, the user approval dialog is now displayed and the
// network remains disconnected and disabled until it is approved.
sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_UNTRUSTED);
+ mLeafCertSent = true;
}
break;
+ }
default: {
handleStatus = NOT_HANDLED;
break;
@@ -6419,12 +6429,6 @@
}
break;
}
- case CMD_ACCEPT_EAP_SERVER_CERTIFICATE:
- // Got an approval for a TOFU network, trigger a scan to accelerate the
- // auto-connection.
- logd("User accepted TOFU provided certificate");
- mWifiConnectivityManager.forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
- break;
default: {
handleStatus = NOT_HANDLED;
break;
diff --git a/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java b/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java
index ac43dcd..fa3bee7 100644
--- a/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java
+++ b/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -40,13 +41,21 @@
import com.android.server.wifi.util.CertificateSubjectInfo;
import com.android.wifi.resources.R;
+import java.security.InvalidAlgorithmParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
import java.util.Date;
-import java.util.List;
+import java.util.LinkedList;
+import java.util.Set;
import java.util.StringJoiner;
/** This class is used to handle insecure EAP networks. */
@@ -100,9 +109,16 @@
// This is updated on setting a pending server cert.
private CertificateSubjectInfo mPendingServerCertIssuerInfo = null;
// Record the whole server cert chain from Root CA to the server cert.
- private List<X509Certificate> mServerCertChain = new ArrayList<>();
+ // The order of the certificates in the chain required by the validation method is in the
+ // reverse order to the order we receive them from the lower layers. Therefore, we are using a
+ // LinkedList data type here, so that we could add certificates to the head, rather than
+ // using an ArrayList and then having to reverse it.
+ // Using SuppressLint here to avoid linter errors related to LinkedList usage.
+ @SuppressLint("JdkObsolete")
+ private LinkedList<X509Certificate> mServerCertChain = new LinkedList<>();
private WifiDialogManager.DialogHandle mTofuAlertDialog = null;
private boolean mIsCertNotificationReceiverRegistered = false;
+ private String mServerCertHash = null;
BroadcastReceiver mCertNotificationReceiver = new BroadcastReceiver() {
@Override
@@ -236,19 +252,17 @@
* @param ssid the target network SSID.
* @param depth the depth of this cert. The Root CA should be 0 or
* a positive number, and the server cert is 0.
- * @param cert a certificate from the server.
+ * @param certInfo a certificate info object from the server.
* @return true if the cert is cached; otherwise, false.
*/
public boolean addPendingCertificate(@NonNull String ssid, int depth,
- @NonNull X509Certificate cert) {
+ @NonNull CertificateEventInfo certInfo) {
String configProfileKey = mCurrentTofuConfig != null
? mCurrentTofuConfig.getProfileKey() : "null";
- Log.d(TAG, "setPendingCertificate: " + "ssid=" + ssid + " depth=" + depth
- + " current config=" + configProfileKey);
if (TextUtils.isEmpty(ssid)) return false;
if (null == mCurrentTofuConfig) return false;
if (!TextUtils.equals(ssid, mCurrentTofuConfig.SSID)) return false;
- if (null == cert) return false;
+ if (null == certInfo) return false;
if (depth < 0) return false;
// If TOFU is not supported return immediately, although this should not happen since
@@ -269,36 +283,38 @@
putNetworkOnHold();
}
- if (!mServerCertChain.contains(cert)) {
- mServerCertChain.add(cert);
+ if (!mServerCertChain.contains(certInfo.getCert())) {
+ mServerCertChain.addFirst(certInfo.getCert());
+ Log.d(TAG, "addPendingCertificate: " + "SSID=" + ssid + " depth=" + depth
+ + " certHash=" + certInfo.getCertHash() + " current config=" + configProfileKey
+ + "\ncertificate content:\n" + certInfo.getCert());
}
// 0 is the tail, i.e. the server cert.
if (depth == 0 && null == mPendingServerCert) {
- mPendingServerCert = cert;
- Log.d(TAG, "Pending server certificate: " + mPendingServerCert);
+ mPendingServerCert = certInfo.getCert();
mPendingServerCertSubjectInfo = CertificateSubjectInfo.parse(
- cert.getSubjectX500Principal().getName());
+ certInfo.getCert().getSubjectX500Principal().getName());
if (null == mPendingServerCertSubjectInfo) {
- Log.e(TAG, "CA cert has no valid subject.");
+ Log.e(TAG, "Cert has no valid subject.");
return false;
}
mPendingServerCertIssuerInfo = CertificateSubjectInfo.parse(
- cert.getIssuerX500Principal().getName());
+ certInfo.getCert().getIssuerX500Principal().getName());
if (null == mPendingServerCertIssuerInfo) {
- Log.e(TAG, "CA cert has no valid issuer.");
+ Log.e(TAG, "Cert has no valid issuer.");
return false;
}
+ mServerCertHash = certInfo.getCertHash();
}
// Root or intermediate cert.
if (depth < mPendingRootCaCertDepth) {
- Log.d(TAG, "Ignore intermediate cert." + cert);
return true;
}
mPendingRootCaCertDepth = depth;
- mPendingRootCaCert = cert;
- Log.d(TAG, "Pending Root CA certificate: " + mPendingRootCaCert);
+ mPendingRootCaCert = certInfo.getCert();
+
return true;
}
@@ -346,7 +362,13 @@
handleError(mCurrentTofuConfig.SSID);
return false;
}
- if (!isServerCertChainValid()) {
+
+ Log.d(TAG, "TOFU certificate chain:");
+ for (X509Certificate cert : mServerCertChain) {
+ Log.d(TAG, cert.getSubjectX500Principal().getName());
+ }
+
+ if (!configureServerValidationMethod()) {
Log.e(TAG, "Server cert chain is invalid.");
String ssid = mCurrentTofuConfig.SSID;
handleError(ssid);
@@ -358,9 +380,6 @@
return false;
}
- Log.d(TAG, "startUserApprovalIfNecessaryForInsecureEapNetwork: mIsUserSelected="
- + isUserSelected);
-
if (isUserSelected) {
askForUserApprovalForCaCertificate();
} else {
@@ -441,32 +460,76 @@
clearNativeData();
}
- private boolean isServerCertChainValid() {
- if (mServerCertChain.size() == 0) return false;
-
- X509Certificate parentCert = null;
- for (X509Certificate cert: mServerCertChain) {
- String subject = cert.getSubjectX500Principal().getName();
- String issuer = cert.getIssuerX500Principal().getName();
- boolean isCa = cert.getBasicConstraints() >= 0;
- Log.d(TAG, "Subject: " + subject + ", Issuer: " + issuer + ", isCA: " + isCa);
-
- if (parentCert == null) {
- // The root cert, it should be a CA cert or a self-signed cert.
- if (!isCa && !subject.equals(issuer)) {
- Log.e(TAG, "The root cert is not a CA cert or a self-signed cert.");
- return false;
- }
- } else {
- // The issuer of intermediate cert of the leaf cert should be
- // the same as the subject of its parent cert.
- if (!parentCert.getSubjectX500Principal().getName().equals(issuer)) {
- Log.e(TAG, "The issuer does not match the subject of its parent.");
- return false;
- }
- }
- parentCert = cert;
+ /**
+ * Configure the server validation method based on the incoming server certificate chain.
+ * If a valid method is found, the method returns true, and the caller can continue the TOFU
+ * process.
+ *
+ * A valid method could be one of the following:
+ * 1. If only the leaf or a partial chain is provided, use server certificate pinning.
+ * 2. If a full chain is provided, use the provided Root CA, but only if we are able to
+ * cryptographically validate it.
+ *
+ * If no certificates were received, or the certificates are invalid, or chain verification
+ * fails, the method returns false and the caller should abort the TOFU process.
+ */
+ private boolean configureServerValidationMethod() {
+ if (mServerCertChain.size() == 0) {
+ Log.e(TAG, "No certificate chain provided by the server.");
+ return false;
}
+ if (mServerCertChain.size() == 1) {
+ Log.i(TAG, "Only one certificate provided, use server certificate pinning");
+ return true;
+ }
+ if (mPendingRootCaCert.getSubjectX500Principal().getName()
+ .equals(mPendingRootCaCert.getIssuerX500Principal().getName())) {
+ if (mPendingRootCaCert.getVersion() >= 2
+ && mPendingRootCaCert.getBasicConstraints() < 0) {
+ Log.i(TAG, "Root CA with no CA bit set in basic constraints, "
+ + "use server certificate pinning");
+ return true;
+ }
+ } else {
+ // TODO: b/271921032 some deployments that use globally trusted Root CAs do not include
+ // the Root during the handshake, only an intermediate. We can start the handshake with
+ // the Android trust store and validate the connection with a Root CA rather than
+ // certificate pinning.
+ Log.i(TAG, "Root CA is not self-signed, use server certificate pinning");
+ return true;
+ }
+
+ CertPath certPath;
+ try {
+ certPath = CertificateFactory.getInstance("X.509").generateCertPath(mServerCertChain);
+ } catch (CertificateException e) {
+ Log.e(TAG, "Certificate chain is invalid.");
+ return false;
+ } catch (IllegalStateException e) {
+ Log.wtf(TAG, "Fail: " + e);
+ return false;
+ }
+ CertPathValidator certPathValidator;
+ try {
+ certPathValidator = CertPathValidator.getInstance("PKIX");
+ } catch (NoSuchAlgorithmException e) {
+ Log.wtf(TAG, "PKIX algorithm not supported.");
+ return false;
+ }
+ try {
+ Set<TrustAnchor> anchorSet = Set.of(new TrustAnchor(mPendingRootCaCert, null));
+ PKIXParameters params = new PKIXParameters(anchorSet);
+ params.setRevocationEnabled(false);
+ certPathValidator.validate(certPath, params);
+ } catch (InvalidAlgorithmParameterException e) {
+ Log.wtf(TAG, "Invalid algorithm exception.");
+ return false;
+ } catch (CertPathValidatorException e) {
+ Log.e(TAG, "Server certificate chain validation failed: " + e);
+ return false;
+ }
+ Log.i(TAG, "Server certificate chain validation succeeded, use Root CA");
+ mServerCertHash = null;
return true;
}
@@ -508,19 +571,21 @@
return;
}
if (!mWifiConfigManager.updateCaCertificate(
- mCurrentTofuConfig.networkId, mPendingRootCaCert, mPendingServerCert)) {
+ mCurrentTofuConfig.networkId, mPendingRootCaCert, mPendingServerCert,
+ mServerCertHash)) {
// The user approved this network,
// keep the connection regardless of the result.
Log.e(TAG, "Cannot update CA cert to network " + mCurrentTofuConfig.getProfileKey()
+ ", CA cert = " + mPendingRootCaCert);
}
}
- mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId,
+ int networkId = mCurrentTofuConfig.networkId;
+ mWifiConfigManager.updateNetworkSelectionStatus(networkId,
WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE);
dismissDialogAndNotification();
clearInternalData();
- if (null != mCallbacks) mCallbacks.onAccept(ssid);
+ if (null != mCallbacks) mCallbacks.onAccept(ssid, networkId);
}
@VisibleForTesting
@@ -741,6 +806,7 @@
mPendingServerCertSubjectInfo = null;
mPendingServerCertIssuerInfo = null;
mCurrentTofuConfig = null;
+ mServerCertHash = null;
}
private void clearNativeData() {
@@ -812,8 +878,9 @@
* When a certificate is accepted, this callback is called.
*
* @param ssid SSID of the network.
+ * @param networkId network ID
*/
- public void onAccept(@NonNull String ssid) {}
+ public void onAccept(@NonNull String ssid, int networkId) {}
/**
* When a certificate is rejected, this callback is called.
*
diff --git a/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java
index c8d9ff9..63a9e46 100644
--- a/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java
+++ b/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java
@@ -209,7 +209,8 @@
+ " certHash=" + certHash
+ " cert=" + cert);
mWifiMonitor.broadcastCertificationEvent(
- mIfaceName, mFrameworkNetworkId, mSsid, depth, cert);
+ mIfaceName, mFrameworkNetworkId, mSsid, depth,
+ new CertificateEventInfo(cert, certHash));
}
}
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index ee6fea7..dca3e6b 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -4108,16 +4108,17 @@
}
/**
- * This method updates the Root CA certifiate and the domain name of the
+ * This method updates the Root CA certificate and the domain name of the
* server in the internal network.
*
* @param networkId networkId corresponding to the network to be updated.
* @param caCert Root CA certificate to be updated.
* @param serverCert Server certificate to be updated.
+ * @param certHash Server certificate hash (for TOFU case with no Root CA)
* @return true if updating Root CA certificate successfully; otherwise, false.
*/
public boolean updateCaCertificate(int networkId, @NonNull X509Certificate caCert,
- @NonNull X509Certificate serverCert) {
+ @NonNull X509Certificate serverCert, String certHash) {
WifiConfiguration internalConfig = getInternalConfiguredNetwork(networkId);
if (internalConfig == null) {
Log.e(TAG, "No network for network ID " + networkId);
@@ -4149,11 +4150,15 @@
WifiConfiguration newConfig = new WifiConfiguration(internalConfig);
try {
if (newConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) {
- newConfig.enterpriseConfig.setCaCertificateForTrustOnFirstUse(caCert);
- // setCaCertificate will mark that this CA certificate should be removed on
- // removing this configuration.
+ if (TextUtils.isEmpty(certHash)) {
+ newConfig.enterpriseConfig.setCaCertificateForTrustOnFirstUse(caCert);
+ } else {
+ newConfig.enterpriseConfig.setServerCertificateHash(certHash);
+ }
newConfig.enterpriseConfig.enableTrustOnFirstUse(false);
} else {
+ // setCaCertificate will mark that this CA certificate should be removed on
+ // removing this configuration.
newConfig.enterpriseConfig.setCaCertificate(caCert);
}
} catch (IllegalArgumentException ex) {
@@ -4175,7 +4180,7 @@
newConfig.enterpriseConfig.setDomainSuffixMatch(serverCertInfo.commonName);
}
newConfig.enterpriseConfig.setUserApproveNoCaCert(false);
- // Trigger an update to install CA certifiate and the corresponding configuration.
+ // Trigger an update to install CA certificate and the corresponding configuration.
NetworkUpdateResult result = addOrUpdateNetwork(newConfig, internalConfig.creatorUid);
if (!result.isSuccess()) {
Log.e(TAG, "Failed to install CA cert for network " + internalConfig.SSID);
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index 907ca72..4a594b7 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -720,6 +720,10 @@
&& !validatePassword(config.preSharedKey, isAdd, true)) {
return false;
}
+ if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_WAPI_PSK)
+ && !validatePassword(config.preSharedKey, isAdd, false)) {
+ return false;
+ }
if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_DPP)
&& (supportedFeatureSet & WifiManager.WIFI_FEATURE_DPP_AKM) == 0) {
Log.e(TAG, "DPP AKM is not supported");
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index 0fdb69b..101fd2e 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -40,7 +40,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -109,8 +108,8 @@
/* Transition Disable Indication */
public static final int TRANSITION_DISABLE_INDICATION = BASE + 72;
- /* Trust On First Use Root CA Certification */
- public static final int TOFU_ROOT_CA_CERTIFICATE = BASE + 73;
+ /* Trust On First Use incoming certificate event */
+ public static final int TOFU_CERTIFICATE_EVENT = BASE + 73;
/* Auxiliary supplicant event */
public static final int AUXILIARY_SUPPLICANT_EVENT = BASE + 74;
@@ -619,11 +618,11 @@
* @param networkId ID of the network in wpa_supplicant.
* @param ssid SSID of the network.
* @param depth the depth of this cert in the chain, 0 is the leaf, i.e. the server cert.
- * @param cert the certificate data.
+ * @param certificateEventInfo the certificate data.
*/
public void broadcastCertificationEvent(String iface, int networkId, String ssid,
- int depth, X509Certificate cert) {
- sendMessage(iface, TOFU_ROOT_CA_CERTIFICATE, networkId, depth, cert);
+ int depth, CertificateEventInfo certificateEventInfo) {
+ sendMessage(iface, TOFU_CERTIFICATE_EVENT, networkId, depth, certificateEventInfo);
}
/**
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index 2422194..d255e50 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.net.MacAddress;
@@ -136,6 +137,7 @@
private final Clock mClock;
private final WifiPermissionsUtil mWifiPermissionsUtil;
private final WifiSettingsStore mSettingsStore;
+ private final boolean mIsLowMemory;
/**
* Map of package name of an app to the app ops changed listener for the app.
@@ -145,7 +147,8 @@
// Counter used for assigning unique identifier to each provider.
private long mProviderIndex;
private boolean mVerboseLoggingEnabled = false;
- private boolean mEnabled;
+ // Set default value to false before receiving boot completed event.
+ private boolean mEnabled = false;
private class CallbackHandler implements PasspointEventHandler.Callbacks {
private final Context mContext;
@@ -379,6 +382,8 @@
new SharedDataSourceHandler()));
mPasspointProvisioner = objectFactory.makePasspointProvisioner(context, wifiNative,
this, wifiMetrics);
+ ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+ mIsLowMemory = activityManager.isLowRamDevice();
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
sPasspointManager = this;
mMacAddressUtil = macAddressUtil;
@@ -477,10 +482,20 @@
Log.e(TAG, "Set isTrusted to false on a non suggestion passpoint is not allowed");
return false;
}
+ if (config.getServiceFriendlyNames() != null && isFromSuggestion) {
+ Log.e(TAG, "Passpoint from suggestion should not have ServiceFriendlyNames");
+ return false;
+ }
if (!mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(uid)) {
Log.e(TAG, "UID " + uid + " not visible to the current user");
return false;
}
+ if (getPasspointProviderWithPackage(packageName).size()
+ >= WifiManager.getMaxNumberOfNetworkSuggestionsPerApp(mIsLowMemory)) {
+ Log.e(TAG, "packageName " + packageName + " has too many passpoint with exceed the "
+ + "limitation");
+ return false;
+ }
mWifiCarrierInfoManager.tryUpdateCarrierIdForPasspoint(config);
// Create a provider and install the necessary certificates and keys.
diff --git a/service/tests/wifitests/Android.bp b/service/tests/wifitests/Android.bp
index 479e3d9..03f30b6 100644
--- a/service/tests/wifitests/Android.bp
+++ b/service/tests/wifitests/Android.bp
@@ -114,6 +114,9 @@
"com.android.server.wifi.ByteBufferReader",
"com.android.server.wifi.ByteBufferReader$*",
"com.android.server.wifi.ByteBufferReader.**",
+ "com.android.server.wifi.CertificateEventInfo",
+ "com.android.server.wifi.CertificateEventInfo*",
+ "com.android.server.wifi.CertificateEventInfo.**",
"com.android.server.wifi.ClientMode",
"com.android.server.wifi.ClientMode$*",
"com.android.server.wifi.ClientMode.**",
diff --git a/service/tests/wifitests/src/com/android/server/wifi/CertificateEventInfoTest.java b/service/tests/wifitests/src/com/android/server/wifi/CertificateEventInfoTest.java
new file mode 100644
index 0000000..4c2662e
--- /dev/null
+++ b/service/tests/wifitests/src/com/android/server/wifi/CertificateEventInfoTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import java.security.cert.X509Certificate;
+
+public class CertificateEventInfoTest extends WifiBaseTest {
+ private static final String TEST_CERT_HASH = "1234567890";
+ CertificateEventInfo mCertificateEventInfo;
+
+ /**
+ * test the getCert() and getCertHash() methods
+ */
+ @Test
+ public void testGetMethods() throws Exception {
+ X509Certificate cert = mock(X509Certificate.class);
+ mCertificateEventInfo = new CertificateEventInfo(cert, TEST_CERT_HASH);
+ assertEquals(mCertificateEventInfo.getCert(), cert);
+ assertTrue(TEST_CERT_HASH.equals(mCertificateEventInfo.getCertHash()));
+ }
+
+ /**
+ * test that a null certificate throws an exception
+ */
+ @Test(expected = NullPointerException.class)
+ public void testCertNullInitializer() throws Exception {
+ mCertificateEventInfo = new CertificateEventInfo(null, TEST_CERT_HASH);
+ }
+
+ /**
+ * test that a null certificate hash throws an exception
+ */
+ @Test(expected = NullPointerException.class)
+ public void testCertHashNullInitializer() throws Exception {
+ X509Certificate cert = mock(X509Certificate.class);
+ mCertificateEventInfo = new CertificateEventInfo(cert, null);
+ }
+}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index cef996f..bb16f49 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -7885,11 +7885,13 @@
SupplicantState.ASSOCIATED));
mLooper.dispatchAll();
- mCmi.sendMessage(WifiMonitor.TOFU_ROOT_CA_CERTIFICATE,
- FRAMEWORK_NETWORK_ID, 0, FakeKeys.CA_CERT0);
+ CertificateEventInfo certificateEventInfo =
+ spy(new CertificateEventInfo(FakeKeys.CA_CERT0, "1234"));
+ mCmi.sendMessage(WifiMonitor.TOFU_CERTIFICATE_EVENT,
+ FRAMEWORK_NETWORK_ID, 0, certificateEventInfo);
mLooper.dispatchAll();
verify(mInsecureEapNetworkHandler).addPendingCertificate(
- eq(eapTlsConfig.SSID), eq(0), eq(FakeKeys.CA_CERT0));
+ eq(eapTlsConfig.SSID), eq(0), eq(certificateEventInfo));
// Adding a certificate in depth 0 will cause a disconnection when TOFU is supported
DisconnectEventInfo disconnectEventInfo =
@@ -7918,9 +7920,16 @@
assumeTrue(SdkLevel.isAtLeastT());
WifiConfiguration testConfig = setupTrustOnFirstUse(true, true, true);
- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID);
+ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID,
+ testConfig.networkId);
mLooper.dispatchAll();
- verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE));
+ ArgumentCaptor<WifiConfiguration> wifiConfigurationArgumentCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+
+ // TOFU will first connect to get the certificates, and then connect once approved
+ verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME),
+ wifiConfigurationArgumentCaptor.capture());
+ assertEquals(testConfig.networkId, wifiConfigurationArgumentCaptor.getValue().networkId);
}
/**
@@ -7942,6 +7951,14 @@
eq(WifiMetricsProto.ConnectionEvent.HLF_NONE),
eq(WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN),
anyInt());
+ ArgumentCaptor<WifiConfiguration> wifiConfigurationArgumentCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+
+ // TOFU will connect only once to get the certificates, but will not proceed
+ verify(mWifiNative).connectToNetwork(eq(WIFI_IFACE_NAME),
+ wifiConfigurationArgumentCaptor.capture());
+ assertEquals(testConfig.networkId, wifiConfigurationArgumentCaptor.getValue().networkId);
+
}
/**
@@ -7976,9 +7993,16 @@
assumeTrue(SdkLevel.isAtLeastT());
WifiConfiguration testConfig = setupTrustOnFirstUse(true, true, false);
- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID);
+ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID,
+ testConfig.networkId);
mLooper.dispatchAll();
- verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE));
+ ArgumentCaptor<WifiConfiguration> wifiConfigurationArgumentCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+
+ // TOFU will first connect to get the certificates, and then connect once approved
+ verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME),
+ wifiConfigurationArgumentCaptor.capture());
+ assertEquals(testConfig.networkId, wifiConfigurationArgumentCaptor.getValue().networkId);
}
/**
@@ -8001,6 +8025,13 @@
eq(WifiMetricsProto.ConnectionEvent.HLF_NONE),
eq(WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN),
anyInt());
+ ArgumentCaptor<WifiConfiguration> wifiConfigurationArgumentCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+
+ // TOFU will connect only once to get the certificates, but will not proceed
+ verify(mWifiNative).connectToNetwork(eq(WIFI_IFACE_NAME),
+ wifiConfigurationArgumentCaptor.capture());
+ assertEquals(testConfig.networkId, wifiConfigurationArgumentCaptor.getValue().networkId);
}
/**
@@ -8034,7 +8065,8 @@
assumeFalse(SdkLevel.isAtLeastT());
WifiConfiguration testConfig = setupLegacyEapNetworkTest(true);
- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID);
+ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID,
+ testConfig.networkId);
mLooper.dispatchAll();
verify(mWifiMetrics, never()).endConnectionEvent(
any(), anyInt(), anyInt(), anyInt(), anyInt());
@@ -8067,7 +8099,8 @@
assumeFalse(SdkLevel.isAtLeastT());
WifiConfiguration testConfig = setupLegacyEapNetworkTest(false);
- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID);
+ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID,
+ testConfig.networkId);
mLooper.dispatchAll();
verify(mWifiMetrics, never()).endConnectionEvent(
any(), anyInt(), anyInt(), anyInt(), anyInt());
diff --git a/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java b/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java
index b83f6e7..356737f 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
import android.app.Notification;
import android.content.BroadcastReceiver;
@@ -42,12 +43,13 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiContext;
import android.net.wifi.WifiEnterpriseConfig;
-import android.net.wifi.util.HexEncoding;
import android.os.Handler;
import android.text.TextUtils;
+import android.text.format.DateFormat;
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.modules.utils.build.SdkLevel;
import com.android.server.wifi.util.CertificateSubjectInfo;
import com.android.wifi.resources.R;
@@ -60,13 +62,14 @@
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import org.mockito.stubbing.Answer;
-import java.nio.charset.StandardCharsets;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import javax.security.auth.x500.X500Principal;
-
/**
* Unit tests for {@link com.android.server.wifi.InsecureEapNetworkHandlerTest}.
*/
@@ -81,8 +84,192 @@
private static final String TEST_SSID = "\"test_ssid\"";
private static final String TEST_IDENTITY = "userid";
private static final String TEST_PASSWORD = "myPassWord!";
- private static final String TEST_EXPECTED_SHA_256_SIGNATURE = "78:A6:27:31:03:D1:7C:39:A0:B6:12"
- + ":6E:22:6C:EC:70:E3:33:37:F4:BC:6A:38:06:74:01:B5:4A:33:E7:8E:AD";
+ private static final String TEST_EXPECTED_SHA_256_SIGNATURE = "54:59:5D:FC:64:9C:17:72:C0:59:"
+ + "9D:25:BD:1F:04:18:E6:00:AB:F4:0A:F0:78:D8:9A:FF:56:C0:7C:89:96:2F";
+ private static final int TEST_GEN_CA_CERT = 0;
+ private static final int TEST_GEN_CA2_CERT = 1;
+ private static final int TEST_GEN_SERVER_CERT = 2;
+ private static final int TEST_GEN_SELF_SIGNED_CERT = 3;
+ private static final int TEST_GEN_FAKE_CA_CERT = 4;
+
+ private static final String TEST_SERVER_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIGPjCCBCagAwIBAgIUN2Ss1JmvjveRe97iWoNh4V+Y5LYwDQYJKoZIhvcNAQEM\n"
+ + "BQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQK\n"
+ + "DBJBbmRyb2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8\n"
+ + "MDoGA1UEAwwzQW5kcm9pZCBQYXJ0bmVyIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5k\n"
+ + "IGRldmVsb3BtZW50MB4XDTIzMDQxMzAyMTYwMVoXDTQzMDQwODAyMTYwMVowgYMx\n"
+ + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMR0wGwYDVQQKDBRBbmRy\n"
+ + "b2lkIFdpLUZpIFRlc3RlcjEYMBYGA1UECwwPYW5kcm9pZHdpZmkub2VtMSYwJAYD\n"
+ + "VQQDDB1BbmRyb2lkIFdpLUZpIE9FTSBUZXN0IFNlcnZlcjCCAiIwDQYJKoZIhvcN\n"
+ + "AQEBBQADggIPADCCAgoCggIBAKveC9QnsxvM2TMzkUINabtM2Bi5M5gzV4v1MN0h\n"
+ + "n1XjXhfRXwwLMK9xtV05r91YQaOTPkHNgA6nhjmL7agcquGPlR7nuS04oxCaqfo4\n"
+ + "unbroyyqDMaXd8U6B1VlvWSbWAAhBEEAPYDhFXF9V83XHEGcp61Hs4VetGmlC3tW\n"
+ + "W1CLIk+o9JRYsZeK4Q1DurAY7YPU8U84QNxPG7OXg+ensGtspuLLNFEdnd9tSi45\n"
+ + "u5KyPpnSwTdRGSCfMVocxj0EINpdrLnWZyf9NX8Uo7tg/D0TFVBo+MbKjgItIdMg\n"
+ + "STLQwceOdOGHZTPiItzpFcP9EA5ug5gXobPjzDTJO2S3NhUt5NURfGr/wyepxR25\n"
+ + "PDRhBgc/xwc7JrtDGaqmknguZuf7Zai/m4iquC0Wh38bWKms8R0ND/H923aFppxp\n"
+ + "vzX/sWotsTYWiGMehh7v6iwIYADifsXBlJXTUhTZt6cnwttZYfp5oqymCsIhXKVU\n"
+ + "IXOE/PLcU71G9U+jCa7PNs5X5LgqorNPABOpkVL+fDpvopNCdhOEVvwCAIl4tIxl\n"
+ + "M0goFbBmY1wnFFYIUki91UfbeUimCUbBq/RSxuXn3liVB/X+dnyjJ3RnNxJ3Wy1m\n"
+ + "mcHFIVV5VxN6tC7XTXYgZAv0EJGCcVn0RN3ldPWGRLTEIQu7cXRSfqs89N4S31Et\n"
+ + "SjaxAgMBAAGjgZMwgZAwHQYDVR0OBBYEFHh9fcIU3LHamK7PdpasvHmzyRoLMB8G\n"
+ + "A1UdIwQYMBaAFH7ro7AWsBlMNpyRXHGW1hG4c1ocMAkGA1UdEwQCMAAwCwYDVR0P\n"
+ + "BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMCEGA1UdEQQaMBiCFnNlcnZlci5h\n"
+ + "bmRyb2lkd2lmaS5vZW0wDQYJKoZIhvcNAQEMBQADggIBAOIkOLyF8mmYvj8TeM2V\n"
+ + "d4YMj4sWf7L5C2lq9OGBJwZad1xytymWWZ7PpNf1MopabfUzxPjw5EfMC94MJmpf\n"
+ + "gqYOwFAye5fXQ8CLC39tb681u44tv/B5vqP74TKVhCR8O1YCsIssa8t8e5nIwcYr\n"
+ + "fj3SBu7iOLtL7zjfEXFo3oSEwVYnvS3lhZL8NTrrHscy/ZLFE3nGRq2d3jPbyuoH\n"
+ + "1FJwenxnD6a/AztERPkRNGk2oSFkWecNU9PC9w3bI5wF4I2AIaFgBOj20S7pVtq7\n"
+ + "7nhKnQFrZYVeWbqbInQcRAcSopI6D6tB/F/T9R1WCWBxvpwdciv7BeNgOtGKAszA\n"
+ + "z0sOxI6O4U77R+tFeb0vCwC0OhVL3W0zX3Fy2835D/hC2P1jmMBlxLVKYHY48RBC\n"
+ + "sG1I1qAMD4eXle8rG9MkB9cE5KfncjCrzSQjT8gs7QBTafb6B3WDdwzfaCaQTOOF\n"
+ + "Tsyrdq0TTJP71bt5qWTr6UZIBE5Tjel+DPpvQlPZPYygXPrI3WBcT12VLhti0II6\n"
+ + "1jgkS8fPLR0VypHR02V5fqCRmy9ln0rSyHXFwL3JpeXYD92eLOKdS1MhIUN4bDxZ\n"
+ + "fiXXVKpKU4gqqWAan2RjbBzQjsi6Eh3yuDm2SAqNZVacpOt7BIslqEZ+Og6KhTTk\n"
+ + "DCzyEOB87ySrUWu3PN3r2sJN\n"
+ + "-----END CERTIFICATE-----";
+
+ private static final String TEST_CA_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIGADCCA+igAwIBAgIUFkmrYCj/UYNrizDdMATu6dE3lBIwDQYJKoZIhvcNAQEM\n"
+ + "BQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQK\n"
+ + "DBJBbmRyb2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8\n"
+ + "MDoGA1UEAwwzQW5kcm9pZCBQYXJ0bmVyIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5k\n"
+ + "IGRldmVsb3BtZW50MB4XDTIzMDQxMzAyMTYwMVoXDTQzMDQwODAyMTYwMVowgZcx\n"
+ + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQKDBJBbmRy\n"
+ + "b2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8MDoGA1UE\n"
+ + "AwwzQW5kcm9pZCBQYXJ0bmVyIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5kIGRldmVs\n"
+ + "b3BtZW50MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9JERd2HVp/PI\n"
+ + "3WmaaHDKHDuWZoxUDlyVrTDd1Vu2zhH3A5KJ232QOMxJiLdZ/KxgcpGlAEllijae\n"
+ + "xihxhkHEYr7ff2/p6ZhUWr+0vuk8f4TZsKDAE0SoZoDBHTIbrJf8hHM5/+R//sx1\n"
+ + "/fTf8abOj20zyeWmXqvUNXoVKiRvjiZD69tcRHmfmTOMX0lAirOel8ZwwDFamH8d\n"
+ + "wov0IIyd58m6CV91WnScgg7TOzw/IGpccft73RbDw7cHU5i3G3KhOqamwJbErgya\n"
+ + "x97AsSVCqjBz7rEwm6pHjUagbgVAk9ULmI1McQzMINIrOWRF0Q8awWpvDNwPu86J\n"
+ + "W/LfyzAruWtriimycpl7wv0b/f7JhKerG0+44JUI0sgTz/kobAsU8nfYSyVu8+cX\n"
+ + "HwnDE2jBGB6co2Y00eVKxy6+gWTekpQTyHuPoCieNDukC/38Mj+U0KUZkgGv4CL7\n"
+ + "zaVBGzjSjtnAp47aXciaDvDbpST23ICS7TN5cUnXQ1fWfNUMNkEbIPy2mrlRoCxg\n"
+ + "OJ67UEvGIygE0IUvwDfFvF21+1yKk6D/kU9gMgd6DKtvWj1CIyKXWf+rQ01OHNhX\n"
+ + "YcOTkF5aF2WU558DuS+utGBzXWFsLxqBRe9nDb9W/SlrT2jajfwLelMddvtZmVsY\n"
+ + "NG8IeY8lDs5hcFBvm/BDr0SvBDhs9H0CAwEAAaNCMEAwHQYDVR0OBBYEFH7ro7AW\n"
+ + "sBlMNpyRXHGW1hG4c1ocMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGG\n"
+ + "MA0GCSqGSIb3DQEBDAUAA4ICAQBINF6auWUhCO0l/AqO5pLgOqZ7BjAzHGDNapW+\n"
+ + "3nn2YicDD/X2eJASfsd3jN5JluBlbLqRBBWnIsNG/fyKxY8I4+IrR1x8ovwBjeJ3\n"
+ + "McQeCW2zedluVp2SW3LaNQS+aptXHATJ6O8EOny2LDM+obEtFyLuDC89a1TXjEdj\n"
+ + "XGIYmSJ8RwpKAi4u6ff4jhtNTSEa/eIUE5zUREV0916xtmu5y1vlmsEbpLEquOph\n"
+ + "ZWxpUVTqGEyc0hHaivAWyBG1dtRgov5olzHchM2TsEq/VufiRAw5uzRQ/sAyVjj4\n"
+ + "pcvWnLDLTYk/+uIG1zmbc0rNpAC7b3tplA4OqTtFb3yX0ppPFUg4OaxhMyu4WqS3\n"
+ + "roNiXc8BmtfzMqyWAG21QUfosLa8heiiHgnvkiUa9V2oJ4kWAhOTmLdU70aocu4N\n"
+ + "pcN5jcT5hSl/A91Lvfht0C9BLOrXU+RDCNAVIUnnWSrgduUPTydKVdUkLxau4G/+\n"
+ + "G8fKAyeCouFNq7bp4DEMkgqAWpx96Qe6FLxAS59Ig3tI8MZSieBZezJyjP4GWtuq\n"
+ + "QsnARbwD7z73FWQ+eqXOhkoqDoQc8E2lQGe8OGbacGuUwXo3PUgGaJobz+2Hqa9g\n"
+ + "6AnBkH6AbvooUwSWSCyYIf2LA+GvZotI+PXWuQL7dqWtkaNf98qqfnlZXjp51e+h\n"
+ + "B8nquw==\n"
+ + "-----END CERTIFICATE-----";
+
+ private static final String TEST_CA2_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIGADCCA+igAwIBAgIUGm2nmrZw4ADU7h/TGKd67Uz5bJIwDQYJKoZIhvcNAQEM\n"
+ + "BQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQK\n"
+ + "DBJBbmRyb2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8\n"
+ + "MDoGA1UEAwwzQW5vdGhlciBBbmRyb2lkIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5k\n"
+ + "IGRldmVsb3BtZW50MB4XDTIzMDQxMzAyMTkxOVoXDTQzMDQwODAyMTkxOVowgZcx\n"
+ + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQKDBJBbmRy\n"
+ + "b2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8MDoGA1UE\n"
+ + "AwwzQW5vdGhlciBBbmRyb2lkIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5kIGRldmVs\n"
+ + "b3BtZW50MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvv7PYhFHK+nC\n"
+ + "KoDiQI7dhDFTNU4RxTTsxMRSt1n/FJGZX/r8nnr76gB+oofFVjKQusYhuquKGPGq\n"
+ + "ZfrfmtsNhcVBMnNRjZkBWpNb3XO+7F+Qd/gT7yoiZ0L3Ef4QMCGqNrf10EWmXvVQ\n"
+ + "tpaM7RrkmlW6Zu2VbfP/iQQ7EVFrFWmnZfkCxpkLT+LK+pxwNxtJz5l7VRYkXelw\n"
+ + "9vFdq81C+obBpLWg62mNVNa25g6y46YrSOPyxhiemiRih+avIZ9Z6/7qRoVu7t8U\n"
+ + "NpxzMdsDL5bJREadsjpQWZr7A+umm0nlod1DB204K18Y5Z4GuOEGifdHIUmb+3c4\n"
+ + "Kz14FzBahyc3xsZL73AsGEVWLHIQQ/kjepomVl8HuSHdgw6SZR30JhWgU/bcVl01\n"
+ + "8qc6qH7x3e64Ip9xHdng42oPJHEKYipRed3AXzlCQ7Lc9MeAeR+nB9JuSNc6HW0L\n"
+ + "eh9Po0cDJa194UfNeqJ7SG2uNpeg/OUbM+M3iO3dmCRcV3GzirbT8eHZk3Cor3gb\n"
+ + "h9AzmJnHyRaRc9Xtj7AE8swJRvAoWVlCzcBcvaLAW0hn2DWXbWXHDf63Q8n5F4J5\n"
+ + "pf//2eXWaOXFLvkm9wYUj6kXOehcibB2O1F1YvqWE3XZ5GTDq/+E5wK55aifq+bz\n"
+ + "l1Mb1ILIB3cEEL9w+0ClHCno+2XGMOkCAwEAAaNCMEAwHQYDVR0OBBYEFH0KeaUK\n"
+ + "koS2PMYfpcanoTkRBTzmMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGG\n"
+ + "MA0GCSqGSIb3DQEBDAUAA4ICAQCnnL83fEA3g8fiJHpeSNSVZ4R3VunQU2BDkwUj\n"
+ + "NgFWPMsZNQcKoChUA5mb8wOM/fk9tdjMsQR5fRO30B94Eoo9NM39HztBcvvLV9i7\n"
+ + "qNQCTjFE7zf4weX6K3tZICR8nZ1Ogccp3itEDkNpOylFLdQxkc29RrKcuculb3PM\n"
+ + "C7IMREKROKFzrAwWkFAaxJGfByTRfjOqWJFgdRq/GHU2yCKkCLN4zRLjr5ZaAk2J\n"
+ + "+8b+Y1/pIW4j2FAB7ebmq0ZbMbdc+EFdVf36WrsWf54L3DsZOuoaC+2wTsyWQ0b/\n"
+ + "8tqJ/XS39I4uo8KpI5//aQpM1usxP0/pWUm9sTXE618Yf2Ynh64eDQHPIAmt+Xoh\n"
+ + "BfIx+nXVkCl4DGGdwvOURUULdHN9wf6YPOXxaMEYxQRGMwmBAlmiDaH41xeaht/A\n"
+ + "+iv3y918rJFDAXWKvGia8oDi1xIL+IDZ1AGVByNp+C/AE5BTV2m9UHZyXsXrMiQA\n"
+ + "ezUrVpiWB6h4C4rUuaucQv1gO6gEPZGEDdvIG8TGJg8wvLL0oZiyaL3gQxlGs0CZ\n"
+ + "tbDGqugtlh4RLeJ1N/TTFkLzf4CAgDTxfqhMKXkFvpMvO6ZHOT7xC0sdaD2FbZRj\n"
+ + "h5ziC9nvWEdTA8RLr0i/r5nFb6GsxmEk6NYFmpnyo5pvlxf5xqOhsJZlcKnUJ8SQ\n"
+ + "NIGLmw==\n"
+ + "-----END CERTIFICATE-----";
+
+ private static final String TEST_SELF_SIGNED_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIFxzCCA6+gAwIBAgIUB8Kqwhhhs1liW23ve7pZsFlv0zAwDQYJKoZIhvcNAQEM\n"
+ + "BQAwezELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExGzAZBgNVBAoM\n"
+ + "EkFuZHJvaWQgV2ktRmkgVGVzdDEYMBYGA1UECwwPYW5kcm9pZHdpZmkuZGV2MSAw\n"
+ + "HgYDVQQDDBdTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0ZTAeFw0yMzA0MTMwMjE0MTda\n"
+ + "Fw00MzA0MDgwMjE0MTdaMHsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y\n"
+ + "bmlhMRswGQYDVQQKDBJBbmRyb2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJv\n"
+ + "aWR3aWZpLmRldjEgMB4GA1UEAwwXU2VsZi1zaWduZWQgY2VydGlmaWNhdGUwggIi\n"
+ + "MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDD0oI2c+1D4D2wc4PnhkXbtA7g\n"
+ + "64Mp/JSbnVbl7PseJKnFD/pdos5joFXFbySFqu60S905T1a3AWNwbucKc7C7IwQw\n"
+ + "gtO7uMEPr35j7MhItyAbmj89dY729yXJ8gBnNnqc8PyYEIfZmnBvSry0Tsm60298\n"
+ + "GGZ9yCQfOOb4TJFX/CIKjniI170eLCiGybOrBvG11Rx6BwwHnk1cjkDspejrkhb0\n"
+ + "13RfkQ1S0cEnylrgnn/nRDAAnOscpHRerJ6Ud2vM64iIJy206ZyU/CrhcGeBWwi9\n"
+ + "C1F4ojzvgoFW7bJahXiyEaC5R3G5WdvX5qOr/eu/yMaCAner0LHUibHc5XA02F/c\n"
+ + "LO0LpN59tTT4dx9sLJVjZQGSUxyXnKHiR5TKkoAMWAZSO5hbE4drgivKLnYmYnhC\n"
+ + "Z1rGM5R0D0gB2llAvecItmynDJNApY6L1F8wnNA9NfGUYFpeqJ8uEOn7RxAvyYmB\n"
+ + "trmUFOqL7W84d1/XzORPGQ7n1wyPfBG3xyGIm2MMvanVsLs0/9NXAYAz2ZAHJPnS\n"
+ + "DsiV+7OHtMCdgTI5BJFmiJpXKgVE+IaewQdSjXDU7bgMlll3lTVoVAiKJmxpOmZ6\n"
+ + "FFz7mkd0pYhsO5jQpNGMfl+IaoIiTx4Zg9ZjwjTcPn9eGunBLJJ8SofkhM4boLrC\n"
+ + "KSen8NYuHVDPwAOwpQIDAQABo0MwQTAdBgNVHQ4EFgQU2IB1Q35ysx0HpRttAqMU\n"
+ + "FO9OhIAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3\n"
+ + "DQEBDAUAA4ICAQBqf4zbooJ4hHeZs7Nd31G7i2WEr6/8OWTuEuDAmJkGW8WBeyUG\n"
+ + "JMrxF3U+kGxVGops4mSxMwVpcsqQa+IwkrP807dSqkuntLVGFqVo7rcQ+l8OcNUv\n"
+ + "oNQIFGPLlWPyMnjXvmWbfvgbgFoY9yUFoxFlHqsVf+1mEvTmW9ya4BGT2hlfvtb6\n"
+ + "Jfvrrocg9zGSnBs9oyI+GzP4Xdqd0riXfk6OuFH3R05/cQj7SlPm8LU1J7ZML/4H\n"
+ + "1AuMg+Ql8vxql4IzIk93CDR8Hq1jb3MhF/ae9UfttuNnHT4vu5X/6qLqWNKMs3zP\n"
+ + "DQQaYkqxWTUWiNlWV7i7pXn8e2J8ZkRHVELvrpdXLKIfL6RxjzKWY+TKiHY+F48I\n"
+ + "JwCAbL1FX+NzB2dS0RxXk/RTAxagenfmDcY1notHNsnDZB54cP9nv+N3wqkDoaKg\n"
+ + "nqOZTlIRWJ4agygqGaxieUuZRgy/AE/dSGpetlXAScKUvhCcO22qXL2jSjBAg5+k\n"
+ + "AynUuiZxdogXbvXrAwSWAVwlz8qEOK3NPFYnEKcjgNbTxiUHp3P/ULBgHQo55o9K\n"
+ + "DdUEbIurd02xG6usEDWxR5ds/RPy6VZ5c6bFUiTEsfMMmQotPL/btuPVXsSdJUR4\n"
+ + "xcxpcV7zx9IjFs/IylyQ1YEYDKWV+nH7iiOigO5WiZ5ck2Wa/Tk3uXg1Ew==\n"
+ + "-----END CERTIFICATE-----\n";
+
+ private static final String TEST_FAKE_CA_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIGADCCA+igAwIBAgIUIxVGWM5Wrs86DpDA2+fo53UryqMwDQYJKoZIhvcNAQEM\n"
+ + "BQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQK\n"
+ + "DBJBbmRyb2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8\n"
+ + "MDoGA1UEAwwzQW5kcm9pZCBQYXJ0bmVyIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5k\n"
+ + "IGRldmVsb3BtZW50MB4XDTIzMDQxMzE1MzkyM1oXDTQzMDQwODE1MzkyM1owgZcx\n"
+ + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQKDBJBbmRy\n"
+ + "b2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8MDoGA1UE\n"
+ + "AwwzQW5kcm9pZCBQYXJ0bmVyIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5kIGRldmVs\n"
+ + "b3BtZW50MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhTF8MJsucR5P\n"
+ + "6oN/Nho92EYz9b3m7n52m9KgI/G6/9bK9PSDZ6Z6U3qNxpG7nFML+5qyk+qeBHP8\n"
+ + "39lGNNoH1c2dQDXw3oLjOmd1UoN+zSZBznLwkDD8YQYafz1GWRcI34FYDgiPuSx7\n"
+ + "o4+O4hxcimrelhoNRQcRsrZFoUyJZjtPy2Z5DTZTB7udg1QwZ+7+pHCme3DB2Im/\n"
+ + "Eszsmm2TAG6yM3G/lxphLZMhUFy6kjeeIiuar56ED6dg7qEqdeIznt2gGKolXRWs\n"
+ + "vPW4a5NX1RUjsQxOcKEQnrXZXJ9mATptY1hOxuP6kg8Jzh0tN/NzyyERGFvnvhGz\n"
+ + "sN7CkTUhPOKUW3dVrKl9ZJ9PbYZ6xbpbOWOR/5znYQ/f3+bxxibbFI3WN/89VO50\n"
+ + "WEzwfmiGiWC6Bz0iBoAmGjCxySbJg8iDCjrbRexkFsOJ84jlY0fDrfaqY1+WuyYu\n"
+ + "vdk+w4lzk0wYRbp+oRuIXplMyZDsS15CPq+svoYeNCCOXlkRiMLuq/SpkdM8lRKp\n"
+ + "Mrsc1AckI+BGVqh8S9lyJoP67uDmba1FUw7X3IMCkZQwvFduLkJLNYwO6QDV2M6R\n"
+ + "nUCVCx+vxJdlIOLNQIAeKW9jzfASom4ehZY2HHErbUYGKzFQJJ/2+uQLLYn7PsaE\n"
+ + "gYTYA1naakQegCgbD2UsbKqrEfOiHEECAwEAAaNCMEAwHQYDVR0OBBYEFBiYeS/E\n"
+ + "IQ5+IoQ3bsXoibK3QuMzMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGG\n"
+ + "MA0GCSqGSIb3DQEBDAUAA4ICAQACOOZdfcQ53BF43glA/0VuFeXQ+VS+keR9aFBX\n"
+ + "caKrIbFXSns9EsnvKj1L/IoHem5k4LkMFoNgE1Skit2iktPYs6unV83p99PG6EQo\n"
+ + "RG1CeZ50cHzZK6N56MbwZUGRy/p6Zr9ak9d6XE8GpvSwMW8XebrLPtgSBvpI+WIZ\n"
+ + "epMVg7v8AIIRQuoR2VtZ7RZF/X1kwfU5t2aASVBnxTjlSy6KtBLuL+Vu4Aefa+Z0\n"
+ + "d9Ma2jZV+hwWp0X6piSrVKkMZIR5tlvwJootNBlO0J1Jn4J0ecGNEGXmFwz4adnK\n"
+ + "eYfpuNBJI4CKq7mv2Aszsvg0rQxfKlN8LV7gSNu3H6BjjkNUtHI6uwsajJfEmGKD\n"
+ + "YRpAFgZq7FzRwoI8uWr0Bucz6+qxpISi48t0pmceSVpn6UV1UdSebLo8CX5P283F\n"
+ + "yUqlw2hMpo22Gm3uW8GfPyHfMfsqfMU+7BCP38DDnhcGUO3CTINjREXUGtn6CuWS\n"
+ + "ImhmATld6KJNtRCql3zQnaEO84IvKdFVOkm5q9qQjNWDr1oYsLhxoZJZjKK2rP5F\n"
+ + "GRbMvqDhmzrV0yG+sIyW+aEjBl44bVjWQnFhGjtNr1BOOftSyjnseYiioLbiiaYG\n"
+ + "9Mqu78VmTWJzfxyOP2QPK5K00jnVBZ+jQH0NyIE9yf2Cg/llfYRoHsz80cfY/DNt\n"
+ + "jUR49A==\n"
+ + "-----END CERTIFICATE-----";
@Mock WifiContext mContext;
@Mock WifiConfigManager mWifiConfigManager;
@@ -95,12 +282,14 @@
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private Notification.Builder mNotificationBuilder;
@Mock private WifiDialogManager.DialogHandle mTofuAlertDialog;
-
+ @Mock private java.text.DateFormat mDateFormat;
@Captor ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
MockResources mResources;
InsecureEapNetworkHandler mInsecureEapNetworkHandler;
+ private MockitoSession mSession;
+
/**
* Sets up for unit test
*/
@@ -142,11 +331,19 @@
when(mFrameworkFacade.makeNotificationBuilder(any(), any()))
.thenReturn(mNotificationBuilder);
+
+ // static mocking
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(DateFormat.class, withSettings().lenient())
+ .startMocking();
+ when(DateFormat.getMediumDateFormat(any())).thenReturn(mDateFormat);
+ when(mDateFormat.format(any())).thenReturn("April 12, 2023");
}
@After
public void cleanUp() throws Exception {
validateMockitoUsage();
+ mSession.finishMocking();
}
/**
@@ -354,35 +551,70 @@
isTrustOnFirstUseSupported, isUserSelected, needUserApproval);
}
- private X509Certificate generateMockCert(String subject, String issuer, boolean isCa) {
- X509Certificate mockCert = mock(X509Certificate.class);
- X500Principal mockSubjectPrincipal = mock(X500Principal.class);
- when(mockCert.getSubjectX500Principal()).thenReturn(mockSubjectPrincipal);
- when(mockSubjectPrincipal.getName()).thenReturn("C=TW,ST=Taiwan,L=Taipei"
- + ",O=" + subject + " Organization"
- + ",CN=" + subject
- + ",1.2.840.113549.1.9.1=#1614" + String.valueOf(HexEncoding.encode(
- (subject + "@email.com").getBytes(StandardCharsets.UTF_8))));
- try {
- when(mockCert.getEncoded()).thenReturn(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
- } catch (Exception e) {
- // nothing
+ /**
+ * Verify Trust On First Use flow with server certificate pinning
+ * - Single depth server certificate by signed by some unknown issuer, CA flag not set
+ * - This network is selected by a user.
+ * - Accept the connection.
+ */
+ @Test
+ public void verifyTrustOnFirstUseFlowWithServerCertPinning1() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastT());
+ runServerCertPinningTest(TEST_GEN_SERVER_CERT);
+ }
+
+ /**
+ * Verify Trust On First Use flow with server certificate pinning
+ * - Single depth server certificate by signed by some unknown issuer, CA flag set
+ * - This network is selected by a user.
+ * - Accept the connection.
+ */
+ @Test
+ public void verifyTrustOnFirstUseFlowWithServerCertPinning2() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastT());
+ runServerCertPinningTest(TEST_GEN_CA_CERT);
+ }
+
+ private void runServerCertPinningTest(int type)
+ throws Exception {
+ WifiConfiguration config = prepareWifiConfiguration(true);
+ setupTest(config, true, true);
+
+ CertificateEventInfo mockServerCert = generateMockCertEventInfo(type);
+ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert);
+ verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, true,
+ true, false, null, mockServerCert.getCert());
+ }
+
+ private CertificateEventInfo generateMockCertEventInfo(int type) throws Exception {
+ CertificateEventInfo certificateEventInfo = mock(CertificateEventInfo.class);
+ X509Certificate cert = getCertificate(type);
+
+ when(certificateEventInfo.getCert()).thenReturn(cert);
+ when(certificateEventInfo.getCertHash()).thenReturn("12345678");
+ return certificateEventInfo;
+ }
+
+ private X509Certificate getCertificate(int type) throws Exception {
+ String certString;
+
+ if (type == TEST_GEN_CA_CERT) {
+ certString = TEST_CA_CERTIFICATE;
+ } else if (type == TEST_GEN_CA2_CERT) {
+ certString = TEST_CA2_CERTIFICATE;
+ } else if (type == TEST_GEN_SERVER_CERT) {
+ certString = TEST_SERVER_CERTIFICATE;
+ } else if (type == TEST_GEN_SELF_SIGNED_CERT) {
+ certString = TEST_SELF_SIGNED_CERTIFICATE;
+ } else if (type == TEST_GEN_FAKE_CA_CERT) {
+ certString = TEST_FAKE_CA_CERTIFICATE;
+ } else {
+ throw (new Exception());
}
- X500Principal mockIssuerX500Principal = mock(X500Principal.class);
- when(mockCert.getIssuerX500Principal()).thenReturn(mockIssuerX500Principal);
- when(mockIssuerX500Principal.getName()).thenReturn("C=TW,ST=Taiwan,L=Taipei"
- + ",O=" + issuer + " Organization"
- + ",CN=" + issuer
- + ",1.2.840.113549.1.9.1=#1614" + String.valueOf(HexEncoding.encode(
- (issuer + "@email.com").getBytes(StandardCharsets.UTF_8))));
- when(mockCert.getSignature()).thenReturn(new byte[]{
- (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
- (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
- (byte) 0x90, (byte) 0xab, (byte) 0xcd, (byte) 0xef});
-
- when(mockCert.getBasicConstraints()).thenReturn(isCa ? 99 : -1);
- return mockCert;
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ InputStream in = new ByteArrayInputStream(certString.getBytes());
+ return (X509Certificate) certFactory.generateCertificate(in);
}
private WifiConfiguration prepareWifiConfiguration(boolean isAtLeastT) {
@@ -475,35 +707,13 @@
WifiConfiguration config = prepareWifiConfiguration(isAtLeastT);
setupTest(config, isAtLeastT, isTrustOnFirstUseSupported);
- X509Certificate mockCaCert = generateMockCert("ca", "ca", true);
- X509Certificate mockServerCert = generateMockCert("server", "ca", false);
+ CertificateEventInfo mockCaCert = generateMockCertEventInfo(TEST_GEN_CA_CERT);
+ CertificateEventInfo mockServerCert = generateMockCertEventInfo(TEST_GEN_SERVER_CERT);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert);
verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported,
- isUserSelected, needUserApproval, mockCaCert, mockServerCert);
- }
-
- /**
- * Verify Trust On First Use flow with a self-signed CA cert.
- * - This network is selected by a user.
- * - Accept the connection.
- */
- @Test
- public void verifyTrustOnFirstUseAcceptWhenConnectByUserWithSelfSignedCaCert()
- throws Exception {
- assumeTrue(SdkLevel.isAtLeastT());
- boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true;
- boolean needUserApproval = true;
-
- WifiConfiguration config = prepareWifiConfiguration(isAtLeastT);
- setupTest(config, isAtLeastT, isTrustOnFirstUseSupported);
-
- X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false);
- mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert);
-
- verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported,
- isUserSelected, needUserApproval, mockSelfSignedCert, mockSelfSignedCert);
+ isUserSelected, needUserApproval, mockCaCert.getCert(), mockServerCert.getCert());
}
/**
@@ -544,9 +754,9 @@
setupTest(config, isAtLeastT, isTrustOnFirstUseSupported);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1,
- generateMockCert("ca", "ca", true));
+ generateMockCertEventInfo(TEST_GEN_CA_CERT));
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0,
- generateMockCert("server", "ca", false));
+ generateMockCertEventInfo(TEST_GEN_SERVER_CERT));
mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected);
assertTrue(config.enterpriseConfig.isTrustOnFirstUseEnabled());
@@ -572,37 +782,15 @@
isInsecureEnterpriseConfigurationAllowed);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1,
- generateMockCert("ca", "ca", true));
+ generateMockCertEventInfo(TEST_GEN_CA_CERT));
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0,
- generateMockCert("server", "ca", false));
+ generateMockCertEventInfo(TEST_GEN_SERVER_CERT));
mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected);
verify(mCallbacks, never()).onError(any());
}
/**
- * Verify that it reports errors if the cert chain is headless.
- */
- @Test
- public void verifyOnErrorWithHeadlessCertChain() throws Exception {
- assumeTrue(SdkLevel.isAtLeastT());
- boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true;
-
- WifiConfiguration config = prepareWifiConfiguration(isAtLeastT);
- setupTest(config, isAtLeastT, isTrustOnFirstUseSupported);
-
- // Missing root CA cert.
- mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0,
- generateMockCert("server", "ca", false));
-
- mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected);
- verify(mCallbacks).onError(eq(config.SSID));
- verify(mWifiConfigManager, atLeastOnce()).updateNetworkSelectionStatus(eq(config.networkId),
- eq(WifiConfiguration.NetworkSelectionStatus
- .DISABLED_BY_WIFI_MANAGER));
- }
-
- /**
* Verify that is reports errors if the server cert issuer does not match the parent subject.
*/
@Test
@@ -613,9 +801,35 @@
WifiConfiguration config = prepareWifiConfiguration(isAtLeastT);
setupTest(config, isAtLeastT, isTrustOnFirstUseSupported);
- X509Certificate mockCaCert = generateMockCert("ca", "ca", true);
+ CertificateEventInfo mockCaCert = generateMockCertEventInfo(TEST_GEN_CA2_CERT);
// Missing intermediate cert.
- X509Certificate mockServerCert = generateMockCert("server", "intermediate", false);
+ CertificateEventInfo mockServerCert = generateMockCertEventInfo(TEST_GEN_SERVER_CERT);
+ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert);
+ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert);
+
+ mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected);
+ verify(mCallbacks).onError(eq(config.SSID));
+ verify(mWifiConfigManager, atLeastOnce()).updateNetworkSelectionStatus(eq(config.networkId),
+ eq(WifiConfiguration.NetworkSelectionStatus
+ .DISABLED_BY_WIFI_MANAGER));
+ }
+
+ /**
+ * Verify that it reports errors if the issuer is a fake Root CA with the same subject of the
+ * real Root CA. Simulates an attack where the leaf is copied from the real server but a fake
+ * Root CA that an attacker controls is attached.
+ */
+ @Test
+ public void verifyOnErrorWithFakeRootCaCertInTheChain() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastT());
+ boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true;
+
+ WifiConfiguration config = prepareWifiConfiguration(isAtLeastT);
+ setupTest(config, isAtLeastT, isTrustOnFirstUseSupported);
+
+ // Fake Root CA that didn't sign the server cert
+ CertificateEventInfo mockCaCert = generateMockCertEventInfo(TEST_GEN_FAKE_CA_CERT);
+ CertificateEventInfo mockServerCert = generateMockCertEventInfo(TEST_GEN_SERVER_CERT);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert);
@@ -645,7 +859,8 @@
mCallbacks,
WIFI_IFACE_NAME,
mHandler);
- X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false);
+ CertificateEventInfo mockSelfSignedCert =
+ generateMockCertEventInfo(TEST_GEN_SELF_SIGNED_CERT);
mInsecureEapNetworkHandler.addPendingCertificate("NotExist", 0, mockSelfSignedCert);
}
@@ -659,12 +874,13 @@
// Missing root CA cert.
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0,
- generateMockCert("server", "ca", false));
+ generateMockCertEventInfo(TEST_GEN_SERVER_CERT));
// The wrong cert chain should be cleared after this call.
mInsecureEapNetworkHandler.prepareConnection(config);
- X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false);
+ CertificateEventInfo mockSelfSignedCert =
+ generateMockCertEventInfo(TEST_GEN_SELF_SIGNED_CERT);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert);
mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected);
@@ -679,7 +895,8 @@
WifiConfiguration config = prepareWifiConfiguration(isAtLeastT);
setupTest(config, isAtLeastT, isTrustOnFirstUseSupported);
- X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false);
+ CertificateEventInfo mockSelfSignedCert =
+ generateMockCertEventInfo(TEST_GEN_SELF_SIGNED_CERT);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert);
// Pass another PSK config which is not the same as the current one.
@@ -701,16 +918,14 @@
private void verifyTrustOnFirstUseFlowWithDefaultCerts(WifiConfiguration config,
int action, boolean isTrustOnFirstUseSupported, boolean isUserSelected,
boolean needUserApproval) throws Exception {
- X509Certificate mockCaCert = generateMockCert("ca", "ca", true);
- X509Certificate mockServerCert = generateMockCert("server", "middle", false);
+ CertificateEventInfo mockCaCert = generateMockCertEventInfo(TEST_GEN_CA_CERT);
+ CertificateEventInfo mockServerCert = generateMockCertEventInfo(TEST_GEN_SERVER_CERT);
if (isTrustOnFirstUseSupported) {
- mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 2, mockCaCert);
- mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1,
- generateMockCert("middle", "ca", false));
+ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert);
mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert);
}
verifyTrustOnFirstUseFlow(config, action, isTrustOnFirstUseSupported,
- isUserSelected, needUserApproval, mockCaCert, mockServerCert);
+ isUserSelected, needUserApproval, mockCaCert.getCert(), mockServerCert.getCert());
}
private void verifyTrustOnFirstUseFlow(WifiConfiguration config,
@@ -727,7 +942,7 @@
any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(), any(),
any(), dialogCallbackCaptor.capture(), any());
if (isTrustOnFirstUseSupported) {
- assertTofuDialogMessage(expectedCaCert, expectedServerCert,
+ assertTofuDialogMessage(expectedServerCert,
dialogMessageCaptor.getValue());
}
if (action == ACTION_ACCEPT) {
@@ -752,7 +967,7 @@
verify(mWifiDialogManager).createSimpleDialogWithUrl(
any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(),
any(), any(), dialogCallbackCaptor.capture(), any());
- assertTofuDialogMessage(expectedCaCert, expectedServerCert,
+ assertTofuDialogMessage(expectedServerCert,
dialogMessageCaptor.getValue());
if (action == ACTION_ACCEPT) {
dialogCallbackCaptor.getValue().onPositiveButtonClicked();
@@ -777,14 +992,7 @@
if (action == ACTION_ACCEPT) {
verify(mWifiConfigManager).updateNetworkSelectionStatus(eq(config.networkId),
eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE));
- if (isTrustOnFirstUseSupported) {
- verify(mWifiConfigManager).updateCaCertificate(
- eq(config.networkId), eq(expectedCaCert), eq(expectedServerCert));
- } else {
- verify(mWifiConfigManager, never()).updateCaCertificate(
- anyInt(), any(), any());
- }
- verify(mCallbacks).onAccept(eq(config.SSID));
+ verify(mCallbacks).onAccept(eq(config.SSID), eq(config.networkId));
} else if (action == ACTION_REJECT) {
verify(mWifiConfigManager, atLeastOnce())
.updateNetworkSelectionStatus(eq(config.networkId),
@@ -800,7 +1008,6 @@
}
private void assertTofuDialogMessage(
- X509Certificate rootCaCert,
X509Certificate serverCert,
String message) {
CertificateSubjectInfo serverCertSubjectInfo =
@@ -838,8 +1045,8 @@
*/
@Test
public void verifyGetDigest() throws Exception {
- X509Certificate mockServerCert = generateMockCert("server", "ca", false);
- assertEquals(mInsecureEapNetworkHandler.getDigest(mockServerCert, "SHA256"),
- TEST_EXPECTED_SHA_256_SIGNATURE);
+ CertificateEventInfo mockServerCert = generateMockCertEventInfo(TEST_GEN_SERVER_CERT);
+ assertEquals(TEST_EXPECTED_SHA_256_SIGNATURE,
+ mInsecureEapNetworkHandler.getDigest(mockServerCert.getCert(), "SHA256"));
}
}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java b/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java
index de777a1..a201086 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java
@@ -525,11 +525,6 @@
homeSp.setFqdn(fqdn);
homeSp.setFriendlyName(friendlyName);
config.setHomeSp(homeSp);
- Map<String, String> friendlyNames = new HashMap<>();
- friendlyNames.put("en", friendlyName);
- friendlyNames.put("kr", friendlyName + 1);
- friendlyNames.put("jp", friendlyName + 2);
- config.setServiceFriendlyNames(friendlyNames);
Credential credential = new Credential();
credential.setRealm(TEST_REALM);
credential.setCaCertificate(FakeKeys.CA_CERT0);
diff --git a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImplTest.java
index 78b9316..2c52db9 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImplTest.java
@@ -15,6 +15,8 @@
*/
package com.android.server.wifi;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -32,6 +34,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
@@ -92,9 +95,14 @@
public void testOnCertificateSuccess() throws Exception {
mSupplicantStaNetworkCallbackAidlImpl.onServerCertificateAvailable(
0, "subject".getBytes(), "certHash".getBytes(), "cert".getBytes());
+ ArgumentCaptor<CertificateEventInfo> certificateEventInfoArgumentCaptor =
+ ArgumentCaptor.forClass(CertificateEventInfo.class);
verify(mWifiMonitor).broadcastCertificationEvent(
- eq(TEST_INTERFACE), eq(TEST_NETWORK_ID),
- eq(TEST_SSID), eq(0), eq(mX509Certificate));
+ eq(TEST_INTERFACE), eq(TEST_NETWORK_ID), eq(TEST_SSID), eq(0),
+ certificateEventInfoArgumentCaptor.capture());
+
+ assertEquals(mX509Certificate, certificateEventInfoArgumentCaptor.getValue().getCert());
+ assertTrue("certHash".equals(certificateEventInfoArgumentCaptor.getValue().getCertHash()));
}
/** verify onServerCertificateAvailable with illegal arguments. */
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index f8c9123..f5eaf3a 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -102,8 +102,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.security.Principal;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -485,7 +483,7 @@
public void testAddWapiPskHexNetwork() {
WifiConfiguration wapiPskNetwork = WifiConfigurationTestUtil.createWapiPskNetwork();
wapiPskNetwork.preSharedKey =
- "123456780abcdef0123456780abcdef0";
+ "123456780abcdef0123456780abcdef0123456780abcdef0123456780abcdef0";
List<WifiConfiguration> networks = new ArrayList<>();
networks.add(wapiPskNetwork);
@@ -7490,170 +7488,9 @@
}
@Test
- public void testUpdateCaCertificateSuccess() throws Exception {
- when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
- WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE);
-
- int openNetId = verifyAddNetwork(WifiConfigurationTestUtil.createOpenNetwork(), true);
- int eapPeapNetId = verifyAddNetwork(prepareTofuEapConfig(
- WifiEnterpriseConfig.Eap.PEAP, WifiEnterpriseConfig.Phase2.NONE), true);
- int eapSimNetId = verifyAddNetwork(WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE), true);
- assertTrue(mWifiConfigManager.updateCaCertificate(eapPeapNetId, FakeKeys.CA_CERT0,
- FakeKeys.CA_CERT1));
- WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(eapPeapNetId);
- assertFalse(config.enterpriseConfig.isTrustOnFirstUseEnabled());
- assertFalse(config.enterpriseConfig.isUserApproveNoCaCert());
- assertEquals(FakeKeys.CA_CERT0, config.enterpriseConfig.getCaCertificate());
- }
-
- @Test
- public void testUpdateCaCertificateWithoutAltSubjectNames() throws Exception {
- when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
- WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE);
-
- verifyAddNetwork(WifiConfigurationTestUtil.createOpenNetwork(), true);
- int eapPeapNetId = verifyAddNetwork(prepareTofuEapConfig(
- WifiEnterpriseConfig.Eap.PEAP, WifiEnterpriseConfig.Phase2.NONE), true);
- verifyAddNetwork(WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE), true);
-
- X509Certificate mockServerCert = mock(X509Certificate.class);
- Principal mockSubjectDn = mock(Principal.class);
- when(mockServerCert.getSubjectDN()).thenReturn(mockSubjectDn);
- when(mockSubjectDn.getName()).thenReturn(
- "C=TW,ST=Taiwan,L=Taipei,O=Google,CN=mockServerCert");
-
- assertTrue(mWifiConfigManager.updateCaCertificate(eapPeapNetId, FakeKeys.CA_CERT0,
- mockServerCert));
- WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(eapPeapNetId);
- assertFalse(config.enterpriseConfig.isTrustOnFirstUseEnabled());
- assertFalse(config.enterpriseConfig.isUserApproveNoCaCert());
- assertEquals("mockServerCert", config.enterpriseConfig.getDomainSuffixMatch());
- assertEquals("", config.enterpriseConfig.getAltSubjectMatch());
- }
-
- @Test
- public void testUpdateCaCertificateWithAltSubjectNames() throws Exception {
- when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
- WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE);
-
- verifyAddNetwork(WifiConfigurationTestUtil.createOpenNetwork(), true);
- int eapPeapNetId = verifyAddNetwork(prepareTofuEapConfig(
- WifiEnterpriseConfig.Eap.PEAP, WifiEnterpriseConfig.Phase2.NONE), true);
- verifyAddNetwork(WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE), true);
-
- X509Certificate mockServerCert = mock(X509Certificate.class);
- Principal mockSubjectDn = mock(Principal.class);
- when(mockServerCert.getSubjectDN()).thenReturn(mockSubjectDn);
- when(mockSubjectDn.getName()).thenReturn(
- "C=TW,ST=Taiwan,L=Taipei,O=Google,CN=mockServerCert");
- List<List<?>> altNames = new ArrayList<>();
- // DNS name 1 with type 2
- altNames.add(Arrays.asList(new Object[]{2, "wifi.android"}));
- // EMail with type 1
- altNames.add(Arrays.asList(new Object[]{1, "[email protected]"}));
- // DNS name 2 with type 2
- altNames.add(Arrays.asList(new Object[]{2, "network.android"}));
- // RID name 2 with type 8, this one should be ignored.
- altNames.add(Arrays.asList(new Object[]{8, "1.2.3.4"}));
- // URI name with type 6
- altNames.add(Arrays.asList(new Object[]{6, "http://test.android.com"}));
- when(mockServerCert.getSubjectAlternativeNames()).thenReturn(altNames);
-
- assertTrue(mWifiConfigManager.updateCaCertificate(eapPeapNetId, FakeKeys.CA_CERT0,
- mockServerCert));
- WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(eapPeapNetId);
- assertFalse(config.enterpriseConfig.isTrustOnFirstUseEnabled());
- assertFalse(config.enterpriseConfig.isUserApproveNoCaCert());
- assertEquals("", config.enterpriseConfig.getDomainSuffixMatch());
- assertEquals("DNS:wifi.android;EMAIL:[email protected];DNS:network.android;"
- + "URI:http://test.android.com",
- config.enterpriseConfig.getAltSubjectMatch());
- }
-
- @Test
- public void testUpdateCaCertificateFaiulreInvalidArgument() throws Exception {
- when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
- WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE);
-
- int openNetId = verifyAddNetwork(WifiConfigurationTestUtil.createOpenNetwork(), true);
- int eapPeapNetId = verifyAddNetwork(prepareTofuEapConfig(
- WifiEnterpriseConfig.Eap.PEAP, WifiEnterpriseConfig.Phase2.NONE), true);
- int eapSimNetId = verifyAddNetwork(WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE), true);
-
- // Invalid network id
- assertFalse(mWifiConfigManager.updateCaCertificate(-1, FakeKeys.CA_CERT0,
- FakeKeys.CA_CERT1));
-
- // Not an enterprise network
- assertFalse(mWifiConfigManager.updateCaCertificate(openNetId, FakeKeys.CA_CERT0,
- FakeKeys.CA_CERT1));
-
- // Not a certificate baseed enterprise network
- assertFalse(mWifiConfigManager.updateCaCertificate(eapSimNetId, FakeKeys.CA_CERT0,
- FakeKeys.CA_CERT1));
-
- // No cert
- assertFalse(mWifiConfigManager.updateCaCertificate(eapPeapNetId, null, null));
-
- // No valid subject
- X509Certificate mockServerCert = mock(X509Certificate.class);
- Principal mockSubjectDn = mock(Principal.class);
- when(mockServerCert.getSubjectDN()).thenReturn(mockSubjectDn);
- when(mockSubjectDn.getName()).thenReturn("");
- assertFalse(mWifiConfigManager.updateCaCertificate(eapPeapNetId, FakeKeys.CA_CERT0,
- mockServerCert));
- }
-
- @Test
- public void testUpdateCaCertificateSuccessWithSelfSignedCertificate() throws Exception {
- when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
- WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE);
-
- int openNetId = verifyAddNetwork(WifiConfigurationTestUtil.createOpenNetwork(), true);
- int eapPeapNetId = verifyAddNetwork(prepareTofuEapConfig(
- WifiEnterpriseConfig.Eap.PEAP, WifiEnterpriseConfig.Phase2.NONE), true);
- int eapSimNetId = verifyAddNetwork(WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE), true);
-
- X509Certificate mockCaCert = mock(X509Certificate.class);
- when(mockCaCert.getBasicConstraints()).thenReturn(-1);
- assertTrue(mWifiConfigManager.updateCaCertificate(eapPeapNetId, mockCaCert,
- FakeKeys.CA_CERT1));
- WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(eapPeapNetId);
- assertFalse(config.enterpriseConfig.isTrustOnFirstUseEnabled());
- assertFalse(config.enterpriseConfig.isUserApproveNoCaCert());
- assertEquals(mockCaCert, config.enterpriseConfig.getCaCertificate());
- }
-
- @Test
- public void testUpdateCaCertificateFailureWithSelfSignedCertificateAndTofuNotEnabled()
- throws Exception {
- when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
- WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE);
-
- int openNetId = verifyAddNetwork(WifiConfigurationTestUtil.createOpenNetwork(), true);
- int eapPeapNetId = verifyAddNetwork(WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.PEAP, WifiEnterpriseConfig.Phase2.NONE), true);
- int eapSimNetId = verifyAddNetwork(WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE), true);
-
- X509Certificate mockCaCert = mock(X509Certificate.class);
- when(mockCaCert.getBasicConstraints()).thenReturn(-1);
- assertFalse(mWifiConfigManager.updateCaCertificate(eapPeapNetId, mockCaCert,
- FakeKeys.CA_CERT1));
- WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(eapPeapNetId);
- assertEquals(null, config.enterpriseConfig.getCaCertificate());
- }
-
- @Test
public void testUpdateNetworkWithCreatorOverride() {
WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
int openNetId = verifyAddNetwork(WifiConfigurationTestUtil.createOpenNetwork(), true);
-
assertEquals(TEST_CREATOR_UID, mWifiConfigManager
.getConfiguredNetwork(openNetId).creatorUid);
config.networkId = openNetId;
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
index e3b3253..7cabcd8 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
@@ -369,6 +369,21 @@
WifiConfigurationUtil.VALIDATE_FOR_ADD));
}
+ @Test
+ public void testValidateNegativeCases_BadAsciiPskLengthWapi() {
+ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork();
+ assertTrue(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+
+ config.preSharedKey = "\"abcdffeeretretyetreteteteabe34tetrertertrsraaaaaaaaaaa345eqwrweewq"
+ + "weqe\"";
+ assertFalse(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+ config.preSharedKey = "\"454\"";
+ assertFalse(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+ }
+
/**
* Verify that the validate method fails to validate WifiConfiguration with bad sae length.
*/
@@ -402,6 +417,17 @@
WifiConfigurationUtil.VALIDATE_FOR_ADD));
}
+ @Test
+ public void testValidateNegativeCases_MalformedAsciiPskStringWapi() {
+ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork();
+ assertTrue(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+
+ config.preSharedKey = "\"abcdfefeeretrety";
+ assertFalse(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+ }
+
/**
* Verify that the validate method fails to validate WifiConfiguration with malformed sae
* string.
@@ -434,6 +460,20 @@
WifiConfigurationUtil.VALIDATE_FOR_ADD));
}
+ @Test
+ public void testValidateNegativeCases_BadHexPskLengthWapi() {
+ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork();
+ assertTrue(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+
+ config.preSharedKey = "abcd123456788990013453445345465465476546";
+ assertFalse(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+ config.preSharedKey = "";
+ assertFalse(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+ }
+
/**
* Verify that the validate method fails to validate WifiConfiguration with malformed psk
* string.
@@ -449,6 +489,17 @@
WifiConfigurationUtil.VALIDATE_FOR_ADD));
}
+ @Test
+ public void testValidateNegativeCases_MalformedHexPskStringWapi() {
+ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork();
+ assertTrue(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+
+ config.preSharedKey = "adbdfgretrtyrtyrty";
+ assertFalse(WifiConfigurationUtil.validate(config, SUPPORTED_FEATURES_ALL,
+ WifiConfigurationUtil.VALIDATE_FOR_ADD));
+ }
+
/**
* Verify that the validate method fails to validate WifiConfiguration with malformed sae
* string.
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiMonitorTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiMonitorTest.java
index d6454b4..2a6404e 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiMonitorTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiMonitorTest.java
@@ -51,7 +51,6 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
@@ -747,18 +746,20 @@
public void testBroadcastCertificateEvent() {
final int depth = 2;
mWifiMonitor.registerHandler(
- WLAN_IFACE_NAME, WifiMonitor.TOFU_ROOT_CA_CERTIFICATE, mHandlerSpy);
+ WLAN_IFACE_NAME, WifiMonitor.TOFU_CERTIFICATE_EVENT, mHandlerSpy);
mWifiMonitor.broadcastCertificationEvent(
- WLAN_IFACE_NAME, NETWORK_ID, SSID, depth, FakeKeys.CA_CERT0);
+ WLAN_IFACE_NAME, NETWORK_ID, SSID, depth,
+ new CertificateEventInfo(FakeKeys.CA_CERT0, "1234"));
mLooper.dispatchAll();
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(mHandlerSpy).handleMessage(messageCaptor.capture());
- assertEquals(WifiMonitor.TOFU_ROOT_CA_CERTIFICATE, messageCaptor.getValue().what);
+ assertEquals(WifiMonitor.TOFU_CERTIFICATE_EVENT, messageCaptor.getValue().what);
assertEquals(NETWORK_ID, messageCaptor.getValue().arg1);
assertEquals(depth, messageCaptor.getValue().arg2);
- X509Certificate cert = (X509Certificate) messageCaptor.getValue().obj;
- assertEquals(FakeKeys.CA_CERT0, cert);
+ CertificateEventInfo certEventInfo = (CertificateEventInfo) messageCaptor.getValue().obj;
+ assertEquals(FakeKeys.CA_CERT0, certEventInfo.getCert());
+ assertEquals("1234", certEventInfo.getCertHash());
}
/**
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
index bfa1725..eeb3ad3 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
@@ -4921,11 +4921,6 @@
homeSp.setFqdn(fqdn);
homeSp.setFriendlyName(friendlyName);
config.setHomeSp(homeSp);
- Map<String, String> friendlyNames = new HashMap<>();
- friendlyNames.put("en", friendlyName);
- friendlyNames.put("kr", friendlyName + 1);
- friendlyNames.put("jp", friendlyName + 2);
- config.setServiceFriendlyNames(friendlyNames);
Credential credential = new Credential();
credential.setRealm(TEST_REALM);
credential.setCaCertificate(FakeKeys.CA_CERT0);
diff --git a/service/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index 8cafc9f..2acd185 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -51,6 +51,7 @@
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
@@ -219,6 +220,7 @@
@Mock WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
@Mock MacAddressUtil mMacAddressUtil;
@Mock WifiPermissionsUtil mWifiPermissionsUtil;
+ @Mock ActivityManager mActivityManager;
Handler mHandler;
TestLooper mLooper;
@@ -257,6 +259,7 @@
any(PasspointManager.class), any(WifiMetrics.class)))
.thenReturn(mPasspointProvisioner);
when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+ when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
when(mWifiInjector.getWifiNetworkSuggestionsManager())
.thenReturn(mWifiNetworkSuggestionsManager);
when(mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(anyInt()))
@@ -369,11 +372,6 @@
homeSp.setFqdn(fqdn);
homeSp.setFriendlyName(friendlyName);
config.setHomeSp(homeSp);
- Map<String, String> friendlyNames = new HashMap<>();
- friendlyNames.put("en", friendlyName);
- friendlyNames.put("kr", friendlyName + 1);
- friendlyNames.put("jp", friendlyName + 2);
- config.setServiceFriendlyNames(friendlyNames);
Credential credential = new Credential();
credential.setRealm(realm != null ? realm : TEST_REALM);
credential.setCaCertificate(FakeKeys.CA_CERT0);
@@ -410,12 +408,14 @@
}
private PasspointProvider addTestProvider(String fqdn, String friendlyName,
- String packageName, boolean isSuggestion, String realm) {
+ String packageName, boolean isSuggestion, String realm,
+ boolean addServiceFriendlyNames) {
WifiConfiguration wifiConfig = WifiConfigurationTestUtil.generateWifiConfig(-1, TEST_UID,
"\"PasspointTestSSID\"", true, true,
fqdn, friendlyName, SECURITY_EAP);
- return addTestProvider(fqdn, friendlyName, packageName, wifiConfig, isSuggestion, realm);
+ return addTestProvider(fqdn, friendlyName, packageName, wifiConfig, isSuggestion, realm,
+ addServiceFriendlyNames);
}
/**
@@ -425,10 +425,18 @@
* @return {@link PasspointProvider}
*/
private PasspointProvider addTestProvider(String fqdn, String friendlyName,
- String packageName, WifiConfiguration wifiConfig, boolean isSuggestion, String realm) {
+ String packageName, WifiConfiguration wifiConfig, boolean isSuggestion, String realm,
+ boolean addServiceFriendlyNames) {
PasspointConfiguration config =
createTestConfigWithUserCredentialAndRealm(fqdn, friendlyName, realm);
wifiConfig.setPasspointUniqueId(config.getUniqueId());
+ if (addServiceFriendlyNames) {
+ Map<String, String> friendlyNames = new HashMap<>();
+ friendlyNames.put("en", friendlyName);
+ friendlyNames.put("kr", friendlyName + 1);
+ friendlyNames.put("jp", friendlyName + 2);
+ config.setServiceFriendlyNames(friendlyNames);
+ }
PasspointProvider provider = createMockProvider(config, wifiConfig, isSuggestion);
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
eq(mWifiCarrierInfoManager), anyLong(), eq(TEST_CREATOR_UID), eq(TEST_PACKAGE),
@@ -1045,7 +1053,7 @@
com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession().mockStatic(
InformationElementUtil.class).startMocking();
try {
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(null);
InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
@@ -1074,7 +1082,7 @@
@Test
public void matchProviderAsHomeProvider() throws Exception {
PasspointProvider provider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -1095,7 +1103,7 @@
@Test
public void matchProviderAsRoamingProvider() throws Exception {
PasspointProvider provider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -1116,7 +1124,7 @@
@Test
public void matchProviderWithNoMatch() throws Exception {
PasspointProvider provider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -1175,7 +1183,7 @@
InformationElementUtil.class).startMocking();
try {
PasspointProvider provider = addTestProvider(TEST_FQDN + 0, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
when(provider.tryUpdateCarrierId()).thenReturn(true);
reset(mWifiConfigManager);
@@ -1209,15 +1217,15 @@
InformationElementUtil.class).startMocking();
try {
PasspointProvider providerHome = addTestProvider(TEST_FQDN + 0, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
providerHome.getWifiConfig().isHomeProviderNetwork = true;
PasspointProvider providerRoaming = addTestProvider(TEST_FQDN + 1, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
WifiConfiguration wifiConfiguration = WifiConfigurationTestUtil.generateWifiConfig(-1,
TEST_UID, "\"PasspointTestSSID\"", true, true,
TEST_FQDN + 2, TEST_FRIENDLY_NAME, SECURITY_EAP);
PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, wifiConfiguration, false, null);
+ TEST_PACKAGE, wifiConfiguration, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID2;
@@ -1266,21 +1274,21 @@
@Test
public void getWifiConfigsForPasspointProfiles() {
PasspointProvider provider1 = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
WifiConfiguration config1 = provider1.getWifiConfig();
when(mWifiConfigManager.getConfiguredNetwork(provider1.getConfig().getUniqueId()))
.thenReturn(config1);
PasspointProvider provider2 = addTestProvider(TEST_FQDN + 1, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
PasspointProvider provider3 = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, true, null);
+ TEST_PACKAGE, true, null, false);
when(mWifiNetworkSuggestionsManager
.isPasspointSuggestionSharedWithUser(provider3.getWifiConfig())).thenReturn(false);
WifiConfiguration config3 = provider3.getWifiConfig();
when(mWifiConfigManager.getConfiguredNetwork(provider3.getConfig().getUniqueId()))
.thenReturn(config3);
PasspointProvider provider4 = addTestProvider(TEST_FQDN + 3, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, true, null);
+ TEST_PACKAGE, true, null, false);
when(mWifiNetworkSuggestionsManager
.isPasspointSuggestionSharedWithUser(provider4.getWifiConfig())).thenReturn(true);
WifiConfiguration config4 = provider4.getWifiConfig();
@@ -1310,7 +1318,7 @@
when(mMacAddressUtil.calculatePersistentMac(any(), any())).thenReturn(randomizedMacAddress);
when(mWifiConfigManager.shouldUseNonPersistentRandomization(any())).thenReturn(false);
PasspointProvider provider = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
WifiConfiguration configuration = provider.getWifiConfig();
when(mWifiConfigManager.getConfiguredNetwork(provider.getConfig().getUniqueId()))
.thenReturn(configuration);
@@ -1333,7 +1341,7 @@
when(mMacAddressUtil.calculatePersistentMac(any(), any())).thenReturn(randomizedMacAddress);
when(mWifiConfigManager.shouldUseNonPersistentRandomization(any())).thenReturn(true);
PasspointProvider provider = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
WifiConfiguration configuration = provider.getWifiConfig();
when(mWifiConfigManager.getConfiguredNetwork(provider.getConfig().getUniqueId()))
.thenReturn(configuration);
@@ -1536,9 +1544,9 @@
@Test
public void getMatchingPasspointConfigsForOsuProvidersWithMatch() {
PasspointProvider provider1 =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, true);
PasspointProvider provider2 =
- addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME2, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME2, TEST_PACKAGE, false, null, true);
List<OsuProvider> osuProviders = new ArrayList<>();
Map<String, String> friendlyNames = new HashMap<>();
@@ -1565,8 +1573,8 @@
*/
@Test
public void getMatchingPasspointConfigsForOsuProvidersWitNoMatch() {
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
- addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME2, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
+ addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME2, TEST_PACKAGE, false, null, false);
List<OsuProvider> osuProviders = new ArrayList<>();
@@ -1867,7 +1875,7 @@
@Test
public void providerNetworkConnectedFirstTime() throws Exception {
PasspointProvider provider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
when(provider.getHasEverConnected()).thenReturn(false);
mManager.onPasspointNetworkConnected(provider.getConfig().getUniqueId());
verify(provider).setHasEverConnected(eq(true));
@@ -1883,7 +1891,7 @@
@Test
public void providerNetworkConnectedNotFirstTime() throws Exception {
PasspointProvider provider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
when(provider.getHasEverConnected()).thenReturn(true);
mManager.onPasspointNetworkConnected(TEST_FQDN);
verify(provider, never()).setHasEverConnected(anyBoolean());
@@ -1898,7 +1906,7 @@
@Test
public void updateMetrics() {
PasspointProvider provider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
ArgumentCaptor<Map<String, PasspointProvider>> argCaptor = ArgumentCaptor.forClass(
Map.class);
// Provider have not provided a successful network connection.
@@ -1945,7 +1953,7 @@
WifiConfiguration currentConfiguration = WifiConfigurationTestUtil.createPasspointNetwork();
currentConfiguration.FQDN = TEST_FQDN;
PasspointProvider passpointProvider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
currentConfiguration.setPasspointUniqueId(passpointProvider.getConfig().getUniqueId());
verify(mAppOpsManager).startWatchingMode(eq(OPSTR_CHANGE_WIFI_STATE), eq(TEST_PACKAGE),
mAppOpChangedListenerCaptor.capture());
@@ -2307,17 +2315,17 @@
InformationElementUtil.class).startMocking();
try {
PasspointProvider providerHome = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
providerHome.getConfig().setSubscriptionExpirationTimeInMillis(
System.currentTimeMillis() + 100000);
providerHome.getWifiConfig().isHomeProviderNetwork = true;
PasspointProvider providerRoaming = addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
WifiConfiguration wifiConfiguration = WifiConfigurationTestUtil.generateWifiConfig(-1,
TEST_UID, "\"PasspointTestSSID\"", true, true,
TEST_FQDN + 2, TEST_FRIENDLY_NAME, SECURITY_EAP);
PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, wifiConfiguration, false, null);
+ TEST_PACKAGE, wifiConfiguration, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID;
@@ -2357,17 +2365,17 @@
InformationElementUtil.class).startMocking();
try {
PasspointProvider providerHome = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
providerHome.getConfig().setSubscriptionExpirationTimeInMillis(
System.currentTimeMillis() - 10000);
providerHome.getWifiConfig().isHomeProviderNetwork = true;
PasspointProvider providerRoaming = addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
WifiConfiguration wifiConfiguration = WifiConfigurationTestUtil.generateWifiConfig(-1,
TEST_UID, "\"PasspointTestSSID\"", true, true,
TEST_FQDN + 2, TEST_FRIENDLY_NAME, SECURITY_EAP);
PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, wifiConfiguration, false, null);
+ TEST_PACKAGE, wifiConfiguration, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID;
@@ -2407,19 +2415,19 @@
InformationElementUtil.class).startMocking();
try {
PasspointProvider providerHome = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
providerHome.getConfig().setSubscriptionExpirationTimeInMillis(
System.currentTimeMillis() - 10000);
providerHome.getWifiConfig().isHomeProviderNetwork = true;
PasspointProvider providerRoaming = addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, null);
+ TEST_PACKAGE, false, null, false);
providerRoaming.getConfig().setSubscriptionExpirationTimeInMillis(
System.currentTimeMillis() + 100000);
WifiConfiguration wifiConfiguration = WifiConfigurationTestUtil.generateWifiConfig(-1,
TEST_UID, "\"PasspointTestSSID\"", true, true,
TEST_FQDN + 2, TEST_FRIENDLY_NAME, SECURITY_EAP);
PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, wifiConfiguration, false, null);
+ TEST_PACKAGE, wifiConfiguration, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID;
@@ -2570,11 +2578,11 @@
@Test
public void removeAllProvidersWithSameFqdn() {
PasspointProvider provider1 = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, TEST_REALM);
+ TEST_PACKAGE, false, TEST_REALM, false);
PasspointProvider provider2 = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, TEST_REALM2);
+ TEST_PACKAGE, false, TEST_REALM2, false);
PasspointProvider provider3 = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, TEST_REALM3);
+ TEST_PACKAGE, false, TEST_REALM3, false);
List<PasspointProvider> providers = mUserDataSource.getProviders();
assertEquals(3, providers.size());
@@ -2713,7 +2721,7 @@
PasspointProvider provider =
addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, wifiConfig, false,
- null);
+ null, false);
WnmData event = WnmData.createDeauthImminentEvent(Utils.parseMac(TEST_BSSID_STRING), "",
true, 30);
@@ -2733,7 +2741,7 @@
PasspointProvider provider =
addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, wifiConfig, false,
- null);
+ null, false);
wifiConfig.enterpriseConfig.setAnonymousIdentity(TEST_ANONYMOUS_IDENTITY);
mManager.setAnonymousIdentity(wifiConfig);
@@ -2756,7 +2764,7 @@
PasspointProvider provider =
addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, wifiConfig, false,
- null);
+ null, false);
WifiConfiguration wifiConfig2 = WifiConfigurationTestUtil.generateWifiConfig(11, TEST_UID,
"\"PasspointTestSSID\"", true, true, TEST_FQDN2,
@@ -2764,7 +2772,7 @@
PasspointProvider provider2 =
addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME, TEST_PACKAGE, wifiConfig2, false,
- null);
+ null, false);
WifiConfigManager.OnNetworkUpdateListener listener = mNetworkListenerCaptor.getValue();
reset(mWifiConfigManager);
@@ -2968,7 +2976,7 @@
public void testHandleTermsAndConditionsEvent() throws Exception {
WifiConfiguration config = WifiConfigurationTestUtil.createPasspointNetwork();
PasspointProvider passpointProvider = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, config, false, null);
+ TEST_PACKAGE, config, false, null, false);
assertEquals(TEST_TERMS_AND_CONDITIONS_URL, mManager.handleTermsAndConditionsEvent(
WnmData.createTermsAndConditionsAccetanceRequiredEvent(TEST_BSSID,
TEST_TERMS_AND_CONDITIONS_URL), config).toString());
@@ -3009,7 +3017,7 @@
@Test
public void testClearAnqpRequestsAndFlushCache() throws Exception {
PasspointProvider provider = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
- TEST_PACKAGE, false, TEST_REALM);
+ TEST_PACKAGE, false, TEST_REALM, false);
mManager.clearAnqpRequestsAndFlushCache();
verify(mAnqpRequestManager).clear();
@@ -3048,7 +3056,7 @@
@Test
public void testPasspointEnableDisable() throws Exception {
PasspointProvider provider =
- addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null);
+ addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME, TEST_PACKAGE, false, null, false);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);