1//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include <stdio.h>
18#include <sysexits.h>
19
20#include <memory>
21#include <string>
22
23#include <base/command_line.h>
24#include <base/files/file_util.h>
25#include <base/message_loop/message_loop.h>
26#include <brillo/bind_lambda.h>
27#include <brillo/daemons/daemon.h>
28#include <brillo/syslog_logging.h>
29
30#include "attestation/client/dbus_proxy.h"
31#include "attestation/common/attestation_ca.pb.h"
32#include "attestation/common/crypto_utility_impl.h"
33#include "attestation/common/interface.pb.h"
34#include "attestation/common/print_interface_proto.h"
35
36namespace attestation {
37
38const char kCreateAndCertifyCommand[] = "create_and_certify";
39const char kCreateCommand[] = "create";
40const char kInfoCommand[] = "info";
41const char kEndorsementCommand[] = "endorsement";
42const char kAttestationKeyCommand[] = "attestation_key";
43const char kActivateCommand[] = "activate";
44const char kEncryptForActivateCommand[] = "encrypt_for_activate";
45const char kEncryptCommand[] = "encrypt";
46const char kDecryptCommand[] = "decrypt";
47const char kSignCommand[] = "sign";
48const char kVerifyCommand[] = "verify";
49const char kRegisterCommand[] = "register";
50const char kUsage[] = R"(
51Usage: attestation_client <command> [<args>]
52Commands:
53  create_and_certify [--user=<email>] [--label=<keylabel>]
54      Creates a key and requests certification by the Google Attestation CA.
55      This is the default command.
56  create [--user=<email>] [--label=<keylabel] [--usage=sign|decrypt]
57      Creates a certifiable key.
58
59  info [--user=<email>] [--label=<keylabel>]
60      Prints info about a key.
61  endorsement
62      Prints info about the TPM endorsement.
63  attestation_key
64      Prints info about the TPM attestation key.
65
66  activate --input=<input_file>
67      Activates an attestation key using the encrypted credential in
68      |input_file|.
69  encrypt_for_activate --input=<input_file> --output=<output_file>
70      Encrypts the content of |input_file| as required by the TPM for activating
71      an attestation key. The result is written to |output_file|.
72
73  encrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
74          --output=<output_file>
75      Encrypts the contents of |input_file| as required by the TPM for a decrypt
76      operation. The result is written to |output_file|.
77  decrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
78      Decrypts the contents of |input_file|.
79
80  sign [--user=<email>] [--label=<keylabel>] --input=<input_file>
81          [--output=<output_file>]
82      Signs the contents of |input_file|.
83  verify [--user=<email>] [--label=<keylabel] --input=<signed_data_file>
84          --signature=<signature_file>
85      Verifies the signature in |signature_file| against the contents of
86      |input_file|.
87
88  register [--user=<email>] [--label=<keylabel]
89      Registers a key with a PKCS #11 token.
90)";
91
92// The Daemon class works well as a client loop as well.
93using ClientLoopBase = brillo::Daemon;
94
95class ClientLoop : public ClientLoopBase {
96 public:
97  ClientLoop() = default;
98  ~ClientLoop() override = default;
99
100 protected:
101  int OnInit() override {
102    int exit_code = ClientLoopBase::OnInit();
103    if (exit_code != EX_OK) {
104      return exit_code;
105    }
106    attestation_.reset(new attestation::DBusProxy());
107    if (!attestation_->Initialize()) {
108      return EX_UNAVAILABLE;
109    }
110    exit_code = ScheduleCommand();
111    if (exit_code == EX_USAGE) {
112      printf("%s", kUsage);
113    }
114    return exit_code;
115  }
116
117  void OnShutdown(int* exit_code) override {
118    attestation_.reset();
119    ClientLoopBase::OnShutdown(exit_code);
120  }
121
122 private:
123  // Posts tasks according to the command line options.
124  int ScheduleCommand() {
125    base::Closure task;
126    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
127    const auto& args = command_line->GetArgs();
128    if (command_line->HasSwitch("help") || command_line->HasSwitch("h") ||
129        (!args.empty() && args.front() == "help")) {
130      return EX_USAGE;
131    }
132    if (args.empty() || args.front() == kCreateAndCertifyCommand) {
133      task = base::Bind(&ClientLoop::CallCreateGoogleAttestedKey,
134                        weak_factory_.GetWeakPtr(),
135                        command_line->GetSwitchValueASCII("label"),
136                        command_line->GetSwitchValueASCII("user"));
137    } else if (args.front() == kCreateCommand) {
138      std::string usage_str = command_line->GetSwitchValueASCII("usage");
139      KeyUsage usage;
140      if (usage_str.empty() || usage_str == "sign") {
141        usage = KEY_USAGE_SIGN;
142      } else if (usage_str == "decrypt") {
143        usage = KEY_USAGE_DECRYPT;
144      } else {
145        return EX_USAGE;
146      }
147      task = base::Bind(&ClientLoop::CallCreateCertifiableKey,
148                        weak_factory_.GetWeakPtr(),
149                        command_line->GetSwitchValueASCII("label"),
150                        command_line->GetSwitchValueASCII("user"),
151                        usage);
152    } else if (args.front() == kInfoCommand) {
153      task = base::Bind(&ClientLoop::CallGetKeyInfo,
154                        weak_factory_.GetWeakPtr(),
155                        command_line->GetSwitchValueASCII("label"),
156                        command_line->GetSwitchValueASCII("user"));
157    } else if (args.front() == kEndorsementCommand) {
158      task = base::Bind(&ClientLoop::CallGetEndorsementInfo,
159                        weak_factory_.GetWeakPtr());
160    } else if (args.front() == kAttestationKeyCommand) {
161      task = base::Bind(&ClientLoop::CallGetAttestationKeyInfo,
162                        weak_factory_.GetWeakPtr());
163    } else if (args.front() == kActivateCommand) {
164      if (!command_line->HasSwitch("input")) {
165        return EX_USAGE;
166      }
167      std::string input;
168      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
169      if (!base::ReadFileToString(filename, &input)) {
170        LOG(ERROR) << "Failed to read file: " << filename.value();
171        return EX_NOINPUT;
172      }
173      task = base::Bind(&ClientLoop::CallActivateAttestationKey,
174                        weak_factory_.GetWeakPtr(),
175                        input);
176    } else if (args.front() == kEncryptForActivateCommand) {
177      if (!command_line->HasSwitch("input") ||
178          !command_line->HasSwitch("output")) {
179        return EX_USAGE;
180      }
181      std::string input;
182      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
183      if (!base::ReadFileToString(filename, &input)) {
184        LOG(ERROR) << "Failed to read file: " << filename.value();
185        return EX_NOINPUT;
186      }
187      task = base::Bind(&ClientLoop::EncryptForActivate,
188                        weak_factory_.GetWeakPtr(),
189                        input);
190    } else if (args.front() == kEncryptCommand) {
191      if (!command_line->HasSwitch("input") ||
192          !command_line->HasSwitch("output")) {
193        return EX_USAGE;
194      }
195      std::string input;
196      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
197      if (!base::ReadFileToString(filename, &input)) {
198        LOG(ERROR) << "Failed to read file: " << filename.value();
199        return EX_NOINPUT;
200      }
201      task = base::Bind(&ClientLoop::Encrypt,
202                        weak_factory_.GetWeakPtr(),
203                        command_line->GetSwitchValueASCII("label"),
204                        command_line->GetSwitchValueASCII("user"),
205                        input);
206    } else if (args.front() == kDecryptCommand) {
207      if (!command_line->HasSwitch("input")) {
208        return EX_USAGE;
209      }
210      std::string input;
211      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
212      if (!base::ReadFileToString(filename, &input)) {
213        LOG(ERROR) << "Failed to read file: " << filename.value();
214        return EX_NOINPUT;
215      }
216      task = base::Bind(&ClientLoop::CallDecrypt,
217                        weak_factory_.GetWeakPtr(),
218                        command_line->GetSwitchValueASCII("label"),
219                        command_line->GetSwitchValueASCII("user"),
220                        input);
221    } else if (args.front() == kSignCommand) {
222      if (!command_line->HasSwitch("input")) {
223        return EX_USAGE;
224      }
225      std::string input;
226      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
227      if (!base::ReadFileToString(filename, &input)) {
228        LOG(ERROR) << "Failed to read file: " << filename.value();
229        return EX_NOINPUT;
230      }
231      task = base::Bind(&ClientLoop::CallSign,
232                        weak_factory_.GetWeakPtr(),
233                        command_line->GetSwitchValueASCII("label"),
234                        command_line->GetSwitchValueASCII("user"),
235                        input);
236    } else if (args.front() == kVerifyCommand) {
237      if (!command_line->HasSwitch("input") ||
238          !command_line->HasSwitch("signature")) {
239        return EX_USAGE;
240      }
241      std::string input;
242      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
243      if (!base::ReadFileToString(filename, &input)) {
244        LOG(ERROR) << "Failed to read file: " << filename.value();
245        return EX_NOINPUT;
246      }
247      std::string signature;
248      base::FilePath filename2(command_line->GetSwitchValueASCII("signature"));
249      if (!base::ReadFileToString(filename2, &signature)) {
250        LOG(ERROR) << "Failed to read file: " << filename2.value();
251        return EX_NOINPUT;
252      }
253      task = base::Bind(&ClientLoop::VerifySignature,
254                        weak_factory_.GetWeakPtr(),
255                        command_line->GetSwitchValueASCII("label"),
256                        command_line->GetSwitchValueASCII("user"),
257                        input,
258                        signature);
259    } else if (args.front() == kRegisterCommand) {
260      task = base::Bind(&ClientLoop::CallRegister,
261                        weak_factory_.GetWeakPtr(),
262                        command_line->GetSwitchValueASCII("label"),
263                        command_line->GetSwitchValueASCII("user"));
264    } else {
265      return EX_USAGE;
266    }
267    base::MessageLoop::current()->PostTask(FROM_HERE, task);
268    return EX_OK;
269  }
270
271  template <typename ProtobufType>
272  void PrintReplyAndQuit(const ProtobufType& reply) {
273    printf("%s\n", GetProtoDebugString(reply).c_str());
274    Quit();
275  }
276
277  void WriteOutput(const std::string& output) {
278    base::FilePath filename(base::CommandLine::ForCurrentProcess()->
279        GetSwitchValueASCII("output"));
280    if (base::WriteFile(filename, output.data(), output.size()) !=
281        static_cast<int>(output.size())) {
282      LOG(ERROR) << "Failed to write file: " << filename.value();
283      QuitWithExitCode(EX_IOERR);
284    }
285  }
286
287  void CallCreateGoogleAttestedKey(const std::string& label,
288                                   const std::string& username) {
289    CreateGoogleAttestedKeyRequest request;
290    request.set_key_label(label);
291    request.set_key_type(KEY_TYPE_RSA);
292    request.set_key_usage(KEY_USAGE_SIGN);
293    request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
294    request.set_username(username);
295    attestation_->CreateGoogleAttestedKey(
296        request,
297        base::Bind(&ClientLoop::PrintReplyAndQuit<CreateGoogleAttestedKeyReply>,
298                   weak_factory_.GetWeakPtr()));
299  }
300
301  void CallGetKeyInfo(const std::string& label, const std::string& username) {
302    GetKeyInfoRequest request;
303    request.set_key_label(label);
304    request.set_username(username);
305    attestation_->GetKeyInfo(
306        request,
307        base::Bind(&ClientLoop::PrintReplyAndQuit<GetKeyInfoReply>,
308                   weak_factory_.GetWeakPtr()));
309  }
310
311  void CallGetEndorsementInfo() {
312    GetEndorsementInfoRequest request;
313    request.set_key_type(KEY_TYPE_RSA);
314    attestation_->GetEndorsementInfo(
315        request,
316        base::Bind(&ClientLoop::PrintReplyAndQuit<GetEndorsementInfoReply>,
317                   weak_factory_.GetWeakPtr()));
318  }
319
320  void CallGetAttestationKeyInfo() {
321    GetAttestationKeyInfoRequest request;
322    request.set_key_type(KEY_TYPE_RSA);
323    attestation_->GetAttestationKeyInfo(
324        request,
325        base::Bind(&ClientLoop::PrintReplyAndQuit<GetAttestationKeyInfoReply>,
326                   weak_factory_.GetWeakPtr()));
327  }
328
329  void CallActivateAttestationKey(const std::string& input) {
330    ActivateAttestationKeyRequest request;
331    request.set_key_type(KEY_TYPE_RSA);
332    request.mutable_encrypted_certificate()->ParseFromString(input);
333    request.set_save_certificate(true);
334    attestation_->ActivateAttestationKey(
335        request,
336        base::Bind(&ClientLoop::PrintReplyAndQuit<ActivateAttestationKeyReply>,
337                   weak_factory_.GetWeakPtr()));
338  }
339
340  void EncryptForActivate(const std::string& input) {
341    GetEndorsementInfoRequest request;
342    request.set_key_type(KEY_TYPE_RSA);
343    attestation_->GetEndorsementInfo(
344        request,
345        base::Bind(&ClientLoop::EncryptForActivate2,
346                   weak_factory_.GetWeakPtr(),
347                   input));
348  }
349
350  void EncryptForActivate2(const std::string& input,
351                           const GetEndorsementInfoReply& endorsement_info) {
352    if (endorsement_info.status() != STATUS_SUCCESS) {
353      PrintReplyAndQuit(endorsement_info);
354    }
355    GetAttestationKeyInfoRequest request;
356    request.set_key_type(KEY_TYPE_RSA);
357    attestation_->GetAttestationKeyInfo(
358        request,
359        base::Bind(&ClientLoop::EncryptForActivate3,
360                   weak_factory_.GetWeakPtr(),
361                   input,
362                   endorsement_info));
363  }
364
365  void EncryptForActivate3(
366      const std::string& input,
367      const GetEndorsementInfoReply& endorsement_info,
368      const GetAttestationKeyInfoReply& attestation_key_info) {
369    if (attestation_key_info.status() != STATUS_SUCCESS) {
370      PrintReplyAndQuit(attestation_key_info);
371    }
372    CryptoUtilityImpl crypto(nullptr);
373    EncryptedIdentityCredential encrypted;
374    if (!crypto.EncryptIdentityCredential(
375        input,
376        endorsement_info.ek_public_key(),
377        attestation_key_info.public_key_tpm_format(),
378        &encrypted)) {
379      QuitWithExitCode(EX_SOFTWARE);
380    }
381    std::string output;
382    encrypted.SerializeToString(&output);
383    WriteOutput(output);
384    Quit();
385  }
386
387  void CallCreateCertifiableKey(const std::string& label,
388                                const std::string& username,
389                                KeyUsage usage) {
390    CreateCertifiableKeyRequest request;
391    request.set_key_label(label);
392    request.set_username(username);
393    request.set_key_type(KEY_TYPE_RSA);
394    request.set_key_usage(usage);
395    attestation_->CreateCertifiableKey(
396        request,
397        base::Bind(&ClientLoop::PrintReplyAndQuit<CreateCertifiableKeyReply>,
398                   weak_factory_.GetWeakPtr()));
399  }
400
401  void Encrypt(const std::string& label,
402               const std::string& username,
403               const std::string& input) {
404    GetKeyInfoRequest request;
405    request.set_key_label(label);
406    request.set_username(username);
407    attestation_->GetKeyInfo(request, base::Bind(&ClientLoop::Encrypt2,
408                                                 weak_factory_.GetWeakPtr(),
409                                                 input));
410  }
411
412  void Encrypt2(const std::string& input,
413                const GetKeyInfoReply& key_info) {
414    CryptoUtilityImpl crypto(nullptr);
415    std::string output;
416    if (!crypto.EncryptForUnbind(key_info.public_key(), input, &output)) {
417      QuitWithExitCode(EX_SOFTWARE);
418    }
419    WriteOutput(output);
420    Quit();
421  }
422
423  void CallDecrypt(const std::string& label,
424                   const std::string& username,
425                   const std::string& input) {
426    DecryptRequest request;
427    request.set_key_label(label);
428    request.set_username(username);
429    request.set_encrypted_data(input);
430    attestation_->Decrypt(
431        request,
432        base::Bind(&ClientLoop::PrintReplyAndQuit<DecryptReply>,
433                   weak_factory_.GetWeakPtr()));
434  }
435
436  void CallSign(const std::string& label,
437                const std::string& username,
438                const std::string& input) {
439    SignRequest request;
440    request.set_key_label(label);
441    request.set_username(username);
442    request.set_data_to_sign(input);
443    attestation_->Sign(request, base::Bind(&ClientLoop::OnSignComplete,
444                                           weak_factory_.GetWeakPtr()));
445  }
446
447  void OnSignComplete(const SignReply& reply) {
448    if (reply.status() == STATUS_SUCCESS &&
449        base::CommandLine::ForCurrentProcess()->HasSwitch("output")) {
450      WriteOutput(reply.signature());
451    }
452    PrintReplyAndQuit<SignReply>(reply);
453  }
454
455  void VerifySignature(const std::string& label,
456                       const std::string& username,
457                       const std::string& input,
458                       const std::string& signature) {
459    GetKeyInfoRequest request;
460    request.set_key_label(label);
461    request.set_username(username);
462    attestation_->GetKeyInfo(request, base::Bind(&ClientLoop::VerifySignature2,
463                                                 weak_factory_.GetWeakPtr(),
464                                                 input, signature));
465  }
466
467  void VerifySignature2(const std::string& input,
468                        const std::string& signature,
469                        const GetKeyInfoReply& key_info) {
470    CryptoUtilityImpl crypto(nullptr);
471    if (crypto.VerifySignature(key_info.public_key(), input, signature)) {
472      printf("Signature is OK!\n");
473    } else {
474      printf("Signature is BAD!\n");
475    }
476    Quit();
477  }
478
479  void CallRegister(const std::string& label, const std::string& username) {
480    RegisterKeyWithChapsTokenRequest request;
481    request.set_key_label(label);
482    request.set_username(username);
483    attestation_->RegisterKeyWithChapsToken(request, base::Bind(
484        &ClientLoop::PrintReplyAndQuit<RegisterKeyWithChapsTokenReply>,
485        weak_factory_.GetWeakPtr()));
486  }
487
488  std::unique_ptr<attestation::AttestationInterface> attestation_;
489
490  // Declare this last so weak pointers will be destroyed first.
491  base::WeakPtrFactory<ClientLoop> weak_factory_{this};
492
493  DISALLOW_COPY_AND_ASSIGN(ClientLoop);
494};
495
496}  // namespace attestation
497
498int main(int argc, char* argv[]) {
499  base::CommandLine::Init(argc, argv);
500  brillo::InitLog(brillo::kLogToStderr);
501  attestation::ClientLoop loop;
502  return loop.Run();
503}
504