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

📄 card-gpk.c

📁 读写Smart卡加解密接口的程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * card-gpk: Driver for GPK 4000 cards * * Copyright (C) 2002  Olaf Kirch <okir@lst.de> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "internal.h"#include "cardctl.h"#include "pkcs15.h"#ifdef HAVE_OPENSSL#include <stdlib.h>#include <string.h>#include <openssl/des.h>#include <openssl/rand.h>#if OPENSSL_VERSION_NUMBER >= 0x00907000L#define des_cleanse(k)	OPENSSL_cleanse(k.ks, sizeof(k.ks))#else#define des_cleanse(k)	memset(&k, 0, sizeof(k))#define DES_set_key_unchecked(a,b) des_set_key_unchecked(a,*b)#define DES_ecb3_encrypt(a,b,c,d,e,f) des_ecb3_encrypt(a,b,*c,*d,*e,f)#endif/* Gemplus card variants */enum {	GPK4000_su256 = 4000,	GPK4000_s,	GPK4000_sp,	GPK4000_sdo,	GPK8000 = 8000,	GPK8000_8K,	GPK8000_16K,	GPK16000 = 16000};#define GPK_SEL_MF		0x00#define GPK_SEL_DF		0x01#define GPK_SEL_EF		0x02#define GPK_SEL_AID		0x04#define GPK_FID_MF		0x3F00#define GPK_FTYPE_SC		0x21#define GPK_SIGN_RSA_MD5	0x11#define GPK_SIGN_RSA_SHA	0x12#define GPK_SIGN_RSA_SSL	0x18#define GPK_VERIFY_RSA_MD5	0x21#define GPK_VERIFY_RSA_SHA	0x22#define GPK_AUTH_RSA_MD5	0x31#define GPK_AUTH_RSA_SHA	0x32#define GPK_AUTH_RSA_SSL	0x38#define GPK_UNWRAP_RSA		0x77#define GPK_MAX_PINS		8#define GPK_HASH_CHUNK		62/* * GPK4000 private data */struct gpk_private_data {	int		variant;	/* The GPK usually do file offsets in multiples of	 * 4 bytes. This can be customized however. We	 * should really query for this during gpk_init */	unsigned int	offset_shift;	unsigned int	offset_mask;	unsigned int	locked : 1,			sample_card : 1;	/* access control bits of file most recently selected */	unsigned short int ac[3];	/* is non-zero if we should use secure messaging */	unsigned	key_set   : 1;	unsigned int	key_reference;	u8		key[16];	/* crypto related data from set_security_env */	unsigned int	sec_algorithm;	unsigned int	sec_hash_len;	unsigned int	sec_mod_len;	unsigned int	sec_padding;};#define DRVDATA(card)	((struct gpk_private_data *) ((card)->drv_data))static int	gpk_get_info(struct sc_card *, u8, u8, u8 *, size_t);/* * ATRs of GPK4000 cards courtesy of libscez */static struct atrinfo {	unsigned char	atr[SC_MAX_ATR_SIZE];	unsigned int	atr_len;	int		variant;	const char *	name;} atrlist[] = {  { "\x3B\x27\x00\x80\x65\xA2\x04\x01\x01\x37", 10, GPK4000_s, "GPK 4K" },  { "\x3B\x27\x00\x80\x65\xA2\x05\x01\x01\x37", 10, GPK4000_sp, "GPK 4K" },  { "\x3B\x27\x00\x80\x65\xA2\x0C\x01\x01\x37", 10, GPK4000_su256, "GPK 4K" },  { "\x3B\xA7\x00\x40\x14\x80\x65\xA2\x14\x01\x01\x37", 12, GPK4000_sdo, "GPK 4K" },  { "\x3B\xA7\x00\x40\x18\x80\x65\xA2\x08\x01\x01\x52", 12, GPK8000_8K, "GPK 8K" },  { "\x3B\xA7\x00\x40\x18\x80\x65\xA2\x09\x01\x01\x52", 12, GPK8000_16K, "GPK 8K" },  { "\x3B\xA7\x00\x40\x18\x80\x65\xA2\x09\x01\x02\x52", 12, GPK16000, "GPK 16K" },  { "", 0, -1 }};/* * Driver and card ops structures */static struct sc_card_operations	gpk_ops, *iso_ops;static struct sc_card_driver gpk_drv = {	"Gemplus GPK driver",	"gpk",	&gpk_ops};/* * Identify the card variant based on the ATR *   returns the variant number or 0 on error */static intgpk_identify(struct sc_card *card){	struct atrinfo	*ai;	/* Gemplus GPK docs say we can use just the 	 * FMN and PRN fields of the historical bytes	 * to recognize a GPK card	 *  See Table 43, pp. 188	 * We'll use the first 2 bytes as well	 */	if ( (card->slot->atr_info.hist_bytes_len >= 7)		&& (card->slot->atr_info.hist_bytes[0] == 0x80)		&& (card->slot->atr_info.hist_bytes[1] == 0x65)		&& (card->slot->atr_info.hist_bytes[2] == 0xa2)) /* FMN */	{		if (card->slot->atr_info.hist_bytes[3] == 0x08){ /* PRN? */			return GPK8000;		}		if (card->slot->atr_info.hist_bytes[3] == 0x09){ /* PRN? */			return GPK16000;		}	}	/* if the above ATR-analysis fails, check the known ATR list */	for (ai = atrlist; ai->atr_len; ai++) {		if (card->atr_len >= ai->atr_len		 && !memcmp(card->atr, ai->atr, ai->atr_len))			return ai->variant;	}	return 0;}/* * return 1 iff this driver can handle the card */static intgpk_match(struct sc_card *card){	return gpk_identify(card)? 1 : 0;}/* * Initialize the card struct */static intgpk_init(struct sc_card *card){	struct gpk_private_data *priv;	unsigned long	exponent, flags, kg;	unsigned char info[13];	int variant;	if (!(variant = gpk_identify(card)))		return SC_ERROR_INVALID_CARD;	card->drv_data = priv = (struct gpk_private_data *) malloc(sizeof(*priv));	if (card->drv_data == NULL)		return SC_ERROR_OUT_OF_MEMORY;	memset(priv, 0, sizeof(*priv));	priv->variant = variant;	/* read/write/update binary expect offset to be the	 * number of 32 bit words.	 * offset_shift is the shift value.	 * offset_mask is the corresponding mask. */	priv->offset_shift = 2;	priv->offset_mask = 3;	card->cla = 0;	/* Set up algorithm info. GPK 16000 will do any RSA	 * exponent, earlier ones are restricted to 0x10001 */	flags = SC_ALGORITHM_RSA_HASH_MD5 | SC_ALGORITHM_RSA_HASH_SHA1		| SC_ALGORITHM_RSA_HASH_MD5_SHA1;	flags |= SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_PAD_ANSI		| SC_ALGORITHM_RSA_PAD_ISO9796;	exponent = (variant < 16000)? 0x10001 : 0;	kg = (variant >= 8000)? SC_ALGORITHM_ONBOARD_KEY_GEN : 0;	_sc_card_add_rsa_alg(card,  512, flags|kg, exponent);	_sc_card_add_rsa_alg(card,  768, flags, exponent);	_sc_card_add_rsa_alg(card, 1024, flags|kg, exponent);	/* Inspect the LOCK byte */	if (gpk_get_info(card, 0x02, 0xA4, info, sizeof(info)) >= 0) {		if (info[12] & 0x40) {			priv->offset_shift = 0;			priv->offset_mask = 0;		}		if (info[12] & 0x10) {			/* DSA supported - add algo information.			 * It's highly unlikely we'll ever see this.			 */		}		if (info[12] & 0x08) {			priv->locked = 1;		}		/* Sample cards use a transport key of "TEST KEYTEST KEY" */		if (!memcmp(info+5, "\x00\xff\x00", 3)) {			priv->sample_card = 1;		}	}	/* State that we have an RNG */	card->caps |= SC_CARD_CAP_RNG;	return 0;}/* * Card is being closed; discard any private data etc */static intgpk_finish(struct sc_card *card){	if (card->drv_data)		free(card->drv_data);	card->drv_data = NULL;	return 0;}/* * Error code handling for the GPK4000. * sc_check_sw doesn't seem to handle all of the * status words the GPK is capable of returning */#if 0static intgpk_check_sw(struct sc_card *card, u8 sw1, u8 sw2){	unsigned short int	sw = (sw1 << 8) | sw2;	if ((sw & 0xFFF0) == 0x63C0) {		sc_error(card->ctx, "wrong PIN, %u tries left\n", sw&0xf);		return SC_ERROR_PIN_CODE_INCORRECT;	}	switch (sw) {	case 0x6400:		sc_error(card->ctx, "wrong crypto context\n");		return SC_ERROR_OBJECT_NOT_VALID; /* XXX ??? */	/* The following are handled by iso7816_check_sw	 * but all return SC_ERROR_UNKNOWN_DATA_RECEIVED	 * XXX: fix in the iso driver? */	case 0x6983:		sc_error(card->ctx, "PIN is blocked\n");		return SC_ERROR_PIN_CODE_INCORRECT;	case 0x6581:		sc_error(card->ctx, "out of space on card or file\n");		return SC_ERROR_OUT_OF_MEMORY;	case 0x6981:		return SC_ERROR_FILE_NOT_FOUND;	case 0x6A80:	case 0x6b00:		return SC_ERROR_INVALID_ARGUMENTS;	}	return iso7816_check_sw(card, sw1, sw2);}#endif/* * Select a DF/EF */static intmatch_path(struct sc_card *card, unsigned short int **pathptr, size_t *pathlen,		int need_info){	unsigned short int	*curptr, *ptr;	size_t		curlen, len;	size_t		i;	curptr = (unsigned short int *) card->cache.current_path.value;	curlen = card->cache.current_path.len;	ptr    = *pathptr;	len    = *pathlen;	if (curlen < 1 || len < 1)		return 0;	/* Make sure path starts with MF.	 * Note the cached path should always begin with MF. */	if (ptr[0] != GPK_FID_MF || curptr[0] != GPK_FID_MF)		return 0;	for (i = 1; i < len && i < curlen; i++) {		if (ptr[i] != curptr[i])			break;	}	if (len < curlen) {		/* Caller asked us to select the DF, but the		 * current file is some EF within the DF we're		 * interested in. Say ACK */		if (len == 2)			goto okay;		/* Anything else won't work */		return 0;	}	/* In the case of an exact match:	 * If the caller needs info on the file to be selected,	 * make sure we at least select the file itself.	 * If the DF matches the current DF, just return the	 * FID */	if (i == len && need_info) {		if (i > 1) {			*pathptr = ptr + len - 1;			*pathlen = len - 1;			return 1;		}		/* bummer */		return 0;	}okay:	*pathptr = ptr + i;	*pathlen = len - i;	return 1;}static voidac_to_acl(unsigned short int ac, struct sc_file *file, unsigned int op){	unsigned int	npins, pin;	npins = (ac >> 14) & 3;	if (npins == 3) {		sc_file_add_acl_entry(file, op, SC_AC_NEVER,			       	SC_AC_KEY_REF_NONE);		return;	}	sc_file_add_acl_entry(file, op, SC_AC_NONE, SC_AC_KEY_REF_NONE);	pin = ac & 0xFF;	if (npins >= 1)		sc_file_add_acl_entry(file, op, SC_AC_CHV, (pin >> 4) & 0xF);	if (npins == 2)		sc_file_add_acl_entry(file, op, SC_AC_CHV, pin & 0xF);	/* Check whether secure messaging key is specified */	if (ac & 0x3F00)		sc_file_add_acl_entry(file, op, SC_AC_PRO, (ac & 0x3F00) >> 8);}/* * Convert ACLs requested by the application to access condition * bits supported by the GPK. Since these do not map 1:1 there's * some fuzz involved. */static voidacl_to_ac(struct sc_file *file, unsigned int op, u8 *ac){	const struct sc_acl_entry *acl;	unsigned int	npins = 0;	ac[0] = ac[1] = 0;	if ((acl = sc_file_get_acl_entry(file, op)) == NULL)		return;	assert(acl->method != SC_AC_UNKNOWN);	switch (acl->method) {	case SC_AC_NEVER:		ac[0] = 0xC0;		return;	case SC_AC_NONE:		return;	}	while (acl) {		if (acl->method == SC_AC_CHV) {			/* Support up to 2 PINS only */			if (++npins >= 2)				continue;			ac[1] >>= 4;			ac[1] |= acl->key_ref << 4;			ac[0] += 0x40;		}		if (acl->method == SC_AC_PRO) {			ac[0] |= acl->key_ref & 0x1f;		}		acl = acl->next;	}}static intgpk_parse_fci(struct sc_card *card,		const u8 *buf, size_t buflen,		struct sc_file *file){	const u8	*end, *next;	unsigned int	tag, len;	end = buf + buflen;	for (; buf + 2 < end; buf = next) {		next = buf + 2 + buf[1];		if (next > end)			break;		tag = *buf++;		len = *buf++;		if (tag == 0x84) {			/* unknown purpose - usually the name, but			 * the content looks weird, such as			 * 84 0D A0 00 00 00 18 0F 00 00 01 63 00 01 04			 */		} else		if (tag == 0xC1 && len >= 2) {			/* Seems to be the file id, followed by something			 * C1 04 02 00 00 00 */			file->id = (buf[0] << 8) | buf[1];		} else		if (tag == 0xC2) {			/* unknown purpose			 * C2 01 01			 */		}	}	return 0;}static intgpk_parse_fileinfo(struct sc_card *card,		const u8 *buf, size_t buflen,		struct sc_file *file){	const u8	*sp, *end, *next;	int		i, rc;	memset(file, 0, sizeof(*file));	for (i = 0; i < SC_MAX_AC_OPS; i++)		sc_file_add_acl_entry(file, i, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE);	end = buf + buflen;	for (sp = buf; sp + 2 < end; sp = next) {		next = sp + 2 + sp[1];		if (next > end)			break;		if (sp[0] == 0x84) {			/* ignore if name is longer than what it should be */			if (sp[1] > sizeof(file->name))				continue;			memset(file->name, 0, sizeof(file->name));			memcpy(file->name, sp+2, sp[1]);		} else		if (sp[0] == 0x85) {			unsigned int	ac[3], n;			file->id = (sp[4] << 8) | sp[5];			file->size = (sp[8] << 8) | sp[9];			file->record_length = sp[7];			/* Map ACLs. Note the third AC byte is			 * valid of EFs only */			for (n = 0; n < 3; n++)				ac[n] = (sp[10+2*n] << 8) | sp[11+2*n];			/* Examine file type */			switch (sp[6] & 7) {			case 0x01: case 0x02: case 0x03: case 0x04:			case 0x05: case 0x06: case 0x07:				file->type = SC_FILE_TYPE_WORKING_EF;				file->ef_structure = sp[6] & 7;				ac_to_acl(ac[0], file, SC_AC_OP_UPDATE);				ac_to_acl(ac[1], file, SC_AC_OP_WRITE);				ac_to_acl(ac[2], file, SC_AC_OP_READ);				break;			case 0x00: /* 0x38 is DF */				file->type = SC_FILE_TYPE_DF;				/* Icky: the GPK uses different ACLs				 * for creating data files and				 * 'sensitive' i.e. key files */				ac_to_acl(ac[0], file, SC_AC_OP_LOCK);				ac_to_acl(ac[1], file, SC_AC_OP_CREATE);				sc_file_add_acl_entry(file, SC_AC_OP_SELECT,					SC_AC_NONE, SC_AC_KEY_REF_NONE);				sc_file_add_acl_entry(file, SC_AC_OP_DELETE,					SC_AC_NEVER, SC_AC_KEY_REF_NONE);				sc_file_add_acl_entry(file, SC_AC_OP_REHABILITATE,					SC_AC_NEVER, SC_AC_KEY_REF_NONE);				sc_file_add_acl_entry(file, SC_AC_OP_INVALIDATE,					SC_AC_NEVER, SC_AC_KEY_REF_NONE);				sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES,					SC_AC_NEVER, SC_AC_KEY_REF_NONE);				break;			}		} else		if (sp[0] == 0x6f) {			/* oops - this is a directory with an IADF.			 * This happens with the personalized GemSafe cards			 * for instance. */			file->type = SC_FILE_TYPE_DF;			rc = gpk_parse_fci(card, sp + 2, sp[1], file);			if (rc < 0)				return rc;		}	}	if (file->record_length)		file->record_count = file->size / file->record_length;	file->magic = SC_FILE_MAGIC;	return 0;}static intgpk_select(struct sc_card *card, u8 kind,		const u8 *buf, size_t buflen,		struct sc_file **file){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_apdu	apdu;	u8		resbuf[SC_MAX_APDU_BUFFER_SIZE];	int		r;	/* If we're about to select a DF, invalidate secure messaging keys */	if (kind == GPK_SEL_MF || kind == GPK_SEL_DF) {		memset(priv->key, 0, sizeof(priv->key));		priv->key_set = 0;	}	/* do the apdu thing */	memset(&apdu, 0, sizeof(apdu));	apdu.cla = 0x00;	apdu.cse = SC_APDU_CASE_3_SHORT;	apdu.ins = 0xA4;	apdu.p1 = kind;	apdu.p2 = 0;	apdu.data = buf;	apdu.datalen = buflen;	apdu.lc = apdu.datalen;	apdu.resp = resbuf;	apdu.resplen = file? sizeof(resbuf) : 0;	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");	/* Nothing we can say about it... invalidate	 * path cache */	if (kind == GPK_SEL_AID) {		card->cache.current_path.len = 0;	}	if (file == NULL)		return 0;	*file = sc_file_new();	r = gpk_parse_fileinfo(card, apdu.resp, apdu.resplen, *file);	if (r < 0) {		sc_file_free(*file);		*file = NULL;	}	return r;}static intgpk_select_id(struct sc_card *card, u8 kind, unsigned short int fid,		struct sc_file **file){	struct sc_path	*cp = &card->cache.current_path;	u8		fbuf[2];	int		r, log_errs;	if (card->ctx->debug)		sc_debug(card->ctx, "gpk_select_id(0x%04X, kind=%u)\n", fid, kind);	fbuf[0] = fid >> 8;

⌨️ 快捷键说明

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