Skip to content

Commit 3021b2b

Browse files
b49020jforissier
authored andcommitted
KEYS: trusted: Introduce TEE based Trusted Keys
Add support for TEE based trusted keys where TEE provides the functionality to seal and unseal trusted keys using hardware unique key. Refer to Documentation/staging/tee.rst for detailed information about TEE. Signed-off-by: Sumit Garg <[email protected]> Tested-by: Jarkko Sakkinen <[email protected]> Reviewed-by: Jarkko Sakkinen <[email protected]> Signed-off-by: Jarkko Sakkinen <[email protected]> [jf: cherry-pick 0a95ebc upstream] [jf: resolve conflict in security/keys/trusted-keys/Makefile] Signed-off-by: Jerome Forissier <[email protected]>
1 parent a8504cf commit 3021b2b

File tree

4 files changed

+340
-0
lines changed

4 files changed

+340
-0
lines changed

include/keys/trusted_tee.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2019-2021 Linaro Ltd.
4+
*
5+
* Author:
6+
* Sumit Garg <[email protected]>
7+
*/
8+
9+
#ifndef __TEE_TRUSTED_KEY_H
10+
#define __TEE_TRUSTED_KEY_H
11+
12+
#include <keys/trusted-type.h>
13+
14+
extern struct trusted_key_ops trusted_key_tee_ops;
15+
16+
#endif

security/keys/trusted-keys/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
77
trusted-y += trusted_core.o
88
trusted-y += trusted_tpm1.o
99
trusted-y += trusted_tpm2.o
10+
11+
trusted-$(CONFIG_TEE) += trusted_tee.o

security/keys/trusted-keys/trusted_core.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <keys/user-type.h>
1010
#include <keys/trusted-type.h>
11+
#include <keys/trusted_tee.h>
1112
#include <keys/trusted_tpm.h>
1213
#include <linux/capability.h>
1314
#include <linux/err.h>
@@ -29,6 +30,9 @@ static const struct trusted_key_source trusted_key_sources[] = {
2930
#if defined(CONFIG_TCG_TPM)
3031
{ "tpm", &trusted_key_tpm_ops },
3132
#endif
33+
#if defined(CONFIG_TEE)
34+
{ "tee", &trusted_key_tee_ops },
35+
#endif
3236
};
3337

