trusted_tee.c (7661B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2019-2021 Linaro Ltd. 4 * 5 * Author: 6 * Sumit Garg <sumit.garg@linaro.org> 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 */ 51struct 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 58static struct trusted_key_tee_private pvt_data; 59 60/* 61 * Have the TEE seal(encrypt) the symmetric key 62 */ 63static 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(¶m, 0, sizeof(param)); 72 73 reg_shm_in = tee_shm_register_kernel_buf(pvt_data.ctx, p->key, 74 p->key_len); 75 if (IS_ERR(reg_shm_in)) { 76 dev_err(pvt_data.dev, "key shm register failed\n"); 77 return PTR_ERR(reg_shm_in); 78 } 79 80 reg_shm_out = tee_shm_register_kernel_buf(pvt_data.ctx, p->blob, 81 sizeof(p->blob)); 82 if (IS_ERR(reg_shm_out)) { 83 dev_err(pvt_data.dev, "blob shm register failed\n"); 84 ret = PTR_ERR(reg_shm_out); 85 goto out; 86 } 87 88 inv_arg.func = TA_CMD_SEAL; 89 inv_arg.session = pvt_data.session_id; 90 inv_arg.num_params = 4; 91 92 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; 93 param[0].u.memref.shm = reg_shm_in; 94 param[0].u.memref.size = p->key_len; 95 param[0].u.memref.shm_offs = 0; 96 param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 97 param[1].u.memref.shm = reg_shm_out; 98 param[1].u.memref.size = sizeof(p->blob); 99 param[1].u.memref.shm_offs = 0; 100 101 ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param); 102 if ((ret < 0) || (inv_arg.ret != 0)) { 103 dev_err(pvt_data.dev, "TA_CMD_SEAL invoke err: %x\n", 104 inv_arg.ret); 105 ret = -EFAULT; 106 } else { 107 p->blob_len = param[1].u.memref.size; 108 } 109 110out: 111 if (reg_shm_out) 112 tee_shm_free(reg_shm_out); 113 if (reg_shm_in) 114 tee_shm_free(reg_shm_in); 115 116 return ret; 117} 118 119/* 120 * Have the TEE unseal(decrypt) the symmetric key 121 */ 122static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob) 123{ 124 int ret; 125 struct tee_ioctl_invoke_arg inv_arg; 126 struct tee_param param[4]; 127 struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL; 128 129 memset(&inv_arg, 0, sizeof(inv_arg)); 130 memset(¶m, 0, sizeof(param)); 131 132 reg_shm_in = tee_shm_register_kernel_buf(pvt_data.ctx, p->blob, 133 p->blob_len); 134 if (IS_ERR(reg_shm_in)) { 135 dev_err(pvt_data.dev, "blob shm register failed\n"); 136 return PTR_ERR(reg_shm_in); 137 } 138 139 reg_shm_out = tee_shm_register_kernel_buf(pvt_data.ctx, p->key, 140 sizeof(p->key)); 141 if (IS_ERR(reg_shm_out)) { 142 dev_err(pvt_data.dev, "key shm register failed\n"); 143 ret = PTR_ERR(reg_shm_out); 144 goto out; 145 } 146 147 inv_arg.func = TA_CMD_UNSEAL; 148 inv_arg.session = pvt_data.session_id; 149 inv_arg.num_params = 4; 150 151 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; 152 param[0].u.memref.shm = reg_shm_in; 153 param[0].u.memref.size = p->blob_len; 154 param[0].u.memref.shm_offs = 0; 155 param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 156 param[1].u.memref.shm = reg_shm_out; 157 param[1].u.memref.size = sizeof(p->key); 158 param[1].u.memref.shm_offs = 0; 159 160 ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param); 161 if ((ret < 0) || (inv_arg.ret != 0)) { 162 dev_err(pvt_data.dev, "TA_CMD_UNSEAL invoke err: %x\n", 163 inv_arg.ret); 164 ret = -EFAULT; 165 } else { 166 p->key_len = param[1].u.memref.size; 167 } 168 169out: 170 if (reg_shm_out) 171 tee_shm_free(reg_shm_out); 172 if (reg_shm_in) 173 tee_shm_free(reg_shm_in); 174 175 return ret; 176} 177 178/* 179 * Have the TEE generate random symmetric key 180 */ 181static int trusted_tee_get_random(unsigned char *key, size_t key_len) 182{ 183 int ret; 184 struct tee_ioctl_invoke_arg inv_arg; 185 struct tee_param param[4]; 186 struct tee_shm *reg_shm = NULL; 187 188 memset(&inv_arg, 0, sizeof(inv_arg)); 189 memset(¶m, 0, sizeof(param)); 190 191 reg_shm = tee_shm_register_kernel_buf(pvt_data.ctx, key, key_len); 192 if (IS_ERR(reg_shm)) { 193 dev_err(pvt_data.dev, "key shm register failed\n"); 194 return PTR_ERR(reg_shm); 195 } 196 197 inv_arg.func = TA_CMD_GET_RANDOM; 198 inv_arg.session = pvt_data.session_id; 199 inv_arg.num_params = 4; 200 201 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 202 param[0].u.memref.shm = reg_shm; 203 param[0].u.memref.size = key_len; 204 param[0].u.memref.shm_offs = 0; 205 206 ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param); 207 if ((ret < 0) || (inv_arg.ret != 0)) { 208 dev_err(pvt_data.dev, "TA_CMD_GET_RANDOM invoke err: %x\n", 209 inv_arg.ret); 210 ret = -EFAULT; 211 } else { 212 ret = param[0].u.memref.size; 213 } 214 215 tee_shm_free(reg_shm); 216 217 return ret; 218} 219 220static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) 221{ 222 if (ver->impl_id == TEE_IMPL_ID_OPTEE) 223 return 1; 224 else 225 return 0; 226} 227 228static int trusted_key_probe(struct device *dev) 229{ 230 struct tee_client_device *rng_device = to_tee_client_device(dev); 231 int ret; 232 struct tee_ioctl_open_session_arg sess_arg; 233 234 memset(&sess_arg, 0, sizeof(sess_arg)); 235 236 pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, 237 NULL); 238 if (IS_ERR(pvt_data.ctx)) 239 return -ENODEV; 240 241 memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN); 242 sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL; 243 sess_arg.num_params = 0; 244 245 ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL); 246 if ((ret < 0) || (sess_arg.ret != 0)) { 247 dev_err(dev, "tee_client_open_session failed, err: %x\n", 248 sess_arg.ret); 249 ret = -EINVAL; 250 goto out_ctx; 251 } 252 pvt_data.session_id = sess_arg.session; 253 254 ret = register_key_type(&key_type_trusted); 255 if (ret < 0) 256 goto out_sess; 257 258 pvt_data.dev = dev; 259 260 return 0; 261 262out_sess: 263 tee_client_close_session(pvt_data.ctx, pvt_data.session_id); 264out_ctx: 265 tee_client_close_context(pvt_data.ctx); 266 267 return ret; 268} 269 270static int trusted_key_remove(struct device *dev) 271{ 272 unregister_key_type(&key_type_trusted); 273 tee_client_close_session(pvt_data.ctx, pvt_data.session_id); 274 tee_client_close_context(pvt_data.ctx); 275 276 return 0; 277} 278 279static const struct tee_client_device_id trusted_key_id_table[] = { 280 {UUID_INIT(0xf04a0fe7, 0x1f5d, 0x4b9b, 281 0xab, 0xf7, 0x61, 0x9b, 0x85, 0xb4, 0xce, 0x8c)}, 282 {} 283}; 284MODULE_DEVICE_TABLE(tee, trusted_key_id_table); 285 286static struct tee_client_driver trusted_key_driver = { 287 .id_table = trusted_key_id_table, 288 .driver = { 289 .name = DRIVER_NAME, 290 .bus = &tee_bus_type, 291 .probe = trusted_key_probe, 292 .remove = trusted_key_remove, 293 }, 294}; 295 296static int trusted_tee_init(void) 297{ 298 return driver_register(&trusted_key_driver.driver); 299} 300 301static void trusted_tee_exit(void) 302{ 303 driver_unregister(&trusted_key_driver.driver); 304} 305 306struct trusted_key_ops trusted_key_tee_ops = { 307 .migratable = 0, /* non-migratable */ 308 .init = trusted_tee_init, 309 .seal = trusted_tee_seal, 310 .unseal = trusted_tee_unseal, 311 .get_random = trusted_tee_get_random, 312 .exit = trusted_tee_exit, 313};