tpm2_hash.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdbool.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include "files.h"
  6. #include "log.h"
  7. #include "tpm2.h"
  8. #include "tpm2_hash.h"
  9. static tool_rc tpm2_hash_common(ESYS_CONTEXT *ectx, TPMI_ALG_HASH halg,
  10. TPMI_RH_HIERARCHY hierarchy, FILE *infilep, BYTE *inbuffer,
  11. UINT16 inbuffer_len, TPM2B_DIGEST **result,
  12. TPMT_TK_HASHCHECK **validation) {
  13. bool use_left = true, done;
  14. unsigned long left = inbuffer_len;
  15. size_t bytes_read;
  16. TPM2B_AUTH null_auth = TPM2B_EMPTY_INIT;
  17. TPMI_DH_OBJECT sequence_handle;
  18. TPM2B_MAX_BUFFER buffer;
  19. /* if we're using infilep, get file size */
  20. if (!!infilep) {
  21. /* Suppress error reporting with NULL path */
  22. use_left = files_get_file_size(infilep, &left, NULL);
  23. }
  24. /* if data length is non-zero (valid) and less than 1024, just do it in one
  25. hash invocation */
  26. if (use_left && left <= TPM2_MAX_DIGEST_BUFFER) {
  27. buffer.size = left;
  28. if (!!infilep) {
  29. bool res = files_read_bytes(infilep, buffer.buffer, buffer.size);
  30. if (!res) {
  31. return tool_rc_general_error;
  32. }
  33. } else {
  34. memcpy(buffer.buffer, inbuffer, buffer.size);
  35. }
  36. return tpm2_hash(ectx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
  37. &buffer, halg, hierarchy, result, validation);
  38. }
  39. /*
  40. * length is either unknown because the FILE * is a fifo, or it's too
  41. * big to do in a single hash call. Based on the size figure out the
  42. * chunks to loop over, if possible. This way we can call Complete with
  43. * data.
  44. */
  45. tool_rc rc = tpm2_hash_sequence_start(ectx, &null_auth, halg, &sequence_handle);
  46. if (rc != tool_rc_success) {
  47. return rc;
  48. }
  49. /* If we know the file size, we decrement the amount read and terminate
  50. * the loop when 1 block is left, else we go till feof.
  51. */
  52. done = false;
  53. while (!done) {
  54. /* if we're using infilep, read the file. Otherwise, directly
  55. copy into our local buffer. */
  56. buffer.size = BUFFER_SIZE(typeof(buffer), buffer);
  57. if (!!infilep) {
  58. bytes_read = fread(buffer.buffer, 1, buffer.size, infilep);
  59. if (ferror(infilep)) {
  60. LOG_ERR("Error reading from input file");
  61. return tool_rc_general_error;
  62. } else {
  63. buffer.size = bytes_read;
  64. }
  65. } else {
  66. memcpy(buffer.buffer, inbuffer, buffer.size);
  67. inbuffer = inbuffer + buffer.size;
  68. }
  69. rc = tpm2_sequence_update(ectx, sequence_handle, &buffer);
  70. if (rc != tool_rc_success) {
  71. return rc;
  72. }
  73. if (use_left) {
  74. left -= buffer.size;
  75. if (left <= TPM2_MAX_DIGEST_BUFFER) {
  76. done = true;
  77. continue;
  78. }
  79. } else if (!!infilep && feof(infilep)) {
  80. done = true;
  81. }
  82. } /* end file read/hash update loop */
  83. /* if there is data left, get the last bit of data from the file or
  84. buffer or set the size to zero */
  85. if (use_left) {
  86. buffer.size = left;
  87. if (!!infilep) {
  88. bool res = files_read_bytes(infilep, buffer.buffer, buffer.size);
  89. if (!res) {
  90. LOG_ERR("Error reading from input file.");
  91. return tool_rc_general_error;
  92. }
  93. } else {
  94. memcpy(buffer.buffer, inbuffer, buffer.size);
  95. }
  96. } else {
  97. buffer.size = 0;
  98. }
  99. return tpm2_sequence_complete(ectx, sequence_handle,
  100. &buffer, hierarchy, result, validation);
  101. }
  102. tool_rc tpm2_hash_compute_data(ESYS_CONTEXT *ectx, TPMI_ALG_HASH halg,
  103. TPMI_RH_HIERARCHY hierarchy, BYTE *buffer, UINT16 length,
  104. TPM2B_DIGEST **result, TPMT_TK_HASHCHECK **validation) {
  105. if (!buffer) {
  106. return tool_rc_general_error;
  107. }
  108. return tpm2_hash_common(ectx, halg, hierarchy, NULL, buffer, length, result,
  109. validation);
  110. }
  111. tool_rc tpm2_hash_file(ESYS_CONTEXT *ectx, TPMI_ALG_HASH halg,
  112. TPMI_RH_HIERARCHY hierarchy, FILE *input, TPM2B_DIGEST **result,
  113. TPMT_TK_HASHCHECK **validation) {
  114. if (!input) {
  115. return tool_rc_general_error;
  116. }
  117. return tpm2_hash_common(ectx, halg, hierarchy, input, NULL, 0, result,
  118. validation);
  119. }