162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright IBM Corp. 2019 462306a36Sopenharmony_ci * Author(s): Harald Freudenberger <freude@linux.ibm.com> 562306a36Sopenharmony_ci * Ingo Franzki <ifranzki@linux.ibm.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Collection of CCA misc functions used by zcrypt and pkey 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define KMSG_COMPONENT "zcrypt" 1162306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/random.h> 1762306a36Sopenharmony_ci#include <asm/zcrypt.h> 1862306a36Sopenharmony_ci#include <asm/pkey.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "ap_bus.h" 2162306a36Sopenharmony_ci#include "zcrypt_api.h" 2262306a36Sopenharmony_ci#include "zcrypt_debug.h" 2362306a36Sopenharmony_ci#include "zcrypt_msgtype6.h" 2462306a36Sopenharmony_ci#include "zcrypt_ccamisc.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define DEBUG_DBG(...) ZCRYPT_DBF(DBF_DEBUG, ##__VA_ARGS__) 2762306a36Sopenharmony_ci#define DEBUG_INFO(...) ZCRYPT_DBF(DBF_INFO, ##__VA_ARGS__) 2862306a36Sopenharmony_ci#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__) 2962306a36Sopenharmony_ci#define DEBUG_ERR(...) ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Size of parameter block used for all cca requests/replies */ 3262306a36Sopenharmony_ci#define PARMBSIZE 512 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Size of vardata block used for some of the cca requests/replies */ 3562306a36Sopenharmony_ci#define VARDATASIZE 4096 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct cca_info_list_entry { 3862306a36Sopenharmony_ci struct list_head list; 3962306a36Sopenharmony_ci u16 cardnr; 4062306a36Sopenharmony_ci u16 domain; 4162306a36Sopenharmony_ci struct cca_info info; 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* a list with cca_info_list_entry entries */ 4562306a36Sopenharmony_cistatic LIST_HEAD(cca_info_list); 4662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(cca_info_list_lock); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * Simple check if the token is a valid CCA secure AES data key 5062306a36Sopenharmony_ci * token. If keybitsize is given, the bitsize of the key is 5162306a36Sopenharmony_ci * also checked. Returns 0 on success or errno value on failure. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ciint cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, 5462306a36Sopenharmony_ci const u8 *token, int keybitsize) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct secaeskeytoken *t = (struct secaeskeytoken *)token; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (t->type != TOKTYPE_CCA_INTERNAL) { 6162306a36Sopenharmony_ci if (dbg) 6262306a36Sopenharmony_ci DBF("%s token check failed, type 0x%02x != 0x%02x\n", 6362306a36Sopenharmony_ci __func__, (int)t->type, TOKTYPE_CCA_INTERNAL); 6462306a36Sopenharmony_ci return -EINVAL; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci if (t->version != TOKVER_CCA_AES) { 6762306a36Sopenharmony_ci if (dbg) 6862306a36Sopenharmony_ci DBF("%s token check failed, version 0x%02x != 0x%02x\n", 6962306a36Sopenharmony_ci __func__, (int)t->version, TOKVER_CCA_AES); 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci if (keybitsize > 0 && t->bitsize != keybitsize) { 7362306a36Sopenharmony_ci if (dbg) 7462306a36Sopenharmony_ci DBF("%s token check failed, bitsize %d != %d\n", 7562306a36Sopenharmony_ci __func__, (int)t->bitsize, keybitsize); 7662306a36Sopenharmony_ci return -EINVAL; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#undef DBF 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ciEXPORT_SYMBOL(cca_check_secaeskeytoken); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Simple check if the token is a valid CCA secure AES cipher key 8762306a36Sopenharmony_ci * token. If keybitsize is given, the bitsize of the key is 8862306a36Sopenharmony_ci * also checked. If checkcpacfexport is enabled, the key is also 8962306a36Sopenharmony_ci * checked for the export flag to allow CPACF export. 9062306a36Sopenharmony_ci * Returns 0 on success or errno value on failure. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ciint cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, 9362306a36Sopenharmony_ci const u8 *token, int keybitsize, 9462306a36Sopenharmony_ci int checkcpacfexport) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct cipherkeytoken *t = (struct cipherkeytoken *)token; 9762306a36Sopenharmony_ci bool keybitsizeok = true; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (t->type != TOKTYPE_CCA_INTERNAL) { 10262306a36Sopenharmony_ci if (dbg) 10362306a36Sopenharmony_ci DBF("%s token check failed, type 0x%02x != 0x%02x\n", 10462306a36Sopenharmony_ci __func__, (int)t->type, TOKTYPE_CCA_INTERNAL); 10562306a36Sopenharmony_ci return -EINVAL; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci if (t->version != TOKVER_CCA_VLSC) { 10862306a36Sopenharmony_ci if (dbg) 10962306a36Sopenharmony_ci DBF("%s token check failed, version 0x%02x != 0x%02x\n", 11062306a36Sopenharmony_ci __func__, (int)t->version, TOKVER_CCA_VLSC); 11162306a36Sopenharmony_ci return -EINVAL; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci if (t->algtype != 0x02) { 11462306a36Sopenharmony_ci if (dbg) 11562306a36Sopenharmony_ci DBF("%s token check failed, algtype 0x%02x != 0x02\n", 11662306a36Sopenharmony_ci __func__, (int)t->algtype); 11762306a36Sopenharmony_ci return -EINVAL; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci if (t->keytype != 0x0001) { 12062306a36Sopenharmony_ci if (dbg) 12162306a36Sopenharmony_ci DBF("%s token check failed, keytype 0x%04x != 0x0001\n", 12262306a36Sopenharmony_ci __func__, (int)t->keytype); 12362306a36Sopenharmony_ci return -EINVAL; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci if (t->plfver != 0x00 && t->plfver != 0x01) { 12662306a36Sopenharmony_ci if (dbg) 12762306a36Sopenharmony_ci DBF("%s token check failed, unknown plfver 0x%02x\n", 12862306a36Sopenharmony_ci __func__, (int)t->plfver); 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci if (t->wpllen != 512 && t->wpllen != 576 && t->wpllen != 640) { 13262306a36Sopenharmony_ci if (dbg) 13362306a36Sopenharmony_ci DBF("%s token check failed, unknown wpllen %d\n", 13462306a36Sopenharmony_ci __func__, (int)t->wpllen); 13562306a36Sopenharmony_ci return -EINVAL; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci if (keybitsize > 0) { 13862306a36Sopenharmony_ci switch (keybitsize) { 13962306a36Sopenharmony_ci case 128: 14062306a36Sopenharmony_ci if (t->wpllen != (t->plfver ? 640 : 512)) 14162306a36Sopenharmony_ci keybitsizeok = false; 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case 192: 14462306a36Sopenharmony_ci if (t->wpllen != (t->plfver ? 640 : 576)) 14562306a36Sopenharmony_ci keybitsizeok = false; 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci case 256: 14862306a36Sopenharmony_ci if (t->wpllen != 640) 14962306a36Sopenharmony_ci keybitsizeok = false; 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci default: 15262306a36Sopenharmony_ci keybitsizeok = false; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci if (!keybitsizeok) { 15662306a36Sopenharmony_ci if (dbg) 15762306a36Sopenharmony_ci DBF("%s token check failed, bitsize %d\n", 15862306a36Sopenharmony_ci __func__, keybitsize); 15962306a36Sopenharmony_ci return -EINVAL; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci if (checkcpacfexport && !(t->kmf1 & KMF1_XPRT_CPAC)) { 16362306a36Sopenharmony_ci if (dbg) 16462306a36Sopenharmony_ci DBF("%s token check failed, XPRT_CPAC bit is 0\n", 16562306a36Sopenharmony_ci __func__); 16662306a36Sopenharmony_ci return -EINVAL; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#undef DBF 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ciEXPORT_SYMBOL(cca_check_secaescipherkey); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * Simple check if the token is a valid CCA secure ECC private 17762306a36Sopenharmony_ci * key token. Returns 0 on success or errno value on failure. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ciint cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl, 18062306a36Sopenharmony_ci const u8 *token, size_t keysize, 18162306a36Sopenharmony_ci int checkcpacfexport) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct eccprivkeytoken *t = (struct eccprivkeytoken *)token; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (t->type != TOKTYPE_CCA_INTERNAL_PKA) { 18862306a36Sopenharmony_ci if (dbg) 18962306a36Sopenharmony_ci DBF("%s token check failed, type 0x%02x != 0x%02x\n", 19062306a36Sopenharmony_ci __func__, (int)t->type, TOKTYPE_CCA_INTERNAL_PKA); 19162306a36Sopenharmony_ci return -EINVAL; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci if (t->len > keysize) { 19462306a36Sopenharmony_ci if (dbg) 19562306a36Sopenharmony_ci DBF("%s token check failed, len %d > keysize %zu\n", 19662306a36Sopenharmony_ci __func__, (int)t->len, keysize); 19762306a36Sopenharmony_ci return -EINVAL; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci if (t->secid != 0x20) { 20062306a36Sopenharmony_ci if (dbg) 20162306a36Sopenharmony_ci DBF("%s token check failed, secid 0x%02x != 0x20\n", 20262306a36Sopenharmony_ci __func__, (int)t->secid); 20362306a36Sopenharmony_ci return -EINVAL; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci if (checkcpacfexport && !(t->kutc & 0x01)) { 20662306a36Sopenharmony_ci if (dbg) 20762306a36Sopenharmony_ci DBF("%s token check failed, XPRTCPAC bit is 0\n", 20862306a36Sopenharmony_ci __func__); 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#undef DBF 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ciEXPORT_SYMBOL(cca_check_sececckeytoken); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* 21962306a36Sopenharmony_ci * Allocate consecutive memory for request CPRB, request param 22062306a36Sopenharmony_ci * block, reply CPRB and reply param block and fill in values 22162306a36Sopenharmony_ci * for the common fields. Returns 0 on success or errno value 22262306a36Sopenharmony_ci * on failure. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic int alloc_and_prep_cprbmem(size_t paramblen, 22562306a36Sopenharmony_ci u8 **p_cprb_mem, 22662306a36Sopenharmony_ci struct CPRBX **p_req_cprb, 22762306a36Sopenharmony_ci struct CPRBX **p_rep_cprb) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci u8 *cprbmem; 23062306a36Sopenharmony_ci size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen; 23162306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci * allocate consecutive memory for request CPRB, request param 23562306a36Sopenharmony_ci * block, reply CPRB and reply param block 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL); 23862306a36Sopenharmony_ci if (!cprbmem) 23962306a36Sopenharmony_ci return -ENOMEM; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci preqcblk = (struct CPRBX *)cprbmem; 24262306a36Sopenharmony_ci prepcblk = (struct CPRBX *)(cprbmem + cprbplusparamblen); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* fill request cprb struct */ 24562306a36Sopenharmony_ci preqcblk->cprb_len = sizeof(struct CPRBX); 24662306a36Sopenharmony_ci preqcblk->cprb_ver_id = 0x02; 24762306a36Sopenharmony_ci memcpy(preqcblk->func_id, "T2", 2); 24862306a36Sopenharmony_ci preqcblk->rpl_msgbl = cprbplusparamblen; 24962306a36Sopenharmony_ci if (paramblen) { 25062306a36Sopenharmony_ci preqcblk->req_parmb = 25162306a36Sopenharmony_ci ((u8 __user *)preqcblk) + sizeof(struct CPRBX); 25262306a36Sopenharmony_ci preqcblk->rpl_parmb = 25362306a36Sopenharmony_ci ((u8 __user *)prepcblk) + sizeof(struct CPRBX); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci *p_cprb_mem = cprbmem; 25762306a36Sopenharmony_ci *p_req_cprb = preqcblk; 25862306a36Sopenharmony_ci *p_rep_cprb = prepcblk; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* 26462306a36Sopenharmony_ci * Free the cprb memory allocated with the function above. 26562306a36Sopenharmony_ci * If the scrub value is not zero, the memory is filled 26662306a36Sopenharmony_ci * with zeros before freeing (useful if there was some 26762306a36Sopenharmony_ci * clear key material in there). 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic void free_cprbmem(void *mem, size_t paramblen, int scrub) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci if (scrub) 27262306a36Sopenharmony_ci memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen)); 27362306a36Sopenharmony_ci kfree(mem); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/* 27762306a36Sopenharmony_ci * Helper function to prepare the xcrb struct 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic inline void prep_xcrb(struct ica_xcRB *pxcrb, 28062306a36Sopenharmony_ci u16 cardnr, 28162306a36Sopenharmony_ci struct CPRBX *preqcblk, 28262306a36Sopenharmony_ci struct CPRBX *prepcblk) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci memset(pxcrb, 0, sizeof(*pxcrb)); 28562306a36Sopenharmony_ci pxcrb->agent_ID = 0x4341; /* 'CA' */ 28662306a36Sopenharmony_ci pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr); 28762306a36Sopenharmony_ci pxcrb->request_control_blk_length = 28862306a36Sopenharmony_ci preqcblk->cprb_len + preqcblk->req_parml; 28962306a36Sopenharmony_ci pxcrb->request_control_blk_addr = (void __user *)preqcblk; 29062306a36Sopenharmony_ci pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl; 29162306a36Sopenharmony_ci pxcrb->reply_control_blk_addr = (void __user *)prepcblk; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* 29562306a36Sopenharmony_ci * Generate (random) CCA AES DATA secure key. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ciint cca_genseckey(u16 cardnr, u16 domain, 29862306a36Sopenharmony_ci u32 keybitsize, u8 *seckey) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int i, rc, keysize; 30162306a36Sopenharmony_ci int seckeysize; 30262306a36Sopenharmony_ci u8 *mem, *ptr; 30362306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 30462306a36Sopenharmony_ci struct ica_xcRB xcrb; 30562306a36Sopenharmony_ci struct kgreqparm { 30662306a36Sopenharmony_ci u8 subfunc_code[2]; 30762306a36Sopenharmony_ci u16 rule_array_len; 30862306a36Sopenharmony_ci struct lv1 { 30962306a36Sopenharmony_ci u16 len; 31062306a36Sopenharmony_ci char key_form[8]; 31162306a36Sopenharmony_ci char key_length[8]; 31262306a36Sopenharmony_ci char key_type1[8]; 31362306a36Sopenharmony_ci char key_type2[8]; 31462306a36Sopenharmony_ci } lv1; 31562306a36Sopenharmony_ci struct lv2 { 31662306a36Sopenharmony_ci u16 len; 31762306a36Sopenharmony_ci struct keyid { 31862306a36Sopenharmony_ci u16 len; 31962306a36Sopenharmony_ci u16 attr; 32062306a36Sopenharmony_ci u8 data[SECKEYBLOBSIZE]; 32162306a36Sopenharmony_ci } keyid[6]; 32262306a36Sopenharmony_ci } lv2; 32362306a36Sopenharmony_ci } __packed * preqparm; 32462306a36Sopenharmony_ci struct kgrepparm { 32562306a36Sopenharmony_ci u8 subfunc_code[2]; 32662306a36Sopenharmony_ci u16 rule_array_len; 32762306a36Sopenharmony_ci struct lv3 { 32862306a36Sopenharmony_ci u16 len; 32962306a36Sopenharmony_ci u16 keyblocklen; 33062306a36Sopenharmony_ci struct { 33162306a36Sopenharmony_ci u16 toklen; 33262306a36Sopenharmony_ci u16 tokattr; 33362306a36Sopenharmony_ci u8 tok[]; 33462306a36Sopenharmony_ci /* ... some more data ... */ 33562306a36Sopenharmony_ci } keyblock; 33662306a36Sopenharmony_ci } lv3; 33762306a36Sopenharmony_ci } __packed * prepparm; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 34062306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); 34162306a36Sopenharmony_ci if (rc) 34262306a36Sopenharmony_ci return rc; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* fill request cprb struct */ 34562306a36Sopenharmony_ci preqcblk->domain = domain; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* fill request cprb param block with KG request */ 34862306a36Sopenharmony_ci preqparm = (struct kgreqparm __force *)preqcblk->req_parmb; 34962306a36Sopenharmony_ci memcpy(preqparm->subfunc_code, "KG", 2); 35062306a36Sopenharmony_ci preqparm->rule_array_len = sizeof(preqparm->rule_array_len); 35162306a36Sopenharmony_ci preqparm->lv1.len = sizeof(struct lv1); 35262306a36Sopenharmony_ci memcpy(preqparm->lv1.key_form, "OP ", 8); 35362306a36Sopenharmony_ci switch (keybitsize) { 35462306a36Sopenharmony_ci case PKEY_SIZE_AES_128: 35562306a36Sopenharmony_ci case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ 35662306a36Sopenharmony_ci keysize = 16; 35762306a36Sopenharmony_ci memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case PKEY_SIZE_AES_192: 36062306a36Sopenharmony_ci case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ 36162306a36Sopenharmony_ci keysize = 24; 36262306a36Sopenharmony_ci memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci case PKEY_SIZE_AES_256: 36562306a36Sopenharmony_ci case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ 36662306a36Sopenharmony_ci keysize = 32; 36762306a36Sopenharmony_ci memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci default: 37062306a36Sopenharmony_ci DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", 37162306a36Sopenharmony_ci __func__, keybitsize); 37262306a36Sopenharmony_ci rc = -EINVAL; 37362306a36Sopenharmony_ci goto out; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci memcpy(preqparm->lv1.key_type1, "AESDATA ", 8); 37662306a36Sopenharmony_ci preqparm->lv2.len = sizeof(struct lv2); 37762306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 37862306a36Sopenharmony_ci preqparm->lv2.keyid[i].len = sizeof(struct keyid); 37962306a36Sopenharmony_ci preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci preqcblk->req_parml = sizeof(struct kgreqparm); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* fill xcrb struct */ 38462306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 38762306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 38862306a36Sopenharmony_ci if (rc) { 38962306a36Sopenharmony_ci DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n", 39062306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 39162306a36Sopenharmony_ci goto out; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* check response returncode and reasoncode */ 39562306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 39662306a36Sopenharmony_ci DEBUG_ERR("%s secure key generate failure, card response %d/%d\n", 39762306a36Sopenharmony_ci __func__, 39862306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 39962306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 40062306a36Sopenharmony_ci rc = -EIO; 40162306a36Sopenharmony_ci goto out; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* process response cprb param block */ 40562306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 40662306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 40762306a36Sopenharmony_ci prepparm = (struct kgrepparm *)ptr; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* check length of the returned secure key token */ 41062306a36Sopenharmony_ci seckeysize = prepparm->lv3.keyblock.toklen 41162306a36Sopenharmony_ci - sizeof(prepparm->lv3.keyblock.toklen) 41262306a36Sopenharmony_ci - sizeof(prepparm->lv3.keyblock.tokattr); 41362306a36Sopenharmony_ci if (seckeysize != SECKEYBLOBSIZE) { 41462306a36Sopenharmony_ci DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n", 41562306a36Sopenharmony_ci __func__, seckeysize, SECKEYBLOBSIZE); 41662306a36Sopenharmony_ci rc = -EIO; 41762306a36Sopenharmony_ci goto out; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* check secure key token */ 42162306a36Sopenharmony_ci rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, 42262306a36Sopenharmony_ci prepparm->lv3.keyblock.tok, 8 * keysize); 42362306a36Sopenharmony_ci if (rc) { 42462306a36Sopenharmony_ci rc = -EIO; 42562306a36Sopenharmony_ci goto out; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* copy the generated secure key token */ 42962306a36Sopenharmony_ci memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ciout: 43262306a36Sopenharmony_ci free_cprbmem(mem, PARMBSIZE, 0); 43362306a36Sopenharmony_ci return rc; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ciEXPORT_SYMBOL(cca_genseckey); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/* 43862306a36Sopenharmony_ci * Generate an CCA AES DATA secure key with given key value. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ciint cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, 44162306a36Sopenharmony_ci const u8 *clrkey, u8 *seckey) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci int rc, keysize, seckeysize; 44462306a36Sopenharmony_ci u8 *mem, *ptr; 44562306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 44662306a36Sopenharmony_ci struct ica_xcRB xcrb; 44762306a36Sopenharmony_ci struct cmreqparm { 44862306a36Sopenharmony_ci u8 subfunc_code[2]; 44962306a36Sopenharmony_ci u16 rule_array_len; 45062306a36Sopenharmony_ci char rule_array[8]; 45162306a36Sopenharmony_ci struct lv1 { 45262306a36Sopenharmony_ci u16 len; 45362306a36Sopenharmony_ci u8 clrkey[]; 45462306a36Sopenharmony_ci } lv1; 45562306a36Sopenharmony_ci /* followed by struct lv2 */ 45662306a36Sopenharmony_ci } __packed * preqparm; 45762306a36Sopenharmony_ci struct lv2 { 45862306a36Sopenharmony_ci u16 len; 45962306a36Sopenharmony_ci struct keyid { 46062306a36Sopenharmony_ci u16 len; 46162306a36Sopenharmony_ci u16 attr; 46262306a36Sopenharmony_ci u8 data[SECKEYBLOBSIZE]; 46362306a36Sopenharmony_ci } keyid; 46462306a36Sopenharmony_ci } __packed * plv2; 46562306a36Sopenharmony_ci struct cmrepparm { 46662306a36Sopenharmony_ci u8 subfunc_code[2]; 46762306a36Sopenharmony_ci u16 rule_array_len; 46862306a36Sopenharmony_ci struct lv3 { 46962306a36Sopenharmony_ci u16 len; 47062306a36Sopenharmony_ci u16 keyblocklen; 47162306a36Sopenharmony_ci struct { 47262306a36Sopenharmony_ci u16 toklen; 47362306a36Sopenharmony_ci u16 tokattr; 47462306a36Sopenharmony_ci u8 tok[]; 47562306a36Sopenharmony_ci /* ... some more data ... */ 47662306a36Sopenharmony_ci } keyblock; 47762306a36Sopenharmony_ci } lv3; 47862306a36Sopenharmony_ci } __packed * prepparm; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 48162306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); 48262306a36Sopenharmony_ci if (rc) 48362306a36Sopenharmony_ci return rc; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* fill request cprb struct */ 48662306a36Sopenharmony_ci preqcblk->domain = domain; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* fill request cprb param block with CM request */ 48962306a36Sopenharmony_ci preqparm = (struct cmreqparm __force *)preqcblk->req_parmb; 49062306a36Sopenharmony_ci memcpy(preqparm->subfunc_code, "CM", 2); 49162306a36Sopenharmony_ci memcpy(preqparm->rule_array, "AES ", 8); 49262306a36Sopenharmony_ci preqparm->rule_array_len = 49362306a36Sopenharmony_ci sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); 49462306a36Sopenharmony_ci switch (keybitsize) { 49562306a36Sopenharmony_ci case PKEY_SIZE_AES_128: 49662306a36Sopenharmony_ci case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ 49762306a36Sopenharmony_ci keysize = 16; 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci case PKEY_SIZE_AES_192: 50062306a36Sopenharmony_ci case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ 50162306a36Sopenharmony_ci keysize = 24; 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case PKEY_SIZE_AES_256: 50462306a36Sopenharmony_ci case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ 50562306a36Sopenharmony_ci keysize = 32; 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci default: 50862306a36Sopenharmony_ci DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", 50962306a36Sopenharmony_ci __func__, keybitsize); 51062306a36Sopenharmony_ci rc = -EINVAL; 51162306a36Sopenharmony_ci goto out; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci preqparm->lv1.len = sizeof(struct lv1) + keysize; 51462306a36Sopenharmony_ci memcpy(preqparm->lv1.clrkey, clrkey, keysize); 51562306a36Sopenharmony_ci plv2 = (struct lv2 *)(((u8 *)preqparm) + sizeof(*preqparm) + keysize); 51662306a36Sopenharmony_ci plv2->len = sizeof(struct lv2); 51762306a36Sopenharmony_ci plv2->keyid.len = sizeof(struct keyid); 51862306a36Sopenharmony_ci plv2->keyid.attr = 0x30; 51962306a36Sopenharmony_ci preqcblk->req_parml = sizeof(*preqparm) + keysize + sizeof(*plv2); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* fill xcrb struct */ 52262306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 52562306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 52662306a36Sopenharmony_ci if (rc) { 52762306a36Sopenharmony_ci DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", 52862306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 52962306a36Sopenharmony_ci goto out; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* check response returncode and reasoncode */ 53362306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 53462306a36Sopenharmony_ci DEBUG_ERR("%s clear key import failure, card response %d/%d\n", 53562306a36Sopenharmony_ci __func__, 53662306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 53762306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 53862306a36Sopenharmony_ci rc = -EIO; 53962306a36Sopenharmony_ci goto out; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* process response cprb param block */ 54362306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 54462306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 54562306a36Sopenharmony_ci prepparm = (struct cmrepparm *)ptr; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* check length of the returned secure key token */ 54862306a36Sopenharmony_ci seckeysize = prepparm->lv3.keyblock.toklen 54962306a36Sopenharmony_ci - sizeof(prepparm->lv3.keyblock.toklen) 55062306a36Sopenharmony_ci - sizeof(prepparm->lv3.keyblock.tokattr); 55162306a36Sopenharmony_ci if (seckeysize != SECKEYBLOBSIZE) { 55262306a36Sopenharmony_ci DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n", 55362306a36Sopenharmony_ci __func__, seckeysize, SECKEYBLOBSIZE); 55462306a36Sopenharmony_ci rc = -EIO; 55562306a36Sopenharmony_ci goto out; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* check secure key token */ 55962306a36Sopenharmony_ci rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, 56062306a36Sopenharmony_ci prepparm->lv3.keyblock.tok, 8 * keysize); 56162306a36Sopenharmony_ci if (rc) { 56262306a36Sopenharmony_ci rc = -EIO; 56362306a36Sopenharmony_ci goto out; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* copy the generated secure key token */ 56762306a36Sopenharmony_ci if (seckey) 56862306a36Sopenharmony_ci memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ciout: 57162306a36Sopenharmony_ci free_cprbmem(mem, PARMBSIZE, 1); 57262306a36Sopenharmony_ci return rc; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ciEXPORT_SYMBOL(cca_clr2seckey); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* 57762306a36Sopenharmony_ci * Derive proteced key from an CCA AES DATA secure key. 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ciint cca_sec2protkey(u16 cardnr, u16 domain, 58062306a36Sopenharmony_ci const u8 *seckey, u8 *protkey, u32 *protkeylen, 58162306a36Sopenharmony_ci u32 *protkeytype) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci int rc; 58462306a36Sopenharmony_ci u8 *mem, *ptr; 58562306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 58662306a36Sopenharmony_ci struct ica_xcRB xcrb; 58762306a36Sopenharmony_ci struct uskreqparm { 58862306a36Sopenharmony_ci u8 subfunc_code[2]; 58962306a36Sopenharmony_ci u16 rule_array_len; 59062306a36Sopenharmony_ci struct lv1 { 59162306a36Sopenharmony_ci u16 len; 59262306a36Sopenharmony_ci u16 attr_len; 59362306a36Sopenharmony_ci u16 attr_flags; 59462306a36Sopenharmony_ci } lv1; 59562306a36Sopenharmony_ci struct lv2 { 59662306a36Sopenharmony_ci u16 len; 59762306a36Sopenharmony_ci u16 attr_len; 59862306a36Sopenharmony_ci u16 attr_flags; 59962306a36Sopenharmony_ci u8 token[]; /* cca secure key token */ 60062306a36Sopenharmony_ci } lv2; 60162306a36Sopenharmony_ci } __packed * preqparm; 60262306a36Sopenharmony_ci struct uskrepparm { 60362306a36Sopenharmony_ci u8 subfunc_code[2]; 60462306a36Sopenharmony_ci u16 rule_array_len; 60562306a36Sopenharmony_ci struct lv3 { 60662306a36Sopenharmony_ci u16 len; 60762306a36Sopenharmony_ci u16 attr_len; 60862306a36Sopenharmony_ci u16 attr_flags; 60962306a36Sopenharmony_ci struct cpacfkeyblock { 61062306a36Sopenharmony_ci u8 version; /* version of this struct */ 61162306a36Sopenharmony_ci u8 flags[2]; 61262306a36Sopenharmony_ci u8 algo; 61362306a36Sopenharmony_ci u8 form; 61462306a36Sopenharmony_ci u8 pad1[3]; 61562306a36Sopenharmony_ci u16 len; 61662306a36Sopenharmony_ci u8 key[64]; /* the key (len bytes) */ 61762306a36Sopenharmony_ci u16 keyattrlen; 61862306a36Sopenharmony_ci u8 keyattr[32]; 61962306a36Sopenharmony_ci u8 pad2[1]; 62062306a36Sopenharmony_ci u8 vptype; 62162306a36Sopenharmony_ci u8 vp[32]; /* verification pattern */ 62262306a36Sopenharmony_ci } ckb; 62362306a36Sopenharmony_ci } lv3; 62462306a36Sopenharmony_ci } __packed * prepparm; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 62762306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); 62862306a36Sopenharmony_ci if (rc) 62962306a36Sopenharmony_ci return rc; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* fill request cprb struct */ 63262306a36Sopenharmony_ci preqcblk->domain = domain; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* fill request cprb param block with USK request */ 63562306a36Sopenharmony_ci preqparm = (struct uskreqparm __force *)preqcblk->req_parmb; 63662306a36Sopenharmony_ci memcpy(preqparm->subfunc_code, "US", 2); 63762306a36Sopenharmony_ci preqparm->rule_array_len = sizeof(preqparm->rule_array_len); 63862306a36Sopenharmony_ci preqparm->lv1.len = sizeof(struct lv1); 63962306a36Sopenharmony_ci preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len); 64062306a36Sopenharmony_ci preqparm->lv1.attr_flags = 0x0001; 64162306a36Sopenharmony_ci preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE; 64262306a36Sopenharmony_ci preqparm->lv2.attr_len = sizeof(struct lv2) 64362306a36Sopenharmony_ci - sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE; 64462306a36Sopenharmony_ci preqparm->lv2.attr_flags = 0x0000; 64562306a36Sopenharmony_ci memcpy(preqparm->lv2.token, seckey, SECKEYBLOBSIZE); 64662306a36Sopenharmony_ci preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* fill xcrb struct */ 64962306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 65262306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 65362306a36Sopenharmony_ci if (rc) { 65462306a36Sopenharmony_ci DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", 65562306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 65662306a36Sopenharmony_ci goto out; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* check response returncode and reasoncode */ 66062306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 66162306a36Sopenharmony_ci DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n", 66262306a36Sopenharmony_ci __func__, 66362306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 66462306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 66562306a36Sopenharmony_ci if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290) 66662306a36Sopenharmony_ci rc = -EAGAIN; 66762306a36Sopenharmony_ci else 66862306a36Sopenharmony_ci rc = -EIO; 66962306a36Sopenharmony_ci goto out; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci if (prepcblk->ccp_rscode != 0) { 67262306a36Sopenharmony_ci DEBUG_WARN("%s unwrap secure key warning, card response %d/%d\n", 67362306a36Sopenharmony_ci __func__, 67462306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 67562306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* process response cprb param block */ 67962306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 68062306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 68162306a36Sopenharmony_ci prepparm = (struct uskrepparm *)ptr; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* check the returned keyblock */ 68462306a36Sopenharmony_ci if (prepparm->lv3.ckb.version != 0x01 && 68562306a36Sopenharmony_ci prepparm->lv3.ckb.version != 0x02) { 68662306a36Sopenharmony_ci DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x\n", 68762306a36Sopenharmony_ci __func__, (int)prepparm->lv3.ckb.version); 68862306a36Sopenharmony_ci rc = -EIO; 68962306a36Sopenharmony_ci goto out; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* copy the translated protected key */ 69362306a36Sopenharmony_ci switch (prepparm->lv3.ckb.len) { 69462306a36Sopenharmony_ci case 16 + 32: 69562306a36Sopenharmony_ci /* AES 128 protected key */ 69662306a36Sopenharmony_ci if (protkeytype) 69762306a36Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_128; 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci case 24 + 32: 70062306a36Sopenharmony_ci /* AES 192 protected key */ 70162306a36Sopenharmony_ci if (protkeytype) 70262306a36Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_192; 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci case 32 + 32: 70562306a36Sopenharmony_ci /* AES 256 protected key */ 70662306a36Sopenharmony_ci if (protkeytype) 70762306a36Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_256; 70862306a36Sopenharmony_ci break; 70962306a36Sopenharmony_ci default: 71062306a36Sopenharmony_ci DEBUG_ERR("%s unknown/unsupported keylen %d\n", 71162306a36Sopenharmony_ci __func__, prepparm->lv3.ckb.len); 71262306a36Sopenharmony_ci rc = -EIO; 71362306a36Sopenharmony_ci goto out; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci memcpy(protkey, prepparm->lv3.ckb.key, prepparm->lv3.ckb.len); 71662306a36Sopenharmony_ci if (protkeylen) 71762306a36Sopenharmony_ci *protkeylen = prepparm->lv3.ckb.len; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ciout: 72062306a36Sopenharmony_ci free_cprbmem(mem, PARMBSIZE, 0); 72162306a36Sopenharmony_ci return rc; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ciEXPORT_SYMBOL(cca_sec2protkey); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci/* 72662306a36Sopenharmony_ci * AES cipher key skeleton created with CSNBKTB2 with these flags: 72762306a36Sopenharmony_ci * INTERNAL, NO-KEY, AES, CIPHER, ANY-MODE, NOEX-SYM, NOEXAASY, 72862306a36Sopenharmony_ci * NOEXUASY, XPRTCPAC, NOEX-RAW, NOEX-DES, NOEX-AES, NOEX-RSA 72962306a36Sopenharmony_ci * used by cca_gencipherkey() and cca_clr2cipherkey(). 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_cistatic const u8 aes_cipher_key_skeleton[] = { 73262306a36Sopenharmony_ci 0x01, 0x00, 0x00, 0x38, 0x05, 0x00, 0x00, 0x00, 73362306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73462306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73562306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 73662306a36Sopenharmony_ci 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73762306a36Sopenharmony_ci 0x00, 0x02, 0x00, 0x01, 0x02, 0xc0, 0x00, 0xff, 73862306a36Sopenharmony_ci 0x00, 0x03, 0x08, 0xc8, 0x00, 0x00, 0x00, 0x00 }; 73962306a36Sopenharmony_ci#define SIZEOF_SKELETON (sizeof(aes_cipher_key_skeleton)) 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci/* 74262306a36Sopenharmony_ci * Generate (random) CCA AES CIPHER secure key. 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ciint cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, 74562306a36Sopenharmony_ci u8 *keybuf, size_t *keybufsize) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci int rc; 74862306a36Sopenharmony_ci u8 *mem, *ptr; 74962306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 75062306a36Sopenharmony_ci struct ica_xcRB xcrb; 75162306a36Sopenharmony_ci struct gkreqparm { 75262306a36Sopenharmony_ci u8 subfunc_code[2]; 75362306a36Sopenharmony_ci u16 rule_array_len; 75462306a36Sopenharmony_ci char rule_array[2 * 8]; 75562306a36Sopenharmony_ci struct { 75662306a36Sopenharmony_ci u16 len; 75762306a36Sopenharmony_ci u8 key_type_1[8]; 75862306a36Sopenharmony_ci u8 key_type_2[8]; 75962306a36Sopenharmony_ci u16 clear_key_bit_len; 76062306a36Sopenharmony_ci u16 key_name_1_len; 76162306a36Sopenharmony_ci u16 key_name_2_len; 76262306a36Sopenharmony_ci u16 user_data_1_len; 76362306a36Sopenharmony_ci u16 user_data_2_len; 76462306a36Sopenharmony_ci /* u8 key_name_1[]; */ 76562306a36Sopenharmony_ci /* u8 key_name_2[]; */ 76662306a36Sopenharmony_ci /* u8 user_data_1[]; */ 76762306a36Sopenharmony_ci /* u8 user_data_2[]; */ 76862306a36Sopenharmony_ci } vud; 76962306a36Sopenharmony_ci struct { 77062306a36Sopenharmony_ci u16 len; 77162306a36Sopenharmony_ci struct { 77262306a36Sopenharmony_ci u16 len; 77362306a36Sopenharmony_ci u16 flag; 77462306a36Sopenharmony_ci /* u8 kek_id_1[]; */ 77562306a36Sopenharmony_ci } tlv1; 77662306a36Sopenharmony_ci struct { 77762306a36Sopenharmony_ci u16 len; 77862306a36Sopenharmony_ci u16 flag; 77962306a36Sopenharmony_ci /* u8 kek_id_2[]; */ 78062306a36Sopenharmony_ci } tlv2; 78162306a36Sopenharmony_ci struct { 78262306a36Sopenharmony_ci u16 len; 78362306a36Sopenharmony_ci u16 flag; 78462306a36Sopenharmony_ci u8 gen_key_id_1[SIZEOF_SKELETON]; 78562306a36Sopenharmony_ci } tlv3; 78662306a36Sopenharmony_ci struct { 78762306a36Sopenharmony_ci u16 len; 78862306a36Sopenharmony_ci u16 flag; 78962306a36Sopenharmony_ci /* u8 gen_key_id_1_label[]; */ 79062306a36Sopenharmony_ci } tlv4; 79162306a36Sopenharmony_ci struct { 79262306a36Sopenharmony_ci u16 len; 79362306a36Sopenharmony_ci u16 flag; 79462306a36Sopenharmony_ci /* u8 gen_key_id_2[]; */ 79562306a36Sopenharmony_ci } tlv5; 79662306a36Sopenharmony_ci struct { 79762306a36Sopenharmony_ci u16 len; 79862306a36Sopenharmony_ci u16 flag; 79962306a36Sopenharmony_ci /* u8 gen_key_id_2_label[]; */ 80062306a36Sopenharmony_ci } tlv6; 80162306a36Sopenharmony_ci } kb; 80262306a36Sopenharmony_ci } __packed * preqparm; 80362306a36Sopenharmony_ci struct gkrepparm { 80462306a36Sopenharmony_ci u8 subfunc_code[2]; 80562306a36Sopenharmony_ci u16 rule_array_len; 80662306a36Sopenharmony_ci struct { 80762306a36Sopenharmony_ci u16 len; 80862306a36Sopenharmony_ci } vud; 80962306a36Sopenharmony_ci struct { 81062306a36Sopenharmony_ci u16 len; 81162306a36Sopenharmony_ci struct { 81262306a36Sopenharmony_ci u16 len; 81362306a36Sopenharmony_ci u16 flag; 81462306a36Sopenharmony_ci u8 gen_key[]; /* 120-136 bytes */ 81562306a36Sopenharmony_ci } tlv1; 81662306a36Sopenharmony_ci } kb; 81762306a36Sopenharmony_ci } __packed * prepparm; 81862306a36Sopenharmony_ci struct cipherkeytoken *t; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 82162306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); 82262306a36Sopenharmony_ci if (rc) 82362306a36Sopenharmony_ci return rc; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* fill request cprb struct */ 82662306a36Sopenharmony_ci preqcblk->domain = domain; 82762306a36Sopenharmony_ci preqcblk->req_parml = sizeof(struct gkreqparm); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* prepare request param block with GK request */ 83062306a36Sopenharmony_ci preqparm = (struct gkreqparm __force *)preqcblk->req_parmb; 83162306a36Sopenharmony_ci memcpy(preqparm->subfunc_code, "GK", 2); 83262306a36Sopenharmony_ci preqparm->rule_array_len = sizeof(uint16_t) + 2 * 8; 83362306a36Sopenharmony_ci memcpy(preqparm->rule_array, "AES OP ", 2 * 8); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* prepare vud block */ 83662306a36Sopenharmony_ci preqparm->vud.len = sizeof(preqparm->vud); 83762306a36Sopenharmony_ci switch (keybitsize) { 83862306a36Sopenharmony_ci case 128: 83962306a36Sopenharmony_ci case 192: 84062306a36Sopenharmony_ci case 256: 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci default: 84362306a36Sopenharmony_ci DEBUG_ERR( 84462306a36Sopenharmony_ci "%s unknown/unsupported keybitsize %d\n", 84562306a36Sopenharmony_ci __func__, keybitsize); 84662306a36Sopenharmony_ci rc = -EINVAL; 84762306a36Sopenharmony_ci goto out; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci preqparm->vud.clear_key_bit_len = keybitsize; 85062306a36Sopenharmony_ci memcpy(preqparm->vud.key_type_1, "TOKEN ", 8); 85162306a36Sopenharmony_ci memset(preqparm->vud.key_type_2, ' ', sizeof(preqparm->vud.key_type_2)); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* prepare kb block */ 85462306a36Sopenharmony_ci preqparm->kb.len = sizeof(preqparm->kb); 85562306a36Sopenharmony_ci preqparm->kb.tlv1.len = sizeof(preqparm->kb.tlv1); 85662306a36Sopenharmony_ci preqparm->kb.tlv1.flag = 0x0030; 85762306a36Sopenharmony_ci preqparm->kb.tlv2.len = sizeof(preqparm->kb.tlv2); 85862306a36Sopenharmony_ci preqparm->kb.tlv2.flag = 0x0030; 85962306a36Sopenharmony_ci preqparm->kb.tlv3.len = sizeof(preqparm->kb.tlv3); 86062306a36Sopenharmony_ci preqparm->kb.tlv3.flag = 0x0030; 86162306a36Sopenharmony_ci memcpy(preqparm->kb.tlv3.gen_key_id_1, 86262306a36Sopenharmony_ci aes_cipher_key_skeleton, SIZEOF_SKELETON); 86362306a36Sopenharmony_ci preqparm->kb.tlv4.len = sizeof(preqparm->kb.tlv4); 86462306a36Sopenharmony_ci preqparm->kb.tlv4.flag = 0x0030; 86562306a36Sopenharmony_ci preqparm->kb.tlv5.len = sizeof(preqparm->kb.tlv5); 86662306a36Sopenharmony_ci preqparm->kb.tlv5.flag = 0x0030; 86762306a36Sopenharmony_ci preqparm->kb.tlv6.len = sizeof(preqparm->kb.tlv6); 86862306a36Sopenharmony_ci preqparm->kb.tlv6.flag = 0x0030; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* patch the skeleton key token export flags inside the kb block */ 87162306a36Sopenharmony_ci if (keygenflags) { 87262306a36Sopenharmony_ci t = (struct cipherkeytoken *)preqparm->kb.tlv3.gen_key_id_1; 87362306a36Sopenharmony_ci t->kmf1 |= (u16)(keygenflags & 0x0000FF00); 87462306a36Sopenharmony_ci t->kmf1 &= (u16)~(keygenflags & 0x000000FF); 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci /* prepare xcrb struct */ 87862306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 88162306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 88262306a36Sopenharmony_ci if (rc) { 88362306a36Sopenharmony_ci DEBUG_ERR( 88462306a36Sopenharmony_ci "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", 88562306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 88662306a36Sopenharmony_ci goto out; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* check response returncode and reasoncode */ 89062306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 89162306a36Sopenharmony_ci DEBUG_ERR( 89262306a36Sopenharmony_ci "%s cipher key generate failure, card response %d/%d\n", 89362306a36Sopenharmony_ci __func__, 89462306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 89562306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 89662306a36Sopenharmony_ci rc = -EIO; 89762306a36Sopenharmony_ci goto out; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci /* process response cprb param block */ 90162306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 90262306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 90362306a36Sopenharmony_ci prepparm = (struct gkrepparm *)ptr; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* do some plausibility checks on the key block */ 90662306a36Sopenharmony_ci if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) || 90762306a36Sopenharmony_ci prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) { 90862306a36Sopenharmony_ci DEBUG_ERR("%s reply with invalid or unknown key block\n", 90962306a36Sopenharmony_ci __func__); 91062306a36Sopenharmony_ci rc = -EIO; 91162306a36Sopenharmony_ci goto out; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* and some checks on the generated key */ 91562306a36Sopenharmony_ci rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR, 91662306a36Sopenharmony_ci prepparm->kb.tlv1.gen_key, 91762306a36Sopenharmony_ci keybitsize, 1); 91862306a36Sopenharmony_ci if (rc) { 91962306a36Sopenharmony_ci rc = -EIO; 92062306a36Sopenharmony_ci goto out; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* copy the generated vlsc key token */ 92462306a36Sopenharmony_ci t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key; 92562306a36Sopenharmony_ci if (keybuf) { 92662306a36Sopenharmony_ci if (*keybufsize >= t->len) 92762306a36Sopenharmony_ci memcpy(keybuf, t, t->len); 92862306a36Sopenharmony_ci else 92962306a36Sopenharmony_ci rc = -EINVAL; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci *keybufsize = t->len; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ciout: 93462306a36Sopenharmony_ci free_cprbmem(mem, PARMBSIZE, 0); 93562306a36Sopenharmony_ci return rc; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ciEXPORT_SYMBOL(cca_gencipherkey); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci/* 94062306a36Sopenharmony_ci * Helper function, does a the CSNBKPI2 CPRB. 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_cistatic int _ip_cprb_helper(u16 cardnr, u16 domain, 94362306a36Sopenharmony_ci const char *rule_array_1, 94462306a36Sopenharmony_ci const char *rule_array_2, 94562306a36Sopenharmony_ci const char *rule_array_3, 94662306a36Sopenharmony_ci const u8 *clr_key_value, 94762306a36Sopenharmony_ci int clr_key_bit_size, 94862306a36Sopenharmony_ci u8 *key_token, 94962306a36Sopenharmony_ci int *key_token_size) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci int rc, n; 95262306a36Sopenharmony_ci u8 *mem, *ptr; 95362306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 95462306a36Sopenharmony_ci struct ica_xcRB xcrb; 95562306a36Sopenharmony_ci struct rule_array_block { 95662306a36Sopenharmony_ci u8 subfunc_code[2]; 95762306a36Sopenharmony_ci u16 rule_array_len; 95862306a36Sopenharmony_ci char rule_array[]; 95962306a36Sopenharmony_ci } __packed * preq_ra_block; 96062306a36Sopenharmony_ci struct vud_block { 96162306a36Sopenharmony_ci u16 len; 96262306a36Sopenharmony_ci struct { 96362306a36Sopenharmony_ci u16 len; 96462306a36Sopenharmony_ci u16 flag; /* 0x0064 */ 96562306a36Sopenharmony_ci u16 clr_key_bit_len; 96662306a36Sopenharmony_ci } tlv1; 96762306a36Sopenharmony_ci struct { 96862306a36Sopenharmony_ci u16 len; 96962306a36Sopenharmony_ci u16 flag; /* 0x0063 */ 97062306a36Sopenharmony_ci u8 clr_key[]; /* clear key value bytes */ 97162306a36Sopenharmony_ci } tlv2; 97262306a36Sopenharmony_ci } __packed * preq_vud_block; 97362306a36Sopenharmony_ci struct key_block { 97462306a36Sopenharmony_ci u16 len; 97562306a36Sopenharmony_ci struct { 97662306a36Sopenharmony_ci u16 len; 97762306a36Sopenharmony_ci u16 flag; /* 0x0030 */ 97862306a36Sopenharmony_ci u8 key_token[]; /* key skeleton */ 97962306a36Sopenharmony_ci } tlv1; 98062306a36Sopenharmony_ci } __packed * preq_key_block; 98162306a36Sopenharmony_ci struct iprepparm { 98262306a36Sopenharmony_ci u8 subfunc_code[2]; 98362306a36Sopenharmony_ci u16 rule_array_len; 98462306a36Sopenharmony_ci struct { 98562306a36Sopenharmony_ci u16 len; 98662306a36Sopenharmony_ci } vud; 98762306a36Sopenharmony_ci struct { 98862306a36Sopenharmony_ci u16 len; 98962306a36Sopenharmony_ci struct { 99062306a36Sopenharmony_ci u16 len; 99162306a36Sopenharmony_ci u16 flag; /* 0x0030 */ 99262306a36Sopenharmony_ci u8 key_token[]; /* key token */ 99362306a36Sopenharmony_ci } tlv1; 99462306a36Sopenharmony_ci } kb; 99562306a36Sopenharmony_ci } __packed * prepparm; 99662306a36Sopenharmony_ci struct cipherkeytoken *t; 99762306a36Sopenharmony_ci int complete = strncmp(rule_array_2, "COMPLETE", 8) ? 0 : 1; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 100062306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); 100162306a36Sopenharmony_ci if (rc) 100262306a36Sopenharmony_ci return rc; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* fill request cprb struct */ 100562306a36Sopenharmony_ci preqcblk->domain = domain; 100662306a36Sopenharmony_ci preqcblk->req_parml = 0; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* prepare request param block with IP request */ 100962306a36Sopenharmony_ci preq_ra_block = (struct rule_array_block __force *)preqcblk->req_parmb; 101062306a36Sopenharmony_ci memcpy(preq_ra_block->subfunc_code, "IP", 2); 101162306a36Sopenharmony_ci preq_ra_block->rule_array_len = sizeof(uint16_t) + 2 * 8; 101262306a36Sopenharmony_ci memcpy(preq_ra_block->rule_array, rule_array_1, 8); 101362306a36Sopenharmony_ci memcpy(preq_ra_block->rule_array + 8, rule_array_2, 8); 101462306a36Sopenharmony_ci preqcblk->req_parml = sizeof(struct rule_array_block) + 2 * 8; 101562306a36Sopenharmony_ci if (rule_array_3) { 101662306a36Sopenharmony_ci preq_ra_block->rule_array_len += 8; 101762306a36Sopenharmony_ci memcpy(preq_ra_block->rule_array + 16, rule_array_3, 8); 101862306a36Sopenharmony_ci preqcblk->req_parml += 8; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* prepare vud block */ 102262306a36Sopenharmony_ci preq_vud_block = (struct vud_block __force *) 102362306a36Sopenharmony_ci (preqcblk->req_parmb + preqcblk->req_parml); 102462306a36Sopenharmony_ci n = complete ? 0 : (clr_key_bit_size + 7) / 8; 102562306a36Sopenharmony_ci preq_vud_block->len = sizeof(struct vud_block) + n; 102662306a36Sopenharmony_ci preq_vud_block->tlv1.len = sizeof(preq_vud_block->tlv1); 102762306a36Sopenharmony_ci preq_vud_block->tlv1.flag = 0x0064; 102862306a36Sopenharmony_ci preq_vud_block->tlv1.clr_key_bit_len = complete ? 0 : clr_key_bit_size; 102962306a36Sopenharmony_ci preq_vud_block->tlv2.len = sizeof(preq_vud_block->tlv2) + n; 103062306a36Sopenharmony_ci preq_vud_block->tlv2.flag = 0x0063; 103162306a36Sopenharmony_ci if (!complete) 103262306a36Sopenharmony_ci memcpy(preq_vud_block->tlv2.clr_key, clr_key_value, n); 103362306a36Sopenharmony_ci preqcblk->req_parml += preq_vud_block->len; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* prepare key block */ 103662306a36Sopenharmony_ci preq_key_block = (struct key_block __force *) 103762306a36Sopenharmony_ci (preqcblk->req_parmb + preqcblk->req_parml); 103862306a36Sopenharmony_ci n = *key_token_size; 103962306a36Sopenharmony_ci preq_key_block->len = sizeof(struct key_block) + n; 104062306a36Sopenharmony_ci preq_key_block->tlv1.len = sizeof(preq_key_block->tlv1) + n; 104162306a36Sopenharmony_ci preq_key_block->tlv1.flag = 0x0030; 104262306a36Sopenharmony_ci memcpy(preq_key_block->tlv1.key_token, key_token, *key_token_size); 104362306a36Sopenharmony_ci preqcblk->req_parml += preq_key_block->len; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* prepare xcrb struct */ 104662306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 104962306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 105062306a36Sopenharmony_ci if (rc) { 105162306a36Sopenharmony_ci DEBUG_ERR( 105262306a36Sopenharmony_ci "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", 105362306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 105462306a36Sopenharmony_ci goto out; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci /* check response returncode and reasoncode */ 105862306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 105962306a36Sopenharmony_ci DEBUG_ERR( 106062306a36Sopenharmony_ci "%s CSNBKPI2 failure, card response %d/%d\n", 106162306a36Sopenharmony_ci __func__, 106262306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 106362306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 106462306a36Sopenharmony_ci rc = -EIO; 106562306a36Sopenharmony_ci goto out; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* process response cprb param block */ 106962306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 107062306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 107162306a36Sopenharmony_ci prepparm = (struct iprepparm *)ptr; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* do some plausibility checks on the key block */ 107462306a36Sopenharmony_ci if (prepparm->kb.len < 120 + 3 * sizeof(uint16_t) || 107562306a36Sopenharmony_ci prepparm->kb.len > 136 + 3 * sizeof(uint16_t)) { 107662306a36Sopenharmony_ci DEBUG_ERR("%s reply with invalid or unknown key block\n", 107762306a36Sopenharmony_ci __func__); 107862306a36Sopenharmony_ci rc = -EIO; 107962306a36Sopenharmony_ci goto out; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci /* do not check the key here, it may be incomplete */ 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci /* copy the vlsc key token back */ 108562306a36Sopenharmony_ci t = (struct cipherkeytoken *)prepparm->kb.tlv1.key_token; 108662306a36Sopenharmony_ci memcpy(key_token, t, t->len); 108762306a36Sopenharmony_ci *key_token_size = t->len; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ciout: 109062306a36Sopenharmony_ci free_cprbmem(mem, PARMBSIZE, 0); 109162306a36Sopenharmony_ci return rc; 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci/* 109562306a36Sopenharmony_ci * Build CCA AES CIPHER secure key with a given clear key value. 109662306a36Sopenharmony_ci */ 109762306a36Sopenharmony_ciint cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, 109862306a36Sopenharmony_ci const u8 *clrkey, u8 *keybuf, size_t *keybufsize) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci int rc; 110162306a36Sopenharmony_ci u8 *token; 110262306a36Sopenharmony_ci int tokensize; 110362306a36Sopenharmony_ci u8 exorbuf[32]; 110462306a36Sopenharmony_ci struct cipherkeytoken *t; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* fill exorbuf with random data */ 110762306a36Sopenharmony_ci get_random_bytes(exorbuf, sizeof(exorbuf)); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* allocate space for the key token to build */ 111062306a36Sopenharmony_ci token = kmalloc(MAXCCAVLSCTOKENSIZE, GFP_KERNEL); 111162306a36Sopenharmony_ci if (!token) 111262306a36Sopenharmony_ci return -ENOMEM; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci /* prepare the token with the key skeleton */ 111562306a36Sopenharmony_ci tokensize = SIZEOF_SKELETON; 111662306a36Sopenharmony_ci memcpy(token, aes_cipher_key_skeleton, tokensize); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* patch the skeleton key token export flags */ 111962306a36Sopenharmony_ci if (keygenflags) { 112062306a36Sopenharmony_ci t = (struct cipherkeytoken *)token; 112162306a36Sopenharmony_ci t->kmf1 |= (u16)(keygenflags & 0x0000FF00); 112262306a36Sopenharmony_ci t->kmf1 &= (u16)~(keygenflags & 0x000000FF); 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* 112662306a36Sopenharmony_ci * Do the key import with the clear key value in 4 steps: 112762306a36Sopenharmony_ci * 1/4 FIRST import with only random data 112862306a36Sopenharmony_ci * 2/4 EXOR the clear key 112962306a36Sopenharmony_ci * 3/4 EXOR the very same random data again 113062306a36Sopenharmony_ci * 4/4 COMPLETE the secure cipher key import 113162306a36Sopenharmony_ci */ 113262306a36Sopenharmony_ci rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART", 113362306a36Sopenharmony_ci exorbuf, keybitsize, token, &tokensize); 113462306a36Sopenharmony_ci if (rc) { 113562306a36Sopenharmony_ci DEBUG_ERR( 113662306a36Sopenharmony_ci "%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n", 113762306a36Sopenharmony_ci __func__, rc); 113862306a36Sopenharmony_ci goto out; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, 114162306a36Sopenharmony_ci clrkey, keybitsize, token, &tokensize); 114262306a36Sopenharmony_ci if (rc) { 114362306a36Sopenharmony_ci DEBUG_ERR( 114462306a36Sopenharmony_ci "%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n", 114562306a36Sopenharmony_ci __func__, rc); 114662306a36Sopenharmony_ci goto out; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, 114962306a36Sopenharmony_ci exorbuf, keybitsize, token, &tokensize); 115062306a36Sopenharmony_ci if (rc) { 115162306a36Sopenharmony_ci DEBUG_ERR( 115262306a36Sopenharmony_ci "%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n", 115362306a36Sopenharmony_ci __func__, rc); 115462306a36Sopenharmony_ci goto out; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL, 115762306a36Sopenharmony_ci NULL, keybitsize, token, &tokensize); 115862306a36Sopenharmony_ci if (rc) { 115962306a36Sopenharmony_ci DEBUG_ERR( 116062306a36Sopenharmony_ci "%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n", 116162306a36Sopenharmony_ci __func__, rc); 116262306a36Sopenharmony_ci goto out; 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci /* copy the generated key token */ 116662306a36Sopenharmony_ci if (keybuf) { 116762306a36Sopenharmony_ci if (tokensize > *keybufsize) 116862306a36Sopenharmony_ci rc = -EINVAL; 116962306a36Sopenharmony_ci else 117062306a36Sopenharmony_ci memcpy(keybuf, token, tokensize); 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci *keybufsize = tokensize; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ciout: 117562306a36Sopenharmony_ci kfree(token); 117662306a36Sopenharmony_ci return rc; 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ciEXPORT_SYMBOL(cca_clr2cipherkey); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci/* 118162306a36Sopenharmony_ci * Derive proteced key from CCA AES cipher secure key. 118262306a36Sopenharmony_ci */ 118362306a36Sopenharmony_ciint cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, 118462306a36Sopenharmony_ci u8 *protkey, u32 *protkeylen, u32 *protkeytype) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci int rc; 118762306a36Sopenharmony_ci u8 *mem, *ptr; 118862306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 118962306a36Sopenharmony_ci struct ica_xcRB xcrb; 119062306a36Sopenharmony_ci struct aureqparm { 119162306a36Sopenharmony_ci u8 subfunc_code[2]; 119262306a36Sopenharmony_ci u16 rule_array_len; 119362306a36Sopenharmony_ci u8 rule_array[8]; 119462306a36Sopenharmony_ci struct { 119562306a36Sopenharmony_ci u16 len; 119662306a36Sopenharmony_ci u16 tk_blob_len; 119762306a36Sopenharmony_ci u16 tk_blob_tag; 119862306a36Sopenharmony_ci u8 tk_blob[66]; 119962306a36Sopenharmony_ci } vud; 120062306a36Sopenharmony_ci struct { 120162306a36Sopenharmony_ci u16 len; 120262306a36Sopenharmony_ci u16 cca_key_token_len; 120362306a36Sopenharmony_ci u16 cca_key_token_flags; 120462306a36Sopenharmony_ci u8 cca_key_token[]; /* 64 or more */ 120562306a36Sopenharmony_ci } kb; 120662306a36Sopenharmony_ci } __packed * preqparm; 120762306a36Sopenharmony_ci struct aurepparm { 120862306a36Sopenharmony_ci u8 subfunc_code[2]; 120962306a36Sopenharmony_ci u16 rule_array_len; 121062306a36Sopenharmony_ci struct { 121162306a36Sopenharmony_ci u16 len; 121262306a36Sopenharmony_ci u16 sublen; 121362306a36Sopenharmony_ci u16 tag; 121462306a36Sopenharmony_ci struct cpacfkeyblock { 121562306a36Sopenharmony_ci u8 version; /* version of this struct */ 121662306a36Sopenharmony_ci u8 flags[2]; 121762306a36Sopenharmony_ci u8 algo; 121862306a36Sopenharmony_ci u8 form; 121962306a36Sopenharmony_ci u8 pad1[3]; 122062306a36Sopenharmony_ci u16 keylen; 122162306a36Sopenharmony_ci u8 key[64]; /* the key (keylen bytes) */ 122262306a36Sopenharmony_ci u16 keyattrlen; 122362306a36Sopenharmony_ci u8 keyattr[32]; 122462306a36Sopenharmony_ci u8 pad2[1]; 122562306a36Sopenharmony_ci u8 vptype; 122662306a36Sopenharmony_ci u8 vp[32]; /* verification pattern */ 122762306a36Sopenharmony_ci } ckb; 122862306a36Sopenharmony_ci } vud; 122962306a36Sopenharmony_ci struct { 123062306a36Sopenharmony_ci u16 len; 123162306a36Sopenharmony_ci } kb; 123262306a36Sopenharmony_ci } __packed * prepparm; 123362306a36Sopenharmony_ci int keytoklen = ((struct cipherkeytoken *)ckey)->len; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 123662306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); 123762306a36Sopenharmony_ci if (rc) 123862306a36Sopenharmony_ci return rc; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* fill request cprb struct */ 124162306a36Sopenharmony_ci preqcblk->domain = domain; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* fill request cprb param block with AU request */ 124462306a36Sopenharmony_ci preqparm = (struct aureqparm __force *)preqcblk->req_parmb; 124562306a36Sopenharmony_ci memcpy(preqparm->subfunc_code, "AU", 2); 124662306a36Sopenharmony_ci preqparm->rule_array_len = 124762306a36Sopenharmony_ci sizeof(preqparm->rule_array_len) 124862306a36Sopenharmony_ci + sizeof(preqparm->rule_array); 124962306a36Sopenharmony_ci memcpy(preqparm->rule_array, "EXPT-SK ", 8); 125062306a36Sopenharmony_ci /* vud, tk blob */ 125162306a36Sopenharmony_ci preqparm->vud.len = sizeof(preqparm->vud); 125262306a36Sopenharmony_ci preqparm->vud.tk_blob_len = sizeof(preqparm->vud.tk_blob) 125362306a36Sopenharmony_ci + 2 * sizeof(uint16_t); 125462306a36Sopenharmony_ci preqparm->vud.tk_blob_tag = 0x00C2; 125562306a36Sopenharmony_ci /* kb, cca token */ 125662306a36Sopenharmony_ci preqparm->kb.len = keytoklen + 3 * sizeof(uint16_t); 125762306a36Sopenharmony_ci preqparm->kb.cca_key_token_len = keytoklen + 2 * sizeof(uint16_t); 125862306a36Sopenharmony_ci memcpy(preqparm->kb.cca_key_token, ckey, keytoklen); 125962306a36Sopenharmony_ci /* now fill length of param block into cprb */ 126062306a36Sopenharmony_ci preqcblk->req_parml = sizeof(struct aureqparm) + keytoklen; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* fill xcrb struct */ 126362306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 126662306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 126762306a36Sopenharmony_ci if (rc) { 126862306a36Sopenharmony_ci DEBUG_ERR( 126962306a36Sopenharmony_ci "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", 127062306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 127162306a36Sopenharmony_ci goto out; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* check response returncode and reasoncode */ 127562306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 127662306a36Sopenharmony_ci DEBUG_ERR( 127762306a36Sopenharmony_ci "%s unwrap secure key failure, card response %d/%d\n", 127862306a36Sopenharmony_ci __func__, 127962306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 128062306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 128162306a36Sopenharmony_ci if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290) 128262306a36Sopenharmony_ci rc = -EAGAIN; 128362306a36Sopenharmony_ci else 128462306a36Sopenharmony_ci rc = -EIO; 128562306a36Sopenharmony_ci goto out; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci if (prepcblk->ccp_rscode != 0) { 128862306a36Sopenharmony_ci DEBUG_WARN( 128962306a36Sopenharmony_ci "%s unwrap secure key warning, card response %d/%d\n", 129062306a36Sopenharmony_ci __func__, 129162306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 129262306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* process response cprb param block */ 129662306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 129762306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 129862306a36Sopenharmony_ci prepparm = (struct aurepparm *)ptr; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* check the returned keyblock */ 130162306a36Sopenharmony_ci if (prepparm->vud.ckb.version != 0x01 && 130262306a36Sopenharmony_ci prepparm->vud.ckb.version != 0x02) { 130362306a36Sopenharmony_ci DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x\n", 130462306a36Sopenharmony_ci __func__, (int)prepparm->vud.ckb.version); 130562306a36Sopenharmony_ci rc = -EIO; 130662306a36Sopenharmony_ci goto out; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci if (prepparm->vud.ckb.algo != 0x02) { 130962306a36Sopenharmony_ci DEBUG_ERR( 131062306a36Sopenharmony_ci "%s reply param keyblock algo mismatch 0x%02x != 0x02\n", 131162306a36Sopenharmony_ci __func__, (int)prepparm->vud.ckb.algo); 131262306a36Sopenharmony_ci rc = -EIO; 131362306a36Sopenharmony_ci goto out; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci /* copy the translated protected key */ 131762306a36Sopenharmony_ci switch (prepparm->vud.ckb.keylen) { 131862306a36Sopenharmony_ci case 16 + 32: 131962306a36Sopenharmony_ci /* AES 128 protected key */ 132062306a36Sopenharmony_ci if (protkeytype) 132162306a36Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_128; 132262306a36Sopenharmony_ci break; 132362306a36Sopenharmony_ci case 24 + 32: 132462306a36Sopenharmony_ci /* AES 192 protected key */ 132562306a36Sopenharmony_ci if (protkeytype) 132662306a36Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_192; 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci case 32 + 32: 132962306a36Sopenharmony_ci /* AES 256 protected key */ 133062306a36Sopenharmony_ci if (protkeytype) 133162306a36Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_AES_256; 133262306a36Sopenharmony_ci break; 133362306a36Sopenharmony_ci default: 133462306a36Sopenharmony_ci DEBUG_ERR("%s unknown/unsupported keylen %d\n", 133562306a36Sopenharmony_ci __func__, prepparm->vud.ckb.keylen); 133662306a36Sopenharmony_ci rc = -EIO; 133762306a36Sopenharmony_ci goto out; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci memcpy(protkey, prepparm->vud.ckb.key, prepparm->vud.ckb.keylen); 134062306a36Sopenharmony_ci if (protkeylen) 134162306a36Sopenharmony_ci *protkeylen = prepparm->vud.ckb.keylen; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ciout: 134462306a36Sopenharmony_ci free_cprbmem(mem, PARMBSIZE, 0); 134562306a36Sopenharmony_ci return rc; 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ciEXPORT_SYMBOL(cca_cipher2protkey); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci/* 135062306a36Sopenharmony_ci * Derive protected key from CCA ECC secure private key. 135162306a36Sopenharmony_ci */ 135262306a36Sopenharmony_ciint cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key, 135362306a36Sopenharmony_ci u8 *protkey, u32 *protkeylen, u32 *protkeytype) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci int rc; 135662306a36Sopenharmony_ci u8 *mem, *ptr; 135762306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 135862306a36Sopenharmony_ci struct ica_xcRB xcrb; 135962306a36Sopenharmony_ci struct aureqparm { 136062306a36Sopenharmony_ci u8 subfunc_code[2]; 136162306a36Sopenharmony_ci u16 rule_array_len; 136262306a36Sopenharmony_ci u8 rule_array[8]; 136362306a36Sopenharmony_ci struct { 136462306a36Sopenharmony_ci u16 len; 136562306a36Sopenharmony_ci u16 tk_blob_len; 136662306a36Sopenharmony_ci u16 tk_blob_tag; 136762306a36Sopenharmony_ci u8 tk_blob[66]; 136862306a36Sopenharmony_ci } vud; 136962306a36Sopenharmony_ci struct { 137062306a36Sopenharmony_ci u16 len; 137162306a36Sopenharmony_ci u16 cca_key_token_len; 137262306a36Sopenharmony_ci u16 cca_key_token_flags; 137362306a36Sopenharmony_ci u8 cca_key_token[]; 137462306a36Sopenharmony_ci } kb; 137562306a36Sopenharmony_ci } __packed * preqparm; 137662306a36Sopenharmony_ci struct aurepparm { 137762306a36Sopenharmony_ci u8 subfunc_code[2]; 137862306a36Sopenharmony_ci u16 rule_array_len; 137962306a36Sopenharmony_ci struct { 138062306a36Sopenharmony_ci u16 len; 138162306a36Sopenharmony_ci u16 sublen; 138262306a36Sopenharmony_ci u16 tag; 138362306a36Sopenharmony_ci struct cpacfkeyblock { 138462306a36Sopenharmony_ci u8 version; /* version of this struct */ 138562306a36Sopenharmony_ci u8 flags[2]; 138662306a36Sopenharmony_ci u8 algo; 138762306a36Sopenharmony_ci u8 form; 138862306a36Sopenharmony_ci u8 pad1[3]; 138962306a36Sopenharmony_ci u16 keylen; 139062306a36Sopenharmony_ci u8 key[]; /* the key (keylen bytes) */ 139162306a36Sopenharmony_ci /* u16 keyattrlen; */ 139262306a36Sopenharmony_ci /* u8 keyattr[32]; */ 139362306a36Sopenharmony_ci /* u8 pad2[1]; */ 139462306a36Sopenharmony_ci /* u8 vptype; */ 139562306a36Sopenharmony_ci /* u8 vp[32]; verification pattern */ 139662306a36Sopenharmony_ci } ckb; 139762306a36Sopenharmony_ci } vud; 139862306a36Sopenharmony_ci /* followed by a key block */ 139962306a36Sopenharmony_ci } __packed * prepparm; 140062306a36Sopenharmony_ci int keylen = ((struct eccprivkeytoken *)key)->len; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 140362306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); 140462306a36Sopenharmony_ci if (rc) 140562306a36Sopenharmony_ci return rc; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* fill request cprb struct */ 140862306a36Sopenharmony_ci preqcblk->domain = domain; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci /* fill request cprb param block with AU request */ 141162306a36Sopenharmony_ci preqparm = (struct aureqparm __force *)preqcblk->req_parmb; 141262306a36Sopenharmony_ci memcpy(preqparm->subfunc_code, "AU", 2); 141362306a36Sopenharmony_ci preqparm->rule_array_len = 141462306a36Sopenharmony_ci sizeof(preqparm->rule_array_len) 141562306a36Sopenharmony_ci + sizeof(preqparm->rule_array); 141662306a36Sopenharmony_ci memcpy(preqparm->rule_array, "EXPT-SK ", 8); 141762306a36Sopenharmony_ci /* vud, tk blob */ 141862306a36Sopenharmony_ci preqparm->vud.len = sizeof(preqparm->vud); 141962306a36Sopenharmony_ci preqparm->vud.tk_blob_len = sizeof(preqparm->vud.tk_blob) 142062306a36Sopenharmony_ci + 2 * sizeof(uint16_t); 142162306a36Sopenharmony_ci preqparm->vud.tk_blob_tag = 0x00C2; 142262306a36Sopenharmony_ci /* kb, cca token */ 142362306a36Sopenharmony_ci preqparm->kb.len = keylen + 3 * sizeof(uint16_t); 142462306a36Sopenharmony_ci preqparm->kb.cca_key_token_len = keylen + 2 * sizeof(uint16_t); 142562306a36Sopenharmony_ci memcpy(preqparm->kb.cca_key_token, key, keylen); 142662306a36Sopenharmony_ci /* now fill length of param block into cprb */ 142762306a36Sopenharmony_ci preqcblk->req_parml = sizeof(struct aureqparm) + keylen; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci /* fill xcrb struct */ 143062306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 143362306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 143462306a36Sopenharmony_ci if (rc) { 143562306a36Sopenharmony_ci DEBUG_ERR( 143662306a36Sopenharmony_ci "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", 143762306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 143862306a36Sopenharmony_ci goto out; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci /* check response returncode and reasoncode */ 144262306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 144362306a36Sopenharmony_ci DEBUG_ERR( 144462306a36Sopenharmony_ci "%s unwrap secure key failure, card response %d/%d\n", 144562306a36Sopenharmony_ci __func__, 144662306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 144762306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 144862306a36Sopenharmony_ci if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290) 144962306a36Sopenharmony_ci rc = -EAGAIN; 145062306a36Sopenharmony_ci else 145162306a36Sopenharmony_ci rc = -EIO; 145262306a36Sopenharmony_ci goto out; 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci if (prepcblk->ccp_rscode != 0) { 145562306a36Sopenharmony_ci DEBUG_WARN( 145662306a36Sopenharmony_ci "%s unwrap secure key warning, card response %d/%d\n", 145762306a36Sopenharmony_ci __func__, 145862306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 145962306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* process response cprb param block */ 146362306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 146462306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 146562306a36Sopenharmony_ci prepparm = (struct aurepparm *)ptr; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* check the returned keyblock */ 146862306a36Sopenharmony_ci if (prepparm->vud.ckb.version != 0x02) { 146962306a36Sopenharmony_ci DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x != 0x02\n", 147062306a36Sopenharmony_ci __func__, (int)prepparm->vud.ckb.version); 147162306a36Sopenharmony_ci rc = -EIO; 147262306a36Sopenharmony_ci goto out; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci if (prepparm->vud.ckb.algo != 0x81) { 147562306a36Sopenharmony_ci DEBUG_ERR( 147662306a36Sopenharmony_ci "%s reply param keyblock algo mismatch 0x%02x != 0x81\n", 147762306a36Sopenharmony_ci __func__, (int)prepparm->vud.ckb.algo); 147862306a36Sopenharmony_ci rc = -EIO; 147962306a36Sopenharmony_ci goto out; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* copy the translated protected key */ 148362306a36Sopenharmony_ci if (prepparm->vud.ckb.keylen > *protkeylen) { 148462306a36Sopenharmony_ci DEBUG_ERR("%s prot keylen mismatch %d > buffersize %u\n", 148562306a36Sopenharmony_ci __func__, prepparm->vud.ckb.keylen, *protkeylen); 148662306a36Sopenharmony_ci rc = -EIO; 148762306a36Sopenharmony_ci goto out; 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci memcpy(protkey, prepparm->vud.ckb.key, prepparm->vud.ckb.keylen); 149062306a36Sopenharmony_ci *protkeylen = prepparm->vud.ckb.keylen; 149162306a36Sopenharmony_ci if (protkeytype) 149262306a36Sopenharmony_ci *protkeytype = PKEY_KEYTYPE_ECC; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ciout: 149562306a36Sopenharmony_ci free_cprbmem(mem, PARMBSIZE, 0); 149662306a36Sopenharmony_ci return rc; 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ciEXPORT_SYMBOL(cca_ecc2protkey); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci/* 150162306a36Sopenharmony_ci * query cryptographic facility from CCA adapter 150262306a36Sopenharmony_ci */ 150362306a36Sopenharmony_ciint cca_query_crypto_facility(u16 cardnr, u16 domain, 150462306a36Sopenharmony_ci const char *keyword, 150562306a36Sopenharmony_ci u8 *rarray, size_t *rarraylen, 150662306a36Sopenharmony_ci u8 *varray, size_t *varraylen) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci int rc; 150962306a36Sopenharmony_ci u16 len; 151062306a36Sopenharmony_ci u8 *mem, *ptr; 151162306a36Sopenharmony_ci struct CPRBX *preqcblk, *prepcblk; 151262306a36Sopenharmony_ci struct ica_xcRB xcrb; 151362306a36Sopenharmony_ci struct fqreqparm { 151462306a36Sopenharmony_ci u8 subfunc_code[2]; 151562306a36Sopenharmony_ci u16 rule_array_len; 151662306a36Sopenharmony_ci char rule_array[8]; 151762306a36Sopenharmony_ci struct lv1 { 151862306a36Sopenharmony_ci u16 len; 151962306a36Sopenharmony_ci u8 data[VARDATASIZE]; 152062306a36Sopenharmony_ci } lv1; 152162306a36Sopenharmony_ci u16 dummylen; 152262306a36Sopenharmony_ci } __packed * preqparm; 152362306a36Sopenharmony_ci size_t parmbsize = sizeof(struct fqreqparm); 152462306a36Sopenharmony_ci struct fqrepparm { 152562306a36Sopenharmony_ci u8 subfunc_code[2]; 152662306a36Sopenharmony_ci u8 lvdata[]; 152762306a36Sopenharmony_ci } __packed * prepparm; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci /* get already prepared memory for 2 cprbs with param block each */ 153062306a36Sopenharmony_ci rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk); 153162306a36Sopenharmony_ci if (rc) 153262306a36Sopenharmony_ci return rc; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* fill request cprb struct */ 153562306a36Sopenharmony_ci preqcblk->domain = domain; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci /* fill request cprb param block with FQ request */ 153862306a36Sopenharmony_ci preqparm = (struct fqreqparm __force *)preqcblk->req_parmb; 153962306a36Sopenharmony_ci memcpy(preqparm->subfunc_code, "FQ", 2); 154062306a36Sopenharmony_ci memcpy(preqparm->rule_array, keyword, sizeof(preqparm->rule_array)); 154162306a36Sopenharmony_ci preqparm->rule_array_len = 154262306a36Sopenharmony_ci sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); 154362306a36Sopenharmony_ci preqparm->lv1.len = sizeof(preqparm->lv1); 154462306a36Sopenharmony_ci preqparm->dummylen = sizeof(preqparm->dummylen); 154562306a36Sopenharmony_ci preqcblk->req_parml = parmbsize; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci /* fill xcrb struct */ 154862306a36Sopenharmony_ci prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ 155162306a36Sopenharmony_ci rc = zcrypt_send_cprb(&xcrb); 155262306a36Sopenharmony_ci if (rc) { 155362306a36Sopenharmony_ci DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", 155462306a36Sopenharmony_ci __func__, (int)cardnr, (int)domain, rc); 155562306a36Sopenharmony_ci goto out; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci /* check response returncode and reasoncode */ 155962306a36Sopenharmony_ci if (prepcblk->ccp_rtcode != 0) { 156062306a36Sopenharmony_ci DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n", 156162306a36Sopenharmony_ci __func__, 156262306a36Sopenharmony_ci (int)prepcblk->ccp_rtcode, 156362306a36Sopenharmony_ci (int)prepcblk->ccp_rscode); 156462306a36Sopenharmony_ci rc = -EIO; 156562306a36Sopenharmony_ci goto out; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci /* process response cprb param block */ 156962306a36Sopenharmony_ci ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); 157062306a36Sopenharmony_ci prepcblk->rpl_parmb = (u8 __user *)ptr; 157162306a36Sopenharmony_ci prepparm = (struct fqrepparm *)ptr; 157262306a36Sopenharmony_ci ptr = prepparm->lvdata; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci /* check and possibly copy reply rule array */ 157562306a36Sopenharmony_ci len = *((u16 *)ptr); 157662306a36Sopenharmony_ci if (len > sizeof(u16)) { 157762306a36Sopenharmony_ci ptr += sizeof(u16); 157862306a36Sopenharmony_ci len -= sizeof(u16); 157962306a36Sopenharmony_ci if (rarray && rarraylen && *rarraylen > 0) { 158062306a36Sopenharmony_ci *rarraylen = (len > *rarraylen ? *rarraylen : len); 158162306a36Sopenharmony_ci memcpy(rarray, ptr, *rarraylen); 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci ptr += len; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci /* check and possible copy reply var array */ 158662306a36Sopenharmony_ci len = *((u16 *)ptr); 158762306a36Sopenharmony_ci if (len > sizeof(u16)) { 158862306a36Sopenharmony_ci ptr += sizeof(u16); 158962306a36Sopenharmony_ci len -= sizeof(u16); 159062306a36Sopenharmony_ci if (varray && varraylen && *varraylen > 0) { 159162306a36Sopenharmony_ci *varraylen = (len > *varraylen ? *varraylen : len); 159262306a36Sopenharmony_ci memcpy(varray, ptr, *varraylen); 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci ptr += len; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ciout: 159862306a36Sopenharmony_ci free_cprbmem(mem, parmbsize, 0); 159962306a36Sopenharmony_ci return rc; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ciEXPORT_SYMBOL(cca_query_crypto_facility); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic int cca_info_cache_fetch(u16 cardnr, u16 domain, struct cca_info *ci) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci int rc = -ENOENT; 160662306a36Sopenharmony_ci struct cca_info_list_entry *ptr; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci spin_lock_bh(&cca_info_list_lock); 160962306a36Sopenharmony_ci list_for_each_entry(ptr, &cca_info_list, list) { 161062306a36Sopenharmony_ci if (ptr->cardnr == cardnr && ptr->domain == domain) { 161162306a36Sopenharmony_ci memcpy(ci, &ptr->info, sizeof(*ci)); 161262306a36Sopenharmony_ci rc = 0; 161362306a36Sopenharmony_ci break; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci spin_unlock_bh(&cca_info_list_lock); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci return rc; 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic void cca_info_cache_update(u16 cardnr, u16 domain, 162262306a36Sopenharmony_ci const struct cca_info *ci) 162362306a36Sopenharmony_ci{ 162462306a36Sopenharmony_ci int found = 0; 162562306a36Sopenharmony_ci struct cca_info_list_entry *ptr; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci spin_lock_bh(&cca_info_list_lock); 162862306a36Sopenharmony_ci list_for_each_entry(ptr, &cca_info_list, list) { 162962306a36Sopenharmony_ci if (ptr->cardnr == cardnr && 163062306a36Sopenharmony_ci ptr->domain == domain) { 163162306a36Sopenharmony_ci memcpy(&ptr->info, ci, sizeof(*ci)); 163262306a36Sopenharmony_ci found = 1; 163362306a36Sopenharmony_ci break; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci if (!found) { 163762306a36Sopenharmony_ci ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); 163862306a36Sopenharmony_ci if (!ptr) { 163962306a36Sopenharmony_ci spin_unlock_bh(&cca_info_list_lock); 164062306a36Sopenharmony_ci return; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci ptr->cardnr = cardnr; 164362306a36Sopenharmony_ci ptr->domain = domain; 164462306a36Sopenharmony_ci memcpy(&ptr->info, ci, sizeof(*ci)); 164562306a36Sopenharmony_ci list_add(&ptr->list, &cca_info_list); 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci spin_unlock_bh(&cca_info_list_lock); 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cistatic void cca_info_cache_scrub(u16 cardnr, u16 domain) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci struct cca_info_list_entry *ptr; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci spin_lock_bh(&cca_info_list_lock); 165562306a36Sopenharmony_ci list_for_each_entry(ptr, &cca_info_list, list) { 165662306a36Sopenharmony_ci if (ptr->cardnr == cardnr && 165762306a36Sopenharmony_ci ptr->domain == domain) { 165862306a36Sopenharmony_ci list_del(&ptr->list); 165962306a36Sopenharmony_ci kfree(ptr); 166062306a36Sopenharmony_ci break; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci spin_unlock_bh(&cca_info_list_lock); 166462306a36Sopenharmony_ci} 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_cistatic void __exit mkvp_cache_free(void) 166762306a36Sopenharmony_ci{ 166862306a36Sopenharmony_ci struct cca_info_list_entry *ptr, *pnext; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci spin_lock_bh(&cca_info_list_lock); 167162306a36Sopenharmony_ci list_for_each_entry_safe(ptr, pnext, &cca_info_list, list) { 167262306a36Sopenharmony_ci list_del(&ptr->list); 167362306a36Sopenharmony_ci kfree(ptr); 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci spin_unlock_bh(&cca_info_list_lock); 167662306a36Sopenharmony_ci} 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci/* 167962306a36Sopenharmony_ci * Fetch cca_info values via query_crypto_facility from adapter. 168062306a36Sopenharmony_ci */ 168162306a36Sopenharmony_cistatic int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) 168262306a36Sopenharmony_ci{ 168362306a36Sopenharmony_ci int rc, found = 0; 168462306a36Sopenharmony_ci size_t rlen, vlen; 168562306a36Sopenharmony_ci u8 *rarray, *varray, *pg; 168662306a36Sopenharmony_ci struct zcrypt_device_status_ext devstat; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci memset(ci, 0, sizeof(*ci)); 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci /* get first info from zcrypt device driver about this apqn */ 169162306a36Sopenharmony_ci rc = zcrypt_device_status_ext(cardnr, domain, &devstat); 169262306a36Sopenharmony_ci if (rc) 169362306a36Sopenharmony_ci return rc; 169462306a36Sopenharmony_ci ci->hwtype = devstat.hwtype; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci /* prep page for rule array and var array use */ 169762306a36Sopenharmony_ci pg = (u8 *)__get_free_page(GFP_KERNEL); 169862306a36Sopenharmony_ci if (!pg) 169962306a36Sopenharmony_ci return -ENOMEM; 170062306a36Sopenharmony_ci rarray = pg; 170162306a36Sopenharmony_ci varray = pg + PAGE_SIZE / 2; 170262306a36Sopenharmony_ci rlen = vlen = PAGE_SIZE / 2; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci /* QF for this card/domain */ 170562306a36Sopenharmony_ci rc = cca_query_crypto_facility(cardnr, domain, "STATICSA", 170662306a36Sopenharmony_ci rarray, &rlen, varray, &vlen); 170762306a36Sopenharmony_ci if (rc == 0 && rlen >= 10 * 8 && vlen >= 204) { 170862306a36Sopenharmony_ci memcpy(ci->serial, rarray, 8); 170962306a36Sopenharmony_ci ci->new_asym_mk_state = (char)rarray[4 * 8]; 171062306a36Sopenharmony_ci ci->cur_asym_mk_state = (char)rarray[5 * 8]; 171162306a36Sopenharmony_ci ci->old_asym_mk_state = (char)rarray[6 * 8]; 171262306a36Sopenharmony_ci if (ci->old_asym_mk_state == '2') 171362306a36Sopenharmony_ci memcpy(ci->old_asym_mkvp, varray + 64, 16); 171462306a36Sopenharmony_ci if (ci->cur_asym_mk_state == '2') 171562306a36Sopenharmony_ci memcpy(ci->cur_asym_mkvp, varray + 84, 16); 171662306a36Sopenharmony_ci if (ci->new_asym_mk_state == '3') 171762306a36Sopenharmony_ci memcpy(ci->new_asym_mkvp, varray + 104, 16); 171862306a36Sopenharmony_ci ci->new_aes_mk_state = (char)rarray[7 * 8]; 171962306a36Sopenharmony_ci ci->cur_aes_mk_state = (char)rarray[8 * 8]; 172062306a36Sopenharmony_ci ci->old_aes_mk_state = (char)rarray[9 * 8]; 172162306a36Sopenharmony_ci if (ci->old_aes_mk_state == '2') 172262306a36Sopenharmony_ci memcpy(&ci->old_aes_mkvp, varray + 172, 8); 172362306a36Sopenharmony_ci if (ci->cur_aes_mk_state == '2') 172462306a36Sopenharmony_ci memcpy(&ci->cur_aes_mkvp, varray + 184, 8); 172562306a36Sopenharmony_ci if (ci->new_aes_mk_state == '3') 172662306a36Sopenharmony_ci memcpy(&ci->new_aes_mkvp, varray + 196, 8); 172762306a36Sopenharmony_ci found++; 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci if (!found) 173062306a36Sopenharmony_ci goto out; 173162306a36Sopenharmony_ci rlen = vlen = PAGE_SIZE / 2; 173262306a36Sopenharmony_ci rc = cca_query_crypto_facility(cardnr, domain, "STATICSB", 173362306a36Sopenharmony_ci rarray, &rlen, varray, &vlen); 173462306a36Sopenharmony_ci if (rc == 0 && rlen >= 13 * 8 && vlen >= 240) { 173562306a36Sopenharmony_ci ci->new_apka_mk_state = (char)rarray[10 * 8]; 173662306a36Sopenharmony_ci ci->cur_apka_mk_state = (char)rarray[11 * 8]; 173762306a36Sopenharmony_ci ci->old_apka_mk_state = (char)rarray[12 * 8]; 173862306a36Sopenharmony_ci if (ci->old_apka_mk_state == '2') 173962306a36Sopenharmony_ci memcpy(&ci->old_apka_mkvp, varray + 208, 8); 174062306a36Sopenharmony_ci if (ci->cur_apka_mk_state == '2') 174162306a36Sopenharmony_ci memcpy(&ci->cur_apka_mkvp, varray + 220, 8); 174262306a36Sopenharmony_ci if (ci->new_apka_mk_state == '3') 174362306a36Sopenharmony_ci memcpy(&ci->new_apka_mkvp, varray + 232, 8); 174462306a36Sopenharmony_ci found++; 174562306a36Sopenharmony_ci } 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ciout: 174862306a36Sopenharmony_ci free_page((unsigned long)pg); 174962306a36Sopenharmony_ci return found == 2 ? 0 : -ENOENT; 175062306a36Sopenharmony_ci} 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci/* 175362306a36Sopenharmony_ci * Fetch cca information about a CCA queue. 175462306a36Sopenharmony_ci */ 175562306a36Sopenharmony_ciint cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci int rc; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci rc = cca_info_cache_fetch(card, dom, ci); 176062306a36Sopenharmony_ci if (rc || verify) { 176162306a36Sopenharmony_ci rc = fetch_cca_info(card, dom, ci); 176262306a36Sopenharmony_ci if (rc == 0) 176362306a36Sopenharmony_ci cca_info_cache_update(card, dom, ci); 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci return rc; 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ciEXPORT_SYMBOL(cca_get_info); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci/* 177162306a36Sopenharmony_ci * Search for a matching crypto card based on the 177262306a36Sopenharmony_ci * Master Key Verification Pattern given. 177362306a36Sopenharmony_ci */ 177462306a36Sopenharmony_cistatic int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, 177562306a36Sopenharmony_ci int verify, int minhwtype) 177662306a36Sopenharmony_ci{ 177762306a36Sopenharmony_ci struct zcrypt_device_status_ext *device_status; 177862306a36Sopenharmony_ci u16 card, dom; 177962306a36Sopenharmony_ci struct cca_info ci; 178062306a36Sopenharmony_ci int i, rc, oi = -1; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci /* mkvp must not be zero, minhwtype needs to be >= 0 */ 178362306a36Sopenharmony_ci if (mkvp == 0 || minhwtype < 0) 178462306a36Sopenharmony_ci return -EINVAL; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* fetch status of all crypto cards */ 178762306a36Sopenharmony_ci device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT, 178862306a36Sopenharmony_ci sizeof(struct zcrypt_device_status_ext), 178962306a36Sopenharmony_ci GFP_KERNEL); 179062306a36Sopenharmony_ci if (!device_status) 179162306a36Sopenharmony_ci return -ENOMEM; 179262306a36Sopenharmony_ci zcrypt_device_status_mask_ext(device_status); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci /* walk through all crypto cards */ 179562306a36Sopenharmony_ci for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { 179662306a36Sopenharmony_ci card = AP_QID_CARD(device_status[i].qid); 179762306a36Sopenharmony_ci dom = AP_QID_QUEUE(device_status[i].qid); 179862306a36Sopenharmony_ci if (device_status[i].online && 179962306a36Sopenharmony_ci device_status[i].functions & 0x04) { 180062306a36Sopenharmony_ci /* enabled CCA card, check current mkvp from cache */ 180162306a36Sopenharmony_ci if (cca_info_cache_fetch(card, dom, &ci) == 0 && 180262306a36Sopenharmony_ci ci.hwtype >= minhwtype && 180362306a36Sopenharmony_ci ci.cur_aes_mk_state == '2' && 180462306a36Sopenharmony_ci ci.cur_aes_mkvp == mkvp) { 180562306a36Sopenharmony_ci if (!verify) 180662306a36Sopenharmony_ci break; 180762306a36Sopenharmony_ci /* verify: refresh card info */ 180862306a36Sopenharmony_ci if (fetch_cca_info(card, dom, &ci) == 0) { 180962306a36Sopenharmony_ci cca_info_cache_update(card, dom, &ci); 181062306a36Sopenharmony_ci if (ci.hwtype >= minhwtype && 181162306a36Sopenharmony_ci ci.cur_aes_mk_state == '2' && 181262306a36Sopenharmony_ci ci.cur_aes_mkvp == mkvp) 181362306a36Sopenharmony_ci break; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci } else { 181762306a36Sopenharmony_ci /* Card is offline and/or not a CCA card. */ 181862306a36Sopenharmony_ci /* del mkvp entry from cache if it exists */ 181962306a36Sopenharmony_ci cca_info_cache_scrub(card, dom); 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci } 182262306a36Sopenharmony_ci if (i >= MAX_ZDEV_ENTRIES_EXT) { 182362306a36Sopenharmony_ci /* nothing found, so this time without cache */ 182462306a36Sopenharmony_ci for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { 182562306a36Sopenharmony_ci if (!(device_status[i].online && 182662306a36Sopenharmony_ci device_status[i].functions & 0x04)) 182762306a36Sopenharmony_ci continue; 182862306a36Sopenharmony_ci card = AP_QID_CARD(device_status[i].qid); 182962306a36Sopenharmony_ci dom = AP_QID_QUEUE(device_status[i].qid); 183062306a36Sopenharmony_ci /* fresh fetch mkvp from adapter */ 183162306a36Sopenharmony_ci if (fetch_cca_info(card, dom, &ci) == 0) { 183262306a36Sopenharmony_ci cca_info_cache_update(card, dom, &ci); 183362306a36Sopenharmony_ci if (ci.hwtype >= minhwtype && 183462306a36Sopenharmony_ci ci.cur_aes_mk_state == '2' && 183562306a36Sopenharmony_ci ci.cur_aes_mkvp == mkvp) 183662306a36Sopenharmony_ci break; 183762306a36Sopenharmony_ci if (ci.hwtype >= minhwtype && 183862306a36Sopenharmony_ci ci.old_aes_mk_state == '2' && 183962306a36Sopenharmony_ci ci.old_aes_mkvp == mkvp && 184062306a36Sopenharmony_ci oi < 0) 184162306a36Sopenharmony_ci oi = i; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci if (i >= MAX_ZDEV_ENTRIES_EXT && oi >= 0) { 184562306a36Sopenharmony_ci /* old mkvp matched, use this card then */ 184662306a36Sopenharmony_ci card = AP_QID_CARD(device_status[oi].qid); 184762306a36Sopenharmony_ci dom = AP_QID_QUEUE(device_status[oi].qid); 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci if (i < MAX_ZDEV_ENTRIES_EXT || oi >= 0) { 185162306a36Sopenharmony_ci if (pcardnr) 185262306a36Sopenharmony_ci *pcardnr = card; 185362306a36Sopenharmony_ci if (pdomain) 185462306a36Sopenharmony_ci *pdomain = dom; 185562306a36Sopenharmony_ci rc = (i < MAX_ZDEV_ENTRIES_EXT ? 0 : 1); 185662306a36Sopenharmony_ci } else { 185762306a36Sopenharmony_ci rc = -ENODEV; 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci kvfree(device_status); 186162306a36Sopenharmony_ci return rc; 186262306a36Sopenharmony_ci} 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci/* 186562306a36Sopenharmony_ci * Search for a matching crypto card based on the Master Key 186662306a36Sopenharmony_ci * Verification Pattern provided inside a secure key token. 186762306a36Sopenharmony_ci */ 186862306a36Sopenharmony_ciint cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) 186962306a36Sopenharmony_ci{ 187062306a36Sopenharmony_ci u64 mkvp; 187162306a36Sopenharmony_ci int minhwtype = 0; 187262306a36Sopenharmony_ci const struct keytoken_header *hdr = (struct keytoken_header *)key; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci if (hdr->type != TOKTYPE_CCA_INTERNAL) 187562306a36Sopenharmony_ci return -EINVAL; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci switch (hdr->version) { 187862306a36Sopenharmony_ci case TOKVER_CCA_AES: 187962306a36Sopenharmony_ci mkvp = ((struct secaeskeytoken *)key)->mkvp; 188062306a36Sopenharmony_ci break; 188162306a36Sopenharmony_ci case TOKVER_CCA_VLSC: 188262306a36Sopenharmony_ci mkvp = ((struct cipherkeytoken *)key)->mkvp0; 188362306a36Sopenharmony_ci minhwtype = AP_DEVICE_TYPE_CEX6; 188462306a36Sopenharmony_ci break; 188562306a36Sopenharmony_ci default: 188662306a36Sopenharmony_ci return -EINVAL; 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci return findcard(mkvp, pcardnr, pdomain, verify, minhwtype); 189062306a36Sopenharmony_ci} 189162306a36Sopenharmony_ciEXPORT_SYMBOL(cca_findcard); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ciint cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, 189462306a36Sopenharmony_ci int minhwtype, int mktype, u64 cur_mkvp, u64 old_mkvp, 189562306a36Sopenharmony_ci int verify) 189662306a36Sopenharmony_ci{ 189762306a36Sopenharmony_ci struct zcrypt_device_status_ext *device_status; 189862306a36Sopenharmony_ci u32 *_apqns = NULL, _nr_apqns = 0; 189962306a36Sopenharmony_ci int i, card, dom, curmatch, oldmatch, rc = 0; 190062306a36Sopenharmony_ci struct cca_info ci; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* fetch status of all crypto cards */ 190362306a36Sopenharmony_ci device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT, 190462306a36Sopenharmony_ci sizeof(struct zcrypt_device_status_ext), 190562306a36Sopenharmony_ci GFP_KERNEL); 190662306a36Sopenharmony_ci if (!device_status) 190762306a36Sopenharmony_ci return -ENOMEM; 190862306a36Sopenharmony_ci zcrypt_device_status_mask_ext(device_status); 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci /* allocate 1k space for up to 256 apqns */ 191162306a36Sopenharmony_ci _apqns = kmalloc_array(256, sizeof(u32), GFP_KERNEL); 191262306a36Sopenharmony_ci if (!_apqns) { 191362306a36Sopenharmony_ci kvfree(device_status); 191462306a36Sopenharmony_ci return -ENOMEM; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci /* walk through all the crypto apqnss */ 191862306a36Sopenharmony_ci for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { 191962306a36Sopenharmony_ci card = AP_QID_CARD(device_status[i].qid); 192062306a36Sopenharmony_ci dom = AP_QID_QUEUE(device_status[i].qid); 192162306a36Sopenharmony_ci /* check online state */ 192262306a36Sopenharmony_ci if (!device_status[i].online) 192362306a36Sopenharmony_ci continue; 192462306a36Sopenharmony_ci /* check for cca functions */ 192562306a36Sopenharmony_ci if (!(device_status[i].functions & 0x04)) 192662306a36Sopenharmony_ci continue; 192762306a36Sopenharmony_ci /* check cardnr */ 192862306a36Sopenharmony_ci if (cardnr != 0xFFFF && card != cardnr) 192962306a36Sopenharmony_ci continue; 193062306a36Sopenharmony_ci /* check domain */ 193162306a36Sopenharmony_ci if (domain != 0xFFFF && dom != domain) 193262306a36Sopenharmony_ci continue; 193362306a36Sopenharmony_ci /* get cca info on this apqn */ 193462306a36Sopenharmony_ci if (cca_get_info(card, dom, &ci, verify)) 193562306a36Sopenharmony_ci continue; 193662306a36Sopenharmony_ci /* current master key needs to be valid */ 193762306a36Sopenharmony_ci if (mktype == AES_MK_SET && ci.cur_aes_mk_state != '2') 193862306a36Sopenharmony_ci continue; 193962306a36Sopenharmony_ci if (mktype == APKA_MK_SET && ci.cur_apka_mk_state != '2') 194062306a36Sopenharmony_ci continue; 194162306a36Sopenharmony_ci /* check min hardware type */ 194262306a36Sopenharmony_ci if (minhwtype > 0 && minhwtype > ci.hwtype) 194362306a36Sopenharmony_ci continue; 194462306a36Sopenharmony_ci if (cur_mkvp || old_mkvp) { 194562306a36Sopenharmony_ci /* check mkvps */ 194662306a36Sopenharmony_ci curmatch = oldmatch = 0; 194762306a36Sopenharmony_ci if (mktype == AES_MK_SET) { 194862306a36Sopenharmony_ci if (cur_mkvp && cur_mkvp == ci.cur_aes_mkvp) 194962306a36Sopenharmony_ci curmatch = 1; 195062306a36Sopenharmony_ci if (old_mkvp && ci.old_aes_mk_state == '2' && 195162306a36Sopenharmony_ci old_mkvp == ci.old_aes_mkvp) 195262306a36Sopenharmony_ci oldmatch = 1; 195362306a36Sopenharmony_ci } else { 195462306a36Sopenharmony_ci if (cur_mkvp && cur_mkvp == ci.cur_apka_mkvp) 195562306a36Sopenharmony_ci curmatch = 1; 195662306a36Sopenharmony_ci if (old_mkvp && ci.old_apka_mk_state == '2' && 195762306a36Sopenharmony_ci old_mkvp == ci.old_apka_mkvp) 195862306a36Sopenharmony_ci oldmatch = 1; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci if (curmatch + oldmatch < 1) 196162306a36Sopenharmony_ci continue; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci /* apqn passed all filtering criterons, add to the array */ 196462306a36Sopenharmony_ci if (_nr_apqns < 256) 196562306a36Sopenharmony_ci _apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom); 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci /* nothing found ? */ 196962306a36Sopenharmony_ci if (!_nr_apqns) { 197062306a36Sopenharmony_ci kfree(_apqns); 197162306a36Sopenharmony_ci rc = -ENODEV; 197262306a36Sopenharmony_ci } else { 197362306a36Sopenharmony_ci /* no re-allocation, simple return the _apqns array */ 197462306a36Sopenharmony_ci *apqns = _apqns; 197562306a36Sopenharmony_ci *nr_apqns = _nr_apqns; 197662306a36Sopenharmony_ci rc = 0; 197762306a36Sopenharmony_ci } 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci kvfree(device_status); 198062306a36Sopenharmony_ci return rc; 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ciEXPORT_SYMBOL(cca_findcard2); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_civoid __exit zcrypt_ccamisc_exit(void) 198562306a36Sopenharmony_ci{ 198662306a36Sopenharmony_ci mkvp_cache_free(); 198762306a36Sopenharmony_ci} 1988