Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4a10406 authored by Eric Biggers's avatar Eric Biggers
Browse files

Zeroize intermediate secrets in unlockLskfBasedProtector()

Secrets derived from or unlocked by the LSKF need to be zeroized as soon
as they are no longer needed.

Zeroize stretchedLskf, weaverKey, gkPassword, and protectorSecret.

Bug: 320392352
Test: atest FrameworksServicesTests:com.android.server.locksettings
Flag: EXEMPT bugfix
Change-Id: I4a6c5bae60d4ef540d68bdec350edc328512e0c9
parent 5bb4ebf0
Loading
Loading
Loading
Loading
+104 −91
Original line number Diff line number Diff line
@@ -1409,9 +1409,12 @@ class SyntheticPasswordManager {
            return result;
        }

        byte[] stretchedLskf = stretchLskf(credential, pwd);

        final byte[] protectorSecret;
        byte[] stretchedLskf = null;
        byte[] weaverKey = null;
        byte[] gkPassword = null;
        byte[] protectorSecret = null;
        try {
            stretchedLskf = stretchLskf(credential, pwd);
            long sid = GateKeeper.INVALID_SECURE_USER_ID;
            int weaverSlot = loadWeaverSlot(protectorId, userId);
            if (weaverSlot != INVALID_WEAVER_SLOT) {
@@ -1423,16 +1426,17 @@ class SyntheticPasswordManager {
                    result.gkResponse = VerifyCredentialResponse.ERROR;
                    return result;
                }
            result.gkResponse = weaverVerify(weaver, weaverSlot,
                    stretchedLskfToWeaverKey(stretchedLskf));
                weaverKey = stretchedLskfToWeaverKey(stretchedLskf);
                result.gkResponse = weaverVerify(weaver, weaverSlot, weaverKey);
                if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
                    return result;
                }
                protectorSecret = transformUnderWeaverSecret(stretchedLskf,
                        result.gkResponse.getGatekeeperHAT());
            } else {
            // Weaver is unavailable, so the protector uses Gatekeeper to verify the LSKF, unless
            // the LSKF is empty in which case Gatekeeper might not have been used at all.
                // Weaver is unavailable, so the protector uses Gatekeeper to verify the LSKF,
                // unless the LSKF is empty in which case Gatekeeper might not have been used at
                // all.
                if (pwd == null || pwd.passwordHandle == null) {
                    if (!credential.isNone()) {
                        Slog.e(TAG, "Missing Gatekeeper password handle for nonempty LSKF");
@@ -1440,7 +1444,7 @@ class SyntheticPasswordManager {
                        return result;
                    }
                } else {
                byte[] gkPassword = stretchedLskfToGkPassword(stretchedLskf);
                    gkPassword = stretchedLskfToGkPassword(stretchedLskf);
                    GateKeeperResponse response;
                    try {
                        response = gatekeeper.verifyChallenge(fakeUserId(userId), 0L,
@@ -1463,7 +1467,8 @@ class SyntheticPasswordManager {
                                reenrollResponse = GateKeeperResponse.ERROR;
                                // continue the flow anyway
                            }
                        if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
                            if (reenrollResponse.getResponseCode()
                                    == GateKeeperResponse.RESPONSE_OK) {
                                pwd.passwordHandle = reenrollResponse.getPayload();
                                // Use the reenrollment opportunity to update credential type
                                // (getting rid of CREDENTIAL_TYPE_PASSWORD_OR_PIN)
@@ -1477,7 +1482,8 @@ class SyntheticPasswordManager {
                            }
                        }
                    } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
                    result.gkResponse = VerifyCredentialResponse.fromTimeout(response.getTimeout());
                        result.gkResponse = VerifyCredentialResponse.fromTimeout(
                                response.getTimeout());
                        return result;
                    } else  {
                        result.gkResponse = VerifyCredentialResponse.ERROR;
@@ -1493,8 +1499,8 @@ class SyntheticPasswordManager {
                }
                protectorSecret = transformUnderSecdiscardable(stretchedLskf, secdiscardable);
            }
        // Supplied credential passes first stage weaver/gatekeeper check so it should be correct.
        // Notify the callback so the keyguard UI can proceed immediately.
            // Supplied credential passes first stage weaver/gatekeeper check so it should be
            // correct.  Notify the callback so the keyguard UI can proceed immediately.
            if (progressCallback != null) {
                try {
                    progressCallback.onCredentialVerified();
@@ -1508,12 +1514,19 @@ class SyntheticPasswordManager {
            // Perform verifyChallenge to refresh auth tokens for GK if user password exists.
            result.gkResponse = verifyChallenge(gatekeeper, result.syntheticPassword, 0L, userId);

        // Upgrade case: store the metrics if the device did not have stored metrics before, should
        // only happen once on old protectors.
            // Upgrade case: store the metrics if the device did not have stored metrics before,
            // should only happen once on old protectors.
            if (result.syntheticPassword != null && !credential.isNone()
                    && !hasPasswordMetrics(protectorId, userId)) {
                savePasswordMetrics(credential, result.syntheticPassword, protectorId, userId);
            syncState(userId); // Not strictly needed as the upgrade can be re-done, but be safe.
                // Not strictly needed as the upgrade can be re-done, but be safe.
                syncState(userId);
            }
        } finally {
            ArrayUtils.zeroize(stretchedLskf);
            ArrayUtils.zeroize(weaverKey);
            ArrayUtils.zeroize(gkPassword);
            ArrayUtils.zeroize(protectorSecret);
        }
        return result;
    }