From 0dde119d7e64d950701fdfaf399e6661ed58b01b Mon Sep 17 00:00:00 2001 From: Tad Date: Mon, 12 Jun 2023 20:21:48 -0400 Subject: [PATCH] 20.0 June ASB work + churn QPR3 is delayed a week now Patches pulled from GrapheneOS and checked against CalyxOS Signed-off-by: Tad --- Patches/Common/contributors.db | Bin 438272 -> 458752 bytes ...actor-readSampleData-buffer-Handling.patch | 75 + .../0003-SUPL_No_IMSI.patch | 6 +- .../0005-User_Logout-a1.patch | 4 +- .../0005-User_Logout.patch | 4 +- .../0032-SUPL_Toggle.patch | 4 +- ...resheet-from-previewing-unowned-URIs.patch | 105 + ...vity-if-it-enters-PiP-without-window.patch | 35 + ...ing-images-to-complete-before-inflat.patch | 238 ++ ...revent-RemoteViews-crashing-SystemUi.patch | 290 +++ ...t-for-selectors-and-prohibited-flags.patch | 167 ++ ...t-for-media-click-action-over-locksc.patch | 48 + .../0007-Allow-filtering-of-services.patch | 236 ++ ...licyManager.setUserControlDisabledPa.patch | 252 ++ ...ubbleMetadata-detection-to-block-FSI.patch | 72 + ...ix-issues-with-setRemotePlaybackInfo.patch | 109 + .../0001-Remove_Analytics.patch | 12 +- .../0004-Private_DNS.patch | 2 +- .../0015-SUPL_Toggle.patch | 2 +- ...ment-to-intent-in-AddAccountSettings.patch | 28 + ...-with-excessively-long-component-nam.patch | 40 + ...e-Traceur-to-check-admin-user-status.patch | 290 +++ ...dd-DISALLOW_DEBUGGING_FEATURES-check.patch | 183 ++ .../0001-Server.patch | 2 +- .../0002-Tor_Support.patch | 4 +- ...ead-in-btm_ble_periodic_av_sync_lost.patch | 44 + ...lidate-buffer-length-in-sdpu_build_u.patch | 128 + .../0001-Random_MAC.patch | 6 +- .../344228.patch | 2 +- ...ntials-in-an-unauthenticated-TLS-tun.patch | 1692 +++++++++++++ ...t-send-credentials-in-an-unauthentic.patch | 1685 +++++++++++++ .../0003-Implement-a-secure-TOFU-flow.patch | 2185 +++++++++++++++++ ...-unbind-service-when-onBind-returns-.patch | 79 + Scripts/Common/Fix_CVE_Patchers.sh | 10 +- .../android_kernel_google_marlin.sh | 2 +- .../android_kernel_motorola_msm8996.sh | 2 +- .../android_kernel_oneplus_msm8996.sh | 2 +- .../android_kernel_zuk_msm8996.sh | 2 +- .../android_kernel_essential_msm8998.sh | 2 +- .../android_kernel_fairphone_sdm632.sh | 2 +- .../android_kernel_fairphone_sm7225.sh | 4 +- .../android_kernel_fxtec_msm8998.sh | 2 +- .../android_kernel_fxtec_sm6115.sh | 4 +- .../android_kernel_google_msm-4.9.sh | 2 +- .../android_kernel_google_wahoo.sh | 2 +- .../android_kernel_oneplus_msm8998.sh | 2 +- .../android_kernel_oneplus_sdm845.sh | 2 +- .../android_kernel_oneplus_sm8250.sh | 4 +- .../android_kernel_oneplus_sm8350.sh | 21 +- .../android_kernel_razer_msm8998.sh | 2 +- .../android_kernel_razer_sdm845.sh | 2 +- .../android_kernel_samsung_exynos9810.sh | 2 +- .../android_kernel_sony_sdm845.sh | 2 +- .../android_kernel_xiaomi_msm8937.sh | 2 +- .../android_kernel_xiaomi_sdm845.sh | 2 +- Scripts/LineageOS-20.0/Patch.sh | 21 + 56 files changed, 8052 insertions(+), 75 deletions(-) create mode 100644 Patches/LineageOS-20.0/android_frameworks_av/ASB-2023-06/0001-Fix-NuMediaExtractor-readSampleData-buffer-Handling.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0001-Prevent-sharesheet-from-previewing-unowned-URIs.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0002-Remove-Activity-if-it-enters-PiP-without-window.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0003-Wait-for-preloading-images-to-complete-before-inflat.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0004-Prevent-RemoteViews-crashing-SystemUi.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0005-Check-key-intent-for-selectors-and-prohibited-flags.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0006-Use-PendingIntent-for-media-click-action-over-locksc.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0007-Allow-filtering-of-services.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0008-Enforce-DevicePolicyManager.setUserControlDisabledPa.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0009-Add-BubbleMetadata-detection-to-block-FSI.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0010-Fix-issues-with-setRemotePlaybackInfo.patch create mode 100644 Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0001-Convert-argument-to-intent-in-AddAccountSettings.patch create mode 100644 Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0002-Don-t-show-NLSes-with-excessively-long-component-nam.patch create mode 100644 Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0001-Update-Traceur-to-check-admin-user-status.patch create mode 100644 Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0002-Add-DISALLOW_DEBUGGING_FEATURES-check.patch create mode 100644 Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0001-Fix-OOB-read-in-btm_ble_periodic_av_sync_lost.patch create mode 100644 Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0002-Revert-Revert-Validate-buffer-length-in-sdpu_build_u.patch create mode 100644 Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0001-Don-t-send-credentials-in-an-unauthenticated-TLS-tun.patch create mode 100644 Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0002-Revert-TOFU-Don-t-send-credentials-in-an-unauthentic.patch create mode 100644 Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0003-Implement-a-secure-TOFU-flow.patch create mode 100644 Patches/LineageOS-20.0/android_packages_services_Telecomm/ASB-2023-06/0001-Call-Redirection-unbind-service-when-onBind-returns-.patch diff --git a/Patches/Common/contributors.db b/Patches/Common/contributors.db index b9f213b835520132bd66b436a79cf6cfe7474741..fd03c02cb2e0428956517747652918bc152b1fc1 100644 GIT binary patch literal 458752 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

k*d>fpTk!0FBI8JlER4Th64foG!qgQ8P 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

