Utility to Import external RSA pem key into TPM
[aaf/sshsm.git] / TPM2-Plugin / lib / tpm2_error.c
1 //**********************************************************************;
2 // Copyright (c) 2018, Intel Corporation
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
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.
14 //
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 //**********************************************************************;
27
28 #include <stdarg.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include <tss2/tss2_sys.h>
34
35 #include "tpm2_error.h"
36 #include "tpm2_util.h"
37
38 /**
39  * The maximum size of a layer name.
40  */
41 #define TSS2_ERR_LAYER_NAME_MAX  4
42
43 /**
44  * The maximum size for layer specific error strings.
45  */
46 #define TSS2_ERR_LAYER_ERROR_STR_MAX  512
47
48 /**
49  * Concatenates (safely) onto a static buffer given a format and varaidic
50  * arguments similar to sprintf.
51  * @param b
52  *   The static buffer to concatenate onto.
53  * @param fmt
54  *   The format specifier as understood by printf followed by the variadic
55  *   parameters for the specifier.
56  */
57 #define catbuf(b, fmt, ...) _catbuf(b, sizeof(b), fmt, ##__VA_ARGS__)
58
59 /**
60  * Clears out a static buffer by setting index 0 to the null byte.
61  * @param buffer
62  *  The buffer to clear out.
63  */
64 static void clearbuf(char *buffer) {
65     buffer[0] = '\0';
66 }
67
68 /**
69  * Prints to a buffer using snprintf(3) using the supplied fmt
70  * and varaiadic arguments.
71  * @param buf
72  *  The buffer to print into.
73  * @param len
74  *  The length of that buffer.
75  * @param fmt
76  *  The format string
77  * @warning
78  *  DO NOT CALL DIRECTLY, use the catbuf() macro.
79  */
80 static void COMPILER_ATTR(format (printf, 3, 4))
81 _catbuf(char *buf, size_t len, const char *fmt, ...) {
82     va_list argptr;
83     va_start(argptr, fmt);
84     size_t offset = strlen(buf);
85     vsnprintf(&buf[offset], len - offset, fmt, argptr);
86     va_end(argptr);
87 }
88
89 /**
90  * Retrieves the layer number. The layer number is in the 3rd
91  * octet and is thus 1 byte big.
92  *
93  * @param rc
94  *  The rc to query for the layer number.
95  * @return
96  *  The layer number.
97  */
98 static inline UINT8 tss2_rc_layer_number_get(TSS2_RC rc) {
99     return ((rc & TSS2_RC_LAYER_MASK) >> TSS2_RC_LAYER_SHIFT);
100 }
101
102 /**
103  * Queries a TPM format 1 error codes N field. The N field
104  * is a 4 bit field located at bits 8:12.
105  * @param rc
106  *  The rc to query the N field for.
107  * @return
108  *  The N field value.
109  */
110 static inline UINT8 tpm2_rc_fmt1_N_get(TPM2_RC rc) {
111     return ((rc & (0xF << 8)) >> 8);
112 }
113
114 /**
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.
117  * @param rc
118  *  The TPM format 1 error code to query for the index bits.
119  * @return
120  *  The index bits from the N field.
121  */
122 static inline UINT8 tpm2_rc_fmt1_N_index_get(TPM2_RC rc) {
123     return (tpm2_rc_fmt1_N_get(rc) & 0x7);
124 }
125
126 /**
127  * Determines if the N field in a TPM format 1 error code is
128  * a handle or not.
129  * @param rc
130  *  The TPM format 1 error code to query.
131  * @return
132  *  True if it is a handle, false otherwise.
133  */
134 static inline bool tpm2_rc_fmt1_N_is_handle(TPM2_RC rc) {
135     return ((tpm2_rc_fmt1_N_get(rc) & 0x8) == 0);
136 }
137
138 static inline UINT8 tpm2_rc_fmt1_P_get(TPM2_RC rc) {
139     return ((rc & (1 << 6)) >> 6);
140 }
141
142 static inline UINT16 tpm2_rc_fmt1_error_get(TPM2_RC rc) {
143     return (rc & 0x3F);
144 }
145
146 static inline UINT16 tpm2_rc_fmt0_error_get(TPM2_RC rc) {
147     return (rc & 0x7F);
148 }
149
150 static inline UINT8 tpm2_rc_tpm_fmt0_V_get(TPM2_RC rc) {
151     return ((rc & (1 << 8)) >> 8);
152 }
153
154 static inline UINT8 tpm2_rc_fmt0_T_get(TPM2_RC rc) {
155     return ((rc & (1 << 10)) >> 8);
156 }
157
158 static inline UINT8 tpm2_rc_fmt0_S_get(TSS2_RC rc) {
159     return ((rc & (1 << 11)) >> 8);
160 }
161
162 /**
163  * Helper macro for adding a layer handler to the layer
164  * registration array.
165  */
166 #define ADD_HANDLER(name, handler) \
167     { name, handler }
168
169 /**
170  * Same as ADD_HANDLER but sets it to NULL. Used as a placeholder
171  * for non-registered indexes into the handler array.
172  */
173 #define ADD_NULL_HANDLER ADD_HANDLER(NULL, NULL)
174
175 static const char *tpm2_err_handler_fmt1(TPM2_RC rc) {
176
177     /*
178      * format 1 error codes start at 1, so
179      * add a NULL entry to index 0.
180      */
181     static const char *fmt1_err_strs[] = {
182         // 0x0 - EMPTY
183         NULL,
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",
194         // 0x6 - EMPTY
195         NULL,
196         // 0x7 - TPM2_RC_KEY_SIZE
197         "key size is not supported",
198         // 0x8 - TPM2_RC_MGF
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",
206         // 0xC - TPM2_RC_KDF
207         "unsupported key derivation function or function not appropriate for "
208         "use",
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",
215         // 0x10 - TPM2_RC_PP
216         "authorization requires assertion of PP",
217         // 0x11 - EMPTY
218         NULL,
219         // 0x12 - TPM2_RC_SCHEME
220         "unsupported or incompatible scheme",
221         // 0x13 - EMPTY
222         NULL,
223         // 0x14 - EMPTY
224         NULL,
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"
229         " instance",
230         // 0x17 - TPM2_RC_TAG
231         "incorrect structure tag",
232         // 0x18 - TPM2_RC_SELECTOR
233         "union selector is incorrect",
234         // 0x19 - EMPTY
235         NULL,
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",
245         // 0x1E - EMPTY
246         NULL,
247         // 0x1F - TPM2_RC_INTEGRITY
248         "integrity check failed",
249         // 0x20 - TPM2_RC_TICKET
250         "invalid 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",
267     };
268
269     static char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
270
271     clearbuf(buf);
272
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
277      * bit field.
278      *
279      * the lower 3 bits of N indicate index, and the high bit
280      * indicates
281      */
282     UINT8 index = tpm2_rc_fmt1_N_index_get(rc);
283
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);
288
289     if (index) {
290         catbuf(buf, "(%u):", index);
291     } else {
292         catbuf(buf, "%s", "(unk):");
293     }
294
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);
299     } else {
300         catbuf(buf, "unknown error num: 0x%X", errnum);
301     }
302
303     return buf;
304 }
305
306 static const char *tpm2_err_handler_fmt0(TSS2_RC rc) {
307
308     /*
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.
314      */
315     static const char *fmt0_warn_strs[] = {
316             // 0x0 - EMPTY
317             NULL,
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"
326             " operations",
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
332             "bad 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",
340             // 0xB - EMPTY
341             NULL,
342             // 0xC - EMPTY
343             NULL,
344             // 0xD - EMPTY
345             NULL,
346             // 0xE - EMPTY
347             NULL,
348             // 0xF - EMPTY
349             NULL,
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",
371             // 0x17 - EMPTY,
372             // 0x18 - TPM2_RC_REFERENCE_S0
373             "the 1st authorization session handle references a session that"
374             " is not loaded",
375             // 0x19 - TPM2_RC_REFERENCE_S1
376             "the 2nd authorization session handle references a session that"
377             " is not loaded",
378             // 0x1A - TPM2_RC_REFERENCE_S2
379             "the 3rd authorization session handle references a session that"
380             " is not loaded",
381             // 0x1B - TPM2_RC_REFERENCE_S3
382             "the 4th authorization session handle references a session that"
383             " is not loaded",
384             // 0x1C - TPM2_RC_REFERENCE_S4
385             "the 5th authorization session handle references a session that"
386             " is not loaded",
387             // 0x1D - TPM2_RC_REFERENCE_S5
388             "the 6th authorization session handle references a session that"
389             " is not loaded",
390             // 0x1E - TPM2_RC_REFERENCE_S6
391             "the 7th authorization session handle references a session that"
392             " is not loaded",
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"
402             " accessible",
403     };
404
405     /*
406      * format 1 error codes start at 0, so
407      * no need to offset the error bits.
408      */
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",
414         // 0x2 - EMPTY
415         NULL,
416         // 0x3 - TPM2_RC_SEQUENCE
417         "improper use of a sequence handle",
418         // 0x4 - EMPTY
419         NULL,
420         // 0x5 - EMPTY
421         NULL,
422         // 0x6 - EMPTY
423         NULL,
424         // 0x7 - EMPTY
425         NULL,
426         // 0x8 - EMPTY
427         NULL,
428         // 0x9 - EMPTY
429         NULL,
430         // 0xA - EMPTY
431         NULL,
432         // 0xB - TPM2_RC_PRIVATE
433         "not currently used",
434         // 0xC - EMPTY
435         NULL,
436         // 0xD - EMPTY
437         NULL,
438         // 0xE - EMPTY
439         NULL,
440         // 0xF - EMPTY
441         NULL,
442         // 0x10 - EMPTY
443         NULL,
444         // 0x11 - EMPTY
445         NULL,
446         // 0x12 - EMPTY
447         NULL,
448         // 0x13 - EMPTY
449         NULL,
450         // 0x14 - EMPTY
451         NULL,
452         // 0x15 - EMPTY
453         NULL,
454         // 0x16 - EMPTY
455         NULL,
456         // 0x17 - EMPTY
457         NULL,
458         // 0x18 - EMPTY
459         NULL,
460         // 0x19 - TPM2_RC_HMAC
461         "not currently used",
462         // 0x1A - EMPTY
463         NULL,
464         // 0x1B - EMPTY
465         NULL,
466         // 0x1C - EMPTY
467         NULL,
468         // 0x1D - EMPTY
469         NULL,
470         // 0x1E - EMPTY
471         NULL,
472         // 0x1F - EMPTY
473         NULL,
474         // 0x20 - TPM2_RC_DISABLED
475         "the command is disabled",
476         // 0x21 - TPM2_RC_EXCLUSIVE
477         "command failed because audit sequence required exclusivity",
478         // 0x22 - EMPTY
479         NULL,
480         // 0x23 - EMPTY,
481         NULL,
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"
486         " not present",
487         // 0x26 - TPM2_RC_POLICY
488         "policy failure in math operation or an invalid authPolicy value",
489         // 0x27 - TPM2_RC_PCR
490         "PCR check fail",
491         // 0x28 - TPM2_RC_PCR_CHANGED
492         "PCR have changed since checked",
493         // 0x29 - EMPTY
494         NULL,
495         // 0x2A - EMPTY
496         NULL,
497         // 0x2B - EMPTY
498         NULL,
499         // 0x2C - EMPTY
500         NULL,
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"
510         " resume operation",
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.",
515         // 0x32 - EMPTY
516         NULL,
517         // 0x33 - EMPTY
518         NULL,
519         // 0x34 - EMPTY
520         NULL,
521         // 0x35 - EMPTY
522         NULL,
523         // 0x36 - EMPTY
524         NULL,
525         // 0x37 - EMPTY
526         NULL,
527         // 0x38 - EMPTY
528         NULL,
529         // 0x39 - EMPTY
530         NULL,
531         // 0x3A - EMPTY
532         NULL,
533         // 0x3B - EMPTY
534         NULL,
535         // 0x3C - EMPTY
536         NULL,
537         // 0x3D - EMPTY
538         NULL,
539         // 0x3E - EMPTY
540         NULL,
541         // 0x3F - EMPTY
542         NULL,
543         // 0x40 - EMPTY
544         NULL,
545         // 0x41 - EMPTY
546         NULL,
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
565         "NV access 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",
575         // 0x4D - EMPTY
576         NULL,
577         // 0x4E - EMPTY
578         NULL,
579         // 0x4F - EMPTY
580         NULL,
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",
596     };
597
598     static char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
599
600     clearbuf(buf);
601
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);
605
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);
612             return buf;
613         }
614
615         /* is it a warning (version 2 error string) or is it a 1.2 error? */
616         size_t len =
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;
621         if (errnum >= len) {
622             return NULL;
623         }
624
625         const char *m = selection[errnum];
626         if (!m) {
627             return NULL;
628         }
629
630         catbuf(buf, "%s", m);
631         return buf;
632     }
633
634     catbuf(buf, "%s", "unknown version 1.2 error code");
635
636     return buf;
637 }
638
639 /**
640  * Retrieves the layer field from a TSS2_RC code.
641  * @param rc
642  *  The rc to query the layer index of.
643  * @return
644  *  The layer index.
645  */
646 static inline UINT8 tss2_rc_layer_format_get(TSS2_RC rc) {
647
648     return ((rc & (1 << 7)) >> 7);
649 }
650
651 /**
652  * Handler for tpm2 error codes. ie codes
653  * coming from the tpm layer aka layer 0.
654  * @param rc
655  *  The rc to decode.
656  * @return
657  *  An error string.
658  */
659 static const char *tpm2_ehandler(TSS2_RC rc) {
660
661     bool is_fmt_1 = tss2_rc_layer_format_get(rc);
662
663     return is_fmt_1 ? tpm2_err_handler_fmt1(rc) : tpm2_err_handler_fmt0(rc);
664 }
665
666 /**
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.
670  * @param rc
671  *  The rc to decode.
672  * @return
673  *  An error string.
674  */
675 static const char *sys_err_handler (TSS2_RC rc) {
676     UNUSED(rc);
677
678     /*
679      * subtract 1 from the error number
680      * before indexing into this array.
681      *
682      * Commented offsets are for the corresponding
683      * error number *before* subtraction. Ie error
684      * number 4 is at array index 3.
685      */
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
706         "IO failure",
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"
734   };
735
736     return (rc - 1u < ARRAY_LEN(errors)) ? errors[rc - 1u] : NULL;
737 }
738
739
740 static struct {
741     const char *name;
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
762 };
763
764 /**
765  * Determines if the layer allowed to be registered to.
766  * @param layer
767  *  The layer to determine handler assignment eligibility of.
768  * @return
769  *  True if it is reserved and thus non-assignable, false otherwise.
770  */
771 static bool is_reserved_layer(UINT8 layer) {
772     return layer == 0;
773 }
774
775 /**
776  * If a layer has no handler registered, default to this
777  * handler that prints the error number in hex.
778  * @param rc
779  *  The rc to print the error number of.
780  * @return
781  *  The string.
782  */
783 static const char *unkown_layer_handler(TSS2_RC rc) {
784     UNUSED(rc);
785
786     static char buf[32];
787
788     clearbuf(buf);
789     catbuf(buf, "0x%X", tpm2_error_get(rc));
790
791     return buf;
792 }
793
794 /**
795  * Register or unregister a custom layer error handler.
796  * @param layer
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
803  * @param name
804  *  A friendly layer name. It is an error for the name to be of
805  *  length 0 or greater than 4.
806  * @param handler
807  *  The handler function to register or NULL to unregister.
808  * @return
809  *  True on success or False on error.
810  */
811 bool tpm2_error_set_handler(UINT8 layer, const char *name,
812         tpm2_error_handler handler) {
813
814     /* don't allow setting reserved layers */
815     if (is_reserved_layer(layer)) {
816         return false;
817     }
818
819     /*
820      * if they are clearing the handler, name doesn't matter
821      * clear it too.
822      */
823     if (!handler) {
824         name = NULL;
825     }
826
827     /* Perform a zero and max-name length check if name is being set */
828     if (name) {
829         size_t len = name ? strlen(name) : 0;
830         if (!len || len > TSS2_ERR_LAYER_NAME_MAX)
831             return false;
832     }
833
834     layer_handler[layer].handler = handler;
835     layer_handler[layer].name = name;
836
837     return true;
838 }
839
840 const char * tpm2_error_str(TSS2_RC rc) {
841
842     static char buf[TSS2_ERR_LAYER_NAME_MAX + TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
843
844     clearbuf(buf);
845
846     UINT8 layer = tss2_rc_layer_number_get(rc);
847
848     tpm2_error_handler handler = layer_handler[layer].handler;
849     const char *lname = layer_handler[layer].name;
850
851     if (lname) {
852         catbuf(buf, "%s:", lname);
853     } else {
854         catbuf(buf, "%u:", layer);
855     }
856
857     handler = !handler ? unkown_layer_handler : handler;
858
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";
864     if (e) {
865         catbuf(buf, "%s", e);
866     } else {
867         catbuf(buf, "0x%X", err_bits);
868     }
869
870     return buf;
871 }