]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - lib/tpm.c
tpm: add missing va_end
[people/ms/u-boot.git] / lib / tpm.c
index f0b4f59eafc73d77e13c1d6d5ca775a081409296..d1cf5a8a1679fa7ab7f828c8b4290bb8aca80fe0 100644 (file)
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -2,30 +2,14 @@
  * Copyright (c) 2013 The Chromium OS Authors.
  * Coypright (c) 2013 Guntermann & Drunck GmbH
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
-#include <stdarg.h>
-#include <sha1.h>
+#include <dm.h>
 #include <tpm.h>
 #include <asm/unaligned.h>
+#include <u-boot/sha1.h>
 
 /* Internal error of TPM command library */
 #define TPM_LIB_ERROR  ((uint32_t)~0u)
@@ -33,7 +17,6 @@
 /* Useful constants */
 enum {
        COMMAND_BUFFER_SIZE             = 256,
-       TPM_PUBEK_SIZE                  = 256,
        TPM_REQUEST_HEADER_LENGTH       = 10,
        TPM_RESPONSE_HEADER_LENGTH      = 10,
        PCR_DIGEST_LENGTH               = 20,
@@ -112,8 +95,10 @@ int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
                        return -1;
                }
 
-               if (offset + length > size)
+               if (offset + length > size) {
+                       va_end(args);
                        return -1;
+               }
 
                switch (*format) {
                case 'b':
@@ -180,6 +165,7 @@ int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
                        length = va_arg(args, uint32_t);
                        break;
                default:
+                       va_end(args);
                        debug("Couldn't recognize format string\n");
                        return -1;
                }
@@ -246,9 +232,10 @@ static uint32_t tpm_return_code(const void *response)
 static uint32_t tpm_sendrecv_command(const void *command,
                void *response, size_t *size_ptr)
 {
+       struct udevice *dev;
+       int err, ret;
        uint8_t response_buffer[COMMAND_BUFFER_SIZE];
        size_t response_length;
-       uint32_t err;
 
        if (response) {
                response_length = *size_ptr;
@@ -256,9 +243,14 @@ static uint32_t tpm_sendrecv_command(const void *command,
                response = response_buffer;
                response_length = sizeof(response_buffer);
        }
-       err = tis_sendrecv(command, tpm_command_size(command),
-                       response, &response_length);
-       if (err)
+
+       ret = uclass_first_device_err(UCLASS_TPM, &dev);
+       if (ret)
+               return ret;
+       err = tpm_xfer(dev, command, tpm_command_size(command),
+                      response, &response_length);
+
+       if (err < 0)
                return TPM_LIB_ERROR;
        if (size_ptr)
                *size_ptr = response_length;
@@ -266,15 +258,15 @@ static uint32_t tpm_sendrecv_command(const void *command,
        return tpm_return_code(response);
 }
 
-uint32_t tpm_init(void)
+int tpm_init(void)
 {
-       uint32_t err;
+       int err;
+       struct udevice *dev;
 
-       err = tis_init();
+       err = uclass_first_device_err(UCLASS_TPM, &dev);
        if (err)
                return err;
-
-       return tis_open();
+       return tpm_open(dev);
 }
 
 uint32_t tpm_startup(enum tpm_startup_type mode)
@@ -605,6 +597,85 @@ uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
        return 0;
 }
 
+uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
+{
+       const uint8_t command[22] = {
+               0x0, 0xc1,              /* TPM_TAG */
+               0x0, 0x0, 0x0, 0x16,    /* parameter size */
+               0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
+               0x0, 0x0, 0x0, 0x4,     /* TPM_CAP_FLAG_PERM */
+               0x0, 0x0, 0x0, 0x4,     /* subcap size */
+               0x0, 0x0, 0x1, 0x8,     /* subcap value */
+       };
+       uint8_t response[COMMAND_BUFFER_SIZE];
+       size_t response_length = sizeof(response);
+       uint32_t err;
+
+       err = tpm_sendrecv_command(command, response, &response_length);
+       if (err)
+               return err;
+       memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
+
+       return 0;
+}
+
+uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
+{
+       const uint8_t command[22] = {
+               0x0, 0xc1,              /* TPM_TAG */
+               0x0, 0x0, 0x0, 0x16,    /* parameter size */
+               0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
+               0x0, 0x0, 0x0, 0x11,
+               0x0, 0x0, 0x0, 0x4,
+       };
+       const size_t index_offset = 18;
+       const size_t perm_offset = 60;
+       uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
+       size_t response_length = sizeof(response);
+       uint32_t err;
+
+       if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
+                            index_offset, index))
+               return TPM_LIB_ERROR;
+       err = tpm_sendrecv_command(buf, response, &response_length);
+       if (err)
+               return err;
+       if (unpack_byte_string(response, response_length, "d",
+                              perm_offset, perm))
+               return TPM_LIB_ERROR;
+
+       return 0;
+}
+
+#ifdef CONFIG_TPM_FLUSH_RESOURCES
+uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type)
+{
+       const uint8_t command[18] = {
+               0x00, 0xc1,             /* TPM_TAG */
+               0x00, 0x00, 0x00, 0x12, /* parameter size */
+               0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
+               0x00, 0x00, 0x00, 0x00, /* key handle */
+               0x00, 0x00, 0x00, 0x00, /* resource type */
+       };
+       const size_t key_handle_offset = 10;
+       const size_t resource_type_offset = 14;
+       uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
+       size_t response_length = sizeof(response);
+       uint32_t err;
+
+       if (pack_byte_string(buf, sizeof(buf), "sdd",
+                            0, command, sizeof(command),
+                            key_handle_offset, key_handle,
+                            resource_type_offset, resource_type))
+               return TPM_LIB_ERROR;
+
+       err = tpm_sendrecv_command(buf, response, &response_length);
+       if (err)
+               return err;
+       return 0;
+}
+#endif /* CONFIG_TPM_FLUSH_RESOURCES */
+
 #ifdef CONFIG_TPM_AUTH_SESSIONS
 
 /**
@@ -927,4 +998,44 @@ uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
        return 0;
 }
 
+#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
+uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t
+                          pubkey_digest[20], uint32_t *handle)
+{
+       uint16_t key_count;
+       uint32_t key_handles[10];
+       uint8_t buf[288];
+       uint8_t *ptr;
+       uint32_t err;
+       uint8_t digest[20];
+       size_t buf_len;
+       unsigned int i;
+
+       /* fetch list of already loaded keys in the TPM */
+       err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
+       if (err)
+               return -1;
+       key_count = get_unaligned_be16(buf);
+       ptr = buf + 2;
+       for (i = 0; i < key_count; ++i, ptr += 4)
+               key_handles[i] = get_unaligned_be32(ptr);
+
+       /* now search a(/ the) key which we can access with the given auth */
+       for (i = 0; i < key_count; ++i) {
+               buf_len = sizeof(buf);
+               err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
+               if (err && err != TPM_AUTHFAIL)
+                       return -1;
+               if (err)
+                       continue;
+               sha1_csum(buf, buf_len, digest);
+               if (!memcmp(digest, pubkey_digest, 20)) {
+                       *handle = key_handles[i];
+                       return 0;
+               }
+       }
+       return 1;
+}
+#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
+
 #endif /* CONFIG_TPM_AUTH_SESSIONS */