diff options
Diffstat (limited to 'TPM2-Plugin/lib/tpm2_error.c')
-rw-r--r-- | TPM2-Plugin/lib/tpm2_error.c | 870 |
1 files changed, 870 insertions, 0 deletions
diff --git a/TPM2-Plugin/lib/tpm2_error.c b/TPM2-Plugin/lib/tpm2_error.c new file mode 100644 index 0000000..7bc024d --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_error.c @@ -0,0 +1,870 @@ +//**********************************************************************; +// Copyright (c) 2018, 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 <stdarg.h> +#include <stdbool.h> +#include <stdio.h> + +#include <sapi/tpm20.h> + +#include "tpm2_error.h" +#include "tpm2_util.h" + +/** + * The maximum size of a layer name. + */ +#define TSS2_ERR_LAYER_NAME_MAX 4 + +/** + * 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); +} + +/** + * 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 UINT16 tpm2_rc_fmt1_error_get(TPM2_RC rc) { + return (rc & 0x3F); +} + +static inline UINT16 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(NULL, 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 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 object/session 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 self-tests", + // 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, + // 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 authorization session handle references a session that" + " is not loaded", + // 0x1D - TPM2_RC_REFERENCE_S5 + "the 6th authorization 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", + // 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 + "TPM is in field upgrade mode unless called via" + " TPM2_FieldUpgradeData(), then it 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 Startup(CLEAR) 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_Shutdown(STATE) 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 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 simlated tpm responses), the marshaling + * library (mu), and the tcti layers. + * @param rc + * The rc to decode. + * @return + * An error string. + */ +static const char *sys_err_handler (TSS2_RC rc) { + UNUSED(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" + }; + + return (rc - 1u < ARRAY_LEN(errors)) ? errors[rc - 1u] : NULL; +} + + +static struct { + const char *name; + tpm2_error_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_NULL_HANDLER, // layer 6 is the feature rc + ADD_HANDLER("fapi", NULL), // layer 7 is the esapi rc + ADD_HANDLER("sys", sys_err_handler), // layer 8 is the sys rc + ADD_HANDLER("mu", sys_err_handler), // layer 9 is the mu rc + // Defaults to the system handler + ADD_HANDLER("tcti", sys_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 +}; + +/** + * Determines if the layer allowed to be registered to. + * @param layer + * The layer to determine handler assignment eligibility of. + * @return + * True if it is reserved and thus non-assignable, false otherwise. + */ +static bool is_reserved_layer(UINT8 layer) { + return layer == 0; +} + +/** + * 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 *unkown_layer_handler(TSS2_RC rc) { + UNUSED(rc); + + static 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. It is an error + * to register for the following reserved layers: + * - TSS2_TPM_RC_LAYER - layer 0 + * - TSS2_SYS_RC_LAYER - layer 8 + * - TSS2_MU_RC_LAYER - layer 9 + * - TSS2_TCTI_RC_LAYER - layer 10 + * @param name + * A friendly layer name. It is an error for the name to be of + * length 0 or greater than 4. + * @param handler + * The handler function to register or NULL to unregister. + * @return + * True on success or False on error. + */ +bool tpm2_error_set_handler(UINT8 layer, const char *name, + tpm2_error_handler handler) { + + /* don't allow setting reserved layers */ + if (is_reserved_layer(layer)) { + return false; + } + + /* + * if they are clearing the handler, name doesn't matter + * clear it too. + */ + if (!handler) { + name = NULL; + } + + /* Perform a zero and max-name length check if name is being set */ + if (name) { + size_t len = name ? strlen(name) : 0; + if (!len || len > TSS2_ERR_LAYER_NAME_MAX) + return false; + } + + layer_handler[layer].handler = handler; + layer_handler[layer].name = name; + + return true; +} + +const char * tpm2_error_str(TSS2_RC rc) { + + static char buf[TSS2_ERR_LAYER_NAME_MAX + TSS2_ERR_LAYER_ERROR_STR_MAX + 1]; + + clearbuf(buf); + + UINT8 layer = tss2_rc_layer_number_get(rc); + + tpm2_error_handler handler = layer_handler[layer].handler; + const char *lname = layer_handler[layer].name; + + if (lname) { + catbuf(buf, "%s:", lname); + } else { + catbuf(buf, "%u:", layer); + } + + handler = !handler ? unkown_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; +} |