ubispl: add support for loading volumes by name
[oweals/u-boot.git] / lib / tpm-v2.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018 Bootlin
4  * Author: Miquel Raynal <miquel.raynal@bootlin.com>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <tpm-common.h>
10 #include <tpm-v2.h>
11 #include "tpm-utils.h"
12
13 u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
14 {
15         const u8 command_v2[12] = {
16                 tpm_u16(TPM2_ST_NO_SESSIONS),
17                 tpm_u32(12),
18                 tpm_u32(TPM2_CC_STARTUP),
19                 tpm_u16(mode),
20         };
21         int ret;
22
23         /*
24          * Note TPM2_Startup command will return RC_SUCCESS the first time,
25          * but will return RC_INITIALIZE otherwise.
26          */
27         ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
28         if (ret && ret != TPM2_RC_INITIALIZE)
29                 return ret;
30
31         return 0;
32 }
33
34 u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
35 {
36         const u8 command_v2[12] = {
37                 tpm_u16(TPM2_ST_NO_SESSIONS),
38                 tpm_u32(11),
39                 tpm_u32(TPM2_CC_SELF_TEST),
40                 full_test,
41         };
42
43         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
44 }
45
46 u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
47                const ssize_t pw_sz)
48 {
49         u8 command_v2[COMMAND_BUFFER_SIZE] = {
50                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
51                 tpm_u32(27 + pw_sz),            /* Length */
52                 tpm_u32(TPM2_CC_CLEAR),         /* Command code */
53
54                 /* HANDLE */
55                 tpm_u32(handle),                /* TPM resource handle */
56
57                 /* AUTH_SESSION */
58                 tpm_u32(9 + pw_sz),             /* Authorization size */
59                 tpm_u32(TPM2_RS_PW),            /* Session handle */
60                 tpm_u16(0),                     /* Size of <nonce> */
61                                                 /* <nonce> (if any) */
62                 0,                              /* Attributes: Cont/Excl/Rst */
63                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
64                 /* STRING(pw)                      <hmac/password> (if any) */
65         };
66         unsigned int offset = 27;
67         int ret;
68
69         /*
70          * Fill the command structure starting from the first buffer:
71          *     - the password (if any)
72          */
73         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
74                                offset, pw, pw_sz);
75         offset += pw_sz;
76         if (ret)
77                 return TPM_LIB_ERROR;
78
79         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
80 }
81
82 u32 tpm2_pcr_extend(struct udevice *dev, u32 index, const uint8_t *digest)
83 {
84         u8 command_v2[COMMAND_BUFFER_SIZE] = {
85                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
86                 tpm_u32(33 + TPM2_DIGEST_LEN),  /* Length */
87                 tpm_u32(TPM2_CC_PCR_EXTEND),    /* Command code */
88
89                 /* HANDLE */
90                 tpm_u32(index),                 /* Handle (PCR Index) */
91
92                 /* AUTH_SESSION */
93                 tpm_u32(9),                     /* Authorization size */
94                 tpm_u32(TPM2_RS_PW),            /* Session handle */
95                 tpm_u16(0),                     /* Size of <nonce> */
96                                                 /* <nonce> (if any) */
97                 0,                              /* Attributes: Cont/Excl/Rst */
98                 tpm_u16(0),                     /* Size of <hmac/password> */
99                                                 /* <hmac/password> (if any) */
100                 tpm_u32(1),                     /* Count (number of hashes) */
101                 tpm_u16(TPM2_ALG_SHA256),       /* Algorithm of the hash */
102                 /* STRING(digest)                  Digest */
103         };
104         unsigned int offset = 33;
105         int ret;
106
107         /*
108          * Fill the command structure starting from the first buffer:
109          *     - the digest
110          */
111         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
112                                offset, digest, TPM2_DIGEST_LEN);
113         offset += TPM2_DIGEST_LEN;
114         if (ret)
115                 return TPM_LIB_ERROR;
116
117         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
118 }
119
120 u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
121                   void *data, unsigned int *updates)
122 {
123         u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
124         u8 command_v2[COMMAND_BUFFER_SIZE] = {
125                 tpm_u16(TPM2_ST_NO_SESSIONS),   /* TAG */
126                 tpm_u32(17 + idx_array_sz),     /* Length */
127                 tpm_u32(TPM2_CC_PCR_READ),      /* Command code */
128
129                 /* TPML_PCR_SELECTION */
130                 tpm_u32(1),                     /* Number of selections */
131                 tpm_u16(TPM2_ALG_SHA256),       /* Algorithm of the hash */
132                 idx_array_sz,                   /* Array size for selection */
133                 /* bitmap(idx)                     Selected PCR bitmap */
134         };
135         size_t response_len = COMMAND_BUFFER_SIZE;
136         u8 response[COMMAND_BUFFER_SIZE];
137         unsigned int pcr_sel_idx = idx / 8;
138         u8 pcr_sel_bit = BIT(idx % 8);
139         unsigned int counter = 0;
140         int ret;
141
142         if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
143                              17 + pcr_sel_idx, pcr_sel_bit))
144                 return TPM_LIB_ERROR;
145
146         ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
147         if (ret)
148                 return ret;
149
150         if (unpack_byte_string(response, response_len, "ds",
151                                10, &counter,
152                                response_len - TPM2_DIGEST_LEN, data,
153                                TPM2_DIGEST_LEN))
154                 return TPM_LIB_ERROR;
155
156         if (updates)
157                 *updates = counter;
158
159         return 0;
160 }
161
162 u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
163                         void *buf, size_t prop_count)
164 {
165         u8 command_v2[COMMAND_BUFFER_SIZE] = {
166                 tpm_u16(TPM2_ST_NO_SESSIONS),           /* TAG */
167                 tpm_u32(22),                            /* Length */
168                 tpm_u32(TPM2_CC_GET_CAPABILITY),        /* Command code */
169
170                 tpm_u32(capability),                    /* Capability */
171                 tpm_u32(property),                      /* Property */
172                 tpm_u32(prop_count),                    /* Property count */
173         };
174         u8 response[COMMAND_BUFFER_SIZE];
175         size_t response_len = COMMAND_BUFFER_SIZE;
176         unsigned int properties_off;
177         int ret;
178
179         ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
180         if (ret)
181                 return ret;
182
183         /*
184          * In the response buffer, the properties are located after the:
185          * tag (u16), response size (u32), response code (u32),
186          * YES/NO flag (u8), TPM_CAP (u32) and TPMU_CAPABILITIES (u32).
187          */
188         properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
189                          sizeof(u8) + sizeof(u32) + sizeof(u32);
190         memcpy(buf, &response[properties_off], response_len - properties_off);
191
192         return 0;
193 }
194
195 u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
196 {
197         u8 command_v2[COMMAND_BUFFER_SIZE] = {
198                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
199                 tpm_u32(27 + pw_sz),            /* Length */
200                 tpm_u32(TPM2_CC_DAM_RESET),     /* Command code */
201
202                 /* HANDLE */
203                 tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
204
205                 /* AUTH_SESSION */
206                 tpm_u32(9 + pw_sz),             /* Authorization size */
207                 tpm_u32(TPM2_RS_PW),            /* Session handle */
208                 tpm_u16(0),                     /* Size of <nonce> */
209                                                 /* <nonce> (if any) */
210                 0,                              /* Attributes: Cont/Excl/Rst */
211                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
212                 /* STRING(pw)                      <hmac/password> (if any) */
213         };
214         unsigned int offset = 27;
215         int ret;
216
217         /*
218          * Fill the command structure starting from the first buffer:
219          *     - the password (if any)
220          */
221         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
222                                offset, pw, pw_sz);
223         offset += pw_sz;
224         if (ret)
225                 return TPM_LIB_ERROR;
226
227         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
228 }
229
230 u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
231                         const ssize_t pw_sz, unsigned int max_tries,
232                         unsigned int recovery_time,
233                         unsigned int lockout_recovery)
234 {
235         u8 command_v2[COMMAND_BUFFER_SIZE] = {
236                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
237                 tpm_u32(27 + pw_sz + 12),       /* Length */
238                 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
239
240                 /* HANDLE */
241                 tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
242
243                 /* AUTH_SESSION */
244                 tpm_u32(9 + pw_sz),             /* Authorization size */
245                 tpm_u32(TPM2_RS_PW),            /* Session handle */
246                 tpm_u16(0),                     /* Size of <nonce> */
247                                                 /* <nonce> (if any) */
248                 0,                              /* Attributes: Cont/Excl/Rst */
249                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
250                 /* STRING(pw)                      <hmac/password> (if any) */
251
252                 /* LOCKOUT PARAMETERS */
253                 /* tpm_u32(max_tries)              Max tries (0, always lock) */
254                 /* tpm_u32(recovery_time)          Recovery time (0, no lock) */
255                 /* tpm_u32(lockout_recovery)       Lockout recovery */
256         };
257         unsigned int offset = 27;
258         int ret;
259
260         /*
261          * Fill the command structure starting from the first buffer:
262          *     - the password (if any)
263          *     - max tries
264          *     - recovery time
265          *     - lockout recovery
266          */
267         ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
268                                offset, pw, pw_sz,
269                                offset + pw_sz, max_tries,
270                                offset + pw_sz + 4, recovery_time,
271                                offset + pw_sz + 8, lockout_recovery);
272         offset += pw_sz + 12;
273         if (ret)
274                 return TPM_LIB_ERROR;
275
276         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
277 }
278
279 int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
280                      const ssize_t newpw_sz, const char *oldpw,
281                      const ssize_t oldpw_sz)
282 {
283         unsigned int offset = 27;
284         u8 command_v2[COMMAND_BUFFER_SIZE] = {
285                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
286                 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
287                 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
288
289                 /* HANDLE */
290                 tpm_u32(handle),                /* TPM resource handle */
291
292                 /* AUTH_SESSION */
293                 tpm_u32(9 + oldpw_sz),          /* Authorization size */
294                 tpm_u32(TPM2_RS_PW),            /* Session handle */
295                 tpm_u16(0),                     /* Size of <nonce> */
296                                                 /* <nonce> (if any) */
297                 0,                              /* Attributes: Cont/Excl/Rst */
298                 tpm_u16(oldpw_sz)               /* Size of <hmac/password> */
299                 /* STRING(oldpw)                   <hmac/password> (if any) */
300
301                 /* TPM2B_AUTH (TPM2B_DIGEST) */
302                 /* tpm_u16(newpw_sz)               Digest size, new pw length */
303                 /* STRING(newpw)                   Digest buffer, new pw */
304         };
305         int ret;
306
307         /*
308          * Fill the command structure starting from the first buffer:
309          *     - the old password (if any)
310          *     - size of the new password
311          *     - new password
312          */
313         ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
314                                offset, oldpw, oldpw_sz,
315                                offset + oldpw_sz, newpw_sz,
316                                offset + oldpw_sz + 2, newpw, newpw_sz);
317         offset += oldpw_sz + 2 + newpw_sz;
318         if (ret)
319                 return TPM_LIB_ERROR;
320
321         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
322 }
323
324 u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
325                            const ssize_t pw_sz, u32 index, const char *key)
326 {
327         u8 command_v2[COMMAND_BUFFER_SIZE] = {
328                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
329                 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
330                 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
331
332                 /* HANDLE */
333                 tpm_u32(TPM2_RH_PLATFORM),      /* TPM resource handle */
334
335                 /* AUTH_SESSION */
336                 tpm_u32(9 + pw_sz),             /* Authorization size */
337                 tpm_u32(TPM2_RS_PW),            /* session handle */
338                 tpm_u16(0),                     /* Size of <nonce> */
339                                                 /* <nonce> (if any) */
340                 0,                              /* Attributes: Cont/Excl/Rst */
341                 tpm_u16(pw_sz)                  /* Size of <hmac/password> */
342                 /* STRING(pw)                      <hmac/password> (if any) */
343
344                 /* TPM2B_AUTH (TPM2B_DIGEST) */
345                 /* tpm_u16(TPM2_DIGEST_LEN)        Digest size length */
346                 /* STRING(key)                     Digest buffer (PCR key) */
347
348                 /* TPMI_ALG_HASH */
349                 /* tpm_u16(TPM2_ALG_SHA256)   Algorithm of the hash */
350
351                 /* TPMI_DH_PCR */
352                 /* tpm_u32(index),                 PCR Index */
353         };
354         unsigned int offset = 27;
355         int ret;
356
357         /*
358          * Fill the command structure starting from the first buffer:
359          *     - the password (if any)
360          *     - the PCR key length
361          *     - the PCR key
362          *     - the hash algorithm
363          *     - the PCR index
364          */
365         ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
366                                offset, pw, pw_sz,
367                                offset + pw_sz, TPM2_DIGEST_LEN,
368                                offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
369                                offset + pw_sz + 2 + TPM2_DIGEST_LEN,
370                                TPM2_ALG_SHA256,
371                                offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
372         offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
373         if (ret)
374                 return TPM_LIB_ERROR;
375
376         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
377 }
378
379 u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
380                           const ssize_t pw_sz, u32 index, const char *key,
381                           const ssize_t key_sz)
382 {
383         u8 command_v2[COMMAND_BUFFER_SIZE] = {
384                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
385                 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
386                 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
387
388                 /* HANDLE */
389                 tpm_u32(index),                 /* Handle (PCR Index) */
390
391                 /* AUTH_SESSION */
392                 tpm_u32(9 + pw_sz),             /* Authorization size */
393                 tpm_u32(TPM2_RS_PW),            /* session handle */
394                 tpm_u16(0),                     /* Size of <nonce> */
395                                                 /* <nonce> (if any) */
396                 0,                              /* Attributes: Cont/Excl/Rst */
397                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
398                 /* STRING(pw)                      <hmac/password> (if any) */
399
400                 /* TPM2B_DIGEST */
401                 /* tpm_u16(key_sz)                 Key length */
402                 /* STRING(key)                     Key */
403         };
404         unsigned int offset = 27;
405         int ret;
406
407         /*
408          * Fill the command structure starting from the first buffer:
409          *     - the password (if any)
410          *     - the number of digests, 1 in our case
411          *     - the algorithm, sha256 in our case
412          *     - the digest (64 bytes)
413          */
414         ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
415                                offset, pw, pw_sz,
416                                offset + pw_sz, key_sz,
417                                offset + pw_sz + 2, key, key_sz);
418         offset += pw_sz + 2 + key_sz;
419         if (ret)
420                 return TPM_LIB_ERROR;
421
422         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
423 }