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