tpm2_capability.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdbool.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "log.h"
  6. #include "tpm2.h"
  7. #include "tpm2_capability.h"
  8. #define APPEND_CAPABILITY_INFORMATION(capability, field, subfield, max_count) \
  9. if (fetched_data->data.capability.count > max_count - property_count) { \
  10. fetched_data->data.capability.count = max_count - property_count; \
  11. } \
  12. \
  13. memmove(&(*capability_data)->data.capability.field[property_count], \
  14. fetched_data->data.capability.field, \
  15. fetched_data->data.capability.count * sizeof(fetched_data->data.capability.field[0])); \
  16. property_count += fetched_data->data.capability.count; \
  17. \
  18. (*capability_data)->data.capability.count = property_count; \
  19. \
  20. if (more_data && property_count < count && fetched_data->data.capability.count) { \
  21. property = (*capability_data)->data.capability.field[property_count - 1]subfield + 1; \
  22. } else { \
  23. more_data = false; \
  24. }
  25. tool_rc tpm2_capability_get(ESYS_CONTEXT *ectx, TPM2_CAP capability,
  26. UINT32 property, UINT32 count, TPMS_CAPABILITY_DATA **capability_data) {
  27. TPMI_YES_NO more_data;
  28. UINT32 property_count = 0;
  29. *capability_data = NULL;
  30. do {
  31. /* fetch capability info */
  32. TPMS_CAPABILITY_DATA *fetched_data = NULL;
  33. tool_rc rc = tpm2_get_capability(ectx, ESYS_TR_NONE, ESYS_TR_NONE,
  34. ESYS_TR_NONE, capability, property, count - property_count,
  35. &more_data, &fetched_data);
  36. LOG_INFO("GetCapability: capability: 0x%x, property: 0x%x", capability,
  37. property);
  38. if (rc != tool_rc_success) {
  39. if (*capability_data) {
  40. free(*capability_data);
  41. *capability_data = NULL;
  42. }
  43. return rc;
  44. }
  45. if (fetched_data->capability != capability) {
  46. LOG_ERR("TPM returned different capability than requested: 0x%x != "
  47. "0x%x", fetched_data->capability, capability);
  48. free(fetched_data);
  49. if (*capability_data) {
  50. free(*capability_data);
  51. *capability_data = NULL;
  52. }
  53. return tool_rc_general_error;
  54. }
  55. if (*capability_data == NULL) {
  56. /* reuse the TPM's result structure */
  57. *capability_data = fetched_data;
  58. if (!more_data) {
  59. /* there won't be another iteration of the loop, just return the result unmodified */
  60. return tool_rc_success;
  61. }
  62. }
  63. /* append the TPM's results to the initial structure, as long as there is still space left */
  64. switch (capability) {
  65. case TPM2_CAP_ALGS:
  66. APPEND_CAPABILITY_INFORMATION(algorithms, algProperties, .alg,
  67. TPM2_MAX_CAP_ALGS);
  68. break;
  69. case TPM2_CAP_HANDLES:
  70. APPEND_CAPABILITY_INFORMATION(handles, handle,,
  71. TPM2_MAX_CAP_HANDLES);
  72. break;
  73. case TPM2_CAP_COMMANDS:
  74. APPEND_CAPABILITY_INFORMATION(command, commandAttributes,,
  75. TPM2_MAX_CAP_CC);
  76. /* workaround because tpm2-tss does not implement attribute commandIndex for TPMA_CC */
  77. property &= TPMA_CC_COMMANDINDEX_MASK;
  78. break;
  79. case TPM2_CAP_PP_COMMANDS:
  80. APPEND_CAPABILITY_INFORMATION(ppCommands, commandCodes,,
  81. TPM2_MAX_CAP_CC);
  82. break;
  83. case TPM2_CAP_AUDIT_COMMANDS:
  84. APPEND_CAPABILITY_INFORMATION(auditCommands, commandCodes,,
  85. TPM2_MAX_CAP_CC);
  86. break;
  87. case TPM2_CAP_PCRS:
  88. APPEND_CAPABILITY_INFORMATION(assignedPCR, pcrSelections, .hash,
  89. TPM2_NUM_PCR_BANKS);
  90. break;
  91. case TPM2_CAP_TPM_PROPERTIES:
  92. APPEND_CAPABILITY_INFORMATION(tpmProperties, tpmProperty, .property,
  93. TPM2_MAX_TPM_PROPERTIES);
  94. break;
  95. case TPM2_CAP_PCR_PROPERTIES:
  96. APPEND_CAPABILITY_INFORMATION(pcrProperties, pcrProperty, .tag,
  97. TPM2_MAX_PCR_PROPERTIES);
  98. break;
  99. case TPM2_CAP_ECC_CURVES:
  100. APPEND_CAPABILITY_INFORMATION(eccCurves, eccCurves,,
  101. TPM2_MAX_ECC_CURVES);
  102. break;
  103. case TPM2_CAP_VENDOR_PROPERTY:
  104. APPEND_CAPABILITY_INFORMATION(intelPttProperty, property,,
  105. TPM2_MAX_PTT_PROPERTIES);
  106. break;
  107. default:
  108. LOG_ERR("Unsupported capability: 0x%x\n", capability);
  109. if (fetched_data != *capability_data) {
  110. free(fetched_data);
  111. }
  112. free(*capability_data);
  113. *capability_data = NULL;
  114. return tool_rc_general_error;
  115. }
  116. if (fetched_data != *capability_data) {
  117. free(fetched_data);
  118. }
  119. } while (more_data);
  120. return tool_rc_success;
  121. }
  122. tool_rc tpm2_capability_find_vacant_persistent_handle(ESYS_CONTEXT *ctx,
  123. bool is_platform, TPMI_DH_PERSISTENT *vacant) {
  124. TPMS_CAPABILITY_DATA *capability_data;
  125. bool handle_found = false;
  126. tool_rc rc = tpm2_capability_get(ctx, TPM2_CAP_HANDLES,
  127. TPM2_PERSISTENT_FIRST, TPM2_MAX_CAP_HANDLES, &capability_data);
  128. if (rc != tool_rc_success) {
  129. return rc;
  130. }
  131. UINT32 count = capability_data->data.handles.count;
  132. if (count == 0) {
  133. /* There aren't any persistent handles, so use the first */
  134. *vacant = is_platform ? TPM2_PLATFORM_PERSISTENT : TPM2_PERSISTENT_FIRST;
  135. handle_found = true;
  136. } else if (count == TPM2_MAX_CAP_HANDLES) {
  137. /* All persistent handles are already in use */
  138. goto out;
  139. } else if (count < TPM2_MAX_CAP_HANDLES) {
  140. /*
  141. * iterate over used handles to ensure we're selecting
  142. * the next available handle.
  143. *
  144. * Platform handles start at a higher hange
  145. */
  146. UINT32 i;
  147. for (i = is_platform ? TPM2_PLATFORM_PERSISTENT : TPM2_PERSISTENT_FIRST;
  148. i <= (UINT32) TPM2_PERSISTENT_LAST; ++i) {
  149. bool inuse = false;
  150. UINT32 c;
  151. for (c = 0; c < count; ++c) {
  152. if (capability_data->data.handles.handle[c] == i) {
  153. inuse = true;
  154. break;
  155. }
  156. }
  157. if (!is_platform && i >= TPM2_PLATFORM_PERSISTENT) {
  158. break;
  159. }
  160. if (!inuse) {
  161. *vacant = i;
  162. handle_found = true;
  163. break;
  164. }
  165. }
  166. }
  167. out:
  168. free(capability_data);
  169. return handle_found ? tool_rc_success : tool_rc_general_error;
  170. }