• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 namespace attestation {
37 
38 const char kCreateAndCertifyCommand[] = "create_and_certify";
39 const char kCreateCommand[] = "create";
40 const char kInfoCommand[] = "info";
41 const char kEndorsementCommand[] = "endorsement";
42 const char kAttestationKeyCommand[] = "attestation_key";
43 const char kActivateCommand[] = "activate";
44 const char kEncryptForActivateCommand[] = "encrypt_for_activate";
45 const char kEncryptCommand[] = "encrypt";
46 const char kDecryptCommand[] = "decrypt";
47 const char kSignCommand[] = "sign";
48 const char kVerifyCommand[] = "verify";
49 const char kRegisterCommand[] = "register";
50 const char kUsage[] = R"(
51 Usage: attestation_client <command> [<args>]
52 Commands:
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.
93 using ClientLoopBase = brillo::Daemon;
94 
95 class ClientLoop : public ClientLoopBase {
96  public:
97   ClientLoop() = default;
98   ~ClientLoop() override = default;
99 
100  protected:
OnInit()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 
OnShutdown(int * exit_code)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.
ScheduleCommand()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>
PrintReplyAndQuit(const ProtobufType & reply)272   void PrintReplyAndQuit(const ProtobufType& reply) {
273     printf("%s\n", GetProtoDebugString(reply).c_str());
274     Quit();
275   }
276 
WriteOutput(const std::string & output)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 
CallCreateGoogleAttestedKey(const std::string & label,const std::string & username)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 
CallGetKeyInfo(const std::string & label,const std::string & username)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 
CallGetEndorsementInfo()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 
CallGetAttestationKeyInfo()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 
CallActivateAttestationKey(const std::string & input)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 
EncryptForActivate(const std::string & input)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 
EncryptForActivate2(const std::string & input,const GetEndorsementInfoReply & endorsement_info)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 
EncryptForActivate3(const std::string & input,const GetEndorsementInfoReply & endorsement_info,const GetAttestationKeyInfoReply & attestation_key_info)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 
CallCreateCertifiableKey(const std::string & label,const std::string & username,KeyUsage usage)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 
Encrypt(const std::string & label,const std::string & username,const std::string & input)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 
Encrypt2(const std::string & input,const GetKeyInfoReply & key_info)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 
CallDecrypt(const std::string & label,const std::string & username,const std::string & input)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 
CallSign(const std::string & label,const std::string & username,const std::string & input)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 
OnSignComplete(const SignReply & reply)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 
VerifySignature(const std::string & label,const std::string & username,const std::string & input,const std::string & signature)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 
VerifySignature2(const std::string & input,const std::string & signature,const GetKeyInfoReply & key_info)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 
CallRegister(const std::string & label,const std::string & username)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 
main(int argc,char * argv[])498 int 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