trunks: Refactored TpmState. am: ce32afbb30
am: df3a5b9734

Change-Id: Ie784ab5fdc1f12aa5f664c10974bcc83e8303ab3
diff --git a/trunks/Android.mk b/trunks/Android.mk
index 28d71ec..c801699 100644
--- a/trunks/Android.mk
+++ b/trunks/Android.mk
@@ -21,8 +21,7 @@
   -Wall -Werror \
   -Wno-unused-parameter \
   -DUSE_BINDER_IPC \
-  -fvisibility=hidden \
-
+  -fvisibility=hidden
 trunksIncludes := $(LOCAL_PATH)/..
 trunksSharedLibraries := \
   libbinder \
@@ -33,7 +32,7 @@
   libchrome-crypto \
   libcrypto \
   libprotobuf-cpp-lite \
-  libutils \
+  libutils
 
 # libtrunks_generated
 # ========================================================
@@ -51,8 +50,7 @@
 LOCAL_SRC_FILES := \
   interface.proto \
   aidl/android/trunks/ITrunks.aidl \
-  aidl/android/trunks/ITrunksClient.aidl \
-
+  aidl/android/trunks/ITrunksClient.aidl
 LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
 include $(BUILD_STATIC_LIBRARY)
 
@@ -79,8 +77,7 @@
   tpm_generated.cc \
   tpm_state_impl.cc \
   tpm_utility_impl.cc \
-  trunks_factory_impl.cc \
-
+  trunks_factory_impl.cc
 include $(BUILD_STATIC_LIBRARY)
 
 # trunksd
@@ -102,25 +99,21 @@
 LOCAL_SHARED_LIBRARIES := \
   $(trunksSharedLibraries) \
   libbrillo-minijail \
-  libminijail \
-
+  libminijail
 ifeq ($(BRILLOEMULATOR),true)
 LOCAL_SHARED_LIBRARIES += libtpm2
 endif
 LOCAL_STATIC_LIBRARIES := \
   libtrunks_generated \
-  libtrunks_common \
-
+  libtrunks_common
 LOCAL_REQUIRED_MODULES := \
-  trunksd-seccomp.policy \
-
+  trunksd-seccomp.policy
 LOCAL_SRC_FILES := \
   resource_manager.cc \
   tpm_handle.cc \
   tpm_simulator_handle.cc \
   trunks_binder_service.cc \
-  trunksd.cc \
-
+  trunksd.cc
 include $(BUILD_EXECUTABLE)
 
 # trunksd-seccomp.policy
@@ -141,14 +134,12 @@
 LOCAL_CLANG := true
 LOCAL_C_INCLUDES := $(trunksIncludes)
 LOCAL_SHARED_LIBRARIES := $(trunksSharedLibraries)
-
 LOCAL_WHOLE_STATIC_LIBRARIES := \
   libtrunks_common \
-  libtrunks_generated \
-
+  libtrunks_generated
 LOCAL_SRC_FILES := \
-  trunks_binder_proxy.cc \
-
+  trunks_binder_proxy.cc
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/..
 include $(BUILD_SHARED_LIBRARY)
 
 # trunks_client
@@ -162,8 +153,7 @@
 LOCAL_SHARED_LIBRARIES := $(trunksSharedLibraries) libtrunks
 LOCAL_SRC_FILES := \
   trunks_client.cc \
-  trunks_client_test.cc \
-
+  trunks_client_test.cc
 include $(BUILD_EXECUTABLE)
 
 # libtrunks_test
@@ -186,11 +176,9 @@
   mock_tpm.cc \
   mock_tpm_state.cc \
   mock_tpm_utility.cc \
-  trunks_factory_for_test.cc \
-
+  trunks_factory_for_test.cc
 LOCAL_STATIC_LIBRARIES := \
-  libgmock \
-
+  libgmock
 include $(BUILD_STATIC_LIBRARY)
 
 # Target unit tests
@@ -215,13 +203,11 @@
   session_manager_test.cc \
   tpm_generated_test.cc \
   tpm_state_test.cc \
-  tpm_utility_test.cc \
-
+  tpm_utility_test.cc
 LOCAL_STATIC_LIBRARIES := \
   libBionicGtestMain \
   libgmock \
   libtrunks_common \
   libtrunks_generated \
-  libtrunks_test \
-
+  libtrunks_test
 include $(BUILD_NATIVE_TEST)
diff --git a/trunks/error_codes.h b/trunks/error_codes.h
index 4b8d61a..eac57e9 100644
--- a/trunks/error_codes.h
+++ b/trunks/error_codes.h
@@ -41,6 +41,7 @@
 const TPM_RC TRUNKS_RC_WRITE_ERROR = kTrunksErrorBase + 4;
 const TPM_RC TRUNKS_RC_IPC_ERROR = kTrunksErrorBase + 5;
 const TPM_RC TRUNKS_RC_SESSION_SETUP_ERROR = kTrunksErrorBase + 6;
+const TPM_RC TRUNKS_RC_INVALID_TPM_CONFIGURATION = kTrunksErrorBase + 7;
 
 const TPM_RC TCTI_RC_TRY_AGAIN = kTctiErrorBase + 1;
 const TPM_RC TCTI_RC_GENERAL_FAILURE = kTctiErrorBase + 2;
diff --git a/trunks/mock_tpm_state.cc b/trunks/mock_tpm_state.cc
index ee52e3b..fad7a75 100644
--- a/trunks/mock_tpm_state.cc
+++ b/trunks/mock_tpm_state.cc
@@ -38,6 +38,7 @@
   ON_CALL(*this, GetLockoutThreshold()).WillByDefault(Return(0));
   ON_CALL(*this, GetLockoutInterval()).WillByDefault(Return(0));
   ON_CALL(*this, GetLockoutRecovery()).WillByDefault(Return(0));
+  ON_CALL(*this, GetMaxNVSize()).WillByDefault(Return(2048));
 }
 
 MockTpmState::~MockTpmState() {}
diff --git a/trunks/mock_tpm_state.h b/trunks/mock_tpm_state.h
index 9c3073a..20dd338 100644
--- a/trunks/mock_tpm_state.h
+++ b/trunks/mock_tpm_state.h
@@ -45,6 +45,9 @@
   MOCK_METHOD0(GetLockoutThreshold, uint32_t());
   MOCK_METHOD0(GetLockoutInterval, uint32_t());
   MOCK_METHOD0(GetLockoutRecovery, uint32_t());
+  MOCK_METHOD0(GetMaxNVSize, uint32_t());
+  MOCK_METHOD2(GetTpmProperty, bool(TPM_PT, uint32_t*));
+  MOCK_METHOD2(GetAlgorithmProperties, bool(TPM_ALG_ID, TPMA_ALGORITHM*));
 };
 
 }  // namespace trunks
