attestation: Implemented a Sign operation.

Keys that were created with KEY_USAGE_SIGN usage can be used to sign
arbitrary data with the RSA-PKCS1v15-SHA256 mechanism.

BUG=brillo:737
TEST=unit, manual using 'attestation_client sign' and
'attestation_client verify'

Change-Id: Iafaf938e3df9bc65f82e5b134ccf94fa7f56b6b1
Reviewed-on: https://chromium-review.googlesource.com/270008
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Darren Krahn <dkrahn@chromium.org>
Tested-by: Darren Krahn <dkrahn@chromium.org>
diff --git a/client/dbus_proxy.cc b/client/dbus_proxy.cc
index b505f04..2089f05 100644
--- a/client/dbus_proxy.cc
+++ b/client/dbus_proxy.cc
@@ -159,4 +159,20 @@
       request);
 }
 
+void DBusProxy::Sign(const SignRequest& request, const SignCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    SignReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kSign,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
 }  // namespace attestation
diff --git a/client/dbus_proxy.h b/client/dbus_proxy.h
index 49ae1e7..678070d 100644
--- a/client/dbus_proxy.h
+++ b/client/dbus_proxy.h
@@ -44,6 +44,7 @@
       const CreateCertifiableKeyCallback& callback) override;
   void Decrypt(const DecryptRequest& request,
                const DecryptCallback& callback) override;
+  void Sign(const SignRequest& request, const SignCallback& callback) override;
 
   // Useful for testing.
   void set_object_proxy(dbus::ObjectProxy* object_proxy) {
diff --git a/client/dbus_proxy_test.cc b/client/dbus_proxy_test.cc
index 51f24d4..f0855f0 100644
--- a/client/dbus_proxy_test.cc
+++ b/client/dbus_proxy_test.cc
@@ -326,4 +326,42 @@
   EXPECT_EQ(1, callback_count);
 }
 
+TEST_F(DBusProxyTest, Sign) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    SignRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ("label", request_proto.key_label());
+    EXPECT_EQ("user", request_proto.username());
+    EXPECT_EQ("data", request_proto.data_to_sign());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    SignReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_signature("signature");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const SignReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("signature", reply.signature());
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  proxy_.Sign(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
 }  // namespace attestation
diff --git a/client/main.cc b/client/main.cc
index 9c8b68e..1d00b18 100644
--- a/client/main.cc
+++ b/client/main.cc
@@ -31,6 +31,8 @@
 const char kEncryptForActivateCommand[] = "encrypt_for_activate";
 const char kEncryptCommand[] = "encrypt";
 const char kDecryptCommand[] = "decrypt";
+const char kSignCommand[] = "sign";
+const char kVerifyCommand[] = "verify";
 const char kUsage[] = R"(
 Usage: attestation_client <command> [<args>]
 Commands:
@@ -56,10 +58,18 @@
 
   encrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
           --output=<output_file>
-      Encrypts the content of |input_file| as required by the TPM for a decrypt
+      Encrypts the contents of |input_file| as required by the TPM for a decrypt
       operation. The result is written to |output_file|.
   decrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
-      Decrypts the content of |input_file|.
+      Decrypts the contents of |input_file|.
+
+  sign [--user=<email>] [--label=<keylabel>] --input=<input_file>
+          [--output=<output_file>]
+      Signs the contents of |input_file|.
+  verify [--user=<email>] [--label=<keylabel] --input=<signed_data_file>
+          --signature=<signature_file>
+      Verifies the signature in |signature_file| against the contents of
+      |input_file|.
 )";
 
 // The Daemon class works well as a client loop as well.
@@ -191,6 +201,44 @@
                         command_line->GetSwitchValueASCII("label"),
                         command_line->GetSwitchValueASCII("user"),
                         input);
