attestation: Implemented TpmUtility for TPM 1.2

BUG=brillo:737
TEST=unit, manually ran against a CA

Change-Id: I4c97ae7ff17849cefa18df1d3c8f7035c1eab69a
Reviewed-on: https://chromium-review.googlesource.com/266918
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Darren Krahn <dkrahn@chromium.org>
Commit-Queue: Darren Krahn <dkrahn@chromium.org>
diff --git a/attestation.gyp b/attestation.gyp
index c0e71c3..39add1e 100644
--- a/attestation.gyp
+++ b/attestation.gyp
@@ -73,6 +73,7 @@
         'server/attestation_service.cc',
         'server/dbus_service.cc',
         'server/database_impl.cc',
+        'server/tpm_utility_v1.cc',
       ],
       'dependencies': [
         'proto_library',
diff --git a/common/database.proto b/common/database.proto
index adcf9ea..ec0196e 100644
--- a/common/database.proto
+++ b/common/database.proto
@@ -74,6 +74,12 @@
   // CA. See |AttestationCertificateResponse.additional_intermediate_ca_cert|
   // for more detail.
   repeated bytes additional_intermediate_ca_cert = 7;
+  // The public key in TPM_PUBKEY form.
+  optional bytes public_key_tpm_format = 8;
+  // The serialized TPM_CERTIFY_INFO for the certified key.
+  optional bytes certified_key_info = 9;
+  // The signature of the TPM_CERTIFY_INFO by the AIK.
+  optional bytes certified_key_proof = 10;
 }
 
 // Holds all information that a client stores locally.
diff --git a/server/attestation_service.cc b/server/attestation_service.cc
index 3c65c2a..d9387e9 100644
--- a/server/attestation_service.cc
+++ b/server/attestation_service.cc
@@ -109,11 +109,9 @@
       return;
     }
   }
-  if (!FindKeyByLabel(username, key_label, nullptr)) {
-    if (!CreateKey(username, key_label, key_type, key_usage)) {
-      result->status = STATUS_UNEXPECTED_DEVICE_ERROR;
-      return;
-    }
+  if (!CreateKey(username, key_label, key_type, key_usage)) {
+    result->status = STATUS_UNEXPECTED_DEVICE_ERROR;
+    return;
   }
   std::string certificate_request;
   std::string message_id;
@@ -261,15 +259,14 @@
     request_pb.set_origin(origin);
     request_pb.set_temporal_index(ChooseTemporalIndex(username, origin));
   }
-  std::string public_key;
-  std::string key_info;
-  std::string proof;
-  if (!CertifyKey(username, key_label, &public_key, &key_info, &proof)) {
+  CertifiedKey key;
+  if (!FindKeyByLabel(username, key_label, &key)) {
+    LOG(ERROR) << __func__ << ": Key not found.";
     return false;
   }
-  request_pb.set_certified_public_key(public_key);
-  request_pb.set_certified_key_info(key_info);
-  request_pb.set_certified_key_proof(proof);
+  request_pb.set_certified_public_key(key.public_key_tpm_format());
+  request_pb.set_certified_key_info(key.certified_key_info());
+  request_pb.set_certified_key_proof(key.certified_key_proof());
   if (!request_pb.SerializeToString(certificate_request)) {
     LOG(ERROR) << __func__ << ": Failed to serialize protobuf.";
     return false;
@@ -375,15 +372,36 @@
                                    const std::string& key_label,
                                    KeyType key_type,
                                    KeyUsage key_usage) {
+  std::string nonce;
+  if (!crypto_utility_->GetRandom(kNonceSize, &nonce)) {
+    LOG(ERROR) << __func__ << ": GetRandom(nonce) failed.";
+    return false;
+  }
   std::string key_blob;
   std::string public_key;
-  if (!tpm_utility_->GenerateKey(key_type, key_usage, &key_blob, &public_key)) {
+  std::string public_key_tpm_format;
+  std::string key_info;
+  std::string proof;
+  auto database_pb = database_->GetProtobuf();
+  if (!tpm_utility_->CreateCertifiedKey(
+      key_type,
+      key_usage,
+      database_pb.identity_key().identity_key_blob(),
+      nonce,
+      &key_blob,
+      &public_key,
+      &public_key_tpm_format,
+      &key_info,
+      &proof)) {
     return false;
   }
   CertifiedKey key;
   key.set_key_blob(key_blob);
   key.set_public_key(public_key);
   key.set_key_name(key_label);
+  key.set_public_key_tpm_format(public_key_tpm_format);
+  key.set_certified_key_info(key_info);
+  key.set_certified_key_proof(proof);
   return SaveKey(username, key_label, key);
 }
 
@@ -456,32 +474,6 @@
   }
 }
 