diff --git a/trunks/tpm_state.h b/trunks/tpm_state.h
index 21443de..7367022 100644
--- a/trunks/tpm_state.h
+++ b/trunks/tpm_state.h
@@ -85,6 +85,18 @@
   // LockoutAuth can be used again.
   virtual uint32_t GetLockoutRecovery() = 0;
 
+  // Returns the maximum size, in bytes, of an NV index data area.
+  virtual uint32_t GetMaxNVSize() = 0;
+
+  // Gets the |value| of any |property|. |value| may be NULL. Returns false if
+  // a value is not available for the property.
+  virtual bool GetTpmProperty(TPM_PT property, uint32_t* value) = 0;
+
+  // Gets |algorithm| |properties|. |properties| may be NULL. Returns false if
+  // properties are not available for the algorithm.
+  virtual bool GetAlgorithmProperties(TPM_ALG_ID algorithm,
+                                      TPMA_ALGORITHM* properties) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(TpmState);
 };
diff --git a/trunks/tpm_state_impl.cc b/trunks/tpm_state_impl.cc
index 93874c4..e453cae 100644
--- a/trunks/tpm_state_impl.cc
+++ b/trunks/tpm_state_impl.cc
@@ -17,6 +17,7 @@
 #include "trunks/tpm_state_impl.h"
 
 #include <base/logging.h>
+#include <brillo/bind_lambda.h>
 
 #include "trunks/error_codes.h"
 #include "trunks/tpm_generated.h"
@@ -36,109 +37,49 @@
 const trunks::TPMA_STARTUP_CLEAR kEndorsementHierarchyMask = 1U << 2;
 const trunks::TPMA_STARTUP_CLEAR kOrderlyShutdownMask = 1U << 31;
 