+    } else if (args.front() == kSignCommand) {
+      if (!command_line->HasSwitch("input")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::CallSign,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"),
+                        input);
+    } else if (args.front() == kVerifyCommand) {
+      if (!command_line->HasSwitch("input") ||
+          !command_line->HasSwitch("signature")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      std::string signature;
+      base::FilePath filename2(command_line->GetSwitchValueASCII("signature"));
+      if (!base::ReadFileToString(filename2, &signature)) {
+        LOG(ERROR) << "Failed to read file: " << filename2.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::VerifySignature,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"),
+                        input,
+                        signature);
     } else {
       return EX_USAGE;
     }
@@ -363,6 +411,49 @@
                    weak_factory_.GetWeakPtr()));
   }
 
+  void CallSign(const std::string& label,
+                const std::string& username,
+                const std::string& input) {
+    SignRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    request.set_data_to_sign(input);
+    attestation_->Sign(request, base::Bind(&ClientLoop::OnSignComplete,
+                                           weak_factory_.GetWeakPtr()));
+  }
+
+  void OnSignComplete(const SignReply& reply) {
+    if (reply.status() == STATUS_SUCCESS &&
+        base::CommandLine::ForCurrentProcess()->HasSwitch("output")) {
+      WriteOutput(reply.signature());
+    }
+    PrintReplyAndQuit<SignReply>(reply);
+  }
+
+  void VerifySignature(const std::string& label,
+                       const std::string& username,
+                       const std::string& input,
+                       const std::string& signature) {
+    GetKeyInfoRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    attestation_->GetKeyInfo(request, base::Bind(&ClientLoop::VerifySignature2,
+                                                 weak_factory_.GetWeakPtr(),
+                                                 input, signature));
+  }
+
+  void VerifySignature2(const std::string& input,
+                        const std::string& signature,
+                        const GetKeyInfoReply& key_info) {
+    CryptoUtilityImpl crypto(nullptr);
+    if (crypto.VerifySignature(key_info.public_key(), input, signature)) {
+      printf("Signature is OK!\n");
+    } else {
+      printf("Signature is BAD!\n");
+    }
+    Quit();
+  }
+
   std::unique_ptr<attestation::AttestationInterface> attestation_;
 
   // Declare this last so weak pointers will be destroyed first.
diff --git a/common/attestation_interface.h b/common/attestation_interface.h
index c5b7111..2ed7213 100644
--- a/common/attestation_interface.h
+++ b/common/attestation_interface.h
@@ -75,6 +75,12 @@
   using DecryptCallback = base::Callback<void(const DecryptReply&)>;
   virtual void Decrypt(const DecryptRequest& request,
                        const DecryptCallback& callback) = 0;
+
+  // Processes a SignRequest and responds with a
+  // SignReply.
+  using SignCallback = base::Callback<void(const SignReply&)>;
+  virtual void Sign(const SignRequest& request,
+                    const SignCallback& callback) = 0;
 };
 
 }  // namespace attestation
diff --git a/common/crypto_utility.h b/common/crypto_utility.h
index 222c005..430c4ad 100644
--- a/common/crypto_utility.h
+++ b/common/crypto_utility.h
@@ -73,6 +73,12 @@
   virtual bool EncryptForUnbind(const std::string& public_key,
                                 const std::string& data,
                                 std::string* encrypted_data) = 0;
+
+  // Verifies a PKCS #1 v1.5 SHA-256 |signature| over |data|. The |public_key|
+  // must be provided in X.509 SubjectPublicKeyInfo format.
+  virtual bool VerifySignature(const std::string& public_key,
+                               const std::string& data,
+                               const std::string& signature) = 0;
 };
 
 }  // namespace attestation
diff --git a/common/crypto_utility_impl.cc b/common/crypto_utility_impl.cc
index dda2731..abf0b4c 100644
--- a/common/crypto_utility_impl.cc
+++ b/common/crypto_utility_impl.cc
@@ -8,9 +8,11 @@
 #include <string>
 
 #include <arpa/inet.h>
+#include <base/sha1.h>
 #include <base/stl_util.h>
 #include <crypto/scoped_openssl_types.h>
 #include <crypto/secure_util.h>
