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