-// From definition of TPMA_ALGORITHM
-const trunks::TPMA_ALGORITHM kAsymmetricAlgMask = 1U;
-
 }  // namespace
 
 namespace trunks {
 
-TpmStateImpl::TpmStateImpl(const TrunksFactory& factory)
-    : factory_(factory),
-      initialized_(false),
-      permanent_flags_(0),
-      startup_clear_flags_(0),
-      rsa_flags_(0),
-      ecc_flags_(0) {}
-
-TpmStateImpl::~TpmStateImpl() {}
+TpmStateImpl::TpmStateImpl(const TrunksFactory& factory) : factory_(factory) {}
 
 TPM_RC TpmStateImpl::Initialize() {
-  TPM_RC result = GetTpmProperty(TPM_PT_PERMANENT, &permanent_flags_);
+  TPM_RC result = CacheTpmProperties();
   if (result != TPM_RC_SUCCESS) {
-    LOG(ERROR) << "Error getting permanent flags: " << GetErrorString(result);
+    LOG(ERROR) << "Failed to query TPM properties: " << GetErrorString(result);
     return result;
   }
-  result = GetTpmProperty(TPM_PT_STARTUP_CLEAR, &startup_clear_flags_);
-  if (result != TPM_RC_SUCCESS) {
-    LOG(ERROR) << "Error getting startup flags: " << GetErrorString(result);
-    return result;
-  }
-  result = GetTpmProperty(TPM_PT_LOCKOUT_COUNTER, &lockout_counter_);
-  if (result != TPM_RC_SUCCESS) {
-    LOG(ERROR) << "Error getting lockout counter: " << GetErrorString(result);
-    return result;
-  }
-  result = GetTpmProperty(TPM_PT_MAX_AUTH_FAIL, &lockout_threshold_);
-  if (result != TPM_RC_SUCCESS) {
-    LOG(ERROR) << "Error getting lockout threshold: " << GetErrorString(result);
-    return result;
-  }
-  result = GetTpmProperty(TPM_PT_LOCKOUT_INTERVAL, &lockout_interval_);
-  if (result != TPM_RC_SUCCESS) {
-    LOG(ERROR) << "Error getting lockout interval: " << GetErrorString(result);
-    return result;
-  }
-  result = GetTpmProperty(TPM_PT_LOCKOUT_RECOVERY, &lockout_recovery_);
-  if (result != TPM_RC_SUCCESS) {
-    LOG(ERROR) << "Error getting lockout recovery: " << GetErrorString(result);
-    return result;
+  if (tpm_properties_.count(TPM_PT_PERMANENT) == 0 ||
+      tpm_properties_.count(TPM_PT_STARTUP_CLEAR) == 0) {
+    LOG(ERROR) << "Required properties missing!";
+    return TRUNKS_RC_INVALID_TPM_CONFIGURATION;
   }
 
-  TPMI_YES_NO more_data;
-  TPMS_CAPABILITY_DATA capability_data;
-  result = factory_.GetTpm()->GetCapabilitySync(TPM_CAP_ALGS, TPM_ALG_RSA,
-                                                1,  // There is only one value.
-                                                &more_data, &capability_data,
-                                                nullptr);
-  if (result) {
-    LOG(ERROR) << __func__ << ": " << GetErrorString(result);
+  result = CacheAlgorithmProperties();
+  if (result != TPM_RC_SUCCESS) {
+    LOG(ERROR) << "Failed to query TPM algorithms: " << GetErrorString(result);
     return result;
   }
-  if (capability_data.capability != TPM_CAP_ALGS ||
-      capability_data.data.algorithms.count != 1) {
-    LOG(ERROR) << __func__ << ": Unexpected capability data.";
-    return SAPI_RC_MALFORMED_RESPONSE;
-  }
-  if (capability_data.data.algorithms.alg_properties[0].alg == TPM_ALG_RSA) {
-    rsa_flags_ =
-        capability_data.data.algorithms.alg_properties[0].alg_properties;
-  }
-  result = factory_.GetTpm()->GetCapabilitySync(TPM_CAP_ALGS, TPM_ALG_ECC,
-                                                1,  // There is only one value.
-                                                &more_data, &capability_data,
-                                                nullptr);
-  if (result) {
-    LOG(ERROR) << __func__ << ": " << GetErrorString(result);
-    return result;
-  }
-  if (capability_data.capability != TPM_CAP_ALGS ||
-      capability_data.data.algorithms.count != 1) {
-    LOG(ERROR) << __func__ << ": Unexpected capability data.";
-    return SAPI_RC_MALFORMED_RESPONSE;
-  }
-  if (capability_data.data.algorithms.alg_properties[0].alg == TPM_ALG_ECC) {
-    ecc_flags_ =
-        capability_data.data.algorithms.alg_properties[0].alg_properties;
-  }
   initialized_ = true;
   return TPM_RC_SUCCESS;
 }
 
 bool TpmStateImpl::IsOwnerPasswordSet() {
   CHECK(initialized_);
-  return ((permanent_flags_ & kOwnerAuthSetMask) == kOwnerAuthSetMask);
+  return ((tpm_properties_[TPM_PT_PERMANENT] & kOwnerAuthSetMask) ==
+          kOwnerAuthSetMask);
 }
 
 bool TpmStateImpl::IsEndorsementPasswordSet() {
   CHECK(initialized_);
-  return ((permanent_flags_ & kEndorsementAuthSetMask) ==
+  return ((tpm_properties_[TPM_PT_PERMANENT] & kEndorsementAuthSetMask) ==
           kEndorsementAuthSetMask);
 }
 
 bool TpmStateImpl::IsLockoutPasswordSet() {
   CHECK(initialized_);
-  return ((permanent_flags_ & kLockoutAuthSetMask) == kLockoutAuthSetMask);
+  return ((tpm_properties_[TPM_PT_PERMANENT] & kLockoutAuthSetMask) ==
+          kLockoutAuthSetMask);
 }
 
 bool TpmStateImpl::IsOwned() {
@@ -148,24 +89,25 @@
 
 bool TpmStateImpl::IsInLockout() {
   CHECK(initialized_);
-  return ((permanent_flags_ & kInLockoutMask) == kInLockoutMask);
+  return ((tpm_properties_[TPM_PT_PERMANENT] & kInLockoutMask) ==
+          kInLockoutMask);
 }
 
 bool TpmStateImpl::IsPlatformHierarchyEnabled() {
   CHECK(initialized_);
-  return ((startup_clear_flags_ & kPlatformHierarchyMask) ==
+  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kPlatformHierarchyMask) ==
           kPlatformHierarchyMask);
 }
 
 bool TpmStateImpl::IsStorageHierarchyEnabled() {
   CHECK(initialized_);
-  return ((startup_clear_flags_ & kStorageHierarchyMask) ==
+  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kStorageHierarchyMask) ==
           kStorageHierarchyMask);
 }
 
 bool TpmStateImpl::IsEndorsementHierarchyEnabled() {
   CHECK(initialized_);
-  return ((startup_clear_flags_ & kEndorsementHierarchyMask) ==
+  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kEndorsementHierarchyMask) ==
           kEndorsementHierarchyMask);
 }
 
@@ -176,60 +118,156 @@
 
 bool TpmStateImpl::WasShutdownOrderly() {
   CHECK(initialized_);
-  return ((startup_clear_flags_ & kOrderlyShutdownMask) ==
+  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kOrderlyShutdownMask) ==
           kOrderlyShutdownMask);
 }
 
 bool TpmStateImpl::IsRSASupported() {
   CHECK(initialized_);
-  return ((rsa_flags_ & kAsymmetricAlgMask) == kAsymmetricAlgMask);
+  return (algorithm_properties_.count(TPM_ALG_RSA) > 0);
 }
 
 bool TpmStateImpl::IsECCSupported() {
   CHECK(initialized_);
-  return ((ecc_flags_ & kAsymmetricAlgMask) == kAsymmetricAlgMask);
+  return (algorithm_properties_.count(TPM_ALG_ECC) > 0);
 }
 
 uint32_t TpmStateImpl::GetLockoutCounter() {
   CHECK(initialized_);
-  return lockout_counter_;
+  return tpm_properties_[TPM_PT_LOCKOUT_COUNTER];
 }
 
 uint32_t TpmStateImpl::GetLockoutThreshold() {
   CHECK(initialized_);
-  return lockout_threshold_;
+  return tpm_properties_[TPM_PT_MAX_AUTH_FAIL];
 }
 
 uint32_t TpmStateImpl::GetLockoutInterval() {
   CHECK(initialized_);
-  return lockout_interval_;
+  return tpm_properties_[TPM_PT_LOCKOUT_INTERVAL];
 }
 
 uint32_t TpmStateImpl::GetLockoutRecovery() {
   CHECK(initialized_);
-  return lockout_recovery_;
+  return tpm_properties_[TPM_PT_LOCKOUT_RECOVERY];
 }
 
-TPM_RC TpmStateImpl::GetTpmProperty(uint32_t property, uint32_t* value) {
-  CHECK(value);
-  TPMI_YES_NO more_data;
-  TPMS_CAPABILITY_DATA capability_data;
-  TPM_RC result = factory_.GetTpm()->GetCapabilitySync(
-      TPM_CAP_TPM_PROPERTIES, property,
-      1,  // Only one property.
-      &more_data, &capability_data, nullptr);
-  if (result != TPM_RC_SUCCESS) {
-    LOG(ERROR) << __func__ << ": " << GetErrorString(result);
-    return result;
+uint32_t TpmStateImpl::GetMaxNVSize() {
+  CHECK(initialized_);
+  uint32_t max_nv_size;
+  if (!GetTpmProperty(TPM_PT_NV_INDEX_MAX, &max_nv_size)) {
+    max_nv_size = 2048;
   }
-  if (capability_data.capability != TPM_CAP_TPM_PROPERTIES ||
-      capability_data.data.tpm_properties.count != 1 ||
-      capability_data.data.tpm_properties.tpm_property[0].property !=
-          property) {
-    LOG(ERROR) << __func__ << ": Unexpected capability data.";
-    return SAPI_RC_MALFORMED_RESPONSE;
+  uint32_t max_nv_buffer;
+  if (GetTpmProperty(TPM_PT_NV_BUFFER_MAX, &max_nv_buffer) &&
+      max_nv_buffer < max_nv_size) {
+    max_nv_size = max_nv_buffer;
   }
-  *value = capability_data.data.tpm_properties.tpm_property[0].value;
+  return max_nv_size;
+}
+
+bool TpmStateImpl::GetTpmProperty(TPM_PT property, uint32_t* value) {
+  CHECK(initialized_);
+  if (tpm_properties_.count(property) == 0) {
+    return false;
+  }
+  if (value) {
+    *value = tpm_properties_[property];
+  }
+  return true;
+}
+
+bool TpmStateImpl::GetAlgorithmProperties(TPM_ALG_ID algorithm,
+                                          TPMA_ALGORITHM* properties) {
+  CHECK(initialized_);
+  if (algorithm_properties_.count(algorithm) == 0) {
+    return false;
+  }
+  if (properties) {
+    *properties = algorithm_properties_[algorithm];
+  }
+  return true;
+}
+
+TPM_RC TpmStateImpl::GetCapability(const CapabilityCallback& callback,
+                                   TPM_CAP capability,
+                                   uint32_t property,
+                                   uint32_t max_properties_per_call) {
+  TPMI_YES_NO more_data = YES;
+  while (more_data) {
+    TPMS_CAPABILITY_DATA capability_data;
+    TPM_RC result = factory_.GetTpm()->GetCapabilitySync(
+        capability, property, max_properties_per_call, &more_data,
+        &capability_data, nullptr);
+    if (result != TPM_RC_SUCCESS) {
+      LOG(ERROR) << __func__ << ": " << GetErrorString(result);
+      return result;
+    }
+    if (capability_data.capability != capability) {
+      LOG(ERROR) << __func__ << ": Unexpected capability data.";
+      return SAPI_RC_MALFORMED_RESPONSE;
+    }
+    uint32_t next_property = callback.Run(capability_data.data);
+    if (more_data) {
+      if (next_property == 0) {
+        LOG(ERROR) << __func__ << ": No properties in response.";
+        return SAPI_RC_MALFORMED_RESPONSE;
+      }
+      if (next_property <= property) {
+        LOG(ERROR) << __func__ << ": Lower properties in response.";
+        return SAPI_RC_MALFORMED_RESPONSE;
+      }
+      property = next_property;
+    }
+  }
+  return TPM_RC_SUCCESS;
+}
+
+TPM_RC TpmStateImpl::CacheTpmProperties() {
+  CapabilityCallback callback =
+      base::Bind([this](const TPMU_CAPABILITIES& capability_data) {
+        uint32_t next_property = 0;
+        for (uint32_t i = 0;
+             i < capability_data.tpm_properties.count && i < MAX_TPM_PROPERTIES;
+             ++i) {
+          const TPMS_TAGGED_PROPERTY& property =
+              capability_data.tpm_properties.tpm_property[i];
+          VLOG(1) << "TPM Property 0x" << std::hex << property.property
+                  << " = 0x" << property.value;
+          tpm_properties_[property.property] = property.value;
+          next_property = property.property + 1;
+        }
+        return next_property;
+      });
+  if (tpm_properties_.empty()) {
+    TPM_RC result = GetCapability(callback, TPM_CAP_TPM_PROPERTIES, PT_FIXED,
+                                  MAX_TPM_PROPERTIES);
+    if (result != TPM_RC_SUCCESS) {
+      return result;
+    }
+  }
+  return GetCapability(callback, TPM_CAP_TPM_PROPERTIES, PT_VAR,
+                       MAX_TPM_PROPERTIES);
+}
+
+TPM_RC TpmStateImpl::CacheAlgorithmProperties() {
+  CapabilityCallback callback =
+      base::Bind([this](const TPMU_CAPABILITIES& capability_data) {
+        uint32_t next_property = 0;
+        for (uint32_t i = 0;
+             i < capability_data.algorithms.count && i < MAX_CAP_ALGS; ++i) {
+          const TPMS_ALG_PROPERTY& property =
+              capability_data.algorithms.alg_properties[i];
+          VLOG(1) << "Algorithm Properties 0x" << std::hex << property.alg
+                  << " = 0x" << property.alg_properties;
+          algorithm_properties_[property.alg] = property.alg_properties;
+          next_property = property.alg + 1;
+        }
+        return next_property;
+      });
+  if (algorithm_properties_.empty()) {
+    return GetCapability(callback, TPM_CAP_ALGS, TPM_ALG_FIRST, MAX_CAP_ALGS);
+  }
   return TPM_RC_SUCCESS;
 }
 
diff --git a/trunks/tpm_state_impl.h b/trunks/tpm_state_impl.h
index 14247ff..4a26f73 100644
--- a/trunks/tpm_state_impl.h
+++ b/trunks/tpm_state_impl.h
@@ -19,6 +19,9 @@
 
 #include "trunks/tpm_state.h"
 
+#include <map>
+
+#include <base/callback.h>
 #include <base/macros.h>
 
 #include "trunks/tpm_generated.h"
@@ -32,7 +35,7 @@
 class TRUNKS_EXPORT TpmStateImpl : public TpmState {
  public:
   explicit TpmStateImpl(const TrunksFactory& factory);
-  ~TpmStateImpl() override;
+  ~TpmStateImpl() override = default;
 
   // TpmState methods.
   TPM_RC Initialize() override;
@@ -52,23 +55,30 @@
   uint32_t GetLockoutThreshold() override;
   uint32_t GetLockoutInterval() override;
   uint32_t GetLockoutRecovery() override;
+  uint32_t GetMaxNVSize() override;
+  bool GetTpmProperty(TPM_PT property, uint32_t* value) override;
+  bool GetAlgorithmProperties(TPM_ALG_ID algorithm,
+                              TPMA_ALGORITHM* properties) override;
 
  private:
-  // This helped method calls Tpm2_GetCapability with TPM_CAP_TPM_PROPERTIES
-  // and |property|. The returned structure is validated, and the value returned
-  // is stored in the out argument |value|. Returns TPM_RC_SUCCESS on success.
-  TPM_RC GetTpmProperty(uint32_t property, uint32_t* value);
+  // This helper method calls TPM2_GetCapability in a loop until all available
+  // capabilities of the given type are sent to the |callback|. The callback
+  // returns the next property value to query if there is more data available or
+  // 0 if the capability data was empty.
+  using CapabilityCallback = base::Callback<uint32_t(const TPMU_CAPABILITIES&)>;
+  TPM_RC GetCapability(const CapabilityCallback& callback,
+                       TPM_CAP capability,
+                       uint32_t property,
+                       uint32_t max_properties_per_call);
+  // Queries TPM properties and populates tpm_properties_.
+  TPM_RC CacheTpmProperties();
+  // Queries algorithm properties and populates algorithm_properties_.
+  TPM_RC CacheAlgorithmProperties();
 
   const TrunksFactory& factory_;
-  bool initialized_;
-  TPMA_PERMANENT permanent_flags_;
-  TPMA_STARTUP_CLEAR startup_clear_flags_;
-  uint32_t lockout_counter_;
-  uint32_t lockout_threshold_;
-  uint32_t lockout_interval_;
-  uint32_t lockout_recovery_;
-  TPMA_ALGORITHM rsa_flags_;
-  TPMA_ALGORITHM ecc_flags_;
+  bool initialized_{false};
+  std::map<TPM_PT, uint32_t> tpm_properties_;
+  std::map<TPM_ALG_ID, TPMA_ALGORITHM> algorithm_properties_;
 
   DISALLOW_COPY_AND_ASSIGN(TpmStateImpl);
 };
diff --git a/trunks/tpm_state_test.cc b/trunks/tpm_state_test.cc
index 7356d8e..24d17ca 100644
--- a/trunks/tpm_state_test.cc
+++ b/trunks/tpm_state_test.cc
@@ -32,124 +32,89 @@
 
 namespace trunks {
 
-// From definition of TPMA_STARTUP_CLEAR.
-const trunks::TPMA_STARTUP_CLEAR kPlatformHierarchyMask = 1U;
-
 // A test fixture for TpmState tests.
 class TpmStateTest : public testing::Test {
  public:
-  TpmStateTest() {}
-  ~TpmStateTest() override {}
+  TpmStateTest() = default;
+  ~TpmStateTest() override = default;
 
   void SetUp() override {
     factory_.set_tpm(&mock_tpm_);
-    permanent_data_ = GetValidCapabilityData(TPM_PT_PERMANENT, 0);
-    startup_clear_data_ = GetValidCapabilityData(TPM_PT_STARTUP_CLEAR, 0);
-    rsa_data_ = GetValidAlgorithmData(TPM_ALG_RSA, 0);
-    ecc_data_ = GetValidAlgorithmData(TPM_ALG_ECC, 0);
-    lockout_counter_ = GetValidCapabilityData(TPM_PT_LOCKOUT_COUNTER, 0);
-    lockout_threshold_ = GetValidCapabilityData(TPM_PT_MAX_AUTH_FAIL, 0);
-    lockout_interval_ = GetValidCapabilityData(TPM_PT_LOCKOUT_INTERVAL, 0);
-    lockout_recovery_ = GetValidCapabilityData(TPM_PT_LOCKOUT_RECOVERY, 0);
-    EXPECT_CALL(mock_tpm_, GetCapabilitySync(TPM_CAP_TPM_PROPERTIES,
-                                             TPM_PT_PERMANENT, 1, _, _, _))
-        .WillRepeatedly(
-            WithArgs<4>(Invoke(this, &TpmStateTest::GetLivePermanent)));
-    EXPECT_CALL(mock_tpm_, GetCapabilitySync(TPM_CAP_TPM_PROPERTIES,
-                                             TPM_PT_STARTUP_CLEAR, 1, _, _, _))
-        .WillRepeatedly(
-            WithArgs<4>(Invoke(this, &TpmStateTest::GetLiveStartupClear)));
-    EXPECT_CALL(mock_tpm_,
-                GetCapabilitySync(TPM_CAP_ALGS, TPM_ALG_RSA, 1, _, _, _))
-        .WillRepeatedly(WithArgs<4>(Invoke(this, &TpmStateTest::GetLiveRSA)));
-    EXPECT_CALL(mock_tpm_,
-                GetCapabilitySync(TPM_CAP_ALGS, TPM_ALG_ECC, 1, _, _, _))
-        .WillRepeatedly(WithArgs<4>(Invoke(this, &TpmStateTest::GetLiveECC)));
-    EXPECT_CALL(mock_tpm_,
-                GetCapabilitySync(TPM_CAP_TPM_PROPERTIES,
-                                  TPM_PT_LOCKOUT_COUNTER, 1, _, _, _))
-        .WillRepeatedly(
-            WithArgs<4>(Invoke(this, &TpmStateTest::GetLiveLockoutCounter)));
-    EXPECT_CALL(mock_tpm_, GetCapabilitySync(TPM_CAP_TPM_PROPERTIES,
-                                             TPM_PT_MAX_AUTH_FAIL, 1, _, _, _))
-        .WillRepeatedly(
-            WithArgs<4>(Invoke(this, &TpmStateTest::GetLiveLockoutThreshold)));
-    EXPECT_CALL(mock_tpm_,
-                GetCapabilitySync(TPM_CAP_TPM_PROPERTIES,
-                                  TPM_PT_LOCKOUT_INTERVAL, 1, _, _, _))
-        .WillRepeatedly(
-            WithArgs<4>(Invoke(this, &TpmStateTest::GetLiveLockoutInterval)));
-    EXPECT_CALL(mock_tpm_,
-                GetCapabilitySync(TPM_CAP_TPM_PROPERTIES,
-                                  TPM_PT_LOCKOUT_RECOVERY, 1, _, _, _))
-        .WillRepeatedly(
-            WithArgs<4>(Invoke(this, &TpmStateTest::GetLiveLockoutRecovery)));
-  }
-
-  TPM_RC GetLivePermanent(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = permanent_data_;
-    return TPM_RC_SUCCESS;
-  }
-  TPM_RC GetLiveStartupClear(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = startup_clear_data_;
-    return TPM_RC_SUCCESS;
-  }
-  TPM_RC GetLiveRSA(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = rsa_data_;
-    return TPM_RC_SUCCESS;
-  }
-  TPM_RC GetLiveECC(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = ecc_data_;
-    return TPM_RC_SUCCESS;
-  }
-  TPM_RC GetLiveLockoutCounter(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = lockout_counter_;
-    return TPM_RC_SUCCESS;
-  }
-  TPM_RC GetLiveLockoutThreshold(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = lockout_threshold_;
-    return TPM_RC_SUCCESS;
-  }
-  TPM_RC GetLiveLockoutInterval(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = lockout_interval_;
-    return TPM_RC_SUCCESS;
-  }
-  TPM_RC GetLiveLockoutRecovery(TPMS_CAPABILITY_DATA* capability_data) {
-    *capability_data = lockout_recovery_;
-    return TPM_RC_SUCCESS;
+    // All auth set (i.e. IsOwned() -> true) and in lockout.
+    fake_tpm_properties_[TPM_PT_PERMANENT] = 0x207;
+    // Orderly shutdown, storage and endorsement enabled, platform disabled
+    // (i.e. IsEnabled() -> true).
+    fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x80000006;
+    fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER] = 2;
+    fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL] = 5;
+    fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL] = 100;
+    fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY] = 200;
+    fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 2048;
+    fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 2048;
+    fake_algorithm_properties_[TPM_ALG_RSA] = 0x9;
+    fake_algorithm_properties_[TPM_ALG_ECC] = 0x9;
+    EXPECT_CALL(mock_tpm_, GetCapabilitySync(_, _, _, _, _, _))
+        .WillRepeatedly(Invoke(this, &TpmStateTest::FakeGetCapability));
   }
 
  protected:
-  TPMS_CAPABILITY_DATA GetValidCapabilityData(TPM_PT property, UINT32 value) {
-    TPMS_CAPABILITY_DATA data;
-    memset(&data, 0, sizeof(TPMS_CAPABILITY_DATA));
-    data.capability = TPM_CAP_TPM_PROPERTIES;
-    data.data.tpm_properties.count = 1;
-    data.data.tpm_properties.tpm_property[0].property = property;
-    data.data.tpm_properties.tpm_property[0].value = value;
-    return data;
-  }
-
-  TPMS_CAPABILITY_DATA GetValidAlgorithmData(TPM_ALG_ID alg_id, UINT32 value) {
-    TPMS_CAPABILITY_DATA data;
-    memset(&data, 0, sizeof(TPMS_CAPABILITY_DATA));
-    data.capability = TPM_CAP_ALGS;
-    data.data.tpm_properties.count = 1;
-    data.data.algorithms.alg_properties[0].alg = alg_id;
-    data.data.algorithms.alg_properties[0].alg_properties = value;
-    return data;
+  TPM_RC FakeGetCapability(const TPM_CAP& capability,
+                           const UINT32& property,
+                           const UINT32& property_count,
+                           TPMI_YES_NO* more_data,
+                           TPMS_CAPABILITY_DATA* capability_data,
+                           AuthorizationDelegate* /* not_used */) {
+    // Return only two properties at a time, this will exercise the more_data
+    // logic.
+    constexpr uint32_t kMaxProperties = 2;
+    *more_data = NO;
+    memset(capability_data, 0, sizeof(TPMS_CAPABILITY_DATA));
+    capability_data->capability = capability;
+    TPMU_CAPABILITIES& data = capability_data->data;
+    if (capability == TPM_CAP_TPM_PROPERTIES) {
+      // TPM properties get returned one group at a time, mimic this.
+      uint32_t group = (property >> 8);
+      uint32_t stop = PT_GROUP * (group + 1);
+      for (uint32_t i = property; i < stop; ++i) {
+        if (fake_tpm_properties_.count(i) > 0) {
+          if (data.tpm_properties.count == kMaxProperties ||
+              data.tpm_properties.count == property_count) {
+            // There are more properties than we can fit.
+            *more_data = YES;
+            break;
+          }
+          data.tpm_properties.tpm_property[data.tpm_properties.count].property =
+              i;
+          data.tpm_properties.tpm_property[data.tpm_properties.count].value =
+              fake_tpm_properties_[i];
+          data.tpm_properties.count++;
+        }
+      }
+    } else if (capability == TPM_CAP_ALGS) {
+      // Algorithm properties.
+      uint32_t stop = TPM_ALG_LAST + 1;
+      for (uint32_t i = property; i < stop; ++i) {
+        if (fake_algorithm_properties_.count(i) > 0) {
+          if (data.algorithms.count == kMaxProperties ||
+              data.algorithms.count == property_count) {
+            // There are more properties than we can fit.
+            *more_data = YES;
+            break;
+          }
+          data.algorithms.alg_properties[data.algorithms.count].alg = i;
+          data.algorithms.alg_properties[data.algorithms.count].alg_properties =
+              fake_algorithm_properties_[i];
+          data.algorithms.count++;
+        }
+      }
+    }
+    return TPM_RC_SUCCESS;
   }
 
   TrunksFactoryForTest factory_;
   NiceMock<MockTpm> mock_tpm_;
-  TPMS_CAPABILITY_DATA permanent_data_;
-  TPMS_CAPABILITY_DATA startup_clear_data_;
-  TPMS_CAPABILITY_DATA rsa_data_;
-  TPMS_CAPABILITY_DATA ecc_data_;
-  TPMS_CAPABILITY_DATA lockout_counter_;
-  TPMS_CAPABILITY_DATA lockout_threshold_;
-  TPMS_CAPABILITY_DATA lockout_interval_;
-  TPMS_CAPABILITY_DATA lockout_recovery_;
+  std::map<TPM_PT, uint32_t> fake_tpm_properties_;
+  std::map<TPM_ALG_ID, TPMA_ALGORITHM> fake_algorithm_properties_;
 };
 
 TEST(TpmState_DeathTest, NotInitialized) {
@@ -175,11 +140,18 @@
   EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetLockoutThreshold(), "Check failed");
   EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetLockoutInterval(), "Check failed");
   EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetLockoutRecovery(), "Check failed");
