1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2018 Bootlin
4 * Author: Miquel Raynal <miquel.raynal@bootlin.com>
9 #include <tpm-common.h>
11 #include "tpm-utils.h"
13 u32 tpm2_startup(enum tpm2_startup_types mode)
15 const u8 command_v2[12] = {
16 tpm_u16(TPM2_ST_NO_SESSIONS),
18 tpm_u32(TPM2_CC_STARTUP),
24 * Note TPM2_Startup command will return RC_SUCCESS the first time,
25 * but will return RC_INITIALIZE otherwise.
27 ret = tpm_sendrecv_command(command_v2, NULL, NULL);
28 if (ret && ret != TPM2_RC_INITIALIZE)
34 u32 tpm2_self_test(enum tpm2_yes_no full_test)
36 const u8 command_v2[12] = {
37 tpm_u16(TPM2_ST_NO_SESSIONS),
39 tpm_u32(TPM2_CC_SELF_TEST),
43 return tpm_sendrecv_command(command_v2, NULL, NULL);
46 u32 tpm2_clear(u32 handle, const char *pw, const ssize_t pw_sz)
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 */
54 tpm_u32(handle), /* TPM resource handle */
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) */
65 unsigned int offset = 27;
69 * Fill the command structure starting from the first buffer:
70 * - the password (if any)
72 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
78 return tpm_sendrecv_command(command_v2, NULL, NULL);
81 u32 tpm2_pcr_extend(u32 index, const uint8_t *digest)
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 */
89 tpm_u32(index), /* Handle (PCR Index) */
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 */
103 unsigned int offset = 33;
107 * Fill the command structure starting from the first buffer:
110 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
111 offset, digest, TPM2_DIGEST_LEN);
112 offset += TPM2_DIGEST_LEN;
114 return TPM_LIB_ERROR;
116 return tpm_sendrecv_command(command_v2, NULL, NULL);
119 u32 tpm2_pcr_read(u32 idx, unsigned int idx_min_sz, void *data,
120 unsigned int *updates)
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 */
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 */
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;
141 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
142 17 + pcr_sel_idx, pcr_sel_bit))
143 return TPM_LIB_ERROR;
145 ret = tpm_sendrecv_command(command_v2, response, &response_len);
149 if (unpack_byte_string(response, response_len, "ds",
151 response_len - TPM2_DIGEST_LEN, data,
153 return TPM_LIB_ERROR;
161 u32 tpm2_get_capability(u32 capability, u32 property, void *buf,
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 */
169 tpm_u32(capability), /* Capability */
170 tpm_u32(property), /* Property */
171 tpm_u32(prop_count), /* Property count */
173 u8 response[COMMAND_BUFFER_SIZE];
174 size_t response_len = COMMAND_BUFFER_SIZE;
175 unsigned int properties_off;
178 ret = tpm_sendrecv_command(command_v2, response, &response_len);
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).
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);
194 u32 tpm2_dam_reset(const char *pw, const ssize_t pw_sz)
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 */
202 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
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) */
213 unsigned int offset = 27;
217 * Fill the command structure starting from the first buffer:
218 * - the password (if any)
220 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
224 return TPM_LIB_ERROR;
226 return tpm_sendrecv_command(command_v2, NULL, NULL);
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)
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 */
239 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
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) */
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 */
255 unsigned int offset = 27;
259 * Fill the command structure starting from the first buffer:
260 * - the password (if any)
265 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
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;
272 return TPM_LIB_ERROR;
274 return tpm_sendrecv_command(command_v2, NULL, NULL);
277 int tpm2_change_auth(u32 handle, const char *newpw, const ssize_t newpw_sz,
278 const char *oldpw, const ssize_t oldpw_sz)
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 */
287 tpm_u32(handle), /* TPM resource handle */
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) */
298 /* TPM2B_AUTH (TPM2B_DIGEST) */
299 /* tpm_u16(newpw_sz) Digest size, new pw length */
300 /* STRING(newpw) Digest buffer, new pw */
305 * Fill the command structure starting from the first buffer:
306 * - the old password (if any)
307 * - size of the new password
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;
316 return TPM_LIB_ERROR;
318 return tpm_sendrecv_command(command_v2, NULL, NULL);
321 u32 tpm2_pcr_setauthpolicy(const char *pw, const ssize_t pw_sz, u32 index,
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 */
330 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
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) */
341 /* TPM2B_AUTH (TPM2B_DIGEST) */
342 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
343 /* STRING(key) Digest buffer (PCR key) */
346 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
349 /* tpm_u32(index), PCR Index */
351 unsigned int offset = 27;
355 * Fill the command structure starting from the first buffer:
356 * - the password (if any)
357 * - the PCR key length
359 * - the hash algorithm
362 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
364 offset + pw_sz, TPM2_DIGEST_LEN,
365 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
366 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
368 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
369 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
371 return TPM_LIB_ERROR;
373 return tpm_sendrecv_command(command_v2, NULL, NULL);
376 u32 tpm2_pcr_setauthvalue(const char *pw, const ssize_t pw_sz, u32 index,
377 const char *key, const ssize_t key_sz)
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 */
385 tpm_u32(index), /* Handle (PCR Index) */
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) */
397 /* tpm_u16(key_sz) Key length */
398 /* STRING(key) Key */
400 unsigned int offset = 27;
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)
410 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
412 offset + pw_sz, key_sz,
413 offset + pw_sz + 2, key, key_sz);
414 offset += pw_sz + 2 + key_sz;
416 return TPM_LIB_ERROR;
418 return tpm_sendrecv_command(command_v2, NULL, NULL);