• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 
3 #include <stdarg.h>
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <string.h>
7 
8 #include "tss2_rc.h"
9 #include "tss2_sys.h"
10 
11 #if defined (__GNUC__)
12 #define COMPILER_ATTR(...) __attribute__((__VA_ARGS__))
13 #else
14 #define COMPILER_ATTR(...)
15 #endif
16 
17 #define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
18 
19 /**
20  * The maximum size of a layer name.
21  */
22 #define TSS2_ERR_LAYER_NAME_MAX  (16 + 1)
23 
24 /**
25  * The maximum size for layer specific error strings.
26  */
27 #define TSS2_ERR_LAYER_ERROR_STR_MAX  512
28 
29 /**
30  * Concatenates (safely) onto a static buffer given a format and varaidic
31  * arguments similar to sprintf.
32  * @param b
33  *   The static buffer to concatenate onto.
34  * @param fmt
35  *   The format specifier as understood by printf followed by the variadic
36  *   parameters for the specifier.
37  */
38 #define catbuf(b, fmt, ...) _catbuf(b, sizeof(b), fmt, ##__VA_ARGS__)
39 
40 /**
41  * Clears out a static buffer by setting index 0 to the null byte.
42  * @param buffer
43  *  The buffer to clear out.
44  */
45 static void
clearbuf(char * buffer)46 clearbuf(char *buffer)
47 {
48     buffer[0] = '\0';
49 }
50 
51 /**
52  * Prints to a buffer using snprintf(3) using the supplied fmt
53  * and varaiadic arguments.
54  * @param buf
55  *  The buffer to print into.
56  * @param len
57  *  The length of that buffer.
58  * @param fmt
59  *  The format string
60  * @warning
61  *  DO NOT CALL DIRECTLY, use the catbuf() macro.
62  */
63 static void COMPILER_ATTR(format (printf, 3, 4))
_catbuf(char * buf,size_t len,const char * fmt,...)64 _catbuf(char *buf, size_t len, const char *fmt, ...)
65 {
66     va_list argptr;
67     va_start(argptr, fmt);
68     size_t offset = strlen(buf);
69     vsnprintf(&buf[offset], len - offset, fmt, argptr);
70     va_end(argptr);
71 }
72 
73 /**
74  * Number of error layers
75  */
76 #define TPM2_ERROR_TSS2_RC_LAYER_COUNT (TSS2_RC_LAYER_MASK >> TSS2_RC_LAYER_SHIFT)
77 
78 /**
79  * Mask for the error bits of tpm2 compliant return code.
80  */
81 #define TPM2_ERROR_TSS2_RC_ERROR_MASK 0xFFFF
82 
83 /**
84  * Retrieves the error bits from a TSS2_RC. The error bits are
85  * contained in the first 2 octets.
86  * @param rc
87  *  The rc to query for the error bits.
88  * @return
89  *  The error bits.
90  */
91 static inline UINT16
tpm2_error_get(TSS2_RC rc)92 tpm2_error_get(TSS2_RC rc)
93 {
94     return ((rc & TPM2_ERROR_TSS2_RC_ERROR_MASK));
95 }
96 
97 /**
98  * Retrieves the layer number. The layer number is in the 3rd
99  * octet and is thus 1 byte big.
100  *
101  * @param rc
102  *  The rc to query for the layer number.
103  * @return
104  *  The layer number.
105  */
106 static inline UINT8
tss2_rc_layer_number_get(TSS2_RC rc)107 tss2_rc_layer_number_get(TSS2_RC rc)
108 {
109     return ((rc & TSS2_RC_LAYER_MASK) >> TSS2_RC_LAYER_SHIFT);
110 }
111 
112 /**
113  * Queries a TPM format 1 error codes N field. The N field
114  * is a 4 bit field located at bits 8:12.
115  * @param rc
116  *  The rc to query the N field for.
117  * @return
118  *  The N field value.
119  */
120 static inline UINT8
tpm2_rc_fmt1_N_get(TPM2_RC rc)121 tpm2_rc_fmt1_N_get(TPM2_RC rc)
122 {
123     return ((rc & (0xF << 8)) >> 8);
124 }
125 
126 /**
127  * Queries the index bits out of the N field contained in a TPM format 1
128  * error code. The index bits are the low 3 bits of the N field.
129  * @param rc
130  *  The TPM format 1 error code to query for the index bits.
131  * @return
132  *  The index bits from the N field.
133  */
134 static inline UINT8
tpm2_rc_fmt1_N_index_get(TPM2_RC rc)135 tpm2_rc_fmt1_N_index_get(TPM2_RC rc)
136 {
137     return (tpm2_rc_fmt1_N_get(rc) & 0x7);
138 }
139 
140 /**
141  * Determines if the N field in a TPM format 1 error code is
142  * a handle or not.
143  * @param rc
144  *  The TPM format 1 error code to query.
145  * @return
146  *  True if it is a handle, false otherwise.
147  */
148 static inline bool
tpm2_rc_fmt1_N_is_handle(TPM2_RC rc)149 tpm2_rc_fmt1_N_is_handle(TPM2_RC rc)
150 {
151     return ((tpm2_rc_fmt1_N_get(rc) & 0x8) == 0);
152 }
153 
154 static inline UINT8
tpm2_rc_fmt1_P_get(TPM2_RC rc)155 tpm2_rc_fmt1_P_get(TPM2_RC rc)
156 {
157     return ((rc & (1 << 6)) >> 6);
158 }
159 
160 static inline UINT8
tpm2_rc_fmt1_error_get(TPM2_RC rc)161 tpm2_rc_fmt1_error_get(TPM2_RC rc)
162 {
163     return (rc & 0x3F);
164 }
165 
166 static inline UINT8
tpm2_rc_fmt0_error_get(TPM2_RC rc)167 tpm2_rc_fmt0_error_get(TPM2_RC rc)
168 {
169     return (rc & 0x7F);
170 }
171 
172 static inline UINT8
tpm2_rc_tpm_fmt0_V_get(TPM2_RC rc)173 tpm2_rc_tpm_fmt0_V_get(TPM2_RC rc)
174 {
175     return ((rc & (1 << 8)) >> 8);
176 }
177 
178 static inline UINT8
tpm2_rc_fmt0_T_get(TPM2_RC rc)179 tpm2_rc_fmt0_T_get(TPM2_RC rc)
180 {
181     return ((rc & (1 << 10)) >> 8);
182 }
183 
184 static inline UINT8
tpm2_rc_fmt0_S_get(TSS2_RC rc)185 tpm2_rc_fmt0_S_get(TSS2_RC rc)
186 {
187     return ((rc & (1 << 11)) >> 8);
188 }
189 
190 /**
191  * Helper macro for adding a layer handler to the layer
192  * registration array.
193  */
194 #define ADD_HANDLER(name, handler) \
195     { name, handler }
196 
197 /**
198  * Same as ADD_HANDLER but sets it to NULL. Used as a placeholder
199  * for non-registered indexes into the handler array.
200  */
201 #define ADD_NULL_HANDLER ADD_HANDLER("\0", NULL)
202 
203 static const char *
tpm2_err_handler_fmt1(TPM2_RC rc)204 tpm2_err_handler_fmt1(TPM2_RC rc)
205 {
206     /*
207      * format 1 error codes start at 1, so
208      * add a NULL entry to index 0.
209      */
210     static const char *fmt1_err_strs[] = {
211         /* 0x0 - EMPTY */
212         NULL,
213         /* 0x1 - TPM2_RC_ASYMMETRIC */
214         "asymmetric algorithm not supported or not correct",
215         /* 0x2 - TPM2_RC_ATTRIBUTES */
216         "inconsistent attributes",
217         /* 0x3 - TPM2_RC_HASH */
218         "hash algorithm not supported or not appropriate",
219         /* 0x4 - TPM2_RC_VALUE */
220         "value is out of range or is not correct for the context",
221         /* 0x5 - TPM2_RC_HIERARCHY */
222         "hierarchy is not enabled or is not correct for the use",
223         /* 0x6 - EMPTY */
224         NULL,
225         /* 0x7 - TPM2_RC_KEY_SIZE */
226         "key size is not supported",
227         /* 0x8 - TPM2_RC_MGF */
228         "mask generation function not supported",
229         /* 0x9 - TPM2_RC_MODE */
230         "mode of operation not supported",
231         /* 0xA - TPM2_RC_TYPE */
232         "the type of the value is not appropriate for the use",
233         /* 0xB - TPM2_RC_HANDLE */
234         "the handle is not correct for the use",
235         /* 0xC - TPM2_RC_KDF */
236         "unsupported key derivation function or function not appropriate for "
237         "use",
238         /* 0xD - TPM2_RC_RANGE */
239         "value was out of allowed range",
240         /* 0xE - TPM2_RC_AUTH_FAIL */
241         "the authorization HMAC check failed and DA counter incremented",
242         /* 0xF - TPM2_RC_NONCE */
243         "invalid nonce size or nonce value mismatch",
244         /* 0x10 - TPM2_RC_PP */
245         "authorization requires assertion of PP",
246         /* 0x11 - EMPTY */
247         NULL,
248         /* 0x12 - TPM2_RC_SCHEME */
249         "unsupported or incompatible scheme",
250         /* 0x13 - EMPTY */
251         NULL,
252         /* 0x14 - EMPTY */
253         NULL,
254         /* 0x15 - TPM2_RC_SIZE */
255         "structure is the wrong size",
256         /* 0x16 - TPM2_RC_SYMMETRIC */
257         "unsupported symmetric algorithm or key size or not appropriate for"
258         " instance",
259         /* 0x17 - TPM2_RC_TAG */
260         "incorrect structure tag",
261         /* 0x18 - TPM2_RC_SELECTOR */
262         "union selector is incorrect",
263         /* 0x19 - EMPTY */
264         NULL,
265         /* 0x1A - TPM2_RC_INSUFFICIENT */
266         "the TPM was unable to unmarshal a value because there were not enough"
267         " octets in the input buffer",
268         /* 0x1B - TPM2_RC_SIGNATURE */
269         "the signature is not valid",
270         /* 0x1C - TPM2_RC_KEY */
271         "key fields are not compatible with the selected use",
272         /* 0x1D - TPM2_RC_POLICY_FAIL */
273         "a policy check failed",
274         /* 0x1E - EMPTY */
275         NULL,
276         /* 0x1F - TPM2_RC_INTEGRITY */
277         "integrity check failed",
278         /* 0x20 - TPM2_RC_TICKET */
279         "invalid ticket",
280         /* 0x21 - TPM2_RC_RESERVED_BITS */
281         "reserved bits not set to zero as required",
282         /* 0x22 - TPM2_RC_BAD_AUTH */
283         "authorization failure without DA implications",
284         /* 0x23 - TPM2_RC_EXPIRED */
285         "the policy has expired",
286         /* 0x24 - TPM2_RC_POLICY_CC */
287         "the commandCode in the policy is not the commandCode of the command"
288         " or the command code in a policy command references a command that"
289         " is not implemented",
290         /* 0x25 - TPM2_RC_BINDING */
291         "public and sensitive portions of an object are not cryptographically bound",
292         /* 0x26 - TPM2_RC_CURVE */
293         "curve not supported",
294         /* 0x27 - TPM2_RC_ECC_POINT */
295         "point is not on the required curve",
296     };
297 
298     static __thread char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
299 
300     clearbuf(buf);
301 
302     /* Print whether or not the error is caused by a bad
303      * handle or parameter. On the case of a Handle (P == 0)
304      * then the N field top bit will be set. Un-set this bit
305      * to get the handle index by subtracting 8 as N is a 4
306      * bit field.
307      *
308      * the lower 3 bits of N indicate index, and the high bit
309      * indicates
310      */
311     UINT8 index = tpm2_rc_fmt1_N_index_get(rc);
312 
313     bool is_handle = tpm2_rc_fmt1_N_is_handle(rc);
314     const char *m = tpm2_rc_fmt1_P_get(rc) ? "parameter" :
315                     is_handle ? "handle" : "session";
316     catbuf(buf, "%s", m);
317 
318     if (index) {
319         catbuf(buf, "(%u):", index);
320     } else {
321         catbuf(buf, "%s", "(unk):");
322     }
323 
324     UINT8 errnum = tpm2_rc_fmt1_error_get(rc);
325     if (errnum < ARRAY_LEN(fmt1_err_strs)) {
326         m = fmt1_err_strs[errnum];
327         catbuf(buf, "%s", m);
328     } else {
329         catbuf(buf, "unknown error num: 0x%X", errnum);
330     }
331 
332     return buf;
333 }
334 
335 static const char *
tpm2_err_handler_fmt0(TSS2_RC rc)336 tpm2_err_handler_fmt0(TSS2_RC rc)
337 {
338     /*
339      * format 0 error codes start at 1, so
340      * add a NULL entry to index 0.
341      * Thus, no need to offset the error bits
342      * and fmt0 and fmt1 arrays can be used
343      * in-place of each other for lookups.
344      */
345     static const char *fmt0_warn_strs[] = {
346             /* 0x0 - EMPTY */
347             NULL,
348             /* 0x1 - TPM2_RC_CONTEXT_GAP */
349             "gap for context ID is too large",
350             /* 0x2 - TPM2_RC_OBJECT_MEMORY */
351             "out of memory for object contexts",
352             /* 0x3 - TPM2_RC_SESSION_MEMORY */
353             "out of memory for session contexts",
354             /* 0x4 - TPM2_RC_MEMORY */
355             "out of shared objectsession memory or need space for internal"
356             " operations",
357             /* 0x5 - TPM2_RC_SESSION_HANDLES */
358             "out of session handles",
359             /* 0x6 - TPM2_RC_OBJECT_HANDLES */
360             "out of object handles",
361             /* 0x7 - TPM2_RC_LOCALITY */
362             "bad locality",
363             /* 0x8 - TPM2_RC_YIELDED */
364             "the TPM has suspended operation on the command forward progress"
365             " was made and the command may be retried",
366             /* 0x9 - TPM2_RC_CANCELED */
367             "the command was canceled",
368             /* 0xA - TPM2_RC_TESTING */
369             "TPM is performing selftests",
370             /* 0xB - EMPTY */
371             NULL,
372             /* 0xC - EMPTY */
373             NULL,
374             /* 0xD - EMPTY */
375             NULL,
376             /* 0xE - EMPTY */
377             NULL,
378             /* 0xF - EMPTY */
379             NULL,
380             /* 0x10 - TPM2_RC_REFERENCE_H0 */
381             "the 1st handle in the handle area references a transient object"
382             " or session that is not loaded",
383             /* 0x11 - TPM2_RC_REFERENCE_H1 */
384             "the 2nd handle in the handle area references a transient object"
385             " or session that is not loaded",
386             /* 0x12 - TPM2_RC_REFERENCE_H2 */
387             "the 3rd handle in the handle area references a transient object"
388             " or session that is not loaded",
389             /* 0x13 - TPM2_RC_REFERENCE_H3 */
390             "the 4th handle in the handle area references a transient object"
391             " or session that is not loaded",
392             /* 0x14 - TPM2_RC_REFERENCE_H4 */
393             "the 5th handle in the handle area references a transient object"
394             " or session that is not loaded",
395             /* 0x15 - TPM2_RC_REFERENCE_H5 */
396             "the 6th handle in the handle area references a transient object"
397             " or session that is not loaded",
398             /* 0x16 - TPM2_RC_REFERENCE_H6 */
399             "the 7th handle in the handle area references a transient object"
400             " or session that is not loaded",
401             /* 0x17 - EMPTY, */
402             NULL,
403             /* 0x18 - TPM2_RC_REFERENCE_S0 */
404             "the 1st authorization session handle references a session that"
405             " is not loaded",
406             /* 0x19 - TPM2_RC_REFERENCE_S1 */
407             "the 2nd authorization session handle references a session that"
408             " is not loaded",
409             /* 0x1A - TPM2_RC_REFERENCE_S2 */
410             "the 3rd authorization session handle references a session that"
411             " is not loaded",
412             /* 0x1B - TPM2_RC_REFERENCE_S3 */
413             "the 4th authorization session handle references a session that"
414             " is not loaded",
415             /* 0x1C - TPM2_RC_REFERENCE_S4 */
416             "the 5th session handle references a session that"
417             " is not loaded",
418             /* 0x1D - TPM2_RC_REFERENCE_S5 */
419             "the 6th session handle references a session that"
420             " is not loaded",
421             /* 0x1E - TPM2_RC_REFERENCE_S6 */
422             "the 7th authorization session handle references a session that"
423             " is not loaded",
424             /* 0x1F - EMPTY, */
425             NULL,
426             /* 0x20 -TPM2_RC_NV_RATE */
427             "the TPM is rate limiting accesses to prevent wearout of NV",
428             /* 0x21 - TPM2_RC_LOCKOUT */
429             "authorizations for objects subject to DA protection are not"
430             " allowed at this time because the TPM is in DA lockout mode",
431             /* 0x22 - TPM2_RC_RETRY */
432             "the TPM was not able to start the command",
433             /* 0x23 - TPM2_RC_NV_UNAVAILABLE */
434             "the command may require writing of NV and NV is not current"
435             " accessible",
436     };
437 
438     /*
439      * format 1 error codes start at 0, so
440      * no need to offset the error bits.
441      */
442     static const char *fmt0_err_strs[] = {
443         /* 0x0 - TPM2_RC_INITIALIZE */
444         "TPM not initialized by TPM2_Startup or already initialized",
445         /* 0x1 - TPM2_RC_FAILURE */
446         "commands not being accepted because of a TPM failure",
447         /* 0x2 - EMPTY */
448         NULL,
449         /* 0x3 - TPM2_RC_SEQUENCE */
450         "improper use of a sequence handle",
451         /* 0x4 - EMPTY */
452         NULL,
453         /* 0x5 - EMPTY */
454         NULL,
455         /* 0x6 - EMPTY */
456         NULL,
457         /* 0x7 - EMPTY */
458         NULL,
459         /* 0x8 - EMPTY */
460         NULL,
461         /* 0x9 - EMPTY */
462         NULL,
463         /* 0xA - EMPTY */
464         NULL,
465         /* 0xB - TPM2_RC_PRIVATE */
466         "not currently used",
467         /* 0xC - EMPTY */
468         NULL,
469         /* 0xD - EMPTY */
470         NULL,
471         /* 0xE - EMPTY */
472         NULL,
473         /* 0xF - EMPTY */
474         NULL,
475         /* 0x10 - EMPTY */
476         NULL,
477         /* 0x11 - EMPTY */
478         NULL,
479         /* 0x12 - EMPTY */
480         NULL,
481         /* 0x13 - EMPTY */
482         NULL,
483         /* 0x14 - EMPTY */
484         NULL,
485         /* 0x15 - EMPTY */
486         NULL,
487         /* 0x16 - EMPTY */
488         NULL,
489         /* 0x17 - EMPTY */
490         NULL,
491         /* 0x18 - EMPTY */
492         NULL,
493         /* 0x19 - TPM2_RC_HMAC */
494         "not currently used",
495         /* 0x1A - EMPTY */
496         NULL,
497         /* 0x1B - EMPTY */
498         NULL,
499         /* 0x1C - EMPTY */
500         NULL,
501         /* 0x1D - EMPTY */
502         NULL,
503         /* 0x1E - EMPTY */
504         NULL,
505         /* 0x1F - EMPTY */
506         NULL,
507         /* 0x20 - TPM2_RC_DISABLED */
508         "the command is disabled",
509         /* 0x21 - TPM2_RC_EXCLUSIVE */
510         "command failed because audit sequence required exclusivity",
511         /* 0x22 - EMPTY */
512         NULL,
513         /* 0x23 - EMPTY, */
514         NULL,
515         /* 0x24 - TPM2_RC_AUTH_TYPE */
516         "authorization handle is not correct for command",
517         /* 0x25 - TPM2_RC_AUTH_MISSING */
518         "command requires an authorization session for handle and it is"
519         " not present",
520         /* 0x26 - TPM2_RC_POLICY */
521         "policy failure in math operation or an invalid authPolicy value",
522         /* 0x27 - TPM2_RC_PCR */
523         "PCR check fail",
524         /* 0x28 - TPM2_RC_PCR_CHANGED */
525         "PCR have changed since checked",
526         /* 0x29 - EMPTY */
527         NULL,
528         /* 0x2A - EMPTY */
529         NULL,
530         /* 0x2B - EMPTY */
531         NULL,
532         /* 0x2C - EMPTY */
533         NULL,
534         /* 0x2D - TPM2_RC_UPGRADE */
535         "For all commands, other than TPM2_FieldUpgradeData, "
536         "this code indicates that the TPM is in field upgrade mode. "
537         "For TPM2_FieldUpgradeData, this code indicates that the TPM "
538         "is not in field upgrade mode",
539         /* 0x2E - TPM2_RC_TOO_MANY_CONTEXTS */
540         "context ID counter is at maximum",
541         /* 0x2F - TPM2_RC_AUTH_UNAVAILABLE */
542         "authValue or authPolicy is not available for selected entity",
543         /* 0x30 - TPM2_RC_REBOOT */
544         "a _TPM_Init and StartupCLEAR is required before the TPM can"
545         " resume operation",
546         /* 0x31 - TPM2_RC_UNBALANCED */
547         "the protection algorithms hash and symmetric are not reasonably"
548         " balanced. The digest size of the hash must be larger than the key"
549         " size of the symmetric algorithm.",
550         /* 0x32 - EMPTY */
551         NULL,
552         /* 0x33 - EMPTY */
553         NULL,
554         /* 0x34 - EMPTY */
555         NULL,
556         /* 0x35 - EMPTY */
557         NULL,
558         /* 0x36 - EMPTY */
559         NULL,
560         /* 0x37 - EMPTY */
561         NULL,
562         /* 0x38 - EMPTY */
563         NULL,
564         /* 0x39 - EMPTY */
565         NULL,
566         /* 0x3A - EMPTY */
567         NULL,
568         /* 0x3B - EMPTY */
569         NULL,
570         /* 0x3C - EMPTY */
571         NULL,
572         /* 0x3D - EMPTY */
573         NULL,
574         /* 0x3E - EMPTY */
575         NULL,
576         /* 0x3F - EMPTY */
577         NULL,
578         /* 0x40 - EMPTY */
579         NULL,
580         /* 0x41 - EMPTY */
581         NULL,
582         /* 0x42 - TPM2_RC_COMMAND_SIZE */
583         "command commandSize value is inconsistent with contents of the"
584         " command buffer. Either the size is not the same as the octets"
585         " loaded by the hardware interface layer or the value is not large"
586         " enough to hold a command header",
587         /* 0x43 - TPM2_RC_COMMAND_CODE */
588         "command code not supported",
589         /* 0x44 - TPM2_RC_AUTHSIZE */
590         "the value of authorizationSize is out of range or the number of"
591         " octets in the Authorization Area is greater than required",
592         /* 0x45 - TPM2_RC_AUTH_CONTEXT */
593         "use of an authorization session with a context command or another"
594         " command that cannot have an authorization session",
595         /* 0x46 - TPM2_RC_NV_RANGE */
596         "NV offset+size is out of range",
597         /* 0x47 - TPM2_RC_NV_SIZE */
598         "Requested allocation size is larger than allowed",
599         /* 0x48 - TPM2_RC_NV_LOCKED */
600         "NV access locked",
601         /* 0x49 - TPM2_RC_NV_AUTHORIZATION */
602         "NV access authorization fails in command actions",
603         /* 0x4A - TPM2_RC_NV_UNINITIALIZED */
604         "an NV Index is used before being initialized or the state saved"
605         " by TPM2_ShutdownSTATE could not be restored",
606         /* 0x4B - TPM2_RC_NV_SPACE */
607         "insufficient space for NV allocation",
608         /* 0x4C - TPM2_RC_NV_DEFINED */
609         "NV Index or persistent object already defined",
610         /* 0x4D - EMPTY */
611         NULL,
612         /* 0x4E - EMPTY */
613         NULL,
614         /* 0x4F - EMPTY */
615         NULL,
616         /* 0x50 - TPM2_RC_BAD_CONTEXT */
617         "context in TPM2_ContextLoad is not valid",
618         /* 0x51 - TPM2_RC_CPHASH */
619         "cpHash value already set or not correct for use",
620         /* 0x52 - TPM2_RC_PARENT */
621         "handle for parent is not a valid parent",
622         /* 0x53 - TPM2_RC_NEEDS_TEST */
623         "some function needs testing",
624         /* 0x54 - TPM2_RC_NO_RESULT */
625         "returned when an internal function cannot process a request due to"
626         " an unspecified problem. This code is usually related to invalid"
627         " parameters that are not properly filtered by the input"
628         " unmarshaling code",
629         /* 0x55 - TPM2_RC_SENSITIVE */
630         "the sensitive area did not unmarshal correctly after decryption",
631     };
632 
633     static __thread char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
634 
635     clearbuf(buf);
636 
637     char *e = tpm2_rc_fmt0_S_get(rc) ? "warn" : "error";
638     char *v = tpm2_rc_tpm_fmt0_V_get(rc) ? "2.0" : "1.2";
639     catbuf(buf, "%s(%s): ", e, v);
640 
641     UINT8 errnum = tpm2_rc_fmt0_error_get(rc);
642     /* We only have version 2.0 spec codes defined */
643     if (tpm2_rc_tpm_fmt0_V_get(rc)) {
644         /* TCG specific error code */
645         if (tpm2_rc_fmt0_T_get(rc)) {
646             catbuf(buf, "Vendor specific error: 0x%X", errnum);
647             return buf;
648         }
649 
650         /* is it a warning (version 2 error string) or is it a 1.2 error? */
651         size_t len =
652                 tpm2_rc_fmt0_S_get(rc) ?
653                         ARRAY_LEN(fmt0_warn_strs) : ARRAY_LEN(fmt0_err_strs);
654         const char **selection =
655                 tpm2_rc_fmt0_S_get(rc) ? fmt0_warn_strs : fmt0_err_strs;
656         if (errnum >= len) {
657             return NULL;
658         }
659 
660         const char *m = selection[errnum];
661         if (!m) {
662             return NULL;
663         }
664 
665         catbuf(buf, "%s", m);
666         return buf;
667     }
668 
669     catbuf(buf, "%s", "unknown version 1.2 error code");
670 
671     return buf;
672 }
673 
674 /**
675  * Retrieves the layer field from a TSS2_RC code.
676  * @param rc
677  *  The rc to query the layer index of.
678  * @return
679  *  The layer index.
680  */
681 static inline UINT8
tss2_rc_layer_format_get(TSS2_RC rc)682 tss2_rc_layer_format_get(TSS2_RC rc)
683 {
684     return ((rc & (1 << 7)) >> 7);
685 }
686 
687 /**
688  * Handler for tpm2 error codes. ie codes
689  * coming from the tpm layer aka layer 0.
690  * @param rc
691  *  The rc to decode.
692  * @return
693  *  An error string.
694  */
695 static const char *
tpm2_ehandler(TSS2_RC rc)696 tpm2_ehandler(TSS2_RC rc)
697 {
698     bool is_fmt_1 = tss2_rc_layer_format_get(rc);
699 
700     return is_fmt_1 ? tpm2_err_handler_fmt1(rc) : tpm2_err_handler_fmt0(rc);
701 }
702 
703 /**
704  * The default system code handler. This handles codes
705  * from the RM (itself and simulated tpm responses), the marshaling
706  * library (mu), the tcti layers, sapi, esys and fapi.
707  * @param rc
708  *  The rc to decode.
709  * @return
710  *  An error string.
711  */
712 static const char *
tss_err_handler(TSS2_RC rc)713 tss_err_handler (TSS2_RC rc)
714 {
715     /*
716      * subtract 1 from the error number
717      * before indexing into this array.
718      *
719      * Commented offsets are for the corresponding
720      * error number *before* subtraction. Ie error
721      * number 4 is at array index 3.
722      */
723     static const char *errors[] =   {
724         /* 1 - TSS2_BASE_RC_GENERAL_FAILURE */
725         "Catch all for all errors not otherwise specified",
726         /* 2 - TSS2_BASE_RC_NOT_IMPLEMENTED */
727         "If called functionality isn't implemented",
728         /* 3 - TSS2_BASE_RC_BAD_CONTEXT */
729         "A context structure is bad",
730         /* 4 - TSS2_BASE_RC_ABI_MISMATCH */
731         "Passed in ABI version doesn't match called module's ABI version",
732         /* 5 - TSS2_BASE_RC_BAD_REFERENCE */
733         "A pointer is NULL that isn't allowed to be NULL.",
734         /* 6 - TSS2_BASE_RC_INSUFFICIENT_BUFFER */
735         "A buffer isn't large enough",
736         /* 7 - TSS2_BASE_RC_BAD_SEQUENCE */
737         "Function called in the wrong order",
738         /* 8 - TSS2_BASE_RC_NO_CONNECTION */
739         "Fails to connect to next lower layer",
740         /* 9 - TSS2_BASE_RC_TRY_AGAIN */
741         "Operation timed out; function must be called again to be completed",
742         /* 10 - TSS2_BASE_RC_IO_ERROR */
743         "IO failure",
744         /* 11 - TSS2_BASE_RC_BAD_VALUE */
745         "A parameter has a bad value",
746         /* 12 - TSS2_BASE_RC_NOT_PERMITTED */
747         "Operation not permitted.",
748         /* 13 - TSS2_BASE_RC_INVALID_SESSIONS */
749         "Session structures were sent, but command doesn't use them or doesn't"
750         " use the specified number of them",
751         /* 14 - TSS2_BASE_RC_NO_DECRYPT_PARAM */
752         "If function called that uses decrypt parameter, but command doesn't"
753         " support decrypt parameter.",
754         /* 15 - TSS2_BASE_RC_NO_ENCRYPT_PARAM */
755         "If function called that uses encrypt parameter, but command doesn't"
756         " support decrypt parameter.",
757         /* 16 - TSS2_BASE_RC_BAD_SIZE */
758         "If size of a parameter is incorrect",
759         /* 17 - TSS2_BASE_RC_MALFORMED_RESPONSE */
760         "Response is malformed",
761         /* 18 - TSS2_BASE_RC_INSUFFICIENT_CONTEXT */
762         "Context not large enough",
763         /* 19 - TSS2_BASE_RC_INSUFFICIENT_RESPONSE */
764         "Response is not long enough",
765         /* 20 - TSS2_BASE_RC_INCOMPATIBLE_TCTI */
766         "Unknown or unusable TCTI version",
767         /* 21 - TSS2_BASE_RC_NOT_SUPPORTED */
768         "Functionality not supported",
769         /* 22 - TSS2_BASE_RC_BAD_TCTI_STRUCTURE */
770         "TCTI context is bad",
771         /* 23 - TSS2_BASE_RC_MEMORY */
772         "Failed to allocate memory",
773         /* 24 - TSS2_BASE_RC_BAD_TR */
774         "The ESYS_TR resource object is bad",
775         /* 25 - TSS2_BASE_RC_MULTIPLE_DECRYPT_SESSIONS */
776         "Multiple sessions were marked with attribute decrypt",
777         /* 26 - TSS2_BASE_RC_MULTIPLE_ENCRYPT_SESSIONS */
778         "Multiple sessions were marked with attribute encrypt",
779         /* 27 - TSS2_BASE_RC_RSP_AUTH_FAILED */
780         "Authorizing the TPM response failed",
781         /* 28 - TSS2_BASE_RC_NO_CONFIG */
782         "No config is available",
783         /* 29 - TSS2_BASE_RC_BAD_PATH */
784         "The provided path is bad",
785         /* 30 - TSS2_BASE_RC_NOT_DELETABLE */
786         "The object is not deletable",
787         /* 31 - TSS2_BASE_RC_PATH_ALREADY_EXISTS */
788         "The provided path already exists",
789         /* 32 - TSS2_BASE_RC_KEY_NOT_FOUND */
790         "The key was not found",
791         /* 33 - TSS2_BASE_RC_SIGNATURE_VERIFICATION_FAILED */
792         "Signature verification failed",
793         /* 34 - TSS2_BASE_RC_HASH_MISMATCH */
794         "Hashes mismatch",
795         /* 35 - TSS2_BASE_RC_KEY_NOT_DUPLICABLE */
796         "Key is not duplicatable",
797         /* 36 - TSS2_BASE_RC_PATH_NOT_FOUND */
798         "The path was not found",
799         /* 37 - TSS2_BASE_RC_NO_CERT */
800         "No certificate",
801         /* 38 - TSS2_BASE_RC_NO_PCR */
802         "No PCR",
803         /* 39 - TSS2_BASE_RC_PCR_NOT_RESETTABLE */
804         "PCR not resettable",
805         /* 40 - TSS2_BASE_RC_BAD_TEMPLATE */
806         "The template is bad",
807         /* 41 - TSS2_BASE_RC_AUTHORIZATION_FAILED */
808         "Authorization failed",
809         /* 42 - TSS2_BASE_RC_AUTHORIZATION_UNKNOWN */
810         "Authorization is unknown",
811         /* 43 - TSS2_BASE_RC_NV_NOT_READABLE */
812         "NV is not readable",
813         /* 44 - TSS2_BASE_RC_NV_TOO_SMALL */
814         "NV is too small",
815         /* 45 - TSS2_BASE_RC_NV_NOT_WRITEABLE */
816         "NV is not writable",
817         /* 46 - TSS2_BASE_RC_POLICY_UNKNOWN */
818         "The policy is unknown",
819         /* 47 - TSS2_BASE_RC_NV_WRONG_TYPE */
820         "The NV type is wrong",
821         /* 48 - TSS2_BASE_RC_NAME_ALREADY_EXISTS */
822         "The name already exists",
823         /* 49 - TSS2_BASE_RC_NO_TPM */
824         "No TPM available",
825         /* 50 - TSS2_BASE_RC_BAD_KEY */
826         "The key is bad",
827         /* 51 - TSS2_BASE_RC_NO_HANDLE */
828         "No handle provided"
829   };
830 
831     return (rc - 1u < ARRAY_LEN(errors)) ? errors[rc - 1u] : NULL;
832 }
833 
834 
835 static struct {
836     char name[TSS2_ERR_LAYER_NAME_MAX];
837     TSS2_RC_HANDLER handler;
838 } layer_handler[TPM2_ERROR_TSS2_RC_LAYER_COUNT] = {
839     ADD_HANDLER("tpm" , tpm2_ehandler),
840     ADD_NULL_HANDLER,                       /* layer 1  is unused */
841     ADD_NULL_HANDLER,                       /* layer 2  is unused */
842     ADD_NULL_HANDLER,                       /* layer 3  is unused */
843     ADD_NULL_HANDLER,                       /* layer 4  is unused */
844     ADD_NULL_HANDLER,                       /* layer 5  is unused */
845     ADD_HANDLER("fapi", tss_err_handler),   /* layer 6  is the fapi rc */
846     ADD_HANDLER("esapi", tss_err_handler),  /* layer 7  is the esapi rc */
847     ADD_HANDLER("sys", tss_err_handler),    /* layer 8  is the sys rc */
848     ADD_HANDLER("mu",  tss_err_handler),    /* layer 9  is the mu rc */
849                                             /* Defaults to the system handler */
850     ADD_HANDLER("tcti", tss_err_handler),   /* layer 10 is the tcti rc */
851                                             /* Defaults to the system handler */
852     ADD_HANDLER("rmt", tpm2_ehandler),      /* layer 11 is the resource manager TPM RC */
853                                             /* The RM usually duplicates TPM responses */
854                                             /* So just default the handler to tpm2. */
855     ADD_HANDLER("rm", NULL),                /* layer 12 is the rm rc */
856     ADD_HANDLER("drvr", NULL),              /* layer 13 is the driver rc */
857 };
858 
859 /**
860  * If a layer has no handler registered, default to this
861  * handler that prints the error number in hex.
862  * @param rc
863  *  The rc to print the error number of.
864  * @return
865  *  The string.
866  */
867 static const char *
unknown_layer_handler(TSS2_RC rc)868 unknown_layer_handler(TSS2_RC rc)
869 {
870     static __thread char buf[32];
871 
872     clearbuf(buf);
873     catbuf(buf, "0x%X", tpm2_error_get(rc));
874 
875     return buf;
876 }
877 
878 /**
879  * Register or unregister a custom layer error handler.
880  * @param layer
881  *  The layer in which to register a handler for.
882  * @param name
883  *  A friendly layer name. If the name is NULL or a
884  *  length 0 string, then the name is output in base
885  *  10 string of the layer number. If the length of
886  *  name is greater than 16 characters, then the string
887  *  is truncated to 16 characters.
888  * @param handler
889  *  The handler function to register or NULL to unregister.
890  * @return
891  *  True on success or False on error.
892  */
893 TSS2_RC_HANDLER
Tss2_RC_SetHandler(UINT8 layer,const char * name,TSS2_RC_HANDLER handler)894 Tss2_RC_SetHandler(UINT8 layer, const char *name,
895                         TSS2_RC_HANDLER handler)
896 {
897     TSS2_RC_HANDLER old = layer_handler[layer].handler;
898 
899     layer_handler[layer].handler = handler;
900 
901     if (handler && name) {
902         snprintf(layer_handler[layer].name, sizeof(layer_handler[layer].name),
903              "%s", name);
904     } else {
905         memset(layer_handler[layer].name, 0, sizeof(layer_handler[layer].name));
906     }
907 
908     return old;
909 }
910 
911 /**
912  * Given a TSS2_RC return code, provides a static error string in the format:
913  * <layer-name>:<layer-specific-msg>.
914  *
915  * The layer-name section will either be the friendly name, or if no layer
916  * handler is registered, the base10 layer number.
917  *
918  * The "layer-specific-msg" is layer specific and will contain details on the
919  * error that occurred or the error code if it couldn't look it up.
920  *
921  * Known layer specific substrings:
922  * TPM - The tpm layer produces 2 distinct format codes that align with:
923  *   - Section 6.6 of: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
924  *   - Section 39.4 of: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf
925  *
926  *   The two formats are format 0 and format 1.
927  *   Format 0 string format:
928  *     - "<error|warn>(<version>): <description>
929  *     - Examples:
930  *       - error(1.2): bad tag
931  *       - warn(2.0): the 1st handle in the handle area references a transient object or session that is not loaded
932  *
933  *   Format 1 string format:
934  *      - <handle|session|parameter>(<index>):<description>
935  *      - Examples:
936  *        - handle(unk):value is out of range or is not correct for the context
937  *        - tpm:handle(5):value is out of range or is not correct for the context
938  *
939  *   Note that passing TPM2_RC_SUCCESS results in the layer specific message of "success".
940  *
941  *   The System, TCTI and Marshaling (MU) layers, all define simple string
942  *   returns analogous to strerror(3).
943  *
944  *   Unknown layers will have the layer number in decimal and then a layer specific string of
945  *   a hex value representing the error code. For example: 9:0x3
946  *
947  * @param rc
948  *  The error code to decode.
949  * @return
950  *  A human understandable error description string.
951  */
952 const char *
Tss2_RC_Decode(TSS2_RC rc)953 Tss2_RC_Decode(TSS2_RC rc)
954 {
955     static __thread char buf[TSS2_ERR_LAYER_NAME_MAX + TSS2_ERR_LAYER_ERROR_STR_MAX + 1];
956 
957     clearbuf(buf);
958 
959     UINT8 layer = tss2_rc_layer_number_get(rc);
960 
961     TSS2_RC_HANDLER handler = layer_handler[layer].handler;
962     const char *lname = layer_handler[layer].name;
963 
964     if (lname[0]) {
965         catbuf(buf, "%s:", lname);
966     } else {
967         catbuf(buf, "%u:", layer);
968     }
969 
970     handler = !handler ? unknown_layer_handler : handler;
971 
972     /*
973      * Handlers only need the error bits. This way they don't
974      * need to concern themselves with masking off the layer
975      * bits or anything else.
976      */
977     UINT16 err_bits = tpm2_error_get(rc);
978     const char *e = err_bits ? handler(err_bits) : "success";
979     if (e) {
980         catbuf(buf, "%s", e);
981     } else {
982         catbuf(buf, "0x%X", err_bits);
983     }
984 
985     return buf;
986 }
987