+#include <crypto/sha2.h>
 #include <openssl/bio.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
@@ -220,7 +222,8 @@
   // Construct a TPM_ASYM_CA_CONTENTS structure.
   std::string asym_header(std::begin(kAsymContentHeader),
                           std::end(kAsymContentHeader));
-  std::string asym_content = asym_header + aes_key + Sha1(aik_public_key);
+  std::string asym_content = asym_header + aes_key +
+                             base::SHA1HashString(aik_public_key);
 
   // Encrypt the TPM_ASYM_CA_CONTENTS with the EK public key.
   auto asn1_ptr = reinterpret_cast<const unsigned char*>(
@@ -261,8 +264,7 @@
   std::string bound_data = header + data;
 
   // Encrypt using the TPM_ES_RSAESOAEP_SHA1_MGF1 scheme.
-  const unsigned char* asn1_ptr = reinterpret_cast<const unsigned char*>(
-      public_key.data());
+  auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
   crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr, public_key.size()));
   if (!rsa.get()) {
     LOG(ERROR) << __func__ << ": Failed to decode public key: "
@@ -276,6 +278,24 @@
   return true;
 }
 
+bool CryptoUtilityImpl::VerifySignature(const std::string& public_key,
+                                        const std::string& data,
+                                        const std::string& signature) {
+  auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
+  crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr, public_key.size()));
+  if (!rsa.get()) {
+    LOG(ERROR) << __func__ << ": Failed to decode public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  std::string digest = crypto::SHA256HashString(data);
+  auto digest_buffer = reinterpret_cast<const unsigned char*>(digest.data());
+  std::string mutable_signature(signature);
+  unsigned char* signature_buffer = StringAsOpenSSLBuffer(&mutable_signature);
+  return (RSA_verify(NID_sha256, digest_buffer, digest.size(),
+                     signature_buffer, signature.size(), rsa.get()) == 1);
+}
+
 bool CryptoUtilityImpl::AesEncrypt(const std::string& data,
                                    const std::string& key,
                                    const std::string& iv,
@@ -386,13 +406,6 @@
   return std::string(std::begin(mac), std::end(mac));
 }
 
-std::string CryptoUtilityImpl::Sha1(const std::string& input) {
-  unsigned char digest[SHA_DIGEST_LENGTH];
-  SHA1(reinterpret_cast<const unsigned char*>(input.data()), input.size(),
-       digest);
-  return std::string(reinterpret_cast<const char*>(digest), SHA_DIGEST_LENGTH);
-}
-
 bool CryptoUtilityImpl::TssCompatibleEncrypt(const std::string& input,
                                              const std::string& key,
                                              std::string* output) {
@@ -422,8 +435,7 @@
   padded_input.resize(RSA_size(key));
   auto padded_buffer = reinterpret_cast<unsigned char*>(
       string_as_array(&padded_input));
-  const unsigned char* input_buffer = reinterpret_cast<const unsigned char*>(
-      input.data());
+  auto input_buffer = reinterpret_cast<const unsigned char*>(input.data());
   int result = RSA_padding_add_PKCS1_OAEP(padded_buffer, padded_input.size(),
                                           input_buffer, input.size(),
                                           oaep_param, arraysize(oaep_param));
diff --git a/common/crypto_utility_impl.h b/common/crypto_utility_impl.h
index dbb917b..04521c0 100644
--- a/common/crypto_utility_impl.h
+++ b/common/crypto_utility_impl.h
@@ -47,6 +47,9 @@
   bool EncryptForUnbind(const std::string& public_key,
                         const std::string& data,
                         std::string* encrypted_data) override;
+  bool VerifySignature(const std::string& public_key,
+                       const std::string& data,
+                       const std::string& signature) override;
 
  private:
   // Encrypts |data| using |key| and |iv| for AES in CBC mode with PKCS #5
@@ -66,9 +69,6 @@
   // Computes and returns an HMAC of |data| using |key| and SHA-512.
   std::string HmacSha512(const std::string& data, const std::string& key);
 
-  // Computes and returns the SHA-1 digest of |input|.
-  std::string Sha1(const std::string& input);
-
   // Encrypt like trousers does. This is like AesEncrypt but a random IV is
   // included in the output.
   bool TssCompatibleEncrypt(const std::string& input,
diff --git a/common/crypto_utility_impl_test.cc b/common/crypto_utility_impl_test.cc
index 0892ac9..fdd16b8 100644
--- a/common/crypto_utility_impl_test.cc
+++ b/common/crypto_utility_impl_test.cc
@@ -212,4 +212,18 @@
                                                  &output));
 }
 
