blob: 21e928a3cc2c66a0fb73d45448c793b5b90579f6 [file] [log] [blame]
/*############################################################################
# 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 <stdio.h>
#include <stdlib.h>
#include <argtable3.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 "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;
}