trunks: implement ManageCCDPwd cr50 command

Add support for VENDOR_CC_MANAGE_CCD_PWD vendor command.

BUG=b:69972868
TEST=unit tests

Change-Id: I3138c6846b460764fa1ae2af3a6a465ce2962f34
Reviewed-on: https://chromium-review.googlesource.com/804600
Commit-Ready: Andrey Pronin <apronin@chromium.org>
Tested-by: Andrey Pronin <apronin@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
diff --git a/trunks/mock_tpm_utility.h b/trunks/mock_tpm_utility.h
index 2126163..e7b7028 100644
--- a/trunks/mock_tpm_utility.h
+++ b/trunks/mock_tpm_utility.h
@@ -157,6 +157,7 @@
                TPM_RC(TPM_ALG_ID, AuthorizationDelegate*, std::string*));
   MOCK_METHOD0(DeclareTpmFirmwareStable, TPM_RC());
   MOCK_METHOD1(GetPublicRSAEndorsementKey, TPM_RC(std::string*));
+  MOCK_METHOD1(ManageCCDPwd, TPM_RC(bool));
 };
 
 }  // namespace trunks
diff --git a/trunks/tpm_utility.h b/trunks/tpm_utility.h
index 62e5b32..503fb5e 100644
--- a/trunks/tpm_utility.h
+++ b/trunks/tpm_utility.h
@@ -364,6 +364,16 @@
   // modulus into |public_key|. Returns TPM_RC_SUCCESS on success.
   virtual TPM_RC GetPublicRSAEndorsementKey(std::string* public_key) = 0;
 
+  // For TPMs that support it: allow setting the CCD password if |allow_pwd|
+  // is true, prohibit otherwise.
+  // Returns the result of sending the appropriate command to the TPM.
+  // For TPMs that don't support it: NOP, always returns TPM_RC_SUCCESS.
+  // Rationale for this behavior: All TPM revisions that need restricting CCD
+  // password implement this command. If the command is not implemented, the
+  // TPM firmware has no notion of restricting the CCD password and doesn't need
+  // a signal to lock things down at login.
+  virtual TPM_RC ManageCCDPwd(bool allow_pwd) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(TpmUtility);
 };
diff --git a/trunks/tpm_utility_impl.cc b/trunks/tpm_utility_impl.cc
index df2ab97..c820ce8 100644
--- a/trunks/tpm_utility_impl.cc
+++ b/trunks/tpm_utility_impl.cc
@@ -55,6 +55,7 @@
 const uint32_t kCr50VendorCC = 0x20000000 | 0; /* Vendor Bit Set + 0 */
 // Vendor-specific subcommand codes.
 const uint16_t kCr50SubcmdInvalidateInactiveRW = 20;
+const uint16_t kCr50SubcmdManageCCDPwd = 33;
 
 // Auth policy used in RSA and ECC templates for EK keys generation.
 // From TCG Credential Profile EK 2.0. Section 2.1.5.
@@ -1784,6 +1785,16 @@
   return TPM_RC_SUCCESS;
 }
 
+TPM_RC TpmUtilityImpl::ManageCCDPwd(bool allow_pwd) {
+  if (!IsCr50()) {
+    return TPM_RC_SUCCESS;
+  }
+  std::string command_payload(1, allow_pwd ? 1 : 0);
+  std::string response_payload;
+  return Cr50VendorCommand(kCr50SubcmdManageCCDPwd,
+                           command_payload, &response_payload);
+}
+
 TPM_RC TpmUtilityImpl::SetKnownOwnerPassword(
     const std::string& known_owner_password) {
   std::unique_ptr<TpmState> tpm_state(factory_.GetTpmState());
diff --git a/trunks/tpm_utility_impl.h b/trunks/tpm_utility_impl.h
index e36887c..8093ee7 100644
--- a/trunks/tpm_utility_impl.h
+++ b/trunks/tpm_utility_impl.h
@@ -169,6 +169,7 @@
                            std::string* key_blob) override;
   TPM_RC DeclareTpmFirmwareStable() override;
   TPM_RC GetPublicRSAEndorsementKey(std::string* public_key) override;
