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 "e_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