+  EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetMaxNVSize(), "Check failed");
+  EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetTpmProperty(0, nullptr),
+                            "Check failed");
+  EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetAlgorithmProperties(0, nullptr),
+                            "Check failed");
 }
 
 TEST_F(TpmStateTest, FlagsClear) {
+  fake_tpm_properties_[TPM_PT_PERMANENT] = 0;
+  fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0;
   TpmStateImpl tpm_state(factory_);
-  EXPECT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
   EXPECT_FALSE(tpm_state.IsOwnerPasswordSet());
   EXPECT_FALSE(tpm_state.IsEndorsementPasswordSet());
   EXPECT_FALSE(tpm_state.IsLockoutPasswordSet());
@@ -188,34 +160,15 @@
   EXPECT_FALSE(tpm_state.IsPlatformHierarchyEnabled());
   EXPECT_FALSE(tpm_state.IsStorageHierarchyEnabled());
   EXPECT_FALSE(tpm_state.IsEndorsementHierarchyEnabled());
-  EXPECT_FALSE(tpm_state.IsEnabled());
   EXPECT_FALSE(tpm_state.WasShutdownOrderly());
-  EXPECT_FALSE(tpm_state.IsRSASupported());
-  EXPECT_FALSE(tpm_state.IsECCSupported());
-  EXPECT_EQ(0u, tpm_state.GetLockoutCounter());
-  EXPECT_EQ(0u, tpm_state.GetLockoutThreshold());
-  EXPECT_EQ(0u, tpm_state.GetLockoutInterval());
-  EXPECT_EQ(0u, tpm_state.GetLockoutRecovery());
 }
 
 TEST_F(TpmStateTest, FlagsSet) {
-  uint32_t lockout_counter = 5;
-  uint32_t lockout_threshold = 8;
-  uint32_t lockout_interval = 1200;
-  uint32_t lockout_recovery = 84600;
-  permanent_data_.data.tpm_properties.tpm_property[0].value = ~0U;
-  startup_clear_data_.data.tpm_properties.tpm_property[0].value = ~0U;
-  lockout_counter_.data.tpm_properties.tpm_property[0].value = lockout_counter;
-  lockout_threshold_.data.tpm_properties.tpm_property[0].value =
-      lockout_threshold;
-  lockout_interval_.data.tpm_properties.tpm_property[0].value =
-      lockout_interval;
-  lockout_recovery_.data.tpm_properties.tpm_property[0].value =
-      lockout_recovery;
-  rsa_data_.data.algorithms.alg_properties[0].alg_properties = ~0U;
-  ecc_data_.data.algorithms.alg_properties[0].alg_properties = ~0U;
+  fake_tpm_properties_[TPM_PT_PERMANENT] = ~0;
+  fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = ~0;
+
   TpmStateImpl tpm_state(factory_);
-  EXPECT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
   EXPECT_TRUE(tpm_state.IsOwnerPasswordSet());
   EXPECT_TRUE(tpm_state.IsEndorsementPasswordSet());
   EXPECT_TRUE(tpm_state.IsLockoutPasswordSet());
@@ -224,158 +177,189 @@
   EXPECT_TRUE(tpm_state.IsPlatformHierarchyEnabled());
   EXPECT_TRUE(tpm_state.IsStorageHierarchyEnabled());
   EXPECT_TRUE(tpm_state.IsEndorsementHierarchyEnabled());
-  EXPECT_FALSE(tpm_state.IsEnabled());
   EXPECT_TRUE(tpm_state.WasShutdownOrderly());
-  EXPECT_TRUE(tpm_state.IsRSASupported());
-  EXPECT_TRUE(tpm_state.IsECCSupported());
-  EXPECT_EQ(lockout_counter, tpm_state.GetLockoutCounter());
-  EXPECT_EQ(lockout_threshold, tpm_state.GetLockoutThreshold());
-  EXPECT_EQ(lockout_interval, tpm_state.GetLockoutInterval());
-  EXPECT_EQ(lockout_recovery, tpm_state.GetLockoutRecovery());
 }
 
 TEST_F(TpmStateTest, EnabledTpm) {
-  startup_clear_data_.data.tpm_properties.tpm_property[0].value =
-      ~kPlatformHierarchyMask;
   TpmStateImpl tpm_state(factory_);
-  EXPECT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
-  EXPECT_FALSE(tpm_state.IsPlatformHierarchyEnabled());
-  EXPECT_TRUE(tpm_state.IsStorageHierarchyEnabled());
-  EXPECT_TRUE(tpm_state.IsEndorsementHierarchyEnabled());
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
   EXPECT_TRUE(tpm_state.IsEnabled());
-  EXPECT_TRUE(tpm_state.WasShutdownOrderly());
+  // All hierarchies enabled.
+  fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x7;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsEnabled());
+  // All hierarchies disabled.
+  fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x0;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsEnabled());
+  // Storage disabled.
+  fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x5;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsEnabled());
+  // Endorsement disabled.
+  fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x3;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsEnabled());
 }
 
