in crypto/zcrypt_ccamisc.c [942:1092]
static int _ip_cprb_helper(u16 cardnr, u16 domain,
const char *rule_array_1,
const char *rule_array_2,
const char *rule_array_3,
const u8 *clr_key_value,
int clr_key_bit_size,
u8 *key_token,
int *key_token_size)
{
int rc, n;
u8 *mem, *ptr;
struct CPRBX *preqcblk, *prepcblk;
struct ica_xcRB xcrb;
struct rule_array_block {
u8 subfunc_code[2];
u16 rule_array_len;
char rule_array[0];
} __packed * preq_ra_block;
struct vud_block {
u16 len;
struct {
u16 len;
u16 flag; /* 0x0064 */
u16 clr_key_bit_len;
} tlv1;
struct {
u16 len;
u16 flag; /* 0x0063 */
u8 clr_key[0]; /* clear key value bytes */
} tlv2;
} __packed * preq_vud_block;
struct key_block {
u16 len;
struct {
u16 len;
u16 flag; /* 0x0030 */
u8 key_token[0]; /* key skeleton */
} tlv1;
} __packed * preq_key_block;
struct iprepparm {
u8 subfunc_code[2];
u16 rule_array_len;
struct {
u16 len;
} vud;
struct {
u16 len;
struct {
u16 len;
u16 flag; /* 0x0030 */
u8 key_token[0]; /* key token */
} tlv1;
} kb;
} __packed * prepparm;
struct cipherkeytoken *t;
int complete = strncmp(rule_array_2, "COMPLETE", 8) ? 0 : 1;
/* 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 = 0;
/* prepare request param block with IP request */
preq_ra_block = (struct rule_array_block __force *) preqcblk->req_parmb;
memcpy(preq_ra_block->subfunc_code, "IP", 2);
preq_ra_block->rule_array_len = sizeof(uint16_t) + 2 * 8;
memcpy(preq_ra_block->rule_array, rule_array_1, 8);
memcpy(preq_ra_block->rule_array + 8, rule_array_2, 8);
preqcblk->req_parml = sizeof(struct rule_array_block) + 2 * 8;
if (rule_array_3) {
preq_ra_block->rule_array_len += 8;
memcpy(preq_ra_block->rule_array + 16, rule_array_3, 8);
preqcblk->req_parml += 8;
}
/* prepare vud block */
preq_vud_block = (struct vud_block __force *)
(preqcblk->req_parmb + preqcblk->req_parml);
n = complete ? 0 : (clr_key_bit_size + 7) / 8;
preq_vud_block->len = sizeof(struct vud_block) + n;
preq_vud_block->tlv1.len = sizeof(preq_vud_block->tlv1);
preq_vud_block->tlv1.flag = 0x0064;
preq_vud_block->tlv1.clr_key_bit_len = complete ? 0 : clr_key_bit_size;
preq_vud_block->tlv2.len = sizeof(preq_vud_block->tlv2) + n;
preq_vud_block->tlv2.flag = 0x0063;
if (!complete)
memcpy(preq_vud_block->tlv2.clr_key, clr_key_value, n);
preqcblk->req_parml += preq_vud_block->len;
/* prepare key block */
preq_key_block = (struct key_block __force *)
(preqcblk->req_parmb + preqcblk->req_parml);
n = *key_token_size;
preq_key_block->len = sizeof(struct key_block) + n;
preq_key_block->tlv1.len = sizeof(preq_key_block->tlv1) + n;
preq_key_block->tlv1.flag = 0x0030;
memcpy(preq_key_block->tlv1.key_token, key_token, *key_token_size);
preqcblk->req_parml += preq_key_block->len;
/* 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 CSNBKPI2 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 iprepparm *) ptr;
/* do some plausibility checks on the key block */
if (prepparm->kb.len < 120 + 3 * sizeof(uint16_t) ||
prepparm->kb.len > 136 + 3 * sizeof(uint16_t)) {
DEBUG_ERR("%s reply with invalid or unknown key block\n",
__func__);
rc = -EIO;
goto out;
}
/* do not check the key here, it may be incomplete */
/* copy the vlsc key token back */
t = (struct cipherkeytoken *) prepparm->kb.tlv1.key_token;
memcpy(key_token, t, t->len);
*key_token_size = t->len;
out:
free_cprbmem(mem, PARMBSIZE, 0);
return rc;
}