Commit 0f4b2ba1762d74c0b5520d99a58796d6ca78abf0

Authored by mario.six@gdsys.cc
Committed by Simon Glass
1 parent 5efa1bfbfa

tpm: Add function to load keys via their parent's SHA1 hash

If we want to load a key into a TPM, we need to know the designated parent
key's handle, so that the TPM is able to insert the key at the correct place in
the key hierarchy.

However, if we want to load a key whose designated parent key we also
previously loaded ourselves, we first need to memorize this parent key's handle
(since the handles for the key are chosen at random when they are inserted into
the TPM). If we are, however, unable to do so, for example if the parent key is
loaded into the TPM during production, and its child key during the actual
boot, we must find a different mechanism to identify the parent key.

To solve this problem, we add a function that allows U-Boot to load a key into
the TPM using their designated parent key's SHA1 hash, and the corresponding
auth data.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
Reviewed-by: Simon Glass <sjg@chromium.org>

Showing 4 changed files with 109 additions and 0 deletions Side-by-side Diff

... ... @@ -592,6 +592,45 @@
592 592 return report_return_code(err);
593 593 }
594 594  
  595 +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
  596 +static int do_tpm_load_key_by_sha1(cmd_tbl_t *cmdtp, int flag, int argc, char *
  597 + const argv[])
  598 +{
  599 + uint32_t parent_handle = 0;
  600 + uint32_t key_len, key_handle, err;
  601 + uint8_t usage_auth[DIGEST_LENGTH];
  602 + uint8_t parent_hash[DIGEST_LENGTH];
  603 + void *key;
  604 +
  605 + if (argc < 5)
  606 + return CMD_RET_USAGE;
  607 +
  608 + parse_byte_string(argv[1], parent_hash, NULL);
  609 + key = (void *)simple_strtoul(argv[2], NULL, 0);
  610 + key_len = simple_strtoul(argv[3], NULL, 0);
  611 + if (strlen(argv[4]) != 2 * DIGEST_LENGTH)
  612 + return CMD_RET_FAILURE;
  613 + parse_byte_string(argv[4], usage_auth, NULL);
  614 +
  615 + err = tpm_find_key_sha1(usage_auth, parent_hash, &parent_handle);
  616 + if (err) {
  617 + printf("Could not find matching parent key (err = %d)\n", err);
  618 + return CMD_RET_FAILURE;
  619 + }
  620 +
  621 + printf("Found parent key %08x\n", parent_handle);
  622 +
  623 + err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth,
  624 + &key_handle);
  625 + if (!err) {
  626 + printf("Key handle is 0x%x\n", key_handle);
  627 + setenv_hex("key_handle", key_handle);
  628 + }
  629 +
  630 + return report_return_code(err);
  631 +}
  632 +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
  633 +
595 634 static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag,
596 635 int argc, char * const argv[])
597 636 {
... ... @@ -756,6 +795,10 @@
756 795 do_tpm_end_oiap, "", ""),
757 796 U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1,
758 797 do_tpm_load_key2_oiap, "", ""),
  798 +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
  799 + U_BOOT_CMD_MKENT(load_key_by_sha1, 0, 1,
  800 + do_tpm_load_key_by_sha1, "", ""),
  801 +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
759 802 U_BOOT_CMD_MKENT(get_pub_key_oiap, 0, 1,
760 803 do_tpm_get_pub_key_oiap, "", ""),
761 804 #endif /* CONFIG_TPM_AUTH_SESSIONS */
... ... @@ -826,6 +869,12 @@
826 869 " - loads a key data from memory address <key_addr>, <key_len> bytes\n"
827 870 " into TPM using the parent key <parent_handle> with authorization\n"
828 871 " <usage_auth> (20 bytes hex string).\n"
  872 +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
  873 +" load_key_by_sha1 parent_hash key_addr key_len usage_auth\n"
  874 +" - loads a key data from memory address <key_addr>, <key_len> bytes\n"
  875 +" into TPM using the parent hash <parent_hash> (20 bytes hex string)\n"
  876 +" with authorization <usage_auth> (20 bytes hex string).\n"
  877 +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
829 878 " get_pub_key_oiap key_handle usage_auth\n"
830 879 " - get the public key portion of a loaded key <key_handle> using\n"
831 880 " authorization <usage auth> (20 bytes hex string)\n"
... ... @@ -88,5 +88,13 @@
88 88 help
89 89 Enable support to flush specific resources (e.g. keys) from the TPM.
90 90 The functionality is available via the 'tpm' command as well.
  91 +
  92 +config TPM_LOAD_KEY_BY_SHA1
  93 + bool "Enable TPM key loading by SHA1 support"
  94 + depends on TPM
  95 + help
  96 + Enable support to load keys into the TPM by identifying
  97 + their parent via the public key's SHA1 hash.
  98 + The functionality is available via the 'tpm' command as well.
91 99 endmenu
... ... @@ -639,5 +639,17 @@
639 639 */
640 640 uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type);
641 641  
  642 +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
  643 +/**
  644 + * Search for a key by usage AuthData and the hash of the parent's pub key.
  645 + *
  646 + * @param auth Usage auth of the key to search for
  647 + * @param pubkey_digest SHA1 hash of the pub key structure of the key
  648 + * @param[out] handle The handle of the key (Non-null iff found)
  649 + * @return 0 if key was found in TPM; != 0 if not.
  650 + */
  651 +uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t
  652 + pubkey_digest[20], uint32_t *handle);
  653 +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
642 654 #endif /* __TPM_H */
... ... @@ -996,5 +996,45 @@
996 996 return 0;
997 997 }
998 998  
  999 +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
  1000 +uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t
  1001 + pubkey_digest[20], uint32_t *handle)
  1002 +{
  1003 + uint16_t key_count;
  1004 + uint32_t key_handles[10];
  1005 + uint8_t buf[288];
  1006 + uint8_t *ptr;
  1007 + uint32_t err;
  1008 + uint8_t digest[20];
  1009 + size_t buf_len;
  1010 + unsigned int i;
  1011 +
  1012 + /* fetch list of already loaded keys in the TPM */
  1013 + err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
  1014 + if (err)
  1015 + return -1;
  1016 + key_count = get_unaligned_be16(buf);
  1017 + ptr = buf + 2;
  1018 + for (i = 0; i < key_count; ++i, ptr += 4)
  1019 + key_handles[i] = get_unaligned_be32(ptr);
  1020 +
  1021 + /* now search a(/ the) key which we can access with the given auth */
  1022 + for (i = 0; i < key_count; ++i) {
  1023 + buf_len = sizeof(buf);
  1024 + err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
  1025 + if (err && err != TPM_AUTHFAIL)
  1026 + return -1;
  1027 + if (err)
  1028 + continue;
  1029 + sha1_csum(buf, buf_len, digest);
  1030 + if (!memcmp(digest, pubkey_digest, 20)) {
  1031 + *handle = key_handles[i];
  1032 + return 0;
  1033 + }
  1034 + }
  1035 + return 1;
  1036 +}
  1037 +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
  1038 +
999 1039 #endif /* CONFIG_TPM_AUTH_SESSIONS */