-TEST_F(TpmStateTest, BadResponsePermanentCapabilityType) {
-  permanent_data_.capability = 0xFFFFF;
+TEST_F(TpmStateTest, OwnedTpm) {
+  TpmStateImpl tpm_state(factory_);
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_TRUE(tpm_state.IsOwned());
+  // All auth missing.
+  fake_tpm_properties_[TPM_PT_PERMANENT] = 0x0;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsOwned());
+  // Owner auth missing.
+  fake_tpm_properties_[TPM_PT_PERMANENT] = 0x6;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsOwned());
+  // Endorsement auth missing.
+  fake_tpm_properties_[TPM_PT_PERMANENT] = 0x5;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsOwned());
+  // Lockout auth missing.
+  fake_tpm_properties_[TPM_PT_PERMANENT] = 0x3;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.IsOwned());
+}
+
+TEST_F(TpmStateTest, AlgorithmSupport) {
+  TpmStateImpl tpm_state(factory_);
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_TRUE(tpm_state.IsRSASupported());
+  EXPECT_TRUE(tpm_state.IsECCSupported());
+
+  fake_algorithm_properties_.clear();
+  // Use a new instance because algorithm properties will not be queried again.
+  TpmStateImpl tpm_state2(factory_);
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state2.Initialize());
+  EXPECT_FALSE(tpm_state2.IsRSASupported());
+  EXPECT_FALSE(tpm_state2.IsECCSupported());
+}
+
+TEST_F(TpmStateTest, LockoutValuePassthrough) {
+  TpmStateImpl tpm_state(factory_);
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_EQ(tpm_state.GetLockoutCounter(),
+            fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER]);
+  EXPECT_EQ(tpm_state.GetLockoutThreshold(),
+            fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL]);
+  EXPECT_EQ(tpm_state.GetLockoutInterval(),
+            fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL]);
+  EXPECT_EQ(tpm_state.GetLockoutRecovery(),
+            fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY]);
+
+  fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER]++;
+  fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL]++;
+  fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL]++;
+  fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY]++;
+  // Refresh and check for the new values.
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_EQ(tpm_state.GetLockoutCounter(),
+            fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER]);
+  EXPECT_EQ(tpm_state.GetLockoutThreshold(),
+            fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL]);
+  EXPECT_EQ(tpm_state.GetLockoutInterval(),
+            fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL]);
+  EXPECT_EQ(tpm_state.GetLockoutRecovery(),
+            fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY]);
+}
+
+TEST_F(TpmStateTest, MaxNVSize) {
+  auto CheckMaxNVSize = [this]() {
+    TpmStateImpl tpm_state(factory_);
+    ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+    bool has_index = fake_tpm_properties_.count(TPM_PT_NV_INDEX_MAX) > 0;
+    bool has_buffer = fake_tpm_properties_.count(TPM_PT_NV_BUFFER_MAX) > 0;
+    if (has_index && has_buffer) {
+      EXPECT_EQ(tpm_state.GetMaxNVSize(),
+                std::min(fake_tpm_properties_[TPM_PT_NV_INDEX_MAX],
+                         fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX]));
+    } else if (has_index) {
+      EXPECT_EQ(tpm_state.GetMaxNVSize(),
+                fake_tpm_properties_[TPM_PT_NV_INDEX_MAX]);
+    } else if (has_buffer) {
+      EXPECT_EQ(tpm_state.GetMaxNVSize(),
+                fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX]);
+    } else {
+      // Check for a reasonable default value. Brillo specs a minimum of 2048 so
+      // it shouldn't be less than that.
+      EXPECT_GE(tpm_state.GetMaxNVSize(), 2048u);
+    }
+  };
+  // Check with the defaults (same index and buffer max).
+  CheckMaxNVSize();
+  // Check with lower buffer max.
+  fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 20;
+  fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 10;
+  CheckMaxNVSize();
+  // Check with lower index max.
+  fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 10;
+  fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 20;
+  CheckMaxNVSize();
+  // Check without index property.
+  fake_tpm_properties_.erase(TPM_PT_NV_INDEX_MAX);
+  fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 5;
+  CheckMaxNVSize();
+  // Check without buffer property.
+  fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 5;
+  fake_tpm_properties_.erase(TPM_PT_NV_BUFFER_MAX);
+  CheckMaxNVSize();
+  // Check without any properties.
+  fake_tpm_properties_.erase(TPM_PT_NV_INDEX_MAX);
+  fake_tpm_properties_.erase(TPM_PT_NV_BUFFER_MAX);
+  CheckMaxNVSize();
+}
+
+TEST_F(TpmStateTest, RawTpmProperty) {
+  constexpr TPM_PT kProperty = 0x2FF;
+  TpmStateImpl tpm_state(factory_);
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.GetTpmProperty(kProperty, nullptr));
+  uint32_t value;
+  EXPECT_FALSE(tpm_state.GetTpmProperty(kProperty, &value));
+
+  fake_tpm_properties_[kProperty] = 1234;
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_TRUE(tpm_state.GetTpmProperty(kProperty, nullptr));
+  EXPECT_TRUE(tpm_state.GetTpmProperty(kProperty, &value));
+  EXPECT_EQ(value, fake_tpm_properties_[kProperty]);
+}
+
+TEST_F(TpmStateTest, RawAlgorithmProperties) {
+  constexpr TPM_ALG_ID kAlgorithm = 0x39;
+  TpmStateImpl tpm_state(factory_);
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_FALSE(tpm_state.GetAlgorithmProperties(kAlgorithm, nullptr));
+  uint32_t value;
+  EXPECT_FALSE(tpm_state.GetAlgorithmProperties(kAlgorithm, &value));
+
+  fake_algorithm_properties_[kAlgorithm] = 1234;
+  TpmStateImpl tpm_state2(factory_);
+  ASSERT_EQ(TPM_RC_SUCCESS, tpm_state2.Initialize());
+  EXPECT_TRUE(tpm_state2.GetAlgorithmProperties(kAlgorithm, nullptr));
+  EXPECT_TRUE(tpm_state2.GetAlgorithmProperties(kAlgorithm, &value));
+  EXPECT_EQ(value, fake_algorithm_properties_[kAlgorithm]);
+}
+
+TEST_F(TpmStateTest, InitFailOnMissingPermanentFlags) {
+  fake_tpm_properties_.erase(TPM_PT_PERMANENT);
   TpmStateImpl tpm_state(factory_);
   EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
 }
 