+TEST_F(CryptoUtilityImplTest, VerifySignatureBadSignature) {
+  std::string public_key = HexDecode(kValidPublicKeyHex);
+  std::string public_key_info;
+  EXPECT_TRUE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key,
+                                                          &public_key_info));
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->VerifySignature(public_key_info, "input",
+                                                "signature"));
+}
+
+TEST_F(CryptoUtilityImplTest, VerifySignatureBadKey) {
+  EXPECT_FALSE(crypto_utility_->VerifySignature("bad_key", "input", ""));
+}
+
 }  // namespace attestation
diff --git a/common/dbus_interface.h b/common/dbus_interface.h
index 83c3de6..97cde33 100644
--- a/common/dbus_interface.h
+++ b/common/dbus_interface.h
@@ -20,6 +20,7 @@
 constexpr char kActivateAttestationKey[] = "ActivateAttestationKey";
 constexpr char kCreateCertifiableKey[] = "CreateCertifiableKey";
 constexpr char kDecrypt[] = "Decrypt";
+constexpr char kSign[] = "Sign";
 
 }  // namespace attestation
 
diff --git a/common/interface.proto b/common/interface.proto
index 946735c..0caa67b 100644
--- a/common/interface.proto
+++ b/common/interface.proto
@@ -137,3 +137,14 @@
   optional AttestationStatus status = 1;
   optional bytes decrypted_data = 2;
 }
+
+message SignRequest {
+  optional string key_label = 1;
+  optional string username = 2;
+  optional bytes data_to_sign = 3;
+}
+
+message SignReply {
+  optional AttestationStatus status = 1;
+  optional bytes signature = 2;
+}
diff --git a/common/mock_attestation_interface.h b/common/mock_attestation_interface.h
index e9e89b7..d568a43 100644
--- a/common/mock_attestation_interface.h
+++ b/common/mock_attestation_interface.h
@@ -35,6 +35,7 @@
   MOCK_METHOD2(CreateCertifiableKey, void(const CreateCertifiableKeyRequest&,
                                           const CreateCertifiableKeyCallback&));
   MOCK_METHOD2(Decrypt, void(const DecryptRequest&, const DecryptCallback&));
+  MOCK_METHOD2(Sign, void(const SignRequest&, const SignCallback&));
 };
 
 }  // namespace attestation
diff --git a/common/mock_crypto_utility.h b/common/mock_crypto_utility.h
index 0b68885..4aaa1db 100644
--- a/common/mock_crypto_utility.h
+++ b/common/mock_crypto_utility.h
@@ -45,6 +45,9 @@
   MOCK_METHOD3(EncryptForUnbind, bool(const std::string&,
                                       const std::string&,
                                       std::string*));
+  MOCK_METHOD3(VerifySignature, bool(const std::string&,
+                                     const std::string&,
+                                     const std::string&));
 };
 
 }  // namespace attestation