-bool AttestationService::CertifyKey(const std::string& username,
-                                    const std::string& key_label,
-                                    std::string* public_key_tpm_format,
-                                    std::string* key_info,
-                                    std::string* proof) {
-  CertifiedKey key;
-  if (!FindKeyByLabel(username, key_label, &key)) {
-    LOG(ERROR) << __func__ << ": Failed to certify key - key not found.";
-    return false;
-  }
-
-  std::string nonce;
-  if (!crypto_utility_->GetRandom(kNonceSize, &nonce)) {
-    LOG(ERROR) << __func__ << ": GetRandom(nonce) failed.";
-    return false;
-  }
-  auto database_pb = database_->GetProtobuf();
-  return tpm_utility_->CertifyKey(
-      key.key_blob(),
-      database_pb.identity_key().identity_key_blob(),
-      nonce,
-      public_key_tpm_format,
-      key_info,
-      proof);
-}
-
 std::string AttestationService::CreatePEMCertificateChain(
     const CertifiedKey& key) {
   if (key.certified_key_credential().empty()) {
diff --git a/server/attestation_service.h b/server/attestation_service.h
index 04dffe1..30b4f89 100644
--- a/server/attestation_service.h
+++ b/server/attestation_service.h
@@ -165,8 +165,8 @@
                               const std::string& request,
                               std::string* reply);
 
-  // Creates a new certifiable key for |username| with the given |key_label|,
-  // |key_type|, and |key_usage|.
+  // Creates, certifies, and saves a new key for |username| with the given
+  // |key_label|, |key_type|, and |key_usage|.
   bool CreateKey(const std::string& username,
                  const std::string& key_label,
                  KeyType key_type,
@@ -194,15 +194,6 @@
   // Removes a device-wide key from the attestation database.
   void RemoveDeviceKey(const std::string& key_label);
 
-  // Certifies the key associated with |username| and |key_label| with the
-  // Attestation Identity Key (AIK). On success returns true and populates
-  // outputs as required by the CA (see AttestationCertificateRequest).
-  bool CertifyKey(const std::string& username,
-                  const std::string& key_label,
-                  std::string* public_key_tpm_format,
-                  std::string* key_info,
-                  std::string* proof);
-
   // Creates a PEM certificate chain from the credential fields of a |key|.
   std::string CreatePEMCertificateChain(const CertifiedKey& key);
 
diff --git a/server/attestation_service_test.cc b/server/attestation_service_test.cc
index 9447e86..1c78664 100644
--- a/server/attestation_service_test.cc
+++ b/server/attestation_service_test.cc
@@ -451,48 +451,8 @@
   Run();
 }
 
-TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmGenerateFailure) {
-  // Return false once to simulate that a key does not initially exist.
-  EXPECT_CALL(mock_key_store_, Read(_, _, _))
-      .WillOnce(Return(false))
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(mock_tpm_utility_, GenerateKey(_, _, _, _))
-      .WillRepeatedly(Return(false));
-  // Set expectations on the outputs.
-  auto callback = [this](const std::string& certificate_chain,
-                         const std::string& server_error,
-                         AttestationStatus status) {
-    EXPECT_NE(STATUS_SUCCESS, status);
-    EXPECT_EQ("", certificate_chain);
-    EXPECT_EQ("", server_error);
-    Quit();
-  };
-  service_->CreateGoogleAttestedKey("label", KEY_TYPE_ECC, KEY_USAGE_SIGN,
-                                    ENTERPRISE_MACHINE_CERTIFICATE, "user",
-                                    "origin", base::Bind(callback));
-  Run();
-}
-
-TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmGenerateFailure2) {
-  EXPECT_CALL(mock_tpm_utility_, GenerateKey(_, _, _, _))
-      .WillRepeatedly(Return(false));
-  // Set expectations on the outputs.
-  auto callback = [this](const std::string& certificate_chain,
-                         const std::string& server_error,
-                         AttestationStatus status) {
-    EXPECT_NE(STATUS_SUCCESS, status);
-    EXPECT_EQ("", certificate_chain);
-    EXPECT_EQ("", server_error);
-    Quit();
-  };
-  service_->CreateGoogleAttestedKey("label", KEY_TYPE_ECC, KEY_USAGE_SIGN,
-                                    ENTERPRISE_MACHINE_CERTIFICATE, "",
-                                    "origin", base::Bind(callback));
-  Run();
-}
-
-TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmCertifyFailure) {
-  EXPECT_CALL(mock_tpm_utility_, CertifyKey(_, _, _, _, _, _))
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmCreateFailure) {
+  EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(_, _, _, _, _, _, _, _, _))
       .WillRepeatedly(Return(false));
   // Set expectations on the outputs.
   auto callback = [this](const std::string& certificate_chain,
diff --git a/server/mock_tpm_utility.cc b/server/mock_tpm_utility.cc
index 80692bd..4e10abd 100644
--- a/server/mock_tpm_utility.cc
+++ b/server/mock_tpm_utility.cc
@@ -13,8 +13,8 @@
   ON_CALL(*this, IsTpmReady()).WillByDefault(Return(true));
   ON_CALL(*this, ActivateIdentity(_, _, _, _, _, _))
       .WillByDefault(Return(true));
-  ON_CALL(*this, GenerateKey(_, _, _, _)).WillByDefault(Return(true));
-  ON_CALL(*this, CertifyKey(_, _, _, _, _, _)).WillByDefault(Return(true));
+  ON_CALL(*this, CreateCertifiedKey(_, _, _, _, _, _, _, _, _))
+      .WillByDefault(Return(true));
 }
 
 MockTpmUtility::~MockTpmUtility() {}