(@I&Xq*EKgZU@m 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 z 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 +Date: Mon, 27 Mar 2023 18:16:46 -0500 +Subject: [PATCH] Fix NuMediaExtractor::readSampleData buffer Handling + +readSampleData() did not initialize buffer before filling it, +leading to OOB memory references. Correct and clarify the book +keeping around output buffer management. + +Bug: 275418191 +Test: CtsMediaExtractorTestCases w/debug messages +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:943fc12219b21d2a98f0ddc070b9b316a6f5d412) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:84c69bca81175feb2fd97ebb22e432ee41572786) +Merged-In: Ie744f118526f100d82a312c64f7c6fcf20773b6d +Change-Id: Ie744f118526f100d82a312c64f7c6fcf20773b6d +--- + media/libstagefright/NuMediaExtractor.cpp | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp +index 2b45f2d16d..5b39618ad7 100644 +--- a/media/libstagefright/NuMediaExtractor.cpp ++++ b/media/libstagefright/NuMediaExtractor.cpp +@@ -639,9 +639,11 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples( + numPageSamples = -1; + } + ++ // insert, including accounting for the space used. + memcpy((uint8_t *)buffer->data() + mbuf->range_length(), + &numPageSamples, + sizeof(numPageSamples)); ++ buffer->setRange(buffer->offset(), buffer->size() + sizeof(numPageSamples)); + + uint32_t type; + const void *data; +@@ -690,6 +692,8 @@ status_t NuMediaExtractor::readSampleData(const sp &buffer) { + + ssize_t minIndex = fetchAllTrackSamples(); + ++ buffer->setRange(0, 0); // start with an empty buffer ++ + if (minIndex < 0) { + return ERROR_END_OF_STREAM; + } +@@ -705,25 +709,25 @@ status_t NuMediaExtractor::readSampleData(const sp &buffer) { + sampleSize += sizeof(int32_t); + } + ++ // capacity() is ok since we cleared out the buffer + if (buffer->capacity() < sampleSize) { + return -ENOMEM; + } + ++ const size_t srclen = it->mBuffer->range_length(); + const uint8_t *src = + (const uint8_t *)it->mBuffer->data() + + it->mBuffer->range_offset(); + +- memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length()); ++ memcpy((uint8_t *)buffer->data(), src, srclen); ++ buffer->setRange(0, srclen); + + status_t err = OK; + if (info->mTrackFlags & kIsVorbis) { ++ // adjusts range when it inserts the extra bits + err = appendVorbisNumPageSamples(it->mBuffer, buffer); + } + +- if (err == OK) { +- buffer->setRange(0, sampleSize); +- } +- + return err; + } + diff --git a/Patches/LineageOS-20.0/android_frameworks_base/0003-SUPL_No_IMSI.patch b/Patches/LineageOS-20.0/android_frameworks_base/0003-SUPL_No_IMSI.patch index aeb17000..62929054 100644 --- a/Patches/LineageOS-20.0/android_frameworks_base/0003-SUPL_No_IMSI.patch +++ b/Patches/LineageOS-20.0/android_frameworks_base/0003-SUPL_No_IMSI.patch @@ -9,10 +9,10 @@ Change-Id: I5ccc4d61e52ac11ef33f44618d0e610089885b87 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java -index 389cbe20dbd3..b3a81f597db1 100644 +index 842e6d914f4f..3a3504528b97 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java -@@ -1722,6 +1722,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements +@@ -1733,6 +1733,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements int type = AGPS_SETID_TYPE_NONE; String setId = null; @@ -24,7 +24,7 @@ index 389cbe20dbd3..b3a81f597db1 100644 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); if (mNIHandler.getInEmergency() && mNetworkConnectivityHandler.getActiveSubId() >= 0) { subId = mNetworkConnectivityHandler.getActiveSubId(); -@@ -1741,7 +1746,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements +@@ -1752,7 +1757,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // This means the framework has the SIM card. type = AGPS_SETID_TYPE_MSISDN; } diff --git a/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout-a1.patch b/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout-a1.patch index b9ff2cd5..2fd59bf9 100644 --- a/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout-a1.patch +++ b/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout-a1.patch @@ -10,10 +10,10 @@ in both callers of this method (both of which are "End session" buttons), making 1 file changed, 6 insertions(+) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java -index ba084057c721..b870c54b2768 100644 +index f3fb5d90a166..87e826e946b5 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java -@@ -11162,6 +11162,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { +@@ -11164,6 +11164,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkCallAuthorization(canManageUsers(caller) || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS)); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout.patch b/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout.patch index 2d147750..467c6c99 100644 --- a/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout.patch +++ b/Patches/LineageOS-20.0/android_frameworks_base/0005-User_Logout.patch @@ -23,10 +23,10 @@ index 0c69067ab131..ef3213b68bfe 100644 // one notification after enabling + one more after reboots static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java -index 515d6dc9cab1..ba084057c721 100644 +index e95f827ff6f1..f3fb5d90a166 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java -@@ -16090,11 +16090,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { +@@ -16092,11 +16092,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public boolean isLogoutEnabled() { if (!mHasFeature) { diff --git a/Patches/LineageOS-20.0/android_frameworks_base/0032-SUPL_Toggle.patch b/Patches/LineageOS-20.0/android_frameworks_base/0032-SUPL_Toggle.patch index 7ca1a4b4..d4a56636 100644 --- a/Patches/LineageOS-20.0/android_frameworks_base/0032-SUPL_Toggle.patch +++ b/Patches/LineageOS-20.0/android_frameworks_base/0032-SUPL_Toggle.patch @@ -75,7 +75,7 @@ index 1435016fc55a..db8131729555 100644 + } } diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java -index b3a81f597db1..97dda44b1c97 100644 +index 3a3504528b97..ed737760779b 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -100,6 +100,7 @@ import android.telephony.TelephonyManager; @@ -86,7 +86,7 @@ index b3a81f597db1..97dda44b1c97 100644 import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; -@@ -481,6 +482,20 @@ public class GnssLocationProvider extends AbstractLocationProvider implements +@@ -482,6 +483,20 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssNative.setNotificationCallbacks(this); mGnssNative.setLocationRequestCallbacks(this); mGnssNative.setTimeCallbacks(this); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0001-Prevent-sharesheet-from-previewing-unowned-URIs.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0001-Prevent-sharesheet-from-previewing-unowned-URIs.patch new file mode 100644 index 00000000..dae662a8 --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0001-Prevent-sharesheet-from-previewing-unowned-URIs.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Renouf +Date: Wed, 22 Feb 2023 14:48:51 +0000 +Subject: [PATCH 01/10] Prevent sharesheet from previewing unowned URIs + +Bug: 261036568 +Test: manually via supplied tool (see bug) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fa83e125d14e458545086d16f2e7d1051812dabc) +Merged-In: Ib3f5839d00c7cf09bca3b01fc0a8a6f0f4960993 +Change-Id: Ib3f5839d00c7cf09bca3b01fc0a8a6f0f4960993 +--- + .../android/internal/app/ChooserActivity.java | 35 +++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java +index bfff93b5f7a4..b68e4f4956d0 100644 +--- a/core/java/com/android/internal/app/ChooserActivity.java ++++ b/core/java/com/android/internal/app/ChooserActivity.java +@@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT + import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL; + import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK; + import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE; ++import static android.content.ContentProvider.getUserIdFromUri; + import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL; + import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK; + +@@ -161,6 +162,7 @@ import java.util.List; + import java.util.Map; + import java.util.Objects; + import java.util.function.Supplier; ++import java.util.stream.Collectors; + + /** + * The Chooser Activity handles intent resolution specifically for sharing intents - +@@ -1395,7 +1397,7 @@ public class ChooserActivity extends ResolverActivity implements + + ImageView previewThumbnailView = contentPreviewLayout.findViewById( + R.id.content_preview_thumbnail); +- if (previewThumbnail == null) { ++ if (!validForContentPreview(previewThumbnail)) { + previewThumbnailView.setVisibility(View.GONE); + } else { + mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, false); +@@ -1428,6 +1430,10 @@ public class ChooserActivity extends ResolverActivity implements + + if (Intent.ACTION_SEND.equals(action)) { + Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); ++ if (!validForContentPreview(uri)) { ++ contentPreviewLayout.setVisibility(View.GONE); ++ return contentPreviewLayout; ++ } + imagePreview.findViewById(R.id.content_preview_image_1_large) + .setTransitionName(ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME); + mPreviewCoord.loadUriIntoView(R.id.content_preview_image_1_large, uri, 0); +@@ -1437,7 +1443,7 @@ public class ChooserActivity extends ResolverActivity implements + List uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + List imageUris = new ArrayList<>(); + for (Uri uri : uris) { +- if (isImageType(resolver.getType(uri))) { ++ if (validForContentPreview(uri) && isImageType(resolver.getType(uri))) { + imageUris.add(uri); + } + } +@@ -1547,9 +1553,16 @@ public class ChooserActivity extends ResolverActivity implements + String action = targetIntent.getAction(); + if (Intent.ACTION_SEND.equals(action)) { + Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); ++ if (!validForContentPreview(uri)) { ++ contentPreviewLayout.setVisibility(View.GONE); ++ return contentPreviewLayout; ++ } + loadFileUriIntoView(uri, contentPreviewLayout); + } else { + List uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); ++ uris = uris.stream() ++ .filter(ChooserActivity::validForContentPreview) ++ .collect(Collectors.toList()); + int uriCount = uris.size(); + + if (uriCount == 0) { +@@ -1608,6 +1621,24 @@ public class ChooserActivity extends ResolverActivity implements + } + } + ++ /** ++ * Indicate if the incoming content URI should be allowed. ++ * ++ * @param uri the uri to test ++ * @return true if the URI is allowed for content preview ++ */ ++ private static boolean validForContentPreview(Uri uri) throws SecurityException { ++ if (uri == null) { ++ return false; ++ } ++ int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT); ++ if (userId != UserHandle.USER_CURRENT && userId != UserHandle.myUserId()) { ++ Log.e(TAG, "dropped invalid content URI belonging to user " + userId); ++ return false; ++ } ++ return true; ++ } ++ + @VisibleForTesting + protected boolean isImageType(String mimeType) { + return mimeType != null && mimeType.startsWith("image/"); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0002-Remove-Activity-if-it-enters-PiP-without-window.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0002-Remove-Activity-if-it-enters-PiP-without-window.patch new file mode 100644 index 00000000..5f08903e --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0002-Remove-Activity-if-it-enters-PiP-without-window.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hongwei Wang +Date: Thu, 23 Feb 2023 13:23:37 -0800 +Subject: [PATCH 02/10] Remove Activity if it enters PiP without window + +This is to prevent malicious app entering PiP without being visible +first, like blocking onResume from completion. Which in turn +leaves the PiP window in limbo and non-interactable. + +Bug: 265293293 +Test: atest PinnedStackTests +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4fad1456409b79d6e649a29d5116a4fe3160bd21) +Merged-In: I458a9508662e72a1adb9d9818105f2e9d7096d44 +Change-Id: I458a9508662e72a1adb9d9818105f2e9d7096d44 +--- + .../core/java/com/android/server/wm/ActivityRecord.java | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java +index c1cbdef6b5f5..69e1511da7be 100644 +--- a/services/core/java/com/android/server/wm/ActivityRecord.java ++++ b/services/core/java/com/android/server/wm/ActivityRecord.java +@@ -1477,6 +1477,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A + mLastReportedMultiWindowMode = inPictureInPictureMode; + ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS, + true /* ignoreVisibility */); ++ if (inPictureInPictureMode && findMainWindow() == null) { ++ // Prevent malicious app entering PiP without valid WindowState, which can in turn ++ // result a non-touchable PiP window since the InputConsumer for PiP requires it. ++ EventLog.writeEvent(0x534e4554, "265293293", -1, ""); ++ removeImmediately(); ++ } + } + } + diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0003-Wait-for-preloading-images-to-complete-before-inflat.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0003-Wait-for-preloading-images-to-complete-before-inflat.patch new file mode 100644 index 00000000..5815fdc7 --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0003-Wait-for-preloading-images-to-complete-before-inflat.patch @@ -0,0 +1,238 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Valentin Iftime +Date: Wed, 15 Feb 2023 20:39:44 +0100 +Subject: [PATCH 03/10] Wait for preloading images to complete before inflating + notifications + + NotificationContentInflater waits on SysUiBg thread for images to load, with a timeout + of 1000ms. + +Test: 1. Build a test app that posts MessagingStyle notifications with a huge image (8k+) set as data Uri. + 2. SystemUi should not ANR + 3. adb logcat | grep NotificationInlineImageCache - shows timeout/cancellation logs + +Bug: 252766417 +Bug: 223859644 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2a2da8935ab70163044c34d7b0d9b9ed4cb91a76) +Merged-In: I341db60223214cf2282b5c0270e343e1ce95fa01 +Change-Id: I341db60223214cf2282b5c0270e343e1ce95fa01 +--- + .../row/NotificationContentInflater.java | 15 +++++- + .../row/NotificationInlineImageCache.java | 21 ++++++-- + .../row/NotificationInlineImageResolver.java | 49 +++++++++++++++++-- + 3 files changed, 76 insertions(+), 9 deletions(-) + +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +index c534860d12c6..d2fb0c142cc5 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +@@ -439,6 +439,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder + CancellationSignal cancellationSignal = new CancellationSignal(); + cancellationSignal.setOnCancelListener( + () -> runningInflations.values().forEach(CancellationSignal::cancel)); ++ + return cancellationSignal; + } + +@@ -711,6 +712,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder + public static class AsyncInflationTask extends AsyncTask + implements InflationCallback, InflationTask { + ++ private static final long IMG_PRELOAD_TIMEOUT_MS = 1000L; + private final NotificationEntry mEntry; + private final Context mContext; + private final boolean mInflateSynchronously; +@@ -804,7 +806,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder + recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight, + mUsesIncreasedHeadsUpHeight, packageContext); + InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState(); +- return inflateSmartReplyViews( ++ InflationProgress result = inflateSmartReplyViews( + inflationProgress, + mReInflateFlags, + mEntry, +@@ -812,6 +814,11 @@ public class NotificationContentInflater implements NotificationRowContentBinder + packageContext, + previousSmartReplyState, + mSmartRepliesInflater); ++ ++ // wait for image resolver to finish preloading ++ mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS); ++ ++ return result; + } catch (Exception e) { + mError = e; + return null; +@@ -846,6 +853,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder + mCallback.handleInflationException(mRow.getEntry(), + new InflationException("Couldn't inflate contentViews" + e)); + } ++ ++ // Cancel any image loading tasks, not useful any more ++ mRow.getImageResolver().cancelRunningTasks(); + } + + @Override +@@ -872,6 +882,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder + // Notify the resolver that the inflation task has finished, + // try to purge unnecessary cached entries. + mRow.getImageResolver().purgeCache(); ++ ++ // Cancel any image loading tasks that have not completed at this point ++ mRow.getImageResolver().cancelRunningTasks(); + } + + private static class RtlEnabledContext extends ContextWrapper { +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java +index 41eeada0fcda..fe0b3123eb25 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java +@@ -22,8 +22,11 @@ import android.os.AsyncTask; + import android.util.Log; + + import java.util.Set; ++import java.util.concurrent.CancellationException; + import java.util.concurrent.ConcurrentHashMap; + import java.util.concurrent.ExecutionException; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.TimeoutException; + + /** + * A cache for inline images of image messages. +@@ -56,12 +59,13 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso + } + + @Override +- public Drawable get(Uri uri) { ++ public Drawable get(Uri uri, long timeoutMs) { + Drawable result = null; + try { +- result = mCache.get(uri).get(); +- } catch (InterruptedException | ExecutionException ex) { +- Log.d(TAG, "get: Failed get image from " + uri); ++ result = mCache.get(uri).get(timeoutMs, TimeUnit.MILLISECONDS); ++ } catch (InterruptedException | ExecutionException ++ | TimeoutException | CancellationException ex) { ++ Log.d(TAG, "get: Failed get image from " + uri + " " + ex); + } + return result; + } +@@ -72,6 +76,15 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso + mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey())); + } + ++ @Override ++ public void cancelRunningTasks() { ++ mCache.forEach((key, value) -> { ++ if (value.getStatus() != AsyncTask.Status.FINISHED) { ++ value.cancel(true); ++ } ++ }); ++ } ++ + private static class PreloadImageTask extends AsyncTask { + private final NotificationInlineImageResolver mResolver; + +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java +index b05e64ab1991..c620f448b3b7 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java +@@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable; + import android.net.Uri; + import android.os.Bundle; + import android.os.Parcelable; ++import android.os.SystemClock; + import android.util.Log; + + import com.android.internal.R; +@@ -45,6 +46,9 @@ import java.util.Set; + public class NotificationInlineImageResolver implements ImageResolver { + private static final String TAG = NotificationInlineImageResolver.class.getSimpleName(); + ++ // Timeout for loading images from ImageCache when calling from UI thread ++ private static final long MAX_UI_THREAD_TIMEOUT_MS = 100L; ++ + private final Context mContext; + private final ImageCache mImageCache; + private Set mWantedUriSet; +@@ -123,17 +127,25 @@ public class NotificationInlineImageResolver implements ImageResolver { + return null; + } + ++ /** ++ * Loads an image from the Uri. ++ * This method is synchronous and is usually called from the Main thread. ++ * It will time-out after MAX_UI_THREAD_TIMEOUT_MS. ++ * ++ * @param uri Uri of the target image. ++ * @return drawable of the image, null if loading failed/timeout ++ */ + @Override + public Drawable loadImage(Uri uri) { +- return hasCache() ? loadImageFromCache(uri) : resolveImage(uri); ++ return hasCache() ? loadImageFromCache(uri, MAX_UI_THREAD_TIMEOUT_MS) : resolveImage(uri); + } + +- private Drawable loadImageFromCache(Uri uri) { ++ private Drawable loadImageFromCache(Uri uri, long timeoutMs) { + // if the uri isn't currently cached, try caching it first + if (!mImageCache.hasEntry(uri)) { + mImageCache.preload((uri)); + } +- return mImageCache.get(uri); ++ return mImageCache.get(uri, timeoutMs); + } + + /** +@@ -207,6 +219,30 @@ public class NotificationInlineImageResolver implements ImageResolver { + return mWantedUriSet; + } + ++ /** ++ * Wait for a maximum timeout for images to finish preloading ++ * @param timeoutMs total timeout time ++ */ ++ void waitForPreloadedImages(long timeoutMs) { ++ if (!hasCache()) { ++ return; ++ } ++ Set preloadedUris = getWantedUriSet(); ++ if (preloadedUris != null) { ++ // Decrement remaining timeout after each image check ++ long endTimeMs = SystemClock.elapsedRealtime() + timeoutMs; ++ preloadedUris.forEach( ++ uri -> loadImageFromCache(uri, endTimeMs - SystemClock.elapsedRealtime())); ++ } ++ } ++ ++ void cancelRunningTasks() { ++ if (!hasCache()) { ++ return; ++ } ++ mImageCache.cancelRunningTasks(); ++ } ++ + /** + * A interface for internal cache implementation of this resolver. + */ +@@ -216,7 +252,7 @@ public class NotificationInlineImageResolver implements ImageResolver { + * @param uri The uri of the image. + * @return Drawable of the image. + */ +- Drawable get(Uri uri); ++ Drawable get(Uri uri, long timeoutMs); + + /** + * Set the image resolver that actually resolves image from specified uri. +@@ -241,6 +277,11 @@ public class NotificationInlineImageResolver implements ImageResolver { + * Purge unnecessary entries in the cache. + */ + void purge(); ++ ++ /** ++ * Cancel all unfinished image loading tasks ++ */ ++ void cancelRunningTasks(); + } + + } diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0004-Prevent-RemoteViews-crashing-SystemUi.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0004-Prevent-RemoteViews-crashing-SystemUi.patch new file mode 100644 index 00000000..06d86ec2 --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0004-Prevent-RemoteViews-crashing-SystemUi.patch @@ -0,0 +1,290 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Valentin Iftime +Date: Wed, 22 Feb 2023 09:38:55 +0100 +Subject: [PATCH 04/10] Prevent RemoteViews crashing SystemUi + + Catch canvas drawing exceptions caused by unsuported image sizes. + +Test: 1. Post a custom view notification with a layout + containing an ImageView that references a 5k x 5k image +2. Add an App Widget to the home screen with that has the + layout mentioned above as preview/initial layout. + +Bug: 268193777 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:10752edb540a053e304139894f941fcaef60949b) +Merged-In: Ib3bda769c499b4069b49c566b1b227f98f707a8a +Change-Id: Ib3bda769c499b4069b49c566b1b227f98f707a8a +--- + .../android/appwidget/AppWidgetHostView.java | 39 ++++++++++---- + .../row/ExpandableNotificationRow.java | 7 ++- + .../ExpandableNotificationRowController.java | 9 +++- + .../row/NotificationContentView.java | 54 ++++++++++++++++++- + .../row/NotificationTestHelper.java | 4 +- + 5 files changed, 97 insertions(+), 16 deletions(-) + +diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java +index fe10b7f8b3f4..27f6a266597c 100644 +--- a/core/java/android/appwidget/AppWidgetHostView.java ++++ b/core/java/android/appwidget/AppWidgetHostView.java +@@ -31,6 +31,7 @@ import android.content.pm.LauncherActivityInfo; + import android.content.pm.LauncherApps; + import android.content.pm.PackageManager.NameNotFoundException; + import android.content.res.Resources; ++import android.graphics.Canvas; + import android.graphics.Color; + import android.graphics.PointF; + import android.graphics.Rect; +@@ -311,19 +312,26 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW + super.onLayout(changed, left, top, right, bottom); + } catch (final RuntimeException e) { + Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e); +- removeViewInLayout(mView); +- View child = getErrorView(); +- prepareView(child); +- addViewInLayout(child, 0, child.getLayoutParams()); +- measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), +- MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); +- child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight, +- child.getMeasuredHeight() + mPaddingTop + mPaddingBottom); +- mView = child; +- mViewMode = VIEW_MODE_ERROR; ++ handleViewError(); + } + } + ++ /** ++ * Remove bad view and replace with error message view ++ */ ++ private void handleViewError() { ++ removeViewInLayout(mView); ++ View child = getErrorView(); ++ prepareView(child); ++ addViewInLayout(child, 0, child.getLayoutParams()); ++ measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), ++ MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); ++ child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight, ++ child.getMeasuredHeight() + mPaddingTop + mPaddingBottom); ++ mView = child; ++ mViewMode = VIEW_MODE_ERROR; ++ } ++ + /** + * Provide guidance about the size of this widget to the AppWidgetManager. The widths and + * heights should correspond to the full area the AppWidgetHostView is given. Padding added by +@@ -953,4 +961,15 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW + reapplyLastRemoteViews(); + } + } ++ ++ @Override ++ protected void dispatchDraw(@NonNull Canvas canvas) { ++ try { ++ super.dispatchDraw(canvas); ++ } catch (Exception e) { ++ // Catch draw exceptions that may be caused by RemoteViews ++ Log.e(TAG, "Drawing view failed: " + e); ++ post(this::handleViewError); ++ } ++ } + } +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +index 9f50aef6de11..816ccee604d4 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +@@ -73,6 +73,7 @@ import androidx.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; + import com.android.internal.logging.MetricsLogger; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; ++import com.android.internal.statusbar.IStatusBarService; + import com.android.internal.util.ContrastColorUtil; + import com.android.internal.widget.CachingIconView; + import com.android.internal.widget.CallLayout; +@@ -1662,7 +1663,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView + NotificationGutsManager gutsManager, + MetricsLogger metricsLogger, + SmartReplyConstants smartReplyConstants, +- SmartReplyController smartReplyController) { ++ SmartReplyController smartReplyController, ++ IStatusBarService statusBarService) { + mEntry = entry; + mAppName = appName; + if (mMenuRow == null) { +@@ -1691,7 +1693,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView + mPeopleNotificationIdentifier, + rivSubcomponentFactory, + smartReplyConstants, +- smartReplyController); ++ smartReplyController, ++ statusBarService); + } + mOnUserInteractionCallback = onUserInteractionCallback; + mBubblesManagerOptional = bubblesManagerOptional; +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +index d1138608805b..a9bf51fae1fd 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +@@ -29,6 +29,7 @@ import androidx.annotation.NonNull; + import androidx.annotation.Nullable; + + import com.android.internal.logging.MetricsLogger; ++import com.android.internal.statusbar.IStatusBarService; + import com.android.systemui.classifier.FalsingCollector; + import com.android.systemui.flags.FeatureFlags; + import com.android.systemui.flags.Flags; +@@ -125,6 +126,7 @@ public class ExpandableNotificationRowController implements NotifViewController + } + }; + ++ private final IStatusBarService mStatusBarService; + + @Inject + public ExpandableNotificationRowController( +@@ -157,7 +159,8 @@ public class ExpandableNotificationRowController implements NotifViewController + FeatureFlags featureFlags, + PeopleNotificationIdentifier peopleNotificationIdentifier, + Optional bubblesManagerOptional, +- ExpandableNotificationRowDragController dragController) { ++ ExpandableNotificationRowDragController dragController, ++ IStatusBarService statusBarService) { + mView = view; + mListContainer = listContainer; + mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory; +@@ -189,6 +192,7 @@ public class ExpandableNotificationRowController implements NotifViewController + mLogBufferLogger = logBufferLogger; + mSmartReplyConstants = smartReplyConstants; + mSmartReplyController = smartReplyController; ++ mStatusBarService = statusBarService; + } + + /** +@@ -219,7 +223,8 @@ public class ExpandableNotificationRowController implements NotifViewController + mNotificationGutsManager, + mMetricsLogger, + mSmartReplyConstants, +- mSmartReplyController ++ mSmartReplyController, ++ mStatusBarService + ); + mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + if (mAllowLongPress) { +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +index e46bf522acff..6b729f240c80 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +@@ -21,10 +21,13 @@ import android.annotation.Nullable; + import android.app.Notification; + import android.app.PendingIntent; + import android.content.Context; ++import android.graphics.Canvas; + import android.graphics.Rect; + import android.graphics.drawable.Drawable; + import android.os.Build; ++import android.os.RemoteException; + import android.provider.Settings; ++import android.service.notification.StatusBarNotification; + import android.util.ArrayMap; + import android.util.AttributeSet; + import android.util.IndentingPrintWriter; +@@ -39,6 +42,7 @@ import android.widget.ImageView; + import android.widget.LinearLayout; + + import com.android.internal.annotations.VisibleForTesting; ++import com.android.internal.statusbar.IStatusBarService; + import com.android.systemui.R; + import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; + import com.android.systemui.statusbar.RemoteInputController; +@@ -129,6 +133,7 @@ public class NotificationContentView extends FrameLayout implements Notification + private Runnable mExpandedVisibleListener; + private PeopleNotificationIdentifier mPeopleIdentifier; + private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory; ++ private IStatusBarService mStatusBarService; + + /** + * List of listeners for when content views become inactive (i.e. not the showing view). +@@ -194,11 +199,13 @@ public class NotificationContentView extends FrameLayout implements Notification + PeopleNotificationIdentifier peopleNotificationIdentifier, + RemoteInputViewSubcomponent.Factory rivSubcomponentFactory, + SmartReplyConstants smartReplyConstants, +- SmartReplyController smartReplyController) { ++ SmartReplyController smartReplyController, ++ IStatusBarService statusBarService) { + mPeopleIdentifier = peopleNotificationIdentifier; + mRemoteInputSubcomponentFactory = rivSubcomponentFactory; + mSmartReplyConstants = smartReplyConstants; + mSmartReplyController = smartReplyController; ++ mStatusBarService = statusBarService; + } + + public void reinflate() { +@@ -2133,4 +2140,49 @@ public class NotificationContentView extends FrameLayout implements Notification + @Nullable RemoteInputView mView; + @Nullable RemoteInputViewController mController; + } ++ ++ @VisibleForTesting ++ protected void setContractedWrapper(NotificationViewWrapper contractedWrapper) { ++ mContractedWrapper = contractedWrapper; ++ } ++ @VisibleForTesting ++ protected void setExpandedWrapper(NotificationViewWrapper expandedWrapper) { ++ mExpandedWrapper = expandedWrapper; ++ } ++ @VisibleForTesting ++ protected void setHeadsUpWrapper(NotificationViewWrapper headsUpWrapper) { ++ mHeadsUpWrapper = headsUpWrapper; ++ } ++ ++ @Override ++ protected void dispatchDraw(Canvas canvas) { ++ try { ++ super.dispatchDraw(canvas); ++ } catch (Exception e) { ++ // Catch draw exceptions that may be caused by RemoteViews ++ Log.e(TAG, "Drawing view failed: " + e); ++ cancelNotification(e); ++ } ++ } ++ ++ private void cancelNotification(Exception exception) { ++ try { ++ setVisibility(GONE); ++ final StatusBarNotification sbn = mNotificationEntry.getSbn(); ++ if (mStatusBarService != null) { ++ // report notification inflation errors back up ++ // to notification delegates ++ mStatusBarService.onNotificationError( ++ sbn.getPackageName(), ++ sbn.getTag(), ++ sbn.getId(), ++ sbn.getUid(), ++ sbn.getInitialPid(), ++ exception.getMessage(), ++ sbn.getUser().getIdentifier()); ++ } ++ } catch (RemoteException ex) { ++ Log.e(TAG, "cancelNotification failed: " + ex); ++ } ++ } + } +diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +index 728e0265c729..e8aeb18552f8 100644 +--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java ++++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +@@ -50,6 +50,7 @@ import android.widget.RemoteViews; + + import com.android.internal.logging.MetricsLogger; + import com.android.internal.logging.UiEventLogger; ++import com.android.internal.statusbar.IStatusBarService; + import com.android.systemui.TestableDependency; + import com.android.systemui.classifier.FalsingCollectorFake; + import com.android.systemui.classifier.FalsingManagerFake; +@@ -561,7 +562,8 @@ public class NotificationTestHelper { + mock(NotificationGutsManager.class), + mock(MetricsLogger.class), + mock(SmartReplyConstants.class), +- mock(SmartReplyController.class)); ++ mock(SmartReplyController.class), ++ mock(IStatusBarService.class)); + + row.setAboveShelfChangedListener(aboveShelf -> { }); + mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0005-Check-key-intent-for-selectors-and-prohibited-flags.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0005-Check-key-intent-for-selectors-and-prohibited-flags.patch new file mode 100644 index 00000000..06e5bfe8 --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0005-Check-key-intent-for-selectors-and-prohibited-flags.patch @@ -0,0 +1,167 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brian Lee +Date: Fri, 17 Feb 2023 16:05:17 -0800 +Subject: [PATCH 05/10] Check key intent for selectors and prohibited flags + +Bug: 265015796 +Test: atest +FrameworksServicesTests: com.android.server.accounts.AccountManagerServiceTest +(cherry picked from commit e53a96304352e2965176c8d32ac1b504e52ef185) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:64f6c1e13588af3cf4d88a39d9d540c140982043) +Merged-In: Ie16f8654337bd75eaad3156817470674b4f0cee3 +Change-Id: Ie16f8654337bd75eaad3156817470674b4f0cee3 +--- + .../accounts/AccountManagerService.java | 18 +++++++--- + .../accounts/AccountManagerServiceTest.java | 36 +++++++++++++++++++ + .../AccountManagerServiceTestFixtures.java | 5 ++- + .../TestAccountType1Authenticator.java | 5 +-- + 4 files changed, 54 insertions(+), 10 deletions(-) + +diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java +index 425158195940..1dc0942ceac5 100644 +--- a/services/core/java/com/android/server/accounts/AccountManagerService.java ++++ b/services/core/java/com/android/server/accounts/AccountManagerService.java +@@ -4893,10 +4893,6 @@ public class AccountManagerService + if (intent.getClipData() == null) { + intent.setClipData(ClipData.newPlainText(null, null)); + } +- intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION +- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION +- | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION +- | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)); + final long bid = Binder.clearCallingIdentity(); + try { + PackageManager pm = mContext.getPackageManager(); +@@ -4942,7 +4938,19 @@ public class AccountManagerService + if (intent == null) { + return (simulateIntent == null); + } +- return intent.filterEquals(simulateIntent); ++ if (!intent.filterEquals(simulateIntent)) { ++ return false; ++ } ++ ++ if (intent.getSelector() != simulateIntent.getSelector()) { ++ return false; ++ } ++ ++ int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION ++ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION ++ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION ++ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; ++ return (simulateIntent.getFlags() & prohibitedFlags) == 0; + } + + private boolean isExportedSystemActivity(ActivityInfo activityInfo) { +diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +index 30ec1632a622..881d1b3d581c 100644 +--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java ++++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +@@ -18,6 +18,7 @@ package com.android.server.accounts; + + import static android.database.sqlite.SQLiteDatabase.deleteDatabase; + ++import static org.mockito.ArgumentMatchers.contains; + import static org.mockito.Matchers.any; + import static org.mockito.Matchers.anyBoolean; + import static org.mockito.Matchers.anyInt; +@@ -707,6 +708,41 @@ public class AccountManagerServiceTest extends AndroidTestCase { + assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK)); + } + ++ @SmallTest ++ public void testStartAddAccountSessionWhereAuthenticatorReturnsIntentWithProhibitedFlags() ++ throws Exception { ++ unlockSystemUser(); ++ ResolveInfo resolveInfo = new ResolveInfo(); ++ resolveInfo.activityInfo = new ActivityInfo(); ++ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo(); ++ when(mMockPackageManager.resolveActivityAsUser( ++ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo); ++ when(mMockPackageManager.checkSignatures( ++ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH); ++ ++ final CountDownLatch latch = new CountDownLatch(1); ++ Response response = new Response(latch, mMockAccountManagerResponse); ++ Bundle options = createOptionsWithAccountName( ++ AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE); ++ int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION ++ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION ++ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION ++ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; ++ options.putInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, prohibitedFlags); ++ ++ mAms.startAddAccountSession( ++ response, // response ++ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType ++ "authTokenType", ++ null, // requiredFeatures ++ true, // expectActivityLaunch ++ options); // optionsIn ++ waitForLatch(latch); ++ ++ verify(mMockAccountManagerResponse).onError( ++ eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), contains("invalid intent")); ++ } ++ + @SmallTest + public void testStartAddAccountSessionError() throws Exception { + unlockSystemUser(); +diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java +index 73f30d9f9e79..b98a6a891d55 100644 +--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java ++++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java +@@ -17,9 +17,6 @@ package com.android.server.accounts; + + import android.accounts.Account; + +-import java.util.ArrayList; +-import java.util.List; +- + /** + * Constants shared between test AccountAuthenticators and AccountManagerServiceTest. + */ +@@ -31,6 +28,8 @@ public final class AccountManagerServiceTestFixtures { + "account_manager_service_test:account_status_token_key"; + public static final String KEY_ACCOUNT_PASSWORD = + "account_manager_service_test:account_password_key"; ++ public static final String KEY_INTENT_FLAGS = ++ "account_manager_service_test:intent_flags_key"; + public static final String KEY_OPTIONS_BUNDLE = + "account_manager_service_test:option_bundle_key"; + public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com"; +diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java +index 8106364477d9..924443e9d5cf 100644 +--- a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java ++++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java +@@ -24,8 +24,6 @@ import android.content.Context; + import android.content.Intent; + import android.os.Bundle; + +-import com.android.frameworks.servicestests.R; +- + import java.util.concurrent.atomic.AtomicInteger; + + /** +@@ -270,11 +268,13 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator + String accountName = null; + Bundle sessionBundle = null; + String password = null; ++ int intentFlags = 0; + if (options != null) { + accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME); + sessionBundle = options.getBundle( + AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE); + password = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD); ++ intentFlags = options.getInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, 0); + } + + Bundle result = new Bundle(); +@@ -302,6 +302,7 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator + intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT, + eventualActivityResultData); + intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response); ++ intent.setFlags(intentFlags); + + result.putParcelable(AccountManager.KEY_INTENT, intent); + } else { diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0006-Use-PendingIntent-for-media-click-action-over-locksc.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0006-Use-PendingIntent-for-media-click-action-over-locksc.patch new file mode 100644 index 00000000..715e7c27 --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0006-Use-PendingIntent-for-media-click-action-over-locksc.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Beth Thibodeau +Date: Mon, 13 Mar 2023 16:59:33 -0500 +Subject: [PATCH 06/10] Use PendingIntent for media click action over + lockscreen + +The clickIntent is provided by apps as the notification's contentIntent, +and it should be sent as is. This fixes the case where the intent called +an activity that could show over lockscreen. + +Bug: 271845008 +Test: atest MediaControlPanelTest +Test: manually with test app +(cherry picked from commit cb2904c7ff653a87cc98904bcb3bcb9c3b6e06ea) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:223e9c5839308d8cd2e14242315a0e27a5154258) +Merged-In: I09d64452c46c4d21b9d958570020b2f5e6c2b23f +Change-Id: I09d64452c46c4d21b9d958570020b2f5e6c2b23f +--- + .../media/controls/ui/MediaControlPanel.java | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +index 15c34430f455..5cdfe73ad3aa 100644 +--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java ++++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +@@ -495,16 +495,16 @@ public class MediaControlPanel { + mLogger.logTapContentView(mUid, mPackageName, mInstanceId); + logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT); + +- // See StatusBarNotificationActivityStarter#onNotificationClicked + boolean showOverLockscreen = mKeyguardStateController.isShowing() +- && mActivityIntentHelper.wouldShowOverLockscreen(clickIntent.getIntent(), ++ && mActivityIntentHelper.wouldPendingShowOverLockscreen(clickIntent, + mLockscreenUserManager.getCurrentUserId()); + + if (showOverLockscreen) { +- mActivityStarter.startActivity(clickIntent.getIntent(), +- /* dismissShade */ true, +- /* animationController */ null, +- /* showOverLockscreenWhenLocked */ true); ++ try { ++ clickIntent.send(); ++ } catch (PendingIntent.CanceledException e) { ++ Log.e(TAG, "Pending intent for " + key + " was cancelled"); ++ } + } else { + mActivityStarter.postStartActivityDismissingKeyguard(clickIntent, + buildLaunchAnimatorController(mMediaViewHolder.getPlayer())); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0007-Allow-filtering-of-services.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0007-Allow-filtering-of-services.patch new file mode 100644 index 00000000..d75ef09f --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0007-Allow-filtering-of-services.patch @@ -0,0 +1,236 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Julia Reynolds +Date: Tue, 7 Mar 2023 15:44:49 -0500 +Subject: [PATCH 07/10] Allow filtering of services + +Test: ServiceListingTest +Bug: 260570119 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ad19ca301191bc709b386bb10f4337cacd895b9e) +Merged-In: Ib4740ba401667de62fa1a33334c2c1fbee25b760 +Change-Id: Ib4740ba401667de62fa1a33334c2c1fbee25b760 +--- + .../applications/ServiceListing.java | 17 +++- + .../applications/ServiceListingTest.java | 98 ++++++++++++++++++- + 2 files changed, 111 insertions(+), 4 deletions(-) + +diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java +index bd9e760acfda..c8bcabff1094 100644 +--- a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java ++++ b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java +@@ -35,6 +35,7 @@ import android.util.Slog; + import java.util.ArrayList; + import java.util.HashSet; + import java.util.List; ++import java.util.function.Predicate; + + /** + * Class for managing services matching a given intent and requesting a given permission. +@@ -51,12 +52,13 @@ public class ServiceListing { + private final HashSet mEnabledServices = new HashSet<>(); + private final List mServices = new ArrayList<>(); + private final List mCallbacks = new ArrayList<>(); ++ private final Predicate mValidator; + + private boolean mListening; + + private ServiceListing(Context context, String tag, + String setting, String intentAction, String permission, String noun, +- boolean addDeviceLockedFlags) { ++ boolean addDeviceLockedFlags, Predicate validator) { + mContentResolver = context.getContentResolver(); + mContext = context; + mTag = tag; +@@ -65,6 +67,7 @@ public class ServiceListing { + mPermission = permission; + mNoun = noun; + mAddDeviceLockedFlags = addDeviceLockedFlags; ++ mValidator = validator; + } + + public void addCallback(Callback callback) { +@@ -137,7 +140,6 @@ public class ServiceListing { + final PackageManager pmWrapper = mContext.getPackageManager(); + List installedServices = pmWrapper.queryIntentServicesAsUser( + new Intent(mIntentAction), flags, user); +- + for (ResolveInfo resolveInfo : installedServices) { + ServiceInfo info = resolveInfo.serviceInfo; + +@@ -148,6 +150,9 @@ public class ServiceListing { + + mPermission); + continue; + } ++ if (mValidator != null && !mValidator.test(info)) { ++ continue; ++ } + mServices.add(info); + } + for (Callback callback : mCallbacks) { +@@ -194,6 +199,7 @@ public class ServiceListing { + private String mPermission; + private String mNoun; + private boolean mAddDeviceLockedFlags = false; ++ private Predicate mValidator; + + public Builder(Context context) { + mContext = context; +@@ -224,6 +230,11 @@ public class ServiceListing { + return this; + } + ++ public Builder setValidator(Predicate validator) { ++ mValidator = validator; ++ return this; ++ } ++ + /** + * Set to true to add support for both MATCH_DIRECT_BOOT_AWARE and + * MATCH_DIRECT_BOOT_UNAWARE flags when querying PackageManager. Required to get results +@@ -236,7 +247,7 @@ public class ServiceListing { + + public ServiceListing build() { + return new ServiceListing(mContext, mTag, mSetting, mIntentAction, mPermission, mNoun, +- mAddDeviceLockedFlags); ++ mAddDeviceLockedFlags, mValidator); + } + } + } +diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java +index f7fd25b9fb7d..7ff0988c494d 100644 +--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java ++++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java +@@ -18,20 +18,35 @@ package com.android.settingslib.applications; + + import static com.google.common.truth.Truth.assertThat; + ++import static org.mockito.ArgumentMatchers.any; ++import static org.mockito.ArgumentMatchers.anyInt; + import static org.mockito.ArgumentMatchers.anyList; + import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.spy; + import static org.mockito.Mockito.times; + import static org.mockito.Mockito.verify; ++import static org.mockito.Mockito.when; + + import android.content.ComponentName; ++import android.content.Context; ++import android.content.pm.PackageManager; ++import android.content.pm.ResolveInfo; ++import android.content.pm.ServiceInfo; + import android.provider.Settings; + ++import androidx.test.core.app.ApplicationProvider; ++ ++import com.google.common.collect.ImmutableList; ++ + import org.junit.Before; + import org.junit.Test; + import org.junit.runner.RunWith; ++import org.mockito.ArgumentCaptor; + import org.robolectric.RobolectricTestRunner; + import org.robolectric.RuntimeEnvironment; + ++import java.util.List; ++ + @RunWith(RobolectricTestRunner.class) + public class ServiceListingTest { + +@@ -39,16 +54,97 @@ public class ServiceListingTest { + private static final String TEST_INTENT = "com.example.intent"; + + private ServiceListing mServiceListing; ++ private Context mContext; ++ private PackageManager mPm; + + @Before + public void setUp() { +- mServiceListing = new ServiceListing.Builder(RuntimeEnvironment.application) ++ mPm = mock(PackageManager.class); ++ mContext = spy(ApplicationProvider.getApplicationContext()); ++ when(mContext.getPackageManager()).thenReturn(mPm); ++ ++ mServiceListing = new ServiceListing.Builder(mContext) ++ .setTag("testTag") ++ .setSetting(TEST_SETTING) ++ .setNoun("testNoun") ++ .setIntentAction(TEST_INTENT) ++ .setPermission("testPermission") ++ .build(); ++ } ++ ++ @Test ++ public void testValidator() { ++ ServiceInfo s1 = new ServiceInfo(); ++ s1.permission = "testPermission"; ++ s1.packageName = "pkg"; ++ ServiceInfo s2 = new ServiceInfo(); ++ s2.permission = "testPermission"; ++ s2.packageName = "pkg2"; ++ ResolveInfo r1 = new ResolveInfo(); ++ r1.serviceInfo = s1; ++ ResolveInfo r2 = new ResolveInfo(); ++ r2.serviceInfo = s2; ++ ++ when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn( ++ ImmutableList.of(r1, r2)); ++ ++ mServiceListing = new ServiceListing.Builder(mContext) ++ .setTag("testTag") ++ .setSetting(TEST_SETTING) ++ .setNoun("testNoun") ++ .setIntentAction(TEST_INTENT) ++ .setValidator(info -> { ++ if (info.packageName.equals("pkg")) { ++ return true; ++ } ++ return false; ++ }) ++ .setPermission("testPermission") ++ .build(); ++ ServiceListing.Callback callback = mock(ServiceListing.Callback.class); ++ mServiceListing.addCallback(callback); ++ mServiceListing.reload(); ++ ++ verify(mPm).queryIntentServicesAsUser(any(), anyInt(), anyInt()); ++ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); ++ verify(callback, times(1)).onServicesReloaded(captor.capture()); ++ ++ assertThat(captor.getValue().size()).isEqualTo(1); ++ assertThat(captor.getValue().get(0)).isEqualTo(s1); ++ } ++ ++ @Test ++ public void testNoValidator() { ++ ServiceInfo s1 = new ServiceInfo(); ++ s1.permission = "testPermission"; ++ s1.packageName = "pkg"; ++ ServiceInfo s2 = new ServiceInfo(); ++ s2.permission = "testPermission"; ++ s2.packageName = "pkg2"; ++ ResolveInfo r1 = new ResolveInfo(); ++ r1.serviceInfo = s1; ++ ResolveInfo r2 = new ResolveInfo(); ++ r2.serviceInfo = s2; ++ ++ when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn( ++ ImmutableList.of(r1, r2)); ++ ++ mServiceListing = new ServiceListing.Builder(mContext) + .setTag("testTag") + .setSetting(TEST_SETTING) + .setNoun("testNoun") + .setIntentAction(TEST_INTENT) + .setPermission("testPermission") + .build(); ++ ServiceListing.Callback callback = mock(ServiceListing.Callback.class); ++ mServiceListing.addCallback(callback); ++ mServiceListing.reload(); ++ ++ verify(mPm).queryIntentServicesAsUser(any(), anyInt(), anyInt()); ++ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); ++ verify(callback, times(1)).onServicesReloaded(captor.capture()); ++ ++ assertThat(captor.getValue().size()).isEqualTo(2); + } + + @Test diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0008-Enforce-DevicePolicyManager.setUserControlDisabledPa.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0008-Enforce-DevicePolicyManager.setUserControlDisabledPa.patch new file mode 100644 index 00000000..750e150b --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0008-Enforce-DevicePolicyManager.setUserControlDisabledPa.patch @@ -0,0 +1,252 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alex Johnston +Date: Wed, 8 Mar 2023 22:28:28 +0000 +Subject: [PATCH 08/10] Enforce + DevicePolicyManager.setUserControlDisabledPackages in AppStandbyController + +When deciding an app's standby bucket, check if the +app has its user control disabled by an IT admin. If so, +the app should be the exempted restricted bucket. + +Bug: 272042183 +Test: atest AppStandbyControllerTests +(cherry picked from commit 269fcb6873dee199dd8023831f882aafff1f6291) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:99b199d1139f50dbecba4f4bdc8066c6d0c28b5b) +Merged-In: I4279dc37f0e17aedb1c2a87468478248443a253e +Change-Id: I4279dc37f0e17aedb1c2a87468478248443a253e +--- + .../server/usage/AppStandbyInternal.java | 2 + + .../server/usage/AppStandbyController.java | 40 +++++++++++++++++++ + .../app/admin/DevicePolicyManager.java | 3 +- + .../app/usage/UsageStatsManagerInternal.java | 10 +++++ + .../DevicePolicyManagerService.java | 2 + + .../usage/AppStandbyControllerTests.java | 38 ++++++++++++++++++ + .../server/usage/UsageStatsService.java | 5 +++ + 7 files changed, 99 insertions(+), 1 deletion(-) + +diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +index 9b64edf53d8c..f50a90248030 100644 +--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java ++++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +@@ -225,6 +225,8 @@ public interface AppStandbyInternal { + + void setActiveAdminApps(Set adminPkgs, int userId); + ++ void setAdminProtectedPackages(Set packageNames, int userId); ++ + /** + * @return {@code true} if the given package is an active device admin app. + */ +diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +index a6f47d4e4908..b27ff411dd58 100644 +--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java ++++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +@@ -264,6 +264,10 @@ public class AppStandbyController + @GuardedBy("mActiveAdminApps") + private final SparseArray> mActiveAdminApps = new SparseArray<>(); + ++ /** List of admin protected packages. Can contain {@link android.os.UserHandle#USER_ALL}. */ ++ @GuardedBy("mAdminProtectedPackages") ++ private final SparseArray> mAdminProtectedPackages = new SparseArray<>(); ++ + /** + * Set of system apps that are headless (don't have any "front door" activities, enabled or + * disabled). Presence in this map indicates that the app is a headless system app. +@@ -1335,6 +1339,9 @@ public class AppStandbyController + synchronized (mActiveAdminApps) { + mActiveAdminApps.remove(userId); + } ++ synchronized (mAdminProtectedPackages) { ++ mAdminProtectedPackages.remove(userId); ++ } + } + } + +@@ -1424,6 +1431,10 @@ public class AppStandbyController + return STANDBY_BUCKET_EXEMPTED; + } + ++ if (isAdminProtectedPackages(packageName, userId)) { ++ return STANDBY_BUCKET_EXEMPTED; ++ } ++ + if (isActiveNetworkScorer(packageName)) { + return STANDBY_BUCKET_EXEMPTED; + } +@@ -1871,6 +1882,17 @@ public class AppStandbyController + } + } + ++ private boolean isAdminProtectedPackages(String packageName, int userId) { ++ synchronized (mAdminProtectedPackages) { ++ if (mAdminProtectedPackages.contains(UserHandle.USER_ALL) ++ && mAdminProtectedPackages.get(UserHandle.USER_ALL).contains(packageName)) { ++ return true; ++ } ++ return mAdminProtectedPackages.contains(userId) ++ && mAdminProtectedPackages.get(userId).contains(packageName); ++ } ++ } ++ + @Override + public void addActiveDeviceAdmin(String adminPkg, int userId) { + synchronized (mActiveAdminApps) { +@@ -1894,6 +1916,17 @@ public class AppStandbyController + } + } + ++ @Override ++ public void setAdminProtectedPackages(Set packageNames, int userId) { ++ synchronized (mAdminProtectedPackages) { ++ if (packageNames == null || packageNames.isEmpty()) { ++ mAdminProtectedPackages.remove(userId); ++ } else { ++ mAdminProtectedPackages.put(userId, packageNames); ++ } ++ } ++ } ++ + @Override + public void onAdminDataAvailable() { + mAdminDataAvailableLatch.countDown(); +@@ -1916,6 +1949,13 @@ public class AppStandbyController + } + } + ++ @VisibleForTesting ++ Set getAdminProtectedPackagesForTest(int userId) { ++ synchronized (mAdminProtectedPackages) { ++ return mAdminProtectedPackages.get(userId); ++ } ++ } ++ + /** + * Returns {@code true} if the supplied package is the device provisioning app. Otherwise, + * returns {@code false}. +diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java +index f563fdb28953..af42dd3dfc76 100644 +--- a/core/java/android/app/admin/DevicePolicyManager.java ++++ b/core/java/android/app/admin/DevicePolicyManager.java +@@ -14625,7 +14625,8 @@ public class DevicePolicyManager { + /** + * Called by a device owner or a profile owner to disable user control over apps. User will not + * be able to clear app data or force-stop packages. When called by a device owner, applies to +- * all users on the device. ++ * all users on the device. Packages with user control disabled are exempted from ++ * App Standby Buckets. + * + * @param admin which {@link DeviceAdminReceiver} this request is associated with + * @param packages The package names for the apps. +diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java +index a35aa7c74ee5..ee70e2ff50ce 100644 +--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java ++++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java +@@ -202,6 +202,16 @@ public abstract class UsageStatsManagerInternal { + */ + public abstract void setActiveAdminApps(Set adminApps, int userId); + ++ /** ++ * Called by DevicePolicyManagerService to inform about the protected packages for a user. ++ * User control will be disabled for protected packages. ++ * ++ * @param packageNames the set of protected packages for {@code userId}. ++ * @param userId the userId to which the protected packages belong. ++ */ ++ public abstract void setAdminProtectedPackages(@Nullable Set packageNames, ++ @UserIdInt int userId); ++ + /** + * Called by DevicePolicyManagerService during boot to inform that admin data is loaded and + * pushed to UsageStatsService. +diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +index 515d6dc9cab1..e95f827ff6f1 100644 +--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java ++++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +@@ -3202,6 +3202,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { + mInjector.binderWithCleanCallingIdentity(() -> + mInjector.getPackageManagerInternal().setOwnerProtectedPackages( + targetUserId, protectedPackages)); ++ mUsageStatsManagerInternal.setAdminProtectedPackages(new ArraySet(protectedPackages), ++ targetUserId); + } + + @Override +diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +index 308a4b67de24..e2db7584a2a6 100644 +--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java ++++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +@@ -158,6 +158,9 @@ public class AppStandbyControllerTests { + private static final String ADMIN_PKG2 = "com.android.admin2"; + private static final String ADMIN_PKG3 = "com.android.admin3"; + ++ private static final String ADMIN_PROTECTED_PKG = "com.android.admin.protected"; ++ private static final String ADMIN_PROTECTED_PKG2 = "com.android.admin.protected2"; ++ + private static final long MINUTE_MS = 60 * 1000; + private static final long HOUR_MS = 60 * MINUTE_MS; + private static final long DAY_MS = 24 * HOUR_MS; +@@ -1750,6 +1753,19 @@ public class AppStandbyControllerTests { + assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID); + } + ++ @Test ++ public void testSetAdminProtectedPackages() { ++ assertAdminProtectedPackagesForTest(USER_ID, (String[]) null); ++ assertAdminProtectedPackagesForTest(USER_ID2, (String[]) null); ++ ++ setAdminProtectedPackages(USER_ID, ADMIN_PROTECTED_PKG, ADMIN_PROTECTED_PKG2); ++ assertAdminProtectedPackagesForTest(USER_ID, ADMIN_PROTECTED_PKG, ADMIN_PROTECTED_PKG2); ++ assertAdminProtectedPackagesForTest(USER_ID2, (String[]) null); ++ ++ setAdminProtectedPackages(USER_ID, (String[]) null); ++ assertAdminProtectedPackagesForTest(USER_ID, (String[]) null); ++ } ++ + @Test + @FlakyTest(bugId = 185169504) + public void testUserInteraction_CrossProfile() throws Exception { +@@ -2144,6 +2160,28 @@ public class AppStandbyControllerTests { + mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId); + } + ++ private void setAdminProtectedPackages(int userId, String... packageNames) { ++ Set adminProtectedPackages = packageNames != null ? new ArraySet<>( ++ Arrays.asList(packageNames)) : null; ++ mController.setAdminProtectedPackages(adminProtectedPackages, userId); ++ } ++ ++ private void assertAdminProtectedPackagesForTest(int userId, String... packageNames) { ++ final Set actualAdminProtectedPackages = ++ mController.getAdminProtectedPackagesForTest(userId); ++ if (packageNames == null) { ++ if (actualAdminProtectedPackages != null && !actualAdminProtectedPackages.isEmpty()) { ++ fail("Admin protected packages should be null; " + getAdminAppsStr(userId, ++ actualAdminProtectedPackages)); ++ } ++ return; ++ } ++ assertEquals(packageNames.length, actualAdminProtectedPackages.size()); ++ for (String adminProtectedPackage : packageNames) { ++ assertTrue(actualAdminProtectedPackages.contains(adminProtectedPackage)); ++ } ++ } ++ + private void setAndAssertBucket(String pkg, int user, int bucket, int reason) throws Exception { + rearmLatch(pkg); + mController.setAppStandbyBucket(pkg, user, bucket, reason); +diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java +index ea40100227c4..71644d08e720 100644 +--- a/services/usage/java/com/android/server/usage/UsageStatsService.java ++++ b/services/usage/java/com/android/server/usage/UsageStatsService.java +@@ -3086,6 +3086,11 @@ public class UsageStatsService extends SystemService implements + mAppStandby.setActiveAdminApps(packageNames, userId); + } + ++ @Override ++ public void setAdminProtectedPackages(Set packageNames, int userId) { ++ mAppStandby.setAdminProtectedPackages(packageNames, userId); ++ } ++ + @Override + public void onAdminDataAvailable() { + mAppStandby.onAdminDataAvailable(); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0009-Add-BubbleMetadata-detection-to-block-FSI.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0009-Add-BubbleMetadata-detection-to-block-FSI.patch new file mode 100644 index 00000000..72c50a4c --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0009-Add-BubbleMetadata-detection-to-block-FSI.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeff DeCew +Date: Fri, 24 Mar 2023 16:15:24 +0000 +Subject: [PATCH 09/10] Add BubbleMetadata detection to block FSI + +Bug: 274759612 +Test: atest NotificationInterruptStateProviderImplTest +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e65f0c9643b52e2656ac2da21dfd0fb7395de04c) +Merged-In: I40e1aa6377b8a60d91cb2f4189df1e9a4a4578a2 +Change-Id: I40e1aa6377b8a60d91cb2f4189df1e9a4a4578a2 +--- + ...otificationInterruptStateProviderImpl.java | 11 ++++++++++ + ...icationInterruptStateProviderImplTest.java | 21 +++++++++++++++++++ + 2 files changed, 32 insertions(+) + +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +index d9dacfd0e27c..5956c5473843 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +@@ -266,6 +266,17 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter + suppressedByDND); + } + ++ // If the notification has suppressive BubbleMetadata, block FSI and warn. ++ Notification.BubbleMetadata bubbleMetadata = sbn.getNotification().getBubbleMetadata(); ++ if (bubbleMetadata != null && bubbleMetadata.isNotificationSuppressed()) { ++ // b/274759612: Detect and report an event when a notification has both an FSI and a ++ // suppressive BubbleMetadata, and now correctly block the FSI from firing. ++ final int uid = entry.getSbn().getUid(); ++ android.util.EventLog.writeEvent(0x534e4554, "274759612", uid, "bubbleMetadata"); ++ mLogger.logNoFullscreenWarning(entry, "BubbleMetadata may prevent HUN"); ++ return FullScreenIntentDecision.NO_FULL_SCREEN_INTENT; ++ } ++ + // If the screen is off, then launch the FullScreenIntent + if (!mPowerManager.isInteractive()) { + return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE, +diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +index 601771d64046..d2a27b30f36f 100644 +--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java ++++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +@@ -633,9 +633,30 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { + testShouldFullScreen_notInteractive(); + } + ++ ++ @Test ++ public void testShouldNotFullScreen_isSuppressedByBubbleMetadata() throws RemoteException { ++ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); ++ Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") ++ .setSuppressNotification(true).build(); ++ entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); ++ when(mPowerManager.isInteractive()).thenReturn(false); ++ when(mDreamManager.isDreaming()).thenReturn(true); ++ when(mStatusBarStateController.getState()).thenReturn(KEYGUARD); ++ ++ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) ++ .isFalse(); ++ verify(mLogger, never()).logNoFullscreen(any(), any()); ++ verify(mLogger).logNoFullscreenWarning(entry, "GroupAlertBehavior will prevent HUN"); ++ verify(mLogger, never()).logFullscreen(any(), any()); ++ } ++ + @Test + public void testShouldFullScreen_notInteractive() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); ++ Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") ++ .setSuppressNotification(false).build(); ++ entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); + when(mPowerManager.isInteractive()).thenReturn(false); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0010-Fix-issues-with-setRemotePlaybackInfo.patch b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0010-Fix-issues-with-setRemotePlaybackInfo.patch new file mode 100644 index 00000000..f0307671 --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/ASB-2023-06/0010-Fix-issues-with-setRemotePlaybackInfo.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Beth Thibodeau +Date: Tue, 14 Mar 2023 22:43:54 -0500 +Subject: [PATCH 10/10] Fix issues with setRemotePlaybackInfo + +- Check permissions when building DecoratedMediaCustomViewStyle if it includes +the extras from this API + +- Send device intent as a regular PendingIntent if it can open over lockscreen + +Bug: 271846393 +Test: atest NotificationManagerServiceTest MediaControlPanelTest +Test: manual using test app +(cherry picked from commit 335a3cb7b413fc178f0b190491b870b3327bd7b0) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3c3056c16970d561175192e7a8909a9de784ae54) +Merged-In: Ida43bb4acc34d666e354c16c4344d5c5eb6b333b +Change-Id: Ida43bb4acc34d666e354c16c4344d5c5eb6b333b +--- + .../media/controls/ui/MediaControlPanel.java | 11 ++++-- + .../NotificationManagerService.java | 3 +- + .../NotificationManagerServiceTest.java | 37 +++++++++++++++++++ + 3 files changed, 46 insertions(+), 5 deletions(-) + +diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +index 5cdfe73ad3aa..e9d8029a1aad 100644 +--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java ++++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +@@ -620,12 +620,15 @@ public class MediaControlPanel { + } else { + mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId); + if (device.getIntent() != null) { +- if (device.getIntent().isActivity()) { +- mActivityStarter.startActivity( +- device.getIntent().getIntent(), true); ++ PendingIntent deviceIntent = device.getIntent(); ++ boolean showOverLockscreen = mKeyguardStateController.isShowing() ++ && mActivityIntentHelper.wouldPendingShowOverLockscreen( ++ deviceIntent, mLockscreenUserManager.getCurrentUserId()); ++ if (device.getIntent().isActivity() && !showOverLockscreen) { ++ mActivityStarter.postStartActivityDismissingKeyguard(deviceIntent); + } else { + try { +- device.getIntent().send(); ++ deviceIntent.send(); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Device pending intent was canceled"); + } +diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java +index d16f856376bf..3999c117d40d 100755 +--- a/services/core/java/com/android/server/notification/NotificationManagerService.java ++++ b/services/core/java/com/android/server/notification/NotificationManagerService.java +@@ -6747,7 +6747,8 @@ public class NotificationManagerService extends SystemService { + } + + // Ensure MediaStyle has correct permissions for remote device extras +- if (notification.isStyle(Notification.MediaStyle.class)) { ++ if (notification.isStyle(Notification.MediaStyle.class) ++ || notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) { + int hasMediaContentControlPermission = mPackageManager.checkPermission( + android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId); + if (hasMediaContentControlPermission != PERMISSION_GRANTED) { +diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +index 3f3b052931ab..9f0a0b2f7628 100755 +--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java ++++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +@@ -4245,6 +4245,43 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + + assertFalse(posted.getNotification().extras + .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); ++ assertFalse(posted.getNotification().extras ++ .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); ++ assertFalse(posted.getNotification().extras ++ .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); ++ } ++ ++ @Test ++ public void testCustomMediaStyleRemote_noPermission() throws RemoteException { ++ String deviceName = "device"; ++ when(mPackageManager.checkPermission( ++ eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt())) ++ .thenReturn(PERMISSION_DENIED); ++ Notification.DecoratedMediaCustomViewStyle style = ++ new Notification.DecoratedMediaCustomViewStyle(); ++ style.setRemotePlaybackInfo(deviceName, 0, null); ++ Notification.Builder nb = new Notification.Builder(mContext, ++ mTestNotificationChannel.getId()) ++ .setStyle(style); ++ ++ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, ++ "testCustomMediaStyleRemoteNoPermission", mUid, 0, ++ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); ++ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); ++ ++ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), ++ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); ++ waitForIdle(); ++ ++ NotificationRecord posted = mService.findNotificationLocked( ++ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); ++ ++ assertFalse(posted.getNotification().extras ++ .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); ++ assertFalse(posted.getNotification().extras ++ .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); ++ assertFalse(posted.getNotification().extras ++ .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); + } + + @Test diff --git a/Patches/LineageOS-20.0/android_packages_apps_LineageParts/0001-Remove_Analytics.patch b/Patches/LineageOS-20.0/android_packages_apps_LineageParts/0001-Remove_Analytics.patch index a3cf3360..a6afb192 100644 --- a/Patches/LineageOS-20.0/android_packages_apps_LineageParts/0001-Remove_Analytics.patch +++ b/Patches/LineageOS-20.0/android_packages_apps_LineageParts/0001-Remove_Analytics.patch @@ -14,10 +14,10 @@ Change-Id: Ic01c97d6ceac8d324609763973639b41b4581a76 6 files changed, 59 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml -index 4f99b4c..d7a6c12 100644 +index b42bdc3..06fe237 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml -@@ -240,31 +240,6 @@ +@@ -251,31 +251,6 @@ android:resource="@string/summary_empty" /> @@ -76,10 +76,10 @@ index a3ee437..c4532c5 100644 The array should be sorted in the same order as the touchscreen gestures advertised by the device's LineageHW impl. --> diff --git a/res/values/strings.xml b/res/values/strings.xml -index f7cf730..2f6c4d3 100644 +index 4c3a92d..9db0d06 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml -@@ -533,28 +533,6 @@ +@@ -550,28 +550,6 @@ Total commits: %2$s