diff --git a/common/mock_tpm_utility.cc b/common/mock_tpm_utility.cc
index 2b38909..055bccb 100644
--- a/common/mock_tpm_utility.cc
+++ b/common/mock_tpm_utility.cc
@@ -11,10 +11,34 @@
 
 namespace {
 
-bool CopyString(const std::string& in, std::string* out) {
-  *out = in;
-  return true;
-}
+class TransformString {
+ public:
+  explicit TransformString(std::string method) : method_(method) {}
+  bool operator()(const std::string& in, std::string* out) {
+    *out = attestation::MockTpmUtility::Transform(method_, in);
+    return true;
+  }
+
+ private:
+  std::string method_;
+};
+
+class UntransformString {
+ public:
+  explicit UntransformString(std::string method) : method_(method) {}
+  bool operator()(const std::string& in, std::string* out) {
+    std::string suffix = "_fake_transform_" + method_;
+    auto position = in.find(suffix);
+    if (position == std::string::npos) {
+      return false;
+    }
+    *out = in.substr(0, position);
+    return true;
+  }
+
+ private:
+  std::string method_;
+};
 
 }  // namespace
 
@@ -27,13 +51,21 @@
   ON_CALL(*this, CreateCertifiedKey(_, _, _, _, _, _, _, _, _))
       .WillByDefault(Return(true));
   ON_CALL(*this, SealToPCR0(_, _))
-      .WillByDefault(Invoke(CopyString));
+      .WillByDefault(Invoke(TransformString("SealToPCR0")));
   ON_CALL(*this, Unseal(_, _))
-      .WillByDefault(Invoke(CopyString));
+      .WillByDefault(Invoke(UntransformString("SealToPCR0")));
   ON_CALL(*this, Unbind(_, _, _))
-      .WillByDefault(WithArgs<1, 2>(Invoke(CopyString)));
+      .WillByDefault(WithArgs<1, 2>(Invoke(TransformString("Unbind"))));
+  ON_CALL(*this, Sign(_, _, _))
+      .WillByDefault(WithArgs<1, 2>(Invoke(TransformString("Sign"))));
 }
 
 MockTpmUtility::~MockTpmUtility() {}
 
+// static
+std::string MockTpmUtility::Transform(const std::string& method,
+                                      const std::string& input) {
+  return input + "_fake_transform_" + method;
+}
+
 }  // namespace attestation
diff --git a/common/mock_tpm_utility.h b/common/mock_tpm_utility.h
index deb9746..5ebf93f 100644
--- a/common/mock_tpm_utility.h
+++ b/common/mock_tpm_utility.h
@@ -17,6 +17,12 @@
  public:
   MockTpmUtility();
   ~MockTpmUtility() override;
+  // By default this class will fake seal/unbind/sign operations by passing the
+  // input through Transform(<method>). E.g. The expected output of a fake Sign
+  // operation on "foo" can be computed by calling
+  // MockTpmUtility::Transform("Sign", "foo").
+  static std::string Transform(const std::string& method,
+                               const std::string& input);
 
   MOCK_METHOD0(IsTpmReady, bool());
   MOCK_METHOD6(ActivateIdentity, bool(const std::string&,
@@ -39,6 +45,8 @@
   MOCK_METHOD1(GetEndorsementPublicKey, bool(std::string*));
   MOCK_METHOD3(Unbind, bool(const std::string&, const std::string&,
                             std::string*));
+  MOCK_METHOD3(Sign, bool(const std::string&, const std::string&,
+                          std::string*));
 };
 
 }  // namespace attestation
diff --git a/common/tpm_utility.h b/common/tpm_utility.h
index 98591c3..e9cc1e3 100644
--- a/common/tpm_utility.h
+++ b/common/tpm_utility.h
@@ -71,6 +71,13 @@
   virtual bool Unbind(const std::string& key_blob,
                       const std::string& bound_data,
                       std::string* data) = 0;
+
+  // Signs |data_to_sign| with the key loaded from |key_blob| using the
+  // TPM_SS_RSASSAPKCS1v15_DER scheme with SHA-256. On success returns true and
+  // provides the |signature|.
+  virtual bool Sign(const std::string& key_blob,
+                    const std::string& data_to_sign,
+                    std::string* signature) = 0;
 };
 
 }  // namespace attestation