diff --git a/server/mock_tpm_utility.h b/server/mock_tpm_utility.h
index 3f2b616..b0a5b65 100644
--- a/server/mock_tpm_utility.h
+++ b/server/mock_tpm_utility.h
@@ -25,14 +25,15 @@
                                       const std::string&,
                                       const std::string&,
                                       std::string*));
-  MOCK_METHOD4(GenerateKey, bool(KeyType, KeyUsage, std::string*,
-                                 std::string*));
-  MOCK_METHOD6(CertifyKey, bool(const std::string&,
-                                const std::string&,
-                                const std::string&,
-                                std::string*,
-                                std::string*,
-                                std::string*));
+  MOCK_METHOD9(CreateCertifiedKey, bool(KeyType,
+                                        KeyUsage,
+                                        const std::string&,
+                                        const std::string&,
+                                        std::string*,
+                                        std::string*,
+                                        std::string*,
+                                        std::string*,
+                                        std::string*));
 };
 
 }  // namespace attestation
diff --git a/server/tpm_utility.h b/server/tpm_utility.h
index bd447a2..9b79ea2 100644
--- a/server/tpm_utility.h
+++ b/server/tpm_utility.h
@@ -34,26 +34,23 @@
                                 const std::string& sym_ca_attestation,
                                 std::string* credential) = 0;
 
-  // Generates a non-migratable key in the TPM corresponding to |key_type| and
-  // |key_usage|. The parent key will be the storage root key. The new key will
-  // always be certifiable.
-  virtual bool GenerateKey(KeyType key_type,
-                           KeyUsage key_usage,
-                           std::string* key_blob,
-                           std::string* public_key) = 0;
-
-  // Certifies the key represented by |key_blob| with the attestation identity
-  // key represented by |identity_key_blob|. The |external_data| will be
-  // included in the |key_info|. On success, returns true and populates
+  // Generates and certifies a non-migratable key in the TPM. The new key will
+  // correspond to |key_type| and |key_usage|. The parent key will be the
+  // storage root key. The new key will be certified with the attestation
+  // identity key represented by |identity_key_blob|. The |external_data| will
+  // be included in the |key_info|. On success, returns true and populates
   // |public_key_tpm_format| with the public key of |key_blob| in TPM_PUBKEY
   // format, |key_info| with the TPM_CERTIFY_INFO that was signed, and |proof|
   // with the signature of |key_info| by the identity key.
