1 //**********************************************************************;
2 // Copyright (c) 2018, Intel Corporation
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 // THE POSSIBILITY OF SUCH DAMAGE.
26 //**********************************************************************;
33 #include <tss2/tss2_sys.h>
35 #include "tpm2_error.h"
36 #include "tpm2_util.h"
39 * The maximum size of a layer name.
41 #define TSS2_ERR_LAYER_NAME_MAX 4
44 * The maximum size for layer specific error strings.
46 #define TSS2_ERR_LAYER_ERROR_STR_MAX 512
49 * Concatenates (safely) onto a static buffer given a format and varaidic
50 * arguments similar to sprintf.
52 * The static buffer to concatenate onto.
54 * The format specifier as understood by printf followed by the variadic
55 * parameters for the specifier.
57 #define catbuf(b, fmt, ...) _catbuf(b, sizeof(b), fmt, ##__VA_ARGS__)
60 * Clears out a static buffer by setting index 0 to the null byte.
62 * The buffer to clear out.
64 static void clearbuf(char *buffer) {
69 * Prints to a buffer using snprintf(3) using the supplied fmt
70 * and varaiadic arguments.
72 * The buffer to print into.
74 * The length of that buffer.
78 * DO NOT CALL DIRECTLY, use the catbuf() macro.
80 static void COMPILER_ATTR(format (printf, 3, 4))
81 _catbuf(char *buf, size_t len, const char *fmt, ...) {
83 va_start(argptr, fmt);
84 size_t offset = strlen(buf);
85 vsnprintf(&buf[offset], len - offset, fmt, argptr);
90 * Retrieves the layer number. The layer number is in the 3rd
91 * octet and is thus 1 byte big.
94 * The rc to query for the layer number.
98 static inline UINT8 tss2_rc_layer_number_get(TSS2_RC rc) {
99 return ((rc & TSS2_RC_LAYER_MASK) >> TSS2_RC_LAYER_SHIFT);
103 * Queries a TPM format 1 error codes N field. The N field
104 * is a 4 bit field located at bits 8:12.
106 * The rc to query the N field for.
110 static inline UINT8 tpm2_rc_fmt1_N_get(TPM2_RC rc) {
111 return ((rc & (0xF << 8)) >> 8);
115 * Queries the index bits out of the N field contained in a TPM format 1
116 * error code. The index bits are the low 3 bits of the N field.
118 * The TPM format 1 error code to query for the index bits.
120 * The index bits from the N field.
122 static inline UINT8 tpm2_rc_fmt1_N_index_get(TPM2_RC rc) {
123 return (tpm2_rc_fmt1_N_get(rc) & 0x7);
127 * Determines if the N field in a TPM format 1 error code is
130 * The TPM format 1 error code to query.
132 * True if it is a handle, false otherwise.
134 static inline bool tpm2_rc_fmt1_N_is_handle(TPM2_RC rc) {
135 return ((tpm2_rc_fmt1_N_get(rc) & 0x8) == 0);
138 static inline UINT8 tpm2_rc_fmt1_P_get(TPM2_RC rc) {
139 return ((rc & (1 << 6)) >> 6);
142 static inline UINT16 tpm2_rc_fmt1_error_get(TPM2_RC rc) {
146 static inline UINT16 tpm2_rc_fmt0_error_get(TPM2_RC rc) {
150 static inline UINT8 tpm2_rc_tpm_fmt0_V_get(TPM2_RC rc) {
151 return ((rc & (1 << 8)) >> 8);
154 static inline UINT8 tpm2_rc_fmt0_T_get(TPM2_RC rc) {
155 return ((rc & (1 << 10)) >> 8);
158 static inline UINT8 tpm2_rc_fmt0_S_get(TSS2_RC rc) {
159 return ((rc & (1 << 11)) >> 8);
163 * Helper macro for adding a layer handler to the layer
164 * registration array.
166 #define ADD_HANDLER(name, handler) \
170 * Same as ADD_HANDLER but sets it to NULL. Used as a placeholder
171 * for non-registered indexes into the handler array.
173 #define ADD_NULL_HANDLER ADD_HANDLER(NULL, NULL)
175 static const char *tpm2_err_handler_fmt1(TPM2_RC rc) {
178 * format 1 error codes start at 1, so
179 * add a NULL entry to index 0.
181 static const char *fmt1_err_strs[] = {
184 // 0x1 - TPM2_RC_ASYMMETRIC
185 "asymmetric algorithm not supported or not correct",
186 // 0x2 - TPM2_RC_ATTRIBUTES
187 "inconsistent attributes",
188 // 0x3 - TPM2_RC_HASH
189 "hash algorithm not supported or not appropriate",
190 // 0x4 - TPM2_RC_VALUE
191 "value is out of range or is not correct for the context",
192 // 0x5 - TPM2_RC_HIERARCHY
193 "hierarchy is not enabled or is not correct for the use",
196 // 0x7 - TPM2_RC_KEY_SIZE
197 "key size is not supported",
199 "mask generation function not supported",
200 // 0x9 - TPM2_RC_MODE
201 "mode of operation not supported",
202 // 0xA - TPM2_RC_TYPE
203 "the type of the value is not appropriate for the use",
204 // 0xB - TPM2_RC_HANDLE
205 "the handle is not correct for the use",
207 "unsupported key derivation function or function not appropriate for "
209 // 0xD - TPM2_RC_RANGE
210 "value was out of allowed range",
211 // 0xE - TPM2_RC_AUTH_FAIL
212 "the authorization HMAC check failed and DA counter incremented",
213 // 0xF - TPM2_RC_NONCE
214 "invalid nonce size or nonce value mismatch",
216 "authorization requires assertion of PP",
219 // 0x12 - TPM2_RC_SCHEME
220 "unsupported or incompatible scheme",
225 // 0x15 - TPM2_RC_SIZE
226 "structure is the wrong size",
227 // 0x16 - TPM2_RC_SYMMETRIC
228 "unsupported symmetric algorithm or key size, or not appropriate for"
230 // 0x17 - TPM2_RC_TAG
231 "incorrect structure tag",
232 // 0x18 - TPM2_RC_SELECTOR
233 "union selector is incorrect",
236 // 0x1A - TPM2_RC_INSUFFICIENT
237 "the TPM was unable to unmarshal a value because there were not enough"
238 " octets in the input buffer",
239 // 0x1B - TPM2_RC_SIGNATURE
240 "the signature is not valid",
241 // 0x1C - TPM2_RC_KEY
242 "key fields are not compatible with the selected use",
243 // 0x1D - TPM2_RC_POLICY_FAIL
244 "a policy check failed",
247 // 0x1F - TPM2_RC_INTEGRITY
248 "integrity check failed",
249 // 0x20 - TPM2_RC_TICKET
251 // 0x21 - TPM2_RC_RESERVED_BITS
252 "reserved bits not set to zero as required",
253 // 0x22 - TPM2_RC_BAD_AUTH
254 "authorization failure without DA implications",
255 // 0x23 - TPM2_RC_EXPIRED
256 "the policy has expired",
257 // 0x24 - TPM2_RC_POLICY_CC
258 "the commandCode in the policy is not the commandCode of the command"
259 " or the command code in a policy command references a command that"
260 " is not implemented",
261 // 0x25 - TPM2_RC_BINDING
262 "public and sensitive portions of an object are not cryptographically bound",
263 // 0x26 - TPM2_RC_CURVE
264 "curve not supported",
265 // 0x27 - TPM2_RC_ECC_POINT
266 "point is not on the required curve",
269 static char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
273 /* Print whether or not the error is caused by a bad
274 * handle or parameter. On the case of a Handle (P == 0)
275 * then the N field top bit will be set. Un-set this bit
276 * to get the handle index by subtracting 8 as N is a 4
279 * the lower 3 bits of N indicate index, and the high bit
282 UINT8 index = tpm2_rc_fmt1_N_index_get(rc);
284 bool is_handle = tpm2_rc_fmt1_N_is_handle(rc);
285 const char *m = tpm2_rc_fmt1_P_get(rc) ? "parameter" :
286 is_handle ? "handle" : "session";
287 catbuf(buf, "%s", m);
290 catbuf(buf, "(%u):", index);
292 catbuf(buf, "%s", "(unk):");
295 UINT8 errnum = tpm2_rc_fmt1_error_get(rc);
296 if (errnum < ARRAY_LEN(fmt1_err_strs)) {
297 m = fmt1_err_strs[errnum];
298 catbuf(buf, "%s", m);
300 catbuf(buf, "unknown error num: 0x%X", errnum);
306 static const char *tpm2_err_handler_fmt0(TSS2_RC rc) {
309 * format 0 error codes start at 1, so
310 * add a NULL entry to index 0.
311 * Thus, no need to offset the error bits
312 * and fmt0 and fmt1 arrays can be used
313 * in-place of each other for lookups.
315 static const char *fmt0_warn_strs[] = {
318 // 0x1 - TPM2_RC_CONTEXT_GAP
319 "gap for context ID is too large",
320 // 0x2 - TPM2_RC_OBJECT_MEMORY
321 "out of memory for object contexts",
322 // 0x3 - TPM2_RC_SESSION_MEMORY
323 "out of memory for session contexts",
324 // 0x4 - TPM2_RC_MEMORY
325 "out of shared object/session memory or need space for internal"
327 // 0x5 - TPM2_RC_SESSION_HANDLES
328 "out of session handles",
329 // 0x6 - TPM2_RC_OBJECT_HANDLES
330 "out of object handles",
331 // 0x7 - TPM2_RC_LOCALITY
333 // 0x8 - TPM2_RC_YIELDED
334 "the TPM has suspended operation on the command; forward progress"
335 " was made and the command may be retried",
336 // 0x9 - TPM2_RC_CANCELED
337 "the command was canceled",
338 // 0xA - TPM2_RC_TESTING
339 "TPM is performing self-tests",
350 // 0x10 - TPM2_RC_REFERENCE_H0
351 "the 1st handle in the handle area references a transient object"
352 " or session that is not loaded",
353 // 0x11 - TPM2_RC_REFERENCE_H1
354 "the 2nd handle in the handle area references a transient object"
355 " or session that is not loaded",
356 // 0x12 - TPM2_RC_REFERENCE_H2
357 "the 3rd handle in the handle area references a transient object"
358 " or session that is not loaded",
359 // 0x13 - TPM2_RC_REFERENCE_H3
360 "the 4th handle in the handle area references a transient object"
361 " or session that is not loaded",
362 // 0x14 - TPM2_RC_REFERENCE_H4
363 "the 5th handle in the handle area references a transient object"
364 " or session that is not loaded",
365 // 0x15 - TPM2_RC_REFERENCE_H5
366 "the 6th handle in the handle area references a transient object"
367 " or session that is not loaded",
368 // 0x16 - TPM2_RC_REFERENCE_H6
369 "the 7th handle in the handle area references a transient object"
370 " or session that is not loaded",
372 // 0x18 - TPM2_RC_REFERENCE_S0
373 "the 1st authorization session handle references a session that"
375 // 0x19 - TPM2_RC_REFERENCE_S1
376 "the 2nd authorization session handle references a session that"
378 // 0x1A - TPM2_RC_REFERENCE_S2
379 "the 3rd authorization session handle references a session that"
381 // 0x1B - TPM2_RC_REFERENCE_S3
382 "the 4th authorization session handle references a session that"
384 // 0x1C - TPM2_RC_REFERENCE_S4
385 "the 5th authorization session handle references a session that"
387 // 0x1D - TPM2_RC_REFERENCE_S5
388 "the 6th authorization session handle references a session that"
390 // 0x1E - TPM2_RC_REFERENCE_S6
391 "the 7th authorization session handle references a session that"
393 // 0x20 -TPM2_RC_NV_RATE
394 "the TPM is rate-limiting accesses to prevent wearout of NV",
395 // 0x21 - TPM2_RC_LOCKOUT
396 "authorizations for objects subject to DA protection are not"
397 " allowed at this time because the TPM is in DA lockout mode",
398 // 0x22 - TPM2_RC_RETRY
399 "the TPM was not able to start the command",
400 // 0x23 - TPM2_RC_NV_UNAVAILABLE
401 "the command may require writing of NV and NV is not current"
406 * format 1 error codes start at 0, so
407 * no need to offset the error bits.
409 static const char *fmt0_err_strs[] = {
410 // 0x0 - TPM2_RC_INITIALIZE
411 "TPM not initialized by TPM2_Startup or already initialized",
412 // 0x1 - TPM2_RC_FAILURE
413 "commands not being accepted because of a TPM failure",
416 // 0x3 - TPM2_RC_SEQUENCE
417 "improper use of a sequence handle",
432 // 0xB - TPM2_RC_PRIVATE
433 "not currently used",
460 // 0x19 - TPM2_RC_HMAC
461 "not currently used",
474 // 0x20 - TPM2_RC_DISABLED
475 "the command is disabled",
476 // 0x21 - TPM2_RC_EXCLUSIVE
477 "command failed because audit sequence required exclusivity",
482 // 0x24 - TPM2_RC_AUTH_TYPE
483 "authorization handle is not correct for command",
484 // 0x25 - TPM2_RC_AUTH_MISSING
485 "command requires an authorization session for handle and it is"
487 // 0x26 - TPM2_RC_POLICY
488 "policy failure in math operation or an invalid authPolicy value",
489 // 0x27 - TPM2_RC_PCR
491 // 0x28 - TPM2_RC_PCR_CHANGED
492 "PCR have changed since checked",
501 // 0x2D - TPM2_RC_UPGRADE
502 "TPM is in field upgrade mode unless called via"
503 " TPM2_FieldUpgradeData(), then it is not in field upgrade mode",
504 // 0x2E - TPM2_RC_TOO_MANY_CONTEXTS
505 "context ID counter is at maximum",
506 // 0x2F - TPM2_RC_AUTH_UNAVAILABLE
507 "authValue or authPolicy is not available for selected entity",
508 // 0x30 - TPM2_RC_REBOOT
509 "a _TPM_Init and Startup(CLEAR) is required before the TPM can"
511 // 0x31 - TPM2_RC_UNBALANCED
512 "the protection algorithms (hash and symmetric) are not reasonably"
513 " balanced. The digest size of the hash must be larger than the key"
514 " size of the symmetric algorithm.",
547 // 0x42 - TPM2_RC_COMMAND_SIZE
548 "command commandSize value is inconsistent with contents of the"
549 " command buffer; either the size is not the same as the octets"
550 " loaded by the hardware interface layer or the value is not large"
551 " enough to hold a command header",
552 // 0x43 - TPM2_RC_COMMAND_CODE
553 "command code not supported",
554 // 0x44 - TPM2_RC_AUTHSIZE
555 "the value of authorizationSize is out of range or the number of"
556 " octets in the Authorization Area is greater than required",
557 // 0x45 - TPM2_RC_AUTH_CONTEXT
558 "use of an authorization session with a context command or another"
559 " command that cannot have an authorization session",
560 // 0x46 - TPM2_RC_NV_RANGE
561 "NV offset+size is out of range",
562 // 0x47 - TPM2_RC_NV_SIZE
563 "Requested allocation size is larger than allowed",
564 // 0x48 - TPM2_RC_NV_LOCKED
566 // 0x49 - TPM2_RC_NV_AUTHORIZATION
567 "NV access authorization fails in command actions",
568 // 0x4A - TPM2_RC_NV_UNINITIALIZED
569 "an NV Index is used before being initialized or the state saved"
570 " by TPM2_Shutdown(STATE) could not be restored",
571 // 0x4B - TPM2_RC_NV_SPACE
572 "insufficient space for NV allocation",
573 // 0x4C - TPM2_RC_NV_DEFINED
574 "NV Index or persistent object already defined",
581 // 0x50 - TPM2_RC_BAD_CONTEXT
582 "context in TPM2_ContextLoad() is not valid",
583 // 0x51 - TPM2_RC_CPHASH
584 "cpHash value already set or not correct for use",
585 // 0x52 - TPM2_RC_PARENT
586 "handle for parent is not a valid parent",
587 // 0x53 - TPM2_RC_NEEDS_TEST
588 "some function needs testing",
589 // 0x54 - TPM2_RC_NO_RESULT
590 "returned when an internal function cannot process a request due to"
591 " an unspecified problem. This code is usually related to invalid"
592 " parameters that are not properly filtered by the input"
593 " unmarshaling code",
594 // 0x55 - TPM2_RC_SENSITIVE
595 "the sensitive area did not unmarshal correctly after decryption",
598 static char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
602 char *e = tpm2_rc_fmt0_S_get(rc) ? "warn" : "error";
603 char *v = tpm2_rc_tpm_fmt0_V_get(rc) ? "2.0" : "1.2";
604 catbuf(buf, "%s(%s): ", e, v);
606 UINT8 errnum = tpm2_rc_fmt0_error_get(rc);
607 /* We only have version 2.0 spec codes defined */
608 if (tpm2_rc_tpm_fmt0_V_get(rc)) {
609 /* TCG specific error code */
610 if (tpm2_rc_fmt0_T_get(rc)) {
611 catbuf(buf, "Vendor specific error: 0x%X", errnum);
615 /* is it a warning (version 2 error string) or is it a 1.2 error? */
617 tpm2_rc_fmt0_S_get(rc) ?
618 ARRAY_LEN(fmt0_warn_strs) : ARRAY_LEN(fmt0_err_strs);
619 const char **selection =
620 tpm2_rc_fmt0_S_get(rc) ? fmt0_warn_strs : fmt0_err_strs;
625 const char *m = selection[errnum];
630 catbuf(buf, "%s", m);
634 catbuf(buf, "%s", "unknown version 1.2 error code");
640 * Retrieves the layer field from a TSS2_RC code.
642 * The rc to query the layer index of.
646 static inline UINT8 tss2_rc_layer_format_get(TSS2_RC rc) {
648 return ((rc & (1 << 7)) >> 7);
652 * Handler for tpm2 error codes. ie codes
653 * coming from the tpm layer aka layer 0.
659 static const char *tpm2_ehandler(TSS2_RC rc) {
661 bool is_fmt_1 = tss2_rc_layer_format_get(rc);
663 return is_fmt_1 ? tpm2_err_handler_fmt1(rc) : tpm2_err_handler_fmt0(rc);
667 * The default system code handler. This handles codes
668 * from the RM (itself and simlated tpm responses), the marshaling
669 * library (mu), and the tcti layers.
675 static const char *sys_err_handler (TSS2_RC rc) {
679 * subtract 1 from the error number
680 * before indexing into this array.
682 * Commented offsets are for the corresponding
683 * error number *before* subtraction. Ie error
684 * number 4 is at array index 3.
686 static const char *errors[] = {
687 // 1 - TSS2_BASE_RC_GENERAL_FAILURE
688 "Catch all for all errors not otherwise specified",
689 // 2 - TSS2_BASE_RC_NOT_IMPLEMENTED
690 "If called functionality isn't implemented",
691 // 3 - TSS2_BASE_RC_BAD_CONTEXT
692 "A context structure is bad",
693 // 4 - TSS2_BASE_RC_ABI_MISMATCH
694 "Passed in ABI version doesn't match called module's ABI version",
695 // 5 - TSS2_BASE_RC_BAD_REFERENCE
696 "A pointer is NULL that isn't allowed to be NULL.",
697 // 6 - TSS2_BASE_RC_INSUFFICIENT_BUFFER
698 "A buffer isn't large enough",
699 // 7 - TSS2_BASE_RC_BAD_SEQUENCE
700 "Function called in the wrong order",
701 // 8 - TSS2_BASE_RC_NO_CONNECTION
702 "Fails to connect to next lower layer",
703 // 9 - TSS2_BASE_RC_TRY_AGAIN
704 "Operation timed out; function must be called again to be completed",
705 // 10 - TSS2_BASE_RC_IO_ERROR
707 // 11 - TSS2_BASE_RC_BAD_VALUE
708 "A parameter has a bad value",
709 // 12 - TSS2_BASE_RC_NOT_PERMITTED
710 "Operation not permitted.",
711 // 13 - TSS2_BASE_RC_INVALID_SESSIONS
712 "Session structures were sent, but command doesn't use them or doesn't"
713 " use the specified number of them",
714 // 14 - TSS2_BASE_RC_NO_DECRYPT_PARAM
715 "If function called that uses decrypt parameter, but command doesn't"
716 " support decrypt parameter.",
717 // 15 - TSS2_BASE_RC_NO_ENCRYPT_PARAM
718 "If function called that uses encrypt parameter, but command doesn't"
719 " support decrypt parameter.",
720 // 16 - TSS2_BASE_RC_BAD_SIZE
721 "If size of a parameter is incorrect",
722 // 17 - TSS2_BASE_RC_MALFORMED_RESPONSE
723 "Response is malformed",
724 // 18 - TSS2_BASE_RC_INSUFFICIENT_CONTEXT
725 "Context not large enough",
726 // 19 - TSS2_BASE_RC_INSUFFICIENT_RESPONSE
727 "Response is not long enough",
728 // 20 - TSS2_BASE_RC_INCOMPATIBLE_TCTI
729 "Unknown or unusable TCTI version",
730 // 21 - TSS2_BASE_RC_NOT_SUPPORTED
731 "Functionality not supported",
732 // 22 - TSS2_BASE_RC_BAD_TCTI_STRUCTURE
733 "TCTI context is bad"
736 return (rc - 1u < ARRAY_LEN(errors)) ? errors[rc - 1u] : NULL;
742 tpm2_error_handler handler;
743 } layer_handler[TPM2_ERROR_TSS2_RC_LAYER_COUNT] = {
744 ADD_HANDLER("tpm" , tpm2_ehandler),
745 ADD_NULL_HANDLER, // layer 1 is unused
746 ADD_NULL_HANDLER, // layer 2 is unused
747 ADD_NULL_HANDLER, // layer 3 is unused
748 ADD_NULL_HANDLER, // layer 4 is unused
749 ADD_NULL_HANDLER, // layer 5 is unused
750 ADD_NULL_HANDLER, // layer 6 is the feature rc
751 ADD_HANDLER("fapi", NULL), // layer 7 is the esapi rc
752 ADD_HANDLER("sys", sys_err_handler), // layer 8 is the sys rc
753 ADD_HANDLER("mu", sys_err_handler), // layer 9 is the mu rc
754 // Defaults to the system handler
755 ADD_HANDLER("tcti", sys_err_handler), // layer 10 is the tcti rc
756 // Defaults to the system handler
757 ADD_HANDLER("rmt", tpm2_ehandler), // layer 11 is the resource manager TPM RC
758 // The RM usually duplicates TPM responses
759 // So just default the handler to tpm2.
760 ADD_HANDLER("rm", NULL), // layer 12 is the rm rc
761 ADD_HANDLER("drvr", NULL), // layer 13 is the driver rc
765 * Determines if the layer allowed to be registered to.
767 * The layer to determine handler assignment eligibility of.
769 * True if it is reserved and thus non-assignable, false otherwise.
771 static bool is_reserved_layer(UINT8 layer) {
776 * If a layer has no handler registered, default to this
777 * handler that prints the error number in hex.
779 * The rc to print the error number of.
783 static const char *unkown_layer_handler(TSS2_RC rc) {
789 catbuf(buf, "0x%X", tpm2_error_get(rc));
795 * Register or unregister a custom layer error handler.
797 * The layer in which to register a handler for. It is an error
798 * to register for the following reserved layers:
799 * - TSS2_TPM_RC_LAYER - layer 0
800 * - TSS2_SYS_RC_LAYER - layer 8
801 * - TSS2_MU_RC_LAYER - layer 9
802 * - TSS2_TCTI_RC_LAYER - layer 10
804 * A friendly layer name. It is an error for the name to be of
805 * length 0 or greater than 4.
807 * The handler function to register or NULL to unregister.
809 * True on success or False on error.
811 bool tpm2_error_set_handler(UINT8 layer, const char *name,
812 tpm2_error_handler handler) {
814 /* don't allow setting reserved layers */
815 if (is_reserved_layer(layer)) {
820 * if they are clearing the handler, name doesn't matter
827 /* Perform a zero and max-name length check if name is being set */
829 size_t len = name ? strlen(name) : 0;
830 if (!len || len > TSS2_ERR_LAYER_NAME_MAX)
834 layer_handler[layer].handler = handler;
835 layer_handler[layer].name = name;
840 const char * tpm2_error_str(TSS2_RC rc) {
842 static char buf[TSS2_ERR_LAYER_NAME_MAX + TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
846 UINT8 layer = tss2_rc_layer_number_get(rc);
848 tpm2_error_handler handler = layer_handler[layer].handler;
849 const char *lname = layer_handler[layer].name;
852 catbuf(buf, "%s:", lname);
854 catbuf(buf, "%u:", layer);
857 handler = !handler ? unkown_layer_handler : handler;
859 // Handlers only need the error bits. This way they don't
860 // need to concern themselves with masking off the layer
861 // bits or anything else.
862 UINT16 err_bits = tpm2_error_get(rc);
863 const char *e = err_bits ? handler(err_bits) : "success";
865 catbuf(buf, "%s", e);
867 catbuf(buf, "0x%X", err_bits);