diff --git a/common/tpm_utility_v1.cc b/common/tpm_utility_v1.cc
index b6749ae..6e918f0 100644
--- a/common/tpm_utility_v1.cc
+++ b/common/tpm_utility_v1.cc
@@ -10,7 +10,9 @@
 #include <base/memory/scoped_ptr.h>
 #include <base/stl_util.h>
 #include <crypto/scoped_openssl_types.h>
+#include <crypto/sha2.h>
 #include <openssl/rsa.h>
+#include <openssl/sha.h>
 #include <trousers/scoped_tss_type.h>
 #include <trousers/trousers.h>
 #include <trousers/tss.h>
@@ -28,10 +30,15 @@
 
 using ScopedByteArray = scoped_ptr<BYTE, base::FreeDeleter>;
 using ScopedTssEncryptedData = trousers::ScopedTssObject<TSS_HENCDATA>;
+using ScopedTssHash = trousers::ScopedTssObject<TSS_HHASH>;
 
 const char* kTpmEnabledFile = "/sys/class/misc/tpm0/device/enabled";
 const char* kTpmOwnedFile = "/sys/class/misc/tpm0/device/owned";
 const unsigned int kWellKnownExponent = 65537;
+const unsigned char kSha256DigestInfo[] = {
+  0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
+  0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+};
 
 std::string GetFirstByte(const char* file_name) {
   std::string content;
@@ -437,6 +444,50 @@
   return true;
 }
 
+bool TpmUtilityV1::Sign(const std::string& key_blob,
+                        const std::string& data_to_sign,
+                        std::string* signature) {
+  CHECK(signature);
+  if (!SetupSrk()) {
+    LOG(ERROR) << "SRK is not ready.";
+    return false;
+  }
+  ScopedTssKey key_handle(context_handle_);
+  if (!LoadKeyFromBlob(key_blob, context_handle_, srk_handle_, &key_handle)) {
+    return false;
+  }
+  // Construct an ASN.1 DER DigestInfo.
+  std::string digest_to_sign(std::begin(kSha256DigestInfo),
+                             std::end(kSha256DigestInfo));
+  digest_to_sign += crypto::SHA256HashString(data_to_sign);
+  // Create a hash object to hold the digest.
+  ScopedTssHash hash_handle(context_handle_);
+  TSS_RESULT result = Tspi_Context_CreateObject(context_handle_,
+                                                TSS_OBJECT_TYPE_HASH,
+                                                TSS_HASH_OTHER,
+                                                hash_handle.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to create hash object.";
+    return false;
+  }
+  result = Tspi_Hash_SetHashValue(hash_handle,
+                                  digest_to_sign.size(),
+                                  StringAsTSSBuffer(&digest_to_sign));
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to set hash data.";
+    return false;
+  }
+  UINT32 length = 0;
+  ScopedTssMemory buffer(context_handle_);
+  result = Tspi_Hash_Sign(hash_handle, key_handle, &length, buffer.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to generate signature.";
+    return false;
+  }
+  signature->assign(TSSBufferAsString(buffer.value(), length));
+  return true;
+}
+
 bool TpmUtilityV1::ConnectContext(ScopedTssContext* context, TSS_HTPM* tpm) {
   *tpm = 0;
   TSS_RESULT result;
@@ -654,5 +705,4 @@
   return true;
 }
 
-
 }  // namespace attestation
diff --git a/common/tpm_utility_v1.h b/common/tpm_utility_v1.h
index 29de576..79b9073 100644
--- a/common/tpm_utility_v1.h
+++ b/common/tpm_utility_v1.h
@@ -48,6 +48,9 @@
   bool Unbind(const std::string& key_blob,
               const std::string& bound_data,
               std::string* data) override;
+  bool Sign(const std::string& key_blob,
+            const std::string& data_to_sign,
+            std::string* signature) override;
 
  private:
   // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
