/*############################################################################ # 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 Verifysig example implementation. */ #include #include #include #include "epid/common/file_parser.h" #include "epid/verifier/1.1/api.h" #include "epid/verifier/api.h" #include "src/verifysig.h" #include "src/verifysig11.h" #include "util/buffutil.h" #include "util/convutil.h" #include "util/envutil.h" // Defaults #define PROGRAM_NAME "verifysig" #define PUBKEYFILE_DEFAULT "pubkey.bin" #define PRIVRL_DEFAULT NULL #define SIGRL_DEFAULT NULL #define GRPRL_DEFAULT "grprl.bin" #define VERIFIERRL_DEFAULT NULL #define SIG_DEFAULT "sig.dat" #define CACERT_DEFAULT "cacert.bin" #define HASHALG_DEFAULT "SHA-512" #define VPRECMPI_DEFAULT NULL #define VPRECMPO_DEFAULT NULL #define ARGPARSE_ERROR_MAX 20 #define ARGTABLE_SIZE 17 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 void* sig = NULL; size_t sig_size = 0; // PrivRl buffer void* signed_priv_rl = NULL; size_t signed_priv_rl_size = 0; // SigRl buffer void* signed_sig_rl = NULL; size_t signed_sig_rl_size = 0; // GrpRl buffer void* signed_grp_rl = NULL; size_t signed_grp_rl_size = 0; // VerRl buffer VerifierRl* ver_rl = NULL; size_t ver_rl_size = 0; // Group public key buffer void* signed_pubkey = NULL; size_t signed_pubkey_size = 0; // Verifier pre-computed settings void* verifier_precmp = NULL; size_t vprecmpi_file_size = 0; // CA certificate EpidCaCertificate cacert = {0}; // Hash algorithm static HashAlg hashalg = kInvalidHashAlg; // Argument variables struct arg_file* sig_file = arg_file0(NULL, "sig", "FILE", "load signature from FILE (default: " SIG_DEFAULT ")"); struct arg_str* msg = arg_str0(NULL, "msg", "MESSAGE", "MESSAGE that was signed (default: empty)"); struct arg_file* msg_file = arg_file0( NULL, "msgfile", "FILE", "FILE containing message that was signed"); struct arg_str* basename = arg_str0( NULL, "bsn", "BASENAME", "BASENAME used in signature (default: random)"); struct arg_file* basename_file = arg_file0( NULL, "bsnfile", "FILE", "FILE containing basename used in signature"); struct arg_file* privrl_file = arg_file0( NULL, "privrl", "FILE", "load private key revocation list from FILE"); struct arg_file* sigrl_file = arg_file0( NULL, "sigrl", "FILE", "load signature based revocation list from FILE"); struct arg_file* grprl_file = arg_file0( NULL, "grprl", "FILE", "load group revocation list from FILE (default: " GRPRL_DEFAULT ")"); struct arg_file* verrl_file = arg_file0( NULL, "verifierrl", "FILE", "load verifier 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* vprecmpi_file = arg_file0( NULL, "vprecmpi", "FILE", "load pre-computed verifier data from FILE"); struct arg_file* vprecmpo_file = arg_file0( NULL, "vprecmpo", "FILE", "write pre-computed verifier data to 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 for 2.0 groups (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] = privrl_file; argtable[6] = sigrl_file; argtable[7] = grprl_file; argtable[8] = verrl_file; argtable[9] = pubkey_file; argtable[10] = vprecmpi_file; argtable[11] = vprecmpo_file; argtable[12] = cacert_file; argtable[13] = hashalg_str; argtable[14] = help; argtable[15] = verbose; argtable[16] = end; // set program name for logging set_prog_name(PROGRAM_NAME); do { EpidVersion epid_version = kNumEpidVersions; // Read command line args /* 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; grprl_file->filename[0] = GRPRL_DEFAULT; pubkey_file->filename[0] = PUBKEYFILE_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" "Verify signature was created by group member in good standing\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(" privrl_file : %s", privrl_file->filename[0]); log_msg(" sigrl_file : %s", sigrl_file->filename[0]); log_msg(" grprl_file : %s", grprl_file->filename[0]); log_msg(" verrl_file : %s", verrl_file->filename[0]); log_msg(" vprecmpi_file : %s", vprecmpi_file->filename[0]); log_msg(" vprecmpo_file : %s", vprecmpo_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 // Signature sig = NewBufferFromFile(sig_file->filename[0], &sig_size); if (!sig) { ret_value = EXIT_FAILURE; break; } // PrivRl if (privrl_file->count > 0) { signed_priv_rl = NewBufferFromFile(privrl_file->filename[0], &signed_priv_rl_size); if (!signed_priv_rl) { ret_value = EXIT_FAILURE; break; } } // SigRl if (sigrl_file->count > 0) { signed_sig_rl = NewBufferFromFile(sigrl_file->filename[0], &signed_sig_rl_size); if (!signed_sig_rl) { ret_value = EXIT_FAILURE; break; } } // GrpRl signed_grp_rl = NewBufferFromFile(grprl_file->filename[0], &signed_grp_rl_size); if (!signed_grp_rl) { ret_value = EXIT_FAILURE; break; } // VerRl if (verrl_file->count > 0) { ver_rl = (VerifierRl*)NewBufferFromFile(verrl_file->filename[0], &ver_rl_size); if (!ver_rl) { ret_value = EXIT_FAILURE; break; } } // Group public key signed_pubkey = NewBufferFromFile(pubkey_file->filename[0], &signed_pubkey_size); if (!signed_pubkey) { ret_value = EXIT_FAILURE; break; } // CA certificate if (0 != ReadLoud(cacert_file->filename[0], &cacert, sizeof(cacert))) { ret_value = EXIT_FAILURE; break; } // Security note: // Application must confirm that IoT Issuing CA // certificate is authorized by IoT Root CA, // e.g., signed by IoT Root CA. if (!IsCaCertAuthorizedByRootCa(&cacert, sizeof(cacert))) { log_error("CA certificate is not authorized"); ret_value = EXIT_FAILURE; break; } // Detect Intel(R) EPID version result = EpidParseFileHeader(signed_pubkey, signed_pubkey_size, &epid_version, NULL); if (kEpidNoErr != result || kNumEpidVersions <= epid_version) { log_error("EPID version can not be detected"); ret_value = EXIT_FAILURE; break; } // Configure hashalg based on group if (kEpid1x == epid_version) { if (kSha256 != hashalg && hashalg_str->count > 0) { log_error( "unsupported hash algorithm: %s only supported for 2.0 groups", HashAlgToString(hashalg)); ret_value = EXIT_FAILURE; break; } } // Load Verifier pre-computed settings if (vprecmpi_file->count > 0) { vprecmpi_file_size = GetFileSize_S(vprecmpi_file->filename[0], SIZE_MAX); verifier_precmp = AllocBuffer(vprecmpi_file_size); if (0 != ReadLoud(vprecmpi_file->filename[0], verifier_precmp, vprecmpi_file_size)) { ret_value = EXIT_FAILURE; break; } } // Report Settings if (verbose_flag) { log_msg("=============================================="); log_msg("Verifying Message:"); log_msg(""); log_msg(" [in] Intel(R) EPID version: %s", EpidVersionToString(epid_version)); 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(""); log_msg(" [in] BaseName Len: %d", (int)basename_size); log_msg(" [in] BaseName: "); PrintBuffer(basename_str, basename_size); log_msg(""); log_msg(" [in] PrivRl Len: %d", (int)signed_priv_rl_size); log_msg(" [in] PrivRl: "); PrintBuffer(signed_priv_rl, signed_priv_rl_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] GrpRl Len: %d", (int)signed_grp_rl_size); log_msg(" [in] GrpRl: "); PrintBuffer(signed_grp_rl, signed_grp_rl_size); log_msg(""); log_msg(" [in] VerRl Len: %d", (int)ver_rl_size); log_msg(" [in] VerRl: "); PrintBuffer(ver_rl, ver_rl_size); log_msg(""); log_msg(" [in] Group Public Key: "); PrintBuffer(signed_pubkey, sizeof(signed_pubkey_size)); log_msg(""); log_msg(" [in] Hash Algorithm: %s", HashAlgToString(hashalg)); if (vprecmpi_file->count > 0) { log_msg(""); log_msg(" [in] Verifier PreComp: "); PrintBuffer(verifier_precmp, vprecmpi_file_size); } log_msg("=============================================="); } // Verify if (kEpid2x == epid_version) { if (verifier_precmp && vprecmpi_file_size != sizeof(VerifierPrecomp)) { if (vprecmpi_file_size == sizeof(VerifierPrecomp) - sizeof(GroupId)) { log_error( "incorrect input precomp size: precomp format may have changed, " "try regenerating it"); } else { log_error("incorrect input precomp size"); } ret_value = EXIT_FAILURE; break; } result = Verify(sig, sig_size, msg_str, msg_size, basename_str, basename_size, signed_priv_rl, signed_priv_rl_size, signed_sig_rl, signed_sig_rl_size, signed_grp_rl, signed_grp_rl_size, ver_rl, ver_rl_size, signed_pubkey, signed_pubkey_size, &cacert, hashalg, &verifier_precmp, &vprecmpi_file_size); } else if (kEpid1x == epid_version) { if (verifier_precmp && vprecmpi_file_size != sizeof(Epid11VerifierPrecomp)) { log_error("incorrect input precomp size"); ret_value = EXIT_FAILURE; break; } result = Verify11(sig, sig_size, msg_str, msg_size, basename_str, basename_size, signed_priv_rl, signed_priv_rl_size, signed_sig_rl, signed_sig_rl_size, signed_grp_rl, signed_grp_rl_size, signed_pubkey, signed_pubkey_size, &cacert, &verifier_precmp, &vprecmpi_file_size); } else { log_error("EPID version %s is not supported", EpidVersionToString(epid_version)); ret_value = EXIT_FAILURE; break; } // Report Result if (kEpidNoErr == result) { log_msg("signature verified successfully"); } else if (kEpidErr == result) { log_error( "signature verification failed: " "member did not prove it was not revoked"); ret_value = result; break; } else { log_error("signature verification failed: %s", EpidStatusToString(result)); ret_value = result; break; } // Store Verifier pre-computed settings if (vprecmpo_file->count > 0) { if (0 != WriteLoud(verifier_precmp, vprecmpi_file_size, vprecmpo_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_priv_rl) free(signed_priv_rl); if (signed_sig_rl) free(signed_sig_rl); if (signed_grp_rl) free(signed_grp_rl); if (ver_rl) free(ver_rl); if (signed_pubkey) free(signed_pubkey); if (verifier_precmp) free(verifier_precmp); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return ret_value; }