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