cryptohome: Set auth_locked policy to false when PIN is reset.

The auth_locked policy must explicitly be set to false for Chrome to
recognize the PIN is usable after a reset.

Cherry picked from
https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2994464

BUG=chromium:1224150
TEST=Lock out PIN and use password

Change-Id: I06896c23be7ceccbaea88f48001f25c752c43d64
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/3002282
Reviewed-by: Daniil Lunev <dlunev@chromium.org>
Commit-Queue: Greg Kerr OOO <kerrnel@chromium.org>
Tested-by: Greg Kerr OOO <kerrnel@chromium.org>
Auto-Submit: Greg Kerr OOO <kerrnel@chromium.org>
diff --git a/cryptohome/crypto_unittest.cc b/cryptohome/crypto_unittest.cc
index 65cc3c6..2aa0b64 100644
--- a/cryptohome/crypto_unittest.cc
+++ b/cryptohome/crypto_unittest.cc
@@ -844,4 +844,32 @@
   EXPECT_EQ(CryptoError::CE_NONE, crypto_error);
 }
 
+// crbug.com/1224150: auth_locked must be set to false when an LE credential is
+// re-saved.
+TEST_F(LeCredentialsManagerTest, EncryptTestReset) {
+  EXPECT_CALL(*le_cred_manager_, InsertCredential(_, _, _, _, _, _))
+      .WillOnce(Return(LE_CRED_SUCCESS));
+
+  pin_vault_keyset_.CreateRandom();
+  pin_vault_keyset_.SetLowEntropyCredential(true);
+
+  // This used to happen in VaultKeyset::EncryptVaultKeyset, but now happens in
+  // VaultKeyset::Encrypt and thus needs to be done manually here.
+  pin_vault_keyset_.reset_seed_ =
+      CryptoLib::CreateSecureRandomBlob(kAesBlockSize);
+  pin_vault_keyset_.reset_salt_ =
+      CryptoLib::CreateSecureRandomBlob(kAesBlockSize);
+  pin_vault_keyset_.reset_secret_ = CryptoLib::HmacSha256(
+      pin_vault_keyset_.reset_salt_.value(), pin_vault_keyset_.reset_seed_);
+  pin_vault_keyset_.auth_locked_ = true;
+
+  SecureBlob key("key");
+  EXPECT_TRUE(pin_vault_keyset_.Encrypt(key, "foo@gmail.com"));
+  EXPECT_TRUE(pin_vault_keyset_.HasKeyData());
+  EXPECT_FALSE(pin_vault_keyset_.auth_locked_);
+
+  const SerializedVaultKeyset& serialized = pin_vault_keyset_.ToSerialized();
+  EXPECT_FALSE(serialized.key_data().policy().auth_locked());
+}
+
 }  // namespace cryptohome
diff --git a/cryptohome/vault_keyset.cc b/cryptohome/vault_keyset.cc
index f8e905a..d6362d5 100644
--- a/cryptohome/vault_keyset.cc
+++ b/cryptohome/vault_keyset.cc
@@ -429,6 +429,13 @@
 
     reset_salt_ = CryptoLib::CreateSecureRandomBlob(kAesBlockSize);
     reset_secret_ = CryptoLib::HmacSha256(reset_salt_.value(), reset_seed_);
+
+    // crbug.com/1224150: When an LE credential is resaved, that means the user
+    // authenticated successfully. In this case, auth_locked policy must always
+    // be set to false. Otherwise when a user enters their password, and
+    // PinWeaver unlocks the LE Credential, this field will remain set to true
+    // and PIN is never usable by Chrome.
+    auth_locked_ = false;
   }
 
   AuthBlockState auth_block_state;
@@ -461,7 +468,7 @@
 }
 
 std::string VaultKeyset::GetLabel() const {
-  if (key_data_.has_value()) {
+  if (key_data_.has_value() & !key_data_->label().empty()) {
     return key_data_->label();
   }
   // Fallback for legacy keys, for which the label has to be inferred from the
@@ -758,10 +765,8 @@
     *(serialized.mutable_key_data()) = key_data_.value();
   }
 
-  if (auth_locked_) {
-    serialized.mutable_key_data()->mutable_policy()->set_auth_locked(
-        auth_locked_);
-  }
+  serialized.mutable_key_data()->mutable_policy()->set_auth_locked(
+      auth_locked_);
 
   if (wrapped_chaps_key_.has_value()) {
     serialized.set_wrapped_chaps_key(wrapped_chaps_key_->data(),
diff --git a/cryptohome/vault_keyset.h b/cryptohome/vault_keyset.h
index 2947ca7..3ee61b5 100644
--- a/cryptohome/vault_keyset.h
+++ b/cryptohome/vault_keyset.h
@@ -325,6 +325,7 @@
   FRIEND_TEST_ALL_PREFIXES(CryptoTest, ScryptStepTest);
   FRIEND_TEST_ALL_PREFIXES(LeCredentialsManagerTest, Encrypt);
   FRIEND_TEST_ALL_PREFIXES(LeCredentialsManagerTest, EncryptFail);
+  FRIEND_TEST_ALL_PREFIXES(LeCredentialsManagerTest, EncryptTestReset);
 };
 
 }  // namespace cryptohome