-TEST_F(TpmStateTest, BadResponseStartupClearCapabilityType) {
-  startup_clear_data_.capability = 0xFFFFF;
+TEST_F(TpmStateTest, InitFailOnMissingStartupClearFlags) {
+  fake_tpm_properties_.erase(TPM_PT_STARTUP_CLEAR);
   TpmStateImpl tpm_state(factory_);
   EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
 }
 
-TEST_F(TpmStateTest, BadResponseLockoutCounterCapabilityType) {
-  lockout_counter_.capability = 0xFFFFF;
+TEST_F(TpmStateTest, InitFailOnFailedTPMCommand) {
+  EXPECT_CALL(mock_tpm_, GetCapabilitySync(_, _, _, _, _, _))
+      .WillRepeatedly(Return(TPM_RC_FAILURE));
   TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutThresholdCapabilityType) {
-  lockout_threshold_.capability = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutIntervalCapabilityType) {
-  lockout_interval_.capability = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutRecoveryCapabilityType) {
-  lockout_recovery_.capability = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseRSAAlgCapabilityType) {
-  rsa_data_.capability = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseECCAlgCapabilityType) {
-  ecc_data_.capability = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponsePermanentPropertyCount) {
-  permanent_data_.data.tpm_properties.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseStartupClearPropertyCount) {
-  startup_clear_data_.data.tpm_properties.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutCounterPropertyCount) {
-  lockout_counter_.data.tpm_properties.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutThresholdPropertyCount) {
-  lockout_threshold_.data.tpm_properties.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutIntervalPropertyCount) {
-  lockout_interval_.data.tpm_properties.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutRecoveryPropertyCount) {
-  lockout_recovery_.data.tpm_properties.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseRSAAlgPropertyCount) {
-  rsa_data_.data.algorithms.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseECCAlgPropertyCount) {
-  ecc_data_.data.algorithms.count = 0;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponsePermanentPropertyType) {
-  permanent_data_.data.tpm_properties.tpm_property[0].property = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseStartupClearPropertyType) {
-  startup_clear_data_.data.tpm_properties.tpm_property[0].property = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutCounterPropertyType) {
-  lockout_counter_.data.tpm_properties.tpm_property[0].property = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutThresholdPropertyType) {
-  lockout_threshold_.data.tpm_properties.tpm_property[0].property = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutIntervalPropertyType) {
-  lockout_interval_.data.tpm_properties.tpm_property[0].property = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
-}
-
-TEST_F(TpmStateTest, BadResponseLockoutRecoveryPropertyType) {
-  lockout_recovery_.data.tpm_properties.tpm_property[0].property = 0xFFFFF;
-  TpmStateImpl tpm_state(factory_);
-  EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize());
+  EXPECT_EQ(TPM_RC_FAILURE, tpm_state.Initialize());
 }
 
 }  // namespace trunks
