xref: /openbmc/u-boot/lib/tpm-v2.c (revision 87a62bce)
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 }
420