+  TPM_RC ManageCCDPwd(bool allow_pwd) override;
 
  private:
   friend class TpmUtilityTest;
diff --git a/trunks/tpm_utility_test.cc b/trunks/tpm_utility_test.cc
index a16bb57..9175dec 100644
--- a/trunks/tpm_utility_test.cc
+++ b/trunks/tpm_utility_test.cc
@@ -2355,4 +2355,63 @@
             base::HexEncode(public_key.data(), public_key.size()));
 }
 
+TEST_F(TpmUtilityTest, ManageCCDPwdNonCr50) {
+  SetCr50(false);
+  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(_))
+      .Times(0);
+  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ManageCCDPwd(true));
+}
+
+TEST_F(TpmUtilityTest, ManageCCDPwdCr50Success) {
+  // A hand-coded kCr50SubcmdManageCCDPwd command (two variants: true and false)
+  // and response.
+  std::string expected_command_true(
+      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
+      "\x00\x00\x00\x0D"  // size=13
+      "\x20\x00\x00\x00"  // code=kCr50VendorCC
+      "\x00\x21"          // subcommand=kCr50SubcmdManageCCDPwd
+      "\x01",             // value=true
+      13);
+  std::string expected_command_false(
+      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
+      "\x00\x00\x00\x0D"  // size=13
+      "\x20\x00\x00\x00"  // code=kCr50VendorCC
+      "\x00\x21"          // subcommand=kCr50SubcmdManageCCDPwd
+      "\x00",             // value=false
+      13);
+  std::string command_response(
+      "\x80\x01"           // tag=TPM_ST_NO_SESSIONS
+      "\x00\x00\x00\x0A"   // size=10
+      "\x00\x00\x00\x00",  // code=TPM_RC_SUCCESS
+      10);
+  SetCr50(true);
+  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command_true))
+      .WillOnce(Return(command_response));
+  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ManageCCDPwd(true));
+  testing::Mock::VerifyAndClearExpectations(&mock_transceiver_);
+  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command_false))
+      .WillOnce(Return(command_response));
+  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ManageCCDPwd(false));
+}
+
+TEST_F(TpmUtilityTest, ManageCCDPwdFailure) {
+  // A hand-coded kCr50SubcmdManageCCDPwd command and response.
+  std::string expected_command(
+      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
+      "\x00\x00\x00\x0D"  // size=13
+      "\x20\x00\x00\x00"  // code=kCr50VendorCC
+      "\x00\x21"          // subcommand=kCr50SubcmdManageCCDPwd
+      "\x01",             // value=true
+      13);
+  std::string command_response(
+      "\x80\x01"           // tag=TPM_ST_NO_SESSIONS
+      "\x00\x00\x00\x0A"   // size=10
+      "\x00\x00\x01\x01",  // code=TPM_RC_FAILURE
+      10);
+  SetCr50(true);
+  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command))
+      .WillOnce(Return(command_response));
+  EXPECT_EQ(TPM_RC_FAILURE, utility_.ManageCCDPwd(true));
+}
+
 }  // namespace trunks
diff --git a/trunks/trunks_factory_for_test.cc b/trunks/trunks_factory_for_test.cc
index a9dc4af..aa404b4 100644
--- a/trunks/trunks_factory_for_test.cc
+++ b/trunks/trunks_factory_for_test.cc
@@ -406,6 +406,10 @@
     return target_->GetPublicRSAEndorsementKey(public_key);
   }
 
+  TPM_RC ManageCCDPwd(bool allow_pwd) override {
+    return target_->ManageCCDPwd(allow_pwd);
+  }
+
  private:
   TpmUtility* target_;
 };