int cca_sec2protkey()

in crypto/zcrypt_ccamisc.c [579:722]


int cca_sec2protkey(u16 cardnr, u16 domain,
		    const u8 *seckey, u8 *protkey, u32 *protkeylen,
		    u32 *protkeytype)
{
	int rc;
	u8 *mem, *ptr;
	struct CPRBX *preqcblk, *prepcblk;
	struct ica_xcRB xcrb;
	struct uskreqparm {
		u8  subfunc_code[2];
		u16 rule_array_len;
		struct lv1 {
			u16 len;
			u16 attr_len;
			u16 attr_flags;
		} lv1;
		struct lv2 {
			u16 len;
			u16 attr_len;
			u16 attr_flags;
			u8  token[];	      /* cca secure key token */
		} lv2;
	} __packed * preqparm;
	struct uskrepparm {
		u8  subfunc_code[2];
		u16 rule_array_len;
		struct lv3 {
			u16 len;
			u16 attr_len;
			u16 attr_flags;
			struct cpacfkeyblock {
				u8  version;  /* version of this struct */
				u8  flags[2];
				u8  algo;
				u8  form;
				u8  pad1[3];
				u16 len;
				u8  key[64];  /* the key (len bytes) */
				u16 keyattrlen;
				u8  keyattr[32];
				u8  pad2[1];
				u8  vptype;
				u8  vp[32];  /* verification pattern */
			} ckb;
		} lv3;
	} __packed * prepparm;

	/* 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;

	/* fill request cprb param block with USK request */
	preqparm = (struct uskreqparm __force *) preqcblk->req_parmb;
	memcpy(preqparm->subfunc_code, "US", 2);
	preqparm->rule_array_len = sizeof(preqparm->rule_array_len);
	preqparm->lv1.len = sizeof(struct lv1);
	preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len);
	preqparm->lv1.attr_flags = 0x0001;
	preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE;
	preqparm->lv2.attr_len = sizeof(struct lv2)
		- sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE;
	preqparm->lv2.attr_flags = 0x0000;
	memcpy(preqparm->lv2.token, seckey, SECKEYBLOBSIZE);
	preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE;

	/* fill 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 unwrap secure key failure, card response %d/%d\n",
			  __func__,
			  (int) prepcblk->ccp_rtcode,
			  (int) prepcblk->ccp_rscode);
		if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290)
			rc = -EAGAIN;
		else
			rc = -EIO;
		goto out;
	}
	if (prepcblk->ccp_rscode != 0) {
		DEBUG_WARN("%s unwrap secure key warning, card response %d/%d\n",
			   __func__,
			   (int) prepcblk->ccp_rtcode,
			   (int) prepcblk->ccp_rscode);
	}

	/* process response cprb param block */
	ptr = ((u8 *) prepcblk) + sizeof(struct CPRBX);
	prepcblk->rpl_parmb = (u8 __user *) ptr;
	prepparm = (struct uskrepparm *) ptr;

	/* check the returned keyblock */
	if (prepparm->lv3.ckb.version != 0x01 &&
	    prepparm->lv3.ckb.version != 0x02) {
		DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x\n",
			  __func__, (int) prepparm->lv3.ckb.version);
		rc = -EIO;
		goto out;
	}

	/* copy the tanslated protected key */
	switch (prepparm->lv3.ckb.len) {
	case 16+32:
		/* AES 128 protected key */
		if (protkeytype)
			*protkeytype = PKEY_KEYTYPE_AES_128;
		break;
	case 24+32:
		/* AES 192 protected key */
		if (protkeytype)
			*protkeytype = PKEY_KEYTYPE_AES_192;
		break;
	case 32+32:
		/* AES 256 protected key */
		if (protkeytype)
			*protkeytype = PKEY_KEYTYPE_AES_256;
		break;
	default:
		DEBUG_ERR("%s unknown/unsupported keylen %d\n",
			  __func__, prepparm->lv3.ckb.len);
		rc = -EIO;
		goto out;
	}
	memcpy(protkey, prepparm->lv3.ckb.key, prepparm->lv3.ckb.len);
	if (protkeylen)
		*protkeylen = prepparm->lv3.ckb.len;

out:
	free_cprbmem(mem, PARMBSIZE, 0);
	return rc;
}