efi_loader: check parameters in memory allocation
[platform/kernel/u-boot.git] / lib / tpm-common.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013 The Chromium OS Authors.
4  * Coypright (c) 2013 Guntermann & Drunck GmbH
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <asm/unaligned.h>
10 #include <tpm-common.h>
11 #include "tpm-utils.h"
12
13 int pack_byte_string(u8 *str, size_t size, const char *format, ...)
14 {
15         va_list args;
16         size_t offset = 0, length = 0;
17         u8 *data = NULL;
18         u32 value = 0;
19
20         va_start(args, format);
21         for (; *format; format++) {
22                 switch (*format) {
23                 case 'b':
24                         offset = va_arg(args, size_t);
25                         value = va_arg(args, int);
26                         length = 1;
27                         break;
28                 case 'w':
29                         offset = va_arg(args, size_t);
30                         value = va_arg(args, int);
31                         length = 2;
32                         break;
33                 case 'd':
34                         offset = va_arg(args, size_t);
35                         value = va_arg(args, u32);
36                         length = 4;
37                         break;
38                 case 's':
39                         offset = va_arg(args, size_t);
40                         data = va_arg(args, u8 *);
41                         length = va_arg(args, u32);
42                         break;
43                 default:
44                         debug("Couldn't recognize format string\n");
45                         va_end(args);
46                         return -1;
47                 }
48
49                 if (offset + length > size) {
50                         va_end(args);
51                         return -1;
52                 }
53
54                 switch (*format) {
55                 case 'b':
56                         str[offset] = value;
57                         break;
58                 case 'w':
59                         put_unaligned_be16(value, str + offset);
60                         break;
61                 case 'd':
62                         put_unaligned_be32(value, str + offset);
63                         break;
64                 case 's':
65                         memcpy(str + offset, data, length);
66                         break;
67                 }
68         }
69         va_end(args);
70
71         return 0;
72 }
73
74 int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
75 {
76         va_list args;
77         size_t offset = 0, length = 0;
78         u8 *ptr8 = NULL;
79         u16 *ptr16 = NULL;
80         u32 *ptr32 = NULL;
81
82         va_start(args, format);
83         for (; *format; format++) {
84                 switch (*format) {
85                 case 'b':
86                         offset = va_arg(args, size_t);
87                         ptr8 = va_arg(args, u8 *);
88                         length = 1;
89                         break;
90                 case 'w':
91                         offset = va_arg(args, size_t);
92                         ptr16 = va_arg(args, u16 *);
93                         length = 2;
94                         break;
95                 case 'd':
96                         offset = va_arg(args, size_t);
97                         ptr32 = va_arg(args, u32 *);
98                         length = 4;
99                         break;
100                 case 's':
101                         offset = va_arg(args, size_t);
102                         ptr8 = va_arg(args, u8 *);
103                         length = va_arg(args, u32);
104                         break;
105                 default:
106                         va_end(args);
107                         debug("Couldn't recognize format string\n");
108                         return -1;
109                 }
110
111                 if (offset + length > size) {
112                         va_end(args);
113                         return -1;
114                 }
115
116                 switch (*format) {
117                 case 'b':
118                         *ptr8 = str[offset];
119                         break;
120                 case 'w':
121                         *ptr16 = get_unaligned_be16(str + offset);
122                         break;
123                 case 'd':
124                         *ptr32 = get_unaligned_be32(str + offset);
125                         break;
126                 case 's':
127                         memcpy(ptr8, str + offset, length);
128                         break;
129                 }
130         }
131         va_end(args);
132
133         return 0;
134 }
135
136 u32 tpm_command_size(const void *command)
137 {
138         const size_t command_size_offset = 2;
139
140         return get_unaligned_be32(command + command_size_offset);
141 }
142
143 u32 tpm_return_code(const void *response)
144 {
145         const size_t return_code_offset = 6;
146
147         return get_unaligned_be32(response + return_code_offset);
148 }
149
150 u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr)
151 {
152         struct udevice *dev;
153         int err, ret;
154         u8 response_buffer[COMMAND_BUFFER_SIZE];
155         size_t response_length;
156         int i;
157
158         if (response) {
159                 response_length = *size_ptr;
160         } else {
161                 response = response_buffer;
162                 response_length = sizeof(response_buffer);
163         }
164
165         ret = uclass_first_device_err(UCLASS_TPM, &dev);
166         if (ret)
167                 return ret;
168         err = tpm_xfer(dev, command, tpm_command_size(command),
169                        response, &response_length);
170
171         if (err < 0)
172                 return err;
173
174         if (size_ptr)
175                 *size_ptr = response_length;
176
177         ret = tpm_return_code(response);
178
179         log(LOGC_NONE, LOGL_DEBUG, "TPM response [ret:%d]: ", ret);
180         for (i = 0; i < response_length; i++)
181                 log(LOGC_NONE, LOGL_DEBUG, "%02x ", ((u8 *)response)[i]);
182         log(LOGC_NONE, LOGL_DEBUG, "\n");
183
184         return ret;
185 }
186
187 int tpm_init(void)
188 {
189         struct udevice *dev;
190         int err;
191
192         err = uclass_first_device_err(UCLASS_TPM, &dev);
193         if (err)
194                 return err;
195
196         return tpm_open(dev);
197 }