| /*############################################################################ |
| # 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 group keys from group key output file |
| */ |
| |
| #include <argtable3.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "epid/common/file_parser.h" |
| #include "epid/common/types.h" |
| #include "util/buffutil.h" |
| #include "util/envutil.h" |
| #include "util/stdtypes.h" |
| #include "util/strutil.h" |
| |
| #define PROGRAM_NAME "extractgrps" |
| #define ARGPARSE_ERROR_MAX 20 |
| #define ARGTABLE_SIZE 5 |
| |
| #pragma pack(1) |
| /// Intel(R) EPID Key Output File Entry |
| typedef struct EpidBinaryGroupCertificate { |
| EpidFileHeader header; ///< Intel(R) EPID binary file header |
| GroupPubKey pubkey; ///< Intel(R) EPID 2.0 group public key |
| EcdsaSignature signature; ///< ECDSA Signature on SHA-256 of above values |
| } EpidBinaryGroupCertificate; |
| #pragma pack() |
| |
| /// Main entrypoint |
| int main(int argc, char* argv[]) { |
| // intermediate return value for C style functions |
| int ret_value = EXIT_SUCCESS; |
| |
| size_t keyfile_size = 0; |
| size_t num_keys_extracted = 0; |
| size_t num_keys_in_file = 0; |
| |
| FILE* file = NULL; |
| |
| int i = 0; |
| size_t bytes_read = 0; |
| |
| // Verbose flag parameter |
| static bool verbose_flag = false; |
| |
| 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* 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] = help; |
| argtable[3] = verbose; |
| argtable[4] = 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 group certs 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 (0 != keyfile_size % sizeof(EpidBinaryGroupCertificate)) { |
| log_error( |
| "input file '%s' is invalid: does not contain integral number of " |
| "group keys", |
| keyfile->filename[0]); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| num_keys_in_file = keyfile_size / sizeof(EpidBinaryGroupCertificate); |
| |
| 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++) { |
| EpidBinaryGroupCertificate temp; |
| int seek_failed = 0; |
| seek_failed = fseek(file, i * sizeof(temp), SEEK_SET); |
| bytes_read = fread(&temp, 1, sizeof(temp), file); |
| if (seek_failed || bytes_read != sizeof(temp)) { |
| log_error("failed to extract key #%lu from '%s'", i, |
| keyfile->filename[0]); |
| } else { |
| // ulong max = 4294967295 |
| char outkeyname[256] = {0}; |
| if (memcmp(&kEpidVersionCode[kEpid2x], &temp.header.epid_version, |
| sizeof(temp.header.epid_version)) || |
| memcmp(&kEpidFileTypeCode[kGroupPubKeyFile], &temp.header.file_type, |
| sizeof(temp.header.file_type))) { |
| log_error("failed to extract key #%lu from '%s': file is invalid", i, |
| keyfile->filename[0]); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| snprintf(outkeyname, sizeof(outkeyname), "pubkey%010u.bin", i); |
| if (FileExists(outkeyname)) { |
| log_error("file '%s' already exists", outkeyname); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| if (0 != WriteLoud(&temp, sizeof(temp), 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; |
| } |