diff --git a/server/attestation_service.cc b/server/attestation_service.cc
index c0cf126..2d50ecf 100644
--- a/server/attestation_service.cc
+++ b/server/attestation_service.cc
@@ -429,6 +429,37 @@
   result->set_decrypted_data(data);
 }
 
+void AttestationService::Sign(const SignRequest& request,
+                              const SignCallback& callback) {
+  auto result = std::make_shared<SignReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::SignTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<SignReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::SignTask(const SignRequest& request,
+                                  const std::shared_ptr<SignReply>& result) {
+  CertifiedKey key;
+  if (!FindKeyByLabel(request.username(), request.key_label(), &key)) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  std::string signature;
+  if (!tpm_utility_->Sign(key.key_blob(), request.data_to_sign(), &signature)) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  result->set_signature(signature);
+}
+
 bool AttestationService::IsPreparedForEnrollment() {
   if (!tpm_utility_->IsTpmReady()) {
     return false;
diff --git a/server/attestation_service.h b/server/attestation_service.h
index ae6dead..1876c2a 100644
--- a/server/attestation_service.h
+++ b/server/attestation_service.h
@@ -74,6 +74,7 @@
       const CreateCertifiableKeyCallback& callback) override;
   void Decrypt(const DecryptRequest& request,
                const DecryptCallback& callback) override;
+  void Sign(const SignRequest& request, const SignCallback& callback) override;
 
   // Mutators useful for testing.
   void set_crypto_utility(CryptoUtility* crypto_utility) {
@@ -117,41 +118,45 @@
     callback.Run(*reply);
   }
 
-  // A synchronous implementation of CreateGoogleAttestedKey appropriate to run
-  // on the worker thread.
+  // A blocking implementation of CreateGoogleAttestedKey appropriate to run on
+  // the worker thread.
   void CreateGoogleAttestedKeyTask(
       const CreateGoogleAttestedKeyRequest& request,
       const std::shared_ptr<CreateGoogleAttestedKeyReply>& result);
 
-  // A synchronous implementation of GetKeyInfo.
+  // A blocking implementation of GetKeyInfo.
   void GetKeyInfoTask(
       const GetKeyInfoRequest& request,
       const std::shared_ptr<GetKeyInfoReply>& result);
 
-  // A synchronous implementation of GetEndorsementInfo.
+  // A blocking implementation of GetEndorsementInfo.
   void GetEndorsementInfoTask(
       const GetEndorsementInfoRequest& request,
       const std::shared_ptr<GetEndorsementInfoReply>& result);
 
-  // A synchronous implementation of GetAttestationKeyInfo.
+  // A blocking implementation of GetAttestationKeyInfo.
   void GetAttestationKeyInfoTask(
       const GetAttestationKeyInfoRequest& request,
       const std::shared_ptr<GetAttestationKeyInfoReply>& result);
 
-  // A synchronous implementation of ActivateAttestationKey.
+  // A blocking implementation of ActivateAttestationKey.
   void ActivateAttestationKeyTask(
       const ActivateAttestationKeyRequest& request,
       const std::shared_ptr<ActivateAttestationKeyReply>& result);
 
-  // A synchronous implementation of CreateCertifiableKey.
+  // A blocking implementation of CreateCertifiableKey.
   void CreateCertifiableKeyTask(
       const CreateCertifiableKeyRequest& request,
       const std::shared_ptr<CreateCertifiableKeyReply>& result);
 
-  // A synchronous implementation of Decrypt.
+  // A blocking implementation of Decrypt.
   void DecryptTask(const DecryptRequest& request,
                    const std::shared_ptr<DecryptReply>& result);
 
+  // A blocking implementation of Sign.
+  void SignTask(const SignRequest& request,
+                const std::shared_ptr<SignReply>& result);
+
   // Returns true iff all information required for enrollment with the Google
   // Attestation CA is available.
   bool IsPreparedForEnrollment();
diff --git a/server/attestation_service_test.cc b/server/attestation_service_test.cc
index ecc2eec..ab2e2f6 100644
--- a/server/attestation_service_test.cc
+++ b/server/attestation_service_test.cc
@@ -851,7 +851,8 @@
   // Set expectations on the outputs.
   auto callback = [this](const DecryptReply& reply) {
     EXPECT_EQ(STATUS_SUCCESS, reply.status());
-    EXPECT_EQ("data", reply.decrypted_data());
+    EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"),
+              reply.decrypted_data());
     Quit();
   };
   DecryptRequest request;
@@ -867,7 +868,8 @@
   // Set expectations on the outputs.
   auto callback = [this](const DecryptReply& reply) {
     EXPECT_EQ(STATUS_SUCCESS, reply.status());
-    EXPECT_EQ("data", reply.decrypted_data());
+    EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"),
+              reply.decrypted_data());
     Quit();
   };
   DecryptRequest request;
