From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Hai Shalom Date: Fri, 3 Feb 2023 00:18:32 +0000 Subject: [PATCH 2/3] Revert "[TOFU] Don't send credentials in an unauthenticated TLS tunnel" This reverts commit fb630e6a13189321d0e83037adc9e7b30dc6d796. Reason for revert: Regression Bug ID: 250574778 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a50b83a25a16749bb22552a6d473c3ca11e9d904) Merged-In: I2788772c8f2f863f0f2117235483b1dd57ab4ae6 Change-Id: I2788772c8f2f863f0f2117235483b1dd57ab4ae6 --- .../res/values/overlayable.xml | 24 -- .../res/values/strings.xml | 3 - .../android/server/wifi/ClientModeImpl.java | 56 +-- .../wifi/InsecureEapNetworkHandler.java | 394 +++++------------- .../android/server/wifi/WifiServiceImpl.java | 7 +- service/proto/src/metrics.proto | 3 - .../server/wifi/ClientModeImplTest.java | 136 ++---- .../wifi/InsecureEapNetworkHandlerTest.java | 342 ++------------- 8 files changed, 220 insertions(+), 745 deletions(-) diff --git a/service/ServiceWifiResources/res/values/overlayable.xml b/service/ServiceWifiResources/res/values/overlayable.xml index 75c90a3887..2eef3f5156 100644 --- a/service/ServiceWifiResources/res/values/overlayable.xml +++ b/service/ServiceWifiResources/res/values/overlayable.xml @@ -321,30 +321,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/service/ServiceWifiResources/res/values/strings.xml b/service/ServiceWifiResources/res/values/strings.xml index db331b2e7b..15ffcf0ada 100644 --- a/service/ServiceWifiResources/res/values/strings.xml +++ b/service/ServiceWifiResources/res/values/strings.xml @@ -205,9 +205,6 @@ Network needs to be verified Review network details for %1$s before connecting. Tap to continue. Certificate installation failed. - Can\'t connect to %1$s - The server certificate chain is invalid. - OK Can\'t verify this network diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 9ec12bdad8..931374bccb 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -580,6 +580,9 @@ public class ClientModeImpl extends StateMachine implements ClientMode { @VisibleForTesting static final int CMD_ACCEPT_EAP_SERVER_CERTIFICATE = BASE + 301; + @VisibleForTesting + static final int CMD_REJECT_EAP_SERVER_CERTIFICATE = BASE + 302; + /* Tracks if suspend optimizations need to be disabled by DHCP, * screen or due to high perf mode. * When any of them needs to disable it, we keep the suspend optimizations @@ -834,11 +837,17 @@ public class ClientModeImpl extends StateMachine implements ClientMode { @Override public void onReject(String ssid) { log("Reject Root CA cert for " + ssid); + sendMessage(CMD_REJECT_EAP_SERVER_CERTIFICATE, + WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_REJECTED_BY_USER, + 0, ssid); } @Override public void onError(String ssid) { log("Insecure EAP network error for " + ssid); + sendMessage(CMD_REJECT_EAP_SERVER_CERTIFICATE, + WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE, + 0, ssid); }}; mInsecureEapNetworkHandler = new InsecureEapNetworkHandler( mContext, @@ -2252,6 +2261,8 @@ public class ClientModeImpl extends StateMachine implements ClientMode { return "CMD_UPDATE_LINKPROPERTIES"; case CMD_ACCEPT_EAP_SERVER_CERTIFICATE: return "CMD_ACCEPT_EAP_SERVER_CERTIFICATE"; + case CMD_REJECT_EAP_SERVER_CERTIFICATE: + return "CMD_REJECT_EAP_SERVER_CERTIFICATE"; case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: return "SUPPLICANT_STATE_CHANGE_EVENT"; case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: @@ -4010,21 +4021,8 @@ public class ClientModeImpl extends StateMachine implements ClientMode { break; } } + mInsecureEapNetworkHandler.prepareConnection(mTargetWifiConfiguration); setSelectedRcoiForPasspoint(config); - if (mInsecureEapNetworkHandler.prepareConnection(mTargetWifiConfiguration)) { - /* If TOFU is not supported and the user did not approve to connect to an - insecure network before, do not connect now and instead, display a dialog - or a notification, and keep network disconnected to avoid sending the - credentials. - */ - mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected); - reportConnectionAttemptEnd( - WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED, - WifiMetricsProto.ConnectionEvent.HLF_NONE, - WifiMetricsProto.ConnectionEvent.DISCONNECTED_USER_APPROVAL_NEEDED); - transitionTo(mDisconnectedState); - break; - } connectToNetwork(config); break; } @@ -4279,6 +4277,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { break; } case CMD_ACCEPT_EAP_SERVER_CERTIFICATE: + case CMD_REJECT_EAP_SERVER_CERTIFICATE: case CMD_START_ROAM: case CMD_START_RSSI_MONITORING_OFFLOAD: case CMD_STOP_RSSI_MONITORING_OFFLOAD: @@ -5385,16 +5384,11 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } case WifiMonitor.TOFU_ROOT_CA_CERTIFICATE: if (null == mTargetWifiConfiguration) break; - int certificateDepth = message.arg2; - if (!mInsecureEapNetworkHandler.addPendingCertificate( + if (!mInsecureEapNetworkHandler.setPendingCertificate( mTargetWifiConfiguration.SSID, message.arg2, (X509Certificate) message.obj)) { Log.d(TAG, "Cannot set pending cert."); } - // Launch user approval upon receiving the server certificate - if (certificateDepth == 0) { - mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected); - } break; default: { handleStatus = NOT_HANDLED; @@ -5873,6 +5867,10 @@ public class ClientModeImpl extends StateMachine implements ClientMode { class L3ProvisioningState extends State { @Override public void enter() { + if (mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected)) { + return; + } + startL3Provisioning(); } @@ -5892,6 +5890,18 @@ public class ClientModeImpl extends StateMachine implements ClientMode { handleStatus = NOT_HANDLED; break; } + case CMD_ACCEPT_EAP_SERVER_CERTIFICATE: + startL3Provisioning(); + break; + case CMD_REJECT_EAP_SERVER_CERTIFICATE: { + int l2FailureReason = message.arg1; + reportConnectionAttemptEnd( + WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION, + WifiMetricsProto.ConnectionEvent.HLF_NONE, + l2FailureReason); + mWifiNative.disconnect(mInterfaceName); + break; + } default: { handleStatus = NOT_HANDLED; break; @@ -6411,12 +6421,6 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } 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 b7389952e0..225d01c7e5 100644 --- a/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java +++ b/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java @@ -40,8 +40,6 @@ import com.android.server.wifi.util.NativeUtil; import com.android.wifi.resources.R; import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.List; /** This class is used to handle insecure EAP networks. */ public class InsecureEapNetworkHandler { @@ -73,27 +71,18 @@ public class InsecureEapNetworkHandler { private final String mInterfaceName; private final Handler mHandler; - // The latest connecting configuration from the caller, it is updated on calling - // prepareConnection() always. This is used to ensure that current TOFU config is aligned - // with the caller connecting config. @NonNull - private WifiConfiguration mConnectingConfig = null; - // The connecting configuration which is a valid TOFU configuration, it is updated - // only when the connecting configuration is a valid TOFU configuration and used - // by later TOFU procedure. - @NonNull - private WifiConfiguration mCurrentTofuConfig = null; - private int mPendingRootCaCertDepth = -1; + private WifiConfiguration mCurConfig = null; + private int mPendingCaCertDepth = -1; @Nullable - private X509Certificate mPendingRootCaCert = null; + private X509Certificate mPendingCaCert = null; @Nullable private X509Certificate mPendingServerCert = null; - // This is updated on setting a pending server cert. - private CertificateSubjectInfo mPendingServerCertSubjectInfo = null; - // 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 mServerCertChain = new ArrayList<>(); + // This is updated on setting a pending CA cert. + private CertificateSubjectInfo mPendingCaCertSubjectInfo = null; + // This is updated on setting a pending CA cert. + private CertificateSubjectInfo mPendingCaCertIssuerInfo = null; + @Nullable private WifiDialogManager.DialogHandle mTofuAlertDialog = null; private boolean mIsCertNotificationReceiverRegistered = false; @@ -148,17 +137,16 @@ public class InsecureEapNetworkHandler { * uses Server Cert, without a valid Root CA certificate or user approval. * * @param config the running wifi configuration. - * @return true if user needs to be notified about an insecure network but TOFU is not supported - * by the device, or false otherwise. */ - public boolean prepareConnection(@NonNull WifiConfiguration config) { - if (null == config) return false; - mConnectingConfig = config; + public void prepareConnection(@NonNull WifiConfiguration config) { + if (null == config) return; - if (!config.isEnterprise()) return false; + if (!config.isEnterprise()) return; WifiEnterpriseConfig entConfig = config.enterpriseConfig; - if (!entConfig.isEapMethodServerCertUsed()) return false; - if (entConfig.hasCaCertificate()) return false; + if (!entConfig.isEapMethodServerCertUsed()) return; + if (entConfig.hasCaCertificate()) return; + + clearConnection(); Log.d(TAG, "prepareConnection: isTofuSupported=" + mIsTrustOnFirstUseSupported + ", isInsecureEapNetworkAllowed=" + mIsInsecureEnterpriseConfigurationAllowed @@ -167,115 +155,71 @@ public class InsecureEapNetworkHandler { // If TOFU is not supported or insecure EAP network is allowed without TOFU enabled, // return to skip the dialog if this network is approved before. if (entConfig.isUserApproveNoCaCert()) { - if (!mIsTrustOnFirstUseSupported) return false; + if (!mIsTrustOnFirstUseSupported) return; if (mIsInsecureEnterpriseConfigurationAllowed && !entConfig.isTrustOnFirstUseEnabled()) { - return false; + return; } } - if (mIsTrustOnFirstUseSupported) { - /** - * Clear the user credentials from this copy of the configuration object. - * Supplicant will start the phase-1 TLS session to acquire the server certificate chain - * which will be provided to the framework. Then since the callbacks for identity and - * password requests are not populated, it will fail the connection and disconnect. - * This will allow the user to review the certificates at their own pace, and a - * reconnection would automatically take place with full verification of the chain once - * they approve. - */ - if (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS - || config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) { - config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE); - config.enterpriseConfig.setIdentity(null); - config.enterpriseConfig.setPassword(null); - } else if (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS) { - config.enterpriseConfig.setClientCertificateAlias(null); - } - } - mCurrentTofuConfig = config; - mServerCertChain.clear(); - dismissDialogAndNotification(); + mCurConfig = config; registerCertificateNotificationReceiver(); - if (!mIsTrustOnFirstUseSupported) { - /** - * Devices with no TOFU support, do not connect to the network until the user is - * aware that the network is insecure, and approves the connection. - */ - putNetworkOnHold(false); - } else { - // Remove cached PMK in the framework and supplicant to avoid skipping the EAP flow. - clearNativeData(); - Log.d(TAG, "Remove native cached data and networks for TOFU."); - } - return !mIsTrustOnFirstUseSupported; + // Remove cached PMK in the framework and supplicant to avoid + // skipping the EAP flow. + clearNativeData(); + Log.d(TAG, "Remove native cached data and networks for TOFU."); } - /** - * Do necessary clean up on stopping client mode. - */ - public void cleanup() { - dismissDialogAndNotification(); + /** Clear data on disconnecting a connection. */ + private void clearConnection() { unregisterCertificateNotificationReceiver(); + dismissDialogAndNotification(); clearInternalData(); } /** - * Stores a received certificate for later use. + * Store the received certifiate for later use. * * @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 cert the Root CA certificate from the server. * @return true if the cert is cached; otherwise, false. */ - public boolean addPendingCertificate(@NonNull String ssid, int depth, + public boolean setPendingCertificate(@NonNull String ssid, int depth, @NonNull X509Certificate cert) { - String configProfileKey = mCurrentTofuConfig != null - ? mCurrentTofuConfig.getProfileKey() : "null"; Log.d(TAG, "setPendingCertificate: " + "ssid=" + ssid + " depth=" + depth - + " current config=" + configProfileKey); + + " current config=" + mCurConfig); if (TextUtils.isEmpty(ssid)) return false; - if (null == mCurrentTofuConfig) return false; - if (!TextUtils.equals(ssid, mCurrentTofuConfig.SSID)) return false; + if (null == mCurConfig) return false; + if (!TextUtils.equals(ssid, mCurConfig.SSID)) return false; if (null == cert) return false; if (depth < 0) return false; - - if (depth == 0) { - // Disable network selection upon receiving the server certificate - putNetworkOnHold(true); - } - - if (!mServerCertChain.contains(cert)) { - mServerCertChain.add(cert); - } - // 0 is the tail, i.e. the server cert. if (depth == 0 && null == mPendingServerCert) { mPendingServerCert = cert; Log.d(TAG, "Pending server certificate: " + mPendingServerCert); - mPendingServerCertSubjectInfo = CertificateSubjectInfo.parse( - cert.getSubjectX500Principal().getName()); - if (null == mPendingServerCertSubjectInfo) { - Log.e(TAG, "CA cert has no valid subject."); - return false; - } - mPendingServerCertIssuerInfo = CertificateSubjectInfo.parse( - cert.getIssuerX500Principal().getName()); - if (null == mPendingServerCertIssuerInfo) { - Log.e(TAG, "CA cert has no valid issuer."); - return false; - } } - - // Root or intermediate cert. - if (depth < mPendingRootCaCertDepth) { + if (depth < mPendingCaCertDepth) { Log.d(TAG, "Ignore intermediate cert." + cert); return true; } - mPendingRootCaCertDepth = depth; - mPendingRootCaCert = cert; - Log.d(TAG, "Pending Root CA certificate: " + mPendingRootCaCert); + + mPendingCaCertSubjectInfo = CertificateSubjectInfo.parse( + cert.getSubjectDN().getName()); + if (null == mPendingCaCertSubjectInfo) { + Log.e(TAG, "CA cert has no valid subject."); + return false; + } + mPendingCaCertIssuerInfo = CertificateSubjectInfo.parse( + cert.getIssuerDN().getName()); + if (null == mPendingCaCertIssuerInfo) { + Log.e(TAG, "CA cert has no valid issuer."); + return false; + } + mPendingCaCertDepth = depth; + mPendingCaCert = cert; + Log.d(TAG, "Pending Root CA certificate: " + mPendingCaCert); return true; } @@ -300,89 +244,31 @@ public class InsecureEapNetworkHandler { * @return true if the user approval is needed; otherwise, false. */ public boolean startUserApprovalIfNecessary(boolean isUserSelected) { - if (null == mConnectingConfig || null == mCurrentTofuConfig) return false; - if (mConnectingConfig.networkId != mCurrentTofuConfig.networkId) return false; + if (null == mCurConfig) return false; + if (!mCurConfig.isEnterprise()) return false; + WifiEnterpriseConfig entConfig = mCurConfig.enterpriseConfig; + if (!entConfig.isEapMethodServerCertUsed()) return false; + if (entConfig.hasCaCertificate()) return false; // If Trust On First Use is supported and insecure enterprise configuration // is not allowed, TOFU must be used for an Enterprise network without certs. if (mIsTrustOnFirstUseSupported && !mIsInsecureEnterpriseConfigurationAllowed - && !mCurrentTofuConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { + && !mCurConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { Log.d(TAG, "Trust On First Use is not enabled."); - handleError(mCurrentTofuConfig.SSID); + handleError(mCurConfig.SSID); return true; } if (useTrustOnFirstUse()) { - if (null == mPendingRootCaCert) { - Log.e(TAG, "No valid CA cert for TLS-based connection."); - handleError(mCurrentTofuConfig.SSID); + if (null == mPendingCaCert) { + Log.d(TAG, "No valid CA cert for TLS-based connection."); + handleError(mCurConfig.SSID); return true; } else if (null == mPendingServerCert) { - Log.e(TAG, "No valid Server cert for TLS-based connection."); - handleError(mCurrentTofuConfig.SSID); - return true; - } else if (!isServerCertChainValid()) { - Log.e(TAG, "Server cert chain is invalid."); - String title = mContext.getString(R.string.wifi_tofu_invalid_cert_chain_title, - mCurrentTofuConfig.SSID); - String message = mContext.getString(R.string.wifi_tofu_invalid_cert_chain_message); - String okButtonText = mContext.getString( - R.string.wifi_tofu_invalid_cert_chain_ok_text); - - handleError(mCurrentTofuConfig.SSID); - - if (TextUtils.isEmpty(title) || TextUtils.isEmpty(message)) return true; - - if (isUserSelected) { - mTofuAlertDialog = mWifiDialogManager.createSimpleDialog( - title, - message, - null /* positiveButtonText */, - null /* negativeButtonText */, - okButtonText, - new WifiDialogManager.SimpleDialogCallback() { - @Override - public void onPositiveButtonClicked() { - // Not used. - } - - @Override - public void onNegativeButtonClicked() { - // Not used. - } - - @Override - public void onNeutralButtonClicked() { - // Not used. - } - - @Override - public void onCancelled() { - // Not used. - } - }, - new WifiThreadRunner(mHandler)); - mTofuAlertDialog.launchDialog(); - } else { - Notification.Builder builder = mFacade.makeNotificationBuilder(mContext, - WifiService.NOTIFICATION_NETWORK_ALERTS) - .setSmallIcon( - Icon.createWithResource(mContext.getWifiOverlayApkPkgName(), - com.android.wifi.resources.R - .drawable.stat_notify_wifi_in_range)) - .setContentTitle(title) - .setContentText(message) - .setStyle(new Notification.BigTextStyle().bigText(message)) - .setColor(mContext.getResources().getColor( - android.R.color.system_notification_accent_color)); - mNotificationManager.notify(SystemMessage.NOTE_SERVER_CA_CERTIFICATE, - builder.build()); - } + Log.d(TAG, "No valid Server cert for TLS-based connection."); + handleError(mCurConfig.SSID); return true; } - } else if (mIsInsecureEnterpriseConfigurationAllowed) { - Log.i(TAG, "networks without the server cert are allowed, skip it."); - return false; } Log.d(TAG, "startUserApprovalIfNecessaryForInsecureEapNetwork: mIsUserSelected=" @@ -396,56 +282,13 @@ public class InsecureEapNetworkHandler { return true; } - /** - * Disable network selection, disconnect if necessary, and clear PMK cache - */ - private void putNetworkOnHold(boolean needToDisconnect) { - // Disable network selection upon receiving the server certificate - mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, - WifiConfiguration.NetworkSelectionStatus - .DISABLED_BY_WIFI_MANAGER); - - // Force disconnect and clear PMK cache to avoid supplicant reconnection - if (needToDisconnect) mWifiNative.disconnect(mInterfaceName); - 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; - } - return true; - } - private boolean useTrustOnFirstUse() { return mIsTrustOnFirstUseSupported - && mCurrentTofuConfig.enterpriseConfig.isTrustOnFirstUseEnabled(); + && mCurConfig.enterpriseConfig.isTrustOnFirstUseEnabled(); } private void registerCertificateNotificationReceiver() { - unregisterCertificateNotificationReceiver(); + if (mIsCertNotificationReceiverRegistered) return; IntentFilter filter = new IntentFilter(); if (useTrustOnFirstUse()) { @@ -470,22 +313,21 @@ public class InsecureEapNetworkHandler { if (!isConnectionValid(ssid)) return; if (!useTrustOnFirstUse()) { - mWifiConfigManager.setUserApproveNoCaCert(mCurrentTofuConfig.networkId, true); + mWifiConfigManager.setUserApproveNoCaCert(mCurConfig.networkId, true); } else { - if (null == mPendingRootCaCert || null == mPendingServerCert) { + if (null == mPendingCaCert || null == mPendingServerCert) { handleError(ssid); return; } if (!mWifiConfigManager.updateCaCertificate( - mCurrentTofuConfig.networkId, mPendingRootCaCert, mPendingServerCert)) { + mCurConfig.networkId, mPendingCaCert, mPendingServerCert)) { // 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); + Log.e(TAG, "Cannot update CA cert to network " + mCurConfig.getProfileKey() + + ", CA cert = " + mPendingCaCert); } } - mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, - WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE); + mWifiConfigManager.allowAutojoin(mCurConfig.networkId, true); dismissDialogAndNotification(); clearInternalData(); @@ -496,8 +338,7 @@ public class InsecureEapNetworkHandler { void handleReject(@NonNull String ssid) { if (!isConnectionValid(ssid)) return; - mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, - WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER); + mWifiConfigManager.allowAutojoin(mCurConfig.networkId, false); dismissDialogAndNotification(); clearInternalData(); clearNativeData(); @@ -506,11 +347,6 @@ public class InsecureEapNetworkHandler { } private void handleError(@Nullable String ssid) { - if (mCurrentTofuConfig != null) { - mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, - WifiConfiguration.NetworkSelectionStatus - .DISABLED_BY_WIFI_MANAGER); - } dismissDialogAndNotification(); clearInternalData(); clearNativeData(); @@ -519,9 +355,9 @@ public class InsecureEapNetworkHandler { } private void askForUserApprovalForCaCertificate() { - if (mCurrentTofuConfig == null || TextUtils.isEmpty(mCurrentTofuConfig.SSID)) return; + if (mCurConfig == null || TextUtils.isEmpty(mCurConfig.SSID)) return; if (useTrustOnFirstUse()) { - if (null == mPendingRootCaCert || null == mPendingServerCert) { + if (null == mPendingCaCert || null == mPendingServerCert) { Log.e(TAG, "Cannot launch a dialog for TOFU without " + "a valid pending CA certificate."); return; @@ -539,42 +375,39 @@ public class InsecureEapNetworkHandler { ? mContext.getString(R.string.wifi_ca_cert_dialog_abort_text) : mContext.getString(R.string.wifi_ca_cert_dialog_preT_abort_text); - String message; + String message = null; String messageUrl = null; int messageUrlStart = 0; int messageUrlEnd = 0; if (useTrustOnFirstUse()) { + String signature = NativeUtil.hexStringFromByteArray( + mPendingCaCert.getSignature()); StringBuilder contentBuilder = new StringBuilder() .append(mContext.getString(R.string.wifi_ca_cert_dialog_message_hint)) .append(mContext.getString( R.string.wifi_ca_cert_dialog_message_server_name_text, - mPendingServerCertSubjectInfo.commonName)) + mPendingCaCertSubjectInfo.commonName)) .append(mContext.getString( R.string.wifi_ca_cert_dialog_message_issuer_name_text, - mPendingServerCertIssuerInfo.commonName)); - if (!TextUtils.isEmpty(mPendingServerCertSubjectInfo.organization)) { + mPendingCaCertIssuerInfo.commonName)); + if (!TextUtils.isEmpty(mPendingCaCertSubjectInfo.organization)) { contentBuilder.append(mContext.getString( R.string.wifi_ca_cert_dialog_message_organization_text, - mPendingServerCertSubjectInfo.organization)); + mPendingCaCertSubjectInfo.organization)); } - if (!TextUtils.isEmpty(mPendingServerCertSubjectInfo.email)) { + if (!TextUtils.isEmpty(mPendingCaCertSubjectInfo.email)) { contentBuilder.append(mContext.getString( R.string.wifi_ca_cert_dialog_message_contact_text, - mPendingServerCertSubjectInfo.email)); - } - byte[] signature = mPendingServerCert.getSignature(); - if (signature != null) { - String signatureString = NativeUtil.hexStringFromByteArray(signature); - if (signatureString.length() > 16) { - signatureString = signatureString.substring(0, 16); - } - contentBuilder.append(mContext.getString( - R.string.wifi_ca_cert_dialog_message_signature_name_text, signatureString)); + mPendingCaCertSubjectInfo.email)); } + contentBuilder + .append(mContext.getString( + R.string.wifi_ca_cert_dialog_message_signature_name_text, + signature.substring(0, 16))); message = contentBuilder.toString(); } else { String hint = mContext.getString( - R.string.wifi_ca_cert_dialog_preT_message_hint, mCurrentTofuConfig.SSID); + R.string.wifi_ca_cert_dialog_preT_message_hint, mCurConfig.SSID); String linkText = mContext.getString( R.string.wifi_ca_cert_dialog_preT_message_link); message = hint + " " + linkText; @@ -594,35 +427,23 @@ public class InsecureEapNetworkHandler { new WifiDialogManager.SimpleDialogCallback() { @Override public void onPositiveButtonClicked() { - if (mCurrentTofuConfig == null) { - return; - } - handleAccept(mCurrentTofuConfig.SSID); + handleAccept(mCurConfig.SSID); } @Override public void onNegativeButtonClicked() { - if (mCurrentTofuConfig == null) { - return; - } - handleReject(mCurrentTofuConfig.SSID); + handleReject(mCurConfig.SSID); } @Override public void onNeutralButtonClicked() { // Not used. - if (mCurrentTofuConfig == null) { - return; - } - handleReject(mCurrentTofuConfig.SSID); + handleReject(mCurConfig.SSID); } @Override public void onCancelled() { - if (mCurrentTofuConfig == null) { - return; - } - handleReject(mCurrentTofuConfig.SSID); + handleReject(mCurConfig.SSID); } }, new WifiThreadRunner(mHandler)); @@ -639,16 +460,16 @@ public class InsecureEapNetworkHandler { } private void notifyUserForCaCertificate() { - if (mCurrentTofuConfig == null) return; + if (mCurConfig == null) return; if (useTrustOnFirstUse()) { - if (null == mPendingRootCaCert) return; + if (null == mPendingCaCert) return; if (null == mPendingServerCert) return; } dismissDialogAndNotification(); PendingIntent tapPendingIntent; if (useTrustOnFirstUse()) { - tapPendingIntent = genCaCertNotifIntent(ACTION_CERT_NOTIF_TAP, mCurrentTofuConfig.SSID); + tapPendingIntent = genCaCertNotifIntent(ACTION_CERT_NOTIF_TAP, mCurConfig.SSID); } else { Intent openLinkIntent = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(mCaCertHelpLink)) @@ -661,10 +482,9 @@ public class InsecureEapNetworkHandler { ? mContext.getString(R.string.wifi_ca_cert_notification_title) : mContext.getString(R.string.wifi_ca_cert_notification_preT_title); String content = useTrustOnFirstUse() - ? mContext.getString(R.string.wifi_ca_cert_notification_message, - mCurrentTofuConfig.SSID) + ? mContext.getString(R.string.wifi_ca_cert_notification_message, mCurConfig.SSID) : mContext.getString(R.string.wifi_ca_cert_notification_preT_message, - mCurrentTofuConfig.SSID); + mCurConfig.SSID); Notification.Builder builder = mFacade.makeNotificationBuilder(mContext, WifiService.NOTIFICATION_NETWORK_ALERTS) .setSmallIcon(Icon.createWithResource(mContext.getWifiOverlayApkPkgName(), @@ -682,13 +502,11 @@ public class InsecureEapNetworkHandler { Notification.Action acceptAction = new Notification.Action.Builder( null /* icon */, mContext.getString(R.string.wifi_ca_cert_dialog_preT_continue_text), - genCaCertNotifIntent(ACTION_CERT_NOTIF_ACCEPT, mCurrentTofuConfig.SSID)) - .build(); + genCaCertNotifIntent(ACTION_CERT_NOTIF_ACCEPT, mCurConfig.SSID)).build(); Notification.Action rejectAction = new Notification.Action.Builder( null /* icon */, mContext.getString(R.string.wifi_ca_cert_dialog_preT_abort_text), - genCaCertNotifIntent(ACTION_CERT_NOTIF_REJECT, mCurrentTofuConfig.SSID)) - .build(); + genCaCertNotifIntent(ACTION_CERT_NOTIF_REJECT, mCurConfig.SSID)).build(); builder.addAction(rejectAction).addAction(acceptAction); } mNotificationManager.notify(SystemMessage.NOTE_SERVER_CA_CERTIFICATE, builder.build()); @@ -703,18 +521,18 @@ public class InsecureEapNetworkHandler { } private void clearInternalData() { - mPendingRootCaCertDepth = -1; - mPendingRootCaCert = null; + mPendingCaCertDepth = -1; + mPendingCaCert = null; mPendingServerCert = null; - mPendingServerCertSubjectInfo = null; - mPendingServerCertIssuerInfo = null; - mCurrentTofuConfig = null; + mPendingCaCertSubjectInfo = null; + mPendingCaCertIssuerInfo = null; + mCurConfig = null; } private void clearNativeData() { // PMK should be cleared or it would skip EAP flow next time. - if (null != mCurrentTofuConfig) { - mWifiNative.removeNetworkCachedData(mCurrentTofuConfig.networkId); + if (null != mCurConfig) { + mWifiNative.removeNetworkCachedData(mCurConfig.networkId); } // remove network so that supplicant's PMKSA cache is cleared mWifiNative.removeAllNetworks(mInterfaceName); @@ -733,13 +551,13 @@ public class InsecureEapNetworkHandler { // If condition #2 occurs, clear existing data and notify the client mode // via onError callback. private boolean isConnectionValid(@Nullable String ssid) { - if (TextUtils.isEmpty(ssid) || null == mCurrentTofuConfig) { + if (TextUtils.isEmpty(ssid) || null == mCurConfig) { handleError(null); return false; } - if (!TextUtils.equals(ssid, mCurrentTofuConfig.SSID)) { - Log.w(TAG, "Target SSID " + mCurrentTofuConfig.SSID + if (!TextUtils.equals(ssid, mCurConfig.SSID)) { + Log.w(TAG, "Target SSID " + mCurConfig.SSID + " is different from TOFU returned SSID" + ssid); return false; } diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index b044508eb7..40acc85cc5 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -528,6 +528,9 @@ public class WifiServiceImpl extends BaseWifiService { if (!mWifiConfigManager.loadFromStore()) { Log.e(TAG, "Failed to load from config store"); } + if (!mWifiGlobals.isInsecureEnterpriseConfigurationAllowed()) { + mWifiConfigManager.updateTrustOnFirstUseFlag(isTrustOnFirstUseSupported()); + } mWifiConfigManager.incrementNumRebootsSinceLastUse(); // config store is read, check if verbose logging is enabled. enableVerboseLoggingInternal( @@ -792,10 +795,6 @@ public class WifiServiceImpl extends BaseWifiService { mLohsSoftApTracker.handleBootCompleted(); mWifiInjector.getSarManager().handleBootCompleted(); mIsBootComplete = true; - // HW capabilities is ready after boot completion. - if (!mWifiGlobals.isInsecureEnterpriseConfigurationAllowed()) { - mWifiConfigManager.updateTrustOnFirstUseFlag(isTrustOnFirstUseSupported()); - } }); } diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto index 871eb2c750..09a596f984 100644 --- a/service/proto/src/metrics.proto +++ b/service/proto/src/metrics.proto @@ -1047,9 +1047,6 @@ message ConnectionEvent { // The reason code if a user rejects this connection. AUTH_FAILURE_REJECTED_BY_USER = 7; - - // The reason code if an insecure Enterprise connection requires user's approval - DISCONNECTED_USER_APPROVAL_NEEDED = 8; } // Entity that recommended connecting to this network. 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 e2309e9ce4..ca8f5b031c 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java @@ -7860,18 +7860,11 @@ public class ClientModeImplTest extends WifiBaseTest { WifiEnterpriseConfig.Eap.TLS, WifiEnterpriseConfig.Phase2.NONE)); eapTlsConfig.networkId = FRAMEWORK_NETWORK_ID; eapTlsConfig.SSID = TEST_SSID; - if (isAtLeastT && isTrustOnFirstUseSupported) { + if (isAtLeastT) { eapTlsConfig.enterpriseConfig.enableTrustOnFirstUse(true); - when(mInsecureEapNetworkHandler.prepareConnection(any(WifiConfiguration.class))) - .thenReturn(false); - } else { - when(mInsecureEapNetworkHandler.prepareConnection(any(WifiConfiguration.class))) - .thenReturn(true); } eapTlsConfig.enterpriseConfig.setCaPath(""); eapTlsConfig.enterpriseConfig.setDomainSuffixMatch(""); - eapTlsConfig.setRandomizedMacAddress(TEST_LOCAL_MAC_ADDRESS); - eapTlsConfig.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO; initializeAndAddNetworkAndVerifySuccess(eapTlsConfig); @@ -7886,31 +7879,31 @@ public class ClientModeImplTest extends WifiBaseTest { } verify(mInsecureEapNetworkHandler).prepareConnection(eq(eapTlsConfig)); - if (isTrustOnFirstUseSupported) { - mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, - new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR, - SupplicantState.ASSOCIATED)); - mLooper.dispatchAll(); + mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, + new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR, + SupplicantState.ASSOCIATED)); + mLooper.dispatchAll(); + if (isTrustOnFirstUseSupported) { mCmi.sendMessage(WifiMonitor.TOFU_ROOT_CA_CERTIFICATE, FRAMEWORK_NETWORK_ID, 0, FakeKeys.CA_CERT0); mLooper.dispatchAll(); - verify(mInsecureEapNetworkHandler).addPendingCertificate( + verify(mInsecureEapNetworkHandler).setPendingCertificate( eq(eapTlsConfig.SSID), eq(0), eq(FakeKeys.CA_CERT0)); - - // Adding a certificate in depth 0 will cause a disconnection when TOFU is supported - DisconnectEventInfo disconnectEventInfo = - new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 3, true); - mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo); - mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, - new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR, - SupplicantState.DISCONNECTED)); - mLooper.dispatchAll(); } + mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, + new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false)); + mLooper.dispatchAll(); + + mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, + new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR, + SupplicantState.COMPLETED)); + mLooper.dispatchAll(); + verify(mInsecureEapNetworkHandler).startUserApprovalIfNecessary(eq(isUserSelected)); - // In any case, we end up in the disconnected state - assertEquals("DisconnectedState", getCurrentState().getName()); + assertEquals("L3ProvisioningState", getCurrentState().getName()); + return eapTlsConfig; } @@ -7926,22 +7919,9 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - } - - /** - * Verify logic when Trust On First Use is not supported - * - This network is selected by a user. - * - Network gets connected - */ - @Test - public void verifyTrustOnFirstUseAcceptWhenConnectByUserNoTofu() throws Exception { - assumeTrue(SdkLevel.isAtLeastT()); - WifiConfiguration testConfig = setupTrustOnFirstUse(true, false, true); - - mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + injectDhcpSuccess(); mLooper.dispatchAll(); - verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + assertEquals("L3ConnectedState", getCurrentState().getName()); } /** @@ -7956,13 +7936,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } /** @@ -7977,13 +7951,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } /** @@ -7999,7 +7967,9 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + injectDhcpSuccess(); + mLooper.dispatchAll(); + assertEquals("L3ConnectedState", getCurrentState().getName()); } /** @@ -8015,13 +7985,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } /** @@ -8036,13 +8000,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } /** @@ -8057,7 +8015,9 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + injectDhcpSuccess(); + mLooper.dispatchAll(); + assertEquals("L3ConnectedState", getCurrentState().getName()); } /** @@ -8072,13 +8032,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.DISCONNECTED_USER_APPROVAL_NEEDED), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } /** @@ -8093,13 +8047,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.DISCONNECTED_USER_APPROVAL_NEEDED), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } /** @@ -8113,8 +8061,9 @@ public class ClientModeImplTest extends WifiBaseTest { WifiConfiguration testConfig = setupLegacyEapNetworkTest(false); mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + injectDhcpSuccess(); mLooper.dispatchAll(); - verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + assertEquals("L3ConnectedState", getCurrentState().getName()); } /** @@ -8129,14 +8078,9 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); mLooper.dispatchAll(); + verify(mFrameworkFacade, never()).makeAlertDialogBuilder(any()); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.DISCONNECTED_USER_APPROVAL_NEEDED), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } /** @@ -8151,13 +8095,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); mLooper.dispatchAll(); - verify(mWifiConnectivityManager, never()) - .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); - verify(mWifiMetrics).endConnectionEvent( - any(), eq(WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED), - eq(WifiMetricsProto.ConnectionEvent.HLF_NONE), - eq(WifiMetricsProto.ConnectionEvent.DISCONNECTED_USER_APPROVAL_NEEDED), - anyInt()); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); } private void setScanResultWithMloInfo() { 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 6e2e67a8a2..aed3753ffc 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java @@ -17,18 +17,14 @@ package com.android.server.wifi; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.validateMockitoUsage; @@ -41,16 +37,11 @@ import android.content.Intent; 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 androidx.test.filters.SmallTest; import com.android.modules.utils.build.SdkLevel; -import com.android.server.wifi.util.CertificateSubjectInfo; -import com.android.server.wifi.util.NativeUtil; -import com.android.wifi.resources.R; import org.junit.After; import org.junit.Before; @@ -60,13 +51,9 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.stubbing.Answer; -import java.nio.charset.StandardCharsets; import java.security.cert.X509Certificate; -import javax.security.auth.x500.X500Principal; - /** * Unit tests for {@link com.android.server.wifi.InsecureEapNetworkHandlerTest}. */ @@ -78,9 +65,7 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { private static final int ACTION_TAP = 2; private static final String WIFI_IFACE_NAME = "wlan-test-9"; private static final int FRAMEWORK_NETWORK_ID = 2; - 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_SSID = "test_ssid"; @Mock WifiContext mContext; @Mock WifiConfigManager mWifiConfigManager; @@ -109,34 +94,11 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { when(mContext.getString(anyInt())).thenReturn("TestString"); when(mContext.getString(anyInt(), any())).thenReturn("TestStringWithArgument"); when(mContext.getText(anyInt())).thenReturn("TestStr"); - when(mContext.getString(eq(R.string.wifi_ca_cert_dialog_message_issuer_name_text), - anyString())) - .thenAnswer((Answer) invocation -> - "Issuer Name:\n" + invocation.getArguments()[1] + "\n\n"); - when(mContext.getString(eq(R.string.wifi_ca_cert_dialog_message_server_name_text), - anyString())) - .thenAnswer((Answer) invocation -> - "Server Name:\n" + invocation.getArguments()[1] + "\n\n"); - when(mContext.getString(eq(R.string.wifi_ca_cert_dialog_message_organization_text), - anyString())) - .thenAnswer((Answer) invocation -> - "Organization:\n" + invocation.getArguments()[1] + "\n\n"); - when(mContext.getString(eq(R.string.wifi_ca_cert_dialog_message_contact_text), - anyString())) - .thenAnswer((Answer) invocation -> - "Contact:\n" + invocation.getArguments()[1] + "\n\n"); - when(mContext.getString(eq(R.string.wifi_ca_cert_dialog_message_signature_name_text), - anyString())) - .thenAnswer((Answer) invocation -> - "Signature:\n" + invocation.getArguments()[1] + "\n\n"); when(mContext.getWifiOverlayApkPkgName()).thenReturn("test.com.android.wifi.resources"); when(mContext.getResources()).thenReturn(mResources); when(mWifiDialogManager.createSimpleDialogWithUrl( any(), any(), any(), anyInt(), anyInt(), any(), any(), any(), any(), any())) .thenReturn(mTofuAlertDialog); - when(mWifiDialogManager.createSimpleDialog( - any(), any(), any(), any(), any(), any(), any())) - .thenReturn(mTofuAlertDialog); when(mFrameworkFacade.makeNotificationBuilder(any(), any())) .thenReturn(mNotificationBuilder); @@ -245,9 +207,6 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); assertTrue(mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); verify(mCallbacks).onError(eq(config.SSID)); - verify(mWifiConfigManager, atLeastOnce()).updateNetworkSelectionStatus(eq(config.networkId), - eq(WifiConfiguration.NetworkSelectionStatus - .DISABLED_BY_WIFI_MANAGER)); } /** @@ -352,36 +311,9 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { 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)))); - - 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; - } - private WifiConfiguration prepareWifiConfiguration(boolean isAtLeastT) { WifiConfiguration config = spy(WifiConfigurationTestUtil.createEapNetwork( - WifiEnterpriseConfig.Eap.TTLS, WifiEnterpriseConfig.Phase2.MSCHAPV2)); + WifiEnterpriseConfig.Eap.TLS, WifiEnterpriseConfig.Phase2.NONE)); config.networkId = FRAMEWORK_NETWORK_ID; config.SSID = TEST_SSID; if (isAtLeastT) { @@ -389,8 +321,6 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { } config.enterpriseConfig.setCaPath(""); config.enterpriseConfig.setDomainSuffixMatch(""); - config.enterpriseConfig.setIdentity(TEST_IDENTITY); - config.enterpriseConfig.setPassword(TEST_PASSWORD); return config; } @@ -408,32 +338,14 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { mWifiNative, mFrameworkFacade, mWifiNotificationManager, - mWifiDialogManager, - isTrustOnFirstUseSupported, + mWifiDialogManager, isTrustOnFirstUseSupported, isInsecureEnterpriseConfigurationAllowed, mCallbacks, WIFI_IFACE_NAME, mHandler); - if (isTrustOnFirstUseSupported - && (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS - || config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) - && config.enterpriseConfig.getPhase2Method() != WifiEnterpriseConfig.Phase2.NONE) { - // Verify that the configuration contains an identity - assertEquals(TEST_IDENTITY, config.enterpriseConfig.getIdentity()); - assertEquals(TEST_PASSWORD, config.enterpriseConfig.getPassword()); - } mInsecureEapNetworkHandler.prepareConnection(config); - if (isTrustOnFirstUseSupported - && (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS - || config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) - && config.enterpriseConfig.getPhase2Method() != WifiEnterpriseConfig.Phase2.NONE) { - // Verify identities are cleared - assertTrue(TextUtils.isEmpty(config.enterpriseConfig.getIdentity())); - assertTrue(TextUtils.isEmpty(config.enterpriseConfig.getPassword())); - } - if (isTrustOnFirstUseSupported && config.enterpriseConfig.isTrustOnFirstUseEnabled()) { verify(mContext, atLeastOnce()).registerReceiver( mBroadcastReceiverCaptor.capture(), @@ -467,13 +379,34 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); - X509Certificate mockCaCert = generateMockCert("ca", "ca", true); - X509Certificate mockServerCert = generateMockCert("server", "ca", false); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 1, FakeKeys.CA_CERT0); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CLIENT_CERT); + + verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported, + isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CLIENT_CERT); + } + + /** + * Verify Trust On First Use flow with a reversal cert chain + * - This network is selected by a user. + * - Accept the connection. + */ + @Test + public void verifyTrustOnFirstUseAcceptWhenConnectByUserWithReversalOrderChain() + throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true; + boolean needUserApproval = true; + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CLIENT_CERT); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 1, FakeKeys.CA_CERT1); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 2, FakeKeys.CA_CERT0); verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported, - isUserSelected, needUserApproval, mockCaCert, mockServerCert); + isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CLIENT_CERT); } /** @@ -491,11 +424,10 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); - X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported, - isUserSelected, needUserApproval, mockSelfSignedCert, mockSelfSignedCert); + isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CA_CERT0); } /** @@ -516,9 +448,6 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { assertEquals(needUserApproval, mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); verify(mCallbacks).onError(eq(config.SSID)); - verify(mWifiConfigManager, atLeastOnce()).updateNetworkSelectionStatus(eq(config.networkId), - eq(WifiConfiguration.NetworkSelectionStatus - .DISABLED_BY_WIFI_MANAGER)); } /** @@ -538,17 +467,11 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { config.enterpriseConfig.enableTrustOnFirstUse(false); setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, - generateMockCert("ca", "ca", true)); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, - generateMockCert("server", "ca", false)); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); assertEquals(needUserApproval, mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); verify(mCallbacks).onError(eq(config.SSID)); - verify(mWifiConfigManager, atLeastOnce()).updateNetworkSelectionStatus(eq(config.networkId), - eq(WifiConfiguration.NetworkSelectionStatus - .DISABLED_BY_WIFI_MANAGER)); } /** @@ -556,161 +479,36 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { * - TOFU is supported. * - Insecure EAP network is allowed. * - TOFU is not enabled - * - No user approval is needed. */ @Test public void verifyNoErrorWithTofuDisabledWhenInsecureEapNetworkIsAllowed() throws Exception { assumeTrue(SdkLevel.isAtLeastT()); boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true; - boolean needUserApproval = false, isInsecureEnterpriseConfigurationAllowed = true; + boolean needUserApproval = true, isInsecureEnterpriseConfigurationAllowed = true; WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); config.enterpriseConfig.enableTrustOnFirstUse(false); setupTest(config, isAtLeastT, isTrustOnFirstUseSupported, isInsecureEnterpriseConfigurationAllowed); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, - generateMockCert("ca", "ca", true)); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, - generateMockCert("server", "ca", false)); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); assertEquals(needUserApproval, 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)); - - assertTrue(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 - public void verifyOnErrorWithIncompleteChain() throws Exception { - assumeTrue(SdkLevel.isAtLeastT()); - boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true; - - WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); - setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); - - X509Certificate mockCaCert = generateMockCert("ca", "ca", true); - // Missing intermediate cert. - X509Certificate mockServerCert = generateMockCert("server", "intermediate", false); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert); - - assertTrue(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 setting pending certificate won't crash with no current configuration. - */ - @Test - public void verifySetPendingCertificateNoCrashWithNoConfig() - throws Exception { - assumeTrue(SdkLevel.isAtLeastT()); - mInsecureEapNetworkHandler = new InsecureEapNetworkHandler( - mContext, - mWifiConfigManager, - mWifiNative, - mFrameworkFacade, - mWifiNotificationManager, - mWifiDialogManager, - true /* isTrustOnFirstUseSupported */, - false /* isInsecureEnterpriseConfigurationAllowed */, - mCallbacks, - WIFI_IFACE_NAME, - mHandler); - X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false); - mInsecureEapNetworkHandler.addPendingCertificate("NotExist", 0, mockSelfSignedCert); - } - - @Test - public void testExistingCertChainIsClearedOnPreparingNewConnection() 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)); - - // The wrong cert chain should be cleared after this call. - mInsecureEapNetworkHandler.prepareConnection(config); - - X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert); - - assertTrue(mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); - verify(mCallbacks, never()).onError(any()); - } - - @Test - public void verifyUserApprovalIsNotNeededWithDifferentTargetConfig() throws Exception { - assumeTrue(SdkLevel.isAtLeastT()); - boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true; - - WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); - setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); - - X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert); - - // Pass another PSK config which is not the same as the current one. - WifiConfiguration pskConfig = WifiConfigurationTestUtil.createPskNetwork(); - pskConfig.networkId = FRAMEWORK_NETWORK_ID + 2; - mInsecureEapNetworkHandler.prepareConnection(pskConfig); - assertFalse(mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); - verify(mCallbacks, never()).onError(any()); - - // Pass another non-TOFU EAP config which is not the same as the current one. - WifiConfiguration anotherEapConfig = spy(WifiConfigurationTestUtil.createEapNetwork( - WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE)); - anotherEapConfig.networkId = FRAMEWORK_NETWORK_ID + 1; - mInsecureEapNetworkHandler.prepareConnection(anotherEapConfig); - assertFalse(mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); - verify(mCallbacks, never()).onError(any()); - } - 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); if (isTrustOnFirstUseSupported) { - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 2, mockCaCert); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, - generateMockCert("middle", "ca", false)); - mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 2, FakeKeys.CA_CERT0); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 1, FakeKeys.CA_CERT1); + mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CLIENT_CERT); } verifyTrustOnFirstUseFlow(config, action, isTrustOnFirstUseSupported, - isUserSelected, needUserApproval, mockCaCert, mockServerCert); + isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CLIENT_CERT); } private void verifyTrustOnFirstUseFlow(WifiConfiguration config, @@ -720,17 +518,12 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { assertEquals(needUserApproval, mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); - ArgumentCaptor dialogMessageCaptor = ArgumentCaptor.forClass(String.class); if (isUserSelected) { ArgumentCaptor dialogCallbackCaptor = ArgumentCaptor.forClass(WifiDialogManager.SimpleDialogCallback.class); verify(mWifiDialogManager).createSimpleDialogWithUrl( - any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(), any(), - any(), dialogCallbackCaptor.capture(), any()); - if (isTrustOnFirstUseSupported) { - assertTofuDialogMessage(expectedCaCert, expectedServerCert, - dialogMessageCaptor.getValue()); - } + any(), any(), any(), anyInt(), anyInt(), any(), any(), any(), + dialogCallbackCaptor.capture(), any()); if (action == ACTION_ACCEPT) { dialogCallbackCaptor.getValue().onPositiveButtonClicked(); } else if (action == ACTION_REJECT) { @@ -740,7 +533,6 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { verify(mFrameworkFacade, never()).makeAlertDialogBuilder(any()); verify(mFrameworkFacade).makeNotificationBuilder( eq(mContext), eq(WifiService.NOTIFICATION_NETWORK_ALERTS)); - // Trust On First Use notification has no accept and reject action buttons. // It only supports TAP and launch the dialog. if (isTrustOnFirstUseSupported) { @@ -751,10 +543,8 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { ArgumentCaptor dialogCallbackCaptor = ArgumentCaptor.forClass(WifiDialogManager.SimpleDialogCallback.class); verify(mWifiDialogManager).createSimpleDialogWithUrl( - any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(), - any(), any(), dialogCallbackCaptor.capture(), any()); - assertTofuDialogMessage(expectedCaCert, expectedServerCert, - dialogMessageCaptor.getValue()); + any(), any(), any(), anyInt(), anyInt(), any(), any(), any(), + dialogCallbackCaptor.capture(), any()); if (action == ACTION_ACCEPT) { dialogCallbackCaptor.getValue().onPositiveButtonClicked(); } else if (action == ACTION_REJECT) { @@ -776,8 +566,7 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { } if (action == ACTION_ACCEPT) { - verify(mWifiConfigManager).updateNetworkSelectionStatus(eq(config.networkId), - eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE)); + verify(mWifiConfigManager).allowAutojoin(eq(config.networkId), eq(true)); if (isTrustOnFirstUseSupported) { verify(mWifiConfigManager).updateCaCertificate( eq(config.networkId), eq(expectedCaCert), eq(expectedServerCert)); @@ -787,10 +576,7 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { } verify(mCallbacks).onAccept(eq(config.SSID)); } else if (action == ACTION_REJECT) { - verify(mWifiConfigManager, atLeastOnce()) - .updateNetworkSelectionStatus(eq(config.networkId), - eq(WifiConfiguration.NetworkSelectionStatus - .DISABLED_BY_WIFI_MANAGER)); + verify(mWifiConfigManager).allowAutojoin(eq(config.networkId), eq(false)); verify(mCallbacks).onReject(eq(config.SSID)); } else if (action == ACTION_TAP) { verify(mWifiDialogManager).createSimpleDialogWithUrl( @@ -800,44 +586,4 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { verify(mCallbacks, never()).onError(any()); } - private void assertTofuDialogMessage( - X509Certificate rootCaCert, - X509Certificate serverCert, - String message) { - CertificateSubjectInfo serverCertSubjectInfo = - CertificateSubjectInfo.parse(serverCert.getSubjectX500Principal().getName()); - CertificateSubjectInfo serverCertIssuerInfo = - CertificateSubjectInfo.parse(serverCert.getIssuerX500Principal().getName()); - assertNotNull("Server cert subject info is null", serverCertSubjectInfo); - assertNotNull("Server cert issuer info is null", serverCertIssuerInfo); - - assertTrue("TOFU dialog message does not contain server cert subject name ", - message.contains(serverCertSubjectInfo.commonName)); - assertTrue("TOFU dialog message does not contain server cert issuer name", - message.contains(serverCertIssuerInfo.commonName)); - if (!TextUtils.isEmpty(serverCertSubjectInfo.organization)) { - assertTrue("TOFU dialog message does not contain server cert organization", - message.contains(serverCertSubjectInfo.organization)); - } - if (!TextUtils.isEmpty(serverCertSubjectInfo.email)) { - assertTrue("TOFU dialog message does not contain server cert email", - message.contains(serverCertSubjectInfo.email)); - } - assertTrue("TOFU dialog message does not contain server cert signature", - message.contains(NativeUtil.hexStringFromByteArray( - rootCaCert.getSignature()).substring(0, 16))); - } - - @Test - public void testCleanUp() throws Exception { - assumeTrue(SdkLevel.isAtLeastT()); - - boolean isAtLeastT = true, isTrustOnFirstUseSupported = true; - WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); - setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); - - BroadcastReceiver br = mBroadcastReceiverCaptor.getValue(); - mInsecureEapNetworkHandler.cleanup(); - verify(mContext).unregisterReceiver(br); - } }