tpm_manager: avoid unnecessary default auth test

Previously the default auth test is performed w/o any aid of the local
data in persistent storage. Thus it causes DA to increase every time
tpm_manager starts. For those device that is incapable of resetting DA,
the consequence is that DA gets locked out and users cannot log in.

If the device has the flag to tell accomplished tpm initialization, the
default auth test would just skip so the DA counter doesn't increase. It
should help withe cases of missing delegate or delegate w/o DA reset
permission.

Note that in case of DA lockout in effect, this CL does very little
because checking the TPM ownership itself also fails in that situation.

To test the CL, on a real device a delegate is created w/o permission of
resetting DA. This setup is verified by observing failed DA reset after
clearing owner password. Then, in sequence --
1. Clear the ownership, no DA increment, just to be sure.
2. Manually touch the flag file of interest, restart tpm manager, and
observe the flag is wiped.
3. Take ownership, and obseve the flag shows up.
4. Manurally remove the flag file of interest, restart tpm manger, and
observe that DA increment by 1 and the flag file of interest shows up.
5. restart tpm manager, no further DA increment.

In case of default password, it is verified tpm maanger doesn't set the
flag file, and of course it doesn't increase the DA counter.

BUG=chromium:1110741
TEST=See above.

Change-Id: I7f6fd0855442db7b47c8726c647c52fab661de08
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2340830
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
Tested-by: Leo Lai <cylai@google.com>
diff --git a/tpm_manager/server/tpm_status_impl.cc b/tpm_manager/server/tpm_status_impl.cc
index 5fd6cc1..edb6fed 100644
--- a/tpm_manager/server/tpm_status_impl.cc
+++ b/tpm_manager/server/tpm_status_impl.cc
@@ -7,8 +7,11 @@
 #include <algorithm>
 #include <vector>
 
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
 #include <base/logging.h>
 #include <base/optional.h>
+#include <brillo/file_utils.h>
 #include <tpm_manager/server/tpm_util.h>
 #include <trousers/trousers.h>
 #include <trousers/tss.h>
@@ -30,6 +33,15 @@
 // The offset of DA counter in the Infineon-specific DA info data.
 constexpr size_t kInfineonDACounterOffset = 9;
 
+// The flag that tells if the tpm is full initialized.
+constexpr char kTpmFullyInitializedPath[] =
+    "/mnt/stateful_partition/.tpm_owned";
+
+bool TouchTpmFullyInitializedPath() {
+  return brillo::WriteBlobToFile<std::vector<char>>(
+      base::FilePath(kTpmFullyInitializedPath), {});
+}
+
 }  // namespace
 
 namespace tpm_manager {
@@ -58,6 +70,11 @@
   }
 
   if (!is_owned_) {
+    if (!base::DeleteFile(base::FilePath(kTpmFullyInitializedPath),
+                          /*recursive=*/false)) {
+      LOG(WARNING) << __func__ << ": Failed to delete "
+                   << kTpmFullyInitializedPath;
+    }
     // We even haven't tried to take ownership yet.
     ownership_status_ = kTpmUnowned;
     *status = ownership_status_;
@@ -207,7 +224,11 @@
 }
 
 base::Optional<bool> TpmStatusImpl::TestTpmWithDefaultOwnerPassword() {
-  if (is_owner_password_default_) {
+  if (base::PathExists(base::FilePath(kTpmFullyInitializedPath))) {
+    is_owner_password_default_ = false;
+  }
+
+  if (is_owner_password_default_.has_value()) {
     return is_owner_password_default_;
   }
 
@@ -226,6 +247,10 @@
     is_owner_password_default_ = true;
   } else if (result == TPM_ERROR(TPM_E_AUTHFAIL)) {
     is_owner_password_default_ = false;
+    if (!TouchTpmFullyInitializedPath()) {
+      LOG(WARNING) << __func__ << ": Failed to touch "
+                   << kTpmFullyInitializedPath;
+    }
   } else {
     TPM_LOG(ERROR, result) << "Unexpected error calling |Tspi_TPM_GetStatus|.";
   }
@@ -284,6 +309,10 @@
   is_enable_initialized_ = is_enabled_ = is_owned_ = true;
   ownership_status_ = kTpmOwned;
   is_owner_password_default_ = false;
+  if (!TouchTpmFullyInitializedPath()) {
+    LOG(WARNING) << __func__ << ": Failed to touch "
+                 << kTpmFullyInitializedPath;
+  }
 }
 
 }  // namespace tpm_manager
diff --git a/tpm_manager/server/tpm_status_impl.h b/tpm_manager/server/tpm_status_impl.h
index 140980d..c19be5c 100644
--- a/tpm_manager/server/tpm_status_impl.h
+++ b/tpm_manager/server/tpm_status_impl.h
@@ -48,6 +48,12 @@
   // 1. true if the test succeed.
   // 2. false if authentication fails with the default owner password.
   // 3. base::nullopt if any other errors.
+  //
+  // Note that, w/o any useful cache data, testing tpm with owner auth means it
+  // could increse DA counter or even fail during DA lockout. In case of no
+  // useful delegate to reset DA, we don't have any way to reset DA so the all
+  // the hwsec daemons cannot function correctly until DA unlocks itself after
+  // timeout (crbug/1110741).
   base::Optional<bool> TestTpmWithDefaultOwnerPassword();
   // This method refreshes the |is_owned_| and |is_enabled_| status of the
   // Tpm. It can be called multiple times.