⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 card-gpk.c

📁 读写Smart卡加解密接口的程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	fbuf[1] = fid & 0xff;	log_errs = card->ctx->log_errors;	card->ctx->log_errors = 0;	r = gpk_select(card, kind, fbuf, 2, file);	card->ctx->log_errors = log_errs;	/* Fix up the path cache.	 * NB we never cache the ID of an EF, just the DF path */	if (r == 0) {		unsigned short int	*path;		switch (kind) {		case GPK_SEL_MF:			cp->len = 0;			/* fallthru */		case GPK_SEL_DF:			assert(cp->len + 1 <= SC_MAX_PATH_SIZE / 2);			path = (unsigned short int *) cp->value;			path[cp->len++] = fid;		}	} else {		cp->len = 0;	}	return r;}static intgpk_select_file(struct sc_card *card, const struct sc_path *path,		struct sc_file **file){	unsigned short int	pathtmp[SC_MAX_PATH_SIZE/2];	unsigned short int	*pathptr;	size_t			pathlen, n;	int			locked = 0, r = 0, use_relative = 0, retry = 1;	u8			leaf_type;	SC_FUNC_CALLED(card->ctx, 1);	/* Handle the AID case first */	if (path->type == SC_PATH_TYPE_DF_NAME) {		if (path->len > 16)			return SC_ERROR_INVALID_ARGUMENTS;		r = gpk_select(card, GPK_SEL_AID,					path->value, path->len, file);		goto done;	}	/* Now we know we're dealing with 16bit FIDs, either as	 * an absolute path name (SC_PATH_TYPE_PATH) or a relative	 * FID (SC_PATH_TYPE_FILE_ID)	 *	 * The API should really tell us whether this is a DF or EF	 * we're selecting. All we can do is read tea leaves...	 */	leaf_type = GPK_SEL_EF;try_again:	if ((path->len & 1) || path->len > sizeof(pathtmp))		return SC_ERROR_INVALID_ARGUMENTS;	pathptr = pathtmp;	for (n = 0; n < path->len; n += 2)		pathptr[n>>1] = (path->value[n] << 8)|path->value[n+1];	pathlen = path->len >> 1;	/* See whether we can skip an initial portion of the	 * (absolute) path */	if (path->type == SC_PATH_TYPE_PATH) {		/* Do not retry selecting if this cannot be a DF */		if ((pathptr[0] == GPK_FID_MF && pathlen > 2)		 || (pathptr[0] != GPK_FID_MF && pathlen > 1))			retry = 0;		use_relative = match_path(card, &pathptr, &pathlen, file != 0);		if (pathlen == 0)			goto done;	} else {		/* SC_PATH_TYPE_FILEID */		if (pathlen > 1)			return SC_ERROR_INVALID_ARGUMENTS;		use_relative = 1;	}	if (pathlen == 1 && pathptr[0] == GPK_FID_MF) {		/* Select just the MF */		leaf_type = GPK_SEL_MF;	} else {		if (!locked++) {			r = sc_lock(card);			SC_TEST_RET(card->ctx, r, "sc_lock() failed");		}		/* Do we need to select the MF first? */		if (!use_relative) {			r = gpk_select_id(card, GPK_SEL_MF, GPK_FID_MF, NULL);			if (r)				sc_unlock(card);			SC_TEST_RET(card->ctx, r, "Unable to select MF");			/* Consume the MF FID if it's there */			if (pathptr[0] == GPK_FID_MF) {				pathptr++;				pathlen--;			}			if (pathlen == 0)				goto done;		}		/* Next comes a DF, if at all.		 * This loop can deal with nesting levels > 1 even		 * though the GPK4000 doesn't support it. */		while (pathlen > 1) {			r = gpk_select_id(card, GPK_SEL_DF, pathptr[0], NULL);			if (r)				sc_unlock(card);			SC_TEST_RET(card->ctx, r, "Unable to select DF");			pathptr++;			pathlen--;		}	}	/* Remaining component will be a DF or EF. How do we find out?	 * All we can do is try */	r = gpk_select_id(card, leaf_type, pathptr[0], file);	if (r) {		/* Did we guess EF, and were wrong? If so, invalidate		 * path cache and try again; this time aiming for a DF */		if (leaf_type == GPK_SEL_EF && retry) {			card->cache.current_path.len = 0;			leaf_type = GPK_SEL_DF;			goto try_again;		}	}done:	if (locked)		sc_unlock(card);	return r;}/* * GPK versions of {read,write,update}_binary functions. * Required because by default the GPKs do word offsets */static intgpk_read_binary(struct sc_card *card, unsigned int offset,		u8 *buf, size_t count, unsigned long flags){	struct gpk_private_data *priv = DRVDATA(card);	if (offset & priv->offset_mask) {		sc_error(card->ctx, "Invalid file offset (not a multiple of %d)",				priv->offset_mask + 1);		return SC_ERROR_INVALID_ARGUMENTS;	}	return iso_ops->read_binary(card, offset >> priv->offset_shift,			buf, count, flags);}static intgpk_write_binary(struct sc_card *card, unsigned int offset,		const u8 *buf, size_t count, unsigned long flags){	struct gpk_private_data *priv = DRVDATA(card);	if (offset & priv->offset_mask) {		sc_error(card->ctx, "Invalid file offset (not a multiple of %d)",				priv->offset_mask + 1);		return SC_ERROR_INVALID_ARGUMENTS;	}	return iso_ops->write_binary(card, offset >> priv->offset_shift,			buf, count, flags);}static intgpk_update_binary(struct sc_card *card, unsigned int offset,		const u8 *buf, size_t count, unsigned long flags){	struct gpk_private_data *priv = DRVDATA(card);	if (offset & priv->offset_mask) {		sc_error(card->ctx, "Invalid file offset (not a multiple of %d)",				priv->offset_mask + 1);		return SC_ERROR_INVALID_ARGUMENTS;	}	return iso_ops->update_binary(card, offset >> priv->offset_shift,			buf, count, flags);}/* * Secure messaging */static intgpk_compute_crycks(struct sc_card *card, struct sc_apdu *apdu,			u8 *crycks1){	struct gpk_private_data *priv = DRVDATA(card);	des_key_schedule k1, k2;	u8		in[8], out[8], block[64];	unsigned int	len = 0, i, j;	/* Set the key schedule */	DES_set_key_unchecked((des_cblock *) priv->key, &k1);	DES_set_key_unchecked((des_cblock *) (priv->key+8), &k2);	/* Fill block with 0x00 and then with the data. */	memset(block, 0x00, sizeof(block));	block[len++] = apdu->cla;	block[len++] = apdu->ins;	block[len++] = apdu->p1;	block[len++] = apdu->p2;	block[len++] = apdu->lc + 3;	if ((i = apdu->datalen) + len > sizeof(block))		i = sizeof(block) - len;	memcpy(block+len, apdu->data, i);	len += i;	/* Set IV */	memset(in, 0x00, 8);	for (j = 0; j < len; ) {		for (i = 0; i < 8; i++, j++)			in[i] ^= block[j];		DES_ecb3_encrypt((des_cblock *)in,				 (des_cblock *)out,				 &k1, &k2, &k1, DES_ENCRYPT);		memcpy(in, out, 8);	}	memcpy((u8 *) (apdu->data + apdu->datalen), out + 5, 3);	apdu->datalen += 3;	apdu->lc += 3;	apdu->le += 3;	if (crycks1)		memcpy(crycks1, out, 3);	des_cleanse(k1);	des_cleanse(k2);	memset(in, 0, sizeof(in));	memset(out, 0, sizeof(out));	memset(block, 0, sizeof(block));	return 0;}/* * Verify secure messaging response */static intgpk_verify_crycks(struct sc_card *card, struct sc_apdu *apdu, u8 *crycks){	if (apdu->resplen < 3	 || memcmp(apdu->resp + apdu->resplen - 3, crycks, 3)) {		if (card->ctx->debug)			sc_debug(card->ctx, "Invalid secure messaging reply\n");		return SC_ERROR_UNKNOWN_DATA_RECEIVED;	}	apdu->resplen -= 3;	return 0;}/* * Create a file or directory. * This is a bit tricky because we abuse the ef_structure * field to transport file types that are non-standard * (the GPK4000 has lots of bizarre file types). */static intgpk_create_file(struct sc_card *card, struct sc_file *file){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_apdu	apdu;	u8		data[28+3], crycks[3], resp[3];	size_t		datalen, namelen;	int		r;	if (card->ctx->debug)		sc_debug(card->ctx, "gpk_create_file(0x%04X)\n", file->id);	/* Prepare APDU */	memset(&apdu, 0, sizeof(apdu));	apdu.cla = 0x80;	/* assume no secure messaging */	apdu.cse = SC_APDU_CASE_3_SHORT;	apdu.ins = 0xE0;	apdu.p2  = 0x00;	/* clear data */	memset(data, 0, sizeof(data));	datalen = 12;	/* FID */	data[0] = file->id >> 8;	data[1] = file->id & 0xFF;	/* encode ACLs */	if (file->type == SC_FILE_TYPE_DF) {		/* The GPK4000 has separate AC bits for		 * creating sensitive files and creating		 * data files. Since OpenSC has just the notion		 * of "file" we use the same ACL for both AC words		 */		apdu.p1 = 0x01; /* create DF */		data[2] = 0x38;		acl_to_ac(file, SC_AC_OP_CREATE, data + 6);		acl_to_ac(file, SC_AC_OP_CREATE, data + 8);		if ((namelen = file->namelen) != 0) {			if (namelen > 16)				return SC_ERROR_INVALID_ARGUMENTS;			memcpy(data+datalen, file->name, namelen);			data[5] = namelen;			datalen += namelen;		}	} else {		apdu.p1 = 0x02; /* create EF */		data[2] = file->ef_structure;		data[3] = file->record_length;		data[4] = file->size >> 8;		data[5] = file->size & 0xff;		acl_to_ac(file, SC_AC_OP_UPDATE, data + 6);		acl_to_ac(file, SC_AC_OP_WRITE, data + 8);		acl_to_ac(file, SC_AC_OP_READ, data + 10);	}	apdu.data = data;	apdu.datalen = datalen;	apdu.lc = datalen;	if (priv->key_set) {		apdu.cla = 0x84;		apdu.cse = SC_APDU_CASE_4_SHORT;		r = gpk_compute_crycks(card, &apdu, crycks);		if (r)			return r;		apdu.resp = resp;		apdu.resplen = sizeof(resp); /* XXX? */	}	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	/* verify secure messaging response */	if (priv->key_set)		r = gpk_verify_crycks(card, &apdu, crycks);	return r;}/* * Set the secure messaging key following a Select FileKey */static intgpk_set_filekey(const u8 *key, const u8 *challenge,		const u8 *r_rn, u8 *kats){	des_key_schedule	k1, k2;	des_cblock		out;	int			r = 0;	DES_set_key_unchecked((des_cblock *) key, &k1);	DES_set_key_unchecked((des_cblock *) (key+8), &k2);	DES_ecb3_encrypt((des_cblock *)(r_rn+4), (des_cblock *) kats,			&k1, &k2, &k1, DES_ENCRYPT);	DES_ecb3_encrypt((des_cblock *)(r_rn+4), (des_cblock *) (kats+8),			&k2, &k1, &k2, DES_ENCRYPT);	/* Verify Cryptogram presented by the card terminal	 * XXX: what is the appropriate error code to return	 * here? INVALID_ARGS doesn't seem quite right	 */	DES_set_key_unchecked((des_cblock *) kats, &k1);	DES_set_key_unchecked((des_cblock *) (kats+8), &k2);	DES_ecb3_encrypt((des_cblock *) challenge, &out,			&k1, &k2, &k1, DES_ENCRYPT );	if (memcmp(r_rn, out+4, 4) != 0)		r = SC_ERROR_INVALID_ARGUMENTS;	des_cleanse(k1);	des_cleanse(k2);	memset(out, 0, sizeof(out));	return r;}/* * Verify a key presented by the user for secure messaging */static intgpk_select_key(struct sc_card *card, int key_sfi, const u8 *buf, size_t buflen){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_apdu	apdu;	u8		random[8], resp[258];	int		r;	SC_FUNC_CALLED(card->ctx, 1);	if (buflen != 16)		return SC_ERROR_INVALID_ARGUMENTS;	/* now do the SelFk */	RAND_pseudo_bytes(random, sizeof(random));	memset(&apdu, 0, sizeof(apdu));	apdu.cla = 0x80;	apdu.cse = SC_APDU_CASE_4_SHORT;	apdu.ins = 0x28;	apdu.p1  = 0;	apdu.p2  = key_sfi;	apdu.data = random;	apdu.datalen = sizeof(random);	apdu.lc = apdu.datalen;	apdu.resp = resp;	apdu.resplen = sizeof(resp);	apdu.le = 12;	apdu.sensitive = 1;		r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	if (apdu.resplen != 12) {		r = SC_ERROR_UNKNOWN_DATA_RECEIVED;	} else	if ((r = gpk_set_filekey(buf, random, resp, priv->key)) == 0) {		priv->key_set = 1;		priv->key_reference = key_sfi;	}	memset(resp, 0, sizeof(resp));	return r;}/* * Select a security environment (Set Crypto Context in GPK docs). * When we get here, the PK file has already been selected. * * Issue: the GPK distinguishes between "signing" and * "card internal authentication". I don't know whether this * makes any difference in practice... * * Issue: it seems that sc_compute_signature() does not hash * the data for the caller. So what is the purpose of HASH_SHA * and other flags? */static intgpk_set_security_env(struct sc_card *card,		const struct sc_security_env *env,		int se_num){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_apdu	apdu;	unsigned int	context, algorithm;	unsigned int	file_id;	u8		sysrec[7];	int		r;	/* According to several sources from GemPlus, they don't	 * have off the shelf cards that do DSA. So I won't bother	 * with implementing this stuff here. */	algorithm = SC_ALGORITHM_RSA;	if (env->flags & SC_SEC_ENV_ALG_PRESENT)		algorithm = env->algorithm;	if (algorithm != SC_ALGORITHM_RSA) {		sc_error(card->ctx, "Algorithm not supported.\n");		return SC_ERROR_NOT_SUPPORTED;	}	priv->sec_algorithm = algorithm;	/* If there's a key reference, it must be 0 */	if ((env->flags & SC_SEC_ENV_KEY_REF_PRESENT)	 && (env->key_ref_len != 1 || env->key_ref[0] != 0)) {		sc_error(card->ctx, "Unknown key referenced.\n");		return SC_ERROR_NOT_SUPPORTED;	}	/* Right now, the OpenSC flags do not support any padding	 * other than PKCS#1. */	if (env->flags & SC_ALGORITHM_RSA_PAD_PKCS1)		priv->sec_padding = 0;	else if (env->flags & SC_ALGORITHM_RSA_PAD_ANSI)		priv->sec_padding = 1;	else if (env->flags & SC_ALGORITHM_RSA_PAD_ISO9796)		priv->sec_padding = 2;	else {		sc_error(card->ctx, "Padding algorithm not supported.\n");		return SC_ERROR_NOT_SUPPORTED;	}	switch (env->operation) {	case SC_SEC_OPERATION_SIGN:		/* Again, the following may not make any difference		 * because we don't do any hashing on-card. But		 * what the hell, we have all those nice macros,		 * so why not use them :) 		 */		if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) {			context = GPK_SIGN_RSA_SHA;			priv->sec_hash_len = 20;		} else		if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5_SHA1) {			context = GPK_SIGN_RSA_SSL;			priv->sec_hash_len = 36;		} else		if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5) {			context = GPK_SIGN_RSA_MD5;			priv->sec_hash_len = 16;		} else {			sc_error(card->ctx, "Unsupported signature algorithm");			return SC_ERROR_NOT_SUPPORTED;		}		break;	case SC_SEC_OPERATION_DECIPHER:		context = GPK_UNWRAP_RSA;		break;	default:		sc_error(card->ctx, "Crypto operation not supported.\n");		return SC_ERROR_NOT_SUPPORTED;	}	/* Get the file ID */	if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) {		if (env->file_ref.len != 2) {			sc_error(card->ctx, "File reference: invalid length.\n");			return SC_ERROR_INVALID_ARGUMENTS;		}		file_id = (env->file_ref.value[0] << 8)			| env->file_ref.value[1];	} else {		sc_error(card->ctx, "File reference missing.\n");		return SC_ERROR_INVALID_ARGUMENTS;	}	/* Select the PK file. The caller has already selected	 * the DF. */	r = gpk_select_id(card, GPK_SEL_EF, file_id, NULL);	SC_TEST_RET(card->ctx, r, "Failed to select PK file");	/* Read the sys record of the PK file to find out the key length */	r = sc_read_record(card, 1, sysrec, sizeof(sysrec),			SC_RECORD_BY_REC_NR);	SC_TEST_RET(card->ctx, r, "Failed to read PK sysrec");	if (r != 7 || sysrec[0] != 0) {		sc_error(card->ctx, "First record of file is not the sysrec");		return SC_ERROR_OBJECT_NOT_VALID;	}	if (sysrec[5] != 0x00) {		sc_error(card->ctx, "Public key is not an RSA key");		return SC_ERROR_OBJECT_NOT_VALID;	}	switch (sysrec[1]) {	case 0x00: priv->sec_mod_len =  512 / 8; break;	case 0x10: priv->sec_mod_len =  768 / 8; break;	case 0x11: priv->sec_mod_len = 1024 / 8; break;	default:		sc_error(card->ctx, "Unsupported modulus length");		return SC_ERROR_OBJECT_NOT_VALID;	}	/* Now do SelectCryptoContext */	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_1;	apdu.cla = 0x80;	apdu.ins = 0xA6;	apdu.p1  = file_id & 0x1f;	apdu.p2  = context;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	return r;}/* * Restore security environment * Not sure what this is supposed to do. */static intgpk_restore_security_env(struct sc_card *card, int se_num){	return 0;}/* * Revert buffer (needed for all GPK crypto operations because * they want LSB byte order internally */static intreverse(u8 *out, size_t outlen, const u8 *in, size_t inlen){	if (inlen > outlen)		return SC_ERROR_BUFFER_TOO_SMALL;	outlen = inlen;	while (inlen--)		*out++ = in[inlen];	return outlen;}/* * Use the card's on-board hashing functions to hash some data */#ifdef dontusestatic intgpk_hash(struct sc_card *card, const u8 *data, size_t datalen){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -