18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2019 48c2ecf20Sopenharmony_ci * Author(s): Harald Freudenberger <freude@linux.ibm.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Collection of EP11 misc functions used by zcrypt and pkey 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zcrypt" 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/random.h> 168c2ecf20Sopenharmony_ci#include <asm/zcrypt.h> 178c2ecf20Sopenharmony_ci#include <asm/pkey.h> 188c2ecf20Sopenharmony_ci#include <crypto/aes.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "ap_bus.h" 218c2ecf20Sopenharmony_ci#include "zcrypt_api.h" 228c2ecf20Sopenharmony_ci#include "zcrypt_debug.h" 238c2ecf20Sopenharmony_ci#include "zcrypt_msgtype6.h" 248c2ecf20Sopenharmony_ci#include "zcrypt_ep11misc.h" 258c2ecf20Sopenharmony_ci#include "zcrypt_ccamisc.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define DEBUG_DBG(...) ZCRYPT_DBF(DBF_DEBUG, ##__VA_ARGS__) 288c2ecf20Sopenharmony_ci#define DEBUG_INFO(...) ZCRYPT_DBF(DBF_INFO, ##__VA_ARGS__) 298c2ecf20Sopenharmony_ci#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__) 308c2ecf20Sopenharmony_ci#define DEBUG_ERR(...) ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* default iv used here */ 338c2ecf20Sopenharmony_cistatic const u8 def_iv[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 348c2ecf20Sopenharmony_ci 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* ep11 card info cache */ 378c2ecf20Sopenharmony_cistruct card_list_entry { 388c2ecf20Sopenharmony_ci struct list_head list; 398c2ecf20Sopenharmony_ci u16 cardnr; 408c2ecf20Sopenharmony_ci struct ep11_card_info info; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_cistatic LIST_HEAD(card_list); 438c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(card_list_lock); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int card_cache_fetch(u16 cardnr, struct ep11_card_info *ci) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int rc = -ENOENT; 488c2ecf20Sopenharmony_ci struct card_list_entry *ptr; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci spin_lock_bh(&card_list_lock); 518c2ecf20Sopenharmony_ci list_for_each_entry(ptr, &card_list, list) { 528c2ecf20Sopenharmony_ci if (ptr->cardnr == cardnr) { 538c2ecf20Sopenharmony_ci memcpy(ci, &ptr->info, sizeof(*ci)); 548c2ecf20Sopenharmony_ci rc = 0; 558c2ecf20Sopenharmony_ci break; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci spin_unlock_bh(&card_list_lock); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return rc; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void card_cache_update(u16 cardnr, const struct ep11_card_info *ci) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci int found = 0; 668c2ecf20Sopenharmony_ci struct card_list_entry *ptr; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci spin_lock_bh(&card_list_lock); 698c2ecf20Sopenharmony_ci list_for_each_entry(ptr, &card_list, list) { 708c2ecf20Sopenharmony_ci if (ptr->cardnr == cardnr) { 718c2ecf20Sopenharmony_ci memcpy(&ptr->info, ci, sizeof(*ci)); 728c2ecf20Sopenharmony_ci found = 1; 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci if (!found) { 778c2ecf20Sopenharmony_ci ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); 788c2ecf20Sopenharmony_ci if (!ptr) { 798c2ecf20Sopenharmony_ci spin_unlock_bh(&card_list_lock); 808c2ecf20Sopenharmony_ci return; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci ptr->cardnr = cardnr; 838c2ecf20Sopenharmony_ci memcpy(&ptr->info, ci, sizeof(*ci)); 848c2ecf20Sopenharmony_ci list_add(&ptr->list, &card_list); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci spin_unlock_bh(&card_list_lock); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void card_cache_scrub(u16 cardnr) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct card_list_entry *ptr; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci spin_lock_bh(&card_list_lock); 948c2ecf20Sopenharmony_ci list_for_each_entry(ptr, &card_list, list) { 958c2ecf20Sopenharmony_ci if (ptr->cardnr == cardnr) { 968c2ecf20Sopenharmony_ci list_del(&ptr->list); 978c2ecf20Sopenharmony_ci kfree(ptr); 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci spin_unlock_bh(&card_list_lock); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void __exit card_cache_free(void) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct card_list_entry *ptr, *pnext; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci spin_lock_bh(&card_list_lock); 1098c2ecf20Sopenharmony_ci list_for_each_entry_safe(ptr, pnext, &card_list, list) { 1108c2ecf20Sopenharmony_ci list_del(&ptr->list); 1118c2ecf20Sopenharmony_ci kfree(ptr); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci spin_unlock_bh(&card_list_lock); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * Simple check if the key blob is a valid EP11 AES key blob with header. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ciint ep11_check_aes_key_with_hdr(debug_info_t *dbg, int dbflvl, 1208c2ecf20Sopenharmony_ci const u8 *key, size_t keylen, int checkcpacfexp) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct ep11kblob_header *hdr = (struct ep11kblob_header *) key; 1238c2ecf20Sopenharmony_ci struct ep11keyblob *kb = (struct ep11keyblob *) (key + sizeof(*hdr)); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (keylen < sizeof(*hdr) + sizeof(*kb)) { 1288c2ecf20Sopenharmony_ci DBF("%s key check failed, keylen %zu < %zu\n", 1298c2ecf20Sopenharmony_ci __func__, keylen, sizeof(*hdr) + sizeof(*kb)); 1308c2ecf20Sopenharmony_ci return -EINVAL; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (hdr->type != TOKTYPE_NON_CCA) { 1348c2ecf20Sopenharmony_ci if (dbg) 1358c2ecf20Sopenharmony_ci DBF("%s key check failed, type 0x%02x != 0x%02x\n", 1368c2ecf20Sopenharmony_ci __func__, (int) hdr->type, TOKTYPE_NON_CCA); 1378c2ecf20Sopenharmony_ci return -EINVAL; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci if (hdr->hver != 0x00) { 1408c2ecf20Sopenharmony_ci if (dbg) 1418c2ecf20Sopenharmony_ci DBF("%s key check failed, header version 0x%02x != 0x00\n", 1428c2ecf20Sopenharmony_ci __func__, (int) hdr->hver); 1438c2ecf20Sopenharmony_ci return -EINVAL; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci if (hdr->version != TOKVER_EP11_AES_WITH_HEADER) { 1468c2ecf20Sopenharmony_ci if (dbg) 1478c2ecf20Sopenharmony_ci DBF("%s key check failed, version 0x%02x != 0x%02x\n", 1488c2ecf20Sopenharmony_ci __func__, (int) hdr->version, TOKVER_EP11_AES_WITH_HEADER); 1498c2ecf20Sopenharmony_ci return -EINVAL; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci if (hdr->len > keylen) { 1528c2ecf20Sopenharmony_ci if (dbg) 1538c2ecf20Sopenharmony_ci DBF("%s key check failed, header len %d keylen %zu mismatch\n", 1548c2ecf20Sopenharmony_ci __func__, (int) hdr->len, keylen); 1558c2ecf20Sopenharmony_ci return -EINVAL; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci if (hdr->len < sizeof(*hdr) + sizeof(*kb)) { 1588c2ecf20Sopenharmony_ci if (dbg) 1598c2ecf20Sopenharmony_ci DBF("%s key check failed, header len %d < %zu\n", 1608c2ecf20Sopenharmony_ci __func__, (int) hdr->len, sizeof(*hdr) + sizeof(*kb)); 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (kb->version != EP11_STRUCT_MAGIC) { 1658c2ecf20Sopenharmony_ci if (dbg) 1668c2ecf20Sopenharmony_ci DBF("%s key check failed, blob magic 0x%04x != 0x%04x\n", 1678c2ecf20Sopenharmony_ci __func__, (int) kb->version, EP11_STRUCT_MAGIC); 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci if (checkcpacfexp && !(kb->attr & EP11_BLOB_PKEY_EXTRACTABLE)) { 1718c2ecf20Sopenharmony_ci if (dbg) 1728c2ecf20Sopenharmony_ci DBF("%s key check failed, PKEY_EXTRACTABLE is off\n", 1738c2ecf20Sopenharmony_ci __func__); 1748c2ecf20Sopenharmony_ci return -EINVAL; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#undef DBF 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_check_aes_key_with_hdr); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* 1848c2ecf20Sopenharmony_ci * Simple check if the key blob is a valid EP11 ECC key blob with header. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ciint ep11_check_ecc_key_with_hdr(debug_info_t *dbg, int dbflvl, 1878c2ecf20Sopenharmony_ci const u8 *key, size_t keylen, int checkcpacfexp) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct ep11kblob_header *hdr = (struct ep11kblob_header *) key; 1908c2ecf20Sopenharmony_ci struct ep11keyblob *kb = (struct ep11keyblob *) (key + sizeof(*hdr)); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (keylen < sizeof(*hdr) + sizeof(*kb)) { 1958c2ecf20Sopenharmony_ci DBF("%s key check failed, keylen %zu < %zu\n", 1968c2ecf20Sopenharmony_ci __func__, keylen, sizeof(*hdr) + sizeof(*kb)); 1978c2ecf20Sopenharmony_ci return -EINVAL; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (hdr->type != TOKTYPE_NON_CCA) { 2018c2ecf20Sopenharmony_ci if (dbg) 2028c2ecf20Sopenharmony_ci DBF("%s key check failed, type 0x%02x != 0x%02x\n", 2038c2ecf20Sopenharmony_ci __func__, (int) hdr->type, TOKTYPE_NON_CCA); 2048c2ecf20Sopenharmony_ci return -EINVAL; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci if (hdr->hver != 0x00) { 2078c2ecf20Sopenharmony_ci if (dbg) 2088c2ecf20Sopenharmony_ci DBF("%s key check failed, header version 0x%02x != 0x00\n", 2098c2ecf20Sopenharmony_ci __func__, (int) hdr->hver); 2108c2ecf20Sopenharmony_ci return -EINVAL; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci if (hdr->version != TOKVER_EP11_ECC_WITH_HEADER) { 2138c2ecf20Sopenharmony_ci if (dbg) 2148c2ecf20Sopenharmony_ci DBF("%s key check failed, version 0x%02x != 0x%02x\n", 2158c2ecf20Sopenharmony_ci __func__, (int) hdr->version, TOKVER_EP11_ECC_WITH_HEADER); 2168c2ecf20Sopenharmony_ci return -EINVAL; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci if (hdr->len > keylen) { 2198c2ecf20Sopenharmony_ci if (dbg) 2208c2ecf20Sopenharmony_ci DBF("%s key check failed, header len %d keylen %zu mismatch\n", 2218c2ecf20Sopenharmony_ci __func__, (int) hdr->len, keylen); 2228c2ecf20Sopenharmony_ci return -EINVAL; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci if (hdr->len < sizeof(*hdr) + sizeof(*kb)) { 2258c2ecf20Sopenharmony_ci if (dbg) 2268c2ecf20Sopenharmony_ci DBF("%s key check failed, header len %d < %zu\n", 2278c2ecf20Sopenharmony_ci __func__, (int) hdr->len, sizeof(*hdr) + sizeof(*kb)); 2288c2ecf20Sopenharmony_ci return -EINVAL; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (kb->version != EP11_STRUCT_MAGIC) { 2328c2ecf20Sopenharmony_ci if (dbg) 2338c2ecf20Sopenharmony_ci DBF("%s key check failed, blob magic 0x%04x != 0x%04x\n", 2348c2ecf20Sopenharmony_ci __func__, (int) kb->version, EP11_STRUCT_MAGIC); 2358c2ecf20Sopenharmony_ci return -EINVAL; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci if (checkcpacfexp && !(kb->attr & EP11_BLOB_PKEY_EXTRACTABLE)) { 2388c2ecf20Sopenharmony_ci if (dbg) 2398c2ecf20Sopenharmony_ci DBF("%s key check failed, PKEY_EXTRACTABLE is off\n", 2408c2ecf20Sopenharmony_ci __func__); 2418c2ecf20Sopenharmony_ci return -EINVAL; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#undef DBF 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_check_ecc_key_with_hdr); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * Simple check if the key blob is a valid EP11 AES key blob with 2528c2ecf20Sopenharmony_ci * the header in the session field (old style EP11 AES key). 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ciint ep11_check_aes_key(debug_info_t *dbg, int dbflvl, 2558c2ecf20Sopenharmony_ci const u8 *key, size_t keylen, int checkcpacfexp) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct ep11keyblob *kb = (struct ep11keyblob *) key; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (keylen < sizeof(*kb)) { 2628c2ecf20Sopenharmony_ci DBF("%s key check failed, keylen %zu < %zu\n", 2638c2ecf20Sopenharmony_ci __func__, keylen, sizeof(*kb)); 2648c2ecf20Sopenharmony_ci return -EINVAL; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (kb->head.type != TOKTYPE_NON_CCA) { 2688c2ecf20Sopenharmony_ci if (dbg) 2698c2ecf20Sopenharmony_ci DBF("%s key check failed, type 0x%02x != 0x%02x\n", 2708c2ecf20Sopenharmony_ci __func__, (int) kb->head.type, TOKTYPE_NON_CCA); 2718c2ecf20Sopenharmony_ci return -EINVAL; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci if (kb->head.version != TOKVER_EP11_AES) { 2748c2ecf20Sopenharmony_ci if (dbg) 2758c2ecf20Sopenharmony_ci DBF("%s key check failed, version 0x%02x != 0x%02x\n", 2768c2ecf20Sopenharmony_ci __func__, (int) kb->head.version, TOKVER_EP11_AES); 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci if (kb->head.len > keylen) { 2808c2ecf20Sopenharmony_ci if (dbg) 2818c2ecf20Sopenharmony_ci DBF("%s key check failed, header len %d keylen %zu mismatch\n", 2828c2ecf20Sopenharmony_ci __func__, (int) kb->head.len, keylen); 2838c2ecf20Sopenharmony_ci return -EINVAL; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci if (kb->head.len < sizeof(*kb)) { 2868c2ecf20Sopenharmony_ci if (dbg) 2878c2ecf20Sopenharmony_ci DBF("%s key check failed, header len %d < %zu\n", 2888c2ecf20Sopenharmony_ci __func__, (int) kb->head.len, sizeof(*kb)); 2898c2ecf20Sopenharmony_ci return -EINVAL; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (kb->version != EP11_STRUCT_MAGIC) { 2938c2ecf20Sopenharmony_ci if (dbg) 2948c2ecf20Sopenharmony_ci DBF("%s key check failed, blob magic 0x%04x != 0x%04x\n", 2958c2ecf20Sopenharmony_ci __func__, (int) kb->version, EP11_STRUCT_MAGIC); 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci if (checkcpacfexp && !(kb->attr & EP11_BLOB_PKEY_EXTRACTABLE)) { 2998c2ecf20Sopenharmony_ci if (dbg) 3008c2ecf20Sopenharmony_ci DBF("%s key check failed, PKEY_EXTRACTABLE is off\n", 3018c2ecf20Sopenharmony_ci __func__); 3028c2ecf20Sopenharmony_ci return -EINVAL; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci#undef DBF 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_check_aes_key); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* 3128c2ecf20Sopenharmony_ci * Allocate and prepare ep11 cprb plus additional payload. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_cistatic inline struct ep11_cprb *alloc_cprb(size_t payload_len) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci size_t len = sizeof(struct ep11_cprb) + payload_len; 3178c2ecf20Sopenharmony_ci struct ep11_cprb *cprb; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci cprb = kzalloc(len, GFP_KERNEL); 3208c2ecf20Sopenharmony_ci if (!cprb) 3218c2ecf20Sopenharmony_ci return NULL; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci cprb->cprb_len = sizeof(struct ep11_cprb); 3248c2ecf20Sopenharmony_ci cprb->cprb_ver_id = 0x04; 3258c2ecf20Sopenharmony_ci memcpy(cprb->func_id, "T4", 2); 3268c2ecf20Sopenharmony_ci cprb->ret_code = 0xFFFFFFFF; 3278c2ecf20Sopenharmony_ci cprb->payload_len = payload_len; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return cprb; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* 3338c2ecf20Sopenharmony_ci * Some helper functions related to ASN1 encoding. 3348c2ecf20Sopenharmony_ci * Limited to length info <= 2 byte. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci#define ASN1TAGLEN(x) (2 + (x) + ((x) > 127 ? 1 : 0) + ((x) > 255 ? 1 : 0)) 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int asn1tag_write(u8 *ptr, u8 tag, const u8 *pvalue, u16 valuelen) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci ptr[0] = tag; 3428c2ecf20Sopenharmony_ci if (valuelen > 255) { 3438c2ecf20Sopenharmony_ci ptr[1] = 0x82; 3448c2ecf20Sopenharmony_ci *((u16 *)(ptr + 2)) = valuelen; 3458c2ecf20Sopenharmony_ci memcpy(ptr + 4, pvalue, valuelen); 3468c2ecf20Sopenharmony_ci return 4 + valuelen; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci if (valuelen > 127) { 3498c2ecf20Sopenharmony_ci ptr[1] = 0x81; 3508c2ecf20Sopenharmony_ci ptr[2] = (u8) valuelen; 3518c2ecf20Sopenharmony_ci memcpy(ptr + 3, pvalue, valuelen); 3528c2ecf20Sopenharmony_ci return 3 + valuelen; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci ptr[1] = (u8) valuelen; 3558c2ecf20Sopenharmony_ci memcpy(ptr + 2, pvalue, valuelen); 3568c2ecf20Sopenharmony_ci return 2 + valuelen; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* EP11 payload > 127 bytes starts with this struct */ 3608c2ecf20Sopenharmony_cistruct pl_head { 3618c2ecf20Sopenharmony_ci u8 tag; 3628c2ecf20Sopenharmony_ci u8 lenfmt; 3638c2ecf20Sopenharmony_ci u16 len; 3648c2ecf20Sopenharmony_ci u8 func_tag; 3658c2ecf20Sopenharmony_ci u8 func_len; 3668c2ecf20Sopenharmony_ci u32 func; 3678c2ecf20Sopenharmony_ci u8 dom_tag; 3688c2ecf20Sopenharmony_ci u8 dom_len; 3698c2ecf20Sopenharmony_ci u32 dom; 3708c2ecf20Sopenharmony_ci} __packed; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* prep ep11 payload head helper function */ 3738c2ecf20Sopenharmony_cistatic inline void prep_head(struct pl_head *h, 3748c2ecf20Sopenharmony_ci size_t pl_size, int api, int func) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci h->tag = 0x30; 3778c2ecf20Sopenharmony_ci h->lenfmt = 0x82; 3788c2ecf20Sopenharmony_ci h->len = pl_size - 4; 3798c2ecf20Sopenharmony_ci h->func_tag = 0x04; 3808c2ecf20Sopenharmony_ci h->func_len = sizeof(u32); 3818c2ecf20Sopenharmony_ci h->func = (api << 16) + func; 3828c2ecf20Sopenharmony_ci h->dom_tag = 0x04; 3838c2ecf20Sopenharmony_ci h->dom_len = sizeof(u32); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/* prep urb helper function */ 3878c2ecf20Sopenharmony_cistatic inline void prep_urb(struct ep11_urb *u, 3888c2ecf20Sopenharmony_ci struct ep11_target_dev *t, int nt, 3898c2ecf20Sopenharmony_ci struct ep11_cprb *req, size_t req_len, 3908c2ecf20Sopenharmony_ci struct ep11_cprb *rep, size_t rep_len) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u->targets = (u8 __user *) t; 3938c2ecf20Sopenharmony_ci u->targets_num = nt; 3948c2ecf20Sopenharmony_ci u->req = (u8 __user *) req; 3958c2ecf20Sopenharmony_ci u->req_len = req_len; 3968c2ecf20Sopenharmony_ci u->resp = (u8 __user *) rep; 3978c2ecf20Sopenharmony_ci u->resp_len = rep_len; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/* Check ep11 reply payload, return 0 or suggested errno value. */ 4018c2ecf20Sopenharmony_cistatic int check_reply_pl(const u8 *pl, const char *func) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci int len; 4048c2ecf20Sopenharmony_ci u32 ret; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* start tag */ 4078c2ecf20Sopenharmony_ci if (*pl++ != 0x30) { 4088c2ecf20Sopenharmony_ci DEBUG_ERR("%s reply start tag mismatch\n", func); 4098c2ecf20Sopenharmony_ci return -EIO; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* payload length format */ 4138c2ecf20Sopenharmony_ci if (*pl < 127) { 4148c2ecf20Sopenharmony_ci len = *pl; 4158c2ecf20Sopenharmony_ci pl++; 4168c2ecf20Sopenharmony_ci } else if (*pl == 0x81) { 4178c2ecf20Sopenharmony_ci pl++; 4188c2ecf20Sopenharmony_ci len = *pl; 4198c2ecf20Sopenharmony_ci pl++; 4208c2ecf20Sopenharmony_ci } else if (*pl == 0x82) { 4218c2ecf20Sopenharmony_ci pl++; 4228c2ecf20Sopenharmony_ci len = *((u16 *)pl); 4238c2ecf20Sopenharmony_ci pl += 2; 4248c2ecf20Sopenharmony_ci } else { 4258c2ecf20Sopenharmony_ci DEBUG_ERR("%s reply start tag lenfmt mismatch 0x%02hhx\n", 4268c2ecf20Sopenharmony_ci func, *pl); 4278c2ecf20Sopenharmony_ci return -EIO; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* len should cover at least 3 fields with 32 bit value each */ 4318c2ecf20Sopenharmony_ci if (len < 3 * 6) { 4328c2ecf20Sopenharmony_ci DEBUG_ERR("%s reply length %d too small\n", func, len); 4338c2ecf20Sopenharmony_ci return -EIO; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* function tag, length and value */ 4378c2ecf20Sopenharmony_ci if (pl[0] != 0x04 || pl[1] != 0x04) { 4388c2ecf20Sopenharmony_ci DEBUG_ERR("%s function tag or length mismatch\n", func); 4398c2ecf20Sopenharmony_ci return -EIO; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci pl += 6; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* dom tag, length and value */ 4448c2ecf20Sopenharmony_ci if (pl[0] != 0x04 || pl[1] != 0x04) { 4458c2ecf20Sopenharmony_ci DEBUG_ERR("%s dom tag or length mismatch\n", func); 4468c2ecf20Sopenharmony_ci return -EIO; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci pl += 6; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* return value tag, length and value */ 4518c2ecf20Sopenharmony_ci if (pl[0] != 0x04 || pl[1] != 0x04) { 4528c2ecf20Sopenharmony_ci DEBUG_ERR("%s return value tag or length mismatch\n", func); 4538c2ecf20Sopenharmony_ci return -EIO; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci pl += 2; 4568c2ecf20Sopenharmony_ci ret = *((u32 *)pl); 4578c2ecf20Sopenharmony_ci if (ret != 0) { 4588c2ecf20Sopenharmony_ci DEBUG_ERR("%s return value 0x%04x != 0\n", func, ret); 4598c2ecf20Sopenharmony_ci return -EIO; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/* 4678c2ecf20Sopenharmony_ci * Helper function which does an ep11 query with given query type. 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_cistatic int ep11_query_info(u16 cardnr, u16 domain, u32 query_type, 4708c2ecf20Sopenharmony_ci size_t buflen, u8 *buf) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct ep11_info_req_pl { 4738c2ecf20Sopenharmony_ci struct pl_head head; 4748c2ecf20Sopenharmony_ci u8 query_type_tag; 4758c2ecf20Sopenharmony_ci u8 query_type_len; 4768c2ecf20Sopenharmony_ci u32 query_type; 4778c2ecf20Sopenharmony_ci u8 query_subtype_tag; 4788c2ecf20Sopenharmony_ci u8 query_subtype_len; 4798c2ecf20Sopenharmony_ci u32 query_subtype; 4808c2ecf20Sopenharmony_ci } __packed * req_pl; 4818c2ecf20Sopenharmony_ci struct ep11_info_rep_pl { 4828c2ecf20Sopenharmony_ci struct pl_head head; 4838c2ecf20Sopenharmony_ci u8 rc_tag; 4848c2ecf20Sopenharmony_ci u8 rc_len; 4858c2ecf20Sopenharmony_ci u32 rc; 4868c2ecf20Sopenharmony_ci u8 data_tag; 4878c2ecf20Sopenharmony_ci u8 data_lenfmt; 4888c2ecf20Sopenharmony_ci u16 data_len; 4898c2ecf20Sopenharmony_ci } __packed * rep_pl; 4908c2ecf20Sopenharmony_ci struct ep11_cprb *req = NULL, *rep = NULL; 4918c2ecf20Sopenharmony_ci struct ep11_target_dev target; 4928c2ecf20Sopenharmony_ci struct ep11_urb *urb = NULL; 4938c2ecf20Sopenharmony_ci int api = 1, rc = -ENOMEM; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* request cprb and payload */ 4968c2ecf20Sopenharmony_ci req = alloc_cprb(sizeof(struct ep11_info_req_pl)); 4978c2ecf20Sopenharmony_ci if (!req) 4988c2ecf20Sopenharmony_ci goto out; 4998c2ecf20Sopenharmony_ci req_pl = (struct ep11_info_req_pl *) (((u8 *) req) + sizeof(*req)); 5008c2ecf20Sopenharmony_ci prep_head(&req_pl->head, sizeof(*req_pl), api, 38); /* get xcp info */ 5018c2ecf20Sopenharmony_ci req_pl->query_type_tag = 0x04; 5028c2ecf20Sopenharmony_ci req_pl->query_type_len = sizeof(u32); 5038c2ecf20Sopenharmony_ci req_pl->query_type = query_type; 5048c2ecf20Sopenharmony_ci req_pl->query_subtype_tag = 0x04; 5058c2ecf20Sopenharmony_ci req_pl->query_subtype_len = sizeof(u32); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* reply cprb and payload */ 5088c2ecf20Sopenharmony_ci rep = alloc_cprb(sizeof(struct ep11_info_rep_pl) + buflen); 5098c2ecf20Sopenharmony_ci if (!rep) 5108c2ecf20Sopenharmony_ci goto out; 5118c2ecf20Sopenharmony_ci rep_pl = (struct ep11_info_rep_pl *) (((u8 *) rep) + sizeof(*rep)); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* urb and target */ 5148c2ecf20Sopenharmony_ci urb = kmalloc(sizeof(struct ep11_urb), GFP_KERNEL); 5158c2ecf20Sopenharmony_ci if (!urb) 5168c2ecf20Sopenharmony_ci goto out; 5178c2ecf20Sopenharmony_ci target.ap_id = cardnr; 5188c2ecf20Sopenharmony_ci target.dom_id = domain; 5198c2ecf20Sopenharmony_ci prep_urb(urb, &target, 1, 5208c2ecf20Sopenharmony_ci req, sizeof(*req) + sizeof(*req_pl), 5218c2ecf20Sopenharmony_ci rep, sizeof(*rep) + sizeof(*rep_pl) + buflen); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci rc = zcrypt_send_ep11_cprb(urb); 5248c2ecf20Sopenharmony_ci if (rc) { 5258c2ecf20Sopenharmony_ci DEBUG_ERR( 5268c2ecf20Sopenharmony_ci "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n", 5278c2ecf20Sopenharmony_ci __func__, (int) cardnr, (int) domain, rc); 5288c2ecf20Sopenharmony_ci goto out; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci rc = check_reply_pl((u8 *)rep_pl, __func__); 5328c2ecf20Sopenharmony_ci if (rc) 5338c2ecf20Sopenharmony_ci goto out; 5348c2ecf20Sopenharmony_ci if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) { 5358c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown reply data format\n", __func__); 5368c2ecf20Sopenharmony_ci rc = -EIO; 5378c2ecf20Sopenharmony_ci goto out; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci if (rep_pl->data_len > buflen) { 5408c2ecf20Sopenharmony_ci DEBUG_ERR("%s mismatch between reply data len and buffer len\n", 5418c2ecf20Sopenharmony_ci __func__); 5428c2ecf20Sopenharmony_ci rc = -ENOSPC; 5438c2ecf20Sopenharmony_ci goto out; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci memcpy(buf, ((u8 *) rep_pl) + sizeof(*rep_pl), rep_pl->data_len); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ciout: 5498c2ecf20Sopenharmony_ci kfree(req); 5508c2ecf20Sopenharmony_ci kfree(rep); 5518c2ecf20Sopenharmony_ci kfree(urb); 5528c2ecf20Sopenharmony_ci return rc; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/* 5568c2ecf20Sopenharmony_ci * Provide information about an EP11 card. 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ciint ep11_get_card_info(u16 card, struct ep11_card_info *info, int verify) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci int rc; 5618c2ecf20Sopenharmony_ci struct ep11_module_query_info { 5628c2ecf20Sopenharmony_ci u32 API_ord_nr; 5638c2ecf20Sopenharmony_ci u32 firmware_id; 5648c2ecf20Sopenharmony_ci u8 FW_major_vers; 5658c2ecf20Sopenharmony_ci u8 FW_minor_vers; 5668c2ecf20Sopenharmony_ci u8 CSP_major_vers; 5678c2ecf20Sopenharmony_ci u8 CSP_minor_vers; 5688c2ecf20Sopenharmony_ci u8 fwid[32]; 5698c2ecf20Sopenharmony_ci u8 xcp_config_hash[32]; 5708c2ecf20Sopenharmony_ci u8 CSP_config_hash[32]; 5718c2ecf20Sopenharmony_ci u8 serial[16]; 5728c2ecf20Sopenharmony_ci u8 module_date_time[16]; 5738c2ecf20Sopenharmony_ci u64 op_mode; 5748c2ecf20Sopenharmony_ci u32 PKCS11_flags; 5758c2ecf20Sopenharmony_ci u32 ext_flags; 5768c2ecf20Sopenharmony_ci u32 domains; 5778c2ecf20Sopenharmony_ci u32 sym_state_bytes; 5788c2ecf20Sopenharmony_ci u32 digest_state_bytes; 5798c2ecf20Sopenharmony_ci u32 pin_blob_bytes; 5808c2ecf20Sopenharmony_ci u32 SPKI_bytes; 5818c2ecf20Sopenharmony_ci u32 priv_key_blob_bytes; 5828c2ecf20Sopenharmony_ci u32 sym_blob_bytes; 5838c2ecf20Sopenharmony_ci u32 max_payload_bytes; 5848c2ecf20Sopenharmony_ci u32 CP_profile_bytes; 5858c2ecf20Sopenharmony_ci u32 max_CP_index; 5868c2ecf20Sopenharmony_ci } __packed * pmqi = NULL; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci rc = card_cache_fetch(card, info); 5898c2ecf20Sopenharmony_ci if (rc || verify) { 5908c2ecf20Sopenharmony_ci pmqi = kmalloc(sizeof(*pmqi), GFP_KERNEL); 5918c2ecf20Sopenharmony_ci if (!pmqi) 5928c2ecf20Sopenharmony_ci return -ENOMEM; 5938c2ecf20Sopenharmony_ci rc = ep11_query_info(card, AUTOSEL_DOM, 5948c2ecf20Sopenharmony_ci 0x01 /* module info query */, 5958c2ecf20Sopenharmony_ci sizeof(*pmqi), (u8 *) pmqi); 5968c2ecf20Sopenharmony_ci if (rc) { 5978c2ecf20Sopenharmony_ci if (rc == -ENODEV) 5988c2ecf20Sopenharmony_ci card_cache_scrub(card); 5998c2ecf20Sopenharmony_ci goto out; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 6028c2ecf20Sopenharmony_ci info->API_ord_nr = pmqi->API_ord_nr; 6038c2ecf20Sopenharmony_ci info->FW_version = 6048c2ecf20Sopenharmony_ci (pmqi->FW_major_vers << 8) + pmqi->FW_minor_vers; 6058c2ecf20Sopenharmony_ci memcpy(info->serial, pmqi->serial, sizeof(info->serial)); 6068c2ecf20Sopenharmony_ci info->op_mode = pmqi->op_mode; 6078c2ecf20Sopenharmony_ci card_cache_update(card, info); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ciout: 6118c2ecf20Sopenharmony_ci kfree(pmqi); 6128c2ecf20Sopenharmony_ci return rc; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_get_card_info); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci/* 6178c2ecf20Sopenharmony_ci * Provide information about a domain within an EP11 card. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ciint ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci int rc; 6228c2ecf20Sopenharmony_ci struct ep11_domain_query_info { 6238c2ecf20Sopenharmony_ci u32 dom_index; 6248c2ecf20Sopenharmony_ci u8 cur_WK_VP[32]; 6258c2ecf20Sopenharmony_ci u8 new_WK_VP[32]; 6268c2ecf20Sopenharmony_ci u32 dom_flags; 6278c2ecf20Sopenharmony_ci u64 op_mode; 6288c2ecf20Sopenharmony_ci } __packed * p_dom_info; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci p_dom_info = kmalloc(sizeof(*p_dom_info), GFP_KERNEL); 6318c2ecf20Sopenharmony_ci if (!p_dom_info) 6328c2ecf20Sopenharmony_ci return -ENOMEM; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci rc = ep11_query_info(card, domain, 0x03 /* domain info query */, 6358c2ecf20Sopenharmony_ci sizeof(*p_dom_info), (u8 *) p_dom_info); 6368c2ecf20Sopenharmony_ci if (rc) 6378c2ecf20Sopenharmony_ci goto out; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 6408c2ecf20Sopenharmony_ci info->cur_wk_state = '0'; 6418c2ecf20Sopenharmony_ci info->new_wk_state = '0'; 6428c2ecf20Sopenharmony_ci if (p_dom_info->dom_flags & 0x10 /* left imprint mode */) { 6438c2ecf20Sopenharmony_ci if (p_dom_info->dom_flags & 0x02 /* cur wk valid */) { 6448c2ecf20Sopenharmony_ci info->cur_wk_state = '1'; 6458c2ecf20Sopenharmony_ci memcpy(info->cur_wkvp, p_dom_info->cur_WK_VP, 32); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci if (p_dom_info->dom_flags & 0x04 /* new wk present */ 6488c2ecf20Sopenharmony_ci || p_dom_info->dom_flags & 0x08 /* new wk committed */) { 6498c2ecf20Sopenharmony_ci info->new_wk_state = 6508c2ecf20Sopenharmony_ci p_dom_info->dom_flags & 0x08 ? '2' : '1'; 6518c2ecf20Sopenharmony_ci memcpy(info->new_wkvp, p_dom_info->new_WK_VP, 32); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci info->op_mode = p_dom_info->op_mode; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ciout: 6578c2ecf20Sopenharmony_ci kfree(p_dom_info); 6588c2ecf20Sopenharmony_ci return rc; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_get_domain_info); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci/* 6638c2ecf20Sopenharmony_ci * Default EP11 AES key generate attributes, used when no keygenflags given: 6648c2ecf20Sopenharmony_ci * XCP_BLOB_ENCRYPT | XCP_BLOB_DECRYPT | XCP_BLOB_PROTKEY_EXTRACTABLE 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci#define KEY_ATTR_DEFAULTS 0x00200c00 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ciint ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, 6698c2ecf20Sopenharmony_ci u8 *keybuf, size_t *keybufsize) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct keygen_req_pl { 6728c2ecf20Sopenharmony_ci struct pl_head head; 6738c2ecf20Sopenharmony_ci u8 var_tag; 6748c2ecf20Sopenharmony_ci u8 var_len; 6758c2ecf20Sopenharmony_ci u32 var; 6768c2ecf20Sopenharmony_ci u8 keybytes_tag; 6778c2ecf20Sopenharmony_ci u8 keybytes_len; 6788c2ecf20Sopenharmony_ci u32 keybytes; 6798c2ecf20Sopenharmony_ci u8 mech_tag; 6808c2ecf20Sopenharmony_ci u8 mech_len; 6818c2ecf20Sopenharmony_ci u32 mech; 6828c2ecf20Sopenharmony_ci u8 attr_tag; 6838c2ecf20Sopenharmony_ci u8 attr_len; 6848c2ecf20Sopenharmony_ci u32 attr_header; 6858c2ecf20Sopenharmony_ci u32 attr_bool_mask; 6868c2ecf20Sopenharmony_ci u32 attr_bool_bits; 6878c2ecf20Sopenharmony_ci u32 attr_val_len_type; 6888c2ecf20Sopenharmony_ci u32 attr_val_len_value; 6898c2ecf20Sopenharmony_ci u8 pin_tag; 6908c2ecf20Sopenharmony_ci u8 pin_len; 6918c2ecf20Sopenharmony_ci } __packed * req_pl; 6928c2ecf20Sopenharmony_ci struct keygen_rep_pl { 6938c2ecf20Sopenharmony_ci struct pl_head head; 6948c2ecf20Sopenharmony_ci u8 rc_tag; 6958c2ecf20Sopenharmony_ci u8 rc_len; 6968c2ecf20Sopenharmony_ci u32 rc; 6978c2ecf20Sopenharmony_ci u8 data_tag; 6988c2ecf20Sopenharmony_ci u8 data_lenfmt; 6998c2ecf20Sopenharmony_ci u16 data_len; 7008c2ecf20Sopenharmony_ci u8 data[512]; 7018c2ecf20Sopenharmony_ci } __packed * rep_pl; 7028c2ecf20Sopenharmony_ci struct ep11_cprb *req = NULL, *rep = NULL; 7038c2ecf20Sopenharmony_ci struct ep11_target_dev target; 7048c2ecf20Sopenharmony_ci struct ep11_urb *urb = NULL; 7058c2ecf20Sopenharmony_ci struct ep11keyblob *kb; 7068c2ecf20Sopenharmony_ci int api, rc = -ENOMEM; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci switch (keybitsize) { 7098c2ecf20Sopenharmony_ci case 128: 7108c2ecf20Sopenharmony_ci case 192: 7118c2ecf20Sopenharmony_ci case 256: 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci default: 7148c2ecf20Sopenharmony_ci DEBUG_ERR( 7158c2ecf20Sopenharmony_ci "%s unknown/unsupported keybitsize %d\n", 7168c2ecf20Sopenharmony_ci __func__, keybitsize); 7178c2ecf20Sopenharmony_ci rc = -EINVAL; 7188c2ecf20Sopenharmony_ci goto out; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* request cprb and payload */ 7228c2ecf20Sopenharmony_ci req = alloc_cprb(sizeof(struct keygen_req_pl)); 7238c2ecf20Sopenharmony_ci if (!req) 7248c2ecf20Sopenharmony_ci goto out; 7258c2ecf20Sopenharmony_ci req_pl = (struct keygen_req_pl *) (((u8 *) req) + sizeof(*req)); 7268c2ecf20Sopenharmony_ci api = (!keygenflags || keygenflags & 0x00200000) ? 4 : 1; 7278c2ecf20Sopenharmony_ci prep_head(&req_pl->head, sizeof(*req_pl), api, 21); /* GenerateKey */ 7288c2ecf20Sopenharmony_ci req_pl->var_tag = 0x04; 7298c2ecf20Sopenharmony_ci req_pl->var_len = sizeof(u32); 7308c2ecf20Sopenharmony_ci req_pl->keybytes_tag = 0x04; 7318c2ecf20Sopenharmony_ci req_pl->keybytes_len = sizeof(u32); 7328c2ecf20Sopenharmony_ci req_pl->keybytes = keybitsize / 8; 7338c2ecf20Sopenharmony_ci req_pl->mech_tag = 0x04; 7348c2ecf20Sopenharmony_ci req_pl->mech_len = sizeof(u32); 7358c2ecf20Sopenharmony_ci req_pl->mech = 0x00001080; /* CKM_AES_KEY_GEN */ 7368c2ecf20Sopenharmony_ci req_pl->attr_tag = 0x04; 7378c2ecf20Sopenharmony_ci req_pl->attr_len = 5 * sizeof(u32); 7388c2ecf20Sopenharmony_ci req_pl->attr_header = 0x10010000; 7398c2ecf20Sopenharmony_ci req_pl->attr_bool_mask = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS; 7408c2ecf20Sopenharmony_ci req_pl->attr_bool_bits = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS; 7418c2ecf20Sopenharmony_ci req_pl->attr_val_len_type = 0x00000161; /* CKA_VALUE_LEN */ 7428c2ecf20Sopenharmony_ci req_pl->attr_val_len_value = keybitsize / 8; 7438c2ecf20Sopenharmony_ci req_pl->pin_tag = 0x04; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* reply cprb and payload */ 7468c2ecf20Sopenharmony_ci rep = alloc_cprb(sizeof(struct keygen_rep_pl)); 7478c2ecf20Sopenharmony_ci if (!rep) 7488c2ecf20Sopenharmony_ci goto out; 7498c2ecf20Sopenharmony_ci rep_pl = (struct keygen_rep_pl *) (((u8 *) rep) + sizeof(*rep)); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* urb and target */ 7528c2ecf20Sopenharmony_ci urb = kmalloc(sizeof(struct ep11_urb), GFP_KERNEL); 7538c2ecf20Sopenharmony_ci if (!urb) 7548c2ecf20Sopenharmony_ci goto out; 7558c2ecf20Sopenharmony_ci target.ap_id = card; 7568c2ecf20Sopenharmony_ci target.dom_id = domain; 7578c2ecf20Sopenharmony_ci prep_urb(urb, &target, 1, 7588c2ecf20Sopenharmony_ci req, sizeof(*req) + sizeof(*req_pl), 7598c2ecf20Sopenharmony_ci rep, sizeof(*rep) + sizeof(*rep_pl)); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci rc = zcrypt_send_ep11_cprb(urb); 7628c2ecf20Sopenharmony_ci if (rc) { 7638c2ecf20Sopenharmony_ci DEBUG_ERR( 7648c2ecf20Sopenharmony_ci "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n", 7658c2ecf20Sopenharmony_ci __func__, (int) card, (int) domain, rc); 7668c2ecf20Sopenharmony_ci goto out; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci rc = check_reply_pl((u8 *)rep_pl, __func__); 7708c2ecf20Sopenharmony_ci if (rc) 7718c2ecf20Sopenharmony_ci goto out; 7728c2ecf20Sopenharmony_ci if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) { 7738c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown reply data format\n", __func__); 7748c2ecf20Sopenharmony_ci rc = -EIO; 7758c2ecf20Sopenharmony_ci goto out; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci if (rep_pl->data_len > *keybufsize) { 7788c2ecf20Sopenharmony_ci DEBUG_ERR("%s mismatch reply data len / key buffer len\n", 7798c2ecf20Sopenharmony_ci __func__); 7808c2ecf20Sopenharmony_ci rc = -ENOSPC; 7818c2ecf20Sopenharmony_ci goto out; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* copy key blob and set header values */ 7858c2ecf20Sopenharmony_ci memcpy(keybuf, rep_pl->data, rep_pl->data_len); 7868c2ecf20Sopenharmony_ci *keybufsize = rep_pl->data_len; 7878c2ecf20Sopenharmony_ci kb = (struct ep11keyblob *) keybuf; 7888c2ecf20Sopenharmony_ci kb->head.type = TOKTYPE_NON_CCA; 7898c2ecf20Sopenharmony_ci kb->head.len = rep_pl->data_len; 7908c2ecf20Sopenharmony_ci kb->head.version = TOKVER_EP11_AES; 7918c2ecf20Sopenharmony_ci kb->head.bitlen = keybitsize; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ciout: 7948c2ecf20Sopenharmony_ci kfree(req); 7958c2ecf20Sopenharmony_ci kfree(rep); 7968c2ecf20Sopenharmony_ci kfree(urb); 7978c2ecf20Sopenharmony_ci return rc; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_genaeskey); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic int ep11_cryptsingle(u16 card, u16 domain, 8028c2ecf20Sopenharmony_ci u16 mode, u32 mech, const u8 *iv, 8038c2ecf20Sopenharmony_ci const u8 *key, size_t keysize, 8048c2ecf20Sopenharmony_ci const u8 *inbuf, size_t inbufsize, 8058c2ecf20Sopenharmony_ci u8 *outbuf, size_t *outbufsize) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct crypt_req_pl { 8088c2ecf20Sopenharmony_ci struct pl_head head; 8098c2ecf20Sopenharmony_ci u8 var_tag; 8108c2ecf20Sopenharmony_ci u8 var_len; 8118c2ecf20Sopenharmony_ci u32 var; 8128c2ecf20Sopenharmony_ci u8 mech_tag; 8138c2ecf20Sopenharmony_ci u8 mech_len; 8148c2ecf20Sopenharmony_ci u32 mech; 8158c2ecf20Sopenharmony_ci /* 8168c2ecf20Sopenharmony_ci * maybe followed by iv data 8178c2ecf20Sopenharmony_ci * followed by key tag + key blob 8188c2ecf20Sopenharmony_ci * followed by plaintext tag + plaintext 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_ci } __packed * req_pl; 8218c2ecf20Sopenharmony_ci struct crypt_rep_pl { 8228c2ecf20Sopenharmony_ci struct pl_head head; 8238c2ecf20Sopenharmony_ci u8 rc_tag; 8248c2ecf20Sopenharmony_ci u8 rc_len; 8258c2ecf20Sopenharmony_ci u32 rc; 8268c2ecf20Sopenharmony_ci u8 data_tag; 8278c2ecf20Sopenharmony_ci u8 data_lenfmt; 8288c2ecf20Sopenharmony_ci /* data follows */ 8298c2ecf20Sopenharmony_ci } __packed * rep_pl; 8308c2ecf20Sopenharmony_ci struct ep11_cprb *req = NULL, *rep = NULL; 8318c2ecf20Sopenharmony_ci struct ep11_target_dev target; 8328c2ecf20Sopenharmony_ci struct ep11_urb *urb = NULL; 8338c2ecf20Sopenharmony_ci size_t req_pl_size, rep_pl_size; 8348c2ecf20Sopenharmony_ci int n, api = 1, rc = -ENOMEM; 8358c2ecf20Sopenharmony_ci u8 *p; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* the simple asn1 coding used has length limits */ 8388c2ecf20Sopenharmony_ci if (keysize > 0xFFFF || inbufsize > 0xFFFF) 8398c2ecf20Sopenharmony_ci return -EINVAL; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* request cprb and payload */ 8428c2ecf20Sopenharmony_ci req_pl_size = sizeof(struct crypt_req_pl) + (iv ? 16 : 0) 8438c2ecf20Sopenharmony_ci + ASN1TAGLEN(keysize) + ASN1TAGLEN(inbufsize); 8448c2ecf20Sopenharmony_ci req = alloc_cprb(req_pl_size); 8458c2ecf20Sopenharmony_ci if (!req) 8468c2ecf20Sopenharmony_ci goto out; 8478c2ecf20Sopenharmony_ci req_pl = (struct crypt_req_pl *) (((u8 *) req) + sizeof(*req)); 8488c2ecf20Sopenharmony_ci prep_head(&req_pl->head, req_pl_size, api, (mode ? 20 : 19)); 8498c2ecf20Sopenharmony_ci req_pl->var_tag = 0x04; 8508c2ecf20Sopenharmony_ci req_pl->var_len = sizeof(u32); 8518c2ecf20Sopenharmony_ci /* mech is mech + mech params (iv here) */ 8528c2ecf20Sopenharmony_ci req_pl->mech_tag = 0x04; 8538c2ecf20Sopenharmony_ci req_pl->mech_len = sizeof(u32) + (iv ? 16 : 0); 8548c2ecf20Sopenharmony_ci req_pl->mech = (mech ? mech : 0x00001085); /* CKM_AES_CBC_PAD */ 8558c2ecf20Sopenharmony_ci p = ((u8 *) req_pl) + sizeof(*req_pl); 8568c2ecf20Sopenharmony_ci if (iv) { 8578c2ecf20Sopenharmony_ci memcpy(p, iv, 16); 8588c2ecf20Sopenharmony_ci p += 16; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci /* key and input data */ 8618c2ecf20Sopenharmony_ci p += asn1tag_write(p, 0x04, key, keysize); 8628c2ecf20Sopenharmony_ci p += asn1tag_write(p, 0x04, inbuf, inbufsize); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* reply cprb and payload, assume out data size <= in data size + 32 */ 8658c2ecf20Sopenharmony_ci rep_pl_size = sizeof(struct crypt_rep_pl) + ASN1TAGLEN(inbufsize + 32); 8668c2ecf20Sopenharmony_ci rep = alloc_cprb(rep_pl_size); 8678c2ecf20Sopenharmony_ci if (!rep) 8688c2ecf20Sopenharmony_ci goto out; 8698c2ecf20Sopenharmony_ci rep_pl = (struct crypt_rep_pl *) (((u8 *) rep) + sizeof(*rep)); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* urb and target */ 8728c2ecf20Sopenharmony_ci urb = kmalloc(sizeof(struct ep11_urb), GFP_KERNEL); 8738c2ecf20Sopenharmony_ci if (!urb) 8748c2ecf20Sopenharmony_ci goto out; 8758c2ecf20Sopenharmony_ci target.ap_id = card; 8768c2ecf20Sopenharmony_ci target.dom_id = domain; 8778c2ecf20Sopenharmony_ci prep_urb(urb, &target, 1, 8788c2ecf20Sopenharmony_ci req, sizeof(*req) + req_pl_size, 8798c2ecf20Sopenharmony_ci rep, sizeof(*rep) + rep_pl_size); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci rc = zcrypt_send_ep11_cprb(urb); 8828c2ecf20Sopenharmony_ci if (rc) { 8838c2ecf20Sopenharmony_ci DEBUG_ERR( 8848c2ecf20Sopenharmony_ci "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n", 8858c2ecf20Sopenharmony_ci __func__, (int) card, (int) domain, rc); 8868c2ecf20Sopenharmony_ci goto out; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci rc = check_reply_pl((u8 *)rep_pl, __func__); 8908c2ecf20Sopenharmony_ci if (rc) 8918c2ecf20Sopenharmony_ci goto out; 8928c2ecf20Sopenharmony_ci if (rep_pl->data_tag != 0x04) { 8938c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown reply data format\n", __func__); 8948c2ecf20Sopenharmony_ci rc = -EIO; 8958c2ecf20Sopenharmony_ci goto out; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci p = ((u8 *) rep_pl) + sizeof(*rep_pl); 8988c2ecf20Sopenharmony_ci if (rep_pl->data_lenfmt <= 127) 8998c2ecf20Sopenharmony_ci n = rep_pl->data_lenfmt; 9008c2ecf20Sopenharmony_ci else if (rep_pl->data_lenfmt == 0x81) 9018c2ecf20Sopenharmony_ci n = *p++; 9028c2ecf20Sopenharmony_ci else if (rep_pl->data_lenfmt == 0x82) { 9038c2ecf20Sopenharmony_ci n = *((u16 *) p); 9048c2ecf20Sopenharmony_ci p += 2; 9058c2ecf20Sopenharmony_ci } else { 9068c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown reply data length format 0x%02hhx\n", 9078c2ecf20Sopenharmony_ci __func__, rep_pl->data_lenfmt); 9088c2ecf20Sopenharmony_ci rc = -EIO; 9098c2ecf20Sopenharmony_ci goto out; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci if (n > *outbufsize) { 9128c2ecf20Sopenharmony_ci DEBUG_ERR("%s mismatch reply data len %d / output buffer %zu\n", 9138c2ecf20Sopenharmony_ci __func__, n, *outbufsize); 9148c2ecf20Sopenharmony_ci rc = -ENOSPC; 9158c2ecf20Sopenharmony_ci goto out; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci memcpy(outbuf, p, n); 9198c2ecf20Sopenharmony_ci *outbufsize = n; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ciout: 9228c2ecf20Sopenharmony_ci kfree(req); 9238c2ecf20Sopenharmony_ci kfree(rep); 9248c2ecf20Sopenharmony_ci kfree(urb); 9258c2ecf20Sopenharmony_ci return rc; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic int ep11_unwrapkey(u16 card, u16 domain, 9298c2ecf20Sopenharmony_ci const u8 *kek, size_t keksize, 9308c2ecf20Sopenharmony_ci const u8 *enckey, size_t enckeysize, 9318c2ecf20Sopenharmony_ci u32 mech, const u8 *iv, 9328c2ecf20Sopenharmony_ci u32 keybitsize, u32 keygenflags, 9338c2ecf20Sopenharmony_ci u8 *keybuf, size_t *keybufsize) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci struct uw_req_pl { 9368c2ecf20Sopenharmony_ci struct pl_head head; 9378c2ecf20Sopenharmony_ci u8 attr_tag; 9388c2ecf20Sopenharmony_ci u8 attr_len; 9398c2ecf20Sopenharmony_ci u32 attr_header; 9408c2ecf20Sopenharmony_ci u32 attr_bool_mask; 9418c2ecf20Sopenharmony_ci u32 attr_bool_bits; 9428c2ecf20Sopenharmony_ci u32 attr_key_type; 9438c2ecf20Sopenharmony_ci u32 attr_key_type_value; 9448c2ecf20Sopenharmony_ci u32 attr_val_len; 9458c2ecf20Sopenharmony_ci u32 attr_val_len_value; 9468c2ecf20Sopenharmony_ci u8 mech_tag; 9478c2ecf20Sopenharmony_ci u8 mech_len; 9488c2ecf20Sopenharmony_ci u32 mech; 9498c2ecf20Sopenharmony_ci /* 9508c2ecf20Sopenharmony_ci * maybe followed by iv data 9518c2ecf20Sopenharmony_ci * followed by kek tag + kek blob 9528c2ecf20Sopenharmony_ci * followed by empty mac tag 9538c2ecf20Sopenharmony_ci * followed by empty pin tag 9548c2ecf20Sopenharmony_ci * followed by encryted key tag + bytes 9558c2ecf20Sopenharmony_ci */ 9568c2ecf20Sopenharmony_ci } __packed * req_pl; 9578c2ecf20Sopenharmony_ci struct uw_rep_pl { 9588c2ecf20Sopenharmony_ci struct pl_head head; 9598c2ecf20Sopenharmony_ci u8 rc_tag; 9608c2ecf20Sopenharmony_ci u8 rc_len; 9618c2ecf20Sopenharmony_ci u32 rc; 9628c2ecf20Sopenharmony_ci u8 data_tag; 9638c2ecf20Sopenharmony_ci u8 data_lenfmt; 9648c2ecf20Sopenharmony_ci u16 data_len; 9658c2ecf20Sopenharmony_ci u8 data[512]; 9668c2ecf20Sopenharmony_ci } __packed * rep_pl; 9678c2ecf20Sopenharmony_ci struct ep11_cprb *req = NULL, *rep = NULL; 9688c2ecf20Sopenharmony_ci struct ep11_target_dev target; 9698c2ecf20Sopenharmony_ci struct ep11_urb *urb = NULL; 9708c2ecf20Sopenharmony_ci struct ep11keyblob *kb; 9718c2ecf20Sopenharmony_ci size_t req_pl_size; 9728c2ecf20Sopenharmony_ci int api, rc = -ENOMEM; 9738c2ecf20Sopenharmony_ci u8 *p; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* request cprb and payload */ 9768c2ecf20Sopenharmony_ci req_pl_size = sizeof(struct uw_req_pl) + (iv ? 16 : 0) 9778c2ecf20Sopenharmony_ci + ASN1TAGLEN(keksize) + 4 + ASN1TAGLEN(enckeysize); 9788c2ecf20Sopenharmony_ci req = alloc_cprb(req_pl_size); 9798c2ecf20Sopenharmony_ci if (!req) 9808c2ecf20Sopenharmony_ci goto out; 9818c2ecf20Sopenharmony_ci req_pl = (struct uw_req_pl *) (((u8 *) req) + sizeof(*req)); 9828c2ecf20Sopenharmony_ci api = (!keygenflags || keygenflags & 0x00200000) ? 4 : 1; 9838c2ecf20Sopenharmony_ci prep_head(&req_pl->head, req_pl_size, api, 34); /* UnwrapKey */ 9848c2ecf20Sopenharmony_ci req_pl->attr_tag = 0x04; 9858c2ecf20Sopenharmony_ci req_pl->attr_len = 7 * sizeof(u32); 9868c2ecf20Sopenharmony_ci req_pl->attr_header = 0x10020000; 9878c2ecf20Sopenharmony_ci req_pl->attr_bool_mask = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS; 9888c2ecf20Sopenharmony_ci req_pl->attr_bool_bits = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS; 9898c2ecf20Sopenharmony_ci req_pl->attr_key_type = 0x00000100; /* CKA_KEY_TYPE */ 9908c2ecf20Sopenharmony_ci req_pl->attr_key_type_value = 0x0000001f; /* CKK_AES */ 9918c2ecf20Sopenharmony_ci req_pl->attr_val_len = 0x00000161; /* CKA_VALUE_LEN */ 9928c2ecf20Sopenharmony_ci req_pl->attr_val_len_value = keybitsize / 8; 9938c2ecf20Sopenharmony_ci /* mech is mech + mech params (iv here) */ 9948c2ecf20Sopenharmony_ci req_pl->mech_tag = 0x04; 9958c2ecf20Sopenharmony_ci req_pl->mech_len = sizeof(u32) + (iv ? 16 : 0); 9968c2ecf20Sopenharmony_ci req_pl->mech = (mech ? mech : 0x00001085); /* CKM_AES_CBC_PAD */ 9978c2ecf20Sopenharmony_ci p = ((u8 *) req_pl) + sizeof(*req_pl); 9988c2ecf20Sopenharmony_ci if (iv) { 9998c2ecf20Sopenharmony_ci memcpy(p, iv, 16); 10008c2ecf20Sopenharmony_ci p += 16; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci /* kek */ 10038c2ecf20Sopenharmony_ci p += asn1tag_write(p, 0x04, kek, keksize); 10048c2ecf20Sopenharmony_ci /* empty mac key tag */ 10058c2ecf20Sopenharmony_ci *p++ = 0x04; 10068c2ecf20Sopenharmony_ci *p++ = 0; 10078c2ecf20Sopenharmony_ci /* empty pin tag */ 10088c2ecf20Sopenharmony_ci *p++ = 0x04; 10098c2ecf20Sopenharmony_ci *p++ = 0; 10108c2ecf20Sopenharmony_ci /* encrypted key value tag and bytes */ 10118c2ecf20Sopenharmony_ci p += asn1tag_write(p, 0x04, enckey, enckeysize); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* reply cprb and payload */ 10148c2ecf20Sopenharmony_ci rep = alloc_cprb(sizeof(struct uw_rep_pl)); 10158c2ecf20Sopenharmony_ci if (!rep) 10168c2ecf20Sopenharmony_ci goto out; 10178c2ecf20Sopenharmony_ci rep_pl = (struct uw_rep_pl *) (((u8 *) rep) + sizeof(*rep)); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* urb and target */ 10208c2ecf20Sopenharmony_ci urb = kmalloc(sizeof(struct ep11_urb), GFP_KERNEL); 10218c2ecf20Sopenharmony_ci if (!urb) 10228c2ecf20Sopenharmony_ci goto out; 10238c2ecf20Sopenharmony_ci target.ap_id = card; 10248c2ecf20Sopenharmony_ci target.dom_id = domain; 10258c2ecf20Sopenharmony_ci prep_urb(urb, &target, 1, 10268c2ecf20Sopenharmony_ci req, sizeof(*req) + req_pl_size, 10278c2ecf20Sopenharmony_ci rep, sizeof(*rep) + sizeof(*rep_pl)); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci rc = zcrypt_send_ep11_cprb(urb); 10308c2ecf20Sopenharmony_ci if (rc) { 10318c2ecf20Sopenharmony_ci DEBUG_ERR( 10328c2ecf20Sopenharmony_ci "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n", 10338c2ecf20Sopenharmony_ci __func__, (int) card, (int) domain, rc); 10348c2ecf20Sopenharmony_ci goto out; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci rc = check_reply_pl((u8 *)rep_pl, __func__); 10388c2ecf20Sopenharmony_ci if (rc) 10398c2ecf20Sopenharmony_ci goto out; 10408c2ecf20Sopenharmony_ci if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) { 10418c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown reply data format\n", __func__); 10428c2ecf20Sopenharmony_ci rc = -EIO; 10438c2ecf20Sopenharmony_ci goto out; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci if (rep_pl->data_len > *keybufsize) { 10468c2ecf20Sopenharmony_ci DEBUG_ERR("%s mismatch reply data len / key buffer len\n", 10478c2ecf20Sopenharmony_ci __func__); 10488c2ecf20Sopenharmony_ci rc = -ENOSPC; 10498c2ecf20Sopenharmony_ci goto out; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* copy key blob and set header values */ 10538c2ecf20Sopenharmony_ci memcpy(keybuf, rep_pl->data, rep_pl->data_len); 10548c2ecf20Sopenharmony_ci *keybufsize = rep_pl->data_len; 10558c2ecf20Sopenharmony_ci kb = (struct ep11keyblob *) keybuf; 10568c2ecf20Sopenharmony_ci kb->head.type = TOKTYPE_NON_CCA; 10578c2ecf20Sopenharmony_ci kb->head.len = rep_pl->data_len; 10588c2ecf20Sopenharmony_ci kb->head.version = TOKVER_EP11_AES; 10598c2ecf20Sopenharmony_ci kb->head.bitlen = keybitsize; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ciout: 10628c2ecf20Sopenharmony_ci kfree(req); 10638c2ecf20Sopenharmony_ci kfree(rep); 10648c2ecf20Sopenharmony_ci kfree(urb); 10658c2ecf20Sopenharmony_ci return rc; 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic int ep11_wrapkey(u16 card, u16 domain, 10698c2ecf20Sopenharmony_ci const u8 *key, size_t keysize, 10708c2ecf20Sopenharmony_ci u32 mech, const u8 *iv, 10718c2ecf20Sopenharmony_ci u8 *databuf, size_t *datasize) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct wk_req_pl { 10748c2ecf20Sopenharmony_ci struct pl_head head; 10758c2ecf20Sopenharmony_ci u8 var_tag; 10768c2ecf20Sopenharmony_ci u8 var_len; 10778c2ecf20Sopenharmony_ci u32 var; 10788c2ecf20Sopenharmony_ci u8 mech_tag; 10798c2ecf20Sopenharmony_ci u8 mech_len; 10808c2ecf20Sopenharmony_ci u32 mech; 10818c2ecf20Sopenharmony_ci /* 10828c2ecf20Sopenharmony_ci * followed by iv data 10838c2ecf20Sopenharmony_ci * followed by key tag + key blob 10848c2ecf20Sopenharmony_ci * followed by dummy kek param 10858c2ecf20Sopenharmony_ci * followed by dummy mac param 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_ci } __packed * req_pl; 10888c2ecf20Sopenharmony_ci struct wk_rep_pl { 10898c2ecf20Sopenharmony_ci struct pl_head head; 10908c2ecf20Sopenharmony_ci u8 rc_tag; 10918c2ecf20Sopenharmony_ci u8 rc_len; 10928c2ecf20Sopenharmony_ci u32 rc; 10938c2ecf20Sopenharmony_ci u8 data_tag; 10948c2ecf20Sopenharmony_ci u8 data_lenfmt; 10958c2ecf20Sopenharmony_ci u16 data_len; 10968c2ecf20Sopenharmony_ci u8 data[1024]; 10978c2ecf20Sopenharmony_ci } __packed * rep_pl; 10988c2ecf20Sopenharmony_ci struct ep11_cprb *req = NULL, *rep = NULL; 10998c2ecf20Sopenharmony_ci struct ep11_target_dev target; 11008c2ecf20Sopenharmony_ci struct ep11_urb *urb = NULL; 11018c2ecf20Sopenharmony_ci struct ep11keyblob *kb; 11028c2ecf20Sopenharmony_ci size_t req_pl_size; 11038c2ecf20Sopenharmony_ci int api, rc = -ENOMEM; 11048c2ecf20Sopenharmony_ci bool has_header = false; 11058c2ecf20Sopenharmony_ci u8 *p; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* maybe the session field holds a header with key info */ 11088c2ecf20Sopenharmony_ci kb = (struct ep11keyblob *) key; 11098c2ecf20Sopenharmony_ci if (kb->head.type == TOKTYPE_NON_CCA && 11108c2ecf20Sopenharmony_ci kb->head.version == TOKVER_EP11_AES) { 11118c2ecf20Sopenharmony_ci has_header = true; 11128c2ecf20Sopenharmony_ci keysize = kb->head.len < keysize ? kb->head.len : keysize; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* request cprb and payload */ 11168c2ecf20Sopenharmony_ci req_pl_size = sizeof(struct wk_req_pl) + (iv ? 16 : 0) 11178c2ecf20Sopenharmony_ci + ASN1TAGLEN(keysize) + 4; 11188c2ecf20Sopenharmony_ci req = alloc_cprb(req_pl_size); 11198c2ecf20Sopenharmony_ci if (!req) 11208c2ecf20Sopenharmony_ci goto out; 11218c2ecf20Sopenharmony_ci if (!mech || mech == 0x80060001) 11228c2ecf20Sopenharmony_ci req->flags |= 0x20; /* CPACF_WRAP needs special bit */ 11238c2ecf20Sopenharmony_ci req_pl = (struct wk_req_pl *) (((u8 *) req) + sizeof(*req)); 11248c2ecf20Sopenharmony_ci api = (!mech || mech == 0x80060001) ? 4 : 1; /* CKM_IBM_CPACF_WRAP */ 11258c2ecf20Sopenharmony_ci prep_head(&req_pl->head, req_pl_size, api, 33); /* WrapKey */ 11268c2ecf20Sopenharmony_ci req_pl->var_tag = 0x04; 11278c2ecf20Sopenharmony_ci req_pl->var_len = sizeof(u32); 11288c2ecf20Sopenharmony_ci /* mech is mech + mech params (iv here) */ 11298c2ecf20Sopenharmony_ci req_pl->mech_tag = 0x04; 11308c2ecf20Sopenharmony_ci req_pl->mech_len = sizeof(u32) + (iv ? 16 : 0); 11318c2ecf20Sopenharmony_ci req_pl->mech = (mech ? mech : 0x80060001); /* CKM_IBM_CPACF_WRAP */ 11328c2ecf20Sopenharmony_ci p = ((u8 *) req_pl) + sizeof(*req_pl); 11338c2ecf20Sopenharmony_ci if (iv) { 11348c2ecf20Sopenharmony_ci memcpy(p, iv, 16); 11358c2ecf20Sopenharmony_ci p += 16; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci /* key blob */ 11388c2ecf20Sopenharmony_ci p += asn1tag_write(p, 0x04, key, keysize); 11398c2ecf20Sopenharmony_ci /* maybe the key argument needs the head data cleaned out */ 11408c2ecf20Sopenharmony_ci if (has_header) { 11418c2ecf20Sopenharmony_ci kb = (struct ep11keyblob *)(p - keysize); 11428c2ecf20Sopenharmony_ci memset(&kb->head, 0, sizeof(kb->head)); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci /* empty kek tag */ 11458c2ecf20Sopenharmony_ci *p++ = 0x04; 11468c2ecf20Sopenharmony_ci *p++ = 0; 11478c2ecf20Sopenharmony_ci /* empty mac tag */ 11488c2ecf20Sopenharmony_ci *p++ = 0x04; 11498c2ecf20Sopenharmony_ci *p++ = 0; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci /* reply cprb and payload */ 11528c2ecf20Sopenharmony_ci rep = alloc_cprb(sizeof(struct wk_rep_pl)); 11538c2ecf20Sopenharmony_ci if (!rep) 11548c2ecf20Sopenharmony_ci goto out; 11558c2ecf20Sopenharmony_ci rep_pl = (struct wk_rep_pl *) (((u8 *) rep) + sizeof(*rep)); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* urb and target */ 11588c2ecf20Sopenharmony_ci urb = kmalloc(sizeof(struct ep11_urb), GFP_KERNEL); 11598c2ecf20Sopenharmony_ci if (!urb) 11608c2ecf20Sopenharmony_ci goto out; 11618c2ecf20Sopenharmony_ci target.ap_id = card; 11628c2ecf20Sopenharmony_ci target.dom_id = domain; 11638c2ecf20Sopenharmony_ci prep_urb(urb, &target, 1, 11648c2ecf20Sopenharmony_ci req, sizeof(*req) + req_pl_size, 11658c2ecf20Sopenharmony_ci rep, sizeof(*rep) + sizeof(*rep_pl)); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci rc = zcrypt_send_ep11_cprb(urb); 11688c2ecf20Sopenharmony_ci if (rc) { 11698c2ecf20Sopenharmony_ci DEBUG_ERR( 11708c2ecf20Sopenharmony_ci "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n", 11718c2ecf20Sopenharmony_ci __func__, (int) card, (int) domain, rc); 11728c2ecf20Sopenharmony_ci goto out; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci rc = check_reply_pl((u8 *)rep_pl, __func__); 11768c2ecf20Sopenharmony_ci if (rc) 11778c2ecf20Sopenharmony_ci goto out; 11788c2ecf20Sopenharmony_ci if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) { 11798c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown reply data format\n", __func__); 11808c2ecf20Sopenharmony_ci rc = -EIO; 11818c2ecf20Sopenharmony_ci goto out; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci if (rep_pl->data_len > *datasize) { 11848c2ecf20Sopenharmony_ci DEBUG_ERR("%s mismatch reply data len / data buffer len\n", 11858c2ecf20Sopenharmony_ci __func__); 11868c2ecf20Sopenharmony_ci rc = -ENOSPC; 11878c2ecf20Sopenharmony_ci goto out; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* copy the data from the cprb to the data buffer */ 11918c2ecf20Sopenharmony_ci memcpy(databuf, rep_pl->data, rep_pl->data_len); 11928c2ecf20Sopenharmony_ci *datasize = rep_pl->data_len; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ciout: 11958c2ecf20Sopenharmony_ci kfree(req); 11968c2ecf20Sopenharmony_ci kfree(rep); 11978c2ecf20Sopenharmony_ci kfree(urb); 11988c2ecf20Sopenharmony_ci return rc; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ciint ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, 12028c2ecf20Sopenharmony_ci const u8 *clrkey, u8 *keybuf, size_t *keybufsize) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci int rc; 12058c2ecf20Sopenharmony_ci struct ep11keyblob *kb; 12068c2ecf20Sopenharmony_ci u8 encbuf[64], *kek = NULL; 12078c2ecf20Sopenharmony_ci size_t clrkeylen, keklen, encbuflen = sizeof(encbuf); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (keybitsize == 128 || keybitsize == 192 || keybitsize == 256) 12108c2ecf20Sopenharmony_ci clrkeylen = keybitsize / 8; 12118c2ecf20Sopenharmony_ci else { 12128c2ecf20Sopenharmony_ci DEBUG_ERR( 12138c2ecf20Sopenharmony_ci "%s unknown/unsupported keybitsize %d\n", 12148c2ecf20Sopenharmony_ci __func__, keybitsize); 12158c2ecf20Sopenharmony_ci return -EINVAL; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* allocate memory for the temp kek */ 12198c2ecf20Sopenharmony_ci keklen = MAXEP11AESKEYBLOBSIZE; 12208c2ecf20Sopenharmony_ci kek = kmalloc(keklen, GFP_ATOMIC); 12218c2ecf20Sopenharmony_ci if (!kek) { 12228c2ecf20Sopenharmony_ci rc = -ENOMEM; 12238c2ecf20Sopenharmony_ci goto out; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* Step 1: generate AES 256 bit random kek key */ 12278c2ecf20Sopenharmony_ci rc = ep11_genaeskey(card, domain, 256, 12288c2ecf20Sopenharmony_ci 0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */ 12298c2ecf20Sopenharmony_ci kek, &keklen); 12308c2ecf20Sopenharmony_ci if (rc) { 12318c2ecf20Sopenharmony_ci DEBUG_ERR( 12328c2ecf20Sopenharmony_ci "%s generate kek key failed, rc=%d\n", 12338c2ecf20Sopenharmony_ci __func__, rc); 12348c2ecf20Sopenharmony_ci goto out; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci kb = (struct ep11keyblob *) kek; 12378c2ecf20Sopenharmony_ci memset(&kb->head, 0, sizeof(kb->head)); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* Step 2: encrypt clear key value with the kek key */ 12408c2ecf20Sopenharmony_ci rc = ep11_cryptsingle(card, domain, 0, 0, def_iv, kek, keklen, 12418c2ecf20Sopenharmony_ci clrkey, clrkeylen, encbuf, &encbuflen); 12428c2ecf20Sopenharmony_ci if (rc) { 12438c2ecf20Sopenharmony_ci DEBUG_ERR( 12448c2ecf20Sopenharmony_ci "%s encrypting key value with kek key failed, rc=%d\n", 12458c2ecf20Sopenharmony_ci __func__, rc); 12468c2ecf20Sopenharmony_ci goto out; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* Step 3: import the encrypted key value as a new key */ 12508c2ecf20Sopenharmony_ci rc = ep11_unwrapkey(card, domain, kek, keklen, 12518c2ecf20Sopenharmony_ci encbuf, encbuflen, 0, def_iv, 12528c2ecf20Sopenharmony_ci keybitsize, 0, keybuf, keybufsize); 12538c2ecf20Sopenharmony_ci if (rc) { 12548c2ecf20Sopenharmony_ci DEBUG_ERR( 12558c2ecf20Sopenharmony_ci "%s importing key value as new key failed,, rc=%d\n", 12568c2ecf20Sopenharmony_ci __func__, rc); 12578c2ecf20Sopenharmony_ci goto out; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ciout: 12618c2ecf20Sopenharmony_ci kfree(kek); 12628c2ecf20Sopenharmony_ci return rc; 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_clr2keyblob); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ciint ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen, 12678c2ecf20Sopenharmony_ci u8 *protkey, u32 *protkeylen, u32 *protkeytype) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci int rc = -EIO; 12708c2ecf20Sopenharmony_ci u8 *wkbuf = NULL; 12718c2ecf20Sopenharmony_ci size_t wkbuflen, keylen; 12728c2ecf20Sopenharmony_ci struct wk_info { 12738c2ecf20Sopenharmony_ci u16 version; 12748c2ecf20Sopenharmony_ci u8 res1[16]; 12758c2ecf20Sopenharmony_ci u32 pkeytype; 12768c2ecf20Sopenharmony_ci u32 pkeybitsize; 12778c2ecf20Sopenharmony_ci u64 pkeysize; 12788c2ecf20Sopenharmony_ci u8 res2[8]; 12798c2ecf20Sopenharmony_ci u8 pkey[0]; 12808c2ecf20Sopenharmony_ci } __packed * wki; 12818c2ecf20Sopenharmony_ci const u8 *key; 12828c2ecf20Sopenharmony_ci struct ep11kblob_header *hdr; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci /* key with or without header ? */ 12858c2ecf20Sopenharmony_ci hdr = (struct ep11kblob_header *) keyblob; 12868c2ecf20Sopenharmony_ci if (hdr->type == TOKTYPE_NON_CCA 12878c2ecf20Sopenharmony_ci && (hdr->version == TOKVER_EP11_AES_WITH_HEADER 12888c2ecf20Sopenharmony_ci || hdr->version == TOKVER_EP11_ECC_WITH_HEADER) 12898c2ecf20Sopenharmony_ci && is_ep11_keyblob(keyblob + sizeof(struct ep11kblob_header))) { 12908c2ecf20Sopenharmony_ci /* EP11 AES or ECC key with header */ 12918c2ecf20Sopenharmony_ci key = keyblob + sizeof(struct ep11kblob_header); 12928c2ecf20Sopenharmony_ci keylen = hdr->len - sizeof(struct ep11kblob_header); 12938c2ecf20Sopenharmony_ci } else if (hdr->type == TOKTYPE_NON_CCA 12948c2ecf20Sopenharmony_ci && hdr->version == TOKVER_EP11_AES 12958c2ecf20Sopenharmony_ci && is_ep11_keyblob(keyblob)) { 12968c2ecf20Sopenharmony_ci /* EP11 AES key (old style) */ 12978c2ecf20Sopenharmony_ci key = keyblob; 12988c2ecf20Sopenharmony_ci keylen = hdr->len; 12998c2ecf20Sopenharmony_ci } else if (is_ep11_keyblob(keyblob)) { 13008c2ecf20Sopenharmony_ci /* raw EP11 key blob */ 13018c2ecf20Sopenharmony_ci key = keyblob; 13028c2ecf20Sopenharmony_ci keylen = keybloblen; 13038c2ecf20Sopenharmony_ci } else 13048c2ecf20Sopenharmony_ci return -EINVAL; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* alloc temp working buffer */ 13078c2ecf20Sopenharmony_ci wkbuflen = (keylen + AES_BLOCK_SIZE) & (~(AES_BLOCK_SIZE - 1)); 13088c2ecf20Sopenharmony_ci wkbuf = kmalloc(wkbuflen, GFP_ATOMIC); 13098c2ecf20Sopenharmony_ci if (!wkbuf) 13108c2ecf20Sopenharmony_ci return -ENOMEM; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* ep11 secure key -> protected key + info */ 13138c2ecf20Sopenharmony_ci rc = ep11_wrapkey(card, dom, key, keylen, 13148c2ecf20Sopenharmony_ci 0, def_iv, wkbuf, &wkbuflen); 13158c2ecf20Sopenharmony_ci if (rc) { 13168c2ecf20Sopenharmony_ci DEBUG_ERR( 13178c2ecf20Sopenharmony_ci "%s rewrapping ep11 key to pkey failed, rc=%d\n", 13188c2ecf20Sopenharmony_ci __func__, rc); 13198c2ecf20Sopenharmony_ci goto out; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci wki = (struct wk_info *) wkbuf; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* check struct version and pkey type */ 13248c2ecf20Sopenharmony_ci if (wki->version != 1 || wki->pkeytype < 1 || wki->pkeytype > 5) { 13258c2ecf20Sopenharmony_ci DEBUG_ERR("%s wk info version %d or pkeytype %d mismatch.\n", 13268c2ecf20Sopenharmony_ci __func__, (int) wki->version, (int) wki->pkeytype); 13278c2ecf20Sopenharmony_ci rc = -EIO; 13288c2ecf20Sopenharmony_ci goto out; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* check protected key type field */ 13328c2ecf20Sopenharmony_ci switch (wki->pkeytype) { 13338c2ecf20Sopenharmony_ci case 1: /* AES */ 13348c2ecf20Sopenharmony_ci switch (wki->pkeysize) { 13358c2ecf20Sopenharmony_ci case 16+32: 13368c2ecf20Sopenharmony_ci /* AES 128 protected key */ 13378c2ecf20Sopenharmony_ci if (protkeytype) 13388c2ecf20Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_128; 13398c2ecf20Sopenharmony_ci break; 13408c2ecf20Sopenharmony_ci case 24+32: 13418c2ecf20Sopenharmony_ci /* AES 192 protected key */ 13428c2ecf20Sopenharmony_ci if (protkeytype) 13438c2ecf20Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_192; 13448c2ecf20Sopenharmony_ci break; 13458c2ecf20Sopenharmony_ci case 32+32: 13468c2ecf20Sopenharmony_ci /* AES 256 protected key */ 13478c2ecf20Sopenharmony_ci if (protkeytype) 13488c2ecf20Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_256; 13498c2ecf20Sopenharmony_ci break; 13508c2ecf20Sopenharmony_ci default: 13518c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown/unsupported AES pkeysize %d\n", 13528c2ecf20Sopenharmony_ci __func__, (int) wki->pkeysize); 13538c2ecf20Sopenharmony_ci rc = -EIO; 13548c2ecf20Sopenharmony_ci goto out; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci break; 13578c2ecf20Sopenharmony_ci case 3: /* EC-P */ 13588c2ecf20Sopenharmony_ci case 4: /* EC-ED */ 13598c2ecf20Sopenharmony_ci case 5: /* EC-BP */ 13608c2ecf20Sopenharmony_ci if (protkeytype) 13618c2ecf20Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_ECC; 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci case 2: /* TDES */ 13648c2ecf20Sopenharmony_ci default: 13658c2ecf20Sopenharmony_ci DEBUG_ERR("%s unknown/unsupported key type %d\n", 13668c2ecf20Sopenharmony_ci __func__, (int) wki->pkeytype); 13678c2ecf20Sopenharmony_ci rc = -EIO; 13688c2ecf20Sopenharmony_ci goto out; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci /* copy the tanslated protected key */ 13728c2ecf20Sopenharmony_ci if (wki->pkeysize > *protkeylen) { 13738c2ecf20Sopenharmony_ci DEBUG_ERR("%s wk info pkeysize %llu > protkeysize %u\n", 13748c2ecf20Sopenharmony_ci __func__, wki->pkeysize, *protkeylen); 13758c2ecf20Sopenharmony_ci rc = -EINVAL; 13768c2ecf20Sopenharmony_ci goto out; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci memcpy(protkey, wki->pkey, wki->pkeysize); 13798c2ecf20Sopenharmony_ci *protkeylen = wki->pkeysize; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ciout: 13828c2ecf20Sopenharmony_ci kfree(wkbuf); 13838c2ecf20Sopenharmony_ci return rc; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_kblob2protkey); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ciint ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, 13888c2ecf20Sopenharmony_ci int minhwtype, int minapi, const u8 *wkvp) 13898c2ecf20Sopenharmony_ci{ 13908c2ecf20Sopenharmony_ci struct zcrypt_device_status_ext *device_status; 13918c2ecf20Sopenharmony_ci u32 *_apqns = NULL, _nr_apqns = 0; 13928c2ecf20Sopenharmony_ci int i, card, dom, rc = -ENOMEM; 13938c2ecf20Sopenharmony_ci struct ep11_domain_info edi; 13948c2ecf20Sopenharmony_ci struct ep11_card_info eci; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* fetch status of all crypto cards */ 13978c2ecf20Sopenharmony_ci device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT, 13988c2ecf20Sopenharmony_ci sizeof(struct zcrypt_device_status_ext), 13998c2ecf20Sopenharmony_ci GFP_KERNEL); 14008c2ecf20Sopenharmony_ci if (!device_status) 14018c2ecf20Sopenharmony_ci return -ENOMEM; 14028c2ecf20Sopenharmony_ci zcrypt_device_status_mask_ext(device_status); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* allocate 1k space for up to 256 apqns */ 14058c2ecf20Sopenharmony_ci _apqns = kmalloc_array(256, sizeof(u32), GFP_KERNEL); 14068c2ecf20Sopenharmony_ci if (!_apqns) { 14078c2ecf20Sopenharmony_ci kvfree(device_status); 14088c2ecf20Sopenharmony_ci return -ENOMEM; 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci /* walk through all the crypto apqnss */ 14128c2ecf20Sopenharmony_ci for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { 14138c2ecf20Sopenharmony_ci card = AP_QID_CARD(device_status[i].qid); 14148c2ecf20Sopenharmony_ci dom = AP_QID_QUEUE(device_status[i].qid); 14158c2ecf20Sopenharmony_ci /* check online state */ 14168c2ecf20Sopenharmony_ci if (!device_status[i].online) 14178c2ecf20Sopenharmony_ci continue; 14188c2ecf20Sopenharmony_ci /* check for ep11 functions */ 14198c2ecf20Sopenharmony_ci if (!(device_status[i].functions & 0x01)) 14208c2ecf20Sopenharmony_ci continue; 14218c2ecf20Sopenharmony_ci /* check cardnr */ 14228c2ecf20Sopenharmony_ci if (cardnr != 0xFFFF && card != cardnr) 14238c2ecf20Sopenharmony_ci continue; 14248c2ecf20Sopenharmony_ci /* check domain */ 14258c2ecf20Sopenharmony_ci if (domain != 0xFFFF && dom != domain) 14268c2ecf20Sopenharmony_ci continue; 14278c2ecf20Sopenharmony_ci /* check min hardware type */ 14288c2ecf20Sopenharmony_ci if (minhwtype && device_status[i].hwtype < minhwtype) 14298c2ecf20Sopenharmony_ci continue; 14308c2ecf20Sopenharmony_ci /* check min api version if given */ 14318c2ecf20Sopenharmony_ci if (minapi > 0) { 14328c2ecf20Sopenharmony_ci if (ep11_get_card_info(card, &eci, 0)) 14338c2ecf20Sopenharmony_ci continue; 14348c2ecf20Sopenharmony_ci if (minapi > eci.API_ord_nr) 14358c2ecf20Sopenharmony_ci continue; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci /* check wkvp if given */ 14388c2ecf20Sopenharmony_ci if (wkvp) { 14398c2ecf20Sopenharmony_ci if (ep11_get_domain_info(card, dom, &edi)) 14408c2ecf20Sopenharmony_ci continue; 14418c2ecf20Sopenharmony_ci if (edi.cur_wk_state != '1') 14428c2ecf20Sopenharmony_ci continue; 14438c2ecf20Sopenharmony_ci if (memcmp(wkvp, edi.cur_wkvp, 16)) 14448c2ecf20Sopenharmony_ci continue; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci /* apqn passed all filtering criterons, add to the array */ 14478c2ecf20Sopenharmony_ci if (_nr_apqns < 256) 14488c2ecf20Sopenharmony_ci _apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16) dom); 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* nothing found ? */ 14528c2ecf20Sopenharmony_ci if (!_nr_apqns) { 14538c2ecf20Sopenharmony_ci kfree(_apqns); 14548c2ecf20Sopenharmony_ci rc = -ENODEV; 14558c2ecf20Sopenharmony_ci } else { 14568c2ecf20Sopenharmony_ci /* no re-allocation, simple return the _apqns array */ 14578c2ecf20Sopenharmony_ci *apqns = _apqns; 14588c2ecf20Sopenharmony_ci *nr_apqns = _nr_apqns; 14598c2ecf20Sopenharmony_ci rc = 0; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci kvfree(device_status); 14638c2ecf20Sopenharmony_ci return rc; 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ep11_findcard2); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_civoid __exit zcrypt_ep11misc_exit(void) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci card_cache_free(); 14708c2ecf20Sopenharmony_ci} 1471