static int _ip_cprb_helper()

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;
}