test_tpm2_policy.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <errno.h>
  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <setjmp.h>
  8. #include <cmocka.h>
  9. #include "pcr.h"
  10. #include "tpm2_policy.h"
  11. #include "tpm2_util.h"
  12. typedef struct pcr_data pcr_data;
  13. struct pcr_data {
  14. TPML_DIGEST values;
  15. };
  16. typedef struct test_file test_file;
  17. struct test_file {
  18. char *path;
  19. FILE *file;
  20. };
  21. /* Passing tests and static data are hardcoded around this sel spec */
  22. #define PCR_SEL_SPEC "sha256:0,1,2,3"
  23. /*
  24. * Dummy value for the session handle read by the wrapped version of:
  25. * Esys_StartAuthSession
  26. */
  27. #define SESSION_HANDLE 0xDEADBEEF
  28. /* dummy handle for esys context */
  29. #define ESAPI_CONTEXT ((ESYS_CONTEXT *)0xDEADBEEF)
  30. /* Any PCR read returns this value */
  31. static TPM2B_DIGEST pcr_value = {
  32. .size = 32,
  33. .buffer = {
  34. 0x96, 0xa7, 0xfa, 0xaf, 0x16, 0x09, 0xb6, 0x50, 0xa4, 0xf2,
  35. 0x88, 0xc0, 0x90, 0x4f, 0x04, 0x83, 0x6e, 0xca, 0xda, 0x2f,
  36. 0x49, 0x78, 0x06, 0x94, 0x86, 0xa2, 0xbb, 0x02, 0xf2, 0xf0,
  37. 0x43, 0xea
  38. }
  39. };
  40. /* The expected hash for the pcr selection of sha256:0,1,2,3 */
  41. static TPM2B_DIGEST expected_policy_digest = {
  42. .size = 32,
  43. .buffer = {
  44. 0x62, 0x69, 0x69, 0xce, 0xa7, 0xc2, 0xea, 0x7a, 0xf8, 0x86,
  45. 0xf4, 0xb5, 0x09, 0xa5, 0xb8, 0x3a, 0xb3, 0x3b, 0x3a, 0x75,
  46. 0x75, 0x5d, 0x17, 0x40, 0x38, 0xa8, 0xd3, 0x33, 0x0f, 0xa7,
  47. 0x2a, 0xd4
  48. }
  49. };
  50. TSS2_RC __wrap_Esys_StartAuthSession(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey,
  51. ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3,
  52. const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType,
  53. const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash,
  54. ESYS_TR *sessionHandle) {
  55. UNUSED(esysContext);
  56. UNUSED(tpmKey);
  57. UNUSED(bind);
  58. UNUSED(shandle1);
  59. UNUSED(shandle2);
  60. UNUSED(shandle3);
  61. UNUSED(nonceCaller);
  62. UNUSED(sessionType);
  63. UNUSED(symmetric);
  64. UNUSED(authHash);
  65. *sessionHandle = SESSION_HANDLE;
  66. return TPM2_RC_SUCCESS;
  67. }
  68. /*
  69. * The current digest passed via PolicyPCR and
  70. * PolicyGetDigest.
  71. */
  72. static TPM2B_DIGEST current_digest;
  73. TSS2_RC __wrap_Esys_PolicyPCR(ESYS_CONTEXT *esysContext, ESYS_TR policySession,
  74. ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3,
  75. const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) {
  76. UNUSED(esysContext);
  77. UNUSED(policySession);
  78. UNUSED(shandle1);
  79. UNUSED(shandle2);
  80. UNUSED(shandle3);
  81. UNUSED(pcrs);
  82. /*
  83. * Set the computed digest, which will be retrieved via
  84. * a call to Esys_PolicyGetDigest
  85. */
  86. current_digest = *pcrDigest;
  87. return TPM2_RC_SUCCESS;
  88. }
  89. TSS2_RC __wrap_Esys_PolicyGetDigest(ESYS_CONTEXT *esysContext,
  90. ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2,
  91. ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) {
  92. UNUSED(esysContext);
  93. UNUSED(policySession);
  94. UNUSED(shandle1);
  95. UNUSED(shandle2);
  96. UNUSED(shandle3);
  97. *policyDigest = &current_digest;
  98. return TPM2_RC_SUCCESS;
  99. }
  100. TSS2_RC __wrap_Esys_PCR_Read(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,
  101. ESYS_TR shandle2, ESYS_TR shandle3,
  102. const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter,
  103. TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues) {
  104. UNUSED(esysContext);
  105. UNUSED(shandle1);
  106. UNUSED(shandle2);
  107. UNUSED(shandle3);
  108. UNUSED(pcrSelectionIn);
  109. UNUSED(pcrUpdateCounter);
  110. UNUSED(pcrSelectionOut);
  111. *pcrValues = calloc(1, sizeof(TPML_DIGEST));
  112. if (*pcrValues == NULL) {
  113. return TPM2_RC_FAILURE;
  114. }
  115. UINT32 i;
  116. /* NOTE: magic number of 4... The prior (SAPI) implementation had a
  117. * semi-populated pcrValues with an appropriate count value set.
  118. * This ESAPI call allocates the pcrValues out-value and thus we don't have
  119. * an appropriate count number at call time, therefore we hard-code the
  120. * expected value for the *one* call we're currently making in this unit
  121. * test.
  122. */
  123. for (i = 0; i < 4; i++) {
  124. (*pcrValues)->digests[i] = pcr_value;
  125. }
  126. return TPM2_RC_SUCCESS;
  127. }
  128. TSS2_RC __wrap_Esys_FlushContext(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle) {
  129. UNUSED(esysContext);
  130. UNUSED(flushHandle);
  131. return TSS2_RC_SUCCESS;
  132. }
  133. static void test_tpm2_policy_build_pcr_good(void **state) {
  134. UNUSED(state);
  135. tpm2_session_data *d = tpm2_session_data_new(TPM2_SE_POLICY);
  136. assert_non_null(d);
  137. tpm2_session *s = NULL;
  138. tool_rc rc = tpm2_session_open(ESAPI_CONTEXT, d, &s);
  139. assert_int_equal(rc, tool_rc_success);
  140. assert_non_null(s);
  141. TPML_PCR_SELECTION pcr_selections;
  142. bool res = pcr_parse_selections(PCR_SEL_SPEC, &pcr_selections);
  143. assert_true(res);
  144. rc = tpm2_policy_build_pcr(ESAPI_CONTEXT, s, NULL, &pcr_selections, NULL);
  145. assert_int_equal(rc, tool_rc_success);
  146. TPM2B_DIGEST *policy_digest;
  147. rc = tpm2_policy_get_digest(ESAPI_CONTEXT, s, &policy_digest);
  148. assert_int_equal(rc, tool_rc_success);
  149. assert_int_equal(policy_digest->size, expected_policy_digest.size);
  150. assert_memory_equal(policy_digest->buffer, expected_policy_digest.buffer,
  151. expected_policy_digest.size);
  152. tpm2_session_close(&s);
  153. assert_null(s);
  154. }
  155. static test_file *test_file_new(void) {
  156. test_file *tf = malloc(sizeof(test_file));
  157. if (!tf) {
  158. return NULL;
  159. }
  160. tf->path = strdup("xxx_test_tpm2_policy_xxx.test");
  161. if (!tf->path) {
  162. free(tf);
  163. return NULL;
  164. }
  165. tf->file = fopen(tf->path, "w+b");
  166. if (!tf->file) {
  167. free(tf->path);
  168. free(tf);
  169. return NULL;
  170. }
  171. return tf;
  172. }
  173. static void test_file_free(test_file *tf) {
  174. assert_non_null(tf);
  175. int rc = remove(tf->path);
  176. assert_return_code(rc, errno);
  177. free(tf->path);
  178. fclose(tf->file);
  179. free(tf);
  180. }
  181. static int test_setup(void **state) {
  182. test_file *tf = test_file_new();
  183. assert_non_null(tf);
  184. *state = tf;
  185. return 0;
  186. }
  187. static int test_teardown(void **state) {
  188. test_file *tf = (test_file *) *state;
  189. test_file_free(tf);
  190. return 0;
  191. }
  192. static test_file *test_file_from_state(void **state) {
  193. test_file *f = (test_file *) *state;
  194. assert_non_null(f);
  195. return f;
  196. }
  197. static void test_tpm2_policy_build_pcr_file_good(void **state) {
  198. test_file *tf = test_file_from_state(state);
  199. assert_non_null(tf);
  200. /*
  201. * This PCR selection must not be to big to fit in the selection
  202. * array at index 0 byte index 0.
  203. *
  204. * If it is, the file generation below needs to change.
  205. */
  206. TPML_PCR_SELECTION pcr_selections;
  207. bool res = pcr_parse_selections(PCR_SEL_SPEC, &pcr_selections);
  208. assert_true(res);
  209. /*
  210. * create a file with the expected PCR hashes based on the number of pcr
  211. * selections. We know that the PCR selection above will always be in the
  212. * first selection array in the first byte.
  213. */
  214. UINT32 i;
  215. UINT32 cnt = tpm2_util_pop_count(
  216. pcr_selections.pcrSelections[0].pcrSelect[0]);
  217. for (i = 0; i < cnt; i++) {
  218. TPM2B_DIGEST *d = &pcr_value;
  219. size_t num = fwrite(d->buffer, d->size, 1, tf->file);
  220. assert_int_equal(num, 1);
  221. }
  222. int rc = fflush(tf->file);
  223. assert_int_equal(rc, 0);
  224. tpm2_session_data *d = tpm2_session_data_new(TPM2_SE_POLICY);
  225. assert_non_null(d);
  226. tpm2_session *s = NULL;
  227. tool_rc trc = tpm2_session_open(ESAPI_CONTEXT, d, &s);
  228. assert_int_equal(trc, tool_rc_success);
  229. assert_non_null(s);
  230. trc = tpm2_policy_build_pcr(ESAPI_CONTEXT, s, tf->path, &pcr_selections,
  231. NULL);
  232. assert_int_equal(trc, tool_rc_success);
  233. TPM2B_DIGEST *policy_digest;
  234. trc = tpm2_policy_get_digest(ESAPI_CONTEXT, s, &policy_digest);
  235. assert_int_equal(rc, tool_rc_success);
  236. assert_int_equal(policy_digest->size, expected_policy_digest.size);
  237. assert_memory_equal(policy_digest->buffer, expected_policy_digest.buffer,
  238. expected_policy_digest.size);
  239. tpm2_session_close(&s);
  240. assert_null(s);
  241. }
  242. static void test_tpm2_policy_build_pcr_file_bad_size(void **state) {
  243. test_file *tf = test_file_from_state(state);
  244. assert_non_null(tf);
  245. /*
  246. * This PCR selection must not be to big to fit in the selection
  247. * array at index 0 byte index 0.
  248. *
  249. * If it is, the file generation below needs to change.
  250. */
  251. TPML_PCR_SELECTION pcr_selections;
  252. bool res = pcr_parse_selections(PCR_SEL_SPEC, &pcr_selections);
  253. assert_true(res);
  254. /*
  255. * create a file with the expected PCR hashes based on the number of pcr
  256. * selections. We know that the PCR selection above will always be in the
  257. * first selection array in the first byte.
  258. */
  259. UINT32 i;
  260. /* force the size to be bad here by subtracting 1 */
  261. UINT32 cnt = tpm2_util_pop_count(
  262. pcr_selections.pcrSelections[0].pcrSelect[0]) - 1;
  263. for (i = 0; i < cnt; i++) {
  264. TPM2B_DIGEST *d = &pcr_value;
  265. size_t num = fwrite(d->buffer, d->size, 1, tf->file);
  266. assert_int_equal(num, 1);
  267. }
  268. int rc = fflush(tf->file);
  269. assert_int_equal(rc, 0);
  270. tpm2_session_data *d = tpm2_session_data_new(TPM2_SE_POLICY);
  271. assert_non_null(d);
  272. tpm2_session *s = NULL;
  273. tool_rc trc = tpm2_session_open(ESAPI_CONTEXT, d, &s);
  274. assert_int_equal(trc, tool_rc_success);
  275. assert_non_null(s);
  276. trc = tpm2_policy_build_pcr(ESAPI_CONTEXT, s, tf->path, &pcr_selections,
  277. NULL);
  278. tpm2_session_close(&s);
  279. assert_null(s);
  280. assert_int_equal(trc, tool_rc_general_error);
  281. }
  282. /* link required symbol, but tpm2_tool.c declares it AND main, which
  283. * we have a main below for cmocka tests.
  284. */
  285. bool output_enabled = true;
  286. int main(int argc, char *argv[]) {
  287. UNUSED(argc);
  288. UNUSED(argv);
  289. const struct CMUnitTest tests[] = {
  290. cmocka_unit_test(test_tpm2_policy_build_pcr_good),
  291. cmocka_unit_test_setup_teardown(test_tpm2_policy_build_pcr_file_good,
  292. test_setup, test_teardown),
  293. cmocka_unit_test_setup_teardown(test_tpm2_policy_build_pcr_file_bad_size,
  294. test_setup, test_teardown)
  295. };
  296. return cmocka_run_group_tests(tests, NULL, NULL);
  297. }