123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- /* SPDX-License-Identifier: BSD-3-Clause */
- #include <stdlib.h>
- #include "files.h"
- #include "log.h"
- #include "object.h"
- #include "tpm2.h"
- #include "tpm2_tool.h"
- #include "tpm2_alg_util.h"
- #include "tpm2_convert.h"
- #include "tpm2_hash.h"
- #include "tpm2_options.h"
- typedef struct tpm2_verifysig_ctx tpm2_verifysig_ctx;
- struct tpm2_verifysig_ctx {
- union {
- struct {
- UINT8 digest :1;
- UINT8 halg :1;
- UINT8 msg :1;
- UINT8 sig :1;
- UINT8 ticket :1;
- UINT8 key_context :1;
- UINT8 fmt;
- };
- UINT8 all;
- } flags;
- TPMI_ALG_SIG_SCHEME format;
- TPMI_ALG_HASH halg;
- TPM2B_DIGEST *msg_hash;
- TPMT_SIGNATURE signature;
- char *msg_file_path;
- char *sig_file_path;
- char *out_file_path;
- const char *context_arg;
- tpm2_loaded_object key_context_object;
- };
- static tpm2_verifysig_ctx ctx = {
- .format = TPM2_ALG_ERROR,
- .msg_hash = NULL,
- .halg = TPM2_ALG_SHA256
- };
- static tool_rc verify_signature(ESYS_CONTEXT *context) {
- TPMT_TK_VERIFIED *validation = NULL;
- tool_rc rc = tpm2_verifysignature(context,
- ctx.key_context_object.tr_handle,
- ctx.msg_hash, &ctx.signature, &validation);
- if (rc != tool_rc_success) {
- goto out;
- }
- /*
- * NULL Hierarchies don't produce validation data, so let the user know
- * by issuing a warning.
- */
- if (ctx.out_file_path) {
- if (validation->hierarchy == TPM2_RH_NULL) {
- LOG_WARN("The NULL hierarchy doesn't produce a validation ticket,"
- " not outputting ticket");
- } else {
- if (!files_save_ticket(validation, ctx.out_file_path)) {
- rc = tool_rc_general_error;
- }
- }
- }
- out:
- free(validation);
- return rc;
- }
- static TPM2B *message_from_file(const char *msg_file_path) {
- unsigned long size;
- bool result = files_get_file_size_path(msg_file_path, &size);
- if (!result) {
- return NULL;
- }
- if (!size) {
- LOG_ERR("The msg file \"%s\" is empty", msg_file_path);
- return NULL;
- }
- TPM2B *msg = (TPM2B *) calloc(1, sizeof(TPM2B) + size);
- if (!msg) {
- LOG_ERR("OOM");
- return NULL;
- }
- UINT16 tmp = msg->size = size;
- if (!files_load_bytes_from_path(msg_file_path, msg->buffer, &tmp)) {
- free(msg);
- return NULL;
- }
- return msg;
- }
- static tool_rc init(ESYS_CONTEXT *context) {
- tool_rc rc = tool_rc_general_error;
- /* check flags for mismatches */
- if (ctx.flags.digest && (ctx.flags.msg || ctx.flags.halg)) {
- LOG_ERR("Cannot specify --digest (-d) and ( --msg (-m) or --halg (-g) )");
- return tool_rc_option_error;
- }
- if (!(ctx.context_arg && ctx.flags.sig)) {
- LOG_ERR("--key-context (-c) and --sig (-s) are required");
- return tool_rc_option_error;
- }
- TPM2B *msg = NULL;
- tool_rc tmp_rc = tpm2_util_object_load(context, ctx.context_arg,
- &ctx.key_context_object, TPM2_HANDLE_ALL_W_NV);
- if (tmp_rc != tool_rc_success) {
- return tmp_rc;
- }
- if (ctx.flags.msg) {
- msg = message_from_file(ctx.msg_file_path);
- if (!msg) {
- /* message_from_file() logs specific error no need to here */
- return tool_rc_general_error;
- }
- }
- if (ctx.flags.sig) {
- tpm2_convert_sig_fmt fmt =
- ctx.flags.fmt ? signature_format_plain : signature_format_tss;
- bool res = tpm2_convert_sig_load(ctx.sig_file_path, fmt, ctx.format,
- ctx.halg, &ctx.signature);
- if (!res) {
- goto err;
- }
- }
- /* If no digest is specified, compute it */
- if (!ctx.flags.digest) {
- if (!msg) {
- /*
- * This is a redundant check since main() checks this case, but
- * we'll add it here to silence any complainers (such as static
- * analysers).
- */
- LOG_ERR("No digest set and no message file to compute from, cannot "
- "compute message hash!");
- goto err;
- }
- tmp_rc = tpm2_hash_compute_data(context, ctx.halg, TPM2_RH_NULL,
- msg->buffer, msg->size, &ctx.msg_hash, NULL);
- if (tmp_rc != tool_rc_success) {
- rc = tmp_rc;
- LOG_ERR("Compute message hash failed!");
- goto err;
- }
- }
- rc = tool_rc_success;
- err:
- free(msg);
- return rc;
- }
- static bool on_option(char key, char *value) {
- switch (key) {
- case 'c':
- ctx.context_arg = value;
- break;
- case 'g': {
- ctx.halg = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_hash);
- if (ctx.halg == TPM2_ALG_ERROR) {
- LOG_ERR("Unable to convert algorithm, got: \"%s\"", value);
- return false;
- }
- ctx.flags.halg = 1;
- }
- break;
- case 'm': {
- ctx.msg_file_path = value;
- ctx.flags.msg = 1;
- }
- break;
- case 'd': {
- ctx.msg_hash = malloc(sizeof(TPM2B_DIGEST));
- ctx.msg_hash->size = sizeof(ctx.msg_hash->buffer);
- if (!files_load_bytes_from_path(value, ctx.msg_hash->buffer,
- &ctx.msg_hash->size)) {
- LOG_ERR("Could not load digest from file!");
- return false;
- }
- ctx.flags.digest = 1;
- }
- break;
- case 0:
- LOG_WARN("Option \"--format\" is deprecated, use \"--scheme\"");
- /* falls through */
- case 'f':
- ctx.format = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_sig);
- if (ctx.format == TPM2_ALG_ERROR) {
- LOG_ERR("Unknown signing scheme, got: \"%s\"", value);
- return false;
- }
- ctx.flags.fmt = 1;
- break;
- case 's':
- ctx.sig_file_path = value;
- ctx.flags.sig = 1;
- break;
- case 't':
- ctx.out_file_path = value;
- ctx.flags.ticket = 1;
- break;
- /* no default */
- }
- return true;
- }
- static bool tpm2_tool_onstart(tpm2_options **opts) {
- const struct option topts[] = {
- { "digest", required_argument, NULL, 'd' },
- { "hash-algorithm", required_argument, NULL, 'g' },
- { "message", required_argument, NULL, 'm' },
- { "format", required_argument, NULL, 0 },
- { "scheme", required_argument, NULL, 'f' },
- { "signature", required_argument, NULL, 's' },
- { "ticket", required_argument, NULL, 't' },
- { "key-context", required_argument, NULL, 'c' },
- };
- *opts = tpm2_options_new("g:m:d:f:s:t:c:", ARRAY_LEN(topts), topts,
- on_option, NULL, 0);
- return *opts != NULL;
- }
- static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *context, tpm2_option_flags flags) {
- UNUSED(flags);
- /* initialize and process */
- tool_rc rc = init(context);
- if (rc != tool_rc_success) {
- return rc;
- }
- rc = verify_signature(context);
- if (rc != tool_rc_success) {
- LOG_ERR("Verify signature failed!");
- return rc;
- }
- return tool_rc_success;
- }
- static void tpm2_tool_onexit(void) {
- if (ctx.msg_hash) {
- free(ctx.msg_hash);
- }
- }
- // Register this tool with tpm2_tool.c
- TPM2_TOOL_REGISTER("verifysignature", tpm2_tool_onstart, tpm2_tool_onrun, NULL, tpm2_tool_onexit)
|