1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <drivers/tpm2_chip.h>
8 #include <drivers/tpm2_cmd.h>
9 #include <io.h>
10 #include <kernel/panic.h>
11 #include <malloc.h>
12 #include <string.h>
13 #include <tpm2.h>
14 #include <trace.h>
15 
tpm2_cmd_init_hdr(void * buf,uint32_t len,uint16_t tag,uint32_t cmd_code)16 static void tpm2_cmd_init_hdr(void *buf, uint32_t len, uint16_t tag,
17 			      uint32_t cmd_code)
18 {
19 	struct tpm2_cmd *cmd = (struct tpm2_cmd *)buf;
20 
21 	assert(len >= sizeof(*cmd));
22 
23 	put_unaligned_be16(&cmd->hdr.tag, tag);
24 	put_unaligned_be32(&cmd->hdr.size, sizeof(struct tpm2_cmd_hdr));
25 	put_unaligned_be32(&cmd->hdr.code, cmd_code);
26 }
27 
tpm2_cmd_add(void * buf,uint32_t len,uint8_t * val,uint32_t val_len)28 static void tpm2_cmd_add(void *buf, uint32_t len, uint8_t *val,
29 			 uint32_t val_len)
30 {
31 	struct tpm2_cmd *cmd = (struct tpm2_cmd *)buf;
32 	uint32_t cmd_len = tpm2_cmd_len(cmd);
33 
34 	assert(len >= (cmd_len + val_len));
35 
36 	memcpy(&cmd->data[cmd_len - sizeof(struct tpm2_cmd_hdr)], val, val_len);
37 
38 	cmd_len += val_len;
39 	put_unaligned_be32(&cmd->hdr.size, cmd_len);
40 }
41 
tpm2_cmd_add_u8(void * buf,uint32_t len,uint8_t val)42 static void tpm2_cmd_add_u8(void *buf, uint32_t len, uint8_t val)
43 {
44 	tpm2_cmd_add(buf, len, &val, 1);
45 }
46 
tpm2_cmd_add_u16(void * buf,uint32_t len,uint16_t val)47 static void tpm2_cmd_add_u16(void *buf, uint32_t len, uint16_t val)
48 {
49 	uint16_t val_be = TEE_U16_FROM_BIG_ENDIAN(val);
50 
51 	tpm2_cmd_add(buf, len, (uint8_t *)&val_be, 2);
52 }
53 
tpm2_cmd_add_u32(void * buf,uint32_t len,uint32_t val)54 static void tpm2_cmd_add_u32(void *buf, uint32_t len, uint32_t val)
55 {
56 	uint32_t val_be = TEE_U32_FROM_BIG_ENDIAN(val);
57 
58 	tpm2_cmd_add(buf, len, (uint8_t *)&val_be, 4);
59 }
60 
61 /* Timeout has been picked up from Table 17 - Command Timing */
tpm2_get_cmd_duration(uint32_t cmd_code)62 static uint32_t tpm2_get_cmd_duration(uint32_t cmd_code)
63 {
64 	switch (cmd_code) {
65 	case TPM2_CC_STARTUP:
66 	case TPM2_CC_PCR_EXTEND:
67 	case TPM2_CC_GET_CAPABILITY:
68 		return TPM2_CMD_DURATION_MEDIUM;
69 	case TPM2_CC_SELFTEST:
70 	case TPM2_CC_NV_READ:
71 		return TPM2_CMD_DURATION_LONG;
72 	default:
73 		return TPM2_CMD_DURATION_DEFAULT;
74 	}
75 }
76 
tpm2_transmit(void * buf,uint32_t bufsz,void * resp,uint32_t * len)77 static enum tpm2_result tpm2_transmit(void *buf, uint32_t bufsz, void *resp,
78 				      uint32_t *len)
79 {
80 	uint32_t cmd_duration = 0;
81 	enum tpm2_result ret = TPM2_OK;
82 	uint32_t err_code = 0;
83 
84 	if (!buf || !resp || !len || (len && !*len))
85 		return TPM2_ERR_INVALID_ARG;
86 
87 	if (bufsz < tpm2_cmd_len(buf))
88 		return TPM2_ERR_INVALID_ARG;
89 
90 	DHEXDUMP(buf, tpm2_cmd_len(buf));
91 
92 	ret = tpm2_chip_send(buf, bufsz);
93 	if (ret)
94 		return ret;
95 
96 	cmd_duration = tpm2_get_cmd_duration(tpm2_cmd_code(buf));
97 
98 	ret = tpm2_chip_recv(resp, len, cmd_duration);
99 	if (ret)
100 		return ret;
101 
102 	err_code = tpm2_ret_code(resp);
103 	if (err_code) {
104 		EMSG("Command Error code %" PRIx32, err_code);
105 		ret = TPM2_ERR_CMD;
106 	}
107 
108 	DHEXDUMP(resp, tpm2_cmd_len(resp));
109 
110 	return ret;
111 }
112 
tpm2_startup(uint16_t mode)113 enum tpm2_result tpm2_startup(uint16_t mode)
114 {
115 	uint8_t buf[16] = { };
116 	uint32_t buf_len = sizeof(buf);
117 	uint8_t resp_buf[TPM2_HDR_LEN] = { };
118 	uint32_t resp_len = sizeof(resp_buf);
119 	enum tpm2_result ret = TPM2_OK;
120 
121 	tpm2_cmd_init_hdr(buf, buf_len, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
122 	tpm2_cmd_add_u16(buf, buf_len, mode);
123 
124 	ret = tpm2_transmit(buf, tpm2_cmd_len((struct tpm2_cmd *)buf), resp_buf,
125 			    &resp_len);
126 	if (ret == TPM2_ERR_SHORT_BUFFER)
127 		EMSG("Increase size of response buffer to %#" PRIx32, resp_len);
128 
129 	return ret;
130 }
131 
tpm2_selftest(uint8_t full)132 enum tpm2_result tpm2_selftest(uint8_t full)
133 {
134 	uint8_t buf[16] = { };
135 	uint32_t buf_len = sizeof(buf);
136 	uint8_t resp_buf[TPM2_HDR_LEN] = { };
137 	uint32_t resp_len = sizeof(resp_buf);
138 	enum tpm2_result ret = TPM2_OK;
139 
140 	tpm2_cmd_init_hdr(buf, buf_len, TPM2_ST_NO_SESSIONS, TPM2_CC_SELFTEST);
141 	tpm2_cmd_add_u8(buf, buf_len, full);
142 
143 	ret = tpm2_transmit(buf, tpm2_cmd_len((struct tpm2_cmd *)buf), resp_buf,
144 			    &resp_len);
145 	if (ret == TPM2_ERR_SHORT_BUFFER)
146 		EMSG("Increase size of response buffer to %#" PRIx32, resp_len);
147 
148 	return ret;
149 }
150 
tpm2_get_capability(uint32_t capability,uint32_t property,uint32_t prop_cnt,void * prop,uint32_t * prop_len)151 enum tpm2_result tpm2_get_capability(uint32_t capability, uint32_t property,
152 				     uint32_t prop_cnt, void *prop,
153 				     uint32_t *prop_len)
154 {
155 	uint8_t buf[32] = { };
156 	uint32_t buf_len = sizeof(buf);
157 	uint8_t *resp_buf = NULL;
158 	uint32_t resp_len = 256;
159 	uint32_t prop_offset = 0;
160 	enum tpm2_result ret = TPM2_OK;
161 
162 	if (!prop || !prop_len || !*prop_len)
163 		return TPM2_ERR_INVALID_ARG;
164 
165 	resp_buf = malloc(resp_len);
166 	if (!resp_buf)
167 		return TPM2_ERR_GENERIC;
168 
169 	tpm2_cmd_init_hdr(buf, buf_len, TPM2_ST_NO_SESSIONS,
170 			  TPM2_CC_GET_CAPABILITY);
171 	tpm2_cmd_add_u32(buf, buf_len, capability);
172 	tpm2_cmd_add_u32(buf, buf_len, property);
173 	tpm2_cmd_add_u32(buf, buf_len, prop_cnt);
174 
175 	ret = tpm2_transmit(buf, tpm2_cmd_len((struct tpm2_cmd *)buf), resp_buf,
176 			    &resp_len);
177 	if (ret)
178 		goto out;
179 
180 	resp_len = tpm2_cmd_len((struct tpm2_cmd *)resp_buf);
181 
182 	/*
183 	 * Response include
184 	 * tpm2_cmd_hdr [10 bytes]
185 	 * TPM1_YES_NO (byte)
186 	 * capability (uin32_t)
187 	 * capability data [ This is the property data to be returned ]
188 	 */
189 	prop_offset = sizeof(struct tpm2_cmd_hdr) + sizeof(uint8_t) +
190 		      sizeof(uint32_t);
191 
192 	if (*prop_len >= resp_len - prop_offset) {
193 		memcpy(prop, &resp_buf[prop_offset], resp_len - prop_offset);
194 	} else {
195 		EMSG("Response Buffer size for property too small");
196 		ret = TPM2_ERR_SHORT_BUFFER;
197 	}
198 
199 	*prop_len = resp_len - prop_offset;
200 out:
201 	free(resp_buf);
202 	return ret;
203 }
204 
tpm2_pcr_read(uint8_t pcr_idx,uint16_t alg,void * digest,uint32_t * digest_len)205 enum tpm2_result tpm2_pcr_read(uint8_t pcr_idx, uint16_t alg, void *digest,
206 			       uint32_t *digest_len)
207 {
208 	uint8_t buf[32] = { };
209 	uint8_t *resp_buf = NULL;
210 	uint32_t buf_len = sizeof(buf);
211 	uint32_t resp_len = 0;
212 	uint32_t alg_len = 0;
213 	uint32_t count = 1;
214 	uint32_t digest_offset = 0;
215 	uint8_t *pcr_select = 0;
216 	uint8_t pcr_select_idx = 0;
217 	uint8_t pcr_select_size = 0;
218 	struct tpm2_caps caps = { };
219 	enum tpm2_result ret = TPM2_OK;
220 	struct tpml_digest *resp_dgst = NULL;
221 	struct tpm2b_digest *dgst = resp_dgst->digest;
222 
223 	if (!digest || !digest_len)
224 		return TPM2_ERR_INVALID_ARG;
225 
226 	ret = tpm2_chip_get_caps(&caps);
227 	if (ret)
228 		return ret;
229 
230 	if (pcr_idx >= caps.num_pcrs || !tpm2_chip_is_active_bank(alg))
231 		return TPM2_ERR_INVALID_ARG;
232 
233 	alg_len = tpm2_get_alg_len(alg);
234 	if (*digest_len < alg_len)
235 		return TPM2_ERR_INVALID_ARG;
236 
237 	/*
238 	 * pcr_select is an array of octets where the octet contains the bit
239 	 * corresponding to a specific PCR. Octet index is found by dividing the
240 	 * PCR number by 8.
241 	 */
242 	pcr_select_idx = pcr_idx >> 3;
243 
244 	/*
245 	 * pcr_select_size indicates the number of octets in pcr_select. It's
246 	 * minimum value is available in caps structure.
247 	 */
248 	pcr_select_size = MAX(pcr_select_idx, caps.pcr_select_min);
249 
250 	/* Double check - the size shouldn't exceed TPM2_PCR_SELECT_MAX */
251 	if (pcr_select_size > TPM2_PCR_SELECT_MAX)
252 		return TPM2_ERR_INVALID_ARG;
253 
254 	pcr_select = calloc(pcr_select_size, sizeof(*pcr_select));
255 	if (!pcr_select)
256 		return TPM2_ERR_GENERIC;
257 
258 	pcr_select[pcr_select_idx] = BIT(pcr_idx % 8);
259 
260 	/* Create the PCR Read command */
261 	tpm2_cmd_init_hdr(buf, buf_len, TPM2_ST_NO_SESSIONS,
262 			  TPM2_CC_PCR_READ);
263 	/* TPML_PCR_SELECTION */
264 	tpm2_cmd_add_u32(buf, buf_len, count);
265 	tpm2_cmd_add_u16(buf, buf_len, alg);
266 	tpm2_cmd_add_u8(buf, buf_len, pcr_select_size);
267 	tpm2_cmd_add(buf, buf_len, pcr_select, pcr_select_size);
268 
269 	free(pcr_select);
270 
271 	/* Response includes:
272 	 * TPM Command header
273 	 * PCR update counter (uint32_t)
274 	 * TPML PCR Selection
275 	 * TPML DIGEST
276 	 */
277 	digest_offset = sizeof(struct tpm2_cmd_hdr) + sizeof(uint32_t) +
278 			offsetof(struct tpml_pcr_selection, pcr_selections) +
279 			offsetof(struct tpms_pcr_selection, pcr_select) +
280 			pcr_select_size;
281 	resp_len = digest_offset + sizeof(struct tpml_digest);
282 
283 	resp_buf = malloc(resp_len);
284 	if (!resp_buf)
285 		return TPM2_ERR_GENERIC;
286 
287 	ret = tpm2_transmit(buf, tpm2_cmd_len((struct tpm2_cmd *)buf), resp_buf,
288 			    &resp_len);
289 	if (ret)
290 		goto out;
291 
292 	resp_len = tpm2_cmd_len((struct tpm2_cmd *)resp_buf);
293 
294 	DHEXDUMP(resp_buf, tpm2_cmd_len((struct tpm2_cmd *)resp_buf));
295 
296 	if (digest_offset > resp_len) {
297 		ret = TPM2_ERR_GENERIC;
298 		goto out;
299 	}
300 
301 	resp_dgst = (struct tpml_digest *)&resp_buf[digest_offset];
302 	dgst = resp_dgst->digest;
303 
304 	/* We had requested for only 1 digest so expected count is 1 */
305 	if (get_be32(&resp_dgst->count) != 1) {
306 		ret = TPM2_ERR_GENERIC;
307 		goto out;
308 	}
309 
310 	if (get_be16(&dgst->size) != alg_len) {
311 		ret = TPM2_ERR_GENERIC;
312 		goto out;
313 	}
314 
315 	memcpy(digest, dgst->buffer, alg_len);
316 
317 	*digest_len = alg_len;
318 out:
319 	free(resp_buf);
320 	return ret;
321 }
322 
tpm2_add_password_auth_cmd(uint8_t * buf,uint32_t buf_len,uint8_t * passwd,uint32_t pass_sz)323 static enum tpm2_result tpm2_add_password_auth_cmd(uint8_t *buf,
324 						   uint32_t buf_len,
325 						   uint8_t *passwd,
326 						   uint32_t pass_sz)
327 {
328 	struct tpms_auth_command cmd = { };
329 	uint32_t auth_sz = 0;
330 
331 	if (pass_sz && (pass_sz > sizeof(cmd.hmac.buffer) || !passwd))
332 		return TPM2_ERR_INVALID_ARG;
333 
334 	cmd.handle = TPM_RS_PW;
335 	/* For password authorization, nonce is empty buffer */
336 	cmd.nonce.size = 0;
337 	/* Password session is always available so has no effect */
338 	cmd.session_attributes = 0;
339 	cmd.hmac.size = pass_sz;
340 
341 	auth_sz = sizeof(cmd.handle) + sizeof(cmd.nonce.size) +
342 		  sizeof(cmd.session_attributes) + sizeof(cmd.hmac.size) +
343 		  cmd.hmac.size;
344 
345 	tpm2_cmd_add_u32(buf, buf_len, auth_sz);
346 	tpm2_cmd_add_u32(buf, buf_len, cmd.handle);
347 	tpm2_cmd_add_u16(buf, buf_len, cmd.nonce.size);
348 	tpm2_cmd_add_u8(buf, buf_len, cmd.session_attributes);
349 	tpm2_cmd_add_u16(buf, buf_len, cmd.hmac.size);
350 	if (cmd.hmac.size)
351 		tpm2_cmd_add(buf, buf_len, passwd, pass_sz);
352 
353 	return TPM2_OK;
354 }
355 
tpm2_pcr_extend(uint8_t pcr_idx,uint16_t alg,void * digest,uint32_t digest_len)356 enum tpm2_result tpm2_pcr_extend(uint8_t pcr_idx, uint16_t alg, void *digest,
357 				 uint32_t digest_len)
358 {
359 	void *buf = NULL;
360 	uint32_t buf_len = 128;
361 	uint8_t *resp_buf = NULL;
362 	uint32_t resp_len = 256;
363 	uint32_t alg_len = 0;
364 	uint32_t count = 1;
365 	struct tpm2_caps caps = { };
366 	enum tpm2_result ret = TPM2_OK;
367 
368 	if (!digest)
369 		return TPM2_ERR_INVALID_ARG;
370 
371 	ret = tpm2_chip_get_caps(&caps);
372 	if (ret)
373 		return ret;
374 
375 	if (pcr_idx >= caps.num_pcrs || !tpm2_chip_is_active_bank(alg))
376 		return TPM2_ERR_INVALID_ARG;
377 
378 	alg_len = tpm2_get_alg_len(alg);
379 	if (digest_len < alg_len)
380 		return TPM2_ERR_INVALID_ARG;
381 
382 	/* CMD size will not exceed 128 bytes */
383 	buf = malloc(buf_len);
384 	if (!buf)
385 		return TPM2_ERR_GENERIC;
386 
387 	resp_buf = malloc(resp_len);
388 	if (!resp_buf) {
389 		free(buf);
390 		return TPM2_ERR_GENERIC;
391 	}
392 
393 	tpm2_cmd_init_hdr(buf, buf_len, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
394 
395 	/* PCR Handle */
396 	tpm2_cmd_add_u32(buf, buf_len, pcr_idx);
397 
398 	/* Add NULL authorization structure */
399 	ret = tpm2_add_password_auth_cmd(buf, buf_len, NULL, 0);
400 	if (ret)
401 		goto out;
402 
403 	/*
404 	 * Add TPML_DIGEST_VALUES structure, we are adding
405 	 * a single digest.
406 	 */
407 	tpm2_cmd_add_u32(buf, buf_len, count);
408 	tpm2_cmd_add_u16(buf, buf_len, alg);
409 	tpm2_cmd_add(buf, buf_len, digest, digest_len);
410 
411 	ret = tpm2_transmit(buf, tpm2_cmd_len((struct tpm2_cmd *)buf), resp_buf,
412 			    &resp_len);
413 	if (ret)
414 		goto out;
415 
416 	DHEXDUMP(resp_buf, tpm2_cmd_len((struct tpm2_cmd *)resp_buf));
417 out:
418 	free(resp_buf);
419 	free(buf);
420 
421 	return ret;
422 }
423