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