Permalink
Browse files

tpm2_rc_decode.c: Add utility to decode TPM_RC error codes.

Basic usage is extremely simple and documented in the -h/--help option.
It expects a single 32bit TPM_RC as a positional parameter. This number
is parsed using the convenience functions in the rc-decode.h header.
This tool then generates human readable output describing each component
of the TPM_RC. This requires a few lookups in the tables from
rc-decode.c, accessed using the helper functions.

The algorithm is roughly:
  Extract the TSS layer / level indicator
  if TCTI | SAPI error
    print layer data to stdout
    lookup string mapping for the error code
    print error code data to stdout
  else if PART2 | TPM error
    if error code is in format zero
      if error code is vendor defined
        return error
      else if error code is a warning
        lookup string mapping for warning code
        print warning code data to stdout
      else if error code is an error
        lookup string mapping for error code
        print error code data to stdout
      else if error code is a TPM 1.2 format
        print error: 1.2 TPM_RCs aren't supported
        return error
      else
        print error: unknown TPM_RC format
        return error
      endif
    else if error code is in format one
      lookup string mapping for the error code
      print error code data to stdout
      if error code has parameter data
        lookup string mapping for parameter code
        print parameter code data to stdout
      else if error code has handle data
        lookup string mapping for handle code
        print handle code data to stdout
      else if error code has session data
        lookup string mapping for session code
        print session code data to stdout
      endif
    endif
  endif

The output format for data is very simple. Each component of
the TPM_RC is preceded by a line identifying the component.
Data about the layer producing the error is preceded by:
'error layer' followed by a new line.

The data in the field is then decoded and the hex value, a
string representation of the identifier and then a string
describing the error. These 3 items are printed each on their
own line and indented 2 spaces. An example makes this more
clear:

TSS2_SYS_PART2_RC_LEVEL + TSS2_SYS_PART2_RC_LEVEL = 0x90100
$ src/tpm2_rc_decode 0x90100
error layer
  hex: 0x90000
  identifier: TSS2_SYS_PART2_RC_LEVEL
  description: Error from the SAPI duplicating TPM error check
format 0 error code
  hex: 0x00
  name: TPM_RC_INITIALIZE
  description: TPM not initialized

TPM_FMT1 + TPM_RC_P + TPM_RC_MFG + TPM_RC_3 = 0x3c8
error layer
  hex: 0x0
  identifier: TSS2_TPM_ERROR_LEVEL
  description: Error produced by the TPM
format 1 error code
  hex: 0x08
  identifier: TPM_RC_MGF
  description: mask generation function not supported
parameter
  hex: 0x300
  identifier:  TPM_RC_3
  description:  (null)

Signed-off-by: Philip Tricca <philip.b.tricca@intel.com>
  • Loading branch information...
flihp committed Jul 12, 2016
1 parent 7502e55 commit 94f0944537ff3d344eb811b597dab1148b84aae7
Showing with 299 additions and 1 deletion.
  1. +1 −0 .gitignore
  2. +4 −0 ChangeLog
  3. +3 −1 Makefile.am
  4. +291 −0 src/tpm2_rc_decode.c
@@ -51,6 +51,7 @@ src/tpm2_getpubek
src/tpm2_takeownership
src/tpm2_loadexternal
src/tpm2_getmanufec
src/tpm2_rc_decode
test-driver
test/tpm2-rc-decode_unit
test/tpm2-rc-entry_unit
@@ -1,3 +1,7 @@
Unreleased
Added
* tpm2_rc_decode tool: Decode TPM_RC error codes.

2015-10-19 Gang Wei <gang.wei@intel.com>
* 1.0 release
* 29 tools included
@@ -71,7 +71,8 @@ sbin_PROGRAMS = src/tpm2_listpcrs \
src/tpm2_sign \
src/tpm2_unseal \
src/tpm2_verifysignature \
src/tpm2_listpersistent
src/tpm2_listpersistent \
src/tpm2_rc_decode

check_PROGRAMS = \
test/tpm2-rc-decode_unit \
@@ -129,6 +130,7 @@ src_tpm2_sign_SOURCES = src/tpm2_sign.cpp
src_tpm2_unseal_SOURCES = src/tpm2_unseal.cpp
src_tpm2_verifysignature_SOURCES = src/tpm2_verifysignature.cpp
src_tpm2_listpersistent_SOURCES = src/tpm2_listpersistent.cpp
src_tpm2_rc_decode_SOURCES = src/rc-decode.c src/tpm2_rc_decode.c

