Loading wifi/java/src/android/net/wifi/WifiBlobStore.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.net.wifi; package android.net.wifi; import android.os.ServiceManager; import android.security.legacykeystore.ILegacyKeystore; import com.android.internal.net.ConnectivityBlobStore; import com.android.internal.net.ConnectivityBlobStore; /** /** Loading @@ -24,6 +27,7 @@ import com.android.internal.net.ConnectivityBlobStore; */ */ public class WifiBlobStore extends ConnectivityBlobStore { public class WifiBlobStore extends ConnectivityBlobStore { private static final String DB_NAME = "WifiBlobStore.db"; private static final String DB_NAME = "WifiBlobStore.db"; private static final String LEGACY_KEYSTORE_SERVICE_NAME = "android.security.legacykeystore"; private static WifiBlobStore sInstance; private static WifiBlobStore sInstance; private WifiBlobStore() { private WifiBlobStore() { super(DB_NAME); super(DB_NAME); Loading @@ -36,4 +40,10 @@ public class WifiBlobStore extends ConnectivityBlobStore { } } return sInstance; return sInstance; } } /** Returns an interface to access the Legacy Keystore service. */ public static ILegacyKeystore getLegacyKeystore() { return ILegacyKeystore.Stub.asInterface( ServiceManager.checkService(LEGACY_KEYSTORE_SERVICE_NAME)); } } } wifi/java/src/android/net/wifi/WifiKeystore.java +4 −10 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.os.Binder; import android.os.Binder; import android.os.Process; import android.os.Process; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.ServiceSpecificException; import android.security.legacykeystore.ILegacyKeystore; import android.security.legacykeystore.ILegacyKeystore; import android.util.Log; import android.util.Log; Loading @@ -37,12 +36,6 @@ import java.util.Set; @SuppressLint("UnflaggedApi") // Promoting from @SystemApi(MODULE_LIBRARIES) @SuppressLint("UnflaggedApi") // Promoting from @SystemApi(MODULE_LIBRARIES) public final class WifiKeystore { public final class WifiKeystore { private static final String TAG = "WifiKeystore"; private static final String TAG = "WifiKeystore"; private static final String LEGACY_KEYSTORE_SERVICE_NAME = "android.security.legacykeystore"; private static ILegacyKeystore getLegacyKeystore() { return ILegacyKeystore.Stub.asInterface( ServiceManager.checkService(LEGACY_KEYSTORE_SERVICE_NAME)); } /** @hide */ /** @hide */ WifiKeystore() { WifiKeystore() { Loading Loading @@ -93,7 +86,7 @@ public final class WifiKeystore { return blob; return blob; } } Log.i(TAG, "Searching for blob in Legacy Keystore"); Log.i(TAG, "Searching for blob in Legacy Keystore"); return getLegacyKeystore().get(alias, Process.WIFI_UID); return WifiBlobStore.getLegacyKeystore().get(alias, Process.WIFI_UID); } catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { Log.e(TAG, "Failed to get blob.", e); Log.e(TAG, "Failed to get blob.", e); Loading Loading @@ -122,7 +115,7 @@ public final class WifiKeystore { Log.i(TAG, "remove blob. alias " + alias); Log.i(TAG, "remove blob. alias " + alias); blobStoreSuccess = WifiBlobStore.getInstance().remove(alias); blobStoreSuccess = WifiBlobStore.getInstance().remove(alias); // Legacy Keystore will throw an exception if the alias is not found. // Legacy Keystore will throw an exception if the alias is not found. getLegacyKeystore().remove(alias, Process.WIFI_UID); WifiBlobStore.getLegacyKeystore().remove(alias, Process.WIFI_UID); legacyKsSuccess = true; legacyKsSuccess = true; } catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { Loading Loading @@ -151,7 +144,8 @@ public final class WifiKeystore { try { try { // Aliases from WifiBlobStore will be pre-trimmed. // Aliases from WifiBlobStore will be pre-trimmed. final String[] blobStoreAliases = WifiBlobStore.getInstance().list(prefix); final String[] blobStoreAliases = WifiBlobStore.getInstance().list(prefix); final String[] legacyAliases = getLegacyKeystore().list(prefix, Process.WIFI_UID); final String[] legacyAliases = WifiBlobStore.getLegacyKeystore().list(prefix, Process.WIFI_UID); for (int i = 0; i < legacyAliases.length; ++i) { for (int i = 0; i < legacyAliases.length; ++i) { legacyAliases[i] = legacyAliases[i].substring(prefix.length()); legacyAliases[i] = legacyAliases[i].substring(prefix.length()); } } Loading wifi/tests/src/android/net/wifi/WifiKeystoreTest.java 0 → 100644 +178 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; import static org.mockito.Mockito.validateMockitoUsage; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import android.os.ServiceSpecificException; import android.security.legacykeystore.ILegacyKeystore; import com.android.dx.mockito.inline.extended.ExtendedMockito; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import java.util.Arrays; /** Unit tests for {@link WifiKeystore} */ public class WifiKeystoreTest { public static final String TEST_ALIAS = "someAliasString"; public static final byte[] TEST_VALUE = new byte[]{10, 11, 12}; @Mock private ILegacyKeystore mLegacyKeystore; @Mock private WifiBlobStore mWifiBlobStore; private MockitoSession mSession; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mSession = ExtendedMockito.mockitoSession() .mockStatic(WifiBlobStore.class, withSettings().lenient()) .startMocking(); when(WifiBlobStore.getLegacyKeystore()).thenReturn(mLegacyKeystore); when(WifiBlobStore.getInstance()).thenReturn(mWifiBlobStore); } @After public void cleanup() { validateMockitoUsage(); if (mSession != null) { mSession.finishMocking(); } } /** * Test that put() only writes to the WifiBlobStore database. */ @Test public void testPut() throws Exception { WifiKeystore.put(TEST_ALIAS, TEST_VALUE); verify(mWifiBlobStore).put(anyString(), any()); verify(mLegacyKeystore, never()).put(anyString(), anyInt(), any()); } /** * Test that if the alias is found in the WifiBlobStore database, * then the legacy database is not searched. */ @Test public void testGet_wifiBlobStoreDb() throws Exception { when(mWifiBlobStore.get(anyString())).thenReturn(TEST_VALUE); assertArrayEquals(TEST_VALUE, WifiKeystore.get(TEST_ALIAS)); verify(mWifiBlobStore).get(anyString()); verify(mLegacyKeystore, never()).get(anyString(), anyInt()); } /** * Test that if the alias is not found in the WifiBlobStore database, * then the legacy database is searched. */ @Test public void testGet_legacyDb() throws Exception { when(mWifiBlobStore.get(anyString())).thenReturn(null); when(mLegacyKeystore.get(anyString(), anyInt())).thenReturn(TEST_VALUE); assertArrayEquals(TEST_VALUE, WifiKeystore.get(TEST_ALIAS)); verify(mWifiBlobStore).get(anyString()); verify(mLegacyKeystore).get(anyString(), anyInt()); } /** * Test that get() returns a non-null value if the alias is * not found in either database. */ @Test public void testGet_notFound() throws Exception { when(mWifiBlobStore.get(anyString())).thenReturn(null); when(mLegacyKeystore.get(anyString(), anyInt())) .thenThrow(new ServiceSpecificException(ILegacyKeystore.ERROR_ENTRY_NOT_FOUND)); assertNotNull(WifiKeystore.get(TEST_ALIAS)); } /** * Test that remove() returns true if the alias is removed * from at least one database. */ @Test public void testRemove_success() throws Exception { // Only removed from WifiBlobStore when(mWifiBlobStore.remove(anyString())).thenReturn(true); doThrow(new ServiceSpecificException(ILegacyKeystore.ERROR_ENTRY_NOT_FOUND)) .when(mLegacyKeystore).remove(anyString(), anyInt()); assertTrue(WifiKeystore.remove(TEST_ALIAS)); // Only removed from Legacy Keystore when(mWifiBlobStore.remove(anyString())).thenReturn(false); doNothing().when(mLegacyKeystore).remove(anyString(), anyInt()); assertTrue(WifiKeystore.remove(TEST_ALIAS)); // Removed from both WifiBlobStore and Legacy Keystore when(mWifiBlobStore.remove(anyString())).thenReturn(true); doNothing().when(mLegacyKeystore).remove(anyString(), anyInt()); assertTrue(WifiKeystore.remove(TEST_ALIAS)); } /** * Test that remove() returns false if the alias is not removed * from any database. */ @Test public void testRemove_notFound() throws Exception { when(mWifiBlobStore.remove(anyString())).thenReturn(false); doThrow(new ServiceSpecificException(ILegacyKeystore.ERROR_ENTRY_NOT_FOUND)) .when(mLegacyKeystore).remove(anyString(), anyInt()); assertFalse(WifiKeystore.remove(TEST_ALIAS)); } /** * Test that list() retrieves aliases from both the WifiBlobStore * and Legacy Keystore databases. The results should be de-duplicated. */ @Test public void testList() throws Exception { // Aliases retrieved from WifiBlobStore will be pre-trimmed. String[] blobStoreAliases = new String[]{"1", "2"}; String[] legacyDbAliases = new String[]{TEST_ALIAS + "2", TEST_ALIAS + "3"}; when(mWifiBlobStore.list(anyString())).thenReturn(blobStoreAliases); when(mLegacyKeystore.list(anyString(), anyInt())).thenReturn(legacyDbAliases); // Alias 2 exists in both DBs and should be de-duplicated. String[] expected = new String[]{"1", "2", "3"}; String[] retrieved = WifiKeystore.list(TEST_ALIAS); Arrays.sort(retrieved); assertArrayEquals(expected, retrieved); } } Loading
wifi/java/src/android/net/wifi/WifiBlobStore.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.net.wifi; package android.net.wifi; import android.os.ServiceManager; import android.security.legacykeystore.ILegacyKeystore; import com.android.internal.net.ConnectivityBlobStore; import com.android.internal.net.ConnectivityBlobStore; /** /** Loading @@ -24,6 +27,7 @@ import com.android.internal.net.ConnectivityBlobStore; */ */ public class WifiBlobStore extends ConnectivityBlobStore { public class WifiBlobStore extends ConnectivityBlobStore { private static final String DB_NAME = "WifiBlobStore.db"; private static final String DB_NAME = "WifiBlobStore.db"; private static final String LEGACY_KEYSTORE_SERVICE_NAME = "android.security.legacykeystore"; private static WifiBlobStore sInstance; private static WifiBlobStore sInstance; private WifiBlobStore() { private WifiBlobStore() { super(DB_NAME); super(DB_NAME); Loading @@ -36,4 +40,10 @@ public class WifiBlobStore extends ConnectivityBlobStore { } } return sInstance; return sInstance; } } /** Returns an interface to access the Legacy Keystore service. */ public static ILegacyKeystore getLegacyKeystore() { return ILegacyKeystore.Stub.asInterface( ServiceManager.checkService(LEGACY_KEYSTORE_SERVICE_NAME)); } } }
wifi/java/src/android/net/wifi/WifiKeystore.java +4 −10 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.os.Binder; import android.os.Binder; import android.os.Process; import android.os.Process; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.ServiceSpecificException; import android.security.legacykeystore.ILegacyKeystore; import android.security.legacykeystore.ILegacyKeystore; import android.util.Log; import android.util.Log; Loading @@ -37,12 +36,6 @@ import java.util.Set; @SuppressLint("UnflaggedApi") // Promoting from @SystemApi(MODULE_LIBRARIES) @SuppressLint("UnflaggedApi") // Promoting from @SystemApi(MODULE_LIBRARIES) public final class WifiKeystore { public final class WifiKeystore { private static final String TAG = "WifiKeystore"; private static final String TAG = "WifiKeystore"; private static final String LEGACY_KEYSTORE_SERVICE_NAME = "android.security.legacykeystore"; private static ILegacyKeystore getLegacyKeystore() { return ILegacyKeystore.Stub.asInterface( ServiceManager.checkService(LEGACY_KEYSTORE_SERVICE_NAME)); } /** @hide */ /** @hide */ WifiKeystore() { WifiKeystore() { Loading Loading @@ -93,7 +86,7 @@ public final class WifiKeystore { return blob; return blob; } } Log.i(TAG, "Searching for blob in Legacy Keystore"); Log.i(TAG, "Searching for blob in Legacy Keystore"); return getLegacyKeystore().get(alias, Process.WIFI_UID); return WifiBlobStore.getLegacyKeystore().get(alias, Process.WIFI_UID); } catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { Log.e(TAG, "Failed to get blob.", e); Log.e(TAG, "Failed to get blob.", e); Loading Loading @@ -122,7 +115,7 @@ public final class WifiKeystore { Log.i(TAG, "remove blob. alias " + alias); Log.i(TAG, "remove blob. alias " + alias); blobStoreSuccess = WifiBlobStore.getInstance().remove(alias); blobStoreSuccess = WifiBlobStore.getInstance().remove(alias); // Legacy Keystore will throw an exception if the alias is not found. // Legacy Keystore will throw an exception if the alias is not found. getLegacyKeystore().remove(alias, Process.WIFI_UID); WifiBlobStore.getLegacyKeystore().remove(alias, Process.WIFI_UID); legacyKsSuccess = true; legacyKsSuccess = true; } catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) { Loading Loading @@ -151,7 +144,8 @@ public final class WifiKeystore { try { try { // Aliases from WifiBlobStore will be pre-trimmed. // Aliases from WifiBlobStore will be pre-trimmed. final String[] blobStoreAliases = WifiBlobStore.getInstance().list(prefix); final String[] blobStoreAliases = WifiBlobStore.getInstance().list(prefix); final String[] legacyAliases = getLegacyKeystore().list(prefix, Process.WIFI_UID); final String[] legacyAliases = WifiBlobStore.getLegacyKeystore().list(prefix, Process.WIFI_UID); for (int i = 0; i < legacyAliases.length; ++i) { for (int i = 0; i < legacyAliases.length; ++i) { legacyAliases[i] = legacyAliases[i].substring(prefix.length()); legacyAliases[i] = legacyAliases[i].substring(prefix.length()); } } Loading
wifi/tests/src/android/net/wifi/WifiKeystoreTest.java 0 → 100644 +178 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; import static org.mockito.Mockito.validateMockitoUsage; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import android.os.ServiceSpecificException; import android.security.legacykeystore.ILegacyKeystore; import com.android.dx.mockito.inline.extended.ExtendedMockito; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import java.util.Arrays; /** Unit tests for {@link WifiKeystore} */ public class WifiKeystoreTest { public static final String TEST_ALIAS = "someAliasString"; public static final byte[] TEST_VALUE = new byte[]{10, 11, 12}; @Mock private ILegacyKeystore mLegacyKeystore; @Mock private WifiBlobStore mWifiBlobStore; private MockitoSession mSession; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mSession = ExtendedMockito.mockitoSession() .mockStatic(WifiBlobStore.class, withSettings().lenient()) .startMocking(); when(WifiBlobStore.getLegacyKeystore()).thenReturn(mLegacyKeystore); when(WifiBlobStore.getInstance()).thenReturn(mWifiBlobStore); } @After public void cleanup() { validateMockitoUsage(); if (mSession != null) { mSession.finishMocking(); } } /** * Test that put() only writes to the WifiBlobStore database. */ @Test public void testPut() throws Exception { WifiKeystore.put(TEST_ALIAS, TEST_VALUE); verify(mWifiBlobStore).put(anyString(), any()); verify(mLegacyKeystore, never()).put(anyString(), anyInt(), any()); } /** * Test that if the alias is found in the WifiBlobStore database, * then the legacy database is not searched. */ @Test public void testGet_wifiBlobStoreDb() throws Exception { when(mWifiBlobStore.get(anyString())).thenReturn(TEST_VALUE); assertArrayEquals(TEST_VALUE, WifiKeystore.get(TEST_ALIAS)); verify(mWifiBlobStore).get(anyString()); verify(mLegacyKeystore, never()).get(anyString(), anyInt()); } /** * Test that if the alias is not found in the WifiBlobStore database, * then the legacy database is searched. */ @Test public void testGet_legacyDb() throws Exception { when(mWifiBlobStore.get(anyString())).thenReturn(null); when(mLegacyKeystore.get(anyString(), anyInt())).thenReturn(TEST_VALUE); assertArrayEquals(TEST_VALUE, WifiKeystore.get(TEST_ALIAS)); verify(mWifiBlobStore).get(anyString()); verify(mLegacyKeystore).get(anyString(), anyInt()); } /** * Test that get() returns a non-null value if the alias is * not found in either database. */ @Test public void testGet_notFound() throws Exception { when(mWifiBlobStore.get(anyString())).thenReturn(null); when(mLegacyKeystore.get(anyString(), anyInt())) .thenThrow(new ServiceSpecificException(ILegacyKeystore.ERROR_ENTRY_NOT_FOUND)); assertNotNull(WifiKeystore.get(TEST_ALIAS)); } /** * Test that remove() returns true if the alias is removed * from at least one database. */ @Test public void testRemove_success() throws Exception { // Only removed from WifiBlobStore when(mWifiBlobStore.remove(anyString())).thenReturn(true); doThrow(new ServiceSpecificException(ILegacyKeystore.ERROR_ENTRY_NOT_FOUND)) .when(mLegacyKeystore).remove(anyString(), anyInt()); assertTrue(WifiKeystore.remove(TEST_ALIAS)); // Only removed from Legacy Keystore when(mWifiBlobStore.remove(anyString())).thenReturn(false); doNothing().when(mLegacyKeystore).remove(anyString(), anyInt()); assertTrue(WifiKeystore.remove(TEST_ALIAS)); // Removed from both WifiBlobStore and Legacy Keystore when(mWifiBlobStore.remove(anyString())).thenReturn(true); doNothing().when(mLegacyKeystore).remove(anyString(), anyInt()); assertTrue(WifiKeystore.remove(TEST_ALIAS)); } /** * Test that remove() returns false if the alias is not removed * from any database. */ @Test public void testRemove_notFound() throws Exception { when(mWifiBlobStore.remove(anyString())).thenReturn(false); doThrow(new ServiceSpecificException(ILegacyKeystore.ERROR_ENTRY_NOT_FOUND)) .when(mLegacyKeystore).remove(anyString(), anyInt()); assertFalse(WifiKeystore.remove(TEST_ALIAS)); } /** * Test that list() retrieves aliases from both the WifiBlobStore * and Legacy Keystore databases. The results should be de-duplicated. */ @Test public void testList() throws Exception { // Aliases retrieved from WifiBlobStore will be pre-trimmed. String[] blobStoreAliases = new String[]{"1", "2"}; String[] legacyDbAliases = new String[]{TEST_ALIAS + "2", TEST_ALIAS + "3"}; when(mWifiBlobStore.list(anyString())).thenReturn(blobStoreAliases); when(mLegacyKeystore.list(anyString(), anyInt())).thenReturn(legacyDbAliases); // Alias 2 exists in both DBs and should be de-duplicated. String[] expected = new String[]{"1", "2", "3"}; String[] retrieved = WifiKeystore.list(TEST_ALIAS); Arrays.sort(retrieved); assertArrayEquals(expected, retrieved); } }