/*############################################################################ # 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 Create private key revocation list request * */ #include <argtable3.h> #include <stdlib.h> #include <string.h> #include "epid/common/file_parser.h" #include "epid/member/api.h" #include "util/buffutil.h" #include "util/envutil.h" #include "util/stdtypes.h" const OctStr16 kEpidFileVersion = {2, 0}; // Defaults #define PROGRAM_NAME "revokekey" #define PRIVKEY_DEFAULT "mprivkey.dat" #define REQFILE_DEFAULT "privreq.dat" #define PUBKEYFILE_DEFAULT "pubkey.bin" #define ARGPARSE_ERROR_MAX 20 #define ARGTABLE_SIZE 8 /// Partial signature request, includes all but message. typedef struct PrivRlRequestTop { EpidFileHeader header; ///< Intel(R) EPID File Header PrivKey privkey; ///< Intel(R) EPID Private Key } PrivRlRequestTop; int OpenKey(char const* privkey_file, char const* gpubkey_file, char const* cacert_file, PrivKey* priv_key) { int retval = EXIT_FAILURE; size_t file_size = GetFileSize(privkey_file); if (0 == file_size && !FileExists(privkey_file)) { log_error("cannot access '%s'", privkey_file); return EXIT_FAILURE; } if (file_size == sizeof(PrivKey)) { if (0 != ReadLoud(privkey_file, priv_key, sizeof(PrivKey))) { return EXIT_FAILURE; } retval = EXIT_SUCCESS; } else if (file_size == sizeof(CompressedPrivKey)) { void* signed_pubkey = NULL; if (!cacert_file) { log_error("issuing CA public key must be specified for compressed key"); return EXIT_FAILURE; } if (!gpubkey_file) { log_error("group public key must be specified for compressed key"); return EXIT_FAILURE; } do { size_t signed_pubkey_size = 0; CompressedPrivKey cmp_key; EpidCaCertificate cacert; GroupPubKey pub_key; EpidStatus sts; if (0 != ReadLoud(privkey_file, &cmp_key, sizeof(CompressedPrivKey))) { retval = EXIT_FAILURE; break; } signed_pubkey = NewBufferFromFile(gpubkey_file, &signed_pubkey_size); if (!signed_pubkey) { retval = EXIT_FAILURE; break; } if (0 != ReadLoud(gpubkey_file, signed_pubkey, signed_pubkey_size)) { retval = EXIT_FAILURE; break; } if (0 != ReadLoud(cacert_file, &cacert, sizeof(cacert))) { retval = EXIT_FAILURE; break; } sts = EpidParseGroupPubKeyFile(signed_pubkey, signed_pubkey_size, &cacert, &pub_key); if (kEpidNoErr != sts) { log_error("error while parsing group public key"); retval = EXIT_FAILURE; break; } sts = EpidDecompressPrivKey(&pub_key, &cmp_key, priv_key); if (kEpidNoErr != sts) { log_error("error while decompressing member private key"); retval = EXIT_FAILURE; break; } retval = EXIT_SUCCESS; } while (0); free(signed_pubkey); } else { log_error("unexpected file size for '%s'", privkey_file); retval = EXIT_FAILURE; } return retval; } int MakeRequest(PrivKey const* priv_key, char const* req_file, bool verbose) { // Request buffer uint8_t* req_buf = NULL; size_t req_size = 0; size_t req_extra_space = 0; int ret_value = EXIT_FAILURE; do { size_t entry_size = sizeof(EpidFileHeader) + sizeof(PrivKey); size_t req_file_size = 0; bool duplicate = false; size_t i = 0; PrivRlRequestTop* req_top = NULL; if (!req_file) { log_error("internal error: badarg to MakeRequest()"); ret_value = EXIT_FAILURE; break; } // convert command line args to usable formats // Report Settings if (verbose) { log_msg("=============================================="); log_msg("Input settings:"); log_msg(""); log_msg(" [in] Group ID: "); PrintBuffer(&(priv_key->gid), sizeof(priv_key->gid)); log_msg(""); log_msg(" [in] Private Key Len: %d", sizeof(PrivKey)); log_msg(" [in] Private Key: "); PrintBuffer(priv_key, sizeof(PrivKey)); log_msg(""); log_msg("=============================================="); } req_extra_space += entry_size; if (FileExists(req_file)) { req_file_size = GetFileSize_S(req_file, SIZE_MAX - req_extra_space); if (req_file_size < entry_size) { log_error("output file smaller then size of one entry"); ret_value = EXIT_FAILURE; break; } if (req_file_size % entry_size != 0) { log_error("size of output file is not multiple of the entry size"); ret_value = EXIT_FAILURE; break; } } else { log_msg("request file does not exsist, create new"); } req_size = req_file_size + req_extra_space; req_buf = AllocBuffer(req_size); if (!req_buf) { ret_value = EXIT_FAILURE; break; } // Load existing request file if (req_file_size > 0) { if (0 != ReadLoud(req_file, req_buf, req_file_size)) { ret_value = EXIT_FAILURE; break; } for (i = 0; i < req_file_size / entry_size; i++) { if (0 == memcmp(req_buf + entry_size * i + sizeof(EpidFileHeader), priv_key, sizeof(PrivKey))) { duplicate = true; break; } } if (duplicate) { log_error("this private key already exists in output file"); ret_value = EXIT_FAILURE; break; } } // Append to the request req_top = (PrivRlRequestTop*)(req_buf + req_file_size); req_top->header.epid_version = kEpidFileVersion; req_top->header.file_type = kEpidFileTypeCode[kPrivRlRequestFile]; req_top->privkey = *priv_key; // Report Settings if (verbose) { log_msg("=============================================="); log_msg("Request generated:"); log_msg(""); log_msg(" [in] Request Len: %d", sizeof(PrivRlRequestTop)); log_msg(" [in] Request: "); PrintBuffer(req_top, sizeof(PrivRlRequestTop)); log_msg("=============================================="); } // Store request if (0 != WriteLoud(req_buf, req_size, req_file)) { ret_value = EXIT_FAILURE; break; } ret_value = EXIT_SUCCESS; } while (0); // Free allocated buffers if (req_buf) free(req_buf); return ret_value; } /// Main entrypoint int main(int argc, char* argv[]) { int retval = EXIT_FAILURE; // Verbose flag parameter static bool verbose_flag = false; // Private key PrivKey priv_key; struct arg_file* privkey_file = arg_file0( NULL, "mprivkey", "FILE", "load private key to revoke from FILE (default: " PRIVKEY_DEFAULT ")"); struct arg_file* req_file = arg_file0( NULL, "req", "FILE", "append signature revocation request to FILE (default: " REQFILE_DEFAULT ")"); 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_rem* comment_line = arg_rem( NULL, "The following options are only needed for compressed keys:"); struct arg_file* gpubkey_file = arg_file0( NULL, "gpubkey", "FILE", "load group public key from FILE (default: " PUBKEYFILE_DEFAULT ")"); struct arg_file* capubkey_file = arg_file0( NULL, "capubkey", "FILE", "load IoT Issuing CA public key from FILE"); 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] = privkey_file; argtable[1] = req_file; argtable[2] = help; argtable[3] = verbose; argtable[4] = comment_line; argtable[5] = gpubkey_file; argtable[6] = capubkey_file; argtable[7] = 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); retval = EXIT_FAILURE; break; } /* set any command line default values prior to parsing */ privkey_file->filename[0] = PRIVKEY_DEFAULT; gpubkey_file->filename[0] = PUBKEYFILE_DEFAULT; req_file->filename[0] = REQFILE_DEFAULT; capubkey_file->filename[0] = NULL; /* Parse the command line as defined by argtable[] */ nerrors = arg_parse(argc, argv, argtable); if (help->count > 0) { log_fmt( "Usage: %s [OPTION]...\n" "Revoke Intel(R) EPID signature\n" "\n" "Options:\n", PROGRAM_NAME); arg_print_glossary(stdout, argtable, " %-25s %s\n"); retval = 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); retval = EXIT_FAILURE; break; } if (verbose_flag) { log_msg("\nOption values:"); log_msg(" mprivkey : %s", privkey_file->filename[0]); log_msg(" req : %s", req_file->filename[0]); log_msg(" gpubkey : %s", gpubkey_file->filename[0]); log_msg(" capubkey : %s", capubkey_file->filename[0]); log_msg(""); } retval = OpenKey(privkey_file->filename[0], gpubkey_file->filename[0], capubkey_file->filename[0], &priv_key); if (EXIT_SUCCESS != retval) { break; } retval = MakeRequest(&priv_key, req_file->filename[0], verbose_flag); } while (0); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return retval; }