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