]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - lib/tpm.c
Prepare for multiple bootcount drivers
[people/ms/u-boot.git] / lib / tpm.c
index d1cf5a8a1679fa7ab7f828c8b4290bb8aca80fe0..c8bf06178f17b90ab679e9424ac6441bbd047073 100644 (file)
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -92,6 +92,7 @@ int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
                        break;
                default:
                        debug("Couldn't recognize format string\n");
+                       va_end(args);
                        return -1;
                }
 
@@ -170,8 +171,10 @@ int unpack_byte_string(const 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':
@@ -607,14 +610,24 @@ uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
                0x0, 0x0, 0x0, 0x4,     /* subcap size */
                0x0, 0x0, 0x1, 0x8,     /* subcap value */
        };
+       const size_t data_size_offset = TPM_HEADER_SIZE;
+       const size_t data_offset = TPM_HEADER_SIZE + sizeof (uint32_t);
        uint8_t response[COMMAND_BUFFER_SIZE];
        size_t response_length = sizeof(response);
        uint32_t err;
+       uint32_t data_size;
 
        err = tpm_sendrecv_command(command, response, &response_length);
        if (err)
                return err;
-       memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
+       if (unpack_byte_string(response, response_length, "d",
+                              data_size_offset, &data_size))
+               return TPM_LIB_ERROR;
+       if (data_size < sizeof(*pflags))
+               return TPM_LIB_ERROR;
+       if (unpack_byte_string(response, response_length, "s",
+                              data_offset, pflags, sizeof(*pflags)))
+               return TPM_LIB_ERROR;
 
        return 0;
 }
@@ -1039,3 +1052,46 @@ uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t
 #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
 
 #endif /* CONFIG_TPM_AUTH_SESSIONS */
+
+uint32_t tpm_get_random(void *data, uint32_t count)
+{
+       const uint8_t command[14] = {
+               0x0, 0xc1,              /* TPM_TAG */
+               0x0, 0x0, 0x0, 0xe,     /* parameter size */
+               0x0, 0x0, 0x0, 0x46,    /* TPM_COMMAND_CODE */
+       };
+       const size_t length_offset = 10;
+       const size_t data_size_offset = 10;
+       const size_t data_offset = 14;
+       uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
+       size_t response_length = sizeof(response);
+       uint32_t data_size;
+       uint8_t *out = data;
+
+       while (count > 0) {
+               uint32_t this_bytes = min((size_t)count,
+                                         sizeof (response) - data_offset);
+               uint32_t err;
+
+               if (pack_byte_string(buf, sizeof(buf), "sd",
+                                    0, command, sizeof(command),
+                                    length_offset, this_bytes))
+                       return TPM_LIB_ERROR;
+               err = tpm_sendrecv_command(buf, response, &response_length);
+               if (err)
+                       return err;
+               if (unpack_byte_string(response, response_length, "d",
+                                      data_size_offset, &data_size))
+                       return TPM_LIB_ERROR;
+               if (data_size > count)
+                       return TPM_LIB_ERROR;
+               if (unpack_byte_string(response, response_length, "s",
+                                      data_offset, out, data_size))
+                       return TPM_LIB_ERROR;
+
+               count -= data_size;
+               out += data_size;
+       }
+
+       return 0;
+}