@@ -924,4 +926,81 @@
   Run();
 }
 
+TEST_F(AttestationServiceTest, SignSuccess) {
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignSuccessNoUser) {
+  mock_database_.GetMutableProtobuf()->add_device_keys()->set_key_name("label");
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignKeyNotFound) {
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignKeyNotFoundNoUser) {
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignUnbindFailure) {
+  EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
 }  // namespace attestation
diff --git a/server/dbus_service.cc b/server/dbus_service.cc
index 815d0f5..d8bc29a 100644
--- a/server/dbus_service.cc
+++ b/server/dbus_service.cc
@@ -48,6 +48,9 @@
   dbus_interface->AddMethodHandler(kDecrypt,
                                    base::Unretained(this),
                                    &DBusService::HandleDecrypt);
+  dbus_interface->AddMethodHandler(kSign,
+                                   base::Unretained(this),
+                                   &DBusService::HandleSign);
 
   dbus_object_.RegisterAsync(callback);
 }
@@ -183,4 +186,22 @@
       base::Bind(callback, SharedResponsePointer(std::move(response))));
 }
 
+void DBusService::HandleSign(
+    std::unique_ptr<DBusMethodResponse<const SignReply&>> response,
+    const SignRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const SignReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const SignReply& reply) {
+    response->Return(reply);
+  };
+  service_->Sign(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
 }  // namespace attestation
diff --git a/server/dbus_service.h b/server/dbus_service.h
index 35fe7be..01e18f7 100644
--- a/server/dbus_service.h
+++ b/server/dbus_service.h
@@ -80,6 +80,12 @@
           const DecryptReply&>> response,
       const DecryptRequest& request);
 
+  // Handles a Sign D-Bus call.
+  void HandleSign(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const SignReply&>> response,
+      const SignRequest& request);
+
   chromeos::dbus_utils::DBusObject dbus_object_;
   AttestationInterface* service_;
 
diff --git a/server/dbus_service_test.cc b/server/dbus_service_test.cc
index 11f1987..8894e3b 100644
--- a/server/dbus_service_test.cc
+++ b/server/dbus_service_test.cc
@@ -301,8 +301,7 @@
         reply.set_decrypted_data("data");
         callback.Run(reply);
       }));
-  std::unique_ptr<dbus::MethodCall> call =
-      CreateMethodCall(kDecrypt);
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kDecrypt);
   dbus::MessageWriter writer(call.get());
   writer.AppendProtoAsArrayOfBytes(request);
   auto response = CallMethod(call.get());
@@ -313,4 +312,32 @@
   EXPECT_EQ("data", reply.decrypted_data());
 }
 
+TEST_F(DBusServiceTest, Sign) {
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  EXPECT_CALL(mock_service_, Sign(_, _))
+      .WillOnce(Invoke([](
+          const SignRequest& request,
+          const AttestationInterface::SignCallback& callback) {
+        EXPECT_EQ("label", request.key_label());
+        EXPECT_EQ("user", request.username());
+        EXPECT_EQ("data", request.data_to_sign());
+        SignReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_signature("signature");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kSign);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  SignReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("signature", reply.signature());
+}
+
 }  // namespace attestation