main.cc revision bc0c74963418442991072b2c87baec839eec9c20
16bead48129845a2bc0d6ff347f3d7e232004d59Nam T. Nguyen// Copyright 2014 The Chromium OS Authors. All rights reserved.
26bead48129845a2bc0d6ff347f3d7e232004d59Nam T. Nguyen// Use of this source code is governed by a BSD-style license that can be
36bead48129845a2bc0d6ff347f3d7e232004d59Nam T. Nguyen// found in the LICENSE file.
46bead48129845a2bc0d6ff347f3d7e232004d59Nam T. Nguyen
50752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn#include <stdio.h>
60752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn#include <sysexits.h>
70752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
845fc1234b4f1a1c1cfdd44774350a70b26b9b630Alex Vakulenko#include <memory>
9b91fd4923f411705be97fbc5c0ada37481c0cd8dDarren Krahn#include <string>
1045fc1234b4f1a1c1cfdd44774350a70b26b9b630Alex Vakulenko
110752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn#include <base/command_line.h>
122e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn#include <base/files/file_util.h>
130752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn#include <base/message_loop/message_loop.h>
140752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn#include <chromeos/bind_lambda.h>
150752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn#include <chromeos/daemons/daemon.h>
160752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn#include <chromeos/syslog_logging.h>
170752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
18b91fd4923f411705be97fbc5c0ada37481c0cd8dDarren Krahn#include "attestation/client/dbus_proxy.h"
19b91fd4923f411705be97fbc5c0ada37481c0cd8dDarren Krahn#include "attestation/common/attestation_ca.pb.h"
202e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn#include "attestation/common/crypto_utility_impl.h"
21b91fd4923f411705be97fbc5c0ada37481c0cd8dDarren Krahn#include "attestation/common/interface.pb.h"
226bead48129845a2bc0d6ff347f3d7e232004d59Nam T. Nguyen
230752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahnnamespace attestation {
240752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
2562c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahnconst char kCreateAndCertifyCommand[] = "create_and_certify";
260752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahnconst char kCreateCommand[] = "create";
276222defa52eb13c0d90673f642f2647f7753478bDarren Krahnconst char kInfoCommand[] = "info";
28cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahnconst char kEndorsementCommand[] = "endorsement";
29566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahnconst char kAttestationKeyCommand[] = "attestation_key";
302e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahnconst char kActivateCommand[] = "activate";
312e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahnconst char kEncryptForActivateCommand[] = "encrypt_for_activate";
32bc0c74963418442991072b2c87baec839eec9c20Darren Krahnconst char kEncryptCommand[] = "encrypt";
33bc0c74963418442991072b2c87baec839eec9c20Darren Krahnconst char kDecryptCommand[] = "decrypt";
340752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahnconst char kUsage[] = R"(
350752bd25ba9f45c07bc989d42bf5272133a85afaDarren KrahnUsage: attestation_client <command> [<args>]
360752bd25ba9f45c07bc989d42bf5272133a85afaDarren KrahnCommands:
3762c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  create_and_certify [--user=<email>] [--label=<keylabel>]
3862c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      Creates a key and requests certification by the Google Attestation CA.
3962c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      This is the default command.
40bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  create [--user=<email>] [--label=<keylabel] [--usage=sign|decrypt]
4162c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      Creates a certifiable key.
422e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn
4362c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  info [--user=<email>] [--label=<keylabel>]
4462c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      Prints info about a key.
4562c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  endorsement
4662c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      Prints info about the TPM endorsement.
4762c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  attestation_key
4862c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      Prints info about the TPM attestation key.
492e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn
5062c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  activate --input=<input_file>
5162c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      Activates an attestation key using the encrypted credential in
5262c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      |input_file|.
5362c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  encrypt_for_activate --input=<input_file> --output=<output_file>
5462c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      Encrypts the content of |input_file| as required by the TPM for activating
5562c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      an attestation key. The result is written to |output_file|.
56bc0c74963418442991072b2c87baec839eec9c20Darren Krahn
57bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  encrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
58bc0c74963418442991072b2c87baec839eec9c20Darren Krahn          --output=<output_file>
59bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      Encrypts the content of |input_file| as required by the TPM for a decrypt
60bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      operation. The result is written to |output_file|.
61bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  decrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
62bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      Decrypts the content of |input_file|.
630752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn)";
640752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
650752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn// The Daemon class works well as a client loop as well.
660752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahnusing ClientLoopBase = chromeos::Daemon;
670752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
680752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahnclass ClientLoop : public ClientLoopBase {
690752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn public:
700752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  ClientLoop() = default;
710752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  ~ClientLoop() override = default;
720752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
730752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn protected:
740752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  int OnInit() override {
750752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    int exit_code = ClientLoopBase::OnInit();
760752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    if (exit_code != EX_OK) {
770752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn      return exit_code;
780752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    }
790752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    attestation_.reset(new attestation::DBusProxy());
800752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    if (!attestation_->Initialize()) {
810752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn      return EX_UNAVAILABLE;
820752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    }
830752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    exit_code = ScheduleCommand();
840752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    if (exit_code == EX_USAGE) {
850752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn      printf("%s", kUsage);
860752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    }
870752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    return exit_code;
880752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  }
890752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
900752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  void OnShutdown(int* exit_code) override {
910752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    attestation_.reset();
920752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    ClientLoopBase::OnShutdown(exit_code);
93b91fd4923f411705be97fbc5c0ada37481c0cd8dDarren Krahn  }
940752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
950752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn private:
960752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  // Posts tasks according to the command line options.
970752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  int ScheduleCommand() {
980752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    base::Closure task;
9959d7aa26782d3c6efd707e3b936d56c893a2555aDarren Krahn    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
10059d7aa26782d3c6efd707e3b936d56c893a2555aDarren Krahn    const auto& args = command_line->GetArgs();
101566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn    if (command_line->HasSwitch("help") || command_line->HasSwitch("h") ||
102bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        (!args.empty() && args.front() == "help")) {
103566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn      return EX_USAGE;
104566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn    }
10562c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn    if (args.empty() || args.front() == kCreateAndCertifyCommand) {
1060752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn      task = base::Bind(&ClientLoop::CallCreateGoogleAttestedKey,
10759d7aa26782d3c6efd707e3b936d56c893a2555aDarren Krahn                        weak_factory_.GetWeakPtr(),
10859d7aa26782d3c6efd707e3b936d56c893a2555aDarren Krahn                        command_line->GetSwitchValueASCII("label"),
10959d7aa26782d3c6efd707e3b936d56c893a2555aDarren Krahn                        command_line->GetSwitchValueASCII("user"));
11062c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn    } else if (args.front() == kCreateCommand) {
111bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      std::string usage_str = command_line->GetSwitchValueASCII("usage");
112bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      KeyUsage usage;
113bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      if (usage_str.empty() || usage_str == "sign") {
114bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        usage = KEY_USAGE_SIGN;
115bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      } else if (usage_str == "decrypt") {
116bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        usage = KEY_USAGE_DECRYPT;
117bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      } else {
118bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        return EX_USAGE;
119bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      }
12062c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn      task = base::Bind(&ClientLoop::CallCreateCertifiableKey,
12162c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn                        weak_factory_.GetWeakPtr(),
12262c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn                        command_line->GetSwitchValueASCII("label"),
123bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        command_line->GetSwitchValueASCII("user"),
124bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        usage);
1256222defa52eb13c0d90673f642f2647f7753478bDarren Krahn    } else if (args.front() == kInfoCommand) {
1266222defa52eb13c0d90673f642f2647f7753478bDarren Krahn      task = base::Bind(&ClientLoop::CallGetKeyInfo,
1276222defa52eb13c0d90673f642f2647f7753478bDarren Krahn                        weak_factory_.GetWeakPtr(),
1286222defa52eb13c0d90673f642f2647f7753478bDarren Krahn                        command_line->GetSwitchValueASCII("label"),
1296222defa52eb13c0d90673f642f2647f7753478bDarren Krahn                        command_line->GetSwitchValueASCII("user"));
130cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn    } else if (args.front() == kEndorsementCommand) {
131cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn      task = base::Bind(&ClientLoop::CallGetEndorsementInfo,
132cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn                        weak_factory_.GetWeakPtr());
133566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn    } else if (args.front() == kAttestationKeyCommand) {
134566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn      task = base::Bind(&ClientLoop::CallGetAttestationKeyInfo,
135566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn                        weak_factory_.GetWeakPtr());
1362e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    } else if (args.front() == kActivateCommand) {
1372e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      if (!command_line->HasSwitch("input")) {
1382e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        return EX_USAGE;
1392e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      }
1402e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      std::string input;
1412e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
1422e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      if (!base::ReadFileToString(filename, &input)) {
1432e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        LOG(ERROR) << "Failed to read file: " << filename.value();
1442e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        return EX_NOINPUT;
1452e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      }
1462e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      task = base::Bind(&ClientLoop::CallActivateAttestationKey,
1472e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                        weak_factory_.GetWeakPtr(),
1482e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                        input);
1492e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    } else if (args.front() == kEncryptForActivateCommand) {
1502e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      if (!command_line->HasSwitch("input") ||
1512e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn          !command_line->HasSwitch("output")) {
1522e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        return EX_USAGE;
1532e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      }
1542e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      std::string input;
1552e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
1562e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      if (!base::ReadFileToString(filename, &input)) {
1572e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        LOG(ERROR) << "Failed to read file: " << filename.value();
1582e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        return EX_NOINPUT;
1592e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      }
1602e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      task = base::Bind(&ClientLoop::EncryptForActivate,
1612e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                        weak_factory_.GetWeakPtr(),
1622e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                        input);
163bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    } else if (args.front() == kEncryptCommand) {
164bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      if (!command_line->HasSwitch("input") ||
165bc0c74963418442991072b2c87baec839eec9c20Darren Krahn          !command_line->HasSwitch("output")) {
166bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        return EX_USAGE;
167bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      }
168bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      std::string input;
169bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
170bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      if (!base::ReadFileToString(filename, &input)) {
171bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        LOG(ERROR) << "Failed to read file: " << filename.value();
172bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        return EX_NOINPUT;
173bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      }
174bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      task = base::Bind(&ClientLoop::Encrypt,
175bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        weak_factory_.GetWeakPtr(),
176bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        command_line->GetSwitchValueASCII("label"),
177bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        command_line->GetSwitchValueASCII("user"),
178bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        input);
179bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    } else if (args.front() == kDecryptCommand) {
180bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      if (!command_line->HasSwitch("input")) {
181bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        return EX_USAGE;
182bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      }
183bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      std::string input;
184bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
185bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      if (!base::ReadFileToString(filename, &input)) {
186bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        LOG(ERROR) << "Failed to read file: " << filename.value();
187bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        return EX_NOINPUT;
188bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      }
189bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      task = base::Bind(&ClientLoop::CallDecrypt,
190bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        weak_factory_.GetWeakPtr(),
191bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        command_line->GetSwitchValueASCII("label"),
192bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        command_line->GetSwitchValueASCII("user"),
193bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                        input);
1940752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    } else {
1950752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn      return EX_USAGE;
1960752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    }
1970752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    base::MessageLoop::current()->PostTask(FROM_HERE, task);
1980752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    return EX_OK;
1990752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  }
2000752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
2016222defa52eb13c0d90673f642f2647f7753478bDarren Krahn  template <typename ProtobufType>
2026222defa52eb13c0d90673f642f2647f7753478bDarren Krahn  void PrintReplyAndQuit(const ProtobufType& reply) {
203b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn    reply.PrintDebugString();
2040752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    Quit();
2050752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  }
2060752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
2072e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  void WriteOutput(const std::string& output) {
2082e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    base::FilePath filename(base::CommandLine::ForCurrentProcess()->
2092e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        GetSwitchValueASCII("output"));
2102e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    if (base::WriteFile(filename, output.data(), output.size()) !=
2112e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        static_cast<int>(output.size())) {
2122e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      LOG(ERROR) << "Failed to write file: " << filename.value();
2132e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      QuitWithExitCode(EX_IOERR);
2142e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    }
2152e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  }
2162e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn
21759d7aa26782d3c6efd707e3b936d56c893a2555aDarren Krahn  void CallCreateGoogleAttestedKey(const std::string& label,
21859d7aa26782d3c6efd707e3b936d56c893a2555aDarren Krahn                                   const std::string& username) {
219b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn    CreateGoogleAttestedKeyRequest request;
220b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn    request.set_key_label(label);
221b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn    request.set_key_type(KEY_TYPE_RSA);
222b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn    request.set_key_usage(KEY_USAGE_SIGN);
223b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn    request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
224b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn    request.set_username(username);
2250752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn    attestation_->CreateGoogleAttestedKey(
226b48a50fc394b9c8a1059463c9eaba4c8d1985b9bDarren Krahn        request,
2276222defa52eb13c0d90673f642f2647f7753478bDarren Krahn        base::Bind(&ClientLoop::PrintReplyAndQuit<CreateGoogleAttestedKeyReply>,
2286222defa52eb13c0d90673f642f2647f7753478bDarren Krahn                   weak_factory_.GetWeakPtr()));
2296222defa52eb13c0d90673f642f2647f7753478bDarren Krahn  }
2306222defa52eb13c0d90673f642f2647f7753478bDarren Krahn
2316222defa52eb13c0d90673f642f2647f7753478bDarren Krahn  void CallGetKeyInfo(const std::string& label, const std::string& username) {
2326222defa52eb13c0d90673f642f2647f7753478bDarren Krahn    GetKeyInfoRequest request;
2336222defa52eb13c0d90673f642f2647f7753478bDarren Krahn    request.set_key_label(label);
2346222defa52eb13c0d90673f642f2647f7753478bDarren Krahn    request.set_username(username);
2356222defa52eb13c0d90673f642f2647f7753478bDarren Krahn    attestation_->GetKeyInfo(
2366222defa52eb13c0d90673f642f2647f7753478bDarren Krahn        request,
2376222defa52eb13c0d90673f642f2647f7753478bDarren Krahn        base::Bind(&ClientLoop::PrintReplyAndQuit<GetKeyInfoReply>,
2380752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn                   weak_factory_.GetWeakPtr()));
23945fc1234b4f1a1c1cfdd44774350a70b26b9b630Alex Vakulenko  }
2400752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
241cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn  void CallGetEndorsementInfo() {
242cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn    GetEndorsementInfoRequest request;
243cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn    request.set_key_type(KEY_TYPE_RSA);
244cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn    attestation_->GetEndorsementInfo(
245cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn        request,
246cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn        base::Bind(&ClientLoop::PrintReplyAndQuit<GetEndorsementInfoReply>,
247cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn                   weak_factory_.GetWeakPtr()));
248cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn  }
249cd5486df897619718b68223ebefc1322a1f5ab29Darren Krahn
250566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn  void CallGetAttestationKeyInfo() {
251566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn    GetAttestationKeyInfoRequest request;
252566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn    request.set_key_type(KEY_TYPE_RSA);
253566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn    attestation_->GetAttestationKeyInfo(
254566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn        request,
255566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn        base::Bind(&ClientLoop::PrintReplyAndQuit<GetAttestationKeyInfoReply>,
256566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn                   weak_factory_.GetWeakPtr()));
257566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn  }
258566c836c403212d5c13428b02ed65e5ff6e49a6bDarren Krahn
2592e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  void CallActivateAttestationKey(const std::string& input) {
2602e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    ActivateAttestationKeyRequest request;
2612e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    request.set_key_type(KEY_TYPE_RSA);
2622e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    request.mutable_encrypted_certificate()->ParseFromString(input);
2632e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    request.set_save_certificate(true);
2642e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    attestation_->ActivateAttestationKey(
2652e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        request,
2662e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        base::Bind(&ClientLoop::PrintReplyAndQuit<ActivateAttestationKeyReply>,
2672e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                   weak_factory_.GetWeakPtr()));
2682e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  }
2692e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn
2702e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  void EncryptForActivate(const std::string& input) {
2712e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    GetEndorsementInfoRequest request;
2722e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    request.set_key_type(KEY_TYPE_RSA);
2732e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    attestation_->GetEndorsementInfo(
2742e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        request,
2752e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        base::Bind(&ClientLoop::EncryptForActivate2,
2762e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                   weak_factory_.GetWeakPtr(),
2772e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                   input));
2782e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  }
2792e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn
2802e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  void EncryptForActivate2(const std::string& input,
2812e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                           const GetEndorsementInfoReply& endorsement_info) {
2822e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    if (endorsement_info.status() != STATUS_SUCCESS) {
2832e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      PrintReplyAndQuit(endorsement_info);
2842e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    }
2852e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    GetAttestationKeyInfoRequest request;
2862e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    request.set_key_type(KEY_TYPE_RSA);
2872e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    attestation_->GetAttestationKeyInfo(
2882e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        request,
2892e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        base::Bind(&ClientLoop::EncryptForActivate3,
2902e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                   weak_factory_.GetWeakPtr(),
2912e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                   input,
2922e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn                   endorsement_info));
2932e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  }
2942e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn
2952e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  void EncryptForActivate3(
2962e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      const std::string& input,
2972e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      const GetEndorsementInfoReply& endorsement_info,
2982e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      const GetAttestationKeyInfoReply& attestation_key_info) {
2992e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    if (attestation_key_info.status() != STATUS_SUCCESS) {
3002e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      PrintReplyAndQuit(attestation_key_info);
3012e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    }
3022e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    CryptoUtilityImpl crypto(nullptr);
3032e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    EncryptedIdentityCredential encrypted;
3042e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    if (!crypto.EncryptIdentityCredential(
3052e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        input,
3062e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        endorsement_info.ek_public_key(),
3072e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        attestation_key_info.public_key_tpm_format(),
3082e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn        &encrypted)) {
3092e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn      QuitWithExitCode(EX_SOFTWARE);
3102e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    }
3112e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    std::string output;
3122e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    encrypted.SerializeToString(&output);
3132e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    WriteOutput(output);
3142e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn    Quit();
3152e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn  }
3162e89ba764046e015ae90a1668f7cb3eb29cf509dDarren Krahn
31762c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  void CallCreateCertifiableKey(const std::string& label,
318bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                                const std::string& username,
319bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                                KeyUsage usage) {
32062c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn    CreateCertifiableKeyRequest request;
32162c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn    request.set_key_label(label);
32262c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn    request.set_username(username);
323bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    request.set_key_type(KEY_TYPE_RSA);
324bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    request.set_key_usage(usage);
32562c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn    attestation_->CreateCertifiableKey(
32662c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn        request,
32762c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn        base::Bind(&ClientLoop::PrintReplyAndQuit<CreateCertifiableKeyReply>,
32862c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn                   weak_factory_.GetWeakPtr()));
32962c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn  }
33062c73fa5a343fbbf6a0b0176dd789352b85c44e5Darren Krahn
331bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  void Encrypt(const std::string& label,
332bc0c74963418442991072b2c87baec839eec9c20Darren Krahn               const std::string& username,
333bc0c74963418442991072b2c87baec839eec9c20Darren Krahn               const std::string& input) {
334bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    GetKeyInfoRequest request;
335bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    request.set_key_label(label);
336bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    request.set_username(username);
337bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    attestation_->GetKeyInfo(request, base::Bind(&ClientLoop::Encrypt2,
338bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                                                 weak_factory_.GetWeakPtr(),
339bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                                                 input));
340bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  }
341bc0c74963418442991072b2c87baec839eec9c20Darren Krahn
342bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  void Encrypt2(const std::string& input,
343bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                const GetKeyInfoReply& key_info) {
344bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    CryptoUtilityImpl crypto(nullptr);
345bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    std::string output;
346bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    if (!crypto.EncryptForUnbind(key_info.public_key(), input, &output)) {
347bc0c74963418442991072b2c87baec839eec9c20Darren Krahn      QuitWithExitCode(EX_SOFTWARE);
348bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    }
349bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    WriteOutput(output);
350bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    Quit();
351bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  }
352bc0c74963418442991072b2c87baec839eec9c20Darren Krahn
353bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  void CallDecrypt(const std::string& label,
354bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                   const std::string& username,
355bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                   const std::string& input) {
356bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    DecryptRequest request;
357bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    request.set_key_label(label);
358bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    request.set_username(username);
359bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    request.set_encrypted_data(input);
360bc0c74963418442991072b2c87baec839eec9c20Darren Krahn    attestation_->Decrypt(
361bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        request,
362bc0c74963418442991072b2c87baec839eec9c20Darren Krahn        base::Bind(&ClientLoop::PrintReplyAndQuit<DecryptReply>,
363bc0c74963418442991072b2c87baec839eec9c20Darren Krahn                   weak_factory_.GetWeakPtr()));
364bc0c74963418442991072b2c87baec839eec9c20Darren Krahn  }
365bc0c74963418442991072b2c87baec839eec9c20Darren Krahn
3660752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  std::unique_ptr<attestation::AttestationInterface> attestation_;
3670752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
3680752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  // Declare this last so weak pointers will be destroyed first.
3690752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  base::WeakPtrFactory<ClientLoop> weak_factory_{this};
3700752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
3710752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  DISALLOW_COPY_AND_ASSIGN(ClientLoop);
3720752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn};
3730752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
3740752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn}  // namespace attestation
3750752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn
3760752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahnint main(int argc, char* argv[]) {
3770752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  base::CommandLine::Init(argc, argv);
3780752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
3790752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  attestation::ClientLoop loop;
3800752bd25ba9f45c07bc989d42bf5272133a85afaDarren Krahn  return loop.Run();
3816bead48129845a2bc0d6ff347f3d7e232004d59Nam T. Nguyen}
382