-  virtual bool CertifyKey(const std::string& key_blob,
-                          const std::string& identity_key_blob,
-                          const std::string& external_data,
-                          std::string* public_key_tpm_format,
-                          std::string* key_info,
-                          std::string* proof) = 0;
+  virtual bool CreateCertifiedKey(KeyType key_type,
+                                  KeyUsage key_usage,
+                                  const std::string& identity_key_blob,
+                                  const std::string& external_data,
+                                  std::string* key_blob,
+                                  std::string* public_key,
+                                  std::string* public_key_tpm_format,
+                                  std::string* key_info,
+                                  std::string* proof) = 0;
 };
 
 }  // namespace attestation
diff --git a/server/tpm_utility_v1.cc b/server/tpm_utility_v1.cc
new file mode 100644
index 0000000..d87d475
--- /dev/null
+++ b/server/tpm_utility_v1.cc
@@ -0,0 +1,443 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "attestation/server/tpm_utility_v1.h"
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/stl_util.h>
+#include <crypto/scoped_openssl_types.h>
+#include <openssl/rsa.h>
+#include <trousers/scoped_tss_type.h>
+#include <trousers/trousers.h>
+#include <trousers/tss.h>
+
+#define TPM_LOG(severity, result) \
+    LOG(severity) << "TPM error 0x" << std::hex << result \
+                  << " (" << Trspi_Error_String(result) << "): "
+
+using trousers::ScopedTssContext;
+using trousers::ScopedTssKey;
+using trousers::ScopedTssMemory;
+
+namespace {
+
+typedef scoped_ptr<BYTE, base::FreeDeleter> ScopedByteArray;
+
+const char* kTpmEnabledFile = "/sys/class/misc/tpm0/device/enabled";
+const char* kTpmOwnedFile = "/sys/class/misc/tpm0/device/owned";
+const unsigned int kWellKnownExponent = 65537;
+
+std::string GetFirstByte(const char* file_name) {
+  std::string content;
+  base::ReadFileToString(base::FilePath(file_name), &content);
+  if (content.size() > 1) {
+    content.resize(1);
+  }
+  return content;
+}
+
+}  // namespace
+
+namespace attestation {
+
+TpmUtilityV1::~TpmUtilityV1() {}
+
+bool TpmUtilityV1::Initialize() {
+  if (!ConnectContext(&context_handle_, &tpm_handle_)) {
+    LOG(ERROR) << __func__ << ": Failed to connect to the TPM.";
+    return false;
+  }
+  srk_handle_.reset(context_handle_, 0);
+  if (!LoadSrk(context_handle_, &srk_handle_)) {
+    LOG(ERROR) << __func__ << ": Failed to load SRK.";
+    return false;
+  }
+  // In order to wrap a key with the SRK we need access to the SRK public key
+  // and we need to get it manually. Once it's in the key object, we don't need
+  // to do this again.
+  UINT32 length = 0;
+  ScopedTssMemory buffer(context_handle_);
+  TSS_RESULT result;
+  result = Tspi_Key_GetPubKey(srk_handle_, &length, buffer.ptr());
+  if (result != TSS_SUCCESS) {
+    TPM_LOG(INFO, result) << __func__ << ": Failed to read SRK public key.";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::IsTpmReady() {
+  if (!is_ready_) {
+    is_ready_ = (GetFirstByte(kTpmEnabledFile) == "1" &&
+                 GetFirstByte(kTpmOwnedFile) == "1");
+  }
+  return is_ready_;
+}
+
+bool TpmUtilityV1::ActivateIdentity(const std::string& delegate_blob,
+                                    const std::string& delegate_secret,
+                                    const std::string& identity_key_blob,
+                                    const std::string& asym_ca_contents,
+                                    const std::string& sym_ca_attestation,
+                                    std::string* credential) {
+  CHECK(credential);
+
+  // Connect to the TPM as the owner delegate.
+  ScopedTssContext context_handle_;
+  TSS_HTPM tpm_handle;
+  if (!ConnectContextAsDelegate(delegate_blob, delegate_secret,
+                                &context_handle_, &tpm_handle)) {
+    LOG(ERROR) << __func__ << ": Could not connect to the TPM.";
+    return false;
+  }
+  // Load the Storage Root Key.
+  TSS_RESULT result;
+  ScopedTssKey srk_handle(context_handle_);
+  if (!LoadSrk(context_handle_, &srk_handle)) {
+    LOG(ERROR) << __func__ << ": Failed to load SRK.";
+    return false;
+  }
+  // Load the AIK (which is wrapped by the SRK).
+  std::string mutable_identity_key_blob(identity_key_blob);
+  BYTE* identity_key_blob_buffer = reinterpret_cast<BYTE*>(string_as_array(
+      &mutable_identity_key_blob));
+  ScopedTssKey identity_key(context_handle_);
+  result = Tspi_Context_LoadKeyByBlob(
+      context_handle_,
+      srk_handle,
+      identity_key_blob.size(),
+      identity_key_blob_buffer,
+      identity_key.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to load AIK.";
+    return false;
+  }
+  std::string mutable_asym_ca_contents(asym_ca_contents);
+  BYTE* asym_ca_contents_buffer = reinterpret_cast<BYTE*>(string_as_array(
+      &mutable_asym_ca_contents));
+  std::string mutable_sym_ca_attestation(sym_ca_attestation);
+  BYTE* sym_ca_attestation_buffer = reinterpret_cast<BYTE*>(string_as_array(
+      &mutable_sym_ca_attestation));
+  UINT32 credential_length = 0;
+  ScopedTssMemory credential_buffer(context_handle_);
+  result = Tspi_TPM_ActivateIdentity(tpm_handle, identity_key,
+                                     asym_ca_contents.size(),
+                                     asym_ca_contents_buffer,
+                                     sym_ca_attestation.size(),
+                                     sym_ca_attestation_buffer,
+                                     &credential_length,
+                                     credential_buffer.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to activate identity.";
+    return false;
+  }
+  credential->assign(reinterpret_cast<const char*>(credential_buffer.value()),
+                     credential_length);
+  return true;
+}
+
+bool TpmUtilityV1::CreateCertifiedKey(KeyType key_type,
+                                      KeyUsage key_usage,
+                                      const std::string& identity_key_blob,
+                                      const std::string& external_data,
+                                      std::string* key_blob,
+                                      std::string* public_key,
+                                      std::string* public_key_tpm_format,
+                                      std::string* key_info,
+                                      std::string* proof) {
+  CHECK(key_blob && public_key && public_key_tpm_format && key_info && proof);
+  if (key_type != KEY_TYPE_RSA) {
+    LOG(ERROR) << "Only RSA supported on TPM v1.2.";
+    return false;
+  }
+
+  // Load the AIK (which is wrapped by the SRK).
+  ScopedTssKey identity_key(context_handle_);
+  if (!LoadKeyFromBlob(identity_key_blob, context_handle_, srk_handle_,
+                       &identity_key)) {
+    LOG(ERROR) << __func__ << "Failed to load AIK.";
+    return false;
+  }
+
+  // Create a non-migratable RSA key.
+  ScopedTssKey key(context_handle_);
+  UINT32 tss_key_type = (key_usage == KEY_USAGE_SIGN) ? TSS_KEY_TYPE_SIGNING :
+                                                        TSS_KEY_TYPE_BIND;
+  UINT32 init_flags = tss_key_type |
+                      TSS_KEY_NOT_MIGRATABLE |
+                      TSS_KEY_VOLATILE |
+                      TSS_KEY_SIZE_2048;
+  TSS_RESULT result = Tspi_Context_CreateObject(context_handle_,
+                                                TSS_OBJECT_TYPE_RSAKEY,
+                                                init_flags, key.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to create object.";
+    return false;
+  }
+  result = Tspi_SetAttribUint32(key,
+                                TSS_TSPATTRIB_KEY_INFO,
+                                TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
+                                TSS_SS_RSASSAPKCS1V15_DER);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to set signature scheme.";
+    return false;
+  }
+  result = Tspi_Key_CreateKey(key, srk_handle_, 0);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to create key.";
+    return false;
+  }
+  result = Tspi_Key_LoadKey(key, srk_handle_);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to load key.";
+    return false;
+  }
+
+  // Certify the key.
+  TSS_VALIDATION validation;
+  memset(&validation, 0, sizeof(validation));
+  validation.ulExternalDataLength = external_data.size();
+  std::string mutable_external_data(external_data);
+  validation.rgbExternalData = reinterpret_cast<BYTE*>(string_as_array(
+      &mutable_external_data));
+  result = Tspi_Key_CertifyKey(key, identity_key, &validation);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to certify key.";
+    return false;
+  }
+  ScopedTssMemory scoped_certified_data(0, validation.rgbData);
+  ScopedTssMemory scoped_proof(0, validation.rgbValidationData);
+
+  // Get the certified public key.
+  if (!GetDataAttribute(context_handle_,
+                        key,
+                        TSS_TSPATTRIB_KEY_BLOB,
+                        TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY,
+                        public_key_tpm_format)) {
+    LOG(ERROR) << __func__ << ": Failed to read public key.";
+    return false;
+  }
+  if (!ConvertPublicKeyToDER(*public_key_tpm_format, public_key)) {
+    return false;
+  }
+
+  // Get the certified key blob so we can load it later.
+  if (!GetDataAttribute(context_handle_,
+                        key,
+                        TSS_TSPATTRIB_KEY_BLOB,
+                        TSS_TSPATTRIB_KEYBLOB_BLOB,
+                        key_blob)) {
+    LOG(ERROR) << __func__ << ": Failed to read key blob.";
+    return false;
+  }
+
+  // Get the data that was certified.
+  key_info->assign(reinterpret_cast<const char*>(validation.rgbData),
+                   validation.ulDataLength);
+
+  // Get the certification proof.
+  proof->assign(reinterpret_cast<const char*>(validation.rgbValidationData),
+                validation.ulValidationDataLength);
+  return true;
+}
+
+bool TpmUtilityV1::ConnectContext(ScopedTssContext* context, TSS_HTPM* tpm) {
+  *tpm = 0;
+  TSS_RESULT result;
+  if (TPM_ERROR(result = Tspi_Context_Create(context->ptr()))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_Create";
+    return false;
+  }
+  if (TPM_ERROR(result = Tspi_Context_Connect(*context, nullptr))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Context_Connect";
+    return false;
+  }
+  if (TPM_ERROR(result = Tspi_Context_GetTpmObject(*context, tpm))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Context_GetTpmObject";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::ConnectContextAsDelegate(const std::string& delegate_blob,
+                                            const std::string& delegate_secret,
+                                            ScopedTssContext* context,
+                                            TSS_HTPM* tpm) {
+  *tpm = 0;
+  if (!ConnectContext(context, tpm)) {
+    return false;
+  }
+  TSS_RESULT result;
+  TSS_HPOLICY tpm_usage_policy;
+  if (TPM_ERROR(result = Tspi_GetPolicyObject(*tpm,
+                                              TSS_POLICY_USAGE,
+                                              &tpm_usage_policy))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_GetPolicyObject";
+    return false;
+  }
+  std::string mutable_delegate_secret(delegate_secret);
+  BYTE* secret_buffer = reinterpret_cast<BYTE*>(string_as_array(
+      &mutable_delegate_secret));
+  if (TPM_ERROR(result = Tspi_Policy_SetSecret(tpm_usage_policy,
+                                               TSS_SECRET_MODE_PLAIN,
+                                               delegate_secret.size(),
+                                               secret_buffer))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Policy_SetSecret";
+    return false;
+  }
+  std::string mutable_delegate_blob(delegate_blob);
+  BYTE* blob_buffer = reinterpret_cast<BYTE*>(string_as_array(
+      &mutable_delegate_blob));
+  if (TPM_ERROR(result = Tspi_SetAttribData(
+      tpm_usage_policy,
+      TSS_TSPATTRIB_POLICY_DELEGATION_INFO,
+      TSS_TSPATTRIB_POLDEL_OWNERBLOB,
+      delegate_blob.size(),
+      blob_buffer))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_SetAttribData";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::LoadSrk(TSS_HCONTEXT context_handle,
+                           ScopedTssKey* srk_handle) {
+  TSS_RESULT result;
+  TSS_UUID uuid = TSS_UUID_SRK;
+  if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID(context_handle_,
+                                                    TSS_PS_TYPE_SYSTEM,
+                                                    uuid,
+                                                    srk_handle->ptr()))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Context_LoadKeyByUUID";
+    return false;
+  }
+  // Check if the SRK wants a password.
+  UINT32 auth_usage;
+  if (TPM_ERROR(result = Tspi_GetAttribUint32(*srk_handle,
+                                              TSS_TSPATTRIB_KEY_INFO,
+                                              TSS_TSPATTRIB_KEYINFO_AUTHUSAGE,
+                                              &auth_usage))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_GetAttribUint32";
+    return false;
+  }
+  if (auth_usage) {
+    // Give it an empty password if needed.
+    TSS_HPOLICY usage_policy;
+    if (TPM_ERROR(result = Tspi_GetPolicyObject(*srk_handle,
+                                                TSS_POLICY_USAGE,
+                                                &usage_policy))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_GetPolicyObject";
+      return false;
+    }
+
+    BYTE empty_password[] = {};
+    if (TPM_ERROR(result = Tspi_Policy_SetSecret(usage_policy,
+                                                 TSS_SECRET_MODE_PLAIN,
+                                                 0, empty_password))) {
+      TPM_LOG(ERROR, result) << __func__
+                             << ": Error calling Tspi_Policy_SetSecret";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool TpmUtilityV1::LoadKeyFromBlob(const std::string& key_blob,
+                                   TSS_HCONTEXT context_handle_,
+                                   TSS_HKEY parent_key_handle,
+                                   ScopedTssKey* key_handle) {
+  std::string mutable_key_blob(key_blob);
+  BYTE* key_blob_buffer = reinterpret_cast<BYTE*>(string_as_array(
+      &mutable_key_blob));
+  TSS_RESULT result = Tspi_Context_LoadKeyByBlob(
+      context_handle_,
+      parent_key_handle,
+      key_blob.size(),
+      key_blob_buffer,
+      key_handle->ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to load key by blob.";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::GetDataAttribute(TSS_HCONTEXT context,
+                                    TSS_HOBJECT object,
+                                    TSS_FLAG flag,
+                                    TSS_FLAG sub_flag,
+                                    std::string* data) {
+  UINT32 length = 0;
+  ScopedTssMemory buffer(context);
+  TSS_RESULT result = Tspi_GetAttribData(object, flag, sub_flag, &length,
+                                         buffer.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << "Failed to read object attribute.";
+    return false;
+  }
+  data->assign(reinterpret_cast<const char*>(buffer.value()), length);
+  return true;
+}
+
+bool TpmUtilityV1::ConvertPublicKeyToDER(const std::string& public_key,
+                                         std::string* public_key_der) {
+  // Parse the serialized TPM_PUBKEY.
+  UINT64 offset = 0;
+  std::string mutable_public_key(public_key);
+  BYTE* buffer = reinterpret_cast<BYTE*>(string_as_array(&mutable_public_key));
+  TPM_PUBKEY parsed;
+  TSS_RESULT result = Trspi_UnloadBlob_PUBKEY(&offset, buffer, &parsed);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << "Failed to parse TPM_PUBKEY.";
+    return false;
+  }
+  ScopedByteArray scoped_key(parsed.pubKey.key);
+  ScopedByteArray scoped_parms(parsed.algorithmParms.parms);
+  TPM_RSA_KEY_PARMS* parms =
+      reinterpret_cast<TPM_RSA_KEY_PARMS*>(parsed.algorithmParms.parms);
+  crypto::ScopedRSA rsa(RSA_new());
+  CHECK(rsa.get());
+  // Get the public exponent.
+  if (parms->exponentSize == 0) {
+    rsa.get()->e = BN_new();
+    CHECK(rsa.get()->e);
+    BN_set_word(rsa.get()->e, kWellKnownExponent);
+  } else {
+    rsa.get()->e = BN_bin2bn(parms->exponent, parms->exponentSize, NULL);
+    CHECK(rsa.get()->e);
+  }
+  // Get the modulus.
+  rsa.get()->n = BN_bin2bn(parsed.pubKey.key, parsed.pubKey.keyLength, NULL);
+  CHECK(rsa.get()->n);
+
+  // DER encode.
+  int der_length = i2d_RSAPublicKey(rsa.get(), NULL);
+  if (der_length < 0) {
+    LOG(ERROR) << "Failed to DER-encode public key.";
+    return false;
+  }
+  public_key_der->resize(der_length);
+  unsigned char* der_buffer = reinterpret_cast<unsigned char*>(
+      string_as_array(public_key_der));
+  der_length = i2d_RSAPublicKey(rsa.get(), &der_buffer);
+  if (der_length < 0) {
+    LOG(ERROR) << "Failed to DER-encode public key.";
+    return false;
+  }
+  public_key_der->resize(der_length);
+  return true;
+}
+
+
+}  // namespace attestation
diff --git a/server/tpm_utility_v1.h b/server/tpm_utility_v1.h
new file mode 100644
index 0000000..d468429
--- /dev/null
+++ b/server/tpm_utility_v1.h
@@ -0,0 +1,96 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ATTESTATION_SERVER_TPM_UTILITY_V1_H_
+#define ATTESTATION_SERVER_TPM_UTILITY_V1_H_
+
+#include "attestation/server/tpm_utility.h"
+
+#include <string>
+
+#include <base/macros.h>
+#include <trousers/scoped_tss_type.h>
+#include <trousers/tss.h>
+
+namespace attestation {
+
+// A TpmUtility implementation for TPM v1.2 modules.
+class TpmUtilityV1 : public TpmUtility {
+ public:
+  TpmUtilityV1() = default;
+  ~TpmUtilityV1() override;
+
+  // Initializes a TpmUtilityV1 instance. This method must be called
+  // successfully before calling any other methods.
+  bool Initialize();
+
+  // TpmUtility methods.
+  bool IsTpmReady() override;
+  bool ActivateIdentity(const std::string& delegate_blob,
+                        const std::string& delegate_secret,
+                        const std::string& identity_key_blob,
+                        const std::string& asym_ca_contents,
+                        const std::string& sym_ca_attestation,
+                        std::string* credential) override;
+  bool CreateCertifiedKey(KeyType key_type,
+                          KeyUsage key_usage,
+                          const std::string& identity_key_blob,
+                          const std::string& external_data,
+                          std::string* key_blob,
+                          std::string* public_key,
+                          std::string* public_key_tpm_format,
+                          std::string* key_info,
+                          std::string* proof) override;
+
+ private:
+  // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
+  // its matching TPM object iff the context can be created and a TPM object
+  // exists in the TSS. Returns true on success.
+  bool ConnectContext(trousers::ScopedTssContext* context_handle,
+                      TSS_HTPM* tpm_handle);
+
+  // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
+  // its matching TPM object authorized by the given |delegate_blob| and
+  // |delegate_secret|. Returns true on success.
+  bool ConnectContextAsDelegate(const std::string& delegate_blob,
+                                const std::string& delegate_secret,
+                                trousers::ScopedTssContext* context,
+                                TSS_HTPM* tpm);
+
+  // Loads the storage root key (SRK) and populates |srk_handle|. The
+  // |context_handle| must be connected and valid. Returns true on success.
+  bool LoadSrk(TSS_HCONTEXT context_handle, trousers::ScopedTssKey* srk_handle);
+
+  // Loads a key in the TPM given a |key_blob| and a |parent_key_handle|. The
+  // |context_handle| must be connected and valid. Returns true and populates
+  // |key_handle| on success.
+  bool LoadKeyFromBlob(const std::string& key_blob,
+                       TSS_HCONTEXT context_handle,
+                       TSS_HKEY parent_key_handle,
+                       trousers::ScopedTssKey* key_handle);
+
+  // Retrieves a |data| attribute defined by |flag| and |sub_flag| from a TSS
+  // |object_handle|. The |context_handle| is only used for TSS memory
+  // management.
+  bool GetDataAttribute(TSS_HCONTEXT context_handle,
+                        TSS_HOBJECT object_handle,
+                        TSS_FLAG flag,
+                        TSS_FLAG sub_flag,
+                        std::string* data);
+
+  // Converts a public in TPM_PUBKEY format to a DER-encoded RSAPublicKey.
+  bool ConvertPublicKeyToDER(const std::string& public_key,
+                             std::string* public_key_der);
+
+  bool is_ready_{false};
+  trousers::ScopedTssContext context_handle_;
+  TSS_HTPM tpm_handle_{0};
+  trousers::ScopedTssKey srk_handle_{0};
+
+  DISALLOW_COPY_AND_ASSIGN(TpmUtilityV1);
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_TPM_UTILITY_V1_H_