b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | #include <linux/module.h> |
| 2 | #include <linux/slab.h> |
| 3 | #include <linux/err.h> |
| 4 | #include <linux/clk-provider.h> |
| 5 | #include <linux/clk.h> |
| 6 | #include <linux/io.h> |
| 7 | #include <linux/hw_random.h> |
| 8 | #include <linux/platform_device.h> |
| 9 | #include <linux/of_device.h> |
| 10 | #include <linux/mutex.h> |
| 11 | #include <linux/device.h> |
| 12 | #include <linux/init.h> |
| 13 | #include <linux/delay.h> |
| 14 | #include <asm/uaccess.h> |
| 15 | #include <uapi/linux/hwrsa_ioctl.h> |
| 16 | #ifdef CONFIG_TEE |
| 17 | #include <linux/tee_drv.h> |
| 18 | #endif |
| 19 | |
| 20 | #include "asr-te200-optee.h" |
| 21 | #include "asr-rsa-optee.h" |
| 22 | |
| 23 | static struct teec_uuid pta_rsa_uuid = ASR_RSA_ACCESS_UUID; |
| 24 | |
| 25 | static int asr_optee_rsa_sign(struct hwrsa_arg *rsa_arg, u_int cmd) |
| 26 | { |
| 27 | struct tee_ioctl_invoke_arg invoke_arg; |
| 28 | struct tee_param params[4]; |
| 29 | struct asrte200_tee_context asrte200_tee_ctx; |
| 30 | struct tee_shm *shm; |
| 31 | int ret = 0; |
| 32 | char *ma = NULL; |
| 33 | struct rsa_ioctl_key *key = rsa_arg->rsa_key; |
| 34 | uint8_t *n = key->n, *e = key->e, *d = key->d, *p = key->p, *q= key->q; |
| 35 | size_t n_size = key->n_size, e_size = key->e_size, d_size = key->d_size; |
| 36 | size_t p_size = key->p_size, q_size = key->q_size; |
| 37 | uint8_t *msg = rsa_arg->msg, *sign = rsa_arg->sign; |
| 38 | size_t msg_size = rsa_arg->msg_size, sign_size = key->n_size; |
| 39 | int is_blinding; |
| 40 | u_int optee_cmd; |
| 41 | |
| 42 | switch (cmd) { |
| 43 | case HWRSA_SIGN_PKCS_V15_SHA1: |
| 44 | optee_cmd = CMD_RSA_SIGN_PKCS_V15_SHA1; |
| 45 | break; |
| 46 | case HWRSA_SIGN_PKCS_V15_SHA256: |
| 47 | optee_cmd = CMD_RSA_SIGN_PKCS_V15_SHA256; |
| 48 | break; |
| 49 | case HWRSA_SIGN_PKCS_V21_SHA1: |
| 50 | optee_cmd = CMD_RSA_SIGN_PKCS_V21_SHA1; |
| 51 | break; |
| 52 | case HWRSA_SIGN_PKCS_V21_SHA256: |
| 53 | optee_cmd = CMD_RSA_SIGN_PKCS_V21_SHA256; |
| 54 | break; |
| 55 | default: |
| 56 | ret = -EINVAL; |
| 57 | goto exit; |
| 58 | } |
| 59 | |
| 60 | if (!p || !q || !p_size || !q_size) { |
| 61 | is_blinding = 0; |
| 62 | } else { |
| 63 | is_blinding = 1; |
| 64 | } |
| 65 | |
| 66 | ret = asrte200_optee_open_ta(&asrte200_tee_ctx, &pta_rsa_uuid); |
| 67 | if (ret != 0) { |
| 68 | return ret; |
| 69 | } |
| 70 | |
| 71 | memset(&invoke_arg, 0x0, sizeof(struct tee_ioctl_invoke_arg)); |
| 72 | invoke_arg.func = optee_cmd; |
| 73 | invoke_arg.session = asrte200_tee_ctx.session; |
| 74 | |
| 75 | if (is_blinding) { |
| 76 | shm = tee_shm_alloc(asrte200_tee_ctx.tee_ctx, |
| 77 | n_size + e_size + d_size + p_size + q_size + msg_size + sign_size, |
| 78 | TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); |
| 79 | } else { |
| 80 | shm = tee_shm_alloc(asrte200_tee_ctx.tee_ctx, |
| 81 | n_size + e_size + d_size + msg_size + sign_size, |
| 82 | TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); |
| 83 | } |
| 84 | if (!shm) { |
| 85 | ret = -EINVAL; |
| 86 | goto exit; |
| 87 | } |
| 88 | |
| 89 | ma = tee_shm_get_va(shm, 0); |
| 90 | memcpy(ma, n, n_size); |
| 91 | memcpy(ma + n_size, e, e_size); |
| 92 | memcpy(ma + n_size + e_size, d, d_size); |
| 93 | if (is_blinding) { |
| 94 | memcpy(ma + n_size + e_size + d_size, p, p_size); |
| 95 | memcpy(ma + n_size + e_size + d_size + q_size, q, q_size); |
| 96 | } |
| 97 | |
| 98 | /* import rsa key */ |
| 99 | params[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; |
| 100 | params[0].u.memref.shm_offs = 0; |
| 101 | if (is_blinding) { |
| 102 | params[0].u.memref.size = n_size + e_size + d_size + p_size + q_size; |
| 103 | } else { |
| 104 | params[0].u.memref.size = n_size + e_size + d_size; |
| 105 | } |
| 106 | params[0].u.memref.shm = shm; |
| 107 | |
| 108 | params[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; |
| 109 | params[1].u.value.a = 0; |
| 110 | params[1].u.value.a |= n_size; |
| 111 | params[1].u.value.a |= e_size << 10; |
| 112 | params[1].u.value.a |= d_size << 20; |
| 113 | params[1].u.value.a |= is_blinding << 30; |
| 114 | if (is_blinding) { |
| 115 | params[1].u.value.b = 0; |
| 116 | params[1].u.value.b |= p_size; |
| 117 | params[1].u.value.b |= q_size << 10; |
| 118 | } |
| 119 | |
| 120 | /* import message */ |
| 121 | params[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; |
| 122 | if (is_blinding) { |
| 123 | memcpy(ma + n_size + e_size + d_size + p_size + q_size, msg, msg_size); |
| 124 | params[2].u.memref.shm_offs = n_size + e_size + d_size + p_size + q_size; |
| 125 | } else { |
| 126 | memcpy(ma + n_size + e_size + d_size, msg, msg_size); |
| 127 | params[2].u.memref.shm_offs = n_size + e_size + d_size; |
| 128 | } |
| 129 | params[2].u.memref.size = msg_size; |
| 130 | params[2].u.memref.shm = shm; |
| 131 | |
| 132 | /* import signature */ |
| 133 | params[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; |
| 134 | if (is_blinding) { |
| 135 | params[3].u.memref.shm_offs = n_size + e_size + d_size + p_size + q_size + msg_size; |
| 136 | } else { |
| 137 | params[3].u.memref.shm_offs = n_size + e_size + d_size + msg_size; |
| 138 | } |
| 139 | params[3].u.memref.size = sign_size; |
| 140 | params[3].u.memref.shm = shm; |
| 141 | |
| 142 | invoke_arg.num_params = 4; |
| 143 | |
| 144 | ret = tee_client_invoke_func(asrte200_tee_ctx.tee_ctx, &invoke_arg, params); |
| 145 | if (ret != 0) { |
| 146 | rsa_arg->result = 0; |
| 147 | } else if (invoke_arg.ret != 0) { |
| 148 | rsa_arg->result = 0; |
| 149 | goto free_shm; |
| 150 | } |
| 151 | |
| 152 | rsa_arg->result = 1; |
| 153 | |
| 154 | if (is_blinding) { |
| 155 | memcpy(sign, ma + n_size + e_size + d_size + p_size + q_size + msg_size, sign_size); |
| 156 | } else { |
| 157 | memcpy(sign, ma + n_size + e_size + d_size + msg_size, sign_size); |
| 158 | } |
| 159 | |
| 160 | free_shm: |
| 161 | tee_shm_free(shm); |
| 162 | exit: |
| 163 | asrte200_optee_close_ta(&asrte200_tee_ctx); |
| 164 | return ret; |
| 165 | } |
| 166 | |
| 167 | static int asr_optee_rsa_verify(struct hwrsa_arg *rsa_arg, u_int cmd) |
| 168 | { |
| 169 | struct tee_ioctl_invoke_arg invoke_arg; |
| 170 | struct tee_param params[4]; |
| 171 | struct asrte200_tee_context asrte200_tee_ctx; |
| 172 | struct tee_shm *shm; |
| 173 | int ret = 0; |
| 174 | char *ma = NULL; |
| 175 | struct rsa_ioctl_key *key = rsa_arg->rsa_key; |
| 176 | uint8_t *n = key->n, *e = key->e; |
| 177 | size_t n_size = key->n_size, e_size = key->e_size; |
| 178 | uint8_t *msg = rsa_arg->msg, *sign = rsa_arg->sign; |
| 179 | size_t msg_size = rsa_arg->msg_size, sign_size = rsa_arg->sign_size; |
| 180 | u_int optee_cmd; |
| 181 | |
| 182 | switch (cmd) { |
| 183 | case HWRSA_VERIFY_PKCS_V15_SHA1: |
| 184 | optee_cmd = CMD_RSA_VERIFY_PKCS_V15_SHA1; |
| 185 | break; |
| 186 | case HWRSA_VERIFY_PKCS_V15_SHA256: |
| 187 | optee_cmd = CMD_RSA_VERIFY_PKCS_V15_SHA256; |
| 188 | break; |
| 189 | case HWRSA_VERIFY_PKCS_V21_SHA1: |
| 190 | optee_cmd = CMD_RSA_VERIFY_PKCS_V21_SHA1; |
| 191 | break; |
| 192 | case HWRSA_VERIFY_PKCS_V21_SHA256: |
| 193 | optee_cmd = CMD_RSA_VERIFY_PKCS_V21_SHA256; |
| 194 | break; |
| 195 | default: |
| 196 | ret = -EINVAL; |
| 197 | goto exit; |
| 198 | } |
| 199 | |
| 200 | ret = asrte200_optee_open_ta(&asrte200_tee_ctx, &pta_rsa_uuid); |
| 201 | if (ret != 0) { |
| 202 | return ret; |
| 203 | } |
| 204 | |
| 205 | memset(&invoke_arg, 0x0, sizeof(struct tee_ioctl_invoke_arg)); |
| 206 | invoke_arg.func = optee_cmd; |
| 207 | invoke_arg.session = asrte200_tee_ctx.session; |
| 208 | |
| 209 | shm = tee_shm_alloc(asrte200_tee_ctx.tee_ctx, |
| 210 | n_size + e_size + msg_size + sign_size, |
| 211 | TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); |
| 212 | |
| 213 | if (!shm) { |
| 214 | ret = -EINVAL; |
| 215 | goto exit; |
| 216 | } |
| 217 | |
| 218 | ma = tee_shm_get_va(shm, 0); |
| 219 | memcpy(ma, n, n_size); |
| 220 | memcpy(ma + n_size, e, e_size); |
| 221 | |
| 222 | /* import rsa key */ |
| 223 | params[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; |
| 224 | params[0].u.memref.shm_offs = 0; |
| 225 | params[0].u.memref.size = n_size + e_size; |
| 226 | params[0].u.memref.shm = shm; |
| 227 | |
| 228 | /* import msg */ |
| 229 | memcpy(ma + n_size + e_size, msg, msg_size); |
| 230 | params[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; |
| 231 | params[1].u.memref.shm_offs = n_size + e_size; |
| 232 | params[1].u.memref.size = msg_size; |
| 233 | params[1].u.memref.shm = shm; |
| 234 | |
| 235 | /* import sign */ |
| 236 | memcpy(ma + n_size + e_size + msg_size, sign, sign_size); |
| 237 | params[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; |
| 238 | params[2].u.memref.shm_offs = n_size + e_size + msg_size; |
| 239 | params[2].u.memref.size = sign_size; |
| 240 | params[2].u.memref.shm = shm; |
| 241 | |
| 242 | params[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; |
| 243 | params[3].u.value.a = n_size; |
| 244 | |
| 245 | invoke_arg.num_params = 4; |
| 246 | |
| 247 | ret = tee_client_invoke_func(asrte200_tee_ctx.tee_ctx, &invoke_arg, params); |
| 248 | if (ret != 0) { |
| 249 | rsa_arg->result = 0; |
| 250 | goto free_shm; |
| 251 | } else if (invoke_arg.ret != 0) { |
| 252 | rsa_arg->result = 0; |
| 253 | goto free_shm; |
| 254 | } |
| 255 | |
| 256 | rsa_arg->result = 1; |
| 257 | |
| 258 | free_shm: |
| 259 | tee_shm_free(shm); |
| 260 | exit: |
| 261 | asrte200_optee_close_ta(&asrte200_tee_ctx); |
| 262 | return ret; |
| 263 | } |
| 264 | |
| 265 | static int asr_rsa_open(struct inode *inode, struct file *file) |
| 266 | { |
| 267 | return 0; |
| 268 | } |
| 269 | |
| 270 | static int asr_rsa_close(struct inode *inode, struct file *file) |
| 271 | { |
| 272 | return 0; |
| 273 | } |
| 274 | |
| 275 | static long asr_rsa_ioctl(struct file *file, u_int cmd, u_long arg) |
| 276 | { |
| 277 | int ret = 0; |
| 278 | struct miscdevice *miscdev; |
| 279 | struct asr_te200_rsa *rsa; |
| 280 | struct hwrsa_arg rsa_arg; |
| 281 | struct rsa_ioctl_key *key; |
| 282 | struct hwrsa_arg *u_arg = (void __user *)arg; |
| 283 | |
| 284 | miscdev = file->private_data; |
| 285 | rsa = container_of(miscdev, struct asr_te200_rsa, rsa_misc); |
| 286 | |
| 287 | if (copy_from_user(&rsa_arg, (void __user *)arg, sizeof(rsa_arg))) { |
| 288 | return -EFAULT; |
| 289 | } |
| 290 | |
| 291 | key = rsa_arg.rsa_key; |
| 292 | |
| 293 | if (!rsa_arg.rsa_key) { |
| 294 | return -EFAULT; |
| 295 | } |
| 296 | |
| 297 | if (!rsa_arg.msg || !rsa_arg.msg_size) { |
| 298 | return -EFAULT; |
| 299 | } |
| 300 | |
| 301 | switch (cmd) { |
| 302 | case HWRSA_SIGN_PKCS_V15_SHA1: |
| 303 | case HWRSA_SIGN_PKCS_V15_SHA256: |
| 304 | case HWRSA_SIGN_PKCS_V21_SHA1: |
| 305 | case HWRSA_SIGN_PKCS_V21_SHA256: |
| 306 | if (!rsa_arg.sign || !key->is_private) { |
| 307 | ret = -EINVAL; |
| 308 | goto exit; |
| 309 | } |
| 310 | ret = asr_optee_rsa_sign(&rsa_arg, cmd); |
| 311 | put_user(rsa_arg.result, &u_arg->result); |
| 312 | break; |
| 313 | case HWRSA_VERIFY_PKCS_V15_SHA1: |
| 314 | case HWRSA_VERIFY_PKCS_V15_SHA256: |
| 315 | case HWRSA_VERIFY_PKCS_V21_SHA1: |
| 316 | case HWRSA_VERIFY_PKCS_V21_SHA256: |
| 317 | if (!rsa_arg.sign || !rsa_arg.sign_size || key->is_private) { |
| 318 | ret = -EINVAL; |
| 319 | goto exit; |
| 320 | } |
| 321 | ret = asr_optee_rsa_verify(&rsa_arg, cmd); |
| 322 | put_user(rsa_arg.result, &u_arg->result); |
| 323 | break; |
| 324 | default: |
| 325 | dev_err(rsa->dev, "asr te200: rsa iotcl invald command %x\n", cmd); |
| 326 | ret = -EINVAL; |
| 327 | goto exit; |
| 328 | } |
| 329 | |
| 330 | exit: |
| 331 | return ret; |
| 332 | } |
| 333 | |
| 334 | static const struct file_operations asr_rsa_fops = { |
| 335 | .owner = THIS_MODULE, |
| 336 | .open = asr_rsa_open, |
| 337 | .release = asr_rsa_close, |
| 338 | .unlocked_ioctl = asr_rsa_ioctl, |
| 339 | }; |
| 340 | |
| 341 | int asr_te200_rsa_register(struct asr_te200_dev *te200_dd) |
| 342 | { |
| 343 | int ret = 0; |
| 344 | struct asr_te200_rsa *prsa; |
| 345 | struct miscdevice *misc; |
| 346 | struct device *dev = te200_dd->dev; |
| 347 | |
| 348 | prsa = &te200_dd->asr_rsa; |
| 349 | misc = &prsa->rsa_misc; |
| 350 | |
| 351 | misc->name = "hwrsa"; |
| 352 | misc->minor = MISC_DYNAMIC_MINOR; |
| 353 | misc->fops = &asr_rsa_fops; |
| 354 | misc->this_device = NULL; |
| 355 | prsa->dev = te200_dd->dev; |
| 356 | |
| 357 | /* register the device */ |
| 358 | ret = misc_register(misc); |
| 359 | if (ret < 0) { |
| 360 | dev_err(dev, |
| 361 | "asr rsa: unable to register device node /dev/hwrsa\n"); |
| 362 | return ret; |
| 363 | } |
| 364 | |
| 365 | return 0; |
| 366 | } |
| 367 | EXPORT_SYMBOL_GPL(asr_te200_rsa_register); |
| 368 | |
| 369 | int asr_te200_rsa_unregister(struct asr_te200_dev *te200_dd) |
| 370 | { |
| 371 | struct miscdevice *miscdev; |
| 372 | |
| 373 | miscdev = &te200_dd->asr_rsa.rsa_misc; |
| 374 | |
| 375 | misc_deregister(miscdev); |
| 376 | |
| 377 | return 0; |
| 378 | } |
| 379 | EXPORT_SYMBOL_GPL(asr_te200_rsa_unregister); |
| 380 | |
| 381 | MODULE_LICENSE("GPL"); |
| 382 | MODULE_AUTHOR("Yonggan Wang <yongganwang@asrmicro.com>"); |
| 383 | MODULE_DESCRIPTION("ASR hwrsa driver"); |