3438
DEFINE_STATIC_CALL_NULL(trusted_key_init, *trusted_key_sources[0].ops->init);
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2019-2021 Linaro Ltd.
4+
*
5+
* Author:
6+
* Sumit Garg <[email protected]>
7+
*/
8+
9+
#include <linux/err.h>
10+
#include <linux/key-type.h>
11+
#include <linux/module.h>
12+
#include <linux/slab.h>
13+
#include <linux/string.h>
14+
#include <linux/tee_drv.h>
15+
#include <linux/uuid.h>
16+
17+
#include <keys/trusted_tee.h>
18+
19+
#define DRIVER_NAME "trusted-key-tee"
20+
21+
/*
22+
* Get random data for symmetric key
23+
*
24+
* [out] memref[0] Random data
25+
*/
26+
#define TA_CMD_GET_RANDOM 0x0
27+
28+
/*
29+
* Seal trusted key using hardware unique key
30+
*
31+
* [in] memref[0] Plain key
32+
* [out] memref[1] Sealed key datablob
33+
*/
34+
#define TA_CMD_SEAL 0x1
35+
36+
/*
37+
* Unseal trusted key using hardware unique key
38+
*
39+
* [in] memref[0] Sealed key datablob
40+
* [out] memref[1] Plain key
41+
*/
42+
#define TA_CMD_UNSEAL 0x2
43+
44+
/**
45+
* struct trusted_key_tee_private - TEE Trusted key private data
46+
* @dev: TEE based Trusted key device.
47+
* @ctx: TEE context handler.
48+
* @session_id: Trusted key TA session identifier.
49+
* @shm_pool: Memory pool shared with TEE device.
50+
*/
51+
struct trusted_key_tee_private {
52+
struct device *dev;
53+
struct tee_context *ctx;
54+
u32 session_id;
55+
struct tee_shm *shm_pool;
56+
};
57+
58+
static struct trusted_key_tee_private pvt_data;
59+
60+
/*
61+
* Have the TEE seal(encrypt) the symmetric key
62+
*/
63+
static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
64+
{
65+
int ret;
66+
struct tee_ioctl_invoke_arg inv_arg;
67+
struct tee_param param[4];
68+
struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL;
69+
70+
memset(&inv_arg, 0, sizeof(inv_arg));
71+
memset(&param, 0, sizeof(param));
72+
73+
reg_shm_in = tee_shm_register(pvt_data.ctx, (unsigned long)p->key,
74+
p->key_len, TEE_SHM_DMA_BUF |
75+
TEE_SHM_KERNEL_MAPPED);
76+
if (IS_ERR(reg_shm_in)) {
77+
dev_err(pvt_data.dev, "key shm register failed\n");
78+
return PTR_ERR(reg_shm_in);
79+
}
80+
81+
reg_shm_out = tee_shm_register(pvt_data.ctx, (unsigned long)p->blob,
82+
sizeof(p->blob), TEE_SHM_DMA_BUF |
83+
TEE_SHM_KERNEL_MAPPED);
84+
if (IS_ERR(reg_shm_out)) {
85+
dev_err(pvt_data.dev, "blob shm register failed\n");
86+
ret = PTR_ERR(reg_shm_out);
87+
goto out;
88+
}
89+
90+
inv_arg.func = TA_CMD_SEAL;
91+
inv_arg.session = pvt_data.session_id;
92+
inv_arg.num_params = 4;
93+
94+
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
95+
param[0].u.memref.shm = reg_shm_in;
96+
param[0].u.memref.size = p->key_len;
97+
param[0].u.memref.shm_offs = 0;
98+
param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
99+
param[1].u.memref.shm = reg_shm_out;
100+
param[1].u.memref.size = sizeof(p->blob);
101+
param[1].u.memref.shm_offs = 0;
102+
103+
ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param);
104+
if ((ret < 0) || (inv_arg.ret != 0)) {
105+
dev_err(pvt_data.dev, "TA_CMD_SEAL invoke err: %x\n",
106+
inv_arg.ret);
107+
ret = -EFAULT;
108+
} else {
109+
p->blob_len = param[1].u.memref.size;
110+
}
111+
112+
out:
113+
if (reg_shm_out)
114+
tee_shm_free(reg_shm_out);
115+
if (reg_shm_in)
116+
tee_shm_free(reg_shm_in);
117+
118+
return ret;
119+
}
120+
121+
/*
122+
* Have the TEE unseal(decrypt) the symmetric key
123+
*/
124+
static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
125+
{
126+
int ret;
127+
struct tee_ioctl_invoke_arg inv_arg;
128+
struct tee_param param[4];
129+
struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL;
130+
131+
memset(&inv_arg, 0, sizeof(inv_arg));
132+
memset(&param, 0, sizeof(param));
133+
134+
reg_shm_in = tee_shm_register(pvt_data.ctx, (unsigned long)p->blob,
135+
p->blob_len, TEE_SHM_DMA_BUF |
136+
TEE_SHM_KERNEL_MAPPED);
137+
if (IS_ERR(reg_shm_in)) {
138+
dev_err(pvt_data.dev, "blob shm register failed\n");
139+
return PTR_ERR(reg_shm_in);
140+
}
141+
142+
reg_shm_out = tee_shm_register(pvt_data.ctx, (unsigned long)p->key,
143+
sizeof(p->key), TEE_SHM_DMA_BUF |
144+
TEE_SHM_KERNEL_MAPPED);
145+
if (IS_ERR(reg_shm_out)) {
146+
dev_err(pvt_data.dev, "key shm register failed\n");
147+
ret = PTR_ERR(reg_shm_out);
148+
goto out;
149+
}
150+
151+
inv_arg.func = TA_CMD_UNSEAL;
152+
inv_arg.session = pvt_data.session_id;
153+
inv_arg.num_params = 4;
154+
155+
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
156+
param[0].u.memref.shm = reg_shm_in;
157+
param[0].u.memref.size = p->blob_len;
158+
param[0].u.memref.shm_offs = 0;
159+
param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
160+
param[1].u.memref.shm = reg_shm_out;
161+
param[1].u.memref.size = sizeof(p->key);
162+
param[1].u.memref.shm_offs = 0;
163+
164+
ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param);
165+
if ((ret < 0) || (inv_arg.ret != 0)) {
166+
dev_err(pvt_data.dev, "TA_CMD_UNSEAL invoke err: %x\n",
167+
inv_arg.ret);
168+
ret = -EFAULT;
169+
} else {
170+
p->key_len = param[1].u.memref.size;
171+
}
172+
173+
out:
174+
if (reg_shm_out)
175+
tee_shm_free(reg_shm_out);
176+
if (reg_shm_in)
177+
tee_shm_free(reg_shm_in);
178+
179+
return ret;
180+
}
181+
182+
/*
183+
* Have the TEE generate random symmetric key
184+
*/
185+
static int trusted_tee_get_random(unsigned char *key, size_t key_len)
186+
{
187+
int ret;
188+
struct tee_ioctl_invoke_arg inv_arg;
189+
struct tee_param param[4];
190+
struct tee_shm *reg_shm = NULL;
191+
192+
memset(&inv_arg, 0, sizeof(inv_arg));
193+
memset(&param, 0, sizeof(param));
194+
195+
reg_shm = tee_shm_register(pvt_data.ctx, (unsigned long)key, key_len,
196+
TEE_SHM_DMA_BUF | TEE_SHM_KERNEL_MAPPED);
197+
if (IS_ERR(reg_shm)) {
198+
dev_err(pvt_data.dev, "key shm register failed\n");
199+
return PTR_ERR(reg_shm);
200+
}
201+
202+
inv_arg.func = TA_CMD_GET_RANDOM;
203+
inv_arg.session = pvt_data.session_id;
204+
inv_arg.num_params = 4;
205+
206+
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
207+
param[0].u.memref.shm = reg_shm;
208+
param[0].u.memref.size = key_len;
209+
param[0].u.memref.shm_offs = 0;
210+
211+
ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param);
212+
if ((ret < 0) || (inv_arg.ret != 0)) {
213+
dev_err(pvt_data.dev, "TA_CMD_GET_RANDOM invoke err: %x\n",
214+
inv_arg.ret);
215+
ret = -EFAULT;
216+
} else {
217+
ret = param[0].u.memref.size;
218+
}
219+
220+
tee_shm_free(reg_shm);
221+
222+
return ret;
223+
}
224+
225+
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
226+
{
227+
if (ver->impl_id == TEE_IMPL_ID_OPTEE)
228+
return 1;
229+
else
230+
return 0;
231+
}
232+
233+
static int trusted_key_probe(struct device *dev)
234+
{
235+
struct tee_client_device *rng_device = to_tee_client_device(dev);
236+
int ret;
237+
struct tee_ioctl_open_session_arg sess_arg;
238+
239+
memset(&sess_arg, 0, sizeof(sess_arg));
240+
241+
pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
242+
NULL);
243+
if (IS_ERR(pvt_data.ctx))
244+
return -ENODEV;
245+
246+
memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
247+
sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
248+
sess_arg.num_params = 0;
249+
250+
ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
251+
if ((ret < 0) || (sess_arg.ret != 0)) {
252+
dev_err(dev, "tee_client_open_session failed, err: %x\n",
253+
sess_arg.ret);
254+
ret = -EINVAL;
255+
goto out_ctx;
256+
}
257+
pvt_data.session_id = sess_arg.session;
258+
259+
ret = register_key_type(&key_type_trusted);
260+
if (ret < 0)
261+
goto out_sess;
262+
263+
pvt_data.dev = dev;
264+
265+
return 0;
266+
267+
out_sess:
268+
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
269+
out_ctx:
270+
tee_client_close_context(pvt_data.ctx);
271+
272+
return ret;
273+
}
274+
275+
static int trusted_key_remove(struct device *dev)
276+
{
277+
unregister_key_type(&key_type_trusted);
278+
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
279+
tee_client_close_context(pvt_data.ctx);
280+
281+
return 0;
282+
}
283+
284+
static const struct tee_client_device_id trusted_key_id_table[] = {
285+
{UUID_INIT(0xf04a0fe7, 0x1f5d, 0x4b9b,
286+
0xab, 0xf7, 0x61, 0x9b, 0x85, 0xb4, 0xce, 0x8c)},
287+
{}
288+
};
289+
MODULE_DEVICE_TABLE(tee, trusted_key_id_table);
290+
291+
static struct tee_client_driver trusted_key_driver = {
292+
.id_table = trusted_key_id_table,
293+
.driver = {
294+
.name = DRIVER_NAME,
295+
.bus = &tee_bus_type,
296+
.probe = trusted_key_probe,
297+
.remove = trusted_key_remove,
298+
},
299+
};
300+
301+
static int trusted_tee_init(void)
302+
{
303+
return driver_register(&trusted_key_driver.driver);
304+
}
305+
306+
static void trusted_tee_exit(void)
307+
{
308+
driver_unregister(&trusted_key_driver.driver);
309+
}
310+
311+
struct trusted_key_ops trusted_key_tee_ops = {
312+
.migratable = 0, /* non-migratable */
313+
.init = trusted_tee_init,
314+
.seal = trusted_tee_seal,
315+
.unseal = trusted_tee_unseal,
316+
.get_random = trusted_tee_get_random,
317+
.exit = trusted_tee_exit,
318+
};

0 commit comments

Comments
 (0)