github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/src/tpm2/ClientGetProgramKeyCert.cc (about)

     1  #include <stdio.h>
     2  #include <stdlib.h>
     3  #include <sys/types.h>
     4  #include <sys/stat.h>
     5  #include <fcntl.h>
     6  #include <unistd.h>
     7  #include <string.h>
     8  
     9  #include <openssl/ssl.h>
    10  #include <openssl/rsa.h>
    11  #include <openssl/x509.h>
    12  #include <openssl_helpers.h>
    13  
    14  #include <tpm20.h>
    15  #include <tpm2_lib.h>
    16  #include <gflags/gflags.h>
    17  
    18  //
    19  // Copyright 2015 Google Corporation, All Rights Reserved.
    20  //
    21  // Licensed under the Apache License, Version 2.0 (the "License");
    22  // you may not use this file except in compliance with the License.
    23  // You may obtain a copy of the License at
    24  //     http://www.apache.org/licenses/LICENSE-2.0
    25  // or in the the file LICENSE-2.0.txt in the top level sourcedirectory
    26  // Unless required by applicable law or agreed to in writing, software
    27  // distributed under the License is distributed on an "AS IS" BASIS,
    28  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    29  // See the License for the specific language governing permissions and
    30  // limitations under the License
    31  //
    32  // Portions of this code were derived TPM2.0-TSS published
    33  // by Intel under the license set forth in intel_license.txt
    34  // and downloaded on or about August 6, 2015.
    35  // Portions of this code were derived tboot published
    36  // by Intel under the license set forth in intel_license.txt
    37  // and downloaded on or about August 6, 2015.
    38  // Portions of this code were derived from the crypto utility
    39  // published by John Manferdelli under the Apache 2.0 license.
    40  // See github.com/jlmucb/crypto.
    41  // File: ClientGetProgramKeyCert.cc
    42  
    43  
    44  //  This program decrypts the program  key certificate using ActivateCredential
    45  //  and stores the resulting decrypted cert.
    46  
    47  // Calling sequence: ClientGetProgramKeyCert.exe
    48  //    --slot_primary=slot-number
    49  //    --slot_seal= slot-number
    50  //    --program_key_response_file=input-file-name
    51  //    --program_key_cert_file=output-file-name
    52  
    53  
    54  using std::string;
    55  
    56  
    57  #define CALLING_SEQUENCE "ClientGetProgramKeyCert.exe " \
    58  "--slot_primary=slot-number " \
    59  "--slot_seal= slot-number " \
    60  "--slot_quote= slot-number " \
    61  "--program_key_response_file=input-file-name " \
    62  "--program_key_cert_file=output-file-name\n"
    63  
    64  void PrintOptions() {
    65    printf("Calling sequence: %s", CALLING_SEQUENCE);
    66  }
    67  
    68  DEFINE_string(program_key_response_file, "", "input-file-name");
    69  DEFINE_int32(slot_primary, 1, "slot-number");
    70  DEFINE_int32(slot_seal, 2, "slot-number");
    71  DEFINE_int32(slot_quote, 3, "slot-number");
    72  DEFINE_string(program_key_type, "RSA", "alg name");
    73  DEFINE_string(program_key_cert_file, "", "output-file-name");
    74  DEFINE_string(hash_alg, "sha1", "hash algorithm");
    75  
    76  #ifndef GFLAGS_NS
    77  #define GFLAGS_NS google
    78  #endif
    79  
    80  #define MAX_SIZE_PARAMS 4096
    81  #define DEBUG
    82  
    83  int main(int an, char** av) {
    84    LocalTpm tpm;
    85    int ret_val = 0;
    86  
    87    printf("\nClientGetProgramKeyCert\n\n");
    88  
    89    GFLAGS_NS::ParseCommandLineFlags(&an, &av, true);
    90    if (!tpm.OpenTpm("/dev/tpm0")) {
    91      printf("Can't open tpm\n");
    92      return 1;
    93    }
    94  
    95    OpenSSL_add_all_algorithms();
    96  
    97    TPM_HANDLE nv_handle = 0;
    98  
    99    string authString("01020304");
   100    string parentAuth("01020304");
   101    string emptyAuth;
   102  
   103    TPML_PCR_SELECTION pcrSelect;
   104  
   105    TPM_HANDLE ekHandle = 0;
   106    TPM_HANDLE root_handle = 0;
   107    TPM_HANDLE seal_handle = 0;
   108    TPM_HANDLE quote_handle = 0;
   109  
   110    TPM2B_ID_OBJECT credentialBlob;
   111    TPM2B_ENCRYPTED_SECRET unmarshaled_secret;
   112  
   113    TPM2B_DIGEST recovered_credential;
   114  
   115    TPMA_OBJECT primary_flags;
   116    TPM2B_PUBLIC ek_pub_out;
   117  
   118    int current_size = 0;
   119    uint16_t context_data_size = 924;
   120    byte context_save_area[MAX_SIZE_PARAMS];
   121  
   122    string cert_key_seed;
   123    string label;
   124    string contextV;
   125    int size_derived_keys;
   126    byte derived_keys[128];
   127    int encrypted_cert_hmac_size;
   128    byte encrypted_cert_hmac[256];
   129    HMAC_CTX hctx;
   130  
   131    int size_response = MAX_SIZE_PARAMS;
   132    byte response_buf[MAX_SIZE_PARAMS];
   133    program_cert_response_message response;
   134    int size_cert_out = MAX_SIZE_PARAMS;
   135    byte cert_out_buf[MAX_SIZE_PARAMS];
   136  
   137    TPM_ALG_ID hash_alg_id;
   138    if (FLAGS_hash_alg == "sha1") {
   139      hash_alg_id = TPM_ALG_SHA1;
   140    } else if (FLAGS_hash_alg == "sha256") {
   141      hash_alg_id = TPM_ALG_SHA256;
   142    } else {
   143      printf("Unknown hash algorithm\n");
   144      return 1;
   145    }
   146  
   147    string input;
   148    string output;
   149  
   150    if (FLAGS_program_key_type != "RSA") {
   151      printf("Only RSA supported\n");
   152      ret_val = 1;
   153      goto done;
   154    }
   155    if (FLAGS_program_key_response_file == "") {
   156      printf("No key name\n");
   157      ret_val = 1;
   158      goto done;
   159    }
   160    if (FLAGS_program_key_cert_file == "") {
   161      printf("No key name\n");
   162      ret_val = 1;
   163      goto done;
   164    }
   165  
   166    // Create endorsement key
   167    *(uint32_t*)(&primary_flags) = 0;
   168  
   169    primary_flags.fixedTPM = 1;
   170    primary_flags.fixedParent = 1;
   171    primary_flags.sensitiveDataOrigin = 1;
   172    primary_flags.userWithAuth = 1;
   173    primary_flags.decrypt = 1;
   174    primary_flags.restricted = 1;
   175  
   176    if (Tpm2_CreatePrimary(tpm, TPM_RH_ENDORSEMENT, emptyAuth, pcrSelect,
   177                           TPM_ALG_RSA, hash_alg_id, primary_flags,
   178                           TPM_ALG_AES, 128, TPM_ALG_CFB, TPM_ALG_NULL,
   179                           2048, 0x010001, &ekHandle, &ek_pub_out)) {
   180      printf("CreatePrimary succeeded parent: %08x\n", ekHandle);
   181    } else {
   182      printf("CreatePrimary failed\n");
   183      ret_val = 1;
   184      goto done;
   185    }
   186  
   187    // restore context
   188    // TODO(jlm): should get pcr list from parameters
   189    InitSinglePcrSelection(7, hash_alg_id, &pcrSelect);
   190  
   191    // root handle
   192    memset(context_save_area, 0, MAX_SIZE_PARAMS);
   193    nv_handle = GetNvHandle(FLAGS_slot_primary);
   194    if (!Tpm2_ReadNv(tpm, nv_handle, authString, &context_data_size,
   195                     context_save_area)) {
   196      printf("Root ReadNv failed\n");
   197      ret_val = 1;
   198      goto done;
   199    }
   200  
   201  #ifdef DEBUG_EXTRA
   202    printf("\ncontext_save_area: ");
   203    PrintBytes(context_data_size, context_save_area);
   204    printf("\n\n");
   205  #endif
   206  
   207    if (!Tpm2_LoadContext(tpm, context_data_size, context_save_area,
   208                          &root_handle)) {
   209      printf("Root LoadContext failed\n");
   210      ret_val = 1;
   211      goto done;
   212    }
   213  
   214    // quote handle
   215    memset(context_save_area, 0, MAX_SIZE_PARAMS);
   216    nv_handle = GetNvHandle(FLAGS_slot_quote);
   217    if (!Tpm2_ReadNv(tpm, nv_handle, authString, &context_data_size,
   218                     context_save_area)) {
   219      printf("Quote ReadNv failed\n");
   220      ret_val = 1;
   221      goto done;
   222    }
   223    if (!Tpm2_LoadContext(tpm, context_data_size, context_save_area,
   224                          &quote_handle)) {
   225      printf("Quote LoadContext failed\n");
   226      ret_val = 1;
   227      goto done;
   228    }
   229  
   230  #ifdef DEBUG_EXTRA
   231    printf("\ncontext_save_area: ");
   232    PrintBytes(context_data_size, context_save_area);
   233    printf("\n\n");
   234  #endif
   235  
   236    // Get response
   237    if (!ReadFileIntoBlock(FLAGS_program_key_response_file, &size_response,
   238                           response_buf)) {
   239      printf("Can't read response\n");
   240      ret_val = 1;
   241      goto done;
   242    }
   243    input.assign((const char*)response_buf, size_response);
   244    if (!response.ParseFromString(input)) {
   245      printf("Can't parse response\n");
   246      ret_val = 1;
   247      goto done;
   248    }
   249  
   250  #ifdef DEBUG
   251    printf("\nintegrity (%d): ", (int)response.integrityhmac().size());
   252    PrintBytes(response.integrityhmac().size(),
   253               (byte*)response.integrityhmac().data());
   254    printf("\n");
   255    printf("encidentity(%d): ", (int)response.encidentity().size());
   256    PrintBytes(response.encidentity().size(),
   257               (byte*)response.encidentity().data());
   258    printf("\n");
   259    printf("secret(%d): ", (int)response.secret().size());
   260    PrintBytes(response.secret().size(),
   261               (byte*)response.secret().data());
   262    printf("\n");
   263  #endif
   264  
   265    // Fill credential blob and secret
   266    credentialBlob.size = (int)response.integrityhmac().size() + (int)response.encidentity().size();
   267    current_size = 0;
   268    memcpy(&credentialBlob.credential[current_size],
   269           (byte*) response.integrityhmac().data(),
   270           response.integrityhmac().size());
   271    current_size += response.integrityhmac().size();
   272    memcpy(&credentialBlob.credential[current_size],
   273           (byte*) response.encidentity().data(),
   274           response.encidentity().size());
   275    current_size += response.encidentity().size();
   276  
   277    // secret 
   278    unmarshaled_secret.size = response.secret().size();
   279    memcpy(unmarshaled_secret.secret, response.secret().data(),
   280           unmarshaled_secret.size);
   281  
   282  #ifdef DEBUG
   283    printf("\nunmarshaled secret: %d\n",
   284           (int) (unmarshaled_secret.size + sizeof(uint16_t)));
   285    PrintBytes(unmarshaled_secret.size, 
   286               (byte*)&unmarshaled_secret.secret);
   287    printf("\n");
   288    printf("\nConstructed credBlob (%d): ", credentialBlob.size);
   289    PrintBytes(credentialBlob.size, credentialBlob.credential);
   290    printf("\n");
   291  #endif
   292  
   293    if (!Tpm2_ActivateCredential(tpm, quote_handle, ekHandle, parentAuth,
   294                                 emptyAuth, credentialBlob, unmarshaled_secret,
   295                                 &recovered_credential)) {
   296      printf("ActivateCredential failed\n");
   297      ret_val = 1;
   298      goto done;
   299    }
   300  
   301  #ifdef DEBUG
   302    printf("\nActivateCredential succeeded\n");
   303    printf("\nRecovered credential (%d): ", recovered_credential.size);
   304    PrintBytes(recovered_credential.size, recovered_credential.buffer);
   305    printf("\n");
   306  #endif
   307  
   308    // Decrypt cert, credential is key
   309    if (response.encrypted_cert().size() > MAX_SIZE_PARAMS) {
   310      printf("encrypted cert too large\n");
   311      ret_val = 1;
   312      goto done;
   313    }
   314    size_cert_out = response.encrypted_cert().size();
   315  
   316    size_derived_keys = 128;
   317    label = "PROTECT";
   318    cert_key_seed.assign((const char*)recovered_credential.buffer,
   319                         recovered_credential.size);
   320    if (!KDFa(hash_alg_id, cert_key_seed, label, contextV, contextV, 256,
   321              size_derived_keys, derived_keys)) {
   322      printf("Can't derive cert protection keys\n");
   323      ret_val = 1;
   324      goto done;
   325    }
   326    // Check Hmac first
   327    if (hash_alg_id == TPM_ALG_SHA1) {
   328      HMAC_Init_ex(&hctx, &derived_keys[16], 16, EVP_sha1(), nullptr);
   329      encrypted_cert_hmac_size = 20;
   330    } else {
   331      HMAC_Init_ex(&hctx, &derived_keys[16], 16, EVP_sha256(), nullptr);
   332      encrypted_cert_hmac_size = 32;
   333    }
   334    HMAC_Update(&hctx, (byte*)response.encrypted_cert().data(),
   335                response.encrypted_cert().size());
   336    HMAC_Final(&hctx, encrypted_cert_hmac, (uint32_t*)&encrypted_cert_hmac_size);
   337    HMAC_CTX_cleanup(&hctx);
   338    if (memcmp(encrypted_cert_hmac, response.encrypted_cert_hmac().data(),
   339               encrypted_cert_hmac_size) !=0) {
   340      printf("Hmac compare failed\n");
   341      ret_val = 1;
   342      goto done;
   343    }
   344    // decrypt
   345    if (!AesCtrCrypt(128, derived_keys, response.encrypted_cert().size(),
   346                     (byte*)response.encrypted_cert().data(),
   347                     cert_out_buf)) {
   348      printf("Can't parse response\n");
   349      ret_val = 1;
   350      goto done;
   351    }
   352    size_cert_out = response.encrypted_cert().size();
   353  
   354  #ifdef DEBUG
   355    printf("\nhmac (%d): ", encrypted_cert_hmac_size);
   356    PrintBytes(encrypted_cert_hmac_size, encrypted_cert_hmac);
   357    printf("\n");
   358    printf("decrypted cert (%d): ", size_cert_out);
   359    PrintBytes(size_cert_out, cert_out_buf);
   360    printf("\n\n");
   361  #endif
   362    
   363   // Write output cert
   364   if (!WriteFileFromBlock(FLAGS_program_key_cert_file,
   365                            size_cert_out,
   366                            cert_out_buf)) {
   367      printf("Can't write out program cert\n");
   368      ret_val = 1;
   369      goto done;
   370    }
   371  
   372  done:
   373   if (root_handle != 0) {
   374      Tpm2_FlushContext(tpm, root_handle);
   375    }
   376    if (seal_handle != 0) {
   377      Tpm2_FlushContext(tpm, seal_handle);
   378    }
   379    if (quote_handle != 0) {
   380      Tpm2_FlushContext(tpm, quote_handle);
   381    }
   382    if (ekHandle != 0) {
   383      Tpm2_FlushContext(tpm, ekHandle);
   384    }
   385    tpm.CloseTpm();
   386    return ret_val;
   387  }
   388