tpm2_nv_util.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #ifndef LIB_TPM2_NV_UTIL_H_
  3. #define LIB_TPM2_NV_UTIL_H_
  4. #include <tss2/tss2_esys.h>
  5. #include <string.h>
  6. #include "log.h"
  7. #include "tpm2.h"
  8. #include "tpm2_capability.h"
  9. #include "tpm2_session.h"
  10. #include "tpm2_auth_util.h"
  11. #include "tpm2_hierarchy.h"
  12. #include "tpm2_util.h"
  13. /*
  14. * The default buffer size when one cannot be determined via get capability.
  15. */
  16. #define NV_DEFAULT_BUFFER_SIZE 512
  17. /**
  18. * Reads the public portion of a Non-Volatile (nv) index.
  19. * @param context
  20. * The ESAPI context.
  21. * @param nv_index
  22. * The index to read.
  23. * @param nv_public
  24. * The public data structure to store the results in.
  25. * @return
  26. * tool_rc indicating status.
  27. */
  28. static inline tool_rc tpm2_util_nv_read_public(ESYS_CONTEXT *context,
  29. TPMI_RH_NV_INDEX nv_index, TPM2B_NV_PUBLIC **nv_public) {
  30. ESYS_TR tr_object;
  31. tool_rc rc = tpm2_from_tpm_public(context, nv_index, ESYS_TR_NONE,
  32. ESYS_TR_NONE, ESYS_TR_NONE, &tr_object);
  33. if (rc != tool_rc_success) {
  34. return rc;
  35. }
  36. rc = tpm2_nv_readpublic(context, tr_object, nv_public, NULL);
  37. tool_rc tmp_rc = tpm2_close(context, &tr_object);
  38. if (tmp_rc != tool_rc_success) {
  39. rc = tmp_rc;
  40. }
  41. return rc;
  42. }
  43. /**
  44. * Retrieves the maximum transmission size for an NV buffer by
  45. * querying the capabilities for TPM2_PT_NV_BUFFER_MAX.
  46. * @param context
  47. * The Enhanced System API (ESAPI) context
  48. * @param size
  49. * The size of the buffer.
  50. * @return
  51. * tool_rc Indicating status.
  52. */
  53. static inline tool_rc tpm2_util_nv_max_buffer_size(ESYS_CONTEXT *ectx,
  54. UINT32 *size) {
  55. /* Get the maximum read block size */
  56. TPMS_CAPABILITY_DATA *cap_data;
  57. TPMI_YES_NO more_data;
  58. tool_rc rc = tpm2_getcap(ectx, TPM2_CAP_TPM_PROPERTIES,
  59. TPM2_PT_NV_BUFFER_MAX, 1, &more_data, &cap_data);
  60. if (rc != tool_rc_success) {
  61. return rc;
  62. }
  63. if ( cap_data->data.tpmProperties.tpmProperty[0].property == TPM2_PT_NV_BUFFER_MAX ) {
  64. *size = cap_data->data.tpmProperties.tpmProperty[0].value;
  65. } else {
  66. /* TPM2_PT_NV_BUFFER_MAX is not part of the module spec <= 0.98*/
  67. *size = NV_DEFAULT_BUFFER_SIZE;
  68. }
  69. free(cap_data);
  70. return rc;
  71. }
  72. /**
  73. * Reads data at Non-Volatile (nv) index.
  74. * @param ectx
  75. * The ESAPI context.
  76. * @param nv_index
  77. * The index to read.
  78. * @param size
  79. * The number of bytes to read.
  80. * @param offset
  81. * Offset (in bytes) from which to start reading.
  82. * @param hierarchy
  83. * TPMI_RH_NV hierarchy value.
  84. * @param sdata
  85. * Session authorization
  86. * @param sess
  87. * tpm2 session.
  88. * @param data_buffer
  89. * (callee-allocated) Buffer containing data at nv_index
  90. * @param bytes_written
  91. * The number of bytes written to data_buffer
  92. * @return
  93. * tool_rc indicating status.
  94. */
  95. static inline tool_rc tpm2_util_nv_read(ESYS_CONTEXT *ectx,
  96. TPMI_RH_NV_INDEX nv_index, UINT16 size, UINT16 offset,
  97. tpm2_loaded_object * auth_hierarchy_obj, UINT8 **data_buffer,
  98. UINT16 *bytes_written, TPM2B_DIGEST *cp_hash) {
  99. *data_buffer = NULL;
  100. TPM2B_NV_PUBLIC *nv_public = NULL;
  101. tool_rc rc = tpm2_util_nv_read_public(ectx, nv_index, &nv_public);
  102. if (rc != tool_rc_success) {
  103. goto out;
  104. }
  105. UINT16 data_size = nv_public->nvPublic.dataSize;
  106. free(nv_public);
  107. /* if size is 0, assume the whole object */
  108. if (size == 0) {
  109. size = data_size;
  110. }
  111. if (offset > data_size) {
  112. LOG_ERR("Requested offset to read from is greater than size. offset=%u"
  113. ", size=%u", offset, data_size);
  114. rc = tool_rc_general_error;
  115. goto out;
  116. }
  117. if (offset + size > data_size) {
  118. LOG_ERR("Requested to read more bytes than available from offset,"
  119. " offset=%u, request-read-size=%u actual-data-size=%u", offset,
  120. size, data_size);
  121. rc = tool_rc_general_error;
  122. goto out;
  123. }
  124. if (cp_hash) {
  125. goto tpm2_util_nv_read_collect_cp_hash;
  126. }
  127. UINT32 max_data_size;
  128. rc = tpm2_util_nv_max_buffer_size(ectx, &max_data_size);
  129. if (rc != tool_rc_success) {
  130. goto out;
  131. }
  132. if (max_data_size > TPM2_MAX_NV_BUFFER_SIZE) {
  133. max_data_size = TPM2_MAX_NV_BUFFER_SIZE;
  134. } else if (max_data_size == 0) {
  135. max_data_size = NV_DEFAULT_BUFFER_SIZE;
  136. }
  137. tpm2_util_nv_read_collect_cp_hash:
  138. if (cp_hash) {
  139. TPM2B_MAX_NV_BUFFER *nv_data;
  140. rc = tpm2_nv_read(ectx, auth_hierarchy_obj, nv_index, size, offset,
  141. &nv_data, cp_hash);
  142. if (rc != tool_rc_success) {
  143. LOG_ERR("Failed cpHash for NVRAM read at index 0x%X", nv_index);
  144. }
  145. goto out;
  146. }
  147. *data_buffer = malloc(data_size);
  148. if (!*data_buffer) {
  149. LOG_ERR("oom");
  150. rc = tool_rc_general_error;
  151. goto out;
  152. }
  153. UINT16 data_offset = 0;
  154. while (size > 0) {
  155. UINT16 bytes_to_read = size > max_data_size ? max_data_size : size;
  156. TPM2B_MAX_NV_BUFFER *nv_data;
  157. rc = tpm2_nv_read(ectx, auth_hierarchy_obj, nv_index, bytes_to_read,
  158. offset, &nv_data, cp_hash);
  159. if (rc != tool_rc_success) {
  160. LOG_ERR("Failed to read NVRAM area at index 0x%X", nv_index);
  161. goto out;
  162. }
  163. size -= nv_data->size;
  164. offset += nv_data->size;
  165. memcpy(*data_buffer + data_offset, nv_data->buffer, nv_data->size);
  166. data_offset += nv_data->size;
  167. free(nv_data);
  168. }
  169. if (bytes_written) {
  170. *bytes_written = data_offset;
  171. }
  172. out:
  173. if (rc != tool_rc_success && *data_buffer != NULL) {
  174. free(*data_buffer);
  175. *data_buffer = NULL;
  176. }
  177. return rc;
  178. }
  179. static inline bool on_arg_nv_index(int argc, char **argv,
  180. TPMI_RH_NV_INDEX *nv_index) {
  181. if (argc > 1) {
  182. LOG_ERR("Specify single value for NV Index");
  183. return false;
  184. }
  185. if (!argc) {
  186. LOG_ERR("Specify at least a single value for NV Index");
  187. return false;
  188. }
  189. bool result = tpm2_util_handle_from_optarg(argv[0], nv_index,
  190. TPM2_HANDLE_FLAGS_NV);
  191. if (!result) {
  192. LOG_ERR("Could not convert NV index to number, got: \"%s\"", argv[0]);
  193. return false;
  194. }
  195. if (*nv_index == 0) {
  196. LOG_ERR("NV Index cannot be 0");
  197. return false;
  198. }
  199. return true;
  200. }
  201. #endif /* LIB_TPM2_NV_UTIL_H_ */