/*############################################################################ # Copyright 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ############################################################################*/ /*! * \file * * \brief Extract member private keys from key output file * * Not validating SHA hashes in key file */ #include #include #include #include "epid/common/types.h" #include "util/buffutil.h" #include "util/envutil.h" #include "util/stdtypes.h" #include "util/strutil.h" #define PROGRAM_NAME "extractkeys" #define ARGPARSE_ERROR_MAX 20 #define ARGTABLE_SIZE 6 #pragma pack(1) /// Intel(R) EPID Key Output File Entry typedef struct EpidKeyOutputFileKey { unsigned char product_id[2]; ///< 2-byte Product ID (Big Endian) unsigned char key_id[8]; ///< 8-byte Key Unique Id(Big Endian) unsigned char svn[4]; ///< 4-byte Security Version Number (SVN) (Big Endian) PrivKey privkey; ///< Intel(R) EPID 2.0 Private Key unsigned char hash[20]; ///< 20-byte SHA-1 of above } EpidKeyOutputFileKey; /// Intel(R) EPID Compressed Key Output File Entry typedef struct EpidCompressedKeyOutputFileKey { unsigned char product_id[2]; ///< 2-byte Product ID (Big Endian) unsigned char key_id[8]; ///< 8-byte Key Unique Id(Big Endian) unsigned char svn[4]; ///< 4-byte Security Version Number (SVN) (Big Endian) CompressedPrivKey privkey; ///< Intel(R) EPID 2.0 Compressed Private Key unsigned char hash[20]; ///< 20-byte SHA-1 of above } EpidCompressedKeyOutputFileKey; #pragma pack() /// Main entrypoint int main(int argc, char* argv[]) { // intermediate return value for C style functions int ret_value = EXIT_SUCCESS; // Buffer to store read key uint8_t temp[sizeof(EpidKeyOutputFileKey)] = {0}; // Private key to extract void* privkey = 0; size_t privkey_size = 0; size_t keyfile_size = 0; size_t keyfile_entry_size = 0; size_t num_keys_extracted = 0; size_t num_keys_in_file = 0; FILE* file = NULL; // Verbose flag parameter static bool verbose_flag = false; int i = 0; size_t bytes_read = 0; struct arg_file* keyfile = arg_file1(NULL, NULL, "FILE", "FILE containing keys to extract"); struct arg_int* num_keys_to_extract = arg_int1(NULL, NULL, "NUM", "number of keys to extract"); struct arg_lit* compressed = arg_lit0("c", "compressed", "extract compressed keys"); struct arg_lit* help = arg_lit0(NULL, "help", "display this help and exit"); struct arg_lit* verbose = arg_lit0("v", "verbose", "print status messages to stdout"); struct arg_end* end = arg_end(ARGPARSE_ERROR_MAX); void* argtable[ARGTABLE_SIZE]; int nerrors; /* initialize the argtable array with ptrs to the arg_xxx structures * constructed above */ argtable[0] = keyfile; argtable[1] = num_keys_to_extract; argtable[2] = compressed; argtable[3] = help; argtable[4] = verbose; argtable[5] = end; // set program name for logging set_prog_name(PROGRAM_NAME); do { /* verify the argtable[] entries were allocated sucessfully */ if (arg_nullcheck(argtable) != 0) { /* NULL entries were detected, some allocations must have failed */ printf("%s: insufficient memory\n", PROGRAM_NAME); ret_value = EXIT_FAILURE; break; } /* Parse the command line as defined by argtable[] */ nerrors = arg_parse(argc, argv, argtable); if (help->count > 0) { log_fmt( "Usage: %s [OPTION]... [FILE] [NUM]\n" "Extract the first NUM private keys from FILE to current " "directory.\n" "\n" "Options:\n", PROGRAM_NAME); arg_print_glossary(stdout, argtable, " %-25s %s\n"); ret_value = EXIT_SUCCESS; break; } if (verbose->count > 0) { verbose_flag = ToggleVerbosity(); } /* If the parser returned any errors then display them and exit */ if (nerrors > 0) { /* Display the error details contained in the arg_end struct.*/ arg_print_errors(stderr, end, PROGRAM_NAME); fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME); ret_value = EXIT_FAILURE; break; } if (num_keys_to_extract->ival[0] < 0) { log_error("unable extract negative number of keys"); ret_value = EXIT_FAILURE; break; } // check file existence if (!FileExists(keyfile->filename[0])) { log_error("cannot access '%s'", keyfile->filename[0]); ret_value = EXIT_FAILURE; break; } keyfile_size = GetFileSize(keyfile->filename[0]); if (compressed->count > 0) { privkey_size = sizeof(CompressedPrivKey); privkey = &(((EpidCompressedKeyOutputFileKey*)&temp[0])->privkey); keyfile_entry_size = sizeof(EpidCompressedKeyOutputFileKey); } else { privkey_size = sizeof(PrivKey); privkey = &(((EpidKeyOutputFileKey*)&temp[0])->privkey); keyfile_entry_size = sizeof(EpidKeyOutputFileKey); } if (0 != keyfile_size % keyfile_entry_size) { log_error( "input file '%s' is invalid: does not contain integral number of " "keys", keyfile->filename[0]); ret_value = EXIT_FAILURE; break; } num_keys_in_file = keyfile_size / keyfile_entry_size; if ((unsigned int)num_keys_to_extract->ival[0] > num_keys_in_file) { log_error("can not extract %d keys: only %d in file", num_keys_to_extract->ival[0], num_keys_in_file); ret_value = EXIT_FAILURE; break; } file = fopen(keyfile->filename[0], "rb"); if (!file) { log_error("failed read from '%s'", keyfile->filename[0]); ret_value = EXIT_FAILURE; break; } // start extraction for (i = 0; i < num_keys_to_extract->ival[0]; ++i) { int seek_failed = 0; seek_failed = fseek(file, (int)(i * keyfile_entry_size), SEEK_SET); bytes_read = fread(&temp, 1, keyfile_entry_size, file); if (seek_failed || bytes_read != keyfile_entry_size) { log_error("failed to extract key #%lu from '%s'", i, keyfile->filename[0]); } else { char outkeyname[256] = {0}; snprintf(outkeyname, sizeof(outkeyname), "mprivkey%010u.dat", i); if (FileExists(outkeyname)) { log_error("file '%s' already exists", outkeyname); ret_value = EXIT_FAILURE; break; } if (0 != WriteLoud(privkey, privkey_size, outkeyname)) { log_error("failed to write key #%lu from '%s'", i, keyfile->filename[0]); } else { num_keys_extracted++; } } } if (EXIT_FAILURE == ret_value) { break; } log_msg("extracted %lu of %lu keys", num_keys_extracted, num_keys_in_file); } while (0); if (file) { fclose(file); file = NULL; } arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return ret_value; }