• 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"), usage);
151     } else if (args.front() == kInfoCommand) {
152       task = base::Bind(&ClientLoop::CallGetKeyInfo, weak_factory_.GetWeakPtr(),
153                         command_line->GetSwitchValueASCII("label"),
154                         command_line->GetSwitchValueASCII("user"));
155     } else if (args.front() == kEndorsementCommand) {
156       task = base::Bind(&ClientLoop::CallGetEndorsementInfo,
157                         weak_factory_.GetWeakPtr());
158     } else if (args.front() == kAttestationKeyCommand) {
159       task = base::Bind(&ClientLoop::CallGetAttestationKeyInfo,
160                         weak_factory_.GetWeakPtr());
161     } else if (args.front() == kActivateCommand) {
162       if (!command_line->HasSwitch("input")) {
163         return EX_USAGE;
164       }
165       std::string input;
166       base::FilePath filename(command_line->GetSwitchValueASCII("input"));
167       if (!base::ReadFileToString(filename, &input)) {
168         LOG(ERROR) << "Failed to read file: " << filename.value();
169         return EX_NOINPUT;
170       }
171       task = base::Bind(&ClientLoop::CallActivateAttestationKey,
172                         weak_factory_.GetWeakPtr(), input);
173     } else if (args.front() == kEncryptForActivateCommand) {
174       if (!command_line->HasSwitch("input") ||
175           !command_line->HasSwitch("output")) {
176         return EX_USAGE;
177       }
178       std::string input;
179       base::FilePath filename(command_line->GetSwitchValueASCII("input"));
180       if (!base::ReadFileToString(filename, &input)) {
181         LOG(ERROR) << "Failed to read file: " << filename.value();
182         return EX_NOINPUT;
183       }
184       task = base::Bind(&ClientLoop::EncryptForActivate,
185                         weak_factory_.GetWeakPtr(), input);
186     } else if (args.front() == kEncryptCommand) {
187       if (!command_line->HasSwitch("input") ||
188           !command_line->HasSwitch("output")) {
189         return EX_USAGE;
190       }
191       std::string input;
192       base::FilePath filename(command_line->GetSwitchValueASCII("input"));
193       if (!base::ReadFileToString(filename, &input)) {
194         LOG(ERROR) << "Failed to read file: " << filename.value();
195         return EX_NOINPUT;
196       }
197       task = base::Bind(&ClientLoop::Encrypt, weak_factory_.GetWeakPtr(),
198                         command_line->GetSwitchValueASCII("label"),
199                         command_line->GetSwitchValueASCII("user"), input);
200     } else if (args.front() == kDecryptCommand) {
201       if (!command_line->HasSwitch("input")) {
202         return EX_USAGE;
203       }
204       std::string input;
205       base::FilePath filename(command_line->GetSwitchValueASCII("input"));
206       if (!base::ReadFileToString(filename, &input)) {
207         LOG(ERROR) << "Failed to read file: " << filename.value();
208         return EX_NOINPUT;
209       }
210       task = base::Bind(&ClientLoop::CallDecrypt, weak_factory_.GetWeakPtr(),
211                         command_line->GetSwitchValueASCII("label"),
212                         command_line->GetSwitchValueASCII("user"), input);
213     } else if (args.front() == kSignCommand) {
214       if (!command_line->HasSwitch("input")) {
215         return EX_USAGE;
216       }
217       std::string input;
218       base::FilePath filename(command_line->GetSwitchValueASCII("input"));
219       if (!base::ReadFileToString(filename, &input)) {
220         LOG(ERROR) << "Failed to read file: " << filename.value();
221         return EX_NOINPUT;
222       }
223       task = base::Bind(&ClientLoop::CallSign, weak_factory_.GetWeakPtr(),
224                         command_line->GetSwitchValueASCII("label"),
225                         command_line->GetSwitchValueASCII("user"), input);
226     } else if (args.front() == kVerifyCommand) {
227       if (!command_line->HasSwitch("input") ||
228           !command_line->HasSwitch("signature")) {
229         return EX_USAGE;
230       }
231       std::string input;
232       base::FilePath filename(command_line->GetSwitchValueASCII("input"));
233       if (!base::ReadFileToString(filename, &input)) {
234         LOG(ERROR) << "Failed to read file: " << filename.value();
235         return EX_NOINPUT;
236       }
237       std::string signature;
238       base::FilePath filename2(command_line->GetSwitchValueASCII("signature"));
239       if (!base::ReadFileToString(filename2, &signature)) {
240         LOG(ERROR) << "Failed to read file: " << filename2.value();
241         return EX_NOINPUT;
242       }
243       task = base::Bind(
244           &ClientLoop::VerifySignature, weak_factory_.GetWeakPtr(),
245           command_line->GetSwitchValueASCII("label"),
246           command_line->GetSwitchValueASCII("user"), input, signature);
247     } else if (args.front() == kRegisterCommand) {
248       task = base::Bind(&ClientLoop::CallRegister, weak_factory_.GetWeakPtr(),
249                         command_line->GetSwitchValueASCII("label"),
250                         command_line->GetSwitchValueASCII("user"));
251     } else {
252       return EX_USAGE;
253     }
254     base::MessageLoop::current()->PostTask(FROM_HERE, task);
255     return EX_OK;
256   }
257 
258   template <typename ProtobufType>
PrintReplyAndQuit(const ProtobufType & reply)259   void PrintReplyAndQuit(const ProtobufType& reply) {
260     printf("%s\n", GetProtoDebugString(reply).c_str());
261     Quit();
262   }
263 
WriteOutput(const std::string & output)264   void WriteOutput(const std::string& output) {
265     base::FilePath filename(
266         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("output"));
267     if (base::WriteFile(filename, output.data(), output.size()) !=
268         static_cast<int>(output.size())) {
269       LOG(ERROR) << "Failed to write file: " << filename.value();
270       QuitWithExitCode(EX_IOERR);
271     }
272   }
273 
CallCreateGoogleAttestedKey(const std::string & label,const std::string & username)274   void CallCreateGoogleAttestedKey(const std::string& label,
275                                    const std::string& username) {
276     CreateGoogleAttestedKeyRequest request;
277     request.set_key_label(label);
278     request.set_key_type(KEY_TYPE_RSA);
279     request.set_key_usage(KEY_USAGE_SIGN);
280     request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
281     request.set_username(username);
282     attestation_->CreateGoogleAttestedKey(
283         request,
284         base::Bind(&ClientLoop::PrintReplyAndQuit<CreateGoogleAttestedKeyReply>,
285                    weak_factory_.GetWeakPtr()));
286   }
287 
CallGetKeyInfo(const std::string & label,const std::string & username)288   void CallGetKeyInfo(const std::string& label, const std::string& username) {
289     GetKeyInfoRequest request;
290     request.set_key_label(label);
291     request.set_username(username);
292     attestation_->GetKeyInfo(
293         request, base::Bind(&ClientLoop::PrintReplyAndQuit<GetKeyInfoReply>,
294                             weak_factory_.GetWeakPtr()));
295   }
296 
CallGetEndorsementInfo()297   void CallGetEndorsementInfo() {
298     GetEndorsementInfoRequest request;
299     request.set_key_type(KEY_TYPE_RSA);
300     attestation_->GetEndorsementInfo(
301         request,
302         base::Bind(&ClientLoop::PrintReplyAndQuit<GetEndorsementInfoReply>,
303                    weak_factory_.GetWeakPtr()));
304   }
305 
CallGetAttestationKeyInfo()306   void CallGetAttestationKeyInfo() {
307     GetAttestationKeyInfoRequest request;
308     request.set_key_type(KEY_TYPE_RSA);
309     attestation_->GetAttestationKeyInfo(
310         request,
311         base::Bind(&ClientLoop::PrintReplyAndQuit<GetAttestationKeyInfoReply>,
312                    weak_factory_.GetWeakPtr()));
313   }
314 
CallActivateAttestationKey(const std::string & input)315   void CallActivateAttestationKey(const std::string& input) {
316     ActivateAttestationKeyRequest request;
317     request.set_key_type(KEY_TYPE_RSA);
318     request.mutable_encrypted_certificate()->ParseFromString(input);
319     request.set_save_certificate(true);
320     attestation_->ActivateAttestationKey(
321         request,
322         base::Bind(&ClientLoop::PrintReplyAndQuit<ActivateAttestationKeyReply>,
323                    weak_factory_.GetWeakPtr()));
324   }
325 
EncryptForActivate(const std::string & input)326   void EncryptForActivate(const std::string& input) {
327     GetEndorsementInfoRequest request;
328     request.set_key_type(KEY_TYPE_RSA);
329     attestation_->GetEndorsementInfo(
330         request, base::Bind(&ClientLoop::EncryptForActivate2,
331                             weak_factory_.GetWeakPtr(), input));
332   }
333 
EncryptForActivate2(const std::string & input,const GetEndorsementInfoReply & endorsement_info)334   void EncryptForActivate2(const std::string& input,
335                            const GetEndorsementInfoReply& endorsement_info) {
336     if (endorsement_info.status() != STATUS_SUCCESS) {
337       PrintReplyAndQuit(endorsement_info);
338     }
339     GetAttestationKeyInfoRequest request;
340     request.set_key_type(KEY_TYPE_RSA);
341     attestation_->GetAttestationKeyInfo(
342         request,
343         base::Bind(&ClientLoop::EncryptForActivate3, weak_factory_.GetWeakPtr(),
344                    input, endorsement_info));
345   }
346 
EncryptForActivate3(const std::string & input,const GetEndorsementInfoReply & endorsement_info,const GetAttestationKeyInfoReply & attestation_key_info)347   void EncryptForActivate3(
348       const std::string& input,
349       const GetEndorsementInfoReply& endorsement_info,
350       const GetAttestationKeyInfoReply& attestation_key_info) {
351     if (attestation_key_info.status() != STATUS_SUCCESS) {
352       PrintReplyAndQuit(attestation_key_info);
353     }
354     CryptoUtilityImpl crypto(nullptr);
355     EncryptedIdentityCredential encrypted;
356     if (!crypto.EncryptIdentityCredential(
357             input, endorsement_info.ek_public_key(),
358             attestation_key_info.public_key_tpm_format(), &encrypted)) {
359       QuitWithExitCode(EX_SOFTWARE);
360     }
361     std::string output;
362     encrypted.SerializeToString(&output);
363     WriteOutput(output);
364     Quit();
365   }
366 
CallCreateCertifiableKey(const std::string & label,const std::string & username,KeyUsage usage)367   void CallCreateCertifiableKey(const std::string& label,
368                                 const std::string& username,
369                                 KeyUsage usage) {
370     CreateCertifiableKeyRequest request;
371     request.set_key_label(label);
372     request.set_username(username);
373     request.set_key_type(KEY_TYPE_RSA);
374     request.set_key_usage(usage);
375     attestation_->CreateCertifiableKey(
376         request,
377         base::Bind(&ClientLoop::PrintReplyAndQuit<CreateCertifiableKeyReply>,
378                    weak_factory_.GetWeakPtr()));
379   }
380 
Encrypt(const std::string & label,const std::string & username,const std::string & input)381   void Encrypt(const std::string& label,
382                const std::string& username,
383                const std::string& input) {
384     GetKeyInfoRequest request;
385     request.set_key_label(label);
386     request.set_username(username);
387     attestation_->GetKeyInfo(
388         request,
389         base::Bind(&ClientLoop::Encrypt2, weak_factory_.GetWeakPtr(), input));
390   }
391 
Encrypt2(const std::string & input,const GetKeyInfoReply & key_info)392   void Encrypt2(const std::string& input, const GetKeyInfoReply& key_info) {
393     CryptoUtilityImpl crypto(nullptr);
394     std::string output;
395     if (!crypto.EncryptForUnbind(key_info.public_key(), input, &output)) {
396       QuitWithExitCode(EX_SOFTWARE);
397     }
398     WriteOutput(output);
399     Quit();
400   }
401 
CallDecrypt(const std::string & label,const std::string & username,const std::string & input)402   void CallDecrypt(const std::string& label,
403                    const std::string& username,
404                    const std::string& input) {
405     DecryptRequest request;
406     request.set_key_label(label);
407     request.set_username(username);
408     request.set_encrypted_data(input);
409     attestation_->Decrypt(
410         request, base::Bind(&ClientLoop::PrintReplyAndQuit<DecryptReply>,
411                             weak_factory_.GetWeakPtr()));
412   }
413 
CallSign(const std::string & label,const std::string & username,const std::string & input)414   void CallSign(const std::string& label,
415                 const std::string& username,
416                 const std::string& input) {
417     SignRequest request;
418     request.set_key_label(label);
419     request.set_username(username);
420     request.set_data_to_sign(input);
421     attestation_->Sign(request, base::Bind(&ClientLoop::OnSignComplete,
422                                            weak_factory_.GetWeakPtr()));
423   }
424 
OnSignComplete(const SignReply & reply)425   void OnSignComplete(const SignReply& reply) {
426     if (reply.status() == STATUS_SUCCESS &&
427         base::CommandLine::ForCurrentProcess()->HasSwitch("output")) {
428       WriteOutput(reply.signature());
429     }
430     PrintReplyAndQuit<SignReply>(reply);
431   }
432 
VerifySignature(const std::string & label,const std::string & username,const std::string & input,const std::string & signature)433   void VerifySignature(const std::string& label,
434                        const std::string& username,
435                        const std::string& input,
436                        const std::string& signature) {
437     GetKeyInfoRequest request;
438     request.set_key_label(label);
439     request.set_username(username);
440     attestation_->GetKeyInfo(
441         request, base::Bind(&ClientLoop::VerifySignature2,
442                             weak_factory_.GetWeakPtr(), input, signature));
443   }
444 
VerifySignature2(const std::string & input,const std::string & signature,const GetKeyInfoReply & key_info)445   void VerifySignature2(const std::string& input,
446                         const std::string& signature,
447                         const GetKeyInfoReply& key_info) {
448     CryptoUtilityImpl crypto(nullptr);
449     if (crypto.VerifySignature(key_info.public_key(), input, signature)) {
450       printf("Signature is OK!\n");
451     } else {
452       printf("Signature is BAD!\n");
453     }
454     Quit();
455   }
456 
CallRegister(const std::string & label,const std::string & username)457   void CallRegister(const std::string& label, const std::string& username) {
458     RegisterKeyWithChapsTokenRequest request;
459     request.set_key_label(label);
460     request.set_username(username);
461     attestation_->RegisterKeyWithChapsToken(
462         request,
463         base::Bind(
464             &ClientLoop::PrintReplyAndQuit<RegisterKeyWithChapsTokenReply>,
465             weak_factory_.GetWeakPtr()));
466   }
467 
468   std::unique_ptr<attestation::AttestationInterface> attestation_;
469 
470   // Declare this last so weak pointers will be destroyed first.
471   base::WeakPtrFactory<ClientLoop> weak_factory_{this};
472 
473   DISALLOW_COPY_AND_ASSIGN(ClientLoop);
474 };
475 
476 }  // namespace attestation
477 
main(int argc,char * argv[])478 int main(int argc, char* argv[]) {
479   base::CommandLine::Init(argc, argv);
480   brillo::InitLog(brillo::kLogToStderr);
481   attestation::ClientLoop loop;
482   return loop.Run();
483 }
484