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