Loading services/core/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ java_library_static { static_libs: [ "time_zone_distro", "time_zone_distro_installer", "android.hardware.authsecret-V1.0-java", "android.hardware.broadcastradio-V2.0-java", "android.hardware.health-V1.0-java", "android.hardware.health-V2.0-java", Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +26 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; import android.hardware.authsecret.V1_0.IAuthSecret; import android.net.Uri; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -126,8 +127,10 @@ import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; Loading Loading @@ -183,6 +186,7 @@ public class LockSettingsService extends ILockSettings.Stub { private boolean mFirstCallToVold; protected IGateKeeperService mGateKeeperService; protected IAuthSecret mAuthSecretService; /** * The UIDs that are used for system credential storage in keystore. Loading Loading @@ -613,6 +617,14 @@ public class LockSettingsService extends ILockSettings.Stub { } catch (RemoteException e) { Slog.e(TAG, "Failure retrieving IGateKeeperService", e); } // Find the AuthSecret HAL try { mAuthSecretService = IAuthSecret.getService(); } catch (NoSuchElementException e) { Slog.i(TAG, "Device doesn't implement AuthSecret HAL"); } catch (RemoteException e) { Slog.w(TAG, "Failed to get AuthSecret HAL", e); } mDeviceProvisionedObserver.onSystemReady(); // TODO: maybe skip this for split system user mode. mStorage.prefetchUser(UserHandle.USER_SYSTEM); Loading Loading @@ -2127,6 +2139,20 @@ public class LockSettingsService extends ILockSettings.Stub { private SparseArray<AuthenticationToken> mSpCache = new SparseArray(); private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) { // Pass the primary user's auth secret to the HAL if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) { try { final byte[] rawSecret = auth.deriveVendorAuthSecret(); final ArrayList<Byte> secret = new ArrayList<>(rawSecret.length); for (int i = 0; i < rawSecret.length; ++i) { secret.add(rawSecret[i]); } mAuthSecretService.primaryUserCredential(secret); } catch (RemoteException e) { Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e); } } // Update the SP cache, removing the entry when allowed synchronized (mSpManager) { if (shouldCacheSpForUser(userId)) { Loading services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ public class SyntheticPasswordManager { private static final byte[] PERSONALIZATION_USER_GK_AUTH = "user-gk-authentication".getBytes(); private static final byte[] PERSONALIZATION_SP_GK_AUTH = "sp-gk-authentication".getBytes(); private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes(); private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes(); private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes(); private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes(); private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes(); Loading Loading @@ -159,6 +160,11 @@ public class SyntheticPasswordManager { syntheticPassword.getBytes()); } public byte[] deriveVendorAuthSecret() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_AUTHSECRET_KEY, syntheticPassword.getBytes()); } private void initialize(byte[] P0, byte[] P1) { this.P1 = P1; this.syntheticPassword = String.valueOf(HexEncoding.encode( Loading services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +8 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.trust.TrustManager; import android.content.ComponentName; import android.content.pm.UserInfo; import android.hardware.authsecret.V1_0.IAuthSecret; import android.os.FileUtils; import android.os.IProgressListener; import android.os.RemoteException; Loading Loading @@ -80,6 +81,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { DevicePolicyManagerInternal mDevicePolicyManagerInternal; KeyStore mKeyStore; MockSyntheticPasswordManager mSpManager; IAuthSecret mAuthSecretService; @Override protected void setUp() throws Exception { Loading Loading @@ -115,17 +117,21 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { }; mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService, mUserManager); mAuthSecretService = mock(IAuthSecret.class); mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage, mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager, mSpManager); mSpManager, mAuthSecretService); when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO); mPrimaryUserProfiles.add(PRIMARY_USER_INFO); installChildProfile(MANAGED_PROFILE_USER_ID); installAndTurnOffChildProfile(TURNED_OFF_PROFILE_USER_ID); when(mUserManager.getUsers(anyBoolean())).thenReturn(mPrimaryUserProfiles); when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(mPrimaryUserProfiles); when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO); final ArrayList<UserInfo> allUsers = new ArrayList<>(mPrimaryUserProfiles); allUsers.add(SECONDARY_USER_INFO); when(mUserManager.getUsers(anyBoolean())).thenReturn(allUsers); when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer( new Answer<Boolean>() { @Override Loading services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +25 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.server.testutils.TestUtils.assertExpectException; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; Loading @@ -31,6 +32,10 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.VerifyCredentialResponse; import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult; import java.util.ArrayList; import org.mockito.ArgumentCaptor; /** * Run the synthetic password tests with caching enabled. * Loading Loading @@ -88,6 +93,26 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { .getResponseCode()); } public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException { final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password"; final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword"; initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); // Untrusted change password mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); // Verify the password assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); // Ensure the same secret was passed each time ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class); verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture()); assertEquals(1, secret.getAllValues().stream().distinct().count()); } public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException { final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password"; final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword"; Loading Loading
services/core/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ java_library_static { static_libs: [ "time_zone_distro", "time_zone_distro_installer", "android.hardware.authsecret-V1.0-java", "android.hardware.broadcastradio-V2.0-java", "android.hardware.health-V1.0-java", "android.hardware.health-V2.0-java", Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +26 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; import android.hardware.authsecret.V1_0.IAuthSecret; import android.net.Uri; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -126,8 +127,10 @@ import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; Loading Loading @@ -183,6 +186,7 @@ public class LockSettingsService extends ILockSettings.Stub { private boolean mFirstCallToVold; protected IGateKeeperService mGateKeeperService; protected IAuthSecret mAuthSecretService; /** * The UIDs that are used for system credential storage in keystore. Loading Loading @@ -613,6 +617,14 @@ public class LockSettingsService extends ILockSettings.Stub { } catch (RemoteException e) { Slog.e(TAG, "Failure retrieving IGateKeeperService", e); } // Find the AuthSecret HAL try { mAuthSecretService = IAuthSecret.getService(); } catch (NoSuchElementException e) { Slog.i(TAG, "Device doesn't implement AuthSecret HAL"); } catch (RemoteException e) { Slog.w(TAG, "Failed to get AuthSecret HAL", e); } mDeviceProvisionedObserver.onSystemReady(); // TODO: maybe skip this for split system user mode. mStorage.prefetchUser(UserHandle.USER_SYSTEM); Loading Loading @@ -2127,6 +2139,20 @@ public class LockSettingsService extends ILockSettings.Stub { private SparseArray<AuthenticationToken> mSpCache = new SparseArray(); private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) { // Pass the primary user's auth secret to the HAL if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) { try { final byte[] rawSecret = auth.deriveVendorAuthSecret(); final ArrayList<Byte> secret = new ArrayList<>(rawSecret.length); for (int i = 0; i < rawSecret.length; ++i) { secret.add(rawSecret[i]); } mAuthSecretService.primaryUserCredential(secret); } catch (RemoteException e) { Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e); } } // Update the SP cache, removing the entry when allowed synchronized (mSpManager) { if (shouldCacheSpForUser(userId)) { Loading
services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ public class SyntheticPasswordManager { private static final byte[] PERSONALIZATION_USER_GK_AUTH = "user-gk-authentication".getBytes(); private static final byte[] PERSONALIZATION_SP_GK_AUTH = "sp-gk-authentication".getBytes(); private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes(); private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes(); private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes(); private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes(); private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes(); Loading Loading @@ -159,6 +160,11 @@ public class SyntheticPasswordManager { syntheticPassword.getBytes()); } public byte[] deriveVendorAuthSecret() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_AUTHSECRET_KEY, syntheticPassword.getBytes()); } private void initialize(byte[] P0, byte[] P1) { this.P1 = P1; this.syntheticPassword = String.valueOf(HexEncoding.encode( Loading
services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +8 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.trust.TrustManager; import android.content.ComponentName; import android.content.pm.UserInfo; import android.hardware.authsecret.V1_0.IAuthSecret; import android.os.FileUtils; import android.os.IProgressListener; import android.os.RemoteException; Loading Loading @@ -80,6 +81,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { DevicePolicyManagerInternal mDevicePolicyManagerInternal; KeyStore mKeyStore; MockSyntheticPasswordManager mSpManager; IAuthSecret mAuthSecretService; @Override protected void setUp() throws Exception { Loading Loading @@ -115,17 +117,21 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { }; mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService, mUserManager); mAuthSecretService = mock(IAuthSecret.class); mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage, mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager, mSpManager); mSpManager, mAuthSecretService); when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO); mPrimaryUserProfiles.add(PRIMARY_USER_INFO); installChildProfile(MANAGED_PROFILE_USER_ID); installAndTurnOffChildProfile(TURNED_OFF_PROFILE_USER_ID); when(mUserManager.getUsers(anyBoolean())).thenReturn(mPrimaryUserProfiles); when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(mPrimaryUserProfiles); when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO); final ArrayList<UserInfo> allUsers = new ArrayList<>(mPrimaryUserProfiles); allUsers.add(SECONDARY_USER_INFO); when(mUserManager.getUsers(anyBoolean())).thenReturn(allUsers); when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer( new Answer<Boolean>() { @Override Loading
services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +25 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.server.testutils.TestUtils.assertExpectException; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; Loading @@ -31,6 +32,10 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.VerifyCredentialResponse; import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult; import java.util.ArrayList; import org.mockito.ArgumentCaptor; /** * Run the synthetic password tests with caching enabled. * Loading Loading @@ -88,6 +93,26 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { .getResponseCode()); } public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException { final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password"; final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword"; initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); // Untrusted change password mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); // Verify the password assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); // Ensure the same secret was passed each time ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class); verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture()); assertEquals(1, secret.getAllValues().stream().distinct().count()); } public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException { final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password"; final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword"; Loading