github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/src/tpm2/ClientGenerateProgramKeyRequest.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 <quote_protocol.h>
    15  
    16  #include <tpm20.h>
    17  #include <tpm2_lib.h>
    18  #include <gflags/gflags.h>
    19  
    20  //
    21  // Copyright 2015 Google Corporation, All Rights Reserved.
    22  //
    23  // Licensed under the Apache License, Version 2.0 (the "License");
    24  // you may not use this file except in compliance with the License.
    25  // You may obtain a copy of the License at
    26  //     http://www.apache.org/licenses/LICENSE-2.0
    27  // or in the the file LICENSE-2.0.txt in the top level sourcedirectory
    28  // Unless required by applicable law or agreed to in writing, software
    29  // distributed under the License is distributed on an "AS IS" BASIS,
    30  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    31  // See the License for the specific language governing permissions and
    32  // limitations under the License
    33  //
    34  // Portions of this code were derived TPM2.0-TSS published
    35  // by Intel under the license set forth in intel_license.txt
    36  // and downloaded on or about August 6, 2015.
    37  // Portions of this code were derived tboot published
    38  // by Intel under the license set forth in intel_license.txt
    39  // and downloaded on or about August 6, 2015.
    40  // Portions of this code were derived from the crypto utility
    41  // published by John Manferdelli under the Apache 2.0 license.
    42  // See github.com/jlmucb/crypto.
    43  // File: ClientGenerateProgramKeyRequest.cc
    44  
    45  
    46  // This program creates a program key and produces a
    47  // program_cert_request_message which contains a protobuf
    48  // consisting of the endorsement key certificate, and
    49  // a request to sign the program key and encrypt the result
    50  // with a credential that can be unlocked with the endorsement
    51  // key referencing the Quote key properties..
    52  
    53  // Calling sequence: ClientGenerateProgramKeyRequest.exe
    54  //    --signed_endorsement_cert=input-file-name
    55  //    --signing_key_type=RSA
    56  //    --signing_key_size=2048
    57  //    --program_key_request_file=output-file-name
    58  
    59  
    60  using std::string;
    61  
    62  
    63  #define CALLING_SEQUENCE "ClientCreateSigningKey.exe " \
    64  "--signed_endorsement_cert_file=input-file-name " \
    65  "--slot_primary=1" \
    66  "--slot_seal=2" \
    67  "--slot_quote=3" \
    68  "--program_key_name=name " \
    69  "--program_key_type=RSA " \
    70  "--program_key_size=2048 " \
    71  "--program_key_exponent=0x10001" \
    72  "--hash_alg=sha1 " \
    73  "--program_key_file=output-file-name" \
    74  "--program_cert_request_file=output-file-name\n"
    75  
    76  void PrintOptions() {
    77    printf("Calling sequence: %s", CALLING_SEQUENCE);
    78  }
    79  
    80  
    81  DEFINE_string(signed_endorsement_cert_file, "", "input-file-name");
    82  DEFINE_string(program_key_name, "NAME", "program name");
    83  DEFINE_string(program_key_type, "RSA", "program key type");
    84  DEFINE_int32(program_key_size, 2048, "program key type");
    85  DEFINE_int64(program_key_exponent, 0x010001ULL, "program key exponent");
    86  DEFINE_int32(slot_primary, 1, "slot number");
    87  DEFINE_int32(slot_seal, 2, "seal slot number");
    88  DEFINE_int32(slot_quote, 3, "quote slot number");
    89  DEFINE_string(hash_alg, "sha1", "sha1|sha256");
    90  DEFINE_string(program_key_file, "", "output-file-name");
    91  DEFINE_string(program_cert_request_file, "", "output-file-name");
    92  
    93  #ifndef GFLAGS_NS
    94  #define GFLAGS_NS google
    95  #endif
    96  
    97  #define MAX_SIZE_PARAMS 4096
    98  #define DEBUG
    99  
   100  int main(int an, char** av) {
   101    LocalTpm tpm;
   102    int ret_val = 0;
   103  
   104    printf("\nClientGenerateProgramKeyRequest\n\n");
   105  
   106    GFLAGS_NS::ParseCommandLineFlags(&an, &av, true);
   107    if (!tpm.OpenTpm("/dev/tpm0")) {
   108      printf("Can't open tpm\n");
   109      return 1;
   110    }
   111  
   112    OpenSSL_add_all_algorithms();
   113  
   114    TPM_HANDLE ekHandle = 0;
   115    TPMA_OBJECT primary_flags;
   116    TPM2B_PUBLIC ek_pub_out;
   117    TPM2B_NAME ek_pub_name;
   118    TPM2B_NAME ek_qualified_pub_name;
   119    uint16_t ek_pub_blob_size = MAX_SIZE_PARAMS;
   120    byte ek_pub_blob[MAX_SIZE_PARAMS];
   121  
   122    int ek_cert_blob_size = MAX_SIZE_PARAMS;
   123    byte ek_cert_blob[MAX_SIZE_PARAMS];
   124  
   125    TPM_HANDLE nv_handle = 0;
   126  
   127    string authString("01020304");
   128    string parentAuth("01020304");
   129    string emptyAuth;
   130  
   131    TPML_PCR_SELECTION pcrSelect;
   132  
   133    TPM_HANDLE root_handle = 0; 
   134    TPM_HANDLE seal_handle = 0;
   135    TPM_HANDLE quote_handle = 0;
   136  
   137    TPM2B_PUBLIC quote_pub_out;
   138    TPM2B_NAME quote_pub_name;
   139    TPM2B_NAME quote_qualified_pub_name;
   140    uint16_t quote_pub_blob_size = MAX_SIZE_PARAMS;
   141    byte quote_pub_blob[MAX_SIZE_PARAMS];
   142  
   143    string endorsement_key_blob;
   144    byte context_save_area[MAX_SIZE_PARAMS];
   145    uint16_t context_data_size = 924;
   146  
   147    RSA* program_rsa_key = nullptr;
   148    byte program_der_array_private[MAX_SIZE_PARAMS];
   149    byte* program_start_private = nullptr;
   150    byte* program_next_private = nullptr;
   151    int program_len_private;
   152  
   153    string* mod = nullptr;
   154    uint64_t expIn;
   155    uint64_t expOut;
   156    SHA_CTX sha1;
   157    SHA256_CTX sha256;
   158    string x509_request_key_blob;
   159  
   160    private_key_blob_message program_key_out;
   161    program_cert_request_message request;
   162  
   163    int quote_size = MAX_SIZE_PARAMS;
   164    byte quoted[MAX_SIZE_PARAMS];
   165    byte quoted_hash[256];
   166    string quote_key_info;
   167    string quote_sig;
   168    string quote_info;
   169    quote_key_info_message quote_key_info_message;
   170    TPM2B_DATA to_quote;
   171    TPMT_SIG_SCHEME scheme;
   172    int sig_size = MAX_SIZE_PARAMS;
   173    byte sig[MAX_SIZE_PARAMS];
   174  
   175    TPM_ALG_ID hash_alg_id;
   176    if (FLAGS_hash_alg == "sha1") {
   177      hash_alg_id = TPM_ALG_SHA1;
   178    } else if (FLAGS_hash_alg == "sha256") {
   179      hash_alg_id = TPM_ALG_SHA256;
   180    } else {
   181      printf("Unknown hash algorithm\n");
   182      return 1;
   183    }
   184  
   185    string output;
   186  
   187    // Create endorsement key
   188    *(uint32_t*)(&primary_flags) = 0;
   189  
   190    primary_flags.fixedTPM = 1;
   191    primary_flags.fixedParent = 1;
   192    primary_flags.sensitiveDataOrigin = 1;
   193    primary_flags.userWithAuth = 1;
   194    primary_flags.decrypt = 1;
   195    primary_flags.restricted = 1;
   196  
   197    InitSinglePcrSelection(7, hash_alg_id, &pcrSelect);
   198    if (Tpm2_CreatePrimary(tpm, TPM_RH_ENDORSEMENT, emptyAuth, pcrSelect,
   199                           TPM_ALG_RSA, hash_alg_id, primary_flags,
   200                           TPM_ALG_AES, 128, TPM_ALG_CFB, TPM_ALG_NULL,
   201                           2048, 0x010001, &ekHandle, &ek_pub_out)) {
   202      printf("CreatePrimary succeeded parent: %08x\n", ekHandle);
   203    } else {
   204      printf("CreatePrimary failed\n");
   205      ret_val = 1;
   206      goto done;
   207    }
   208    if (Tpm2_ReadPublic(tpm, ekHandle, &ek_pub_blob_size, ek_pub_blob,
   209                        &ek_pub_out, &ek_pub_name, &ek_qualified_pub_name)) {
   210      printf("ek ReadPublic succeeded\n");
   211    } else {
   212      printf("ek ReadPublic failed\n");
   213      ret_val = 1;
   214      goto done;
   215    }
   216  
   217  #ifdef DEBUG_EXTRA
   218    printf("\nek Public blob: ");
   219    PrintBytes(ek_pub_blob_size, ek_pub_blob);
   220    printf("\n");
   221    printf("ek Name: ");
   222    PrintBytes(ek_pub_name.size, ek_pub_name.name);
   223    printf("\n");
   224    printf("ek Qualified name: ");
   225    PrintBytes(ek_qualified_pub_name.size, ek_qualified_pub_name.name);
   226    printf("\n");
   227  #endif
   228  
   229    Tpm2_FlushContext(tpm, ekHandle);
   230    ekHandle = 0;
   231  
   232    // Get endorsement cert
   233    if (!ReadFileIntoBlock(FLAGS_signed_endorsement_cert_file, 
   234                           &ek_cert_blob_size, ek_cert_blob)) {
   235      printf("Can't read endorsement info\n");
   236      ret_val = 1;
   237      goto done;
   238    }
   239    endorsement_key_blob.assign((const char*)ek_cert_blob, ek_cert_blob_size);
   240  
   241    // restore hierarchy
   242    // TODO(jlm): should get pcr list from parameters
   243    InitSinglePcrSelection(7, hash_alg_id, &pcrSelect);
   244  
   245    // root handle
   246    memset(context_save_area, 0, MAX_SIZE_PARAMS);
   247    nv_handle = GetNvHandle(FLAGS_slot_primary);
   248    if (!Tpm2_ReadNv(tpm, nv_handle, authString, &context_data_size,
   249                     context_save_area)) {
   250      printf("Root ReadNv failed\n");
   251      ret_val = 1;
   252      goto done;
   253    }
   254  
   255  #ifdef DEBUG_EXTRA
   256    printf("\ncontext_save_area: ");
   257    PrintBytes(context_data_size, context_save_area);
   258    printf("\n\n");
   259  #endif
   260  
   261    if (!Tpm2_LoadContext(tpm, context_data_size, context_save_area,
   262                          &root_handle)) {
   263      printf("Root LoadContext failed\n");
   264      ret_val = 1;
   265      goto done;
   266    }
   267  
   268    // seal handle
   269    memset(context_save_area, 0, MAX_SIZE_PARAMS);
   270    nv_handle = GetNvHandle(FLAGS_slot_seal);
   271    if (!Tpm2_ReadNv(tpm, nv_handle, authString, &context_data_size,
   272                     context_save_area)) {
   273      printf("Root ReadNv failed\n");
   274      ret_val = 1;
   275      goto done;
   276    }
   277  
   278  #ifdef DEBUG_EXTRA
   279    printf("context_save_area: ");
   280    PrintBytes(context_data_size, context_save_area);
   281    printf("\n");
   282  #endif
   283  
   284    if (!Tpm2_LoadContext(tpm, context_data_size, context_save_area,
   285                          &seal_handle)) {
   286      printf("Seal LoadContext failed\n");
   287      ret_val = 1;
   288      goto done;
   289    }
   290  
   291    // quote handle
   292    memset(context_save_area, 0, MAX_SIZE_PARAMS);
   293    nv_handle = GetNvHandle(FLAGS_slot_quote);
   294    if (!Tpm2_ReadNv(tpm, nv_handle, authString, &context_data_size,
   295                     context_save_area)) {
   296      printf("Quote ReadNv failed\n");
   297      ret_val = 1;
   298      goto done;
   299    }
   300  
   301  #ifdef DEBUG_EXTRA
   302    printf("context_save_area: ");
   303    PrintBytes(context_data_size, context_save_area);
   304    printf("\n");
   305  #endif
   306  
   307    if (!Tpm2_LoadContext(tpm, context_data_size, context_save_area,
   308                          &quote_handle)) {
   309      printf("Quote LoadContext failed\n");
   310      ret_val = 1;
   311      goto done;
   312    }
   313  
   314    // Generate program key
   315    if (FLAGS_program_key_type != "RSA") {
   316      printf("Only RSA supported\n");
   317      ret_val = 1;
   318      goto done;
   319    }
   320    if (FLAGS_program_key_name == "") {
   321      printf("No key name\n");
   322      ret_val = 1;
   323      goto done;
   324    }
   325    if (FLAGS_program_key_file == "") {
   326      printf("No key file\n");
   327      ret_val = 1;
   328      goto done;
   329    }
   330  
   331    program_rsa_key = RSA_generate_key(FLAGS_program_key_size, 
   332                                       FLAGS_program_key_exponent,
   333                                       nullptr, nullptr);
   334    if (program_rsa_key == nullptr) {
   335      printf("Can't generate RSA key\n");
   336      ret_val = 1;
   337      goto done;
   338    }
   339    program_len_private = i2d_RSAPrivateKey(program_rsa_key, nullptr);
   340    program_start_private = program_der_array_private;
   341    program_next_private = program_der_array_private;
   342    i2d_RSAPrivateKey(program_rsa_key, (byte**)&program_next_private);
   343    printf("\nder encoded private key (%d): ", program_len_private);
   344    PrintBytes(program_len_private, program_start_private);
   345    printf("\n\n");
   346  
   347    program_key_out.set_key_type("RSA");
   348    program_key_out.set_key_name(FLAGS_program_key_name);
   349    program_key_out.set_blob((const char*)program_start_private,
   350                             program_len_private);
   351    if (!program_key_out.SerializeToString(&output)) {
   352      printf("Can't serialize output\n");
   353      ret_val = 1;
   354      goto done;
   355    }
   356    if (!WriteFileFromBlock(FLAGS_program_key_file, output.size(),
   357                            (byte*)output.data())) {
   358      printf("Can't write output file\n");
   359      ret_val = 1;
   360      goto done;
   361    }
   362  
   363    // Fill program key parameters
   364    request.set_endorsement_cert_blob(endorsement_key_blob);
   365    request.set_quote_sign_alg("RSA");
   366    request.set_quote_sign_hash_alg(FLAGS_hash_alg);
   367    request.mutable_program_key()->set_program_name(FLAGS_program_key_name);
   368    request.mutable_program_key()->set_program_key_type("RSA");
   369    request.mutable_program_key()->set_program_bit_modulus_size(
   370        FLAGS_program_key_size);
   371    expIn = (uint64_t) FLAGS_program_key_exponent;
   372    ChangeEndian64((uint64_t*)&expIn, (uint64_t*)(&expOut));
   373    request.mutable_program_key()->set_program_key_exponent(
   374        (const char*)&expOut, sizeof(uint64_t));
   375    mod = BN_to_bin(*program_rsa_key->n);
   376    if (mod == nullptr) {
   377      printf("Can't get program key modulus\n");
   378      ret_val = 1;
   379      goto done;
   380    }
   381    request.mutable_program_key()->set_program_key_modulus(
   382        (byte*)mod->data(), mod->size());
   383  
   384    // get quote key info
   385    if (Tpm2_ReadPublic(tpm, quote_handle, &quote_pub_blob_size,
   386                        quote_pub_blob, &quote_pub_out, &quote_pub_name,
   387                        &quote_qualified_pub_name)) {
   388      printf("Quote ReadPublic succeeded\n");
   389    } else {
   390      printf("Quote ReadPublic failed\n");
   391      ret_val = 1;
   392      goto done;
   393    }
   394  
   395  #ifdef DEBUG_EXTRA
   396    printf("\nQuote Public blob: ");
   397    PrintBytes(quote_pub_blob_size, quote_pub_blob);
   398    printf("\n");
   399    printf("Quote Name: ");
   400    PrintBytes(quote_pub_name.size, quote_pub_name.name);
   401    printf("\n");
   402    printf("Quote Qualified name: ");
   403    PrintBytes(quote_qualified_pub_name.size, quote_qualified_pub_name.name);
   404    printf("\n");
   405  #endif
   406  
   407    // hash program key request
   408    {
   409      string serialized_key = request.mutable_program_key()->DebugString();
   410      if (hash_alg_id == TPM_ALG_SHA1) {
   411        SHA1_Init(&sha1);
   412        SHA1_Update(&sha1, (byte*)serialized_key.data(), serialized_key.size());
   413        SHA1_Final(quoted_hash, &sha1);
   414      } else {
   415        SHA256_Init(&sha256);
   416        SHA256_Update(&sha256, (byte*)serialized_key.data(),
   417                      serialized_key.size());
   418        SHA256_Final(quoted_hash, &sha256);
   419      }
   420      to_quote.size = SizeHash(hash_alg_id);
   421      memset(to_quote.buffer, 0, to_quote.size);
   422      memcpy(to_quote.buffer, quoted_hash, to_quote.size);
   423    }
   424  
   425  #ifdef DEBUG
   426    printf("\nquoted_hash: "); PrintBytes(to_quote.size, to_quote.buffer);
   427    printf("\n");
   428  #endif
   429  
   430    if (!Tpm2_Quote(tpm, quote_handle, parentAuth, to_quote.size,
   431                    to_quote.buffer, scheme, pcrSelect, TPM_ALG_RSA,
   432                    hash_alg_id, &quote_size, quoted, &sig_size, sig)) {
   433      printf("Quote failed\n");
   434      ret_val = 1;
   435      goto done;
   436    }
   437  
   438  #ifdef DEBUG
   439    {
   440      printf("\nQuote succeeded\n");
   441      printf("Quoted (%d): ", to_quote.size);
   442      PrintBytes(to_quote.size, to_quote.buffer);
   443      printf("\n");
   444      printf("TPM computed quote (%d): ", quote_size);
   445      PrintBytes(quote_size, quoted);
   446      printf("\n");
   447      printf("Sig (%d): ", sig_size);
   448      PrintBytes(sig_size, sig);
   449      printf("\n");
   450      TPMS_ATTEST t;
   451      if (UnmarshalCertifyInfo(quote_size, quoted, &t)) {
   452        print_quote_certifyinfo(t);
   453      }
   454      printf("\n");
   455    }
   456  #endif
   457  
   458    // Quote key information
   459    // quote_pub_out.publicArea contains quote key info.  Namely,
   460    // TPMI_ALG_PUBLIC   type;
   461    // TPMI_ALG_HASH     nameAlg;
   462    // TPMA_OBJECT       objectAttributes;
   463    // TPM2B_DIGEST      authPolicy;
   464    // TPMU_PUBLIC_PARMS parameters;
   465    //   TPMI_ALG_PUBLIC   type;
   466    //   TPMU_PUBLIC_PARMS parameters;
   467    //     TPMS_RSA_PARMS rsaDetails
   468    //        TPMT_SYM_DEF_OBJECT symmetric;
   469    //        TPMT_RSA_SCHEME     scheme;
   470    //        TPMI_RSA_KEY_BITS   keyBits;
   471    //        uint32_t            exponent;
   472    // TPMU_PUBLIC_ID    unique;
   473    //   TPM2B_PUBLIC_KEY_RSA rsa
   474    //      size
   475    //      buffer
   476    request.set_quoted_blob(quoted, quote_size);
   477    quote_sig.assign((const char*)sig, sig_size);
   478    request.set_quote_signature(quote_sig);
   479    request.mutable_quote_key_info()->mutable_public_key()->set_key_type("RSA");
   480    request.mutable_quote_key_info()->mutable_public_key()->mutable_rsa_key()
   481        ->set_key_name("Quote_key");
   482    request.mutable_quote_key_info()->mutable_public_key()->mutable_rsa_key()
   483        ->set_bit_modulus_size(
   484           quote_pub_out.publicArea.parameters.rsaDetail.keyBits);
   485    expIn = quote_pub_out.publicArea.parameters.rsaDetail.exponent;
   486    expOut = 0ULL;
   487    ChangeEndian64((uint64_t*)&expIn, (uint64_t*)&expOut);
   488    request.mutable_quote_key_info()->mutable_public_key()->mutable_rsa_key()
   489       ->set_exponent((const char*)&expOut, sizeof(uint64_t));
   490    request.mutable_quote_key_info()->mutable_public_key()->mutable_rsa_key()
   491      ->set_modulus((const char*)quote_pub_out.publicArea.unique.rsa.buffer,
   492                    quote_pub_out.publicArea.unique.rsa.size);
   493    request.mutable_quote_key_info()->set_name(
   494        (const char*)quote_pub_name.name, quote_pub_name.size);
   495    request.mutable_quote_key_info()->set_properties(
   496        *(uint32_t*)&quote_pub_out.publicArea.objectAttributes);
   497    if (quote_pub_out.publicArea.nameAlg == TPM_ALG_SHA1) {
   498      request.set_quote_sign_hash_alg("sha1");
   499    } else if (quote_pub_out.publicArea.nameAlg == TPM_ALG_SHA256) {
   500      request.set_quote_sign_hash_alg("sha256");
   501    } else {
   502      printf("Unsupported hash alg\n");
   503      ret_val = 1;
   504      goto done;
   505    }
   506  
   507    output.clear();
   508    if (!request.SerializeToString(&output)) {
   509      printf("Can't serialize string\n");
   510      ret_val = 1;
   511      goto done;
   512    }
   513    if (!WriteFileFromBlock(FLAGS_program_cert_request_file,
   514                            output.size(),
   515                            (byte*)output.data())) {
   516      printf("Can't write endorsement cert\n");
   517      goto done;
   518    }
   519  
   520  #ifdef DEBUG_EXTRA
   521    printf("\nrequest:\n%s\n", request.DebugString().c_str());
   522  #endif
   523  
   524  done:
   525    if (root_handle != 0) {
   526      Tpm2_FlushContext(tpm, root_handle);
   527    }
   528    if (seal_handle != 0) {
   529      Tpm2_FlushContext(tpm, seal_handle);
   530    }
   531    if (quote_handle != 0) {
   532      Tpm2_FlushContext(tpm, quote_handle);
   533    }
   534    if (ekHandle != 0) {
   535      Tpm2_FlushContext(tpm, ekHandle);
   536    }
   537  
   538    tpm.CloseTpm();
   539    return ret_val;
   540  }