diff --git a/trunks/trunks_factory_for_test.cc b/trunks/trunks_factory_for_test.cc
index f18bb0d..792adf9 100644
--- a/trunks/trunks_factory_for_test.cc
+++ b/trunks/trunks_factory_for_test.cc
@@ -97,6 +97,17 @@
     return target_->GetLockoutRecovery();
   }
 
+  uint32_t GetMaxNVSize() override { return target_->GetMaxNVSize(); }
+
+  bool GetTpmProperty(TPM_PT property, uint32_t* value) override {
+    return target_->GetTpmProperty(property, value);
+  }
+
+  bool GetAlgorithmProperties(TPM_ALG_ID algorithm,
+                              TPMA_ALGORITHM* properties) override {
+    return target_->GetAlgorithmProperties(algorithm, properties);
+  }
+
  private:
   TpmState* target_;
 };
@@ -576,7 +587,7 @@
 }
 
 std::unique_ptr<PolicySession> TrunksFactoryForTest::GetTrialSession() const {
-  return base::MakeUnique<PolicySessionForwarder>(policy_session_);
+  return base::MakeUnique<PolicySessionForwarder>(trial_session_);
 }
 
 std::unique_ptr<BlobParser> TrunksFactoryForTest::GetBlobParser() const {
diff --git a/trunks/trunksd-seccomp-amd64.policy b/trunks/trunksd-seccomp-amd64.policy
index aa8650b..fa8db09 100644
--- a/trunks/trunksd-seccomp-amd64.policy
+++ b/trunks/trunksd-seccomp-amd64.policy
@@ -78,6 +78,7 @@
 signalfd4: 1
 ioctl: 1
 getpriority: 1
+setpriority: 1
 exit: 1
 exit_group: 1
 chdir: 1
diff --git a/trunks/trunksd-seccomp-arm.policy b/trunks/trunksd-seccomp-arm.policy
index 40b0c1a..cc9e2b7 100644
--- a/trunks/trunksd-seccomp-arm.policy
+++ b/trunks/trunksd-seccomp-arm.policy
@@ -72,6 +72,7 @@
 signalfd4: 1
 ioctl: 1
 getpriority: 1
+setpriority: 1
 exit: 1
 exit_group: 1
 chdir: 1
diff --git a/trunks/trunksd-seccomp-arm64.policy b/trunks/trunksd-seccomp-arm64.policy
index 7581d3c..12d4a31 100644
--- a/trunks/trunksd-seccomp-arm64.policy
+++ b/trunks/trunksd-seccomp-arm64.policy
@@ -72,6 +72,7 @@
 signalfd4: 1
 ioctl: 1
 getpriority: 1
+setpriority: 1
 exit: 1
 exit_group: 1
 chdir: 1
diff --git a/trunks/trunksd-seccomp-mips.policy b/trunks/trunksd-seccomp-mips.policy
index f6ca4da..24b78b5 100644
--- a/trunks/trunksd-seccomp-mips.policy
+++ b/trunks/trunksd-seccomp-mips.policy
@@ -76,4 +76,3 @@
 exit: 1
 exit_group: 1
 chdir: 1
-
diff --git a/trunks/trunksd-seccomp-x86.policy b/trunks/trunksd-seccomp-x86.policy
index 575ccb8..b525b5f 100644
--- a/trunks/trunksd-seccomp-x86.policy
+++ b/trunks/trunksd-seccomp-x86.policy
@@ -79,6 +79,7 @@
 signalfd4: 1
 ioctl: 1
 getpriority: 1
+setpriority: 1
 exit: 1
 exit_group: 1
 chdir: 1
diff --git a/trunks/trunksd-seccomp-x86_64.policy b/trunks/trunksd-seccomp-x86_64.policy
index aa8650b..fa8db09 100644
--- a/trunks/trunksd-seccomp-x86_64.policy
+++ b/trunks/trunksd-seccomp-x86_64.policy
@@ -78,6 +78,7 @@
 signalfd4: 1
 ioctl: 1
 getpriority: 1
+setpriority: 1
 exit: 1
 exit_group: 1
 chdir: 1