| /*############################################################################ |
| # 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 Signmsg example implementation. |
| */ |
| |
| #include <argtable3.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "src/signmsg.h" |
| #include "util/buffutil.h" |
| #include "util/convutil.h" |
| #include "util/envutil.h" |
| |
| // Defaults |
| #define PROGRAM_NAME "signmsg" |
| #define MPRIVKEYFILE_DEFAULT "mprivkey.dat" |
| #define PUBKEYFILE_DEFAULT "pubkey.bin" |
| #define SIG_DEFAULT "sig.dat" |
| #define CACERT_DEFAULT "cacert.bin" |
| #define HASHALG_DEFAULT "SHA-512" |
| #define ARGPARSE_ERROR_MAX 20 |
| #define ARGTABLE_SIZE 14 |
| |
| bool IsCaCertAuthorizedByRootCa(void const* data, size_t size) { |
| // Implementation of this function is out of scope of the sample. |
| // In an actual implementation Issuing CA certificate must be validated |
| // with CA Root certificate before using it in parse functions. |
| (void)data; |
| (void)size; |
| return true; |
| } |
| |
| /// Main entrypoint |
| int main(int argc, char* argv[]) { |
| // intermediate return value for C style functions |
| int ret_value = EXIT_SUCCESS; |
| |
| // intermediate return value for Intel(R) EPID functions |
| EpidStatus result = kEpidErr; |
| |
| // User Settings |
| |
| // Message string parameter |
| static char* msg_str = NULL; |
| size_t msg_size = 0; |
| char* msg_buf = NULL; // message loaded from msg_file |
| |
| // Basename string parameter |
| static char* basename_str = NULL; |
| size_t basename_size = 0; |
| char* basename_buf = NULL; // basename loaded from basename_file |
| |
| // Verbose flag parameter |
| static bool verbose_flag = false; |
| |
| // Buffers and computed values |
| |
| // Signature buffer |
| EpidSignature* sig = NULL; |
| size_t sig_size = 0; |
| |
| // SigRl file |
| unsigned char* signed_sig_rl = NULL; |
| size_t signed_sig_rl_size = 0; |
| |
| // Group public key file |
| unsigned char* signed_pubkey = NULL; |
| size_t signed_pubkey_size = 0; |
| |
| // CA certificate |
| EpidCaCertificate cacert = {0}; |
| |
| // Member private key buffer |
| unsigned char* mprivkey = NULL; |
| size_t mprivkey_size = 0; |
| |
| // Member pre-computed settings |
| MemberPrecomp member_precmp = {0}; |
| MemberPrecomp* member_precmp_ptr = NULL; |
| |
| // Hash algorithm |
| static HashAlg hashalg = kInvalidHashAlg; |
| |
| // Argument variables |
| struct arg_file* sig_file = |
| arg_file0(NULL, "sig", "FILE", |
| "write signature to FILE (default: " SIG_DEFAULT ")"); |
| struct arg_str* msg = arg_str0(NULL, "msg", "MESSAGE", "MESSAGE to sign"); |
| struct arg_file* msg_file = |
| arg_file0(NULL, "msgfile", "FILE", "FILE containing message to sign"); |
| struct arg_str* basename = arg_str0( |
| NULL, "bsn", "BASENAME", "BASENAME to sign with (default: random)"); |
| struct arg_file* basename_file = arg_file0( |
| NULL, "bsnfile", "FILE", "FILE containing basename to sign with"); |
| struct arg_file* sigrl_file = arg_file0( |
| NULL, "sigrl", "FILE", "load signature based revocation list from FILE"); |
| struct arg_file* pubkey_file = arg_file0( |
| NULL, "gpubkey", "FILE", |
| "load group public key from FILE (default: " PUBKEYFILE_DEFAULT ")"); |
| struct arg_file* mprivkey_file = arg_file0( |
| NULL, "mprivkey", "FILE", |
| "load member private key from FILE (default: " MPRIVKEYFILE_DEFAULT ")"); |
| struct arg_file* mprecmpi_file = arg_file0( |
| NULL, "mprecmpi", "FILE", "load pre-computed member data from FILE"); |
| struct arg_file* cacert_file = arg_file0( |
| NULL, "capubkey", "FILE", |
| "load IoT Issuing CA public key from FILE (default: " CACERT_DEFAULT ")"); |
| struct arg_str* hashalg_str = |
| arg_str0(NULL, "hashalg", "{SHA-256 | SHA-384 | SHA-512 | SHA-512/256}", |
| "use specified hash algorithm (default: " HASHALG_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_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] = sig_file; |
| argtable[1] = msg; |
| argtable[2] = msg_file; |
| argtable[3] = basename; |
| argtable[4] = basename_file; |
| argtable[5] = sigrl_file; |
| argtable[6] = pubkey_file; |
| argtable[7] = mprivkey_file; |
| argtable[8] = mprecmpi_file; |
| argtable[9] = cacert_file; |
| argtable[10] = hashalg_str; |
| argtable[11] = help; |
| argtable[12] = verbose; |
| argtable[13] = 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; |
| } |
| |
| /* set any command line default values prior to parsing */ |
| sig_file->filename[0] = SIG_DEFAULT; |
| pubkey_file->filename[0] = PUBKEYFILE_DEFAULT; |
| mprivkey_file->filename[0] = MPRIVKEYFILE_DEFAULT; |
| cacert_file->filename[0] = CACERT_DEFAULT; |
| hashalg_str->sval[0] = HASHALG_DEFAULT; |
| |
| /* Parse the command line as defined by argtable[] */ |
| nerrors = arg_parse(argc, argv, argtable); |
| |
| if (help->count > 0) { |
| log_fmt( |
| "Usage: %s [OPTION]...\n" |
| "Create Intel(R) EPID signature of message\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 (msg->count > 0 && msg_file->count > 0) { |
| log_error("options --msg and --msgfile cannot be used together"); |
| ret_value = EXIT_FAILURE; |
| break; |
| } else if (msg->count > 0) { |
| msg_str = (char*)msg->sval[0]; |
| msg_size = strlen(msg_str); |
| } else if (msg_file->count > 0) { |
| msg_buf = NewBufferFromFile(msg_file->filename[0], &msg_size); |
| if (!msg_buf) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| msg_str = msg_buf; |
| } else { |
| msg_size = 0; |
| } |
| |
| if (basename->count > 0 && basename_file->count > 0) { |
| log_error("options --bsn and --bsnfile cannot be used together"); |
| ret_value = EXIT_FAILURE; |
| break; |
| } else if (basename->count > 0) { |
| basename_str = (char*)basename->sval[0]; |
| basename_size = strlen(basename_str); |
| } else if (basename_file->count > 0) { |
| basename_buf = |
| NewBufferFromFile(basename_file->filename[0], &basename_size); |
| if (!basename_buf) { |
| log_error("Failed in reading basename from %s", basename_file); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| basename_str = basename_buf; |
| } else { |
| basename_size = 0; |
| } |
| |
| if (!StringToHashAlg(hashalg_str->sval[0], &hashalg)) { |
| log_error("invalid hashalg: %s", hashalg_str->sval[0]); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| |
| if (verbose_flag) { |
| log_msg("\nOption values:"); |
| log_msg(" sig_file : %s", sig_file->filename[0]); |
| log_msg(" msg_str : %s", msg_str); |
| log_msg(" basename_str : %s", basename_str); |
| log_msg(" pubkey_file : %s", pubkey_file->filename[0]); |
| log_msg(" mprivkey_file : %s", mprivkey_file->filename[0]); |
| log_msg(" mprecmpi_file : %s", mprecmpi_file->filename[0]); |
| log_msg(" hashalg : %s", HashAlgToString(hashalg)); |
| log_msg(" cacert_file : %s", cacert_file->filename[0]); |
| log_msg(""); |
| } |
| // convert command line args to usable formats |
| |
| // CA certificate |
| if (0 != ReadLoud(cacert_file->filename[0], &cacert, sizeof(cacert))) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| // Security note: |
| // Application must confirm that IoT Intel(R) EPID Issuing CA certificate |
| // is authorized by IoT Intel(R) EPID Root CA, e.g., |
| // signed by IoT Intel(R) EPID Root CA. |
| if (!IsCaCertAuthorizedByRootCa(&cacert, sizeof(cacert))) { |
| log_error("CA certificate is not authorized"); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| // SigRl |
| if (sigrl_file->count > 0) { |
| if (FileExists(sigrl_file->filename[0])) { |
| signed_sig_rl = |
| NewBufferFromFile(sigrl_file->filename[0], &signed_sig_rl_size); |
| if (!signed_sig_rl) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| |
| if (0 != ReadLoud(sigrl_file->filename[0], signed_sig_rl, |
| signed_sig_rl_size)) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| } else { |
| log_error("SigRL file %s does not exist", sigrl_file->filename[0]); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| } |
| // Group public key file |
| signed_pubkey = |
| NewBufferFromFile(pubkey_file->filename[0], &signed_pubkey_size); |
| if (!signed_pubkey) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| if (0 != |
| ReadLoud(pubkey_file->filename[0], signed_pubkey, signed_pubkey_size)) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| // Member private key |
| mprivkey = NewBufferFromFile(mprivkey_file->filename[0], &mprivkey_size); |
| if (!mprivkey) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| if (mprivkey_size != sizeof(PrivKey) && |
| mprivkey_size != sizeof(CompressedPrivKey) && |
| mprivkey_size != sizeof(MembershipCredential)) { |
| log_error("Private Key file size is inconsistent"); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| if (0 != ReadLoud(mprivkey_file->filename[0], mprivkey, mprivkey_size)) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| // Load Member pre-computed settings |
| if (mprecmpi_file->count > 0) { |
| if (sizeof(MemberPrecomp) != GetFileSize(mprecmpi_file->filename[0])) { |
| log_error("incorrect input precomp size"); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| |
| if (0 != ReadLoud(mprecmpi_file->filename[0], &member_precmp, |
| sizeof(MemberPrecomp))) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| member_precmp_ptr = &member_precmp; |
| } |
| |
| // Report Settings |
| if (verbose_flag) { |
| log_msg("=============================================="); |
| log_msg("Signing Message:"); |
| log_msg(""); |
| log_msg(" [in] Message Len: %d", (int)msg_size); |
| log_msg(" [in] Message: "); |
| PrintBuffer(msg_str, msg_size); |
| log_msg(""); |
| log_msg(" [in] BaseName Len: %d", (int)basename_size); |
| log_msg(" [in] BaseName: "); |
| PrintBuffer(basename_str, basename_size); |
| log_msg(""); |
| log_msg(" [in] SigRl Len: %d", (int)signed_sig_rl_size); |
| log_msg(" [in] SigRl: "); |
| PrintBuffer(signed_sig_rl, signed_sig_rl_size); |
| log_msg(""); |
| log_msg(" [in] Group Public Key: "); |
| PrintBuffer(signed_pubkey, signed_pubkey_size); |
| log_msg(""); |
| log_msg(" [in] Member Private Key: "); |
| PrintBuffer(mprivkey, mprivkey_size); |
| log_msg(""); |
| log_msg(" [in] Hash Algorithm: %s", HashAlgToString(hashalg)); |
| log_msg(""); |
| log_msg(" [in] IoT Intel(R) EPID Issuing CA Certificate: "); |
| PrintBuffer(&cacert, sizeof(cacert)); |
| if (member_precmp_ptr) { |
| log_msg(""); |
| log_msg(" [in] Member PreComp: "); |
| PrintBuffer(member_precmp_ptr, sizeof(member_precmp)); |
| } |
| log_msg("=============================================="); |
| } |
| |
| // Sign |
| result = SignMsg(msg_str, msg_size, basename_str, basename_size, |
| signed_sig_rl, signed_sig_rl_size, signed_pubkey, |
| signed_pubkey_size, mprivkey, mprivkey_size, hashalg, |
| member_precmp_ptr, &sig, &sig_size, &cacert); |
| |
| // Report Result |
| if (kEpidNoErr != result) { |
| if (kEpidSigRevokedInSigRl == result) { |
| log_error("signature revoked in SigRL"); |
| } else { |
| log_error("function SignMsg returned %s", EpidStatusToString(result)); |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| } |
| |
| if (sig && sig_size != 0) { |
| // Store signature |
| if (0 != WriteLoud(sig, sig_size, sig_file->filename[0])) { |
| ret_value = EXIT_FAILURE; |
| break; |
| } |
| } |
| |
| // Success |
| ret_value = EXIT_SUCCESS; |
| } while (0); |
| |
| // Free allocated buffers |
| if (sig) free(sig); |
| if (msg_buf) free(msg_buf); |
| if (basename_buf) free(basename_buf); |
| if (signed_sig_rl) free(signed_sig_rl); |
| if (signed_pubkey) free(signed_pubkey); |
| if (mprivkey) free(mprivkey); |
| |
| arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); |
| |
| return ret_value; |
| } |