in crypto/zcrypt_ccamisc.c [744:936]
int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
u8 *keybuf, size_t *keybufsize)
{
int rc;
u8 *mem, *ptr;
struct CPRBX *preqcblk, *prepcblk;
struct ica_xcRB xcrb;
struct gkreqparm {
u8 subfunc_code[2];
u16 rule_array_len;
char rule_array[2*8];
struct {
u16 len;
u8 key_type_1[8];
u8 key_type_2[8];
u16 clear_key_bit_len;
u16 key_name_1_len;
u16 key_name_2_len;
u16 user_data_1_len;
u16 user_data_2_len;
u8 key_name_1[0];
u8 key_name_2[0];
u8 user_data_1[0];
u8 user_data_2[0];
} vud;
struct {
u16 len;
struct {
u16 len;
u16 flag;
u8 kek_id_1[0];
} tlv1;
struct {
u16 len;
u16 flag;
u8 kek_id_2[0];
} tlv2;
struct {
u16 len;
u16 flag;
u8 gen_key_id_1[SIZEOF_SKELETON];
} tlv3;
struct {
u16 len;
u16 flag;
u8 gen_key_id_1_label[0];
} tlv4;
struct {
u16 len;
u16 flag;
u8 gen_key_id_2[0];
} tlv5;
struct {
u16 len;
u16 flag;
u8 gen_key_id_2_label[0];
} tlv6;
} kb;
} __packed * preqparm;
struct gkrepparm {
u8 subfunc_code[2];
u16 rule_array_len;
struct {
u16 len;
} vud;
struct {
u16 len;
struct {
u16 len;
u16 flag;
u8 gen_key[0]; /* 120-136 bytes */
} tlv1;
} kb;
} __packed * prepparm;
struct cipherkeytoken *t;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
if (rc)
return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
preqcblk->req_parml = sizeof(struct gkreqparm);
/* prepare request param block with GK request */
preqparm = (struct gkreqparm __force *) preqcblk->req_parmb;
memcpy(preqparm->subfunc_code, "GK", 2);
preqparm->rule_array_len = sizeof(uint16_t) + 2 * 8;
memcpy(preqparm->rule_array, "AES OP ", 2*8);
/* prepare vud block */
preqparm->vud.len = sizeof(preqparm->vud);
switch (keybitsize) {
case 128:
case 192:
case 256:
break;
default:
DEBUG_ERR(
"%s unknown/unsupported keybitsize %d\n",
__func__, keybitsize);
rc = -EINVAL;
goto out;
}
preqparm->vud.clear_key_bit_len = keybitsize;
memcpy(preqparm->vud.key_type_1, "TOKEN ", 8);
memset(preqparm->vud.key_type_2, ' ', sizeof(preqparm->vud.key_type_2));
/* prepare kb block */
preqparm->kb.len = sizeof(preqparm->kb);
preqparm->kb.tlv1.len = sizeof(preqparm->kb.tlv1);
preqparm->kb.tlv1.flag = 0x0030;
preqparm->kb.tlv2.len = sizeof(preqparm->kb.tlv2);
preqparm->kb.tlv2.flag = 0x0030;
preqparm->kb.tlv3.len = sizeof(preqparm->kb.tlv3);
preqparm->kb.tlv3.flag = 0x0030;
memcpy(preqparm->kb.tlv3.gen_key_id_1,
aes_cipher_key_skeleton, SIZEOF_SKELETON);
preqparm->kb.tlv4.len = sizeof(preqparm->kb.tlv4);
preqparm->kb.tlv4.flag = 0x0030;
preqparm->kb.tlv5.len = sizeof(preqparm->kb.tlv5);
preqparm->kb.tlv5.flag = 0x0030;
preqparm->kb.tlv6.len = sizeof(preqparm->kb.tlv6);
preqparm->kb.tlv6.flag = 0x0030;
/* patch the skeleton key token export flags inside the kb block */
if (keygenflags) {
t = (struct cipherkeytoken *) preqparm->kb.tlv3.gen_key_id_1;
t->kmf1 |= (u16) (keygenflags & 0x0000FF00);
t->kmf1 &= (u16) ~(keygenflags & 0x000000FF);
}
/* prepare xcrb struct */
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = zcrypt_send_cprb(&xcrb);
if (rc) {
DEBUG_ERR(
"%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int) cardnr, (int) domain, rc);
goto out;
}
/* check response returncode and reasoncode */
if (prepcblk->ccp_rtcode != 0) {
DEBUG_ERR(
"%s cipher key generate failure, card response %d/%d\n",
__func__,
(int) prepcblk->ccp_rtcode,
(int) prepcblk->ccp_rscode);
rc = -EIO;
goto out;
}
/* process response cprb param block */
ptr = ((u8 *) prepcblk) + sizeof(struct CPRBX);
prepcblk->rpl_parmb = (u8 __user *) ptr;
prepparm = (struct gkrepparm *) ptr;
/* do some plausibility checks on the key block */
if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) ||
prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) {
DEBUG_ERR("%s reply with invalid or unknown key block\n",
__func__);
rc = -EIO;
goto out;
}
/* and some checks on the generated key */
rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR,
prepparm->kb.tlv1.gen_key,
keybitsize, 1);
if (rc) {
rc = -EIO;
goto out;
}
/* copy the generated vlsc key token */
t = (struct cipherkeytoken *) prepparm->kb.tlv1.gen_key;
if (keybuf) {
if (*keybufsize >= t->len)
memcpy(keybuf, t, t->len);
else
rc = -EINVAL;
}
*keybufsize = t->len;
out:
free_cprbmem(mem, PARMBSIZE, 0);
return rc;
}