/*############################################################################
# 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;
}