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