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
);
46 int tpm2_init_space(struct tpm_space
*space
)
48 space
->context_buf
= kzalloc(PAGE_SIZE
, GFP_KERNEL
);
49 if (!space
->context_buf
)
52 space
->session_buf
= kzalloc(PAGE_SIZE
, GFP_KERNEL
);
53 if (space
->session_buf
== NULL
) {
54 kfree(space
->context_buf
);
61 void tpm2_del_space(struct tpm_chip
*chip
, struct tpm_space
*space
)
63 mutex_lock(&chip
->tpm_mutex
);
64 tpm2_flush_sessions(chip
, space
);
65 mutex_unlock(&chip
->tpm_mutex
);
66 kfree(space
->context_buf
);
67 kfree(space
->session_buf
);
70 static int tpm2_load_context(struct tpm_chip
*chip
, u8
*buf
,
71 unsigned int *offset
, u32
*handle
)
74 struct tpm2_context
*ctx
;
75 unsigned int body_size
;
78 rc
= tpm_buf_init(&tbuf
, TPM2_ST_NO_SESSIONS
, TPM2_CC_CONTEXT_LOAD
);
82 ctx
= (struct tpm2_context
*)&buf
[*offset
];
83 body_size
= sizeof(*ctx
) + be16_to_cpu(ctx
->blob_size
);
84 tpm_buf_append(&tbuf
, &buf
[*offset
], body_size
);
86 rc
= tpm_transmit_cmd(chip
, NULL
, tbuf
.data
, PAGE_SIZE
, 4,
87 TPM_TRANSMIT_UNLOCKED
, NULL
);
89 dev_warn(&chip
->dev
, "%s: failed with a system error %d\n",
91 tpm_buf_destroy(&tbuf
);
93 } else if (tpm2_rc_value(rc
) == TPM2_RC_HANDLE
||
94 rc
== TPM2_RC_REFERENCE_H0
) {
96 * TPM_RC_HANDLE means that the session context can't
97 * be loaded because of an internal counter mismatch
98 * that makes the TPM think there might have been a
99 * replay. This might happen if the context was saved
100 * and loaded outside the space.
102 * TPM_RC_REFERENCE_H0 means the session has been
103 * flushed outside the space
106 tpm_buf_destroy(&tbuf
);
108 dev_warn(&chip
->dev
, "%s: failed with a TPM error 0x%04X\n",
110 tpm_buf_destroy(&tbuf
);
114 *handle
= be32_to_cpup((__be32
*)&tbuf
.data
[TPM_HEADER_SIZE
]);
115 *offset
+= body_size
;
117 tpm_buf_destroy(&tbuf
);
121 static int tpm2_save_context(struct tpm_chip
*chip
, u32 handle
, u8
*buf
,
122 unsigned int buf_size
, unsigned int *offset
)
125 unsigned int body_size
;
128 rc
= tpm_buf_init(&tbuf
, TPM2_ST_NO_SESSIONS
, TPM2_CC_CONTEXT_SAVE
);
132 tpm_buf_append_u32(&tbuf
, handle
);
134 rc
= tpm_transmit_cmd(chip
, NULL
, tbuf
.data
, PAGE_SIZE
, 0,
135 TPM_TRANSMIT_UNLOCKED
, NULL
);
137 dev_warn(&chip
->dev
, "%s: failed with a system error %d\n",
139 tpm_buf_destroy(&tbuf
);
141 } else if (tpm2_rc_value(rc
) == TPM2_RC_REFERENCE_H0
) {
142 tpm_buf_destroy(&tbuf
);
145 dev_warn(&chip
->dev
, "%s: failed with a TPM error 0x%04X\n",
147 tpm_buf_destroy(&tbuf
);
151 body_size
= tpm_buf_length(&tbuf
) - TPM_HEADER_SIZE
;
152 if ((*offset
+ body_size
) > buf_size
) {
153 dev_warn(&chip
->dev
, "%s: out of backing storage\n", __func__
);
154 tpm_buf_destroy(&tbuf
);
158 memcpy(&buf
[*offset
], &tbuf
.data
[TPM_HEADER_SIZE
], body_size
);
159 *offset
+= body_size
;
160 tpm_buf_destroy(&tbuf
);
164 static void tpm2_flush_space(struct tpm_chip
*chip
)
166 struct tpm_space
*space
= &chip
->work_space
;
169 for (i
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++)
170 if (space
->context_tbl
[i
] && ~space
->context_tbl
[i
])
171 tpm2_flush_context_cmd(chip
, space
->context_tbl
[i
],
172 TPM_TRANSMIT_UNLOCKED
);
174 tpm2_flush_sessions(chip
, space
);
177 static int tpm2_load_space(struct tpm_chip
*chip
)
179 struct tpm_space
*space
= &chip
->work_space
;
184 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
185 if (!space
->context_tbl
[i
])
188 /* sanity check, should never happen */
189 if (~space
->context_tbl
[i
]) {
190 dev_err(&chip
->dev
, "context table is inconsistent");
194 rc
= tpm2_load_context(chip
, space
->context_buf
, &offset
,
195 &space
->context_tbl
[i
]);
200 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++) {
203 if (!space
->session_tbl
[i
])
206 rc
= tpm2_load_context(chip
, space
->session_buf
,
209 /* load failed, just forget session */
210 space
->session_tbl
[i
] = 0;
212 tpm2_flush_space(chip
);
215 if (handle
!= space
->session_tbl
[i
]) {
216 dev_warn(&chip
->dev
, "session restored to wrong handle\n");
217 tpm2_flush_space(chip
);
225 static bool tpm2_map_to_phandle(struct tpm_space
*space
, void *handle
)
227 u32 vhandle
= be32_to_cpup((__be32
*)handle
);
231 i
= 0xFFFFFF - (vhandle
& 0xFFFFFF);
232 if (i
>= ARRAY_SIZE(space
->context_tbl
) || !space
->context_tbl
[i
])
235 phandle
= space
->context_tbl
[i
];
236 *((__be32
*)handle
) = cpu_to_be32(phandle
);
240 static int tpm2_map_command(struct tpm_chip
*chip
, u32 cc
, u8
*cmd
)
242 struct tpm_space
*space
= &chip
->work_space
;
243 unsigned int nr_handles
;
248 i
= tpm2_find_cc(chip
, cc
);
252 attrs
= chip
->cc_attrs_tbl
[i
];
253 nr_handles
= (attrs
>> TPM2_CC_ATTR_CHANDLES
) & GENMASK(2, 0);
255 handle
= (u32
*)&cmd
[TPM_HEADER_SIZE
];
256 for (i
= 0; i
< nr_handles
; i
++, handle
++) {
257 if ((be32_to_cpu(*handle
) & 0xFF000000) == TPM2_HT_TRANSIENT
) {
258 if (!tpm2_map_to_phandle(space
, handle
))
266 int tpm2_prepare_space(struct tpm_chip
*chip
, struct tpm_space
*space
, u32 cc
,
274 memcpy(&chip
->work_space
.context_tbl
, &space
->context_tbl
,
275 sizeof(space
->context_tbl
));
276 memcpy(&chip
->work_space
.session_tbl
, &space
->session_tbl
,
277 sizeof(space
->session_tbl
));
278 memcpy(chip
->work_space
.context_buf
, space
->context_buf
, PAGE_SIZE
);
279 memcpy(chip
->work_space
.session_buf
, space
->session_buf
, PAGE_SIZE
);
281 rc
= tpm2_load_space(chip
);
283 tpm2_flush_space(chip
);
287 rc
= tpm2_map_command(chip
, cc
, cmd
);
289 tpm2_flush_space(chip
);
296 static bool tpm2_add_session(struct tpm_chip
*chip
, u32 handle
)
298 struct tpm_space
*space
= &chip
->work_space
;
301 for (i
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++)
302 if (space
->session_tbl
[i
] == 0)
305 if (i
== ARRAY_SIZE(space
->session_tbl
))
308 space
->session_tbl
[i
] = handle
;
312 static u32
tpm2_map_to_vhandle(struct tpm_space
*space
, u32 phandle
, bool alloc
)
316 for (i
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
318 if (!space
->context_tbl
[i
]) {
319 space
->context_tbl
[i
] = phandle
;
322 } else if (space
->context_tbl
[i
] == phandle
)
326 if (i
== ARRAY_SIZE(space
->context_tbl
))
329 return TPM2_HT_TRANSIENT
| (0xFFFFFF - i
);
332 static int tpm2_map_response_header(struct tpm_chip
*chip
, u32 cc
, u8
*rsp
,
335 struct tpm_space
*space
= &chip
->work_space
;
336 struct tpm_output_header
*header
= (void *)rsp
;
343 if (be32_to_cpu(header
->return_code
) != TPM2_RC_SUCCESS
)
346 i
= tpm2_find_cc(chip
, cc
);
347 /* sanity check, should never happen */
351 attrs
= chip
->cc_attrs_tbl
[i
];
352 if (!((attrs
>> TPM2_CC_ATTR_RHANDLE
) & 1))
355 phandle
= be32_to_cpup((__be32
*)&rsp
[TPM_HEADER_SIZE
]);
356 phandle_type
= phandle
& 0xFF000000;
358 switch (phandle_type
) {
359 case TPM2_HT_TRANSIENT
:
360 vhandle
= tpm2_map_to_vhandle(space
, phandle
, true);
364 *(__be32
*)&rsp
[TPM_HEADER_SIZE
] = cpu_to_be32(vhandle
);
366 case TPM2_HT_HMAC_SESSION
:
367 case TPM2_HT_POLICY_SESSION
:
368 if (!tpm2_add_session(chip
, phandle
))
372 dev_err(&chip
->dev
, "%s: unknown handle 0x%08X\n",
379 tpm2_flush_context_cmd(chip
, phandle
, TPM_TRANSMIT_UNLOCKED
);
380 dev_warn(&chip
->dev
, "%s: out of slots for 0x%08X\n", __func__
,
385 struct tpm2_cap_handles
{
392 static int tpm2_map_response_body(struct tpm_chip
*chip
, u32 cc
, u8
*rsp
,
395 struct tpm_space
*space
= &chip
->work_space
;
396 struct tpm_output_header
*header
= (void *)rsp
;
397 struct tpm2_cap_handles
*data
;
404 if (cc
!= TPM2_CC_GET_CAPABILITY
||
405 be32_to_cpu(header
->return_code
) != TPM2_RC_SUCCESS
) {
409 if (len
< TPM_HEADER_SIZE
+ 9)
412 data
= (void *)&rsp
[TPM_HEADER_SIZE
];
413 if (be32_to_cpu(data
->capability
) != TPM2_CAP_HANDLES
)
416 if (len
!= TPM_HEADER_SIZE
+ 9 + 4 * be32_to_cpu(data
->count
))
419 for (i
= 0, j
= 0; i
< be32_to_cpu(data
->count
); i
++) {
420 phandle
= be32_to_cpup((__be32
*)&data
->handles
[i
]);
421 phandle_type
= phandle
& 0xFF000000;
423 switch (phandle_type
) {
424 case TPM2_HT_TRANSIENT
:
425 vhandle
= tpm2_map_to_vhandle(space
, phandle
, false);
429 data
->handles
[j
] = cpu_to_be32(vhandle
);
434 data
->handles
[j
] = cpu_to_be32(phandle
);
441 header
->length
= cpu_to_be32(TPM_HEADER_SIZE
+ 9 + 4 * j
);
442 data
->count
= cpu_to_be32(j
);
446 static int tpm2_save_space(struct tpm_chip
*chip
)
448 struct tpm_space
*space
= &chip
->work_space
;
453 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
454 if (!(space
->context_tbl
[i
] && ~space
->context_tbl
[i
]))
457 rc
= tpm2_save_context(chip
, space
->context_tbl
[i
],
458 space
->context_buf
, PAGE_SIZE
,
461 space
->context_tbl
[i
] = 0;
466 tpm2_flush_context_cmd(chip
, space
->context_tbl
[i
],
467 TPM_TRANSMIT_UNLOCKED
);
468 space
->context_tbl
[i
] = ~0;
471 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++) {
472 if (!space
->session_tbl
[i
])
475 rc
= tpm2_save_context(chip
, space
->session_tbl
[i
],
476 space
->session_buf
, PAGE_SIZE
,
480 /* handle error saving session, just forget it */
481 space
->session_tbl
[i
] = 0;
483 tpm2_flush_space(chip
);
491 int tpm2_commit_space(struct tpm_chip
*chip
, struct tpm_space
*space
,
492 u32 cc
, u8
*buf
, size_t *bufsiz
)
494 struct tpm_output_header
*header
= (void *)buf
;
500 rc
= tpm2_map_response_header(chip
, cc
, buf
, *bufsiz
);
502 tpm2_flush_space(chip
);
506 rc
= tpm2_map_response_body(chip
, cc
, buf
, *bufsiz
);
508 tpm2_flush_space(chip
);
512 rc
= tpm2_save_space(chip
);
514 tpm2_flush_space(chip
);
518 *bufsiz
= be32_to_cpu(header
->length
);
520 memcpy(&space
->context_tbl
, &chip
->work_space
.context_tbl
,
521 sizeof(space
->context_tbl
));
522 memcpy(&space
->session_tbl
, &chip
->work_space
.session_tbl
,
523 sizeof(space
->session_tbl
));
524 memcpy(space
->context_buf
, chip
->work_space
.context_buf
, PAGE_SIZE
);
525 memcpy(space
->session_buf
, chip
->work_space
.session_buf
, PAGE_SIZE
);