test_tpm2_rc_decode_unit_CFLAGS = $(AM_CXXFLAGS) $(CMOCKA_CFLAGS)
test_tpm2_rc_decode_unit_LDADD = $(CMOCKA_LIBS)
@@ -0,0 +1,291 @@
//**********************************************************************;
// Copyright (c) 2016, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//**********************************************************************;

#include <getopt.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sapi/tpm20.h>

#include "common.h"
#include "rc-decode.h"

#define TPM_RC_MAX 0xffffffff

void
showHelp (const char *name)
{
printf ("%s [--version|--help] TPM_RC\n"
"-h, --help\t\tDisplay help message\n"
"-v, --version\t\tDisplay version info\n"
"\nExample:\n"
"Decode hex TPM return code: %s 0xffffffff\n", name, name);
}

TPM_RC
str_to_tpm_rc (const char *rc_str)
{
uintmax_t rc_read = 0;
char *end_ptr = NULL;

rc_read = strtoumax (rc_str, &end_ptr, 0);
if (rc_read > TPM_RC_MAX) {
fprintf (stderr, "invalid TPM_RC\n");
exit (1);
}
/* apply the TPM_RC_MAX mask to the possibly larger uintmax_t */
return rc_read & TPM_RC_MAX;
}

int
process_cmdline (int argc,
char *argv[])
{
int opt = -1;
const char *optstring = "hr";
static struct option long_options[] = {
{ "help", 0 , NULL, 'h' },
{ "version", 0, NULL, 'r' },
{ 0 }
};
while ((opt = getopt_long (argc, argv, optstring, long_options, NULL)) != -1)
{
switch (opt)
{
case 'h':
showHelp (argv[0]);
exit (0);
case 'r':
showVersion (argv[0]);
exit (0);
case '?':
exit (1);
}
}
return optind;
}

/* Dump the hex, identifier and description for the format zero / VER1 error
* provided in TPM_RC parameter.
*/
int
print_tpm_rc_format_zero (TPM_RC rc)
{
TPM_RC rc_tmp;
tpm2_rc_entry_t *entry;

rc_tmp = tpm2_rc_get_code_7bit (rc);
if (tpm2_rc_is_vendor_defined (rc)) {
fprintf (stderr, "vendor defined TPM_RCs are not supported\n");
return -1;
} else if (tpm2_rc_is_warning_code (rc)) {
entry = tpm2_get_warn_entry (rc_tmp);
if (entry)
printf ("format 0 warning code\n hex: 0x%02x\n name: %s\n "
"description: %s\n",
rc_tmp, entry->name, entry->description);
else
printf ("failed to decode TPM_RC warning: 0x%x\n", rc_tmp);
} else if (tpm2_rc_is_error_code (rc)) {
entry = tpm2_get_fmt0_entry (rc_tmp);
if (entry)
printf ("format 0 error code\n hex: 0x%02x\n name: %s\n "
"description: %s\n",
rc_tmp, entry->name, entry->description);
else
printf ("failed to decode TPM_RC error: 0x%02x\n", rc_tmp);
} else if (tpm2_rc_is_tpm12 (rc_tmp)) {
fprintf (stderr, "version 1.2 TPM_RCs are not supproted\n");
return -1;
} else {
fprintf (stderr, "Unknown TPM_RC format\n");
return -1;
}
/* decode warning / error code */
return 0;
}
/* Dump the hex, identifier and description for the format one / FMT1 error
* as well as the parameter, handle or session data.
*/
int
print_tpm_rc_format_one (TPM_RC rc)
{
TPM_RC rc_tmp;
tpm2_rc_entry_t *entry;
int ret;

printf ("format 1 error code\n");
rc_tmp = tpm2_rc_get_code_6bit (rc);
printf (" hex: 0x%02x\n", rc_tmp);
/* decode error message */
entry = tpm2_get_fmt1_entry (rc_tmp);
if (!entry) {
printf ("Unknown TPM_RC\n");
return -1;
}
printf (" identifier: %s\n description: %s\n",
entry->name, entry->description);
/* decode parameter / handle / session number */
if (tpm2_rc_is_error_code_with_parameter (rc)) {
rc_tmp = tpm2_rc_get_parameter_number (rc);
entry = tpm2_get_parameter_entry (rc_tmp);
if (!entry) {
printf ("Unknown TPM_RC parameter number: 0x%03x\n", rc_tmp);
return -1;
}
printf ("parameter\n hex: 0x%03x\n identifier: %s\n "
"description: %s\n", rc_tmp, entry->name, entry->description);
} else if (tpm2_rc_is_error_code_with_handle (rc)) {
rc_tmp = tpm2_rc_get_handle_number (rc);
entry = tpm2_get_handle_entry (rc_tmp);
if (!entry) {
printf ("Unkonwn TPM_RC handle number: 0x%03x\n", rc_tmp);
return -1;
}
printf ("handle\n hex:0x%03x\n identifier: %s\n "
"description: %s\n", rc_tmp, entry->name, entry->description);
} else if (tpm2_rc_is_error_code_with_session (rc)) {
rc_tmp = tpm2_rc_get_session_number (rc);
entry = tpm2_get_session_entry (rc_tmp);
if (!entry) {
printf ("Unknown TPM_RC session number: 0x%03x\n", rc_tmp);
return -1;
}
printf ("session\n hex: 0x%03x\n identifier: %s\n "
"description: %s\n", rc_tmp, entry->name, entry->description);
}

return 0;
}
/* Dump the hex, identifier and description for the TSS defined layer
* indicator in the provided TPM_RC.
*/
int
print_tpm_rc_tss_layer (TPM_RC rc)
{
TPM_RC rc_tmp;
tpm2_rc_entry_t *entry;
int ret;

rc_tmp = tpm2_rc_get_layer (rc);
/* Currently no entry for 0x0 layer, assume it's directly from the TPM? */
printf ("error layer\n hex: 0x%x\n", rc_tmp);
entry = tpm2_get_layer_entry (rc_tmp);
if (entry) {
printf (" identifier: %s\n description: %s\n",
entry->name, entry->description);
ret = 0;
} else {
printf ("failed to decode TPM_RC layer: 0x%x\n", rc_tmp);
ret = -1;
}

return ret;
}
/* Dump the hex, identifier string and description for the TSS defined
* base error code in the provided TPM_RC.
*/
int
print_tpm_rc_tss_error_code (TPM_RC rc)
{
TPM_RC rc_tmp;
tpm2_rc_entry_t *entry;
int ret;

entry = tpm2_get_tss_base_rc_entry (rc);
if (entry) {
printf ("base error code\n identifier: %s\n description: %s\n",
entry->name, entry->description);
ret = 0;
} else {
rc_tmp = tpm2_rc_get_tss_err_code (rc);
printf ("failed to decode TPM_RC error code: 0x%x\n", rc_tmp);
ret = -1;
}

return ret;
}
/* Top level function to dump human readable data about TPM_RCs as defined
* in the TPM2 Part 2: Structures, Table 17..
*/
int
print_tpm_rc_tpm_error_code (TPM_RC rc)
{
if (tpm2_rc_is_format_zero (rc))
print_tpm_rc_format_zero (rc);
else if (tpm2_rc_is_format_one (rc))
print_tpm_rc_format_one (rc);
else {
fprintf (stderr, "Unknown TPM_RC format\n");
return -1;
}
}
/* Top level function to dump human readable data about TPM_RCs.
*/
int
print_tpm_rc (TPM_RC rc)
{
int ret;
TPM_RC rc_tmp;

/* determin which layer in the stack produced the error */
rc_tmp = tpm2_rc_get_layer (rc);
ret = print_tpm_rc_tss_layer (rc);
switch (rc_tmp) {
case TSS2_SYS_ERROR_LEVEL:
case TSS2_TCTI_ERROR_LEVEL:
ret = print_tpm_rc_tss_error_code (rc);
break;
case TSS2_SYS_PART2_ERROR_LEVEL:
case TSS2_TPM_ERROR_LEVEL:
ret = print_tpm_rc_tpm_error_code (rc);
break;
default:
break;
}

return ret;
}

int
main (int argc, char *argv[])
{
TPM_RC rc = 0;
int pos_ind = -1, ret = -1;

pos_ind = process_cmdline (argc, argv);
if (pos_ind + 1 != argc) {
printf ("No error code provided, try --help\n");
exit (1);
}
rc = str_to_tpm_rc (argv[pos_ind]);
ret = print_tpm_rc (rc);
exit (ret);
}

0 comments on commit 94f0944

Please sign in to comment.