diff options
Diffstat (limited to 'tools/revokesig/src/main.c')
-rw-r--r-- | tools/revokesig/src/main.c | 455 |
1 files changed, 455 insertions, 0 deletions
diff --git a/tools/revokesig/src/main.c b/tools/revokesig/src/main.c new file mode 100644 index 0000000..861e389 --- /dev/null +++ b/tools/revokesig/src/main.c @@ -0,0 +1,455 @@ +/*############################################################################ + # Copyright 2016 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 signature based revocation list request + * + */ + +#include <stdlib.h> +#include <string.h> +#include <dropt.h> +#include "util/buffutil.h" +#include "util/envutil.h" +#include "util/stdtypes.h" +#include "epid/common/file_parser.h" + +// Defaults +#define PROGRAM_NAME "revokesig" +#define PUBKEYFILE_DEFAULT "pubkey.bin" +#define REQFILE_DEFAULT "sigrlreq.dat" +#define SIG_DEFAULT "sig.dat" +#define GROUP_PUB_KEY_SIZE \ + (sizeof(EpidFileHeader) + sizeof(GroupPubKey) + sizeof(EcdsaSignature)) + +#pragma pack(1) +/// Partial signature request, includes components through sig. +typedef struct SigRlRequestTop { + EpidFileHeader header; ///< EPID File Header + GroupId gid; ///< EPID Group ID + EpidSignature sig; ///< EPID Signature +} SigRlRequestTop; + +/// Partial signature request, includes components after. +typedef struct SigRlRequestMid { + uint32_t be_msg_size; ///< size of message in bytes (big endian) + uint8_t msg[1]; ///< message used to create signature (flexible array) +} SigRlRequestMid; +#pragma pack() + +/// convert host to network byte order +static uint32_t htonl(uint32_t hostlong) { + return (((hostlong & 0xFF) << 24) | ((hostlong & 0xFF00) << 8) | + ((hostlong & 0xFF0000) >> 8) | ((hostlong & 0xFF000000) >> 24)); +} + +/// Fill a single SigRlRequest structure +/*! +\param[in] pubkey +Group public key. +\param[in] sig +Signature to append to request. +\param[in] sig_size +Size of the signature. +\param[in] msg_str +Message used to generate signature to revoke. +\param[in] msg_size +Length of the message. +\param[in out] req_buf +Pointer to request buffer. +\param[in] req_size +Size of request buffer. +\param[in out] req_top +Pointer to top structure of request. +*/ +void FillRequest(GroupPubKey const* pubkey, EpidSignature const* sig, + size_t sig_size, char const* msg_str, size_t msg_size, + uint8_t* req_buf, size_t req_size, SigRlRequestTop* req_top); + +/// Makes a request and appends it to file. +/*! +\param[in] cacert_file +Issuing CA certificate used to sign group public key file. +\param[in] sig_file +File containing signature to add to request. +\param[in] pubkey_file +File containing group public key. +\param[in] req_file +File to write a request. +\param[in] msg_str +Message used to generate signature to revoke. +\param[in] msg_size +Length of the message. +\param[in] verbose +If true function would print debug information to stdout. +*/ +int MakeRequest(char const* cacert_file, char const* sig_file, + char const* pubkey_file, char const* req_file, + char const* msg_str, size_t msg_size, bool verbose); + +/// Main entrypoint +int main(int argc, char* argv[]) { + // intermediate return value for C style functions + int ret_value = EXIT_FAILURE; + + // Signature file name parameter + static char* sig_file = NULL; + + // Message string parameter + static char* msg_str = NULL; + size_t msg_size = 0; + static char* msg_file = NULL; + char* msg_buf = NULL; // message loaded from msg_file + + // Signature revocation request file name parameter + static char* req_file = NULL; + + // Group public key file name parameter + static char* pubkey_file = NULL; + + // CA certificate file name parameter + static char* cacert_file = NULL; + + // help flag parameter + static bool show_help = false; + + // Verbose flag parameter + static bool verbose = false; + + dropt_option options[] = { + {'\0', "sig", + "load signature to revoke from FILE (default: " SIG_DEFAULT ")", "FILE", + dropt_handle_string, &sig_file}, + {'\0', "msg", "MESSAGE used to generate signature to revoke", "MESSAGE", + dropt_handle_string, &msg_str}, + {'\0', "msgfile", + "FILE containing message used to generate signature to revoke", "FILE", + dropt_handle_string, &msg_file}, + {'\0', "gpubkey", + "load group public key from FILE (default: " PUBKEYFILE_DEFAULT ")", + "FILE", dropt_handle_string, &pubkey_file}, + {'\0', "capubkey", "load IoT Issuing CA public key from FILE", "FILE", + dropt_handle_string, &cacert_file}, + {'\0', "req", + "append signature revocation request to FILE (default: " REQFILE_DEFAULT + ")", + "FILE", dropt_handle_string, &req_file}, + + {'h', "help", "display this help and exit", NULL, dropt_handle_bool, + &show_help, dropt_attr_halt}, + {'v', "verbose", "print status messages to stdout", NULL, + dropt_handle_bool, &verbose}, + + {0} /* Required sentinel value. */ + }; + + dropt_context* dropt_ctx = NULL; + // set program name for logging + set_prog_name(PROGRAM_NAME); + do { + dropt_ctx = dropt_new_context(options); + if (!dropt_ctx) { + ret_value = EXIT_FAILURE; + break; + } else if (argc > 0) { + /* Parse the arguments from argv. + * + * argv[1] is always safe to access since argv[argc] is guaranteed + * to be NULL and since we've established that argc > 0. + */ + char** rest = dropt_parse(dropt_ctx, -1, &argv[1]); + if (dropt_get_error(dropt_ctx) != dropt_error_none) { + log_error(dropt_get_error_message(dropt_ctx)); + if (dropt_error_invalid_option == dropt_get_error(dropt_ctx)) { + fprintf(stderr, "Try '%s --help' for more information.\n", + PROGRAM_NAME); + } + ret_value = EXIT_FAILURE; + break; + } else if (show_help) { + log_fmt( + "Usage: %s [OPTION]...\n" + "Revoke Intel(R) EPID signature\n" + "\n" + "Options:\n", + PROGRAM_NAME); + dropt_print_help(stdout, dropt_ctx, NULL); + ret_value = EXIT_SUCCESS; + break; + } else if (*rest) { + // we have unparsed (positional) arguments + log_error("invalid argument: %s", *rest); + fprintf(stderr, "Try '%s --help' for more information.\n", + PROGRAM_NAME); + ret_value = EXIT_FAILURE; + break; + } else { + if (verbose) { + verbose = ToggleVerbosity(); + } + if (!sig_file) { + sig_file = SIG_DEFAULT; + } + + if (msg_str && msg_file) { + log_error("--msg and --msgfile cannot be used together"); + ret_value = EXIT_FAILURE; + break; + } else if (msg_str) { + msg_size = strlen(msg_str); + } else if (msg_file) { + msg_buf = NewBufferFromFile(msg_file, &msg_size); + if (!msg_buf) { + ret_value = EXIT_FAILURE; + break; + } + msg_str = msg_buf; + } else { + msg_size = 0; + } + + if (!pubkey_file) { + pubkey_file = PUBKEYFILE_DEFAULT; + } + if (!cacert_file) { + log_error("issuing CA public key must be specified"); + ret_value = EXIT_FAILURE; + break; + } + if (!req_file) { + req_file = REQFILE_DEFAULT; + } + if (verbose) { + log_msg("\nOption values:"); + log_msg(" sig_file : %s", sig_file); + log_msg(" msg_str : %s", msg_str); + log_msg(" pubkey_file : %s", pubkey_file); + log_msg(" cacert_file : %s", cacert_file); + log_msg(" req_file : %s", req_file); + log_msg(""); + } + } + } + + ret_value = MakeRequest(cacert_file, sig_file, pubkey_file, req_file, + msg_str, msg_size, verbose); + } while (0); + + if (msg_buf) { + free(msg_buf); + msg_buf = NULL; + } + + dropt_free_context(dropt_ctx); + + return ret_value; +} + +/// Fill a single SigRlRequest structure +/*! + + | Field | Size | + |:--------------------------------|--------------:| + | EPID Version (0x0200) | 2 bytes | + | File Type (0x000B) | 2 bytes | + | Group ID Number | 16 bytes | + | Basic Signature | 52 bytes | + | SigRL Version | 4 bytes | + | Number of Non-Revoked Proofs | 4 bytes | + | nNRP * Non-Revoked Proofs | 160 * nNRP | + | Message Size in Bytes (msgSize) | 4 bytes | + | Message | msgSize bytes | + + */ +void FillRequest(GroupPubKey const* pubkey, EpidSignature const* sig, + size_t sig_size, char const* msg_str, size_t msg_size, + uint8_t* req_buf, size_t req_size, SigRlRequestTop* req_top) { + const OctStr16 kEpidFileVersion = {2, 0}; + size_t i = 0; + size_t req_mid_size = sizeof(((SigRlRequestMid*)0)->be_msg_size) + msg_size; + SigRlRequestMid* req_mid = + (SigRlRequestMid*)(req_buf + req_size - req_mid_size); + + if (!pubkey || !sig || !req_buf || !req_top || (!msg_str && 0 != msg_size)) { + log_error("internal error: badarg to FillRequest()"); + return; + } + + req_top->header.epid_version = kEpidFileVersion; + req_top->header.file_type = kEpidFileTypeCode[kSigRlRequestFile]; + req_top->gid = pubkey->gid; + // copy signature + for (i = 0; i < sig_size; i++) { + ((uint8_t*)&req_top->sig)[i] = ((uint8_t*)sig)[i]; + } + req_mid->be_msg_size = htonl((uint32_t)msg_size); + // copy msg + for (i = 0; i < msg_size; i++) { + req_mid->msg[i] = msg_str[i]; + } +} + +int MakeRequest(char const* cacert_file, char const* sig_file, + char const* pubkey_file, char const* req_file, + char const* msg_str, size_t msg_size, bool verbose) { + // Buffers and computed values + // Signature buffer + EpidSignature* sig = NULL; + size_t sig_size = 0; + + // Group public key file + unsigned char* pubkey_file_data = NULL; + size_t pubkey_file_size = 0; + + // CA certificate + EpidCaCertificate cacert = {0}; + + // Group public key buffer + GroupPubKey pubkey = {0}; + + // Request buffer + uint8_t* req_buf = NULL; + size_t req_size = 0; + + size_t req_extra_space = (sizeof(EpidFileHeader) + sizeof(GroupId)); + + int ret_value = EXIT_FAILURE; + do { + SigRlRequestTop* req_top = NULL; + size_t req_file_size = 0; + const size_t kMsgSizeSize = sizeof(((SigRlRequestMid*)0)->be_msg_size); + + if (!cacert_file || !sig_file || !pubkey_file || !req_file || + (!msg_str && 0 != msg_size)) { + log_error("internal error: badarg to MakeRequest()"); + ret_value = EXIT_FAILURE; + break; + } + + // convert command line args to usable formats + // CA certificate + if (0 != ReadLoud(cacert_file, &cacert, sizeof(cacert))) { + ret_value = EXIT_FAILURE; + break; + } + + // Signature + sig = NewBufferFromFile(sig_file, &sig_size); + if (!sig) { + ret_value = EXIT_FAILURE; + break; + } + + // Group public key file + pubkey_file_data = NewBufferFromFile(pubkey_file, &pubkey_file_size); + if (!pubkey_file_data) { + ret_value = EXIT_FAILURE; + break; + } + + // Security note: + // Application must confirm group public key is + // authorized by the issuer, e.g., signed by the issuer. + if (GROUP_PUB_KEY_SIZE != pubkey_file_size) { + log_error("unexpected file size for '%s'. Expected: %d; got: %d", + pubkey_file, (int)GROUP_PUB_KEY_SIZE, (int)pubkey_file_size); + ret_value = EXIT_FAILURE; + break; + } + if (kEpidNoErr != EpidParseGroupPubKeyFile(pubkey_file_data, + pubkey_file_size, &cacert, + &pubkey)) { + log_error("group public key is not authorized"); + ret_value = EXIT_FAILURE; + break; + } + + // Report Settings + if (verbose) { + log_msg("=============================================="); + log_msg("Creating SigRL revocation request:"); + log_msg(""); + log_msg(" [in] Group ID: "); + PrintBuffer(&pubkey.gid, sizeof(pubkey.gid)); + log_msg(""); + log_msg(" [in] Signature Len: %d", (int)sig_size); + log_msg(" [in] Signature: "); + PrintBuffer(&sig, sig_size); + log_msg(""); + log_msg(" [in] Message Len: %d", (int)msg_size); + log_msg(" [in] Message: "); + PrintBuffer(msg_str, msg_size); + log_msg("=============================================="); + } + + req_extra_space += sig_size + kMsgSizeSize + msg_size; + + if (FileExists(req_file)) { + req_file_size = GetFileSize_S(req_file, SIZE_MAX - req_extra_space); + } 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; + } + + if (req_file_size > 0) { + if (0 != ReadLoud(req_file, req_buf, req_file_size)) { + ret_value = EXIT_FAILURE; + break; + } + } + + req_top = (SigRlRequestTop*)(req_buf + req_file_size); + + FillRequest(&pubkey, sig, sig_size, msg_str, msg_size, req_buf, req_size, + req_top); + + // Report Settings + if (verbose) { + log_msg("=============================================="); + log_msg("Reqest generated:"); + log_msg(""); + log_msg(" [in] Request Len: %d", sizeof(SigRlRequestTop)); + log_msg(" [in] Request: "); + PrintBuffer(&req_top, sizeof(SigRlRequestTop)); + log_msg("=============================================="); + } + + // Store request + if (0 != WriteLoud(req_buf, req_size, req_file)) { + ret_value = EXIT_FAILURE; + break; + } + + // Success + ret_value = EXIT_SUCCESS; + } while (0); + + // Free allocated buffers + if (pubkey_file_data) free(pubkey_file_data); + if (sig) free(sig); + if (req_buf) free(req_buf); + + return ret_value; +} |