2 * Copyright (C) 2016 Intel Corporation
5 * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
7 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
9 * This file contains TPM2 protocol implementations of the commands
10 * used by the kernel internally.
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; version 2
18 #include <linux/gfp.h>
19 #include <asm/unaligned.h>
22 enum tpm2_handle_types
{
23 TPM2_HT_HMAC_SESSION
= 0x02000000,
24 TPM2_HT_POLICY_SESSION
= 0x03000000,
25 TPM2_HT_TRANSIENT
= 0x80000000,
35 static void tpm2_flush_sessions(struct tpm_chip
*chip
, struct tpm_space
*space
)
39 for (i
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++) {
40 if (space
->session_tbl
[i
])
41 tpm2_flush_context_cmd(chip
, space
->session_tbl
[i
],
42 TPM_TRANSMIT_UNLOCKED
|
47 int tpm2_init_space(struct tpm_space
*space
)
49 space
->context_buf
= kzalloc(PAGE_SIZE
, GFP_KERNEL
);
50 if (!space
->context_buf
)
53 space
->session_buf
= kzalloc(PAGE_SIZE
, GFP_KERNEL
);
54 if (space
->session_buf
== NULL
) {
55 kfree(space
->context_buf
);
62 void tpm2_del_space(struct tpm_chip
*chip
, struct tpm_space
*space
)
64 mutex_lock(&chip
->tpm_mutex
);
65 tpm2_flush_sessions(chip
, space
);
66 mutex_unlock(&chip
->tpm_mutex
);
67 kfree(space
->context_buf
);
68 kfree(space
->session_buf
);
71 static int tpm2_load_context(struct tpm_chip
*chip
, u8
*buf
,
72 unsigned int *offset
, u32
*handle
)
75 struct tpm2_context
*ctx
;
76 unsigned int body_size
;
79 rc
= tpm_buf_init(&tbuf
, TPM2_ST_NO_SESSIONS
, TPM2_CC_CONTEXT_LOAD
);
83 ctx
= (struct tpm2_context
*)&buf
[*offset
];
84 body_size
= sizeof(*ctx
) + be16_to_cpu(ctx
->blob_size
);
85 tpm_buf_append(&tbuf
, &buf
[*offset
], body_size
);
87 rc
= tpm_transmit_cmd(chip
, NULL
, tbuf
.data
, PAGE_SIZE
, 4,
88 TPM_TRANSMIT_UNLOCKED
| TPM_TRANSMIT_RAW
, NULL
);
90 dev_warn(&chip
->dev
, "%s: failed with a system error %d\n",
92 tpm_buf_destroy(&tbuf
);
94 } else if (tpm2_rc_value(rc
) == TPM2_RC_HANDLE
||
95 rc
== TPM2_RC_REFERENCE_H0
) {
97 * TPM_RC_HANDLE means that the session context can't
98 * be loaded because of an internal counter mismatch
99 * that makes the TPM think there might have been a
100 * replay. This might happen if the context was saved
101 * and loaded outside the space.
103 * TPM_RC_REFERENCE_H0 means the session has been
104 * flushed outside the space
107 tpm_buf_destroy(&tbuf
);
110 dev_warn(&chip
->dev
, "%s: failed with a TPM error 0x%04X\n",
112 tpm_buf_destroy(&tbuf
);
116 *handle
= be32_to_cpup((__be32
*)&tbuf
.data
[TPM_HEADER_SIZE
]);
117 *offset
+= body_size
;
119 tpm_buf_destroy(&tbuf
);
123 static int tpm2_save_context(struct tpm_chip
*chip
, u32 handle
, u8
*buf
,
124 unsigned int buf_size
, unsigned int *offset
)
127 unsigned int body_size
;
130 rc
= tpm_buf_init(&tbuf
, TPM2_ST_NO_SESSIONS
, TPM2_CC_CONTEXT_SAVE
);
134 tpm_buf_append_u32(&tbuf
, handle
);
136 rc
= tpm_transmit_cmd(chip
, NULL
, tbuf
.data
, PAGE_SIZE
, 0,
137 TPM_TRANSMIT_UNLOCKED
| TPM_TRANSMIT_RAW
, NULL
);
139 dev_warn(&chip
->dev
, "%s: failed with a system error %d\n",
141 tpm_buf_destroy(&tbuf
);
143 } else if (tpm2_rc_value(rc
) == TPM2_RC_REFERENCE_H0
) {
144 tpm_buf_destroy(&tbuf
);
147 dev_warn(&chip
->dev
, "%s: failed with a TPM error 0x%04X\n",
149 tpm_buf_destroy(&tbuf
);
153 body_size
= tpm_buf_length(&tbuf
) - TPM_HEADER_SIZE
;
154 if ((*offset
+ body_size
) > buf_size
) {
155 dev_warn(&chip
->dev
, "%s: out of backing storage\n", __func__
);
156 tpm_buf_destroy(&tbuf
);
160 memcpy(&buf
[*offset
], &tbuf
.data
[TPM_HEADER_SIZE
], body_size
);
161 *offset
+= body_size
;
162 tpm_buf_destroy(&tbuf
);
166 static void tpm2_flush_space(struct tpm_chip
*chip
)
168 struct tpm_space
*space
= &chip
->work_space
;
171 for (i
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++)
172 if (space
->context_tbl
[i
] && ~space
->context_tbl
[i
])
173 tpm2_flush_context_cmd(chip
, space
->context_tbl
[i
],
174 TPM_TRANSMIT_UNLOCKED
|
177 tpm2_flush_sessions(chip
, space
);
180 static int tpm2_load_space(struct tpm_chip
*chip
)
182 struct tpm_space
*space
= &chip
->work_space
;
187 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
188 if (!space
->context_tbl
[i
])
191 /* sanity check, should never happen */
192 if (~space
->context_tbl
[i
]) {
193 dev_err(&chip
->dev
, "context table is inconsistent");
197 rc
= tpm2_load_context(chip
, space
->context_buf
, &offset
,
198 &space
->context_tbl
[i
]);
203 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++) {
206 if (!space
->session_tbl
[i
])
209 rc
= tpm2_load_context(chip
, space
->session_buf
,
212 /* load failed, just forget session */
213 space
->session_tbl
[i
] = 0;
215 tpm2_flush_space(chip
);
218 if (handle
!= space
->session_tbl
[i
]) {
219 dev_warn(&chip
->dev
, "session restored to wrong handle\n");
220 tpm2_flush_space(chip
);
228 static bool tpm2_map_to_phandle(struct tpm_space
*space
, void *handle
)
230 u32 vhandle
= be32_to_cpup((__be32
*)handle
);
234 i
= 0xFFFFFF - (vhandle
& 0xFFFFFF);
235 if (i
>= ARRAY_SIZE(space
->context_tbl
) || !space
->context_tbl
[i
])
238 phandle
= space
->context_tbl
[i
];
239 *((__be32
*)handle
) = cpu_to_be32(phandle
);
243 static int tpm2_map_command(struct tpm_chip
*chip
, u32 cc
, u8
*cmd
)
245 struct tpm_space
*space
= &chip
->work_space
;
246 unsigned int nr_handles
;
251 i
= tpm2_find_cc(chip
, cc
);
255 attrs
= chip
->cc_attrs_tbl
[i
];
256 nr_handles
= (attrs
>> TPM2_CC_ATTR_CHANDLES
) & GENMASK(2, 0);
258 handle
= (__be32
*)&cmd
[TPM_HEADER_SIZE
];
259 for (i
= 0; i
< nr_handles
; i
++, handle
++) {
260 if ((be32_to_cpu(*handle
) & 0xFF000000) == TPM2_HT_TRANSIENT
) {
261 if (!tpm2_map_to_phandle(space
, handle
))
269 int tpm2_prepare_space(struct tpm_chip
*chip
, struct tpm_space
*space
, u32 cc
,
277 memcpy(&chip
->work_space
.context_tbl
, &space
->context_tbl
,
278 sizeof(space
->context_tbl
));
279 memcpy(&chip
->work_space
.session_tbl
, &space
->session_tbl
,
280 sizeof(space
->session_tbl
));
281 memcpy(chip
->work_space
.context_buf
, space
->context_buf
, PAGE_SIZE
);
282 memcpy(chip
->work_space
.session_buf
, space
->session_buf
, PAGE_SIZE
);
284 rc
= tpm2_load_space(chip
);
286 tpm2_flush_space(chip
);
290 rc
= tpm2_map_command(chip
, cc
, cmd
);
292 tpm2_flush_space(chip
);
299 static bool tpm2_add_session(struct tpm_chip
*chip
, u32 handle
)
301 struct tpm_space
*space
= &chip
->work_space
;
304 for (i
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++)
305 if (space
->session_tbl
[i
] == 0)
308 if (i
== ARRAY_SIZE(space
->session_tbl
))
311 space
->session_tbl
[i
] = handle
;
315 static u32
tpm2_map_to_vhandle(struct tpm_space
*space
, u32 phandle
, bool alloc
)
319 for (i
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
321 if (!space
->context_tbl
[i
]) {
322 space
->context_tbl
[i
] = phandle
;
325 } else if (space
->context_tbl
[i
] == phandle
)
329 if (i
== ARRAY_SIZE(space
->context_tbl
))
332 return TPM2_HT_TRANSIENT
| (0xFFFFFF - i
);
335 static int tpm2_map_response_header(struct tpm_chip
*chip
, u32 cc
, u8
*rsp
,
338 struct tpm_space
*space
= &chip
->work_space
;
339 struct tpm_output_header
*header
= (void *)rsp
;
346 if (be32_to_cpu(header
->return_code
) != TPM2_RC_SUCCESS
)
349 i
= tpm2_find_cc(chip
, cc
);
350 /* sanity check, should never happen */
354 attrs
= chip
->cc_attrs_tbl
[i
];
355 if (!((attrs
>> TPM2_CC_ATTR_RHANDLE
) & 1))
358 phandle
= be32_to_cpup((__be32
*)&rsp
[TPM_HEADER_SIZE
]);
359 phandle_type
= phandle
& 0xFF000000;
361 switch (phandle_type
) {
362 case TPM2_HT_TRANSIENT
:
363 vhandle
= tpm2_map_to_vhandle(space
, phandle
, true);
367 *(__be32
*)&rsp
[TPM_HEADER_SIZE
] = cpu_to_be32(vhandle
);
369 case TPM2_HT_HMAC_SESSION
:
370 case TPM2_HT_POLICY_SESSION
:
371 if (!tpm2_add_session(chip
, phandle
))
375 dev_err(&chip
->dev
, "%s: unknown handle 0x%08X\n",
382 tpm2_flush_context_cmd(chip
, phandle
,
383 TPM_TRANSMIT_UNLOCKED
| TPM_TRANSMIT_RAW
);
384 dev_warn(&chip
->dev
, "%s: out of slots for 0x%08X\n", __func__
,
389 struct tpm2_cap_handles
{
396 static int tpm2_map_response_body(struct tpm_chip
*chip
, u32 cc
, u8
*rsp
,
399 struct tpm_space
*space
= &chip
->work_space
;
400 struct tpm_output_header
*header
= (void *)rsp
;
401 struct tpm2_cap_handles
*data
;
408 if (cc
!= TPM2_CC_GET_CAPABILITY
||
409 be32_to_cpu(header
->return_code
) != TPM2_RC_SUCCESS
) {
413 if (len
< TPM_HEADER_SIZE
+ 9)
416 data
= (void *)&rsp
[TPM_HEADER_SIZE
];
417 if (be32_to_cpu(data
->capability
) != TPM2_CAP_HANDLES
)
420 if (len
!= TPM_HEADER_SIZE
+ 9 + 4 * be32_to_cpu(data
->count
))
423 for (i
= 0, j
= 0; i
< be32_to_cpu(data
->count
); i
++) {
424 phandle
= be32_to_cpup((__be32
*)&data
->handles
[i
]);
425 phandle_type
= phandle
& 0xFF000000;
427 switch (phandle_type
) {
428 case TPM2_HT_TRANSIENT
:
429 vhandle
= tpm2_map_to_vhandle(space
, phandle
, false);
433 data
->handles
[j
] = cpu_to_be32(vhandle
);
438 data
->handles
[j
] = cpu_to_be32(phandle
);
445 header
->length
= cpu_to_be32(TPM_HEADER_SIZE
+ 9 + 4 * j
);
446 data
->count
= cpu_to_be32(j
);
450 static int tpm2_save_space(struct tpm_chip
*chip
)
452 struct tpm_space
*space
= &chip
->work_space
;
457 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
458 if (!(space
->context_tbl
[i
] && ~space
->context_tbl
[i
]))
461 rc
= tpm2_save_context(chip
, space
->context_tbl
[i
],
462 space
->context_buf
, PAGE_SIZE
,
465 space
->context_tbl
[i
] = 0;
470 tpm2_flush_context_cmd(chip
, space
->context_tbl
[i
],
471 TPM_TRANSMIT_UNLOCKED
|
473 space
->context_tbl
[i
] = ~0;
476 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++) {
477 if (!space
->session_tbl
[i
])
480 rc
= tpm2_save_context(chip
, space
->session_tbl
[i
],
481 space
->session_buf
, PAGE_SIZE
,
485 /* handle error saving session, just forget it */
486 space
->session_tbl
[i
] = 0;
488 tpm2_flush_space(chip
);
496 int tpm2_commit_space(struct tpm_chip
*chip
, struct tpm_space
*space
,
497 u32 cc
, u8
*buf
, size_t *bufsiz
)
499 struct tpm_output_header
*header
= (void *)buf
;
505 rc
= tpm2_map_response_header(chip
, cc
, buf
, *bufsiz
);
507 tpm2_flush_space(chip
);
511 rc
= tpm2_map_response_body(chip
, cc
, buf
, *bufsiz
);
513 tpm2_flush_space(chip
);
517 rc
= tpm2_save_space(chip
);
519 tpm2_flush_space(chip
);
523 *bufsiz
= be32_to_cpu(header
->length
);
525 memcpy(&space
->context_tbl
, &chip
->work_space
.context_tbl
,
526 sizeof(space
->context_tbl
));
527 memcpy(&space
->session_tbl
, &chip
->work_space
.session_tbl
,
528 sizeof(space
->session_tbl
));
529 memcpy(space
->context_buf
, chip
->work_space
.context_buf
, PAGE_SIZE
);
530 memcpy(space
->session_buf
, chip
->work_space
.session_buf
, PAGE_SIZE
);