Last update: %3$s]]>
@@ -109,10 +109,10 @@ index f7cf730..2f6c4d3 100644 Auto-rotate screen Rotation settings diff --git a/res/xml/parts_catalog.xml b/res/xml/parts_catalog.xml -index 9711b21..414640e 100644 +index 691ce47..ea2a07b 100644 --- a/res/xml/parts_catalog.xml +++ b/res/xml/parts_catalog.xml -@@ -70,11 +70,6 @@ +@@ -75,11 +75,6 @@ android:fragment="org.lineageos.lineageparts.statusbar.StatusBarSettings" lineage:xmlRes="@xml/status_bar_settings" /> diff --git a/Patches/LineageOS-20.0/android_packages_apps_Settings/0004-Private_DNS.patch b/Patches/LineageOS-20.0/android_packages_apps_Settings/0004-Private_DNS.patch index 565e8324..f10669a8 100644 --- a/Patches/LineageOS-20.0/android_packages_apps_Settings/0004-Private_DNS.patch +++ b/Patches/LineageOS-20.0/android_packages_apps_Settings/0004-Private_DNS.patch @@ -368,7 +368,7 @@ index 5c7c54eda3..c321b6cbaf 100644 mMode = PRIVATE_DNS_MODE_OPPORTUNISTIC; } else if (checkedId == R.id.private_dns_mode_provider) { diff --git a/src/com/android/settings/network/PrivateDnsPreferenceController.java b/src/com/android/settings/network/PrivateDnsPreferenceController.java -index ed6f9ed955..4258e6c039 100644 +index 42974be8e0..8ff447f05f 100644 --- a/src/com/android/settings/network/PrivateDnsPreferenceController.java +++ b/src/com/android/settings/network/PrivateDnsPreferenceController.java @@ -133,9 +133,41 @@ public class PrivateDnsPreferenceController extends BasePreferenceController diff --git a/Patches/LineageOS-20.0/android_packages_apps_Settings/0015-SUPL_Toggle.patch b/Patches/LineageOS-20.0/android_packages_apps_Settings/0015-SUPL_Toggle.patch index d3fa2305..5d5928fc 100644 --- a/Patches/LineageOS-20.0/android_packages_apps_Settings/0015-SUPL_Toggle.patch +++ b/Patches/LineageOS-20.0/android_packages_apps_Settings/0015-SUPL_Toggle.patch @@ -11,7 +11,7 @@ Subject: [PATCH] add a toggle for forcibly disabling SUPL create mode 100644 src/com/android/settings/location/ForceDisableSuplPrefController.java diff --git a/res/values/strings.xml b/res/values/strings.xml -index e68a5595ab..553038c2b4 100644 +index e68a5595ab..047a675bdf 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -14518,4 +14518,6 @@ diff --git a/Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0001-Convert-argument-to-intent-in-AddAccountSettings.patch b/Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0001-Convert-argument-to-intent-in-AddAccountSettings.patch new file mode 100644 index 00000000..5d8e46ce --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0001-Convert-argument-to-intent-in-AddAccountSettings.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dmitry Dementyev +Date: Tue, 7 Mar 2023 10:36:41 -0800 +Subject: [PATCH 1/2] Convert argument to intent in AddAccountSettings. + +Bug: 265798353 +Test: manual +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c7e8052b527434ed8660e3babdab718f7f3cd7da) +Merged-In: I0051e5d5fc9fd3691504cb5fbb959f701e0bce6a +Change-Id: I0051e5d5fc9fd3691504cb5fbb959f701e0bce6a +--- + src/com/android/settings/accounts/AddAccountSettings.java | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/com/android/settings/accounts/AddAccountSettings.java b/src/com/android/settings/accounts/AddAccountSettings.java +index 81db4df329..85e942b199 100644 +--- a/src/com/android/settings/accounts/AddAccountSettings.java ++++ b/src/com/android/settings/accounts/AddAccountSettings.java +@@ -103,7 +103,8 @@ public class AddAccountSettings extends Activity { + intent.putExtras(addAccountOptions) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); +- startActivityForResultAsUser(intent, ADD_ACCOUNT_REQUEST, mUserHandle); ++ startActivityForResultAsUser( ++ new Intent(intent), ADD_ACCOUNT_REQUEST, mUserHandle); + } else { + setResult(RESULT_OK); + if (mPendingIntent != null) { diff --git a/Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0002-Don-t-show-NLSes-with-excessively-long-component-nam.patch b/Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0002-Don-t-show-NLSes-with-excessively-long-component-nam.patch new file mode 100644 index 00000000..ff4614ac --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_apps_Settings/ASB-2023-06/0002-Don-t-show-NLSes-with-excessively-long-component-nam.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Julia Reynolds +Date: Tue, 7 Mar 2023 15:44:29 -0500 +Subject: [PATCH 2/2] Don't show NLSes with excessively long component names + +Test: install test app with long CN +Test: ServiceListingTest +Bug: 260570119 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:793257967f165970f8cb0f4cebddab9dcd5d8353) +Merged-In: I3ffd02f6cf6bf282e7fc264fd070ed3add4d8571 +Change-Id: I3ffd02f6cf6bf282e7fc264fd070ed3add4d8571 +--- + .../settings/notification/NotificationAccessSettings.java | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java +index 4ec9ccd814..56d3f0e445 100644 +--- a/src/com/android/settings/notification/NotificationAccessSettings.java ++++ b/src/com/android/settings/notification/NotificationAccessSettings.java +@@ -65,6 +65,7 @@ public class NotificationAccessSettings extends EmptyTextSettings { + private static final String TAG = "NotifAccessSettings"; + private static final String ALLOWED_KEY = "allowed"; + private static final String NOT_ALLOWED_KEY = "not_allowed"; ++ private static final int MAX_CN_LENGTH = 500; + + private static final ManagedServiceSettings.Config CONFIG = + new ManagedServiceSettings.Config.Builder() +@@ -101,6 +102,12 @@ public class NotificationAccessSettings extends EmptyTextSettings { + .setNoun(CONFIG.noun) + .setSetting(CONFIG.setting) + .setTag(CONFIG.tag) ++ .setValidator(info -> { ++ if (info.getComponentName().flattenToString().length() > MAX_CN_LENGTH) { ++ return false; ++ } ++ return true; ++ }) + .build(); + mServiceListing.addCallback(this::updateList); + diff --git a/Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0001-Update-Traceur-to-check-admin-user-status.patch b/Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0001-Update-Traceur-to-check-admin-user-status.patch new file mode 100644 index 00000000..0f1db518 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0001-Update-Traceur-to-check-admin-user-status.patch @@ -0,0 +1,290 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kevin Jeon +Date: Fri, 17 Feb 2023 20:17:54 +0000 +Subject: [PATCH 1/2] Update Traceur to check admin user status + +This change updates Traceur to check for admin user privileges wherever +a developer options check occurs. This is intended to address the case +in which developer options (a global setting not differentiated on +current user privileges) being enabled would allow guest users to open +Traceur through a 3P app and view its trace files. This would previously +be possible even when ADB debugging was disabled by the admin user. + +Traceur now listens for user changes so that its document root +(containing traces) is enabled/disabled based on the new user's admin +status. + +Test: Using ABTD, apply this on tm-dev+tm-qpr-dev, then check that: + - There are no merge conflicts + - CtsIntentSignatureTestCases passes (b/270791503) + - TraceurUiTests passes + Build+flash a local device on tm-dev+tm-qpr-dev and check that: + - Traceur cannot be opened through 'am start' on a guest account + - Opening Files on a guest account no longer shows a System Traces + folder (even if Traceur's onCreate is somehow called) + - System tracing no longer appears in settings for guests +Bug: 262243665 +Bug: 262244249 +Ignore-AOSP-First: Internal-first security fix +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:35b3591dc4e50d51d0d7b54eef6cc0c5c6260898) +Merged-In: I1c0c8c9588554378ae39a1a69a35ff44052b93e0 +Change-Id: I1c0c8c9588554378ae39a1a69a35ff44052b93e0 +--- + AndroidManifest.xml | 4 +++ + src/com/android/traceur/MainActivity.java | 5 +++- + src/com/android/traceur/MainTvActivity.java | 5 +++- + src/com/android/traceur/Receiver.java | 29 ++++++++++++++----- + src/com/android/traceur/SearchProvider.java | 7 +++-- + src/com/android/traceur/StopTraceService.java | 7 ++++- + src/com/android/traceur/StorageProvider.java | 8 +++-- + src/com/android/traceur/TraceService.java | 7 ++++- + 8 files changed, 55 insertions(+), 17 deletions(-) + +diff --git a/AndroidManifest.xml b/AndroidManifest.xml +index 6a2544e..f38a71d 100644 +--- a/AndroidManifest.xml ++++ b/AndroidManifest.xml +@@ -47,6 +47,9 @@ + + + ++ ++ ++ + + +@@ -113,6 +116,7 @@ + android:exported="true"> + + ++ + + + +diff --git a/src/com/android/traceur/MainActivity.java b/src/com/android/traceur/MainActivity.java +index 0380dcd..3342652 100644 +--- a/src/com/android/traceur/MainActivity.java ++++ b/src/com/android/traceur/MainActivity.java +@@ -17,6 +17,7 @@ package com.android.traceur; + + import android.app.Activity; + import android.os.Bundle; ++import android.os.UserManager; + import android.provider.Settings; + + import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; +@@ -34,8 +35,10 @@ public class MainActivity extends CollapsingToolbarBaseActivity { + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getApplicationContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; ++ boolean isAdminUser = getApplicationContext() ++ .getSystemService(UserManager.class).isAdminUser(); + +- if (!developerOptionsIsEnabled) { ++ if (!developerOptionsIsEnabled || !isAdminUser) { + finish(); + } + } +diff --git a/src/com/android/traceur/MainTvActivity.java b/src/com/android/traceur/MainTvActivity.java +index 91f67c4..7459b7a 100644 +--- a/src/com/android/traceur/MainTvActivity.java ++++ b/src/com/android/traceur/MainTvActivity.java +@@ -17,6 +17,7 @@ package com.android.traceur; + + import android.app.Activity; + import android.os.Bundle; ++import android.os.UserManager; + import android.provider.Settings; + + public class MainTvActivity extends Activity { +@@ -32,8 +33,10 @@ public class MainTvActivity extends Activity { + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getApplicationContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; ++ boolean isAdminUser = getApplicationContext() ++ .getSystemService(UserManager.class).isAdminUser(); + +- if (!developerOptionsIsEnabled) { ++ if (!developerOptionsIsEnabled || !isAdminUser) { + finish(); + } + } +diff --git a/src/com/android/traceur/Receiver.java b/src/com/android/traceur/Receiver.java +index 0ed5d5d..acadb9a 100644 +--- a/src/com/android/traceur/Receiver.java ++++ b/src/com/android/traceur/Receiver.java +@@ -32,6 +32,7 @@ import android.os.Build; + import android.os.Handler; + import android.os.RemoteException; + import android.os.ServiceManager; ++import android.os.UserManager; + import android.preference.PreferenceManager; + import android.provider.Settings; + import android.text.TextUtils; +@@ -85,6 +86,12 @@ public class Receiver extends BroadcastReceiver { + // We know that Perfetto won't be tracing already at boot, so pass the + // tracingIsOff argument to avoid the Perfetto check. + updateTracing(context, /* assumeTracingIsOff= */ true); ++ } else if (Intent.ACTION_USER_FOREGROUND.equals(intent.getAction())) { ++ boolean developerOptionsEnabled = (1 == ++ Settings.Global.getInt(context.getContentResolver(), ++ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0)); ++ boolean isAdminUser = context.getSystemService(UserManager.class).isAdminUser(); ++ updateStorageProvider(context, developerOptionsEnabled && isAdminUser); + } else if (STOP_ACTION.equals(intent.getAction())) { + prefs.edit().putBoolean( + context.getString(R.string.pref_key_tracing_on), false).commit(); +@@ -213,14 +220,9 @@ public class Receiver extends BroadcastReceiver { + boolean developerOptionsEnabled = (1 == + Settings.Global.getInt(context.getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0)); +- +- ComponentName name = new ComponentName(context, +- StorageProvider.class); +- context.getPackageManager().setComponentEnabledSetting(name, +- developerOptionsEnabled +- ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED +- : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, +- PackageManager.DONT_KILL_APP); ++ boolean isAdminUser = context.getSystemService(UserManager.class) ++ .isAdminUser(); ++ updateStorageProvider(context, developerOptionsEnabled && isAdminUser); + + if (!developerOptionsEnabled) { + SharedPreferences prefs = +@@ -243,6 +245,17 @@ public class Receiver extends BroadcastReceiver { + } + } + ++ // Enables/disables the System Traces storage component. enableProvider should be true iff ++ // developer options are enabled and the current user is an admin user. ++ static void updateStorageProvider(Context context, boolean enableProvider) { ++ ComponentName name = new ComponentName(context, StorageProvider.class); ++ context.getPackageManager().setComponentEnabledSetting(name, ++ enableProvider ++ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED ++ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, ++ PackageManager.DONT_KILL_APP); ++ } ++ + private static void postCategoryNotification(Context context, SharedPreferences prefs) { + Intent sendIntent = new Intent(context, MainActivity.class); + +diff --git a/src/com/android/traceur/SearchProvider.java b/src/com/android/traceur/SearchProvider.java +index 9586bdb..0d76e9f 100644 +--- a/src/com/android/traceur/SearchProvider.java ++++ b/src/com/android/traceur/SearchProvider.java +@@ -30,6 +30,7 @@ import android.content.Context; + import android.content.Intent; + import android.database.Cursor; + import android.database.MatrixCursor; ++import android.os.UserManager; + import android.provider.SearchIndexablesProvider; + import android.provider.Settings; + +@@ -68,9 +69,11 @@ public class SearchProvider extends SearchIndexablesProvider { + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; ++ boolean isAdminUser = getContext().getSystemService(UserManager.class).isAdminUser(); + +- // If developer options is not enabled, System Tracing shouldn't be searchable. +- if (!developerOptionsIsEnabled) { ++ // System Tracing shouldn't be searchable if developer options are not enabled or if the ++ // user is not an admin. ++ if (!developerOptionsIsEnabled || !isAdminUser) { + MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS); + Object[] row = new Object[] {getContext().getString(R.string.system_tracing)}; + cursor.addRow(row); +diff --git a/src/com/android/traceur/StopTraceService.java b/src/com/android/traceur/StopTraceService.java +index 20c5f6e..b0c941b 100644 +--- a/src/com/android/traceur/StopTraceService.java ++++ b/src/com/android/traceur/StopTraceService.java +@@ -20,6 +20,7 @@ package com.android.traceur; + import android.content.Context; + import android.content.Intent; + import android.content.SharedPreferences; ++import android.os.UserManager; + import android.preference.PreferenceManager; + import android.provider.Settings; + import android.util.EventLog; +@@ -40,7 +41,7 @@ public class StopTraceService extends TraceService { + @Override + public void onHandleIntent(Intent intent) { + Context context = getApplicationContext(); +- // Checks that developer options are enabled before continuing. ++ // Checks that developer options are enabled and the user is an admin before continuing. + boolean developerOptionsEnabled = + Settings.Global.getInt(context.getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; +@@ -49,6 +50,10 @@ public class StopTraceService extends TraceService { + EventLog.writeEvent(0x534e4554, "204992293", -1, ""); + return; + } ++ boolean isAdminUser = context.getSystemService(UserManager.class).isAdminUser(); ++ if (!isAdminUser) { ++ return; ++ } + // Ensures that only intents that pertain to stopping a trace and need to be accessed from + // outside Traceur are passed to TraceService through StopTraceService. + String intentAction = intent.getAction(); +diff --git a/src/com/android/traceur/StorageProvider.java b/src/com/android/traceur/StorageProvider.java +index 3df07d5..a2a6c3a 100644 +--- a/src/com/android/traceur/StorageProvider.java ++++ b/src/com/android/traceur/StorageProvider.java +@@ -22,6 +22,7 @@ import android.os.Bundle; + import android.os.FileUtils; + import android.os.CancellationSignal; + import android.os.ParcelFileDescriptor; ++import android.os.UserManager; + import android.provider.DocumentsContract; + import android.provider.DocumentsContract.Document; + import android.provider.DocumentsContract.Root; +@@ -75,10 +76,11 @@ public class StorageProvider extends FileSystemProvider{ + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; ++ boolean isAdminUser = getContext().getSystemService(UserManager.class).isAdminUser(); + +- // If developer options is not enabled, return an empty root cursor. +- // This removes the provider from the list entirely. +- if (!developerOptionsIsEnabled) { ++ // If developer options is not enabled or the user is not an admin, return an empty root ++ // cursor. This removes the provider from the list entirely. ++ if (!developerOptionsIsEnabled || !isAdminUser) { + return null; + } + +diff --git a/src/com/android/traceur/TraceService.java b/src/com/android/traceur/TraceService.java +index 96e76a8..0039f6f 100644 +--- a/src/com/android/traceur/TraceService.java ++++ b/src/com/android/traceur/TraceService.java +@@ -26,6 +26,7 @@ import android.content.Context; + import android.content.Intent; + import android.content.SharedPreferences; + import android.content.pm.PackageManager; ++import android.os.UserManager; + import android.preference.PreferenceManager; + import android.provider.Settings; + import android.text.format.DateUtils; +@@ -108,7 +109,7 @@ public class TraceService extends IntentService { + @Override + public void onHandleIntent(Intent intent) { + Context context = getApplicationContext(); +- // Checks that developer options are enabled before continuing. ++ // Checks that developer options are enabled and the user is an admin before continuing. + boolean developerOptionsEnabled = + Settings.Global.getInt(context.getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; +@@ -117,6 +118,10 @@ public class TraceService extends IntentService { + EventLog.writeEvent(0x534e4554, "204992293", -1, ""); + return; + } ++ boolean isAdminUser = context.getSystemService(UserManager.class).isAdminUser(); ++ if (!isAdminUser) { ++ return; ++ } + + if (intent.getAction().equals(INTENT_ACTION_START_TRACING)) { + startTracingInternal(intent.getStringArrayListExtra(INTENT_EXTRA_TAGS), diff --git a/Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0002-Add-DISALLOW_DEBUGGING_FEATURES-check.patch b/Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0002-Add-DISALLOW_DEBUGGING_FEATURES-check.patch new file mode 100644 index 00000000..1ee476f0 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_apps_Traceur/ASB-2023-06/0002-Add-DISALLOW_DEBUGGING_FEATURES-check.patch @@ -0,0 +1,183 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kevin Jeon +Date: Wed, 29 Mar 2023 16:38:23 -0400 +Subject: [PATCH 2/2] Add DISALLOW_DEBUGGING_FEATURES check + +This change adds a check for the DISALLOW_DEBUGGING_FEATURES restriction +wherever a developer options or admin-privileges check exists. + +Test: Apply this change to the relevant branches and verify that Traceur + cannot be opened through the researcher-provided APK. +Bug: 270050064 +Bug: 270050191 +Ignore-AOSP-First: Internal-first security fix. +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:44480ce656dfa33a63bda978b4067bb4e67ee312) +Merged-In: I95d308f6e73a19e489f5eb09558275ca6fb3c4aa +Change-Id: I95d308f6e73a19e489f5eb09558275ca6fb3c4aa +--- + src/com/android/traceur/MainActivity.java | 10 +++++++--- + src/com/android/traceur/MainTvActivity.java | 10 +++++++--- + src/com/android/traceur/Receiver.java | 17 ++++++++++++----- + src/com/android/traceur/SearchProvider.java | 7 +++++-- + src/com/android/traceur/StopTraceService.java | 7 +++++-- + src/com/android/traceur/StorageProvider.java | 7 +++++-- + src/com/android/traceur/TraceService.java | 7 +++++-- + 7 files changed, 46 insertions(+), 19 deletions(-) + +diff --git a/src/com/android/traceur/MainActivity.java b/src/com/android/traceur/MainActivity.java +index 3342652..2d48923 100644 +--- a/src/com/android/traceur/MainActivity.java ++++ b/src/com/android/traceur/MainActivity.java +@@ -35,10 +35,14 @@ public class MainActivity extends CollapsingToolbarBaseActivity { + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getApplicationContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; +- boolean isAdminUser = getApplicationContext() +- .getSystemService(UserManager.class).isAdminUser(); + +- if (!developerOptionsIsEnabled || !isAdminUser) { ++ UserManager userManager = getApplicationContext() ++ .getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); ++ ++ if (!developerOptionsIsEnabled || !isAdminUser || debuggingDisallowed) { + finish(); + } + } +diff --git a/src/com/android/traceur/MainTvActivity.java b/src/com/android/traceur/MainTvActivity.java +index 7459b7a..de8c2bd 100644 +--- a/src/com/android/traceur/MainTvActivity.java ++++ b/src/com/android/traceur/MainTvActivity.java +@@ -33,10 +33,14 @@ public class MainTvActivity extends Activity { + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getApplicationContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; +- boolean isAdminUser = getApplicationContext() +- .getSystemService(UserManager.class).isAdminUser(); + +- if (!developerOptionsIsEnabled || !isAdminUser) { ++ UserManager userManager = getApplicationContext() ++ .getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); ++ ++ if (!developerOptionsIsEnabled || !isAdminUser || debuggingDisallowed) { + finish(); + } + } +diff --git a/src/com/android/traceur/Receiver.java b/src/com/android/traceur/Receiver.java +index acadb9a..f3c2ae3 100644 +--- a/src/com/android/traceur/Receiver.java ++++ b/src/com/android/traceur/Receiver.java +@@ -90,8 +90,12 @@ public class Receiver extends BroadcastReceiver { + boolean developerOptionsEnabled = (1 == + Settings.Global.getInt(context.getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0)); +- boolean isAdminUser = context.getSystemService(UserManager.class).isAdminUser(); +- updateStorageProvider(context, developerOptionsEnabled && isAdminUser); ++ UserManager userManager = context.getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); ++ updateStorageProvider(context, ++ developerOptionsEnabled && isAdminUser && !debuggingDisallowed); + } else if (STOP_ACTION.equals(intent.getAction())) { + prefs.edit().putBoolean( + context.getString(R.string.pref_key_tracing_on), false).commit(); +@@ -220,9 +224,12 @@ public class Receiver extends BroadcastReceiver { + boolean developerOptionsEnabled = (1 == + Settings.Global.getInt(context.getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0)); +- boolean isAdminUser = context.getSystemService(UserManager.class) +- .isAdminUser(); +- updateStorageProvider(context, developerOptionsEnabled && isAdminUser); ++ UserManager userManager = context.getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); ++ updateStorageProvider(context, ++ developerOptionsEnabled && isAdminUser && !debuggingDisallowed); + + if (!developerOptionsEnabled) { + SharedPreferences prefs = +diff --git a/src/com/android/traceur/SearchProvider.java b/src/com/android/traceur/SearchProvider.java +index 0d76e9f..8a20331 100644 +--- a/src/com/android/traceur/SearchProvider.java ++++ b/src/com/android/traceur/SearchProvider.java +@@ -69,11 +69,14 @@ public class SearchProvider extends SearchIndexablesProvider { + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; +- boolean isAdminUser = getContext().getSystemService(UserManager.class).isAdminUser(); ++ UserManager userManager = getContext().getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); + + // System Tracing shouldn't be searchable if developer options are not enabled or if the + // user is not an admin. +- if (!developerOptionsIsEnabled || !isAdminUser) { ++ if (!developerOptionsIsEnabled || !isAdminUser || debuggingDisallowed) { + MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS); + Object[] row = new Object[] {getContext().getString(R.string.system_tracing)}; + cursor.addRow(row); +diff --git a/src/com/android/traceur/StopTraceService.java b/src/com/android/traceur/StopTraceService.java +index b0c941b..0e754ac 100644 +--- a/src/com/android/traceur/StopTraceService.java ++++ b/src/com/android/traceur/StopTraceService.java +@@ -50,8 +50,11 @@ public class StopTraceService extends TraceService { + EventLog.writeEvent(0x534e4554, "204992293", -1, ""); + return; + } +- boolean isAdminUser = context.getSystemService(UserManager.class).isAdminUser(); +- if (!isAdminUser) { ++ UserManager userManager = context.getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); ++ if (!isAdminUser || debuggingDisallowed) { + return; + } + // Ensures that only intents that pertain to stopping a trace and need to be accessed from +diff --git a/src/com/android/traceur/StorageProvider.java b/src/com/android/traceur/StorageProvider.java +index a2a6c3a..0044a81 100644 +--- a/src/com/android/traceur/StorageProvider.java ++++ b/src/com/android/traceur/StorageProvider.java +@@ -76,11 +76,14 @@ public class StorageProvider extends FileSystemProvider{ + boolean developerOptionsIsEnabled = + Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; +- boolean isAdminUser = getContext().getSystemService(UserManager.class).isAdminUser(); ++ UserManager userManager = getContext().getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); + + // If developer options is not enabled or the user is not an admin, return an empty root + // cursor. This removes the provider from the list entirely. +- if (!developerOptionsIsEnabled || !isAdminUser) { ++ if (!developerOptionsIsEnabled || !isAdminUser || debuggingDisallowed) { + return null; + } + +diff --git a/src/com/android/traceur/TraceService.java b/src/com/android/traceur/TraceService.java +index 0039f6f..9b6f69d 100644 +--- a/src/com/android/traceur/TraceService.java ++++ b/src/com/android/traceur/TraceService.java +@@ -118,8 +118,11 @@ public class TraceService extends IntentService { + EventLog.writeEvent(0x534e4554, "204992293", -1, ""); + return; + } +- boolean isAdminUser = context.getSystemService(UserManager.class).isAdminUser(); +- if (!isAdminUser) { ++ UserManager userManager = context.getSystemService(UserManager.class); ++ boolean isAdminUser = userManager.isAdminUser(); ++ boolean debuggingDisallowed = userManager.hasUserRestriction( ++ UserManager.DISALLOW_DEBUGGING_FEATURES); ++ if (!isAdminUser || debuggingDisallowed) { + return; + } + diff --git a/Patches/LineageOS-20.0/android_packages_apps_Updater/0001-Server.patch b/Patches/LineageOS-20.0/android_packages_apps_Updater/0001-Server.patch index a7e881c8..78a4cb1a 100644 --- a/Patches/LineageOS-20.0/android_packages_apps_Updater/0001-Server.patch +++ b/Patches/LineageOS-20.0/android_packages_apps_Updater/0001-Server.patch @@ -9,7 +9,7 @@ Change-Id: I26dc2942736cf0cfe4e7b92ddfdd04b9d74dbae5 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/org/lineageos/updater/misc/Utils.java b/src/org/lineageos/updater/misc/Utils.java -index d768f62..77e7af6 100644 +index f0e390a..4ab3a51 100644 --- a/src/org/lineageos/updater/misc/Utils.java +++ b/src/org/lineageos/updater/misc/Utils.java @@ -155,16 +155,9 @@ public class Utils { diff --git a/Patches/LineageOS-20.0/android_packages_apps_Updater/0002-Tor_Support.patch b/Patches/LineageOS-20.0/android_packages_apps_Updater/0002-Tor_Support.patch index bdcfef42..73f46e52 100644 --- a/Patches/LineageOS-20.0/android_packages_apps_Updater/0002-Tor_Support.patch +++ b/Patches/LineageOS-20.0/android_packages_apps_Updater/0002-Tor_Support.patch @@ -72,7 +72,7 @@ index 18e3ede..e92eb1d 100644 This update can\'t be installed on top of the current build. diff --git a/src/org/lineageos/updater/UpdatesActivity.java b/src/org/lineageos/updater/UpdatesActivity.java -index b1365cc..de386c3 100644 +index 12254c7..5da1026 100644 --- a/src/org/lineageos/updater/UpdatesActivity.java +++ b/src/org/lineageos/updater/UpdatesActivity.java @@ -377,10 +377,14 @@ public class UpdatesActivity extends UpdatesListActivity { @@ -308,7 +308,7 @@ index beb9423..a51ab15 100644 public static final String PREF_AB_PERF_MODE = "ab_perf_mode"; public static final String PREF_METERED_NETWORK_WARNING = "pref_metered_network_warning"; diff --git a/src/org/lineageos/updater/misc/Utils.java b/src/org/lineageos/updater/misc/Utils.java -index 77e7af6..79e5dce 100644 +index 4ab3a51..805285b 100644 --- a/src/org/lineageos/updater/misc/Utils.java +++ b/src/org/lineageos/updater/misc/Utils.java @@ -46,6 +46,7 @@ import java.io.BufferedReader; diff --git a/Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0001-Fix-OOB-read-in-btm_ble_periodic_av_sync_lost.patch b/Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0001-Fix-OOB-read-in-btm_ble_periodic_av_sync_lost.patch new file mode 100644 index 00000000..1b69e7e8 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0001-Fix-OOB-read-in-btm_ble_periodic_av_sync_lost.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brian Delwiche +Date: Wed, 29 Mar 2023 22:52:06 +0000 +Subject: [PATCH 1/2] Fix OOB read in btm_ble_periodic_av_sync_lost + +btm_ble_periodic_av_sync_lost internally calls the function +btm_ble_get_psync_index_from_handle, which polls the internal periodic +sync buffer and returns a matching index if one exists. If no matching +handle is found, it returns MAX_SYNC_TRANSACTION. + +However, here the calling function lacks the check for this case present +in similar functions. If no handle is matched, it will attempt to index +the buffer with MAX_SYNC_TRANSACTION, which will overrun it by a single +width and lead to OOB access. + +Add handling for this case. + +Bug: 273502002 +Test: atest bluetooth_test_gd_unit, atest net_test_stack_btm, validated +against researcher POC +Tag: #security +Ignore-AOSP-First: Security +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c077ffbe609c33adc212b73cd3018b174f0c8f89) +Merged-In: I2e1e95b277f81b2668f721a7693df50841968ec5 +Change-Id: I2e1e95b277f81b2668f721a7693df50841968ec5 +--- + system/stack/btm/btm_ble_gap.cc | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc +index f8a8940d98..af7da7f70c 100644 +--- a/system/stack/btm/btm_ble_gap.cc ++++ b/system/stack/btm/btm_ble_gap.cc +@@ -1180,6 +1180,10 @@ void btm_ble_periodic_adv_sync_lost(uint16_t sync_handle) { + LOG_DEBUG("[PSync]: sync_handle = %d", sync_handle); + + int index = btm_ble_get_psync_index_from_handle(sync_handle); ++ if (index == MAX_SYNC_TRANSACTION) { ++ LOG_ERROR("[PSync]: index not found for handle %u", sync_handle); ++ return; ++ } + tBTM_BLE_PERIODIC_SYNC* ps = &btm_ble_pa_sync_cb.p_sync[index]; + ps->sync_lost_cb.Run(sync_handle); + diff --git a/Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0002-Revert-Revert-Validate-buffer-length-in-sdpu_build_u.patch b/Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0002-Revert-Revert-Validate-buffer-length-in-sdpu_build_u.patch new file mode 100644 index 00000000..d73f2b32 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_modules_Bluetooth/ASB-2023-06/0002-Revert-Revert-Validate-buffer-length-in-sdpu_build_u.patch @@ -0,0 +1,128 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brian Delwiche +Date: Tue, 21 Mar 2023 22:34:41 +0000 +Subject: [PATCH 2/2] Revert "Revert "Validate buffer length in + sdpu_build_uuid_seq"" + +This reverts commit e6cf2700522cf639d8115b025833edc24702c7e9. + +Reason for revert: Reinstate original change for QPR +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4a33fbcfdb10a16760ef208f1f12a71c1be2d084) +Merged-In: I3e039f1b8f8ffbcc4875b663d417462451fb76a0 +Change-Id: I3e039f1b8f8ffbcc4875b663d417462451fb76a0 +--- + system/stack/sdp/sdp_discovery.cc | 58 ++++++++++++++++++++++++++++--- + 1 file changed, 53 insertions(+), 5 deletions(-) + +diff --git a/system/stack/sdp/sdp_discovery.cc b/system/stack/sdp/sdp_discovery.cc +index 22d6e7caf4..654f899a89 100644 +--- a/system/stack/sdp/sdp_discovery.cc ++++ b/system/stack/sdp/sdp_discovery.cc +@@ -70,10 +70,15 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, + * + ******************************************************************************/ + static uint8_t* sdpu_build_uuid_seq(uint8_t* p_out, uint16_t num_uuids, +- Uuid* p_uuid_list) { ++ Uuid* p_uuid_list, uint16_t& bytes_left) { + uint16_t xx; + uint8_t* p_len; + ++ if (bytes_left < 2) { ++ DCHECK(0) << "SDP: No space for data element header"; ++ return (p_out); ++ } ++ + /* First thing is the data element header */ + UINT8_TO_BE_STREAM(p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + +@@ -81,9 +86,20 @@ static uint8_t* sdpu_build_uuid_seq(uint8_t* p_out, uint16_t num_uuids, + p_len = p_out; + p_out += 1; + ++ /* Account for data element header and length */ ++ bytes_left -= 2; ++ + /* Now, loop through and put in all the UUID(s) */ + for (xx = 0; xx < num_uuids; xx++, p_uuid_list++) { + int len = p_uuid_list->GetShortestRepresentationSize(); ++ ++ if (len + 1 > bytes_left) { ++ DCHECK(0) << "SDP: Too many UUIDs for internal buffer"; ++ break; ++ } else { ++ bytes_left -= (len + 1); ++ } ++ + if (len == Uuid::kNumBytes16) { + UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM(p_out, p_uuid_list->As16Bit()); +@@ -120,6 +136,7 @@ static void sdp_snd_service_search_req(tCONN_CB* p_ccb, uint8_t cont_len, + uint8_t *p, *p_start, *p_param_len; + BT_HDR* p_cmd = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); + uint16_t param_len; ++ uint16_t bytes_left = SDP_DATA_BUF_SIZE; + + /* Prepare the buffer for sending the packet to L2CAP */ + p_cmd->offset = L2CAP_MIN_OFFSET; +@@ -134,9 +151,24 @@ static void sdp_snd_service_search_req(tCONN_CB* p_ccb, uint8_t cont_len, + p_param_len = p; + p += 2; + +-/* Build the UID sequence. */ ++ /* Account for header size, max service record count and ++ * continuation state */ ++ const uint16_t base_bytes = (sizeof(BT_HDR) + L2CAP_MIN_OFFSET + ++ 3u + /* service search request header */ ++ 2u + /* param len */ ++ 3u + ((p_cont) ? cont_len : 0)); ++ ++ if (base_bytes > bytes_left) { ++ DCHECK(0) << "SDP: Overran SDP data buffer"; ++ osi_free(p_cmd); ++ return; ++ } ++ ++ bytes_left -= base_bytes; ++ ++ /* Build the UID sequence. */ + p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters, +- p_ccb->p_db->uuid_filters); ++ p_ccb->p_db->uuid_filters, bytes_left); + + /* Set max service record count */ + UINT16_TO_BE_STREAM(p, sdp_cb.max_recs_per_search); +@@ -562,6 +594,7 @@ static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply, + if ((cont_request_needed) || (!p_reply)) { + BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); + uint8_t* p; ++ uint16_t bytes_left = SDP_DATA_BUF_SIZE; + + p_msg->offset = L2CAP_MIN_OFFSET; + p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; +@@ -575,9 +608,24 @@ static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply, + p_param_len = p; + p += 2; + +-/* Build the UID sequence. */ ++ /* Account for header size, max service record count and ++ * continuation state */ ++ const uint16_t base_bytes = (sizeof(BT_HDR) + L2CAP_MIN_OFFSET + ++ 3u + /* service search request header */ ++ 2u + /* param len */ ++ 3u + /* max service record count */ ++ ((p_reply) ? (*p_reply) : 0)); ++ ++ if (base_bytes > bytes_left) { ++ sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); ++ return; ++ } ++ ++ bytes_left -= base_bytes; ++ ++ /* Build the UID sequence. */ + p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters, +- p_ccb->p_db->uuid_filters); ++ p_ccb->p_db->uuid_filters, bytes_left); + + /* Max attribute byte count */ + UINT16_TO_BE_STREAM(p, sdp_cb.max_attr_list_size); diff --git a/Patches/LineageOS-20.0/android_packages_modules_Wifi/0001-Random_MAC.patch b/Patches/LineageOS-20.0/android_packages_modules_Wifi/0001-Random_MAC.patch index b5db1116..9041d255 100644 --- a/Patches/LineageOS-20.0/android_packages_modules_Wifi/0001-Random_MAC.patch +++ b/Patches/LineageOS-20.0/android_packages_modules_Wifi/0001-Random_MAC.patch @@ -63,10 +63,10 @@ index e988679fac..b7f4692198 100644 /** * Set the MAC randomization setting for this network. diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java -index d3e20bef27..1c7d700268 100644 +index ee6fea7ac8..5a6ab45179 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java -@@ -466,6 +466,9 @@ public class WifiConfigManager { +@@ -467,6 +467,9 @@ public class WifiConfigManager { return true; } @@ -76,7 +76,7 @@ index d3e20bef27..1c7d700268 100644 if (!isMacRandomizationSupported() || config.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_NONE) { return false; -@@ -620,7 +623,8 @@ public class WifiConfigManager { +@@ -621,7 +624,8 @@ public class WifiConfigManager { private MacAddress updateRandomizedMacIfNeeded(WifiConfiguration config) { boolean shouldUpdateMac = config.randomizedMacExpirationTimeMs < mClock.getWallClockMillis() || mClock.getWallClockMillis() diff --git a/Patches/LineageOS-20.0/android_packages_modules_Wifi/344228.patch b/Patches/LineageOS-20.0/android_packages_modules_Wifi/344228.patch index 828704d8..33a6f4f3 100644 --- a/Patches/LineageOS-20.0/android_packages_modules_Wifi/344228.patch +++ b/Patches/LineageOS-20.0/android_packages_modules_Wifi/344228.patch @@ -19,7 +19,7 @@ Signed-off-by: penglezos 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java -index 931374bccb..f1bf970ef4 100644 +index bd87041319..29855575e1 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -345,6 +345,8 @@ public class ClientModeImpl extends StateMachine implements ClientMode { diff --git a/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0001-Don-t-send-credentials-in-an-unauthenticated-TLS-tun.patch b/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0001-Don-t-send-credentials-in-an-unauthenticated-TLS-tun.patch new file mode 100644 index 00000000..a3a5ba86 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0001-Don-t-send-credentials-in-an-unauthenticated-TLS-tun.patch @@ -0,0 +1,1692 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jimmy Chen +Date: Wed, 28 Dec 2022 15:19:08 +0800 +Subject: [PATCH 1/3] Don't send credentials in an unauthenticated TLS tunnel + +Fix the security vulnerability reported in the security report. +Do not send the user credentials in phase2 before the user +approves the server certificate. This is done by connecting +with no credentials for the purpose of getting the server +certificate chain only, and reconnecting once the user approves +with full certificate chain authentication. + +Updated-PDD: TRUE +Bug: 250574778 +Bug: 251910611 +Test: atest InsecureEapNetworkHandlerTest ClientModeImplTest +Test: Integration test with WPA-Enterprise network with an S +device and a T device. +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fb630e6a13189321d0e83037adc9e7b30dc6d796) +Merged-In: Ib3501f5e04881b11ea9ab52472dd233f2aa82c7a +Change-Id: Ib3501f5e04881b11ea9ab52472dd233f2aa82c7a +--- + .../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, 745 insertions(+), 220 deletions(-) + +diff --git a/service/ServiceWifiResources/res/values/overlayable.xml b/service/ServiceWifiResources/res/values/overlayable.xml +index 2eef3f5156..75c90a3887 100644 +--- a/service/ServiceWifiResources/res/values/overlayable.xml ++++ b/service/ServiceWifiResources/res/values/overlayable.xml +@@ -321,6 +321,30 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/service/ServiceWifiResources/res/values/strings.xml b/service/ServiceWifiResources/res/values/strings.xml +index 15ffcf0ada..db331b2e7b 100644 +--- a/service/ServiceWifiResources/res/values/strings.xml ++++ b/service/ServiceWifiResources/res/values/strings.xml +@@ -205,6 +205,9 @@ + 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 931374bccb..9ec12bdad8 100644 +--- a/service/java/com/android/server/wifi/ClientModeImpl.java ++++ b/service/java/com/android/server/wifi/ClientModeImpl.java +@@ -580,9 +580,6 @@ 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 +@@ -837,17 +834,11 @@ 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, +@@ -2261,8 +2252,6 @@ 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: +@@ -4021,8 +4010,21 @@ 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; + } +@@ -4277,7 +4279,6 @@ 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: +@@ -5384,11 +5385,16 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + } + case WifiMonitor.TOFU_ROOT_CA_CERTIFICATE: + if (null == mTargetWifiConfiguration) break; +- if (!mInsecureEapNetworkHandler.setPendingCertificate( ++ int certificateDepth = message.arg2; ++ if (!mInsecureEapNetworkHandler.addPendingCertificate( + 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; +@@ -5867,10 +5873,6 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + class L3ProvisioningState extends State { + @Override + public void enter() { +- if (mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected)) { +- return; +- } +- + startL3Provisioning(); + } + +@@ -5890,18 +5892,6 @@ 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; +@@ -6421,6 +6411,12 @@ 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 225d01c7e5..b7389952e0 100644 +--- a/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java ++++ b/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java +@@ -40,6 +40,8 @@ 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 { +@@ -71,18 +73,27 @@ 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 mCurConfig = null; +- private int mPendingCaCertDepth = -1; ++ 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; + @Nullable +- private X509Certificate mPendingCaCert = null; ++ private X509Certificate mPendingRootCaCert = null; + @Nullable + private X509Certificate mPendingServerCert = null; +- // 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 ++ // 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<>(); + private WifiDialogManager.DialogHandle mTofuAlertDialog = null; + private boolean mIsCertNotificationReceiverRegistered = false; + +@@ -137,16 +148,17 @@ 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 void prepareConnection(@NonNull WifiConfiguration config) { +- if (null == config) return; ++ public boolean prepareConnection(@NonNull WifiConfiguration config) { ++ if (null == config) return false; ++ mConnectingConfig = config; + +- if (!config.isEnterprise()) return; ++ if (!config.isEnterprise()) return false; + WifiEnterpriseConfig entConfig = config.enterpriseConfig; +- if (!entConfig.isEapMethodServerCertUsed()) return; +- if (entConfig.hasCaCertificate()) return; +- +- clearConnection(); ++ if (!entConfig.isEapMethodServerCertUsed()) return false; ++ if (entConfig.hasCaCertificate()) return false; + + Log.d(TAG, "prepareConnection: isTofuSupported=" + mIsTrustOnFirstUseSupported + + ", isInsecureEapNetworkAllowed=" + mIsInsecureEnterpriseConfigurationAllowed +@@ -155,71 +167,115 @@ 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; ++ if (!mIsTrustOnFirstUseSupported) return false; + if (mIsInsecureEnterpriseConfigurationAllowed + && !entConfig.isTrustOnFirstUseEnabled()) { +- return; ++ return false; + } + } + +- mCurConfig = config; ++ 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(); + registerCertificateNotificationReceiver(); +- // 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."); ++ 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; + } + +- /** Clear data on disconnecting a connection. */ +- private void clearConnection() { +- unregisterCertificateNotificationReceiver(); ++ /** ++ * Do necessary clean up on stopping client mode. ++ */ ++ public void cleanup() { + dismissDialogAndNotification(); ++ unregisterCertificateNotificationReceiver(); + clearInternalData(); + } + + /** +- * Store the received certifiate for later use. ++ * Stores a received certificate 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 the Root CA certificate from the server. ++ * @param cert a certificate from the server. + * @return true if the cert is cached; otherwise, false. + */ +- public boolean setPendingCertificate(@NonNull String ssid, int depth, ++ public boolean addPendingCertificate(@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=" + mCurConfig); ++ + " current config=" + configProfileKey); + if (TextUtils.isEmpty(ssid)) return false; +- if (null == mCurConfig) return false; +- if (!TextUtils.equals(ssid, mCurConfig.SSID)) return false; ++ if (null == mCurrentTofuConfig) return false; ++ if (!TextUtils.equals(ssid, mCurrentTofuConfig.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; ++ } + } +- if (depth < mPendingCaCertDepth) { ++ ++ // Root or intermediate cert. ++ if (depth < mPendingRootCaCertDepth) { + Log.d(TAG, "Ignore intermediate cert." + cert); + return true; + } +- +- 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); ++ mPendingRootCaCertDepth = depth; ++ mPendingRootCaCert = cert; ++ Log.d(TAG, "Pending Root CA certificate: " + mPendingRootCaCert); + return true; + } + +@@ -244,31 +300,89 @@ public class InsecureEapNetworkHandler { + * @return true if the user approval is needed; otherwise, false. + */ + public boolean startUserApprovalIfNecessary(boolean isUserSelected) { +- 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 (null == mConnectingConfig || null == mCurrentTofuConfig) return false; ++ if (mConnectingConfig.networkId != mCurrentTofuConfig.networkId) 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 +- && !mCurConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { ++ && !mCurrentTofuConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { + Log.d(TAG, "Trust On First Use is not enabled."); +- handleError(mCurConfig.SSID); ++ handleError(mCurrentTofuConfig.SSID); + return true; + } + + if (useTrustOnFirstUse()) { +- if (null == mPendingCaCert) { +- Log.d(TAG, "No valid CA cert for TLS-based connection."); +- handleError(mCurConfig.SSID); ++ if (null == mPendingRootCaCert) { ++ Log.e(TAG, "No valid CA cert for TLS-based connection."); ++ handleError(mCurrentTofuConfig.SSID); + return true; + } else if (null == mPendingServerCert) { +- Log.d(TAG, "No valid Server cert for TLS-based connection."); +- handleError(mCurConfig.SSID); ++ 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()); ++ } + return true; + } ++ } else if (mIsInsecureEnterpriseConfigurationAllowed) { ++ Log.i(TAG, "networks without the server cert are allowed, skip it."); ++ return false; + } + + Log.d(TAG, "startUserApprovalIfNecessaryForInsecureEapNetwork: mIsUserSelected=" +@@ -282,13 +396,56 @@ 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 +- && mCurConfig.enterpriseConfig.isTrustOnFirstUseEnabled(); ++ && mCurrentTofuConfig.enterpriseConfig.isTrustOnFirstUseEnabled(); + } + + private void registerCertificateNotificationReceiver() { +- if (mIsCertNotificationReceiverRegistered) return; ++ unregisterCertificateNotificationReceiver(); + + IntentFilter filter = new IntentFilter(); + if (useTrustOnFirstUse()) { +@@ -313,21 +470,22 @@ public class InsecureEapNetworkHandler { + if (!isConnectionValid(ssid)) return; + + if (!useTrustOnFirstUse()) { +- mWifiConfigManager.setUserApproveNoCaCert(mCurConfig.networkId, true); ++ mWifiConfigManager.setUserApproveNoCaCert(mCurrentTofuConfig.networkId, true); + } else { +- if (null == mPendingCaCert || null == mPendingServerCert) { ++ if (null == mPendingRootCaCert || null == mPendingServerCert) { + handleError(ssid); + return; + } + if (!mWifiConfigManager.updateCaCertificate( +- mCurConfig.networkId, mPendingCaCert, mPendingServerCert)) { ++ mCurrentTofuConfig.networkId, mPendingRootCaCert, mPendingServerCert)) { + // The user approved this network, + // keep the connection regardless of the result. +- Log.e(TAG, "Cannot update CA cert to network " + mCurConfig.getProfileKey() +- + ", CA cert = " + mPendingCaCert); ++ Log.e(TAG, "Cannot update CA cert to network " + mCurrentTofuConfig.getProfileKey() ++ + ", CA cert = " + mPendingRootCaCert); + } + } +- mWifiConfigManager.allowAutojoin(mCurConfig.networkId, true); ++ mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, ++ WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE); + dismissDialogAndNotification(); + clearInternalData(); + +@@ -338,7 +496,8 @@ public class InsecureEapNetworkHandler { + void handleReject(@NonNull String ssid) { + if (!isConnectionValid(ssid)) return; + +- mWifiConfigManager.allowAutojoin(mCurConfig.networkId, false); ++ mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, ++ WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER); + dismissDialogAndNotification(); + clearInternalData(); + clearNativeData(); +@@ -347,6 +506,11 @@ 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(); +@@ -355,9 +519,9 @@ public class InsecureEapNetworkHandler { + } + + private void askForUserApprovalForCaCertificate() { +- if (mCurConfig == null || TextUtils.isEmpty(mCurConfig.SSID)) return; ++ if (mCurrentTofuConfig == null || TextUtils.isEmpty(mCurrentTofuConfig.SSID)) return; + if (useTrustOnFirstUse()) { +- if (null == mPendingCaCert || null == mPendingServerCert) { ++ if (null == mPendingRootCaCert || null == mPendingServerCert) { + Log.e(TAG, "Cannot launch a dialog for TOFU without " + + "a valid pending CA certificate."); + return; +@@ -375,39 +539,42 @@ 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 = null; ++ String message; + 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, +- mPendingCaCertSubjectInfo.commonName)) ++ mPendingServerCertSubjectInfo.commonName)) + .append(mContext.getString( + R.string.wifi_ca_cert_dialog_message_issuer_name_text, +- mPendingCaCertIssuerInfo.commonName)); +- if (!TextUtils.isEmpty(mPendingCaCertSubjectInfo.organization)) { ++ mPendingServerCertIssuerInfo.commonName)); ++ if (!TextUtils.isEmpty(mPendingServerCertSubjectInfo.organization)) { + contentBuilder.append(mContext.getString( + R.string.wifi_ca_cert_dialog_message_organization_text, +- mPendingCaCertSubjectInfo.organization)); ++ mPendingServerCertSubjectInfo.organization)); + } +- if (!TextUtils.isEmpty(mPendingCaCertSubjectInfo.email)) { ++ if (!TextUtils.isEmpty(mPendingServerCertSubjectInfo.email)) { + contentBuilder.append(mContext.getString( + R.string.wifi_ca_cert_dialog_message_contact_text, +- mPendingCaCertSubjectInfo.email)); ++ 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)); + } +- 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, mCurConfig.SSID); ++ R.string.wifi_ca_cert_dialog_preT_message_hint, mCurrentTofuConfig.SSID); + String linkText = mContext.getString( + R.string.wifi_ca_cert_dialog_preT_message_link); + message = hint + " " + linkText; +@@ -427,23 +594,35 @@ public class InsecureEapNetworkHandler { + new WifiDialogManager.SimpleDialogCallback() { + @Override + public void onPositiveButtonClicked() { +- handleAccept(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ handleAccept(mCurrentTofuConfig.SSID); + } + + @Override + public void onNegativeButtonClicked() { +- handleReject(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ handleReject(mCurrentTofuConfig.SSID); + } + + @Override + public void onNeutralButtonClicked() { + // Not used. +- handleReject(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ handleReject(mCurrentTofuConfig.SSID); + } + + @Override + public void onCancelled() { +- handleReject(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ handleReject(mCurrentTofuConfig.SSID); + } + }, + new WifiThreadRunner(mHandler)); +@@ -460,16 +639,16 @@ public class InsecureEapNetworkHandler { + } + + private void notifyUserForCaCertificate() { +- if (mCurConfig == null) return; ++ if (mCurrentTofuConfig == null) return; + if (useTrustOnFirstUse()) { +- if (null == mPendingCaCert) return; ++ if (null == mPendingRootCaCert) return; + if (null == mPendingServerCert) return; + } + dismissDialogAndNotification(); + + PendingIntent tapPendingIntent; + if (useTrustOnFirstUse()) { +- tapPendingIntent = genCaCertNotifIntent(ACTION_CERT_NOTIF_TAP, mCurConfig.SSID); ++ tapPendingIntent = genCaCertNotifIntent(ACTION_CERT_NOTIF_TAP, mCurrentTofuConfig.SSID); + } else { + Intent openLinkIntent = new Intent(Intent.ACTION_VIEW) + .setData(Uri.parse(mCaCertHelpLink)) +@@ -482,9 +661,10 @@ 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, mCurConfig.SSID) ++ ? mContext.getString(R.string.wifi_ca_cert_notification_message, ++ mCurrentTofuConfig.SSID) + : mContext.getString(R.string.wifi_ca_cert_notification_preT_message, +- mCurConfig.SSID); ++ mCurrentTofuConfig.SSID); + Notification.Builder builder = mFacade.makeNotificationBuilder(mContext, + WifiService.NOTIFICATION_NETWORK_ALERTS) + .setSmallIcon(Icon.createWithResource(mContext.getWifiOverlayApkPkgName(), +@@ -502,11 +682,13 @@ 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, mCurConfig.SSID)).build(); ++ genCaCertNotifIntent(ACTION_CERT_NOTIF_ACCEPT, mCurrentTofuConfig.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, mCurConfig.SSID)).build(); ++ genCaCertNotifIntent(ACTION_CERT_NOTIF_REJECT, mCurrentTofuConfig.SSID)) ++ .build(); + builder.addAction(rejectAction).addAction(acceptAction); + } + mNotificationManager.notify(SystemMessage.NOTE_SERVER_CA_CERTIFICATE, builder.build()); +@@ -521,18 +703,18 @@ public class InsecureEapNetworkHandler { + } + + private void clearInternalData() { +- mPendingCaCertDepth = -1; +- mPendingCaCert = null; ++ mPendingRootCaCertDepth = -1; ++ mPendingRootCaCert = null; + mPendingServerCert = null; +- mPendingCaCertSubjectInfo = null; +- mPendingCaCertIssuerInfo = null; +- mCurConfig = null; ++ mPendingServerCertSubjectInfo = null; ++ mPendingServerCertIssuerInfo = null; ++ mCurrentTofuConfig = null; + } + + private void clearNativeData() { + // PMK should be cleared or it would skip EAP flow next time. +- if (null != mCurConfig) { +- mWifiNative.removeNetworkCachedData(mCurConfig.networkId); ++ if (null != mCurrentTofuConfig) { ++ mWifiNative.removeNetworkCachedData(mCurrentTofuConfig.networkId); + } + // remove network so that supplicant's PMKSA cache is cleared + mWifiNative.removeAllNetworks(mInterfaceName); +@@ -551,13 +733,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 == mCurConfig) { ++ if (TextUtils.isEmpty(ssid) || null == mCurrentTofuConfig) { + handleError(null); + return false; + } + +- if (!TextUtils.equals(ssid, mCurConfig.SSID)) { +- Log.w(TAG, "Target SSID " + mCurConfig.SSID ++ if (!TextUtils.equals(ssid, mCurrentTofuConfig.SSID)) { ++ Log.w(TAG, "Target SSID " + mCurrentTofuConfig.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 40acc85cc5..b044508eb7 100644 +--- a/service/java/com/android/server/wifi/WifiServiceImpl.java ++++ b/service/java/com/android/server/wifi/WifiServiceImpl.java +@@ -528,9 +528,6 @@ 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( +@@ -795,6 +792,10 @@ 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 09a596f984..871eb2c750 100644 +--- a/service/proto/src/metrics.proto ++++ b/service/proto/src/metrics.proto +@@ -1047,6 +1047,9 @@ 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 ca8f5b031c..e2309e9ce4 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +@@ -7860,11 +7860,18 @@ public class ClientModeImplTest extends WifiBaseTest { + WifiEnterpriseConfig.Eap.TLS, WifiEnterpriseConfig.Phase2.NONE)); + eapTlsConfig.networkId = FRAMEWORK_NETWORK_ID; + eapTlsConfig.SSID = TEST_SSID; +- if (isAtLeastT) { ++ if (isAtLeastT && isTrustOnFirstUseSupported) { + 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); + +@@ -7879,31 +7886,31 @@ public class ClientModeImplTest extends WifiBaseTest { + } + verify(mInsecureEapNetworkHandler).prepareConnection(eq(eapTlsConfig)); + +- 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.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, ++ new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR, ++ SupplicantState.ASSOCIATED)); ++ mLooper.dispatchAll(); ++ + mCmi.sendMessage(WifiMonitor.TOFU_ROOT_CA_CERTIFICATE, + FRAMEWORK_NETWORK_ID, 0, FakeKeys.CA_CERT0); + mLooper.dispatchAll(); +- verify(mInsecureEapNetworkHandler).setPendingCertificate( ++ verify(mInsecureEapNetworkHandler).addPendingCertificate( + eq(eapTlsConfig.SSID), eq(0), eq(FakeKeys.CA_CERT0)); +- } + +- 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(); ++ // 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(); ++ } + + verify(mInsecureEapNetworkHandler).startUserApprovalIfNecessary(eq(isUserSelected)); +- assertEquals("L3ProvisioningState", getCurrentState().getName()); +- ++ // In any case, we end up in the disconnected state ++ assertEquals("DisconnectedState", getCurrentState().getName()); + return eapTlsConfig; + } + +@@ -7919,9 +7926,22 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + mLooper.dispatchAll(); +- injectDhcpSuccess(); ++ 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); + mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + } + + /** +@@ -7936,7 +7956,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -7951,7 +7977,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -7967,9 +7999,7 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + mLooper.dispatchAll(); +- injectDhcpSuccess(); +- mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + } + + /** +@@ -7985,7 +8015,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -8000,7 +8036,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -8015,9 +8057,7 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + mLooper.dispatchAll(); +- injectDhcpSuccess(); +- mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + } + + /** +@@ -8032,7 +8072,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -8047,7 +8093,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -8061,9 +8113,8 @@ public class ClientModeImplTest extends WifiBaseTest { + WifiConfiguration testConfig = setupLegacyEapNetworkTest(false); + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); +- injectDhcpSuccess(); + mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + } + + /** +@@ -8078,9 +8129,14 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); + mLooper.dispatchAll(); +- + verify(mFrameworkFacade, never()).makeAlertDialogBuilder(any()); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -8095,7 +8151,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + 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 aed3753ffc..6e2e67a8a2 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java +@@ -17,14 +17,18 @@ + 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; +@@ -37,11 +41,16 @@ 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; +@@ -51,9 +60,13 @@ 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}. + */ +@@ -65,7 +78,9 @@ 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_SSID = "\"test_ssid\""; ++ private static final String TEST_IDENTITY = "userid"; ++ private static final String TEST_PASSWORD = "myPassWord!"; + + @Mock WifiContext mContext; + @Mock WifiConfigManager mWifiConfigManager; +@@ -94,11 +109,34 @@ 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); +@@ -207,6 +245,9 @@ 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)); + } + + /** +@@ -311,9 +352,36 @@ 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.TLS, WifiEnterpriseConfig.Phase2.NONE)); ++ WifiEnterpriseConfig.Eap.TTLS, WifiEnterpriseConfig.Phase2.MSCHAPV2)); + config.networkId = FRAMEWORK_NETWORK_ID; + config.SSID = TEST_SSID; + if (isAtLeastT) { +@@ -321,6 +389,8 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + } + config.enterpriseConfig.setCaPath(""); + config.enterpriseConfig.setDomainSuffixMatch(""); ++ config.enterpriseConfig.setIdentity(TEST_IDENTITY); ++ config.enterpriseConfig.setPassword(TEST_PASSWORD); + return config; + } + +@@ -338,14 +408,32 @@ 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(), +@@ -379,34 +467,13 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + +- 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); ++ X509Certificate mockCaCert = generateMockCert("ca", "ca", true); ++ X509Certificate mockServerCert = generateMockCert("server", "ca", false); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert); + + verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported, +- isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CLIENT_CERT); ++ isUserSelected, needUserApproval, mockCaCert, mockServerCert); + } + + /** +@@ -424,10 +491,11 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); ++ X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert); + + verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported, +- isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CA_CERT0); ++ isUserSelected, needUserApproval, mockSelfSignedCert, mockSelfSignedCert); + } + + /** +@@ -448,6 +516,9 @@ 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)); + } + + /** +@@ -467,11 +538,17 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + config.enterpriseConfig.enableTrustOnFirstUse(false); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, ++ generateMockCert("ca", "ca", true)); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, ++ generateMockCert("server", "ca", false)); + + 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)); + } + + /** +@@ -479,36 +556,161 @@ 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 = true, isInsecureEnterpriseConfigurationAllowed = true; ++ boolean needUserApproval = false, isInsecureEnterpriseConfigurationAllowed = true; + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + config.enterpriseConfig.enableTrustOnFirstUse(false); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported, + isInsecureEnterpriseConfigurationAllowed); + +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, ++ generateMockCert("ca", "ca", true)); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, ++ generateMockCert("server", "ca", false)); + + 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.setPendingCertificate(config.SSID, 2, FakeKeys.CA_CERT0); +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 1, FakeKeys.CA_CERT1); +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CLIENT_CERT); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 2, mockCaCert); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, ++ generateMockCert("middle", "ca", false)); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert); + } + verifyTrustOnFirstUseFlow(config, action, isTrustOnFirstUseSupported, +- isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CLIENT_CERT); ++ isUserSelected, needUserApproval, mockCaCert, mockServerCert); + } + + private void verifyTrustOnFirstUseFlow(WifiConfiguration config, +@@ -518,12 +720,17 @@ 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(), any(), any(), anyInt(), anyInt(), any(), any(), any(), +- dialogCallbackCaptor.capture(), any()); ++ any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(), any(), ++ any(), dialogCallbackCaptor.capture(), any()); ++ if (isTrustOnFirstUseSupported) { ++ assertTofuDialogMessage(expectedCaCert, expectedServerCert, ++ dialogMessageCaptor.getValue()); ++ } + if (action == ACTION_ACCEPT) { + dialogCallbackCaptor.getValue().onPositiveButtonClicked(); + } else if (action == ACTION_REJECT) { +@@ -533,6 +740,7 @@ 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) { +@@ -543,8 +751,10 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + ArgumentCaptor dialogCallbackCaptor = + ArgumentCaptor.forClass(WifiDialogManager.SimpleDialogCallback.class); + verify(mWifiDialogManager).createSimpleDialogWithUrl( +- any(), any(), any(), anyInt(), anyInt(), any(), any(), any(), +- dialogCallbackCaptor.capture(), any()); ++ any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(), ++ any(), any(), dialogCallbackCaptor.capture(), any()); ++ assertTofuDialogMessage(expectedCaCert, expectedServerCert, ++ dialogMessageCaptor.getValue()); + if (action == ACTION_ACCEPT) { + dialogCallbackCaptor.getValue().onPositiveButtonClicked(); + } else if (action == ACTION_REJECT) { +@@ -566,7 +776,8 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + } + + if (action == ACTION_ACCEPT) { +- verify(mWifiConfigManager).allowAutojoin(eq(config.networkId), eq(true)); ++ verify(mWifiConfigManager).updateNetworkSelectionStatus(eq(config.networkId), ++ eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE)); + if (isTrustOnFirstUseSupported) { + verify(mWifiConfigManager).updateCaCertificate( + eq(config.networkId), eq(expectedCaCert), eq(expectedServerCert)); +@@ -576,7 +787,10 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + } + verify(mCallbacks).onAccept(eq(config.SSID)); + } else if (action == ACTION_REJECT) { +- verify(mWifiConfigManager).allowAutojoin(eq(config.networkId), eq(false)); ++ verify(mWifiConfigManager, atLeastOnce()) ++ .updateNetworkSelectionStatus(eq(config.networkId), ++ eq(WifiConfiguration.NetworkSelectionStatus ++ .DISABLED_BY_WIFI_MANAGER)); + verify(mCallbacks).onReject(eq(config.SSID)); + } else if (action == ACTION_TAP) { + verify(mWifiDialogManager).createSimpleDialogWithUrl( +@@ -586,4 +800,44 @@ 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); ++ } + } diff --git a/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0002-Revert-TOFU-Don-t-send-credentials-in-an-unauthentic.patch b/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0002-Revert-TOFU-Don-t-send-credentials-in-an-unauthentic.patch new file mode 100644 index 00000000..f3cd5ea6 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0002-Revert-TOFU-Don-t-send-credentials-in-an-unauthentic.patch @@ -0,0 +1,1685 @@ +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); +- } + } diff --git a/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0003-Implement-a-secure-TOFU-flow.patch b/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0003-Implement-a-secure-TOFU-flow.patch new file mode 100644 index 00000000..540148c0 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_modules_Wifi/ASB-2023-06/0003-Implement-a-secure-TOFU-flow.patch @@ -0,0 +1,2185 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hai Shalom +Date: Thu, 2 Mar 2023 23:00:56 +0000 +Subject: [PATCH 3/3] Implement a secure TOFU flow + +Implement a secure TOFU flow for supporting devices, and +notifications about insecure connections in non-supporting +devices, when insecure configurations are not allowed. +Handle the case where insecure enterprise configurations are +allowed in the new and secure TOFU flow. In this mode, do not +disconnect the network, do not load certificates, and do not +notify the user about anything. +Display the correct certificate information in the dialog, +remove the email and 8-octet signature from the TOFU dialog, and +replace with user verifiable information: certificate expiration +date (locale adjusted) and a SHA-256 fingerprint of the server +certificate which is locally generated. +Network admins can calculate the fingerprint of their server +certificate and publish the result to their users, using: +openssl x509 -in server-cert.pem -noout -fingerprint -sha256 + +Updated-Overlayable: TRUE +Updated-PDD: TRUE + +Bug: 267633332 +Bug: 251910611 +Bug: 250574778 +Test: atest ClientModeImplTest InsecureEapNetworkHandlerTest +Test: atest WifiConfigManagerTest +Test: Integration test on R, and T devices with overlay setting +of insecure networks allowed and not allowed, and with new +configs and insecure (Do not validate) configs made with R. +Test: Functional test, UI verification with multiple locales +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a5227527411bc24e6e2c6276f16559c7305b6783) +Merged-In: I5cac12cd8c52a8a9425e98dad0fb90893f53e374 +Change-Id: I5cac12cd8c52a8a9425e98dad0fb90893f53e374 +--- + .../res/values/overlayable.xml | 25 + + .../res/values/strings.xml | 10 +- + .../android/server/wifi/ClientModeImpl.java | 65 ++- + .../wifi/InsecureEapNetworkHandler.java | 471 +++++++++++++----- + .../server/wifi/WifiConfigManager.java | 32 +- + .../com/android/server/wifi/WifiKeyStore.java | 56 ++- + .../android/server/wifi/WifiServiceImpl.java | 7 +- + service/proto/src/metrics.proto | 3 + + .../server/wifi/ClientModeImplTest.java | 135 +++-- + .../wifi/InsecureEapNetworkHandlerTest.java | 374 +++++++++++--- + .../server/wifi/WifiConfigManagerTest.java | 69 +++ + .../wifi/WifiConfigurationTestUtil.java | 1 + + .../android/server/wifi/WifiKeyStoreTest.java | 31 ++ + 13 files changed, 971 insertions(+), 308 deletions(-) + +diff --git a/service/ServiceWifiResources/res/values/overlayable.xml b/service/ServiceWifiResources/res/values/overlayable.xml +index 2eef3f5156..160b711091 100644 +--- a/service/ServiceWifiResources/res/values/overlayable.xml ++++ b/service/ServiceWifiResources/res/values/overlayable.xml +@@ -321,6 +321,31 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/service/ServiceWifiResources/res/values/strings.xml b/service/ServiceWifiResources/res/values/strings.xml +index 15ffcf0ada..bfcb96a1f8 100644 +--- a/service/ServiceWifiResources/res/values/strings.xml ++++ b/service/ServiceWifiResources/res/values/strings.xml +@@ -200,16 +200,20 @@ + Server Name:\n%1$s\n\n + Issuer Name:\n%1$s\n\n + Organization:\n%1$s\n\n ++ Certificate Expiration:\n%1$s\n\n ++ SHA-256 Fingerprint:\n%1$s\n\n + Contact:\n%1$s\n\n +- Signature:\n%1$s\n\n + 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 +- Connect anyway +- Don\'t connect ++ Stay connected ++ Disconnect now + The network %1$s is missing a certificate. + Learn how to add certificates + 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 931374bccb..bd87041319 100644 +--- a/service/java/com/android/server/wifi/ClientModeImpl.java ++++ b/service/java/com/android/server/wifi/ClientModeImpl.java +@@ -581,7 +581,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + static final int CMD_ACCEPT_EAP_SERVER_CERTIFICATE = BASE + 301; + + @VisibleForTesting +- static final int CMD_REJECT_EAP_SERVER_CERTIFICATE = BASE + 302; ++ static final int CMD_REJECT_EAP_INSECURE_CONNECTION = BASE + 302; + + /* Tracks if suspend optimizations need to be disabled by DHCP, + * screen or due to high perf mode. +@@ -835,17 +835,17 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + } + + @Override +- public void onReject(String ssid) { ++ public void onReject(String ssid, boolean disconnectRequired) { + log("Reject Root CA cert for " + ssid); +- sendMessage(CMD_REJECT_EAP_SERVER_CERTIFICATE, ++ sendMessage(CMD_REJECT_EAP_INSECURE_CONNECTION, + WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_REJECTED_BY_USER, +- 0, ssid); ++ disconnectRequired ? 1 : 0, ssid); + } + + @Override + public void onError(String ssid) { + log("Insecure EAP network error for " + ssid); +- sendMessage(CMD_REJECT_EAP_SERVER_CERTIFICATE, ++ sendMessage(CMD_REJECT_EAP_INSECURE_CONNECTION, + WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE, + 0, ssid); + }}; +@@ -2261,7 +2261,7 @@ 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: ++ case CMD_REJECT_EAP_INSECURE_CONNECTION: + return "CMD_REJECT_EAP_SERVER_CERTIFICATE"; + case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: + return "SUPPLICANT_STATE_CHANGE_EVENT"; +@@ -4021,8 +4021,13 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + break; + } + } +- mInsecureEapNetworkHandler.prepareConnection(mTargetWifiConfiguration); + setSelectedRcoiForPasspoint(config); ++ ++ // TOFU flow for devices that do not support this feature ++ mInsecureEapNetworkHandler.prepareConnection(mTargetWifiConfiguration); ++ if (!isTrustOnFirstUseSupported()) { ++ mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected); ++ } + connectToNetwork(config); + break; + } +@@ -4277,7 +4282,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + break; + } + case CMD_ACCEPT_EAP_SERVER_CERTIFICATE: +- case CMD_REJECT_EAP_SERVER_CERTIFICATE: ++ case CMD_REJECT_EAP_INSECURE_CONNECTION: + case CMD_START_ROAM: + case CMD_START_RSSI_MONITORING_OFFLOAD: + case CMD_STOP_RSSI_MONITORING_OFFLOAD: +@@ -5062,6 +5067,18 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + } + break; + } ++ case CMD_REJECT_EAP_INSECURE_CONNECTION: { ++ log("Received CMD_REJECT_EAP_INSECURE_CONNECTION event"); ++ boolean disconnectRequired = message.arg2 == 1; ++ ++ // TOFU connections are not established until the user approves the certificate. ++ // If TOFU is not supported and the network is already connected, this will ++ // disconnect the network. ++ if (disconnectRequired) { ++ sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_UNTRUSTED); ++ } ++ break; ++ } + default: { + handleStatus = NOT_HANDLED; + break; +@@ -5384,11 +5401,19 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + } + case WifiMonitor.TOFU_ROOT_CA_CERTIFICATE: + if (null == mTargetWifiConfiguration) break; +- if (!mInsecureEapNetworkHandler.setPendingCertificate( ++ int certificateDepth = message.arg2; ++ if (!mInsecureEapNetworkHandler.addPendingCertificate( + mTargetWifiConfiguration.SSID, message.arg2, + (X509Certificate) message.obj)) { + Log.d(TAG, "Cannot set pending cert."); + } ++ // Launch user approval upon receiving the server certificate and disconnect ++ if (certificateDepth == 0 && 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); ++ } + break; + default: { + handleStatus = NOT_HANDLED; +@@ -5867,10 +5892,6 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + class L3ProvisioningState extends State { + @Override + public void enter() { +- if (mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected)) { +- return; +- } +- + startL3Provisioning(); + } + +@@ -5890,18 +5911,6 @@ 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; +@@ -6421,6 +6430,12 @@ 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 225d01c7e5..6c55feab7f 100644 +--- a/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java ++++ b/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java +@@ -31,15 +31,23 @@ import android.net.wifi.WifiContext; + import android.net.wifi.WifiEnterpriseConfig; + import android.os.Handler; + import android.text.TextUtils; ++import android.text.format.DateFormat; + import android.util.Log; + + import com.android.internal.annotations.VisibleForTesting; + import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; ++import com.android.internal.util.HexDump; + import com.android.server.wifi.util.CertificateSubjectInfo; +-import com.android.server.wifi.util.NativeUtil; + import com.android.wifi.resources.R; + ++import java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.security.cert.CertificateEncodingException; + import java.security.cert.X509Certificate; ++import java.util.ArrayList; ++import java.util.Date; ++import java.util.List; ++import java.util.StringJoiner; + + /** This class is used to handle insecure EAP networks. */ + public class InsecureEapNetworkHandler { +@@ -58,6 +66,7 @@ public class InsecureEapNetworkHandler { + static final String EXTRA_PENDING_CERT_SSID = + "com.android.server.wifi.ClientModeImpl.EXTRA_PENDING_CERT_SSID"; + ++ static final String TOFU_ANONYMOUS_IDENTITY = "anonymous"; + private final String mCaCertHelpLink; + private final WifiContext mContext; + private final WifiConfigManager mWifiConfigManager; +@@ -71,18 +80,27 @@ 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 mCurConfig = null; +- private int mPendingCaCertDepth = -1; ++ 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; + @Nullable +- private X509Certificate mPendingCaCert = null; ++ private X509Certificate mPendingRootCaCert = null; + @Nullable + private X509Certificate mPendingServerCert = null; +- // 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 ++ // 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<>(); + private WifiDialogManager.DialogHandle mTofuAlertDialog = null; + private boolean mIsCertNotificationReceiverRegistered = false; + +@@ -131,29 +149,30 @@ public class InsecureEapNetworkHandler { + } + + /** +- * Prepare data for a new connection. ++ * Prepare TOFU data for a new connection. + * +- * Prepare data if this is an Enterprise configuration, which ++ * Prepare TOFU data if this is an Enterprise configuration, which + * uses Server Cert, without a valid Root CA certificate or user approval. ++ * If TOFU is supported and enabled, this method will also clear the user credentials in the ++ * initial connection to the server. + * + * @param config the running wifi configuration. + */ + public void prepareConnection(@NonNull WifiConfiguration config) { + if (null == config) return; ++ mConnectingConfig = config; + + if (!config.isEnterprise()) return; + WifiEnterpriseConfig entConfig = config.enterpriseConfig; + if (!entConfig.isEapMethodServerCertUsed()) return; + if (entConfig.hasCaCertificate()) return; + +- clearConnection(); +- + Log.d(TAG, "prepareConnection: isTofuSupported=" + mIsTrustOnFirstUseSupported + + ", isInsecureEapNetworkAllowed=" + mIsInsecureEnterpriseConfigurationAllowed + + ", isTofuEnabled=" + entConfig.isTrustOnFirstUseEnabled() + + ", isUserApprovedNoCaCert=" + entConfig.isUserApproveNoCaCert()); + // 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. ++ // skip the entire TOFU logic if this network was approved earlier by the user. + if (entConfig.isUserApproveNoCaCert()) { + if (!mIsTrustOnFirstUseSupported) return; + if (mIsInsecureEnterpriseConfigurationAllowed +@@ -162,64 +181,122 @@ public class InsecureEapNetworkHandler { + } + } + +- mCurConfig = config; ++ if (mIsTrustOnFirstUseSupported && (entConfig.isTrustOnFirstUseEnabled() ++ || !mIsInsecureEnterpriseConfigurationAllowed)) { ++ /** ++ * 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); ++ if (TextUtils.isEmpty(config.enterpriseConfig.getAnonymousIdentity())) { ++ /** ++ * If anonymous identity was not provided, use "anonymous" to prevent any ++ * untrusted server from tracking real user identities. ++ */ ++ config.enterpriseConfig.setAnonymousIdentity(TOFU_ANONYMOUS_IDENTITY); ++ } ++ config.enterpriseConfig.setPassword(null); ++ } ++ } ++ mCurrentTofuConfig = config; ++ mServerCertChain.clear(); ++ dismissDialogAndNotification(); + registerCertificateNotificationReceiver(); +- // 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."); ++ ++ if (useTrustOnFirstUse()) { ++ // Remove cached PMK in the framework and supplicant to avoid skipping the EAP flow ++ // only when TOFU is in use. ++ clearNativeData(); ++ Log.d(TAG, "Remove native cached data and networks for TOFU."); ++ } + } + +- /** Clear data on disconnecting a connection. */ +- private void clearConnection() { +- unregisterCertificateNotificationReceiver(); ++ /** ++ * Do necessary clean up on stopping client mode. ++ */ ++ public void cleanup() { + dismissDialogAndNotification(); ++ unregisterCertificateNotificationReceiver(); + clearInternalData(); + } + + /** +- * Store the received certifiate for later use. ++ * Stores a received certificate 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 the Root CA certificate from the server. ++ * @param cert a certificate from the server. + * @return true if the cert is cached; otherwise, false. + */ +- public boolean setPendingCertificate(@NonNull String ssid, int depth, ++ public boolean addPendingCertificate(@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=" + mCurConfig); ++ + " current config=" + configProfileKey); + if (TextUtils.isEmpty(ssid)) return false; +- if (null == mCurConfig) return false; +- if (!TextUtils.equals(ssid, mCurConfig.SSID)) return false; ++ if (null == mCurrentTofuConfig) return false; ++ if (!TextUtils.equals(ssid, mCurrentTofuConfig.SSID)) return false; + if (null == cert) return false; + if (depth < 0) return false; ++ ++ // If TOFU is not supported return immediately, although this should not happen since ++ // the caller code flow is only active when TOFU is supported. ++ if (!mIsTrustOnFirstUseSupported) return false; ++ ++ // If insecure configurations are allowed and this configuration is configured with ++ // "Do not validate" (i.e. TOFU is disabled), skip loading the certificates (no need for ++ // them anyway) and don't disconnect the network. ++ if (mIsInsecureEnterpriseConfigurationAllowed ++ && !mCurrentTofuConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { ++ Log.d(TAG, "Certificates are not required for this connection"); ++ return false; ++ } ++ ++ if (depth == 0) { ++ // Disable network selection upon receiving the server certificate ++ putNetworkOnHold(); ++ } ++ ++ 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; ++ } + } +- if (depth < mPendingCaCertDepth) { ++ ++ // Root or intermediate cert. ++ if (depth < mPendingRootCaCertDepth) { + Log.d(TAG, "Ignore intermediate cert." + cert); + return true; + } +- +- 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); ++ mPendingRootCaCertDepth = depth; ++ mPendingRootCaCert = cert; ++ Log.d(TAG, "Pending Root CA certificate: " + mPendingRootCaCert); + return true; + } + +@@ -241,34 +318,42 @@ public class InsecureEapNetworkHandler { + * cert from the server, just mark this network is approved by the user. + * + * @param isUserSelected indicates that this connection is triggered by a user. +- * @return true if the user approval is needed; otherwise, false. ++ * @return true if user approval dialog is displayed and the network is pending. + */ + public boolean startUserApprovalIfNecessary(boolean isUserSelected) { +- 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 (null == mConnectingConfig || null == mCurrentTofuConfig) return false; ++ if (mConnectingConfig.networkId != mCurrentTofuConfig.networkId) 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. ++ // is not allowed, TOFU must be used for an Enterprise network without certs. This should ++ // not happen because the TOFU flag will be set during boot if these conditions are met. + if (mIsTrustOnFirstUseSupported && !mIsInsecureEnterpriseConfigurationAllowed +- && !mCurConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { +- Log.d(TAG, "Trust On First Use is not enabled."); +- handleError(mCurConfig.SSID); +- return true; ++ && !mCurrentTofuConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { ++ Log.e(TAG, "Upgrade insecure connection to TOFU."); ++ mCurrentTofuConfig.enterpriseConfig.enableTrustOnFirstUse(true); + } + + if (useTrustOnFirstUse()) { +- if (null == mPendingCaCert) { +- Log.d(TAG, "No valid CA cert for TLS-based connection."); +- handleError(mCurConfig.SSID); +- return true; +- } else if (null == mPendingServerCert) { +- Log.d(TAG, "No valid Server cert for TLS-based connection."); +- handleError(mCurConfig.SSID); +- return true; ++ if (null == mPendingRootCaCert) { ++ Log.e(TAG, "No valid CA cert for TLS-based connection."); ++ handleError(mCurrentTofuConfig.SSID); ++ return false; + } ++ if (null == mPendingServerCert) { ++ Log.e(TAG, "No valid Server cert for TLS-based connection."); ++ handleError(mCurrentTofuConfig.SSID); ++ return false; ++ } ++ if (!isServerCertChainValid()) { ++ Log.e(TAG, "Server cert chain is invalid."); ++ String ssid = mCurrentTofuConfig.SSID; ++ handleError(ssid); ++ createCertificateErrorNotification(isUserSelected, ssid); ++ return false; ++ } ++ } else if (mIsInsecureEnterpriseConfigurationAllowed) { ++ Log.i(TAG, "Insecure networks without a Root CA cert are allowed."); ++ return false; + } + + Log.d(TAG, "startUserApprovalIfNecessaryForInsecureEapNetwork: mIsUserSelected=" +@@ -282,13 +367,114 @@ public class InsecureEapNetworkHandler { + return true; + } + ++ /** ++ * Create a notification or a dialog when a server certificate is invalid ++ */ ++ private void createCertificateErrorNotification(boolean isUserSelected, String ssid) { ++ String title = mContext.getString(R.string.wifi_tofu_invalid_cert_chain_title, 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); ++ ++ if (TextUtils.isEmpty(title) || TextUtils.isEmpty(message)) return; ++ ++ 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()); ++ } ++ } ++ ++ /** ++ * Disable network selection, disconnect if necessary, and clear PMK cache ++ */ ++ private void putNetworkOnHold() { ++ // 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 ++ 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 +- && mCurConfig.enterpriseConfig.isTrustOnFirstUseEnabled(); ++ && mCurrentTofuConfig.enterpriseConfig.isTrustOnFirstUseEnabled(); + } + + private void registerCertificateNotificationReceiver() { +- if (mIsCertNotificationReceiverRegistered) return; ++ unregisterCertificateNotificationReceiver(); + + IntentFilter filter = new IntentFilter(); + if (useTrustOnFirstUse()) { +@@ -313,21 +499,22 @@ public class InsecureEapNetworkHandler { + if (!isConnectionValid(ssid)) return; + + if (!useTrustOnFirstUse()) { +- mWifiConfigManager.setUserApproveNoCaCert(mCurConfig.networkId, true); ++ mWifiConfigManager.setUserApproveNoCaCert(mCurrentTofuConfig.networkId, true); + } else { +- if (null == mPendingCaCert || null == mPendingServerCert) { ++ if (null == mPendingRootCaCert || null == mPendingServerCert) { + handleError(ssid); + return; + } + if (!mWifiConfigManager.updateCaCertificate( +- mCurConfig.networkId, mPendingCaCert, mPendingServerCert)) { ++ mCurrentTofuConfig.networkId, mPendingRootCaCert, mPendingServerCert)) { + // The user approved this network, + // keep the connection regardless of the result. +- Log.e(TAG, "Cannot update CA cert to network " + mCurConfig.getProfileKey() +- + ", CA cert = " + mPendingCaCert); ++ Log.e(TAG, "Cannot update CA cert to network " + mCurrentTofuConfig.getProfileKey() ++ + ", CA cert = " + mPendingRootCaCert); + } + } +- mWifiConfigManager.allowAutojoin(mCurConfig.networkId, true); ++ mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, ++ WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE); + dismissDialogAndNotification(); + clearInternalData(); + +@@ -337,16 +524,22 @@ public class InsecureEapNetworkHandler { + @VisibleForTesting + void handleReject(@NonNull String ssid) { + if (!isConnectionValid(ssid)) return; ++ boolean disconnectRequired = !useTrustOnFirstUse(); + +- mWifiConfigManager.allowAutojoin(mCurConfig.networkId, false); ++ mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, ++ WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER); + dismissDialogAndNotification(); + clearInternalData(); +- clearNativeData(); +- +- if (null != mCallbacks) mCallbacks.onReject(ssid); ++ if (disconnectRequired) clearNativeData(); ++ if (null != mCallbacks) mCallbacks.onReject(ssid, disconnectRequired); + } + + private void handleError(@Nullable String ssid) { ++ if (mCurrentTofuConfig != null) { ++ mWifiConfigManager.updateNetworkSelectionStatus(mCurrentTofuConfig.networkId, ++ WifiConfiguration.NetworkSelectionStatus ++ .DISABLED_BY_WIFI_MANAGER); ++ } + dismissDialogAndNotification(); + clearInternalData(); + clearNativeData(); +@@ -355,9 +548,9 @@ public class InsecureEapNetworkHandler { + } + + private void askForUserApprovalForCaCertificate() { +- if (mCurConfig == null || TextUtils.isEmpty(mCurConfig.SSID)) return; ++ if (mCurrentTofuConfig == null || TextUtils.isEmpty(mCurrentTofuConfig.SSID)) return; + if (useTrustOnFirstUse()) { +- if (null == mPendingCaCert || null == mPendingServerCert) { ++ if (null == mPendingRootCaCert || null == mPendingServerCert) { + Log.e(TAG, "Cannot launch a dialog for TOFU without " + + "a valid pending CA certificate."); + return; +@@ -375,39 +568,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 = null; ++ String message; + 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, +- mPendingCaCertSubjectInfo.commonName)) ++ mPendingServerCertSubjectInfo.commonName)) + .append(mContext.getString( + R.string.wifi_ca_cert_dialog_message_issuer_name_text, +- mPendingCaCertIssuerInfo.commonName)); +- if (!TextUtils.isEmpty(mPendingCaCertSubjectInfo.organization)) { ++ mPendingServerCertIssuerInfo.commonName)); ++ if (!TextUtils.isEmpty(mPendingServerCertSubjectInfo.organization)) { + contentBuilder.append(mContext.getString( + R.string.wifi_ca_cert_dialog_message_organization_text, +- mPendingCaCertSubjectInfo.organization)); ++ mPendingServerCertSubjectInfo.organization)); + } +- if (!TextUtils.isEmpty(mPendingCaCertSubjectInfo.email)) { ++ final Date expiration = mPendingServerCert.getNotAfter(); ++ if (expiration != null) { + contentBuilder.append(mContext.getString( +- R.string.wifi_ca_cert_dialog_message_contact_text, +- mPendingCaCertSubjectInfo.email)); ++ R.string.wifi_ca_cert_dialog_message_expiration_text, ++ DateFormat.getMediumDateFormat(mContext).format(expiration))); ++ } ++ final String fingerprint = getDigest(mPendingServerCert, "SHA256"); ++ if (!TextUtils.isEmpty(fingerprint)) { ++ contentBuilder.append(mContext.getString( ++ R.string.wifi_ca_cert_dialog_message_signature_name_text, fingerprint)); + } +- 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, mCurConfig.SSID); ++ R.string.wifi_ca_cert_dialog_preT_message_hint, mCurrentTofuConfig.SSID); + String linkText = mContext.getString( + R.string.wifi_ca_cert_dialog_preT_message_link); + message = hint + " " + linkText; +@@ -427,23 +620,39 @@ public class InsecureEapNetworkHandler { + new WifiDialogManager.SimpleDialogCallback() { + @Override + public void onPositiveButtonClicked() { +- handleAccept(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ Log.d(TAG, "User accepted the server certificate"); ++ handleAccept(mCurrentTofuConfig.SSID); + } + + @Override + public void onNegativeButtonClicked() { +- handleReject(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ Log.d(TAG, "User rejected the server certificate"); ++ handleReject(mCurrentTofuConfig.SSID); + } + + @Override + public void onNeutralButtonClicked() { + // Not used. +- handleReject(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ Log.d(TAG, "User input neutral"); ++ handleReject(mCurrentTofuConfig.SSID); + } + + @Override + public void onCancelled() { +- handleReject(mCurConfig.SSID); ++ if (mCurrentTofuConfig == null) { ++ return; ++ } ++ Log.d(TAG, "User input canceled"); ++ handleReject(mCurrentTofuConfig.SSID); + } + }, + new WifiThreadRunner(mHandler)); +@@ -460,16 +669,16 @@ public class InsecureEapNetworkHandler { + } + + private void notifyUserForCaCertificate() { +- if (mCurConfig == null) return; ++ if (mCurrentTofuConfig == null) return; + if (useTrustOnFirstUse()) { +- if (null == mPendingCaCert) return; ++ if (null == mPendingRootCaCert) return; + if (null == mPendingServerCert) return; + } + dismissDialogAndNotification(); + + PendingIntent tapPendingIntent; + if (useTrustOnFirstUse()) { +- tapPendingIntent = genCaCertNotifIntent(ACTION_CERT_NOTIF_TAP, mCurConfig.SSID); ++ tapPendingIntent = genCaCertNotifIntent(ACTION_CERT_NOTIF_TAP, mCurrentTofuConfig.SSID); + } else { + Intent openLinkIntent = new Intent(Intent.ACTION_VIEW) + .setData(Uri.parse(mCaCertHelpLink)) +@@ -482,9 +691,10 @@ 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, mCurConfig.SSID) ++ ? mContext.getString(R.string.wifi_ca_cert_notification_message, ++ mCurrentTofuConfig.SSID) + : mContext.getString(R.string.wifi_ca_cert_notification_preT_message, +- mCurConfig.SSID); ++ mCurrentTofuConfig.SSID); + Notification.Builder builder = mFacade.makeNotificationBuilder(mContext, + WifiService.NOTIFICATION_NETWORK_ALERTS) + .setSmallIcon(Icon.createWithResource(mContext.getWifiOverlayApkPkgName(), +@@ -502,11 +712,13 @@ 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, mCurConfig.SSID)).build(); ++ genCaCertNotifIntent(ACTION_CERT_NOTIF_ACCEPT, mCurrentTofuConfig.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, mCurConfig.SSID)).build(); ++ genCaCertNotifIntent(ACTION_CERT_NOTIF_REJECT, mCurrentTofuConfig.SSID)) ++ .build(); + builder.addAction(rejectAction).addAction(acceptAction); + } + mNotificationManager.notify(SystemMessage.NOTE_SERVER_CA_CERTIFICATE, builder.build()); +@@ -521,18 +733,18 @@ public class InsecureEapNetworkHandler { + } + + private void clearInternalData() { +- mPendingCaCertDepth = -1; +- mPendingCaCert = null; ++ mPendingRootCaCertDepth = -1; ++ mPendingRootCaCert = null; + mPendingServerCert = null; +- mPendingCaCertSubjectInfo = null; +- mPendingCaCertIssuerInfo = null; +- mCurConfig = null; ++ mPendingServerCertSubjectInfo = null; ++ mPendingServerCertIssuerInfo = null; ++ mCurrentTofuConfig = null; + } + + private void clearNativeData() { + // PMK should be cleared or it would skip EAP flow next time. +- if (null != mCurConfig) { +- mWifiNative.removeNetworkCachedData(mCurConfig.networkId); ++ if (null != mCurrentTofuConfig) { ++ mWifiNative.removeNetworkCachedData(mCurrentTofuConfig.networkId); + } + // remove network so that supplicant's PMKSA cache is cleared + mWifiNative.removeAllNetworks(mInterfaceName); +@@ -551,19 +763,47 @@ 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 == mCurConfig) { ++ if (TextUtils.isEmpty(ssid) || null == mCurrentTofuConfig) { + handleError(null); + return false; + } + +- if (!TextUtils.equals(ssid, mCurConfig.SSID)) { +- Log.w(TAG, "Target SSID " + mCurConfig.SSID ++ if (!TextUtils.equals(ssid, mCurrentTofuConfig.SSID)) { ++ Log.w(TAG, "Target SSID " + mCurrentTofuConfig.SSID + + " is different from TOFU returned SSID" + ssid); + return false; + } + return true; + } + ++ @VisibleForTesting ++ static String getDigest(X509Certificate x509Certificate, String algorithm) { ++ if (x509Certificate == null) { ++ return ""; ++ } ++ try { ++ byte[] bytes = x509Certificate.getEncoded(); ++ MessageDigest md = MessageDigest.getInstance(algorithm); ++ byte[] digest = md.digest(bytes); ++ return fingerprint(digest); ++ } catch (CertificateEncodingException ignored) { ++ return ""; ++ } catch (NoSuchAlgorithmException ignored) { ++ return ""; ++ } ++ } ++ ++ private static String fingerprint(byte[] bytes) { ++ if (bytes == null) { ++ return ""; ++ } ++ StringJoiner sj = new StringJoiner(":"); ++ for (byte b : bytes) { ++ sj.add(HexDump.toHexString(b)); ++ } ++ return sj.toString(); ++ } ++ + /** The callbacks object to notify the consumer. */ + public static class InsecureEapNetworkHandlerCallbacks { + /** +@@ -576,8 +816,9 @@ public class InsecureEapNetworkHandler { + * When a certificate is rejected, this callback is called. + * + * @param ssid SSID of the network. ++ * @param disconnectRequired Set to true if the network is currently connected + */ +- public void onReject(@NonNull String ssid) {} ++ public void onReject(@NonNull String ssid, boolean disconnectRequired) {} + /** + * When there are no valid data to handle this insecure EAP network, + * this callback is called. +diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java +index d3e20bef27..ee6fea7ac8 100644 +--- a/service/java/com/android/server/wifi/WifiConfigManager.java ++++ b/service/java/com/android/server/wifi/WifiConfigManager.java +@@ -16,6 +16,7 @@ + + package com.android.server.wifi; + ++import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import static android.net.wifi.WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE; + + import android.Manifest; +@@ -1433,6 +1434,30 @@ public class WifiConfigManager { + existingInternalConfig); + } + ++ if (config.isEnterprise() ++ && config.enterpriseConfig.isEapMethodServerCertUsed() ++ && !config.enterpriseConfig.isMandatoryParameterSetForServerCertValidation() ++ && !config.enterpriseConfig.isTrustOnFirstUseEnabled()) { ++ boolean isSettingsOrSuw = mContext.checkPermission(Manifest.permission.NETWORK_SETTINGS, ++ -1 /* pid */, uid) == PERMISSION_GRANTED ++ || mContext.checkPermission(Manifest.permission.NETWORK_SETUP_WIZARD, ++ -1 /* pid */, uid) == PERMISSION_GRANTED; ++ if (!(mWifiInjector.getWifiGlobals().isInsecureEnterpriseConfigurationAllowed() ++ && isSettingsOrSuw)) { ++ Log.e(TAG, "Enterprise network configuration is missing either a Root CA " ++ + "or a domain name"); ++ return new Pair<>( ++ new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID), ++ existingInternalConfig); ++ } ++ Log.w(TAG, "Insecure Enterprise network " + config.SSID ++ + " configured by Settings/SUW"); ++ ++ // Implicit user approval, when creating an insecure connection which is allowed ++ // in the configuration of the device ++ newInternalConfig.enterpriseConfig.setUserApproveNoCaCert(true); ++ } ++ + // Update the keys for saved enterprise networks. For Passpoint, the certificates + // and keys are installed at the time the provider is installed. For suggestion enterprise + // network the certificates and keys are installed at the time the suggestion is added +@@ -1484,11 +1509,6 @@ public class WifiConfigManager { + newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false); + } + +- // Ensure that the user approve flag is set to false for a new network. +- if (newNetwork && config.isEnterprise()) { +- config.enterpriseConfig.setUserApproveNoCaCert(false); +- } +- + // Add it to our internal map. This will replace any existing network configuration for + // updates. + try { +@@ -4130,7 +4150,7 @@ public class WifiConfigManager { + try { + if (newConfig.enterpriseConfig.isTrustOnFirstUseEnabled()) { + newConfig.enterpriseConfig.setCaCertificateForTrustOnFirstUse(caCert); +- // setCaCertificate will mark that this CA certifiate should be removed on ++ // setCaCertificate will mark that this CA certificate should be removed on + // removing this configuration. + newConfig.enterpriseConfig.enableTrustOnFirstUse(false); + } else { +diff --git a/service/java/com/android/server/wifi/WifiKeyStore.java b/service/java/com/android/server/wifi/WifiKeyStore.java +index a69614090c..deb2e9d94c 100644 +--- a/service/java/com/android/server/wifi/WifiKeyStore.java ++++ b/service/java/com/android/server/wifi/WifiKeyStore.java +@@ -315,38 +315,41 @@ public class WifiKeyStore { + if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT)) { + // Read the CA certificates, and initialize + String[] caAliases = config.enterpriseConfig.getCaCertificateAliases(); +- +- if (caAliases == null || caAliases.length == 0) { +- Log.e(TAG, "No CA aliases in profile"); +- return false; +- } +- + int caCertType = -1; +- int prevCaCertType = -1; +- for (String caAlias : caAliases) { +- Certificate caCert = null; +- try { +- caCert = mKeyStore.getCertificate(caAlias); +- } catch (KeyStoreException e) { +- Log.e(TAG, "Failed to get Suite-B certificate", e); +- } +- if (caCert == null || !(caCert instanceof X509Certificate)) { +- Log.e(TAG, "Failed reading CA certificate for Suite-B"); +- return false; +- } + +- // Confirm that the CA certificate is compatible with Suite-B requirements +- caCertType = getSuiteBCipherFromCert((X509Certificate) caCert); +- if (caCertType < 0) { ++ // In TOFU mode, configure the security mode based on the user certificate only. ++ if (!config.enterpriseConfig.isTrustOnFirstUseEnabled()) { ++ if (caAliases == null || caAliases.length == 0) { ++ Log.e(TAG, "No CA aliases in profile"); + return false; + } +- if (prevCaCertType != -1) { +- if (prevCaCertType != caCertType) { +- Log.e(TAG, "Incompatible CA certificates"); ++ ++ int prevCaCertType = -1; ++ for (String caAlias : caAliases) { ++ Certificate caCert = null; ++ try { ++ caCert = mKeyStore.getCertificate(caAlias); ++ } catch (KeyStoreException e) { ++ Log.e(TAG, "Failed to get Suite-B certificate", e); ++ } ++ if (caCert == null || !(caCert instanceof X509Certificate)) { ++ Log.e(TAG, "Failed reading CA certificate for Suite-B"); + return false; + } ++ ++ // Confirm that the CA certificate is compatible with Suite-B requirements ++ caCertType = getSuiteBCipherFromCert((X509Certificate) caCert); ++ if (caCertType < 0) { ++ return false; ++ } ++ if (prevCaCertType != -1) { ++ if (prevCaCertType != caCertType) { ++ Log.e(TAG, "Incompatible CA certificates"); ++ return false; ++ } ++ } ++ prevCaCertType = caCertType; + } +- prevCaCertType = caCertType; + } + + Certificate clientCert = null; +@@ -366,7 +369,8 @@ public class WifiKeyStore { + return false; + } + +- if (clientCertType == caCertType) { ++ if (clientCertType == caCertType ++ || config.enterpriseConfig.isTrustOnFirstUseEnabled()) { + config.enableSuiteBCiphers( + clientCertType == WifiConfiguration.SuiteBCipher.ECDHE_ECDSA, + clientCertType == WifiConfiguration.SuiteBCipher.ECDHE_RSA); +diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java +index 40acc85cc5..b044508eb7 100644 +--- a/service/java/com/android/server/wifi/WifiServiceImpl.java ++++ b/service/java/com/android/server/wifi/WifiServiceImpl.java +@@ -528,9 +528,6 @@ 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( +@@ -795,6 +792,10 @@ 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 09a596f984..871eb2c750 100644 +--- a/service/proto/src/metrics.proto ++++ b/service/proto/src/metrics.proto +@@ -1047,6 +1047,9 @@ 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 ca8f5b031c..cef996fef1 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +@@ -7853,18 +7853,18 @@ public class ClientModeImplTest extends WifiBaseTest { + WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE); + } + mCmi.mInsecureEapNetworkHandler = mInsecureEapNetworkHandler; +- when(mInsecureEapNetworkHandler.startUserApprovalIfNecessary(anyBoolean())) +- .thenReturn(true); + + WifiConfiguration eapTlsConfig = spy(WifiConfigurationTestUtil.createEapNetwork( + WifiEnterpriseConfig.Eap.TLS, WifiEnterpriseConfig.Phase2.NONE)); + eapTlsConfig.networkId = FRAMEWORK_NETWORK_ID; + eapTlsConfig.SSID = TEST_SSID; +- if (isAtLeastT) { ++ if (isAtLeastT && isTrustOnFirstUseSupported) { + eapTlsConfig.enterpriseConfig.enableTrustOnFirstUse(true); + } + eapTlsConfig.enterpriseConfig.setCaPath(""); + eapTlsConfig.enterpriseConfig.setDomainSuffixMatch(""); ++ eapTlsConfig.setRandomizedMacAddress(TEST_LOCAL_MAC_ADDRESS); ++ eapTlsConfig.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO; + + initializeAndAddNetworkAndVerifySuccess(eapTlsConfig); + +@@ -7879,31 +7879,32 @@ public class ClientModeImplTest extends WifiBaseTest { + } + verify(mInsecureEapNetworkHandler).prepareConnection(eq(eapTlsConfig)); + +- 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.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, ++ new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR, ++ SupplicantState.ASSOCIATED)); ++ mLooper.dispatchAll(); ++ + mCmi.sendMessage(WifiMonitor.TOFU_ROOT_CA_CERTIFICATE, + FRAMEWORK_NETWORK_ID, 0, FakeKeys.CA_CERT0); + mLooper.dispatchAll(); +- verify(mInsecureEapNetworkHandler).setPendingCertificate( ++ verify(mInsecureEapNetworkHandler).addPendingCertificate( + eq(eapTlsConfig.SSID), eq(0), eq(FakeKeys.CA_CERT0)); +- } + +- 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(); ++ // 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(); ++ } + + verify(mInsecureEapNetworkHandler).startUserApprovalIfNecessary(eq(isUserSelected)); +- assertEquals("L3ProvisioningState", getCurrentState().getName()); +- ++ if (isTrustOnFirstUseSupported) { ++ assertEquals("DisconnectedState", getCurrentState().getName()); ++ } + return eapTlsConfig; + } + +@@ -7919,9 +7920,7 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + mLooper.dispatchAll(); +- injectDhcpSuccess(); +- mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + } + + /** +@@ -7934,9 +7933,15 @@ public class ClientModeImplTest extends WifiBaseTest { + assumeTrue(SdkLevel.isAtLeastT()); + WifiConfiguration testConfig = setupTrustOnFirstUse(true, true, true); + +- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); ++ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID, false); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -7951,7 +7956,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -7967,9 +7978,7 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + mLooper.dispatchAll(); +- injectDhcpSuccess(); +- mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiConnectivityManager).forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + } + + /** +@@ -7983,9 +7992,15 @@ public class ClientModeImplTest extends WifiBaseTest { + assumeTrue(SdkLevel.isAtLeastT()); + WifiConfiguration testConfig = setupTrustOnFirstUse(true, true, false); + +- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); ++ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID, false); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -8000,7 +8015,13 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); + mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); ++ 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()); + } + + /** +@@ -8015,9 +8036,8 @@ public class ClientModeImplTest extends WifiBaseTest { + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); + mLooper.dispatchAll(); +- injectDhcpSuccess(); +- mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiMetrics, never()).endConnectionEvent( ++ any(), anyInt(), anyInt(), anyInt(), anyInt()); + } + + /** +@@ -8030,23 +8050,10 @@ public class ClientModeImplTest extends WifiBaseTest { + assumeFalse(SdkLevel.isAtLeastT()); + WifiConfiguration testConfig = setupLegacyEapNetworkTest(true); + +- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); +- mLooper.dispatchAll(); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); +- } +- +- /** +- * Verify legacy EAP network handling. +- * - This network is automatically connected. +- * - Errors occur in InsecureEapNetworkHandler. +- */ +- @Test +- public void verifyLegacyEapNetworkErrorWhenConnectByUser() throws Exception { +- assumeFalse(SdkLevel.isAtLeastT()); +- WifiConfiguration testConfig = setupLegacyEapNetworkTest(true); +- +- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); ++ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID, true); + mLooper.dispatchAll(); ++ verify(mWifiConnectivityManager, never()) ++ .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); + } + +@@ -8061,40 +8068,26 @@ public class ClientModeImplTest extends WifiBaseTest { + WifiConfiguration testConfig = setupLegacyEapNetworkTest(false); + + mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onAccept(testConfig.SSID); +- injectDhcpSuccess(); + mLooper.dispatchAll(); +- assertEquals("L3ConnectedState", getCurrentState().getName()); ++ verify(mWifiMetrics, never()).endConnectionEvent( ++ any(), anyInt(), anyInt(), anyInt(), anyInt()); + } + + /** + * Verify legacy EAP network handling. + * - This network is automatically connected. +- * - Tap "Don't connect" on the notification ++ * - Tap "Disconnect now" on the notification + */ + @Test + public void verifyLegacyEapNetworkRejectOnNotificationWhenAutoConnect() throws Exception { + assumeFalse(SdkLevel.isAtLeastT()); + WifiConfiguration testConfig = setupLegacyEapNetworkTest(false); + +- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID); ++ mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onReject(testConfig.SSID, true); + mLooper.dispatchAll(); +- + verify(mFrameworkFacade, never()).makeAlertDialogBuilder(any()); +- verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); +- } +- +- /** +- * Verify legacy EAP network handling. +- * - This network is automatically connected. +- * - Errors occur in InsecureEapNetworkHandler. +- */ +- @Test +- public void verifyLegacyEapNetworkErrorWhenAutoConnect() throws Exception { +- assumeFalse(SdkLevel.isAtLeastT()); +- WifiConfiguration testConfig = setupLegacyEapNetworkTest(false); +- +- mCmi.mInsecureEapNetworkHandlerCallbacksImpl.onError(testConfig.SSID); +- mLooper.dispatchAll(); ++ verify(mWifiConnectivityManager, never()) ++ .forceConnectivityScan(eq(ClientModeImpl.WIFI_WORK_SOURCE)); + verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME)); + } + +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 aed3753ffc..b83f6e7e6c 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java +@@ -16,15 +16,20 @@ + + package com.android.server.wifi; + ++import static com.android.server.wifi.InsecureEapNetworkHandler.TOFU_ANONYMOUS_IDENTITY; ++ + import static org.junit.Assert.assertEquals; ++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; +@@ -37,11 +42,15 @@ 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.wifi.resources.R; + + import org.junit.After; + import org.junit.Before; +@@ -51,9 +60,13 @@ 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}. + */ +@@ -65,7 +78,11 @@ 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_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"; + + @Mock WifiContext mContext; + @Mock WifiConfigManager mWifiConfigManager; +@@ -94,11 +111,34 @@ 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 -> ++ "SHA-256 Fingerprint:\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); +@@ -205,8 +245,11 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); +- assertTrue(mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); ++ mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected); + verify(mCallbacks).onError(eq(config.SSID)); ++ verify(mWifiConfigManager, atLeastOnce()).updateNetworkSelectionStatus(eq(config.networkId), ++ eq(WifiConfiguration.NetworkSelectionStatus ++ .DISABLED_BY_WIFI_MANAGER)); + } + + /** +@@ -220,7 +263,7 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); +- assertTrue(mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); ++ mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected); + verify(mCallbacks, never()).onError(any()); + } + +@@ -311,9 +354,40 @@ 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)))); ++ try { ++ when(mockCert.getEncoded()).thenReturn(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); ++ } catch (Exception e) { ++ // nothing ++ } ++ 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.TLS, WifiEnterpriseConfig.Phase2.NONE)); ++ WifiEnterpriseConfig.Eap.TTLS, WifiEnterpriseConfig.Phase2.MSCHAPV2)); + config.networkId = FRAMEWORK_NETWORK_ID; + config.SSID = TEST_SSID; + if (isAtLeastT) { +@@ -321,6 +395,8 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + } + config.enterpriseConfig.setCaPath(""); + config.enterpriseConfig.setDomainSuffixMatch(""); ++ config.enterpriseConfig.setIdentity(TEST_IDENTITY); ++ config.enterpriseConfig.setPassword(TEST_PASSWORD); + return config; + } + +@@ -338,14 +414,34 @@ 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()); ++ assertTrue(TextUtils.isEmpty(config.enterpriseConfig.getAnonymousIdentity())); ++ assertEquals(TEST_PASSWORD, config.enterpriseConfig.getPassword()); ++ } + mInsecureEapNetworkHandler.prepareConnection(config); + ++ if (isTrustOnFirstUseSupported && config.enterpriseConfig.isTrustOnFirstUseEnabled() ++ && (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())); ++ assertEquals(TOFU_ANONYMOUS_IDENTITY, config.enterpriseConfig.getAnonymousIdentity()); ++ assertTrue(TextUtils.isEmpty(config.enterpriseConfig.getPassword())); ++ } ++ + if (isTrustOnFirstUseSupported && config.enterpriseConfig.isTrustOnFirstUseEnabled()) { + verify(mContext, atLeastOnce()).registerReceiver( + mBroadcastReceiverCaptor.capture(), +@@ -379,34 +475,13 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + +- 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); ++ X509Certificate mockCaCert = generateMockCert("ca", "ca", true); ++ X509Certificate mockServerCert = generateMockCert("server", "ca", false); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, mockCaCert); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert); + + verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported, +- isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CLIENT_CERT); ++ isUserSelected, needUserApproval, mockCaCert, mockServerCert); + } + + /** +@@ -424,10 +499,11 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); ++ X509Certificate mockSelfSignedCert = generateMockCert("self", "self", false); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockSelfSignedCert); + + verifyTrustOnFirstUseFlow(config, ACTION_ACCEPT, isTrustOnFirstUseSupported, +- isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CA_CERT0); ++ isUserSelected, needUserApproval, mockSelfSignedCert, mockSelfSignedCert); + } + + /** +@@ -440,18 +516,19 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + public void verifyOnErrorWithoutCert() throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true; +- boolean needUserApproval = true; + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + +- assertEquals(needUserApproval, +- mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); ++ 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 the connection should be terminated. ++ * Verify that the connection should be upgraded to TOFU. + * - TOFU is supported. + * - Insecure EAP network is not allowed. + * - TOFU is not enabled +@@ -461,17 +538,18 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true; +- boolean needUserApproval = true; + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + config.enterpriseConfig.enableTrustOnFirstUse(false); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, ++ generateMockCert("ca", "ca", true)); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, ++ generateMockCert("server", "ca", false)); + +- assertEquals(needUserApproval, +- mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); +- verify(mCallbacks).onError(eq(config.SSID)); ++ mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected); ++ assertTrue(config.enterpriseConfig.isTrustOnFirstUseEnabled()); + } + + /** +@@ -479,51 +557,179 @@ 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 = true, isInsecureEnterpriseConfigurationAllowed = true; ++ boolean isInsecureEnterpriseConfigurationAllowed = true; + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + config.enterpriseConfig.enableTrustOnFirstUse(false); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported, + isInsecureEnterpriseConfigurationAllowed); + +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CA_CERT0); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, ++ generateMockCert("ca", "ca", true)); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, ++ generateMockCert("server", "ca", false)); + +- assertEquals(needUserApproval, +- mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); ++ 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 ++ 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); ++ ++ 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); ++ ++ 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); ++ 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); ++ 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.setPendingCertificate(config.SSID, 2, FakeKeys.CA_CERT0); +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 1, FakeKeys.CA_CERT1); +- mInsecureEapNetworkHandler.setPendingCertificate(config.SSID, 0, FakeKeys.CLIENT_CERT); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 2, mockCaCert); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 1, ++ generateMockCert("middle", "ca", false)); ++ mInsecureEapNetworkHandler.addPendingCertificate(config.SSID, 0, mockServerCert); + } + verifyTrustOnFirstUseFlow(config, action, isTrustOnFirstUseSupported, +- isUserSelected, needUserApproval, FakeKeys.CA_CERT0, FakeKeys.CLIENT_CERT); ++ isUserSelected, needUserApproval, mockCaCert, mockServerCert); + } + + private void verifyTrustOnFirstUseFlow(WifiConfiguration config, + int action, boolean isTrustOnFirstUseSupported, boolean isUserSelected, + boolean needUserApproval, X509Certificate expectedCaCert, + X509Certificate expectedServerCert) throws Exception { +- assertEquals(needUserApproval, +- mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected)); ++ mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected); + ++ ArgumentCaptor dialogMessageCaptor = ArgumentCaptor.forClass(String.class); + if (isUserSelected) { + ArgumentCaptor dialogCallbackCaptor = + ArgumentCaptor.forClass(WifiDialogManager.SimpleDialogCallback.class); + verify(mWifiDialogManager).createSimpleDialogWithUrl( +- any(), any(), any(), anyInt(), anyInt(), any(), any(), any(), +- dialogCallbackCaptor.capture(), any()); ++ any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(), any(), ++ any(), dialogCallbackCaptor.capture(), any()); ++ if (isTrustOnFirstUseSupported) { ++ assertTofuDialogMessage(expectedCaCert, expectedServerCert, ++ dialogMessageCaptor.getValue()); ++ } + if (action == ACTION_ACCEPT) { + dialogCallbackCaptor.getValue().onPositiveButtonClicked(); + } else if (action == ACTION_REJECT) { +@@ -533,6 +739,7 @@ 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) { +@@ -543,8 +750,10 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + ArgumentCaptor dialogCallbackCaptor = + ArgumentCaptor.forClass(WifiDialogManager.SimpleDialogCallback.class); + verify(mWifiDialogManager).createSimpleDialogWithUrl( +- any(), any(), any(), anyInt(), anyInt(), any(), any(), any(), +- dialogCallbackCaptor.capture(), any()); ++ any(), dialogMessageCaptor.capture(), any(), anyInt(), anyInt(), any(), ++ any(), any(), dialogCallbackCaptor.capture(), any()); ++ assertTofuDialogMessage(expectedCaCert, expectedServerCert, ++ dialogMessageCaptor.getValue()); + if (action == ACTION_ACCEPT) { + dialogCallbackCaptor.getValue().onPositiveButtonClicked(); + } else if (action == ACTION_REJECT) { +@@ -566,7 +775,8 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + } + + if (action == ACTION_ACCEPT) { +- verify(mWifiConfigManager).allowAutojoin(eq(config.networkId), eq(true)); ++ verify(mWifiConfigManager).updateNetworkSelectionStatus(eq(config.networkId), ++ eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE)); + if (isTrustOnFirstUseSupported) { + verify(mWifiConfigManager).updateCaCertificate( + eq(config.networkId), eq(expectedCaCert), eq(expectedServerCert)); +@@ -576,8 +786,11 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + } + verify(mCallbacks).onAccept(eq(config.SSID)); + } else if (action == ACTION_REJECT) { +- verify(mWifiConfigManager).allowAutojoin(eq(config.networkId), eq(false)); +- verify(mCallbacks).onReject(eq(config.SSID)); ++ verify(mWifiConfigManager, atLeastOnce()) ++ .updateNetworkSelectionStatus(eq(config.networkId), ++ eq(WifiConfiguration.NetworkSelectionStatus ++ .DISABLED_BY_WIFI_MANAGER)); ++ verify(mCallbacks).onReject(eq(config.SSID), eq(!isTrustOnFirstUseSupported)); + } else if (action == ACTION_TAP) { + verify(mWifiDialogManager).createSimpleDialogWithUrl( + any(), any(), any(), anyInt(), anyInt(), any(), any(), any(), any(), any()); +@@ -586,4 +799,47 @@ 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)); ++ } ++ } ++ ++ @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); ++ } ++ ++ /** ++ * Verify the getDigest and fingerprint methods ++ */ ++ @Test ++ public void verifyGetDigest() throws Exception { ++ X509Certificate mockServerCert = generateMockCert("server", "ca", false); ++ assertEquals(mInsecureEapNetworkHandler.getDigest(mockServerCert, "SHA256"), ++ TEST_EXPECTED_SHA_256_SIGNATURE); ++ } + } +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 efb62b127f..f8c9123694 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +@@ -45,6 +45,7 @@ import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + import static org.mockito.Mockito.withSettings; + ++import android.Manifest; + import android.annotation.Nullable; + import android.app.ActivityManager; + import android.app.test.MockAnswerUtil.AnswerWithArguments; +@@ -7665,4 +7666,72 @@ public class WifiConfigManagerTest extends WifiBaseTest { + assertEquals(TEST_UPDATE_NAME, mWifiConfigManager + .getConfiguredNetwork(openNetId).creatorName); + } ++ ++ /** ++ * Verify that if the caller has NETWORK_SETTINGS permission, and the overlay ++ * config_wifiAllowInsecureEnterpriseConfigurationsForSettingsAndSUW is set, then it can add an ++ * insecure Enterprise network, with Root CA certificate not set and/or domain name not set. ++ */ ++ @Test ++ public void testAddInsecureEnterpriseNetworkWithNetworkSettingsPerm() throws Exception { ++ when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), ++ anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); ++ when(mContext.checkPermission(eq(Manifest.permission.NETWORK_SETUP_WIZARD), ++ anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); ++ ++ // First set flag to not allow ++ when(mWifiGlobals.isInsecureEnterpriseConfigurationAllowed()).thenReturn(false); ++ ++ // Create an insecure Enterprise network ++ WifiConfiguration config = WifiConfigurationTestUtil.createEapNetwork(); ++ config.enterpriseConfig.setCaPath(null); ++ config.enterpriseConfig.setDomainSuffixMatch(null); ++ assertFalse(config.enterpriseConfig.isUserApproveNoCaCert()); ++ ++ // Verify operation fails ++ NetworkUpdateResult result = addNetworkToWifiConfigManager(config); ++ assertFalse(result.isSuccess()); ++ ++ // Set flag to allow ++ when(mWifiGlobals.isInsecureEnterpriseConfigurationAllowed()).thenReturn(true); ++ ++ // Verify operation succeeds ++ NetworkUpdateResult res = addNetworkToWifiConfigManager(config); ++ assertTrue(res.isSuccess()); ++ config = mWifiConfigManager.getConfiguredNetwork(res.getNetworkId()); ++ assertNotNull(config); ++ assertTrue(config.enterpriseConfig.isUserApproveNoCaCert()); ++ } ++ ++ /** ++ * Verify that if the caller does NOT have NETWORK_SETTINGS permission, then it cannot add an ++ * insecure Enterprise network, with Root CA certificate not set and/or domain name not set, ++ * regardless of the overlay config_wifiAllowInsecureEnterpriseConfigurationsForSettingsAndSUW ++ * value. ++ */ ++ @Test ++ public void testAddInsecureEnterpriseNetworkWithNoNetworkSettingsPerm() throws Exception { ++ when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), ++ anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); ++ when(mContext.checkPermission(eq(Manifest.permission.NETWORK_SETUP_WIZARD), ++ anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); ++ ++ // First set flag to not allow ++ when(mWifiGlobals.isInsecureEnterpriseConfigurationAllowed()).thenReturn(false); ++ ++ // Create an insecure Enterprise network ++ WifiConfiguration config = WifiConfigurationTestUtil.createEapNetwork(); ++ config.enterpriseConfig.setCaPath(null); ++ config.enterpriseConfig.setDomainSuffixMatch(null); ++ ++ // Verify operation fails ++ NetworkUpdateResult result = addNetworkToWifiConfigManager(config); ++ assertFalse(result.isSuccess()); ++ ++ // Set flag to allow ++ when(mWifiGlobals.isInsecureEnterpriseConfigurationAllowed()).thenReturn(true); ++ ++ // Verify operation still fails ++ assertFalse(addNetworkToWifiConfigManager(config).isSuccess()); ++ } + } +diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java +index eefa46bb7c..9dc610b275 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java +@@ -191,6 +191,7 @@ public class WifiConfigurationTestUtil { + if ((security & SECURITY_EAP_SUITE_B) != 0) { + config.addSecurityParams( + WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT); ++ config.enterpriseConfig.setDomainSuffixMatch(TEST_DOM_SUBJECT_MATCH); + } + + if ((security & SECURITY_WAPI_PSK) != 0) { +diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java +index 9de443def4..37fbb8f7b2 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java +@@ -307,6 +307,37 @@ public class WifiKeyStoreTest extends WifiBaseTest { + savedNetwork.allowedSuiteBCiphers.get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA)); + } + ++ /** ++ * Test configuring WPA3-Enterprise in 192-bit mode for RSA 3072 correctly when CA and client ++ * certificates are of RSA 3072 type and the network is Suite-B. ++ */ ++ @Test ++ public void testConfigureSuiteBRsa3072UserAndTofu() throws Exception { ++ // No Root CA certificates, but TOFU is on - Setting the suite-b mode by the user cert ++ when(mWifiEnterpriseConfig.getCaCertificateAliases()) ++ .thenReturn(null); ++ when(mWifiEnterpriseConfig.getCaCertificate()).thenReturn(null); ++ when(mWifiEnterpriseConfig.getCaCertificates()) ++ .thenReturn(null); ++ when(mWifiEnterpriseConfig.isTrustOnFirstUseEnabled()).thenReturn(true); ++ ++ when(mWifiEnterpriseConfig.isEapMethodServerCertUsed()).thenReturn(true); ++ when(mWifiEnterpriseConfig.getClientPrivateKey()) ++ .thenReturn(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY); ++ when(mWifiEnterpriseConfig.getClientCertificate()).thenReturn( ++ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT); ++ when(mWifiEnterpriseConfig.getClientCertificateChain()) ++ .thenReturn(new X509Certificate[]{FakeKeys.CLIENT_SUITE_B_RSA3072_CERT}); ++ when(mKeyStore.getCertificate(eq(USER_CERT_ALIAS))).thenReturn( ++ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT); ++ WifiConfiguration savedNetwork = WifiConfigurationTestUtil.createEapSuiteBNetwork( ++ WifiConfiguration.SuiteBCipher.ECDHE_RSA); ++ savedNetwork.enterpriseConfig = mWifiEnterpriseConfig; ++ assertTrue(mWifiKeyStore.updateNetworkKeys(savedNetwork, null)); ++ assertTrue(savedNetwork.allowedSuiteBCiphers.get(WifiConfiguration.SuiteBCipher.ECDHE_RSA)); ++ } ++ ++ + /** + * Test configuring WPA3-Enterprise in 192-bit mode for RSA 3072 fails when CA and client + * certificates are not of the same type. diff --git a/Patches/LineageOS-20.0/android_packages_services_Telecomm/ASB-2023-06/0001-Call-Redirection-unbind-service-when-onBind-returns-.patch b/Patches/LineageOS-20.0/android_packages_services_Telecomm/ASB-2023-06/0001-Call-Redirection-unbind-service-when-onBind-returns-.patch new file mode 100644 index 00000000..4b753393 --- /dev/null +++ b/Patches/LineageOS-20.0/android_packages_services_Telecomm/ASB-2023-06/0001-Call-Redirection-unbind-service-when-onBind-returns-.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Pranav Madapurmath +Date: Tue, 21 Mar 2023 23:28:56 +0000 +Subject: [PATCH] Call Redirection: unbind service when onBind returns null + +The call redirection service does not handle the corner case of +onNullBinding (occurs when onBind returns null). This vulnerability +would give the app that has the call redirection role unintentional +access to launch background activities outside the scope of a call +lifecycle. + +Fixes: 273260090 +Test: Unit test to ensure we unbind the service on null onBind +Test: CTS for similar assertion +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:9b753a1d0d1e563b3363ecd49f7f9d0100200cab) +Merged-In: Ib9d44d239833131eb055e83801cb635e8efe0b81 +Change-Id: Ib9d44d239833131eb055e83801cb635e8efe0b81 +--- + .../CallRedirectionProcessor.java | 13 ++++++++++ + .../tests/CallRedirectionProcessorTest.java | 24 +++++++++++++++++++ + 2 files changed, 37 insertions(+) + +diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java +index adeb3113d..226382bde 100644 +--- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java ++++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java +@@ -162,6 +162,19 @@ public class CallRedirectionProcessor implements CallRedirectionCallback { + Log.endSession(); + } + } ++ ++ @Override ++ public void onNullBinding(ComponentName componentName) { ++ // Make sure we unbind the service if onBind returns null ++ Log.startSession("CRSC.oNB"); ++ try { ++ synchronized (mTelecomLock) { ++ finishCallRedirection(); ++ } ++ } finally { ++ Log.endSession(); ++ } ++ } + } + + private class CallRedirectionAdapter extends ICallRedirectionAdapter.Stub { +diff --git a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java +index 0a896a8ce..f2fe045ef 100644 +--- a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java ++++ b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java +@@ -352,4 +352,28 @@ public class CallRedirectionProcessorTest extends TelecomTestCase { + assertEquals(REDIRECTED_GATEWAY_NUMBER_WITH_POST_DIAL, + gatewayInfoArgumentCaptor.getValue().getGatewayAddress()); + } ++ ++ @Test ++ public void testUnbindOnNullBind() throws Exception { ++ startProcessWithNoGateWayInfo(); ++ // To make sure tests are not flaky, clean all the previous handler messages ++ waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY); ++ enableUserDefinedCallRedirectionService(); ++ disableCarrierCallRedirectionService(); ++ ++ mProcessor.performCallRedirection(); ++ ++ // Capture the binder ++ ArgumentCaptor serviceConnectionCaptor = ArgumentCaptor.forClass( ++ ServiceConnection.class); ++ // Verify binding occurred ++ verify(mContext, times(1)).bindServiceAsUser(any(Intent.class), ++ serviceConnectionCaptor.capture(), anyInt(), eq(UserHandle.CURRENT)); ++ // Simulate null return from onBind ++ serviceConnectionCaptor.getValue().onNullBinding(USER_DEFINED_SERVICE_TEST_COMPONENT_NAME); ++ ++ // Verify service was unbound ++ verify(mContext, times(1)). ++ unbindService(any(ServiceConnection.class)); ++ } + } diff --git a/Scripts/Common/Fix_CVE_Patchers.sh b/Scripts/Common/Fix_CVE_Patchers.sh index 6ef76e3a..b6eb7146 100644 --- a/Scripts/Common/Fix_CVE_Patchers.sh +++ b/Scripts/Common/Fix_CVE_Patchers.sh @@ -68,7 +68,7 @@ commentPatches android_kernel_htc_msm8974.sh "CVE-2016-8393" "CVE-2022-22058"; commentPatches android_kernel_htc_msm8994.sh "CVE-2016-8394/ANY/0001.patch" "CVE-2017-13166" "CVE-2018-3585" "CVE-2018-9514"; commentPatches android_kernel_lge_bullhead.sh "CVE-2014-8559"; commentPatches android_kernel_lge_msm8992.sh "CVE-2018-5897" "CVE-2018-11266"; -commentPatches android_kernel_lge_msm8996.sh "0008-Graphene-Kernel_Hardening-canaries/4.4/0002.patch" "CVE-2023-31084/^6.4/0001.patch"; +commentPatches android_kernel_lge_msm8996.sh "0008-Graphene-Kernel_Hardening-canaries/4.4/0002.patch"; commentPatches android_kernel_moto_shamu.sh "CVE-2014-8559"; commentPatches android_kernel_motorola_msm8916.sh "0001-LinuxIncrementals/3.10/3.10.0050-0051.patch" "CVE-2014-8559" "CVE-2017-15817" "CVE-2018-9514"; commentPatches android_kernel_motorola_msm8974.sh "CVE-2016-5696" "CVE-2017-7373" "CVE-2017-17770/3.4/0002.patch" "CVE-2019-11599" "CVE-2022-22058"; @@ -94,13 +94,13 @@ commentPatches android_kernel_samsung_tuna.sh "CVE-2012-2127"; commentPatches android_kernel_samsung_universal8890.sh "0008-Graphene-Kernel_Hardening-ro" "CVE-2016-7917" "CVE-2018-1092" "CVE-2018-17972" "CVE-2019-16746" "CVE-2020-0427" "CVE-2020-14381" "CVE-2020-16166" "CVE-2022-42896/4.9"; commentPatches android_kernel_samsung_exynos9810.sh "CVE-2020-1749" "CVE-2019-ctnl-addr-leak" "CVE-2019-18282" "CVE-2019-11599" "CVE-2022-20566" "CVE-2019-16746" "CVE-2021-45469" "CVE-2020-0305"; commentPatches android_kernel_samsung_universal9810.sh "CVE-2020-1749"; -commentPatches android_kernel_sony_sdm660.sh "0008-Graphene-Kernel_Hardening-canaries/4.4/0002.patch" "CVE-2019-19319" "CVE-2020-0305" "CVE-2020-8992" "CVE-2020-16166" "CVE-2023-31084/^6.4/0001.patch"; +commentPatches android_kernel_sony_sdm660.sh "0008-Graphene-Kernel_Hardening-canaries/4.4/0002.patch" "CVE-2019-19319" "CVE-2020-0305" "CVE-2020-8992" "CVE-2020-16166"; commentPatches android_kernel_sony_sdm845.sh "CVE-2019-19319" "CVE-2020-1749" "CVE-2020-8992"; commentPatches android_kernel_xiaomi_msm8937.sh "CVE-2017-13162" "CVE-2019-14070" "CVE-2019-16746" "CVE-2020-0427" "CVE-2020-16166" "CVE-2021-39715/ANY/0001.patch" "CVE-2022-25715"; -commentPatches android_kernel_xiaomi_sdm660.sh "0008-Graphene-Kernel_Hardening-canaries/4.4/0002.patch" "CVE-2023-31084/^6.4/0001.patch"; +commentPatches android_kernel_xiaomi_sdm660.sh "0008-Graphene-Kernel_Hardening-canaries/4.4/0002.patch"; commentPatches android_kernel_xiaomi_sm8150.sh "CVE-2020-24588/4.14/0018.patch"; commentPatches android_kernel_xiaomi_sm8250.sh "CVE-2018-5873" "CVE-2020-1749" "CVE-2021-3444" "CVE-2021-3600" "CVE-2022-22075"; -commentPatches android_kernel_yandex_sdm660.sh "CVE-2019-11599" "CVE-2019-14070/ANY/0005.patch" "CVE-2019-19319" "CVE-2020-1749" "CVE-2020-8992" "CVE-2020-16166" "CVE-2023-31084/^6.4/0001.patch"; +commentPatches android_kernel_yandex_sdm660.sh "CVE-2019-11599" "CVE-2019-14070/ANY/0005.patch" "CVE-2019-19319" "CVE-2020-1749" "CVE-2020-8992" "CVE-2020-16166"; commentPatches android_kernel_zte_msm8930.sh "CVE-2015-2922" "CVE-2017-11015/prima"; commentPatches android_kernel_zte_msm8996.sh "0001-LinuxIncrementals/3.18/3.18.0098-0099.patch" "CVE-2017-13162" "CVE-2017-15951" "CVE-2017-16939" "CVE-2018-17972" "CVE-2019-2214" "CVE-2019-14070" "CVE-2019-16746" "CVE-2020-0427" "CVE-2020-14381" "CVE-2020-16166" "CVE-2021-39715/ANY/0001.patch" "CVE-2022-42896/4.9"; commentPatches android_kernel_zuk_msm8996.sh "0008-Graphene-Kernel_Hardening-slab" "CVE-2019-19319" "CVE-2020-0305" "CVE-2020-1749" "CVE-2020-8992" "CVE-2020-1616"; @@ -140,7 +140,7 @@ done declare -a fourDotNine=("${fourDotFour[@]}" "android_kernel_fairphone_sdm632.sh" "android_kernel_google_msm-4.9.sh" "android_kernel_oneplus_sdm845.sh" "android_kernel_razer_sdm845.sh" "android_kernel_samsung_exynos9810.sh" "android_kernel_samsung_universal9810.sh" "android_kernel_sony_sdm845.sh" "android_kernel_xiaomi_msm8937.sh" "android_kernel_xiaomi_sdm845.sh"); for script in "${fourDotNine[@]}" do - commentPatches $script "CVE-2018-11412/4.14" "CVE-2020-0067/4.14" "CVE-2022-1204/4.14" "CVE-2023-0461/4.14"; #handle 4.14 + commentPatches $script "CVE-2018-11412/4.14" "CVE-2020-0067/4.14" "CVE-2022-1204/4.14" "CVE-2023-0461/4.14" "CVE-2023-31084/^6.4/0001.patch"; #handle 4.14 done echo -e "\e[0;32m[SCRIPT COMPLETE] Fixed CVE patchers\e[0m"; diff --git a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_google_marlin.sh b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_google_marlin.sh index 2eefd1c4..f373620d 100644 --- a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_google_marlin.sh +++ b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_google_marlin.sh @@ -522,7 +522,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-20941/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/Untracked-01/ANY/0002-ozwpan-Use-unsigned-ints-to-prevent-heap-overflow.patch git apply $DOS_PATCHES_LINUX_CVES/Untracked-01/ANY/0005-tcp-fix-zero-cwnd-in-tcp_cwnd_reduction.patch diff --git a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_motorola_msm8996.sh b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_motorola_msm8996.sh index 30a47b02..624ae817 100644 --- a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_motorola_msm8996.sh +++ b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_motorola_msm8996.sh @@ -535,7 +535,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-20941/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2017-0610/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2017-15815/qcacld-2.0/0002.patch --directory=drivers/staging/qcacld-2.0 diff --git a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_oneplus_msm8996.sh b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_oneplus_msm8996.sh index 3e6a004b..17040567 100644 --- a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_oneplus_msm8996.sh +++ b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_oneplus_msm8996.sh @@ -523,7 +523,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-20941/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2017-0610/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2019-14283/3.18/0004.patch diff --git a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_zuk_msm8996.sh b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_zuk_msm8996.sh index bec0bf80..32144b66 100644 --- a/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_zuk_msm8996.sh +++ b/Scripts/LineageOS-18.1/CVE_Patchers/android_kernel_zuk_msm8996.sh @@ -432,7 +432,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-26545/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28772/4.4/0004.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.4/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2020-0429/4.4/0012.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_essential_msm8998.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_essential_msm8998.sh index 059c6541..561d9539 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_essential_msm8998.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_essential_msm8998.sh @@ -209,7 +209,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-26545/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.4/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-ro/4.9/0016.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sdm632.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sdm632.sh index 67c638d6..8509225a 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sdm632.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sdm632.sh @@ -96,7 +96,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-fortify/4.9/0003.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sm7225.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sm7225.sh index 5683a0ee..1e4def1c 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sm7225.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fairphone_sm7225.sh @@ -73,7 +73,6 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-4662/4.19/0004.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-20148/^5.15/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-20571/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-27950/^5.16/0001.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-42703/4.19/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-0030/^4.20/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-0386/^6.2/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1380/4.19/0003.patch @@ -82,8 +81,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.19/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23000/^5.16/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32233/4.19/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.19/0003.patch -editKernelLocalversion "-dos.p83" +editKernelLocalversion "-dos.p81" else echo "kernel_fairphone_sm7225 is unavailable, not patching."; fi; cd "$DOS_BUILD_BASE" diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_msm8998.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_msm8998.sh index 4d1d1950..44d1b023 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_msm8998.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_msm8998.sh @@ -162,7 +162,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-26545/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.4/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/^6.4/0001.patch editKernelLocalversion "-dos.p165" diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_sm6115.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_sm6115.sh index 1a56d3e6..6cbe593a 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_sm6115.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_fxtec_sm6115.sh @@ -73,7 +73,6 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-4662/4.19/0004.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-20148/^5.15/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-20571/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-27950/^5.16/0001.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-42703/4.19/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-0030/^4.20/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-0386/^6.2/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1380/4.19/0003.patch @@ -82,8 +81,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.19/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23000/^5.16/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32233/4.19/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.19/0003.patch -editKernelLocalversion "-dos.p83" +editKernelLocalversion "-dos.p81" else echo "kernel_fxtec_sm6115 is unavailable, not patching."; fi; cd "$DOS_BUILD_BASE" diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_msm-4.9.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_msm-4.9.sh index fb5a14c1..0264ab68 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_msm-4.9.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_msm-4.9.sh @@ -102,7 +102,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-fortify/4.9/0003.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_wahoo.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_wahoo.sh index bfa68337..e80b5e1b 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_wahoo.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_google_wahoo.sh @@ -172,7 +172,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-26545/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.4/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-ro/4.9/0016.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_msm8998.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_msm8998.sh index 065b8dde..3c811198 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_msm8998.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_msm8998.sh @@ -163,7 +163,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-26545/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.4/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/^6.4/0001.patch editKernelLocalversion "-dos.p166" diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sdm845.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sdm845.sh index 27dc133f..68a16204 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sdm845.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sdm845.sh @@ -96,7 +96,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-fortify/4.9/0003.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8250.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8250.sh index f5899872..551eb56e 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8250.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8250.sh @@ -71,7 +71,6 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-4662/4.19/0004.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-20148/^5.15/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-20571/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-27950/^5.16/0001.patch -#git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-42703/4.19/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-0030/^4.20/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-0386/^6.2/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1380/4.19/0003.patch @@ -80,8 +79,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.19/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23000/^5.16/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32233/4.19/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.19/0003.patch -editKernelLocalversion "-dos.p81" +editKernelLocalversion "-dos.p79" else echo "kernel_oneplus_sm8250 is unavailable, not patching."; fi; cd "$DOS_BUILD_BASE" diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8350.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8350.sh index 232d22bd..f9a116fb 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8350.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_oneplus_sm8350.sh @@ -1,7 +1,6 @@ #!/bin/bash if cd "$DOS_BUILD_BASE""kernel/oneplus/sm8350"; then git apply $DOS_PATCHES_LINUX_CVES/0003-syzkaller-Misc/ANY/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/0003-syzkaller-Misc2/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-misc/ANY/0015.patch git apply $DOS_PATCHES_LINUX_CVES/0009-rfc4941bis/5.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2016-3695/ANY/0001.patch @@ -25,36 +24,18 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-3061/^5.18/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-3108/^5.16/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-3903/^6.0/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-4662/5.4/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-4744/5.4/0005.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-27950/^5.16/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-39189/5.4/0004.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-42703/5.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2022-OctWirelessASB/ANY/0009.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-0386/^6.2/0001.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1281/^6.2/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1380/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1670/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1855/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1859/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1989/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1990/5.4/0007.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-1998/5.4/0006.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2002/3.10-^6.3/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2166/5.4/0004.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2194/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2248/5.4/0006.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2483/5.4/0006.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/5.4/0007.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-21630/ANY/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23000/^5.16/0001.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28466/5.4/0004.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30456/5.4/0004.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/5.4/0006.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32233/5.4/0005.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/5.4/0006.patch -editKernelLocalversion "-dos.p54" +editKernelLocalversion "-dos.p35" else echo "kernel_oneplus_sm8350 is unavailable, not patching."; fi; cd "$DOS_BUILD_BASE" diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_msm8998.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_msm8998.sh index c37f7b07..c31ddd1d 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_msm8998.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_msm8998.sh @@ -162,7 +162,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-26545/4.4/0007.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.4/0008.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/^6.4/0001.patch editKernelLocalversion "-dos.p165" diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_sdm845.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_sdm845.sh index ea9eaa2b..fdae4ef2 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_sdm845.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_razer_sdm845.sh @@ -96,7 +96,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-fortify/4.9/0003.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_samsung_exynos9810.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_samsung_exynos9810.sh index 6c76d792..719c30df 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_samsung_exynos9810.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_samsung_exynos9810.sh @@ -578,7 +578,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.9/0005.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28772/4.9/0005.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-ro/4.9/0016.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_sony_sdm845.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_sony_sdm845.sh index 06e9f99c..6e28a630 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_sony_sdm845.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_sony_sdm845.sh @@ -411,7 +411,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28328/4.9/0005.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-28772/4.9/0005.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-fortify/4.9/0003.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_msm8937.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_msm8937.sh index 88e1001d..9010b964 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_msm8937.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_msm8937.sh @@ -94,7 +94,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-fortify/4.9/0003.patch diff --git a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_sdm845.sh b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_sdm845.sh index 78d2f16c..68cf25ca 100644 --- a/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_sdm845.sh +++ b/Scripts/LineageOS-20.0/CVE_Patchers/android_kernel_xiaomi_sdm845.sh @@ -98,7 +98,7 @@ git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2269/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-2985/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-23559/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-30772/4.14/0002.patch -git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch +#git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-31084/^6.4/0001.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-32269/4.14/0003.patch git apply $DOS_PATCHES_LINUX_CVES/CVE-2023-34256/4.14/0002.patch git apply $DOS_PATCHES_LINUX_CVES/0008-Graphene-Kernel_Hardening-fortify/4.9/0003.patch diff --git a/Scripts/LineageOS-20.0/Patch.sh b/Scripts/LineageOS-20.0/Patch.sh index df1f8abb..44942065 100644 --- a/Scripts/LineageOS-20.0/Patch.sh +++ b/Scripts/LineageOS-20.0/Patch.sh @@ -97,6 +97,7 @@ applyPatch "$DOS_PATCHES/android_build/0004-Selective_APEX.patch"; #Only enable sed -i '75i$(my_res_package): PRIVATE_AAPT_FLAGS += --auto-add-overlay' core/aapt2.mk; #Enable auto-add-overlay for packages, this allows the vendor overlay to easily work across all branches. sed -i 's/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 23/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 28/' core/version_util.mk; #Set the minimum supported target SDK to Pie (GrapheneOS) #sed -i 's/PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS := true/PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS := false/' core/product_config.mk; #broken by hardenDefconfig +sed -i 's/2023-05-05/2023-06-01/' core/version_defaults.mk; #Bump Security String #T_asb_2023-06 #XXX fi; if enterAndClear "build/soong"; then @@ -122,7 +123,12 @@ sed -i 's/34359738368/2147483648/' Android.bp; #revert 48-bit address space requ fi; fi; +if enterAndClear "frameworks/av"; then +git am $DOS_PATCHES/android_frameworks_av/ASB-2023-06/*.patch; #T_asb_2023-06 +fi; + if enterAndClear "frameworks/base"; then +git am $DOS_PATCHES/android_frameworks_base/ASB-2023-06/*.patch; #T_asb_2023-06 git revert --no-edit d36faad3267522c6d3ff91ba9dcca8f6274bccd1; #Reverts "JobScheduler: Respect allow-in-power-save perm" in favor of below patch git revert --no-edit 90d6826548189ca850d91692e71fcc1be426f453; #Reverts "Remove sensitive info from SUPL requests" in favor of below patch applyPatch "$DOS_PATCHES/android_frameworks_base/0007-Always_Restict_Serial.patch"; #Always restrict access to Build.SERIAL (GrapheneOS) @@ -285,6 +291,8 @@ if [ "$DOS_GRAPHENE_CONSTIFY" = true ]; then applyPatch "$DOS_PATCHES/android_pa fi; if enterAndClear "packages/apps/Settings"; then +git am $DOS_PATCHES/android_packages_apps_Settings/ASB-2023-06/*.patch; #T_asb_2023-06 +git revert --no-edit 41b4ed345a91da1dd46c00ee11a151c2b5ff4f43; applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0004-Private_DNS.patch"; #More 'Private DNS' options (heavily based off of a CalyxOS patch) applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0005-Automatic_Reboot.patch"; #Timeout for reboot (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0006-Bluetooth_Timeout.patch"; #Timeout for Bluetooth (CalyxOS) @@ -308,6 +316,10 @@ if enterAndClear "packages/apps/ThemePicker"; then git revert --no-edit fcf658d2005dc557a95d5a7fb89cb90d06b31d33; #grant permission by default, to prevent crashes, missing previews, and confusion fi; +if enterAndClear "packages/apps/Traceur"; then +git am $DOS_PATCHES/android_packages_apps_Traceur/ASB-2023-06/*.patch; #T_asb_2023-06 +fi; + if enterAndClear "packages/apps/Trebuchet"; then cp $DOS_BUILD_BASE/vendor/divested/overlay/common/packages/apps/Trebuchet/res/xml/default_workspace_*.xml res/xml/; #XXX: Likely no longer needed fi; @@ -324,6 +336,10 @@ applyPatch "$DOS_PATCHES_COMMON/android_packages_inputmethods_LatinIME/0001-Voic applyPatch "$DOS_PATCHES_COMMON/android_packages_inputmethods_LatinIME/0002-Disable_Personalization.patch"; #Disable personalization dictionary by default (GrapheneOS) fi; +if enterAndClear "packages/modules/Bluetooth"; then +git am $DOS_PATCHES/android_packages_modules_Bluetooth/ASB-2023-06/*.patch; #T_asb_2023-06 +fi; + if enterAndClear "packages/modules/Connectivity"; then applyPatch "$DOS_PATCHES/android_packages_modules_Connectivity/0001-Network_Permission-1.patch"; #Skip reportNetworkConnectivity() when permission is revoked (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_modules_Connectivity/0001-Network_Permission-2.patch"; #Enforce INTERNET permission per-uid instead of per-appId (GrapheneOS) @@ -349,6 +365,7 @@ applyPatch "$DOS_PATCHES/android_packages_modules_Permission/0006-Location_Indic fi; if enterAndClear "packages/modules/Wifi"; then +git am $DOS_PATCHES/android_packages_modules_Wifi/ASB-2023-06/*.patch; #T_asb_2023-06 applyPatch "$DOS_PATCHES/android_packages_modules_Wifi/344228.patch"; #wifi: resurrect mWifiLinkLayerStatsSupported counter (sassmann) applyPatch "$DOS_PATCHES/android_packages_modules_Wifi/0001-Random_MAC.patch"; #Add support for always generating new random MAC (GrapheneOS) fi; @@ -357,6 +374,10 @@ if enterAndClear "packages/providers/DownloadProvider"; then applyPatch "$DOS_PATCHES/android_packages_providers_DownloadProvider/0001-Network_Permission.patch"; #Expose the NETWORK permission (GrapheneOS) fi; +if enterAndClear "packages/services/Telecomm"; then +git am $DOS_PATCHES/android_packages_services_Telecomm/ASB-2023-06/*.patch; #T_asb_2023-06 +fi; + #if enterAndClear "packages/providers/TelephonyProvider"; then #cp $DOS_PATCHES_COMMON/android_packages_providers_TelephonyProvider/carrier_list.* assets/latest_carrier_id/; #fi;

=04qhw7U%q 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