Home | History | Annotate | Download | only in client
      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:
    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 
    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