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