123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- /* SPDX-License-Identifier: BSD-3-Clause */
- #include <fcntl.h>
- #include <libgen.h>
- #include <signal.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <termios.h>
- #include <unistd.h>
- #include <tss2/tss2_rc.h>
- #include <sys/wait.h>
- #include <stdarg.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "tools/fapi/tss2_template.h"
- #include "lib/config.h"
- #include "lib/tpm2_alg_util.h"
- #define READ_SIZE 1024
- /* needed by tpm2_util and tpm2_option functions */
- bool output_enabled = false;
- static struct termios old;
- /* When the program is interrupted during callbacks,
- * restore the old termios state (with ICANON and ECHO) */
- static void signal_termio_restore(__attribute__((unused)) int signumber) {
- tcsetattr (STDIN_FILENO, TCSANOW, &old);
- }
- /* adapted from lib/tpm2_options.c for tss2 */
- static bool execute_man(char *prog_name, bool show_errors) {
- pid_t pid;
- int status;
- if ((pid = fork()) < 0) {
- LOG_ERR("Could not fork process to execute man, error: %s",
- strerror(errno));
- return false;
- }
- if (pid == 0) {
- if (!show_errors) {
- /* redirect manpager errors to stderr */
- int fd = open("/dev/null", O_WRONLY);
- if (fd < 0) {
- LOG_ERR("Could not open /dev/null");
- return false;
- }
- dup2(fd, 2);
- close(fd);
- }
- char *manpage = basename(prog_name);
- execlp("man", "man", manpage, NULL);
- } else {
- if (waitpid(pid, &status, 0) == -1) {
- LOG_ERR("Waiting for child process that executes man failed, error:"
- " %s", strerror(errno));
- return false;
- }
- return WEXITSTATUS(status) == 0;
- }
- return true;
- }
- /* adapted from lib/tpm2_options.c for tss2 */
- static tpm2_option_code tss2_handle_options (
- int argc,
- char **argv,
- tpm2_options **tool_opts) {
- tpm2_option_code rc = tpm2_option_code_err;
- bool show_help = false, manpager = true, explicit_manpager = false;
- struct option long_options [] = {
- {"help" , optional_argument, NULL, 'h'},
- {"version", no_argument, NULL, 'v'}
- };
- tpm2_options *opts = tpm2_options_new("h::v",
- ARRAY_LEN(long_options), long_options, NULL, NULL, 0);
- if (!opts) {
- return tpm2_option_code_err;
- }
- /* Get the options from the tool */
- if (!*tool_opts || !(*tool_opts)->callbacks.on_opt) {
- fprintf (stderr, "Unknown option found\n");
- goto out;
- }
- tpm2_option_handler on_opt = (*tool_opts)->callbacks.on_opt;
- tpm2_arg_handler on_arg = (*tool_opts)->callbacks.on_arg;
- if (!tpm2_options_cat (tool_opts, opts))
- goto out;
- (*tool_opts)->callbacks.on_opt = on_opt;
- (*tool_opts)->callbacks.on_arg = on_arg;
- /* Parse the options, calling the tool callback if unknown */
- int c;
- while ((c = getopt_long (argc, argv, (*tool_opts)->short_opts,
- (*tool_opts)->long_opts, NULL)) != -1) {
- switch (c) {
- case 'h':
- show_help = true;
- if (argv[optind]) {
- if (!strcmp(argv[optind], "man")) {
- manpager = true;
- explicit_manpager = true;
- optind++;
- } else if (!strcmp(argv[optind], "no-man")) {
- manpager = false;
- optind++;
- } else {
- show_help=false;
- fprintf (stderr, "Unknown help argument, got: \"%s\"\n",
- argv[optind]);
- }
- }
- goto out;
- break;
- case 'v': {
- char *prog_name = strdup (argv[0]);
- if (!prog_name) {
- fprintf (stderr, "Not enough memory\n");
- goto out;
- }
- printf("tool=\"%s\" version=\"%s\"\n", basename (prog_name),
- VERSION);
- free(prog_name);
- }
- rc = tpm2_option_code_stop;
- goto out;
- case '?':
- goto out;
- default:
- if (!(*tool_opts)->callbacks.on_opt(c, optarg))
- goto out;
- }
- }
- char **tool_args = &argv[optind];
- int tool_argc = argc - optind;
- /* have args and no handler, error condition */
- if (tool_argc && !(*tool_opts)->callbacks.on_arg) {
- char *prog_name = strdup (argv[0]);
- if (!prog_name) {
- fprintf (stderr, "Not enough memory\n");
- goto out;
- }
- fprintf (stderr, "Got arguments but %s takes no arguments\n",
- basename (prog_name));
- free (prog_name);
- goto out;
- } else if (tool_argc && (*tool_opts)->callbacks.on_arg
- && !(*tool_opts)->callbacks.on_arg(tool_argc, tool_args)) {
- goto out;
- }
- rc = tpm2_option_code_continue;
- out:
- /*
- * If help output is selected via -h or indicated by an error that help
- * output is desirable, show it.
- *
- * However, 3 conditions are possible:
- * 1. Try manpager and success -- done, no need to show short help output.
- * 2. Try manpager and failure -- show short help output.
- * 3. Do not use manpager -- show short help output.
- *
- */
- if (show_help) {
- if (!manpager || !execute_man (argv[0], explicit_manpager)) {
- tpm2_print_usage (argv[0], *tool_opts);
- }
- rc = tpm2_option_code_stop;
- }
- tpm2_options_free (opts);
- return rc;
- }
- char *password = NULL;
- TSS2_RC auth_callback(
- #ifdef FAPI_3_0
- char const *objectPath,
- char const *description,
- char const **auth,
- void *userdata)
- {
- #else /* FAPI_3_0 */
- __attribute__((unused)) FAPI_CONTEXT *fapi_context,
- char const *description,
- char **auth,
- void *userdata)
- {
- const char *objectPath = "object";
- #endif /* FAPI_3_0 */
- if (password != NULL) {
- free(password);
- password = NULL;
- }
- struct termios new;
- tcgetattr (STDIN_FILENO, &old);
- new = old;
- new.c_lflag &= ~(ICANON | ECHO);
- if (userdata) {
- printf("%s:", (const char *) userdata);
- } else {
- printf ("Authorize %s \"%s\": ", objectPath, description);
- }
- tcsetattr (STDIN_FILENO, TCSANOW, &new);
- size_t input_size = 0;
- struct sigaction signal_action;
- memset (&signal_action, 0, sizeof signal_action);
- signal_action.sa_handler = signal_termio_restore;
- sigaction (SIGTERM, &signal_action, NULL);
- sigaction (SIGINT, &signal_action, NULL);
- ssize_t getline_ret = getline (&password, &input_size, stdin);
- /* It is intentional, that auth can contain null bytes, and from
- * FAPI’s perspective these terminate the password. */
- tcsetattr (STDIN_FILENO, TCSANOW, &old);
- signal_action.sa_handler = SIG_DFL;
- sigaction (SIGTERM, &signal_action, NULL);
- sigaction (SIGINT, &signal_action, NULL);
- printf ("\n");
- if (getline_ret == -1) {
- fprintf (stderr, "getline() failed: %m\n");
- free (password);
- password = NULL;
- return TSS2_TCTI_RC_GENERAL_FAILURE;
- }
- password[getline_ret - 1] = '\0';
- #ifdef FAPI_3_0
- *auth = password;
- #else /* FAPI_3_0 */
- *auth = strdup(password);
- #endif /* FAPI_3_0 */
- return TSS2_RC_SUCCESS;
- }
- uint8_t *input_signature = NULL;
- TSS2_RC sign_callback(
- #ifdef FAPI_3_0
- char const *objectPath,
- #else /* FAPI_3_0 */
- __attribute__((unused)) FAPI_CONTEXT *fapi_context,
- #endif /* FAPI_3_0 */
- char const *description,
- char const *publicKey,
- char const *publicKeyHint,
- uint32_t hashAlg,
- uint8_t const *dataToSign,
- size_t dataToSignSize,
- #ifdef FAPI_3_0
- uint8_t const **signature,
- #else /* FAPI_3_0 */
- uint8_t **signature,
- #endif /* FAPI_3_0 */
- size_t *signatureSize,
- void *userData)
- {
- if (input_signature != NULL) {
- free(input_signature);
- input_signature = NULL;
- }
- int rc;
- char path[READ_SIZE];
- char publicKeyHintStr[READ_SIZE];
- if (userData) {
- printf("%s:", (const char *) userData);
- } else {
- const char *hashAlgName = tpm2_alg_util_algtostr(hashAlg,
- tpm2_alg_util_flags_hash);
- int cpy_size = 0;
- if (strlen(publicKeyHint) > 0) {
- const char* tmp = "the key corresponding to the key hint \"%s\" and";
- cpy_size = strlen(tmp) - 2 /* remove replaced %s */ +
- strlen(publicKeyHint);
- rc = snprintf(publicKeyHintStr, cpy_size+1 /* add \0 */, tmp,
- publicKeyHint);
- if (rc != cpy_size){
- fprintf (stderr, "Command snprintf failed with %d\n", rc);
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- }
- else {
- const char* tmp = "the key corresponding to the fingerprint \"%s\" and";
- char publicKeyHintTmp[READ_SIZE];
- rc = tpm2_pem_encoded_key_to_fingerprint(publicKey, publicKeyHintTmp);
- if (rc != true){
- fprintf (stderr, "Error getting the fingerprint of the "\
- "PEM-encoded public key\n");
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- cpy_size = strlen(tmp) - 2 /* remove replaced %s */ +
- strlen(publicKeyHintTmp);
- rc = snprintf(publicKeyHintStr, cpy_size+1 /* add \0 */, tmp,
- publicKeyHintTmp);
- if (rc != cpy_size){
- fprintf (stderr, "Command snprintf failed with %d\n", rc);
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- }
- #ifdef FAPI_3_0
- printf("%s: Authorize usage of %s by signing the nonce with %s the hash "\
- "algorithm \"%s\".\n", description, objectPath, publicKeyHintStr,
- hashAlgName);
- #else /* FAPI_3_0 */
- printf("%s: Authorize usage of the key by signing the nonce with %s the "\
- "hash algorithm \"%s\".\n", description, publicKeyHintStr,
- hashAlgName);
- #endif /* FAPI_3_0 */
- }
- printf("Filename for nonce output: ");
- rc = tpm2_safe_read_from_stdin(READ_SIZE, path);
- if (rc != true){
- fprintf (stderr, "Please enter a valid file path\n");
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- rc = open_write_and_close(path, true, dataToSign,
- dataToSignSize);
- if (rc) {
- fprintf (stderr, "Could not write to file: %s\n", path);
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- printf("Filename for signature input: ");
- rc = tpm2_safe_read_from_stdin(READ_SIZE, path);
- if (rc != true){
- fprintf (stderr, "Please enter a valid file path\n");
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- size_t input_signatureSize;
- rc = open_read_and_close (path, (void**)&input_signature,
- &input_signatureSize);
- if (rc) {
- fprintf (stderr, "Could not read from file path: %s\n", path);
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- *signature = input_signature;
- *signatureSize = input_signatureSize;
- return TSS2_RC_SUCCESS;
- }
- TSS2_RC branch_callback(
- #ifdef FAPI_3_0
- char const *objectPath,
- #else /* FAPI_3_0 */
- __attribute__((unused)) FAPI_CONTEXT *fapi_context,
- #endif /* FAPI_3_0 */
- char const *description,
- char const **branchNames,
- size_t numBranches,
- size_t *selectedBranch,
- __attribute__((unused)) void *userData)
- {
- #ifdef FAPI_3_0
- printf ("Select a branch for %s \"%s\"\n", objectPath, description);
- #else /* FAPI_3_0 */
- printf ("Select a branch for object \"%s\"\n", description);
- #endif /* FAPI_3_0 */
- for (size_t i = 0; i < numBranches; i++) {
- printf ("%4zu %s\n", i + 1, branchNames[i]);
- }
- while (1) {
- printf ("Your choice: ");
- if (scanf ("%zu", selectedBranch) != EOF) {
- while (getchar () != '\n'); /* Consume all remaining input */
- if (*selectedBranch > numBranches || *selectedBranch < 1) {
- fprintf (stderr, "The entered integer must be positive and "\
- "less than %zu.\n", numBranches + 1);
- } else {
- (*selectedBranch)--; /* the user display/choice is always +1 */
- return TSS2_RC_SUCCESS;
- }
- } else {
- fprintf (stderr, "No number received, but EOF.\n");
- return TSS2_FAPI_RC_GENERAL_FAILURE;
- }
- }
- }
- static FAPI_CONTEXT* ctx_init(char const * uri) {
- FAPI_CONTEXT* ret;
- const unsigned int rval = Fapi_Initialize(&ret, uri);
- if (rval != TSS2_RC_SUCCESS){
- LOG_PERR("Fapi_Initialize", rval);
- return NULL;
- }
- return ret;
- }
- /*
- * Build a list of the TSS2 tools linked into this executable
- */
- #ifndef TSS2_TOOLS_MAX
- #define TSS2_TOOLS_MAX 1024
- #endif
- static const tss2_tool *tools[TSS2_TOOLS_MAX];
- static unsigned tool_count;
- void tss2_tool_register(const tss2_tool *tool) {
- if (tool_count < TSS2_TOOLS_MAX) {
- tools[tool_count++] = tool;
- } else {
- LOG_ERR("Over tool count");
- abort();
- }
- }
- static const char *tss2_tool_name(const char *arg) {
- const char *name = rindex(arg, '/');
- if (name) {
- name++; // skip the '/'
- } else {
- name = arg; // use the full executable name as is
- }
- if (strncmp(name, "tss2_", 5) == 0) {
- name += 5;
- }
- return name;
- }
- static const tss2_tool *tss2_tool_lookup(int *argc, char ***argv)
- {
- // find the executable name in the path
- // and skip "tss2_" prefix if it is present
- const char *name = tss2_tool_name((*argv)[0]);
- // if this was invoked as 'tss2', then try again with the second argument
- if (strcmp(name, "tss2") == 0) {
- if (--(*argc) == 0) {
- return NULL;
- }
- (*argv)++;
- name = tss2_tool_name((*argv)[0]);
- }
- // search the tools array for a matching name
- for(unsigned i = 0 ; i < tool_count ; i++)
- {
- const tss2_tool * const tool = tools[i];
- if (!tool || !tool->name) {
- continue;
- }
- if (strcmp(name, tool->name) == 0) {
- return tool;
- }
- }
- // not found? should print a table of the tools
- return NULL;
- }
- /*
- * This program is a template for TPM2 tools that use the FAPI. It does
- * nothing more than parsing command line options that allow the caller to
- * specify which FAPI function to call.
- */
- int main(int argc, char *argv[]) {
- /* get rid of:
- * other write + read + execute (7)
- */
- umask(0007);
- const tss2_tool * const tool = tss2_tool_lookup(&argc, &argv);
- if (!tool) {
- LOG_ERR("%s: unknown tool. Available tss2 commands:\n", argv[0]);
- for(unsigned i = 0 ; i < tool_count ; i++) {
- fprintf(stderr, "%s\n", tools[i]->name);
- }
- return EXIT_FAILURE;
- }
- tpm2_options *tool_opts = NULL;
- if (tool->onstart && !tool->onstart (&tool_opts)) {
- fprintf (stderr,"error retrieving tool options\n");
- return 1;
- }
- int ret = 1;
- tpm2_option_code rc = tss2_handle_options (argc, argv, &tool_opts);
- if (rc != tpm2_option_code_continue) {
- ret = rc == tpm2_option_code_err ? 1 : 0;
- goto free_opts;
- }
- FAPI_CONTEXT *fctx = ctx_init (NULL);
- if (!fctx)
- goto free_opts;
- TSS2_RC r = Fapi_SetAuthCB (fctx, auth_callback, NULL);
- if (r != TSS2_RC_SUCCESS) {
- fprintf (stderr, "Fapi_SetAuthCB returned %u\n", r);
- Fapi_Finalize (&fctx);
- goto free_opts;
- }
- r = Fapi_SetSignCB (fctx, sign_callback, NULL);
- if (r != TSS2_RC_SUCCESS) {
- fprintf (stderr, "Fapi_SetSignCB returned %u\n", r);
- Fapi_Finalize (&fctx);
- goto free_opts;
- }
- r = Fapi_SetBranchCB (fctx, branch_callback, NULL);
- if (r != TSS2_RC_SUCCESS) {
- fprintf (stderr, "Fapi_SetBranchCB returned %u\n", r);
- Fapi_Finalize (&fctx);
- goto free_opts;
- }
- /*
- * Call the specific tool, all tools implement this function instead of
- * 'main'.
- * rc 1 = failure
- * rc 0 = success
- * rc -1 = show usage
- */
- ret = tool->onrun(fctx);
- if (ret < 0) {
- tpm2_print_usage(argv[0], tool_opts);
- ret = 1;
- }
- if (tool->onexit) {
- tool->onexit();
- }
- /*
- * Cleanup contexts & memory allocated for the modified argument vector
- * passed to execute_tool.
- */
- Fapi_Finalize (&fctx);
- free_opts:
- if (tool_opts)
- tpm2_options_free (tool_opts);
- free (password);
- if (ret == 0){
- free (input_signature);
- }
- exit(ret);
- }
- int open_write_and_close(const char* path, bool overwrite, const void *output,
- size_t output_len) {
- size_t length = 0;
- if (output_len){
- length = output_len;
- }
- if (!path || !strcmp(path, "-")) {
- if (-1 == write (STDOUT_FILENO, output, length)) {
- fprintf (stderr, "write(2) to stdout failed: %m\n");
- return 1;
- }
- return 0;
- }
- int oflags = O_CREAT | O_WRONLY | O_TRUNC ;
- if (!overwrite) {
- oflags |= O_EXCL;
- }
- int fileno = open (path, oflags, S_IWUSR | S_IRUSR);
- if (fileno == -1) {
- if (errno == EEXIST) {
- fprintf (stderr, "open(2) %s failed: %m\n", path);
- }
- return 1;
- }
- ssize_t bytes_written = write (fileno, output, length);
- if (bytes_written == -1) {
- fprintf (stderr, "write(2) %s failed: %m\n", path);
- close (fileno);
- return 1;
- }
- if (bytes_written - length) {
- fprintf (stderr, "write(2) could not write the whole file, deleting "\
- "%s\n", path);
- unlink (path);
- close (fileno);
- return 1;
- }
- if (close (fileno)) {
- fprintf (stderr, "close(2) %s failed: %m\n", path);
- return 1;
- }
- return 0;
- }
- int open_read_and_close (const char *path, void **input, size_t *size) {
- if (!path || !strcmp(path, "-")) {
- size_t data_consumed = 0, buffer_size = 1024, data_read;
- *input = malloc (buffer_size + 1);
- if (!*input) {
- fprintf (stderr, "malloc(2) failed: %m\n");
- return 1;
- }
- while ((data_read = read (STDIN_FILENO, *input + data_consumed, 1024))){
- data_consumed += data_read;
- if (data_read < 1024) /* EOF reached */
- break;
- buffer_size += 1024;
- *input = realloc (*input, buffer_size + 1);
- if (!*input) {
- fprintf (stderr, "realloc(3) failed: %m\n");
- return 1;
- }
- }
- if (size)
- *size = data_consumed;
- ((char*)(*input))[data_consumed] = 0;
- return 0;
- }
- int fileno = open (path, O_RDONLY);
- if (fileno == -1) {
- fprintf (stderr, "Opening %s failed: %m\n", path);
- return 1;
- }
- struct stat stat_;
- errno = 0;
- if (fstat (fileno, &stat_)) {
- printf("\nfstat error: [%s]\n",strerror(errno));
- close(fileno);
- return 1;
- }
- if (size)
- *size = stat_.st_size;
- *input = malloc (stat_.st_size + 1);
- if (!*input) {
- fprintf (stderr, "malloc(2) failed: %m\n");
- close (fileno);
- return 1;
- }
- if (-1 == read (fileno, *input, stat_.st_size)) {
- fprintf (stderr, "read(2) %s failed with: %m\n", path);
- free (*input);
- close (fileno);
- return 1;
- }
- ((char*)(*input))[stat_.st_size] = '\0';
- if (close (fileno)) {
- fprintf (stderr, "Error close(2) %s: %m\n", path);
- free (*input);
- return 1;
- }
- return 0;
- }
- char* ask_for_password() {
- #ifdef FAPI_3_0
- const char *pw;
- #else /* FAPI_3_0 */
- char *pw;
- #endif /* FAPI_3_0 */
- char *ret_pw = NULL;
- if (auth_callback (NULL, NULL, &pw, "New password"))
- goto error;
- #ifdef FAPI_3_0
- ret_pw = strdup(pw);
- if (!ret_pw) {
- fprintf (stderr, "OOM\n");
- return NULL;
- }
- #else /* FAPI_3_0 */
- ret_pw = pw;
- #endif /* FAPI_3_0 */
- if (auth_callback (NULL, NULL, &pw, "Re-enter new password"))
- goto error;
- bool eq = !strcmp (ret_pw, pw);
- #ifndef FAPI_3_0
- free(pw);
- #endif
- if (!eq) {
- fprintf (stderr, "Passwords do not match.\n");
- goto error;
- }
- return ret_pw;
- error:
- if (ret_pw)
- free(ret_pw);
- return NULL;
- }
- void LOG_PERR(const char *func, TSS2_RC rc) {
- fprintf (stderr, "%s(0x%X) - %s\n", func, rc, Tss2_RC_Decode(rc));
- }
- void LOG_ERR(const char *format, ...) {
- va_list arg;
- va_start (arg, format);
- vfprintf (stderr, format, arg);
- va_end (arg);
- }
|