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 "e_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, "e_pub_blob_size, 386 quote_pub_blob, "e_pub_out, "e_pub_name, 387 "e_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, "e_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*)"e_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 }