blob: 15ced5671f6330200c5160def04221a9704091f2 [file] [log] [blame]
/* SPDX-License-Identifier: BSD-2-Clause */
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "tss2_rc.h"
#include "tss2_sys.h"
#include "util/aux_util.h"
#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
/**
* The maximum size of a layer name.
*/
#define TSS2_ERR_LAYER_NAME_MAX (16 + 1)
/**
* The maximum size for layer specific error strings.
*/
#define TSS2_ERR_LAYER_ERROR_STR_MAX 512
/**
* Concatenates (safely) onto a static buffer given a format and varaidic
* arguments similar to sprintf.
* @param b
* The static buffer to concatenate onto.
* @param fmt
* The format specifier as understood by printf followed by the variadic
* parameters for the specifier.
*/
#define catbuf(b, fmt, ...) _catbuf(b, sizeof(b), fmt, ##__VA_ARGS__)
/**
* Clears out a static buffer by setting index 0 to the null byte.
* @param buffer
* The buffer to clear out.
*/
static void
clearbuf(char *buffer)
{
buffer[0] = '\0';
}
/**
* Prints to a buffer using snprintf(3) using the supplied fmt
* and varaiadic arguments.
* @param buf
* The buffer to print into.
* @param len
* The length of that buffer.
* @param fmt
* The format string
* @warning
* DO NOT CALL DIRECTLY, use the catbuf() macro.
*/
static void COMPILER_ATTR(format (printf, 3, 4))
_catbuf(char *buf, size_t len, const char *fmt, ...)
{
va_list argptr;
va_start(argptr, fmt);
size_t offset = strlen(buf);
vsnprintf(&buf[offset], len - offset, fmt, argptr);
va_end(argptr);
}
/**
* Number of error layers
*/
#define TPM2_ERROR_TSS2_RC_LAYER_COUNT (TSS2_RC_LAYER_MASK >> TSS2_RC_LAYER_SHIFT)
/**
* Mask for the error bits of tpm2 compliant return code.
*/
#define TPM2_ERROR_TSS2_RC_ERROR_MASK 0xFFFF
/**
* Retrieves the error bits from a TSS2_RC. The error bits are
* contained in the first 2 octets.
* @param rc
* The rc to query for the error bits.
* @return
* The error bits.
*/
static inline UINT16
tpm2_error_get(TSS2_RC rc)
{
return ((rc & TPM2_ERROR_TSS2_RC_ERROR_MASK));
}
/**
* Retrieves the layer number. The layer number is in the 3rd
* octet and is thus 1 byte big.
*
* @param rc
* The rc to query for the layer number.
* @return
* The layer number.
*/
static inline UINT8
tss2_rc_layer_number_get(TSS2_RC rc)
{
return ((rc & TSS2_RC_LAYER_MASK) >> TSS2_RC_LAYER_SHIFT);
}
/**
* Queries a TPM format 1 error codes N field. The N field
* is a 4 bit field located at bits 8:12.
* @param rc
* The rc to query the N field for.
* @return
* The N field value.
*/
static inline UINT8
tpm2_rc_fmt1_N_get(TPM2_RC rc)
{
return ((rc & (0xF << 8)) >> 8);
}
/**
* Queries the index bits out of the N field contained in a TPM format 1
* error code. The index bits are the low 3 bits of the N field.
* @param rc
* The TPM format 1 error code to query for the index bits.
* @return
* The index bits from the N field.
*/
static inline UINT8
tpm2_rc_fmt1_N_index_get(TPM2_RC rc)
{
return (tpm2_rc_fmt1_N_get(rc) & 0x7);
}
/**
* Determines if the N field in a TPM format 1 error code is
* a handle or not.
* @param rc
* The TPM format 1 error code to query.
* @return
* True if it is a handle, false otherwise.
*/
static inline bool
tpm2_rc_fmt1_N_is_handle(TPM2_RC rc)
{
return ((tpm2_rc_fmt1_N_get(rc) & 0x8) == 0);
}
static inline UINT8
tpm2_rc_fmt1_P_get(TPM2_RC rc)
{
return ((rc & (1 << 6)) >> 6);
}
static inline UINT8
tpm2_rc_fmt1_error_get(TPM2_RC rc)
{
return (rc & 0x3F);
}
static inline UINT8
tpm2_rc_fmt0_error_get(TPM2_RC rc)
{
return (rc & 0x7F);
}
static inline UINT8
tpm2_rc_tpm_fmt0_V_get(TPM2_RC rc)
{
return ((rc & (1 << 8)) >> 8);
}
static inline UINT8
tpm2_rc_fmt0_T_get(TPM2_RC rc)
{
return ((rc & (1 << 10)) >> 8);
}
static inline UINT8
tpm2_rc_fmt0_S_get(TSS2_RC rc)
{
return ((rc & (1 << 11)) >> 8);
}
/**
* Helper macro for adding a layer handler to the layer
* registration array.
*/
#define ADD_HANDLER(name, handler) \
{ name, handler }
/**
* Same as ADD_HANDLER but sets it to NULL. Used as a placeholder
* for non-registered indexes into the handler array.
*/
#define ADD_NULL_HANDLER ADD_HANDLER("\0", NULL)
static const char *
tpm2_err_handler_fmt1(TPM2_RC rc)
{
/*
* format 1 error codes start at 1, so
* add a NULL entry to index 0.
*/
static const char *fmt1_err_strs[] = {
/* 0x0 - EMPTY */
NULL,
/* 0x1 - TPM2_RC_ASYMMETRIC */
"asymmetric algorithm not supported or not correct",
/* 0x2 - TPM2_RC_ATTRIBUTES */
"inconsistent attributes",
/* 0x3 - TPM2_RC_HASH */
"hash algorithm not supported or not appropriate",
/* 0x4 - TPM2_RC_VALUE */
"value is out of range or is not correct for the context",
/* 0x5 - TPM2_RC_HIERARCHY */
"hierarchy is not enabled or is not correct for the use",
/* 0x6 - EMPTY */
NULL,
/* 0x7 - TPM2_RC_KEY_SIZE */
"key size is not supported",
/* 0x8 - TPM2_RC_MGF */
"mask generation function not supported",
/* 0x9 - TPM2_RC_MODE */
"mode of operation not supported",
/* 0xA - TPM2_RC_TYPE */
"the type of the value is not appropriate for the use",
/* 0xB - TPM2_RC_HANDLE */
"the handle is not correct for the use",
/* 0xC - TPM2_RC_KDF */
"unsupported key derivation function or function not appropriate for "
"use",
/* 0xD - TPM2_RC_RANGE */
"value was out of allowed range",
/* 0xE - TPM2_RC_AUTH_FAIL */
"the authorization HMAC check failed and DA counter incremented",
/* 0xF - TPM2_RC_NONCE */
"invalid nonce size or nonce value mismatch",
/* 0x10 - TPM2_RC_PP */
"authorization requires assertion of PP",
/* 0x11 - EMPTY */
NULL,
/* 0x12 - TPM2_RC_SCHEME */
"unsupported or incompatible scheme",
/* 0x13 - EMPTY */
NULL,
/* 0x14 - EMPTY */
NULL,
/* 0x15 - TPM2_RC_SIZE */
"structure is the wrong size",
/* 0x16 - TPM2_RC_SYMMETRIC */
"unsupported symmetric algorithm or key size or not appropriate for"
" instance",
/* 0x17 - TPM2_RC_TAG */
"incorrect structure tag",
/* 0x18 - TPM2_RC_SELECTOR */
"union selector is incorrect",
/* 0x19 - EMPTY */
NULL,
/* 0x1A - TPM2_RC_INSUFFICIENT */
"the TPM was unable to unmarshal a value because there were not enough"
" octets in the input buffer",
/* 0x1B - TPM2_RC_SIGNATURE */
"the signature is not valid",
/* 0x1C - TPM2_RC_KEY */
"key fields are not compatible with the selected use",
/* 0x1D - TPM2_RC_POLICY_FAIL */
"a policy check failed",
/* 0x1E - EMPTY */
NULL,
/* 0x1F - TPM2_RC_INTEGRITY */
"integrity check failed",
/* 0x20 - TPM2_RC_TICKET */
"invalid ticket",
/* 0x21 - TPM2_RC_RESERVED_BITS */
"reserved bits not set to zero as required",
/* 0x22 - TPM2_RC_BAD_AUTH */
"authorization failure without DA implications",
/* 0x23 - TPM2_RC_EXPIRED */
"the policy has expired",
/* 0x24 - TPM2_RC_POLICY_CC */
"the commandCode in the policy is not the commandCode of the command"
" or the command code in a policy command references a command that"
" is not implemented",
/* 0x25 - TPM2_RC_BINDING */
"public and sensitive portions of an object are not cryptographically bound",
/* 0x26 - TPM2_RC_CURVE */
"curve not supported",
/* 0x27 - TPM2_RC_ECC_POINT */
"point is not on the required curve",
};
static __thread char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
clearbuf(buf);
/* Print whether or not the error is caused by a bad
* handle or parameter. On the case of a Handle (P == 0)
* then the N field top bit will be set. Un-set this bit
* to get the handle index by subtracting 8 as N is a 4
* bit field.
*
* the lower 3 bits of N indicate index, and the high bit
* indicates
*/
UINT8 index = tpm2_rc_fmt1_N_index_get(rc);
bool is_handle = tpm2_rc_fmt1_N_is_handle(rc);
const char *m = tpm2_rc_fmt1_P_get(rc) ? "parameter" :
is_handle ? "handle" : "session";
catbuf(buf, "%s", m);
if (index) {
catbuf(buf, "(%u):", index);
} else {
catbuf(buf, "%s", "(unk):");
}
UINT8 errnum = tpm2_rc_fmt1_error_get(rc);
if (errnum < ARRAY_LEN(fmt1_err_strs)) {
m = fmt1_err_strs[errnum];
catbuf(buf, "%s", m);
} else {
catbuf(buf, "unknown error num: 0x%X", errnum);
}
return buf;
}
static const char *
tpm2_err_handler_fmt0(TSS2_RC rc)
{
/*
* format 0 error codes start at 1, so
* add a NULL entry to index 0.
* Thus, no need to offset the error bits
* and fmt0 and fmt1 arrays can be used
* in-place of each other for lookups.
*/
static const char *fmt0_warn_strs[] = {
/* 0x0 - EMPTY */
NULL,
/* 0x1 - TPM2_RC_CONTEXT_GAP */
"gap for context ID is too large",
/* 0x2 - TPM2_RC_OBJECT_MEMORY */
"out of memory for object contexts",
/* 0x3 - TPM2_RC_SESSION_MEMORY */
"out of memory for session contexts",
/* 0x4 - TPM2_RC_MEMORY */
"out of shared objectsession memory or need space for internal"
" operations",
/* 0x5 - TPM2_RC_SESSION_HANDLES */
"out of session handles",
/* 0x6 - TPM2_RC_OBJECT_HANDLES */
"out of object handles",
/* 0x7 - TPM2_RC_LOCALITY */
"bad locality",
/* 0x8 - TPM2_RC_YIELDED */
"the TPM has suspended operation on the command forward progress"
" was made and the command may be retried",
/* 0x9 - TPM2_RC_CANCELED */
"the command was canceled",
/* 0xA - TPM2_RC_TESTING */
"TPM is performing selftests",
/* 0xB - EMPTY */
NULL,
/* 0xC - EMPTY */
NULL,
/* 0xD - EMPTY */
NULL,
/* 0xE - EMPTY */
NULL,
/* 0xF - EMPTY */
NULL,
/* 0x10 - TPM2_RC_REFERENCE_H0 */
"the 1st handle in the handle area references a transient object"
" or session that is not loaded",
/* 0x11 - TPM2_RC_REFERENCE_H1 */
"the 2nd handle in the handle area references a transient object"
" or session that is not loaded",
/* 0x12 - TPM2_RC_REFERENCE_H2 */
"the 3rd handle in the handle area references a transient object"
" or session that is not loaded",
/* 0x13 - TPM2_RC_REFERENCE_H3 */
"the 4th handle in the handle area references a transient object"
" or session that is not loaded",
/* 0x14 - TPM2_RC_REFERENCE_H4 */
"the 5th handle in the handle area references a transient object"
" or session that is not loaded",
/* 0x15 - TPM2_RC_REFERENCE_H5 */
"the 6th handle in the handle area references a transient object"
" or session that is not loaded",
/* 0x16 - TPM2_RC_REFERENCE_H6 */
"the 7th handle in the handle area references a transient object"
" or session that is not loaded",
/* 0x17 - EMPTY, */
NULL,
/* 0x18 - TPM2_RC_REFERENCE_S0 */
"the 1st authorization session handle references a session that"
" is not loaded",
/* 0x19 - TPM2_RC_REFERENCE_S1 */
"the 2nd authorization session handle references a session that"
" is not loaded",
/* 0x1A - TPM2_RC_REFERENCE_S2 */
"the 3rd authorization session handle references a session that"
" is not loaded",
/* 0x1B - TPM2_RC_REFERENCE_S3 */
"the 4th authorization session handle references a session that"
" is not loaded",
/* 0x1C - TPM2_RC_REFERENCE_S4 */
"the 5th session handle references a session that"
" is not loaded",
/* 0x1D - TPM2_RC_REFERENCE_S5 */
"the 6th session handle references a session that"
" is not loaded",
/* 0x1E - TPM2_RC_REFERENCE_S6 */
"the 7th authorization session handle references a session that"
" is not loaded",
/* 0x1F - EMPTY, */
NULL,
/* 0x20 -TPM2_RC_NV_RATE */
"the TPM is rate limiting accesses to prevent wearout of NV",
/* 0x21 - TPM2_RC_LOCKOUT */
"authorizations for objects subject to DA protection are not"
" allowed at this time because the TPM is in DA lockout mode",
/* 0x22 - TPM2_RC_RETRY */
"the TPM was not able to start the command",
/* 0x23 - TPM2_RC_NV_UNAVAILABLE */
"the command may require writing of NV and NV is not current"
" accessible",
};
/*
* format 1 error codes start at 0, so
* no need to offset the error bits.
*/
static const char *fmt0_err_strs[] = {
/* 0x0 - TPM2_RC_INITIALIZE */
"TPM not initialized by TPM2_Startup or already initialized",
/* 0x1 - TPM2_RC_FAILURE */
"commands not being accepted because of a TPM failure",
/* 0x2 - EMPTY */
NULL,
/* 0x3 - TPM2_RC_SEQUENCE */
"improper use of a sequence handle",
/* 0x4 - EMPTY */
NULL,
/* 0x5 - EMPTY */
NULL,
/* 0x6 - EMPTY */
NULL,
/* 0x7 - EMPTY */
NULL,
/* 0x8 - EMPTY */
NULL,
/* 0x9 - EMPTY */
NULL,
/* 0xA - EMPTY */
NULL,
/* 0xB - TPM2_RC_PRIVATE */
"not currently used",
/* 0xC - EMPTY */
NULL,
/* 0xD - EMPTY */
NULL,
/* 0xE - EMPTY */
NULL,
/* 0xF - EMPTY */
NULL,
/* 0x10 - EMPTY */
NULL,
/* 0x11 - EMPTY */
NULL,
/* 0x12 - EMPTY */
NULL,
/* 0x13 - EMPTY */
NULL,
/* 0x14 - EMPTY */
NULL,
/* 0x15 - EMPTY */
NULL,
/* 0x16 - EMPTY */
NULL,
/* 0x17 - EMPTY */
NULL,
/* 0x18 - EMPTY */
NULL,
/* 0x19 - TPM2_RC_HMAC */
"not currently used",
/* 0x1A - EMPTY */
NULL,
/* 0x1B - EMPTY */
NULL,
/* 0x1C - EMPTY */
NULL,
/* 0x1D - EMPTY */
NULL,
/* 0x1E - EMPTY */
NULL,
/* 0x1F - EMPTY */
NULL,
/* 0x20 - TPM2_RC_DISABLED */
"the command is disabled",
/* 0x21 - TPM2_RC_EXCLUSIVE */
"command failed because audit sequence required exclusivity",
/* 0x22 - EMPTY */
NULL,
/* 0x23 - EMPTY, */
NULL,
/* 0x24 - TPM2_RC_AUTH_TYPE */
"authorization handle is not correct for command",
/* 0x25 - TPM2_RC_AUTH_MISSING */
"command requires an authorization session for handle and it is"
" not present",
/* 0x26 - TPM2_RC_POLICY */
"policy failure in math operation or an invalid authPolicy value",
/* 0x27 - TPM2_RC_PCR */
"PCR check fail",
/* 0x28 - TPM2_RC_PCR_CHANGED */
"PCR have changed since checked",
/* 0x29 - EMPTY */
NULL,
/* 0x2A - EMPTY */
NULL,
/* 0x2B - EMPTY */
NULL,
/* 0x2C - EMPTY */
NULL,
/* 0x2D - TPM2_RC_UPGRADE */
"For all commands, other than TPM2_FieldUpgradeData, "
"this code indicates that the TPM is in field upgrade mode. "
"For TPM2_FieldUpgradeData, this code indicates that the TPM "
"is not in field upgrade mode",
/* 0x2E - TPM2_RC_TOO_MANY_CONTEXTS */
"context ID counter is at maximum",
/* 0x2F - TPM2_RC_AUTH_UNAVAILABLE */
"authValue or authPolicy is not available for selected entity",
/* 0x30 - TPM2_RC_REBOOT */
"a _TPM_Init and StartupCLEAR is required before the TPM can"
" resume operation",
/* 0x31 - TPM2_RC_UNBALANCED */
"the protection algorithms hash and symmetric are not reasonably"
" balanced. The digest size of the hash must be larger than the key"
" size of the symmetric algorithm.",
/* 0x32 - EMPTY */
NULL,
/* 0x33 - EMPTY */
NULL,
/* 0x34 - EMPTY */
NULL,
/* 0x35 - EMPTY */
NULL,
/* 0x36 - EMPTY */
NULL,
/* 0x37 - EMPTY */
NULL,
/* 0x38 - EMPTY */
NULL,
/* 0x39 - EMPTY */
NULL,
/* 0x3A - EMPTY */
NULL,
/* 0x3B - EMPTY */
NULL,
/* 0x3C - EMPTY */
NULL,
/* 0x3D - EMPTY */
NULL,
/* 0x3E - EMPTY */
NULL,
/* 0x3F - EMPTY */
NULL,
/* 0x40 - EMPTY */
NULL,
/* 0x41 - EMPTY */
NULL,
/* 0x42 - TPM2_RC_COMMAND_SIZE */
"command commandSize value is inconsistent with contents of the"
" command buffer. Either the size is not the same as the octets"
" loaded by the hardware interface layer or the value is not large"
" enough to hold a command header",
/* 0x43 - TPM2_RC_COMMAND_CODE */
"command code not supported",
/* 0x44 - TPM2_RC_AUTHSIZE */
"the value of authorizationSize is out of range or the number of"
" octets in the Authorization Area is greater than required",
/* 0x45 - TPM2_RC_AUTH_CONTEXT */
"use of an authorization session with a context command or another"
" command that cannot have an authorization session",
/* 0x46 - TPM2_RC_NV_RANGE */
"NV offset+size is out of range",
/* 0x47 - TPM2_RC_NV_SIZE */
"Requested allocation size is larger than allowed",
/* 0x48 - TPM2_RC_NV_LOCKED */
"NV access locked",
/* 0x49 - TPM2_RC_NV_AUTHORIZATION */
"NV access authorization fails in command actions",
/* 0x4A - TPM2_RC_NV_UNINITIALIZED */
"an NV Index is used before being initialized or the state saved"
" by TPM2_ShutdownSTATE could not be restored",
/* 0x4B - TPM2_RC_NV_SPACE */
"insufficient space for NV allocation",
/* 0x4C - TPM2_RC_NV_DEFINED */
"NV Index or persistent object already defined",
/* 0x4D - EMPTY */
NULL,
/* 0x4E - EMPTY */
NULL,
/* 0x4F - EMPTY */
NULL,
/* 0x50 - TPM2_RC_BAD_CONTEXT */
"context in TPM2_ContextLoad is not valid",
/* 0x51 - TPM2_RC_CPHASH */
"cpHash value already set or not correct for use",
/* 0x52 - TPM2_RC_PARENT */
"handle for parent is not a valid parent",
/* 0x53 - TPM2_RC_NEEDS_TEST */
"some function needs testing",
/* 0x54 - TPM2_RC_NO_RESULT */
"returned when an internal function cannot process a request due to"
" an unspecified problem. This code is usually related to invalid"
" parameters that are not properly filtered by the input"
" unmarshaling code",
/* 0x55 - TPM2_RC_SENSITIVE */
"the sensitive area did not unmarshal correctly after decryption",
};
static __thread char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
clearbuf(buf);
char *e = tpm2_rc_fmt0_S_get(rc) ? "warn" : "error";
char *v = tpm2_rc_tpm_fmt0_V_get(rc) ? "2.0" : "1.2";
catbuf(buf, "%s(%s): ", e, v);
UINT8 errnum = tpm2_rc_fmt0_error_get(rc);
/* We only have version 2.0 spec codes defined */
if (tpm2_rc_tpm_fmt0_V_get(rc)) {
/* TCG specific error code */
if (tpm2_rc_fmt0_T_get(rc)) {
catbuf(buf, "Vendor specific error: 0x%X", errnum);
return buf;
}
/* is it a warning (version 2 error string) or is it a 1.2 error? */
size_t len =
tpm2_rc_fmt0_S_get(rc) ?
ARRAY_LEN(fmt0_warn_strs) : ARRAY_LEN(fmt0_err_strs);
const char **selection =
tpm2_rc_fmt0_S_get(rc) ? fmt0_warn_strs : fmt0_err_strs;
if (errnum >= len) {
return NULL;
}
const char *m = selection[errnum];
if (!m) {
return NULL;
}
catbuf(buf, "%s", m);
return buf;
}
catbuf(buf, "%s", "unknown version 1.2 error code");
return buf;
}
/**
* Retrieves the layer field from a TSS2_RC code.
* @param rc
* The rc to query the layer index of.
* @return
* The layer index.
*/
static inline UINT8
tss2_rc_layer_format_get(TSS2_RC rc)
{
return ((rc & (1 << 7)) >> 7);
}
/**
* Handler for tpm2 error codes. ie codes
* coming from the tpm layer aka layer 0.
* @param rc
* The rc to decode.
* @return
* An error string.
*/
static const char *
tpm2_ehandler(TSS2_RC rc)
{
bool is_fmt_1 = tss2_rc_layer_format_get(rc);
return is_fmt_1 ? tpm2_err_handler_fmt1(rc) : tpm2_err_handler_fmt0(rc);
}
/**
* The default system code handler. This handles codes
* from the RM (itself and simulated tpm responses), the marshaling
* library (mu), the tcti layers, sapi, esys and fapi.
* @param rc
* The rc to decode.
* @return
* An error string.
*/
static const char *
tss_err_handler (TSS2_RC rc)
{
/*
* subtract 1 from the error number
* before indexing into this array.
*
* Commented offsets are for the corresponding
* error number *before* subtraction. Ie error
* number 4 is at array index 3.
*/
static const char *errors[] = {
/* 1 - TSS2_BASE_RC_GENERAL_FAILURE */
"Catch all for all errors not otherwise specified",
/* 2 - TSS2_BASE_RC_NOT_IMPLEMENTED */
"If called functionality isn't implemented",
/* 3 - TSS2_BASE_RC_BAD_CONTEXT */
"A context structure is bad",
/* 4 - TSS2_BASE_RC_ABI_MISMATCH */
"Passed in ABI version doesn't match called module's ABI version",
/* 5 - TSS2_BASE_RC_BAD_REFERENCE */
"A pointer is NULL that isn't allowed to be NULL.",
/* 6 - TSS2_BASE_RC_INSUFFICIENT_BUFFER */
"A buffer isn't large enough",
/* 7 - TSS2_BASE_RC_BAD_SEQUENCE */
"Function called in the wrong order",
/* 8 - TSS2_BASE_RC_NO_CONNECTION */
"Fails to connect to next lower layer",
/* 9 - TSS2_BASE_RC_TRY_AGAIN */
"Operation timed out; function must be called again to be completed",
/* 10 - TSS2_BASE_RC_IO_ERROR */
"IO failure",
/* 11 - TSS2_BASE_RC_BAD_VALUE */
"A parameter has a bad value",
/* 12 - TSS2_BASE_RC_NOT_PERMITTED */
"Operation not permitted.",
/* 13 - TSS2_BASE_RC_INVALID_SESSIONS */
"Session structures were sent, but command doesn't use them or doesn't"
" use the specified number of them",
/* 14 - TSS2_BASE_RC_NO_DECRYPT_PARAM */
"If function called that uses decrypt parameter, but command doesn't"
" support decrypt parameter.",
/* 15 - TSS2_BASE_RC_NO_ENCRYPT_PARAM */
"If function called that uses encrypt parameter, but command doesn't"
" support decrypt parameter.",
/* 16 - TSS2_BASE_RC_BAD_SIZE */
"If size of a parameter is incorrect",
/* 17 - TSS2_BASE_RC_MALFORMED_RESPONSE */
"Response is malformed",
/* 18 - TSS2_BASE_RC_INSUFFICIENT_CONTEXT */
"Context not large enough",
/* 19 - TSS2_BASE_RC_INSUFFICIENT_RESPONSE */
"Response is not long enough",
/* 20 - TSS2_BASE_RC_INCOMPATIBLE_TCTI */
"Unknown or unusable TCTI version",
/* 21 - TSS2_BASE_RC_NOT_SUPPORTED */
"Functionality not supported",
/* 22 - TSS2_BASE_RC_BAD_TCTI_STRUCTURE */
"TCTI context is bad",
/* 23 - TSS2_BASE_RC_MEMORY */
"Failed to allocate memory",
/* 24 - TSS2_BASE_RC_BAD_TR */
"The ESYS_TR resource object is bad",
/* 25 - TSS2_BASE_RC_MULTIPLE_DECRYPT_SESSIONS */
"Multiple sessions were marked with attribute decrypt",
/* 26 - TSS2_BASE_RC_MULTIPLE_ENCRYPT_SESSIONS */
"Multiple sessions were marked with attribute encrypt",
/* 27 - TSS2_BASE_RC_RSP_AUTH_FAILED */
"Authorizing the TPM response failed",
/* 28 - TSS2_BASE_RC_NO_CONFIG */
"No config is available",
/* 29 - TSS2_BASE_RC_BAD_PATH */
"The provided path is bad",
/* 30 - TSS2_BASE_RC_NOT_DELETABLE */
"The object is not deletable",
/* 31 - TSS2_BASE_RC_PATH_ALREADY_EXISTS */
"The provided path already exists",
/* 32 - TSS2_BASE_RC_KEY_NOT_FOUND */
"The key was not found",
/* 33 - TSS2_BASE_RC_SIGNATURE_VERIFICATION_FAILED */
"Signature verification failed",
/* 34 - TSS2_BASE_RC_HASH_MISMATCH */
"Hashes mismatch",
/* 35 - TSS2_BASE_RC_KEY_NOT_DUPLICABLE */
"Key is not duplicatable",
/* 36 - TSS2_BASE_RC_PATH_NOT_FOUND */
"The path was not found",
/* 37 - TSS2_BASE_RC_NO_CERT */
"No certificate",
/* 38 - TSS2_BASE_RC_NO_PCR */
"No PCR",
/* 39 - TSS2_BASE_RC_PCR_NOT_RESETTABLE */
"PCR not resettable",
/* 40 - TSS2_BASE_RC_BAD_TEMPLATE */
"The template is bad",
/* 41 - TSS2_BASE_RC_AUTHORIZATION_FAILED */
"Authorization failed",
/* 42 - TSS2_BASE_RC_AUTHORIZATION_UNKNOWN */
"Authorization is unknown",
/* 43 - TSS2_BASE_RC_NV_NOT_READABLE */
"NV is not readable",
/* 44 - TSS2_BASE_RC_NV_TOO_SMALL */
"NV is too small",
/* 45 - TSS2_BASE_RC_NV_NOT_WRITEABLE */
"NV is not writable",
/* 46 - TSS2_BASE_RC_POLICY_UNKNOWN */
"The policy is unknown",
/* 47 - TSS2_BASE_RC_NV_WRONG_TYPE */
"The NV type is wrong",
/* 48 - TSS2_BASE_RC_NAME_ALREADY_EXISTS */
"The name already exists",
/* 49 - TSS2_BASE_RC_NO_TPM */
"No TPM available",
/* 50 - TSS2_BASE_RC_BAD_KEY */
"The key is bad",
/* 51 - TSS2_BASE_RC_NO_HANDLE */
"No handle provided",
/* 52 - TSS2_BASE_RC_NOT_PROVISIONED */
"Provisioning was not executed.",
/* 53 - TSS2_FAPI_RC_ALREADY_PROVISIONED */
"Already provisioned"
};
return (rc - 1u < ARRAY_LEN(errors)) ? errors[rc - 1u] : NULL;
}
static struct {
char name[TSS2_ERR_LAYER_NAME_MAX];
TSS2_RC_HANDLER handler;
} layer_handler[TPM2_ERROR_TSS2_RC_LAYER_COUNT] = {
ADD_HANDLER("tpm" , tpm2_ehandler),
ADD_NULL_HANDLER, /* layer 1 is unused */
ADD_NULL_HANDLER, /* layer 2 is unused */
ADD_NULL_HANDLER, /* layer 3 is unused */
ADD_NULL_HANDLER, /* layer 4 is unused */
ADD_NULL_HANDLER, /* layer 5 is unused */
ADD_HANDLER("fapi", tss_err_handler), /* layer 6 is the fapi rc */
ADD_HANDLER("esapi", tss_err_handler), /* layer 7 is the esapi rc */
ADD_HANDLER("sys", tss_err_handler), /* layer 8 is the sys rc */
ADD_HANDLER("mu", tss_err_handler), /* layer 9 is the mu rc */
/* Defaults to the system handler */
ADD_HANDLER("tcti", tss_err_handler), /* layer 10 is the tcti rc */
/* Defaults to the system handler */
ADD_HANDLER("rmt", tpm2_ehandler), /* layer 11 is the resource manager TPM RC */
/* The RM usually duplicates TPM responses */
/* So just default the handler to tpm2. */
ADD_HANDLER("rm", NULL), /* layer 12 is the rm rc */
ADD_HANDLER("drvr", NULL), /* layer 13 is the driver rc */
};
/**
* If a layer has no handler registered, default to this
* handler that prints the error number in hex.
* @param rc
* The rc to print the error number of.
* @return
* The string.
*/
static const char *
unknown_layer_handler(TSS2_RC rc)
{
static __thread char buf[32];
clearbuf(buf);
catbuf(buf, "0x%X", tpm2_error_get(rc));
return buf;
}
/**
* Register or unregister a custom layer error handler.
* @param layer
* The layer in which to register a handler for.
* @param name
* A friendly layer name. If the name is NULL or a
* length 0 string, then the name is output in base
* 10 string of the layer number. If the length of
* name is greater than 16 characters, then the string
* is truncated to 16 characters.
* @param handler
* The handler function to register or NULL to unregister.
* @return
* True on success or False on error.
*/
TSS2_RC_HANDLER
Tss2_RC_SetHandler(UINT8 layer, const char *name,
TSS2_RC_HANDLER handler)
{
TSS2_RC_HANDLER old = layer_handler[layer].handler;
layer_handler[layer].handler = handler;
if (handler && name) {
snprintf(layer_handler[layer].name, sizeof(layer_handler[layer].name),
"%s", name);
} else {
memset(layer_handler[layer].name, 0, sizeof(layer_handler[layer].name));
}
return old;
}
/**
* Given a TSS2_RC return code, provides a static error string in the format:
* <layer-name>:<layer-specific-msg>.
*
* The layer-name section will either be the friendly name, or if no layer
* handler is registered, the base10 layer number.
*
* The "layer-specific-msg" is layer specific and will contain details on the
* error that occurred or the error code if it couldn't look it up.
*
* Known layer specific substrings:
* TPM - The tpm layer produces 2 distinct format codes that align with:
* - Section 6.6 of: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
* - Section 39.4 of: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf
*
* The two formats are format 0 and format 1.
* Format 0 string format:
* - "<error|warn>(<version>): <description>
* - Examples:
* - error(1.2): bad tag
* - warn(2.0): the 1st handle in the handle area references a transient object or session that is not loaded
*
* Format 1 string format:
* - <handle|session|parameter>(<index>):<description>
* - Examples:
* - handle(unk):value is out of range or is not correct for the context
* - tpm:handle(5):value is out of range or is not correct for the context
*
* Note that passing TPM2_RC_SUCCESS results in the layer specific message of "success".
*
* The System, TCTI and Marshaling (MU) layers, all define simple string
* returns analogous to strerror(3).
*
* Unknown layers will have the layer number in decimal and then a layer specific string of
* a hex value representing the error code. For example: 9:0x3
*
* @param rc
* The error code to decode.
* @return
* A human understandable error description string.
*/
const char *
Tss2_RC_Decode(TSS2_RC rc)
{
static __thread char buf[TSS2_ERR_LAYER_NAME_MAX + TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
clearbuf(buf);
UINT8 layer = tss2_rc_layer_number_get(rc);
TSS2_RC_HANDLER handler = layer_handler[layer].handler;
const char *lname = layer_handler[layer].name;
if (lname[0]) {
catbuf(buf, "%s:", lname);
} else {
catbuf(buf, "%u:", layer);
}
handler = !handler ? unknown_layer_handler : handler;
/*
* Handlers only need the error bits. This way they don't
* need to concern themselves with masking off the layer
* bits or anything else.
*/
UINT16 err_bits = tpm2_error_get(rc);
const char *e = err_bits ? handler(err_bits) : "success";
if (e) {
catbuf(buf, "%s", e);
} else {
catbuf(buf, "0x%X", err_bits);
}
return buf;
}