- added preliminary support for EMV cards

- changed a few function prototypes
- implemented access control lists to files
- added sc_read_record() function
- updated the NEWS file


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@111 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2001-12-29 02:07:32 +00:00
parent 4586a88efc
commit ad2e34cb6c
22 changed files with 457 additions and 225 deletions

8
NEWS
View File

@ -3,11 +3,13 @@ NEWS for OpenSC -- History of user visible changes
New in 0.4.0; 2001-12-xx; Juha Yrjölä:
* Finished migrating to Autotools
* Rewritten ASN.1 decoder (should work better on all PKCS #15 cards)
* Abstracted card handling, so adding support for new (bizarre)
cards is a whiz
* Added colored debug and error output :)
* Abstracted card handling, so adding support for new cards is a whiz,
'opensc-tool -D' will list all installed drivers.
* Added colored debug and error output ;)
* Fixed some memory leaks
* Support for Swedish Posten eID cards
* Added very preliminary support for EMV compatible cards and Multiflex
cards by Schlumberger
New in 0.3.5; 2001-12-15; Juha Yrjölä:
* Now compiles with C++

View File

@ -6,7 +6,7 @@ dnl $Id$
AC_PREREQ(2.52)
AC_INIT(src/libopensc/sc.c)
AM_INIT_AUTOMAKE(libopensc, 0.4.0)
AM_INIT_AUTOMAKE(opensc, 0.4.0)
AM_CONFIG_HEADER(config.h)
AC_CANONICAL_HOST

View File

@ -420,7 +420,7 @@ int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
assert(id != NULL);
if (inlen < 1)
return SC_ERROR_INVALID_ASN1_OBJECT;
for (i = 0; i < SC_ASN1_MAX_OBJECT_ID_OCTETS; i++)
for (i = 0; i < SC_MAX_OBJECT_ID_OCTETS; i++)
id->value[i] = -1;
a = *p;
*octet++ = a / 40;
@ -438,7 +438,7 @@ int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
inlen--;
}
*octet++ = a;
if (octet - id->value >= SC_ASN1_MAX_OBJECT_ID_OCTETS-1)
if (octet - id->value >= SC_MAX_OBJECT_ID_OCTETS-1)
return SC_ERROR_INVALID_ASN1_OBJECT;
};

View File

@ -53,7 +53,6 @@ static int autodetect_class(struct sc_card *card)
debug(card->ctx, "trying with 0x%02X\n", classes[i]);
apdu.cla = classes[i];
apdu.cse = SC_APDU_CASE_3_SHORT;
apdu.no_response = 1;
memcpy(buf, "\x3F\x00", 2);
apdu.data = buf;
apdu.datalen = 2;

View File

@ -116,7 +116,7 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen
static int mflex_select_file(struct sc_card *card, const struct sc_path *path,
struct sc_file *file)
{
int r;
int r, i;
struct sc_apdu apdu;
u8 rbuf[MAX_BUFFER_SIZE];
u8 *pathptr = path->value;
@ -167,12 +167,12 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path,
/* No need to get file information, if file is NULL or already
* valid. */
if (file == NULL || sc_file_valid(file))
apdu.no_response = 1;
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, r, "Card returned error");
if (apdu.no_response)
if (file == NULL || sc_file_valid(file))
return 0;
if (apdu.resplen < 14)
@ -180,9 +180,13 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path,
if (apdu.resp[0] == 0x6F) {
error(card->ctx, "unsupported: Multiflex returned FCI\n");
return SC_ERROR_UNKNOWN_REPLY; /* FIXME */
return SC_ERROR_UNKNOWN_REPLY; /* FIXME */
}
memset(file, 0, sizeof(struct sc_file));
for (i = 0; i < SC_MAX_AC_OPS; i++)
file->acl[i] = SC_AC_UNKNOWN;
return parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file);
}

View File

@ -26,7 +26,13 @@
int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2)
{
if (sw1 != 0x90 || sw2 != 0)
error(card->ctx, "card returned SW1=%02X, SW2=%02X\n", sw1, sw2);
switch (sw1) {
case 0x67:
if (sw2 == 0)
return SC_ERROR_WRONG_LENGTH;
break;
case 0x69:
switch (sw2) {
case 0x82:
@ -40,8 +46,10 @@ int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2)
case 0x81:
return SC_ERROR_NOT_SUPPORTED;
case 0x82:
case 0x83:
return SC_ERROR_FILE_NOT_FOUND;
case 0x83:
return SC_ERROR_RECORD_NOT_FOUND;
case 0x85:
case 0x86:
case 0x87:
return SC_ERROR_INVALID_ARGUMENTS;
@ -49,6 +57,10 @@ int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2)
break;
}
break;
case 0x6C:
error(card->ctx, "incorrect length, right length is %d\n",
sw2);
return SC_ERROR_WRONG_LENGTH;
case 0x6D:
return SC_ERROR_NOT_SUPPORTED;
case 0x6E:
@ -57,7 +69,6 @@ int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2)
if (sw2 == 0)
return 0;
}
error(card->ctx, "Unknown SW's: SW1=%02X, SW2=%02X\n", sw1, sw2);
return SC_ERROR_UNKNOWN_REPLY;
}
@ -201,8 +212,11 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
{
int r;
size_t orig_resplen;
assert(card != NULL && apdu != NULL);
SC_FUNC_CALLED(card->ctx, 4);
orig_resplen = apdu->resplen;
r = sc_check_apdu(card->ctx, apdu);
SC_TEST_RET(card->ctx, r, "APDU sanity check failed");
r = sc_lock(card);
@ -223,12 +237,21 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
debug(card->ctx, "Received %d bytes (SW1=%02X SW2=%02X)\n%s",
apdu->resplen, apdu->sw1, apdu->sw2, buf);
}
if (apdu->sw1 == 0x6C && apdu->resplen == 0) {
apdu->resplen = orig_resplen;
apdu->le = apdu->sw2;
r = sc_transceive_t0(card, apdu);
if (r != 0) {
sc_unlock(card);
SC_TEST_RET(card->ctx, r, "transceive_t0() failed");
}
}
if (apdu->sw1 == 0x61 && apdu->resplen == 0) {
struct sc_apdu rspapdu;
BYTE rsp[SC_MAX_APDU_BUFFER_SIZE];
if (apdu->no_response != 0) {
apdu->sw1 = 0x90;
if (orig_resplen == 0) {
apdu->sw1 = 0x90; /* FIXME: should we do this? */
apdu->sw2 = 0;
sc_unlock(card);
return 0;
@ -257,9 +280,14 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
debug(card->ctx, "Response %d bytes (SW1=%02X SW2=%02X)\n%s",
rspapdu.resplen, rspapdu.sw1, rspapdu.sw2, buf);
}
/* FIXME: Check apdu->resplen */
memcpy(apdu->resp, rspapdu.resp, rspapdu.resplen);
apdu->resplen = rspapdu.resplen;
if (rspapdu.resplen) {
size_t c = rspapdu.resplen;
if (c > orig_resplen)
c = orig_resplen;
memcpy(apdu->resp, rspapdu.resp, c);
apdu->resplen = c;
}
apdu->sw1 = rspapdu.sw1;
apdu->sw2 = rspapdu.sw2;
}
@ -277,7 +305,6 @@ void sc_format_apdu(struct sc_card *card, struct sc_apdu *apdu,
apdu->ins = (u8) ins;
apdu->p1 = (u8) p1;
apdu->p2 = (u8) p2;
apdu->no_response = 0;
return;
}
@ -342,13 +369,17 @@ int sc_connect_card(struct sc_context *ctx,
continue;
if (ctx->debug >= 3)
debug(ctx, "matched: %s\n", drv->name);
r = ops->init(card);
card->ops = ops;
r = card->ops->init(card);
card->driver = drv;
if (r) {
error(ctx, "driver '%s' init() failed: %s\n", drv->name,
sc_strerror(r));
if (r == SC_ERROR_INVALID_CARD)
if (r == SC_ERROR_INVALID_CARD) {
card->ops = NULL;
card->driver = NULL;
continue;
}
free(card);
return r;
}
@ -543,7 +574,7 @@ int sc_delete_file(struct sc_card *card, int file_id)
}
int sc_read_binary(struct sc_card *card, unsigned int idx,
unsigned char *buf, size_t count)
unsigned char *buf, size_t count, unsigned long flags)
{
#define RB_BUF_SIZE 250
int r;
@ -556,7 +587,7 @@ int sc_read_binary(struct sc_card *card, unsigned int idx,
unsigned char *p = buf;
if (card->ops->read_binary_large != NULL) {
r = card->ops->read_binary_large(card, idx, buf, count);
r = card->ops->read_binary_large(card, idx, buf, count, flags);
SC_FUNC_RETURN(card->ctx, 2, r);
}
/* no read_binary_large support... */
@ -564,7 +595,7 @@ int sc_read_binary(struct sc_card *card, unsigned int idx,
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
while (count > 0) {
int n = count > RB_BUF_SIZE ? RB_BUF_SIZE : count;
r = sc_read_binary(card, idx, p, n);
r = sc_read_binary(card, idx, p, n, flags);
if (r < 0) {
sc_unlock(card);
SC_TEST_RET(card->ctx, r, "sc_read_binary() failed");
@ -583,7 +614,7 @@ int sc_read_binary(struct sc_card *card, unsigned int idx,
}
if (card->ops->read_binary == NULL)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
r = card->ops->read_binary(card, idx, buf, count);
r = card->ops->read_binary(card, idx, buf, count, flags);
SC_FUNC_RETURN(card->ctx, 2, r);
}
@ -625,6 +656,19 @@ int sc_get_challenge(struct sc_card *card, u8 *rnd, size_t len)
SC_FUNC_RETURN(card->ctx, 2, r);
}
int sc_read_record(struct sc_card *card, unsigned int rec_nr, u8 *buf,
size_t count, unsigned long flags)
{
int r;
assert(card != NULL);
SC_FUNC_CALLED(card->ctx, 2);
if (card->ops->read_record == NULL)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
r = card->ops->read_record(card, rec_nr, buf, count, flags);
SC_FUNC_RETURN(card->ctx, 2, r);
}
inline int sc_card_valid(const struct sc_card *card) {
#ifndef NDEBUG
assert(card != NULL);

View File

@ -31,12 +31,6 @@
#define SC_CARD_MAGIC 0x27182818
/* Internal use only */
inline int sc_card_valid(const struct sc_card *card);
inline int sc_file_valid(const struct sc_file *file);
void sc_print_binary(FILE *f, const u8 *buf, int len);
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen);
int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2);
void sc_format_path(const char *path_in, struct sc_path *path_out);
#endif

View File

@ -26,7 +26,8 @@
#include <ctype.h>
static int iso7816_read_binary(struct sc_card *card,
unsigned int idx, u8 *buf, size_t count)
unsigned int idx, u8 *buf, size_t count,
unsigned long flags)
{
struct sc_apdu apdu;
u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE];
@ -47,6 +48,60 @@ static int iso7816_read_binary(struct sc_card *card,
SC_FUNC_RETURN(card->ctx, 2, apdu.resplen);
}
static int iso7816_read_record(struct sc_card *card,
unsigned int rec_nr, u8 *buf, size_t count,
unsigned long flags)
{
struct sc_apdu apdu;
u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE];
int r;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB2, rec_nr, 0);
apdu.p2 = (rec_nr & SC_READ_RECORD_EF_ID_MASK) << 3;
if (flags & SC_READ_RECORD_BY_REC_NR)
apdu.p2 |= 0x04;
apdu.le = count;
apdu.resplen = count;
apdu.resp = recvbuf;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.resplen == 0)
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
memcpy(buf, recvbuf, apdu.resplen);
SC_FUNC_RETURN(card->ctx, 2, apdu.resplen);
}
static unsigned int byte_to_acl(u8 byte)
{
switch (byte >> 4) {
case 0:
return SC_AC_NONE;
case 1:
return SC_AC_CHV1;
case 2:
return SC_AC_CHV2;
case 4:
return SC_AC_TERM;
case 15:
return SC_AC_NEVER;
}
return SC_AC_UNKNOWN;
}
static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
{
/* FIXME: confirm if this is specified in the ISO 7816-9 standard */
int i;
if (len < 6)
return;
for (i = 0; i < 6; i++)
file->acl[i] = byte_to_acl(buf[i]);
}
static void process_fci(struct sc_context *ctx, struct sc_file *file,
const u8 *buf, int buflen)
{
@ -79,23 +134,25 @@ static void process_fci(struct sc_context *ctx, struct sc_file *file,
if (ctx->debug >= 3)
debug(ctx, " shareable: %s\n",
(byte & 0x40) ? "yes" : "no");
file->type = (byte >> 3) & 7;
file->ef_structure = byte & 0x07;
switch ((byte >> 3) & 7) {
case 0:
type = "working EF";
file->type = SC_FILE_TYPE_WORKING_EF;
break;
case 1:
type = "internal EF";
file->type = SC_FILE_TYPE_INTERNAL_EF;
break;
case 7:
type = "DF";
file->type = SC_FILE_TYPE_DF;
break;
default:
type = "unknown";
break;
}
if (ctx->debug >= 3) {
switch ((byte >> 3) & 7) {
case 0:
type = "working EF";
break;
case 1:
type = "internal EF";
break;
case 7:
type = "DF";
break;
default:
type = "unknown";
break;
}
debug(ctx, " type: %s\n", type);
debug(ctx, " EF structure: %d\n",
byte & 0x07);
@ -128,10 +185,9 @@ static void process_fci(struct sc_context *ctx, struct sc_file *file,
} else
file->prop_attr_len = 0;
tag = sc_asn1_find_tag(p, len, 0x86, &taglen);
if (tag != NULL && taglen && taglen <= SC_MAX_SEC_ATTR_SIZE) {
memcpy(file->sec_attr, tag, taglen);
file->sec_attr_len = taglen;
} else
if (tag != NULL && taglen && taglen <= SC_MAX_SEC_ATTR_SIZE)
parse_sec_attr(file, tag, taglen);
else
file->sec_attr_len = 0;
file->magic = SC_FILE_MAGIC;
}
@ -184,16 +240,19 @@ static int iso7816_select_file(struct sc_card *card,
apdu.datalen = pathlen;
if (file != NULL) {
memset(file, 0, sizeof(*file));
int i;
/* initialize file to default values */
memset(file, 0, sizeof(struct sc_file));
for (i = 0; i < SC_MAX_AC_OPS; i++)
file->acl[i] = SC_AC_UNKNOWN;
memcpy(&file->path.value, path, pathlen);
file->path.len = pathlen;
}
if (file == NULL || sc_file_valid(file))
apdu.no_response = 1;
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.no_response) {
if (file == NULL || sc_file_valid(file)) {
if (apdu.sw1 == 0x61)
SC_FUNC_RETURN(card->ctx, 2, 0);
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
@ -256,6 +315,7 @@ const struct sc_card_driver * sc_get_iso7816_driver(void)
if (iso_ops.read_binary == NULL) {
memset(&iso_ops, 0, sizeof(iso_ops));
iso_ops.read_binary = iso7816_read_binary;
iso_ops.read_record = iso7816_read_record;
iso_ops.select_file = iso7816_select_file;
iso_ops.get_challenge = iso7816_get_challenge;
}

View File

@ -220,8 +220,8 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *card,
const u8 *pincode, int pinlen);
int sc_pkcs15_change_pin(struct sc_pkcs15_card *card,
struct sc_pkcs15_pin_info *pin,
const char *oldpincode, int oldpinlen,
const char *newpincode, int newpinlen);
const u8 *oldpincode, int oldpinlen,
const u8 *newpincode, int newpinlen);
int sc_pkcs15_find_pin_by_auth_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_pin_info **out);

View File

@ -1,4 +1,4 @@
/*
/*
* opensc.h: OpenSC library header file
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
@ -63,7 +63,10 @@ extern "C" {
#define SC_ERROR_ASN1_END_OF_CONTENTS -1027
#define SC_ERROR_TOO_MANY_OBJECTS -1028
#define SC_ERROR_INVALID_CARD -1029
#define SC_ERROR_WRONG_LENGTH -1030
#define SC_ERROR_RECORD_NOT_FOUND -1031
/* Different APDU cases */
#define SC_APDU_CASE_NONE 0
#define SC_APDU_CASE_1 1
#define SC_APDU_CASE_2_SHORT 2
@ -73,19 +76,57 @@ extern "C" {
#define SC_APDU_CASE_3_EXT 6
#define SC_APDU_CASE_4_EXT 7
#define SC_FILE_TYPE_DF 0x02
#define SC_FILE_TYPE_INTERNAL_EF 0x01
#define SC_FILE_TYPE_WORKING_EF 0x00
/* File types */
#define SC_FILE_TYPE_DF 0x04
#define SC_FILE_TYPE_INTERNAL_EF 0x03
#define SC_FILE_TYPE_WORKING_EF 0x01
/* EF structures */
#define SC_FILE_EF_UNKNOWN 0x00
#define SC_FILE_EF_TRANSPARENT 0x01
#define SC_FILE_EF_LINEAR_FIXED 0x02
#define SC_FILE_EF_LINEAR_FIXED_TLV 0x03
#define SC_FILE_EF_LINEAR_VARIABLE 0x04
#define SC_FILE_EF_LINEAR_VARIABLE_TLV 0x05
#define SC_FILE_EF_CYCLIC 0x06
#define SC_FILE_EF_CYCLIC_TLV 0x07
/* File status flags */
#define SC_FILE_STATUS_ACTIVATED 0x00
#define SC_FILE_STATUS_INVALIDATED 0x01
/* Access Control flags */
#define SC_AC_NONE 0x00000000
#define SC_AC_CHV1 0x00000001 /* Card Holder Verif. */
#define SC_AC_CHV2 0x00000002
#define SC_AC_TERM 0x00000004 /* Terminal auth */
#define SC_AC_PRO 0x00000008 /* Protected mode */
#define SC_AC_NEVER 0xFFFFFFFE
#define SC_AC_UNKNOWN 0xFFFFFFFF
/* Operations relating to access control (in case of DF) */
#define SC_AC_OP_SELECT 0
#define SC_AC_OP_LOCK 1
#define SC_AC_OP_DELETE 2
#define SC_AC_OP_CREATE 3
#define SC_AC_OP_REHABILITATE 4
#define SC_AC_OP_INVALIDATE 5
/* Operations relating to access control (in case of EF) */
#define SC_AC_OP_READ 0
#define SC_AC_OP_UPDATE 1
#define SC_AC_OP_WRITE 2
#define SC_AC_OP_ERASE 3
/* rehab and invalidate are the same as in DF case */
#define SC_MAX_AC_OPS 6
/* sc_read_binary() flags */
#define SC_READ_RECORD_EF_ID_MASK 0x0001F
#define SC_READ_RECORD_BY_REC_ID 0x00000
#define SC_READ_RECORD_BY_REC_NR 0x00100
/* various maximum values */
#define SC_MAX_CARD_DRIVERS 16
#define SC_MAX_READERS 4
#define SC_MAX_APDU_BUFFER_SIZE 255
@ -95,12 +136,12 @@ extern "C" {
#define SC_MAX_SEC_ATTR_SIZE 16
#define SC_MAX_PROP_ATTR_SIZE 16
#define SC_ASN1_MAX_OBJECT_ID_OCTETS 16
#define SC_MAX_OBJECT_ID_OCTETS 16
typedef unsigned char u8;
struct sc_object_id {
int value[SC_ASN1_MAX_OBJECT_ID_OCTETS];
int value[SC_MAX_OBJECT_ID_OCTETS];
};
#define SC_PATH_TYPE_FILE_ID 0
@ -117,12 +158,15 @@ struct sc_path {
struct sc_file {
struct sc_path path;
u8 name[16];
size_t namelen;
u8 name[16]; /* DF name */
size_t namelen; /* length of DF name */
int type, shareable, ef_structure;
size_t size;
int id, status;
size_t size; /* Size of file (in bytes) */
int id; /* Short file id (2 bytes) */
int status; /* Status flags */
unsigned int acl[SC_MAX_AC_OPS]; /* Access Control List */
u8 sec_attr[SC_MAX_SEC_ATTR_SIZE];
size_t sec_attr_len;
u8 prop_attr[SC_MAX_PROP_ATTR_SIZE];
@ -151,6 +195,7 @@ struct sc_card {
pthread_mutex_t mutex;
int lock_count;
const struct sc_card_driver *driver;
const struct sc_card_operations *ops;
void *ops_data;
@ -175,22 +220,23 @@ struct sc_card_operations {
/* ISO 7816-4 functions */
int (*read_binary)(struct sc_card *card, unsigned int idx,
u8 * buf, size_t count);
u8 * buf, size_t count, unsigned long flags);
int (*write_binary)(struct sc_card *card, unsigned int idx,
const u8 * buf, size_t count);
const u8 * buf, size_t count, unsigned long flags);
int (*update_binary)(struct sc_card *card, unsigned int idx,
const u8 * buf, size_t count);
const u8 * buf, size_t count, unsigned long flags);
int (*erase_binary)(struct sc_card *card, unsigned int idx,
size_t count);
size_t count, unsigned long flags);
/* These may be left NULL. If not present, multiple calls
* to read_binary et al. will be made. */
int (*read_binary_large)(struct sc_card *card, unsigned int idx,
u8 * buf, size_t count);
u8 * buf, size_t count, unsigned long flags);
int (*write_binary_large)(struct sc_card *card, unsigned int idx,
const u8 * buf, size_t count);
const u8 * buf, size_t count, unsigned long flags);
int (*update_binary_large)(struct sc_card *card, unsigned int idx,
const u8 * buf, size_t count);
/* possibly TODO: record handling */
const u8 * buf, size_t count, unsigned long flags);
int (*read_record)(struct sc_card *card, unsigned int rec_nr,
u8 * buf, size_t count, unsigned long flags);
/* select_file: Does the equivalent of SELECT FILE command specified
* in ISO7816-4. Stores information about the selected file to
@ -247,15 +293,15 @@ struct sc_context {
struct sc_apdu {
int cse; /* APDU case */
u8 cla, ins, p1, p2;
size_t lc, le;
const u8 *data; /* C-APDU */
size_t datalen; /* length of C-APDU */
u8 *resp; /* R-APDU */
size_t resplen; /* length of R-APDU */
int no_response; /* No response required */
u8 cla, ins, p1, p2; /* CLA, INS, P1 and P2 bytes */
size_t lc, le; /* Lc and Le bytes */
const u8 *data; /* C-APDU data */
size_t datalen; /* length of data in C-APDU */
u8 *resp; /* R-APDU data buffer */
size_t resplen; /* in: size of R-APDU buffer,
* out: length of data returned in R-APDU */
unsigned int sw1, sw2;
unsigned int sw1, sw2; /* Status words returned in R-APDU */
};
/* Base64 encoding/decoding functions */
@ -273,6 +319,7 @@ int sc_destroy_context(struct sc_context *ctx);
int sc_connect_card(struct sc_context *ctx,
int reader, struct sc_card **card);
int sc_disconnect_card(struct sc_card *card);
inline int sc_card_valid(const struct sc_card *card);
/* Checks if a card is present on the supplied reader
* Returns: 1 if card present, 0 if card absent and < 0 in case of an error */
@ -290,7 +337,10 @@ int sc_unlock(struct sc_card *card);
/* ISO 7816-4 related functions */
int sc_select_file(struct sc_card *card, const struct sc_path *path,
struct sc_file *file);
int sc_read_binary(struct sc_card *card, unsigned int idx, u8 * buf, size_t count);
int sc_read_binary(struct sc_card *card, unsigned int idx, u8 * buf,
size_t count, unsigned long flags);
int sc_read_record(struct sc_card *card, unsigned int rec_nr, u8 * buf,
size_t count, unsigned long flags);
int sc_get_challenge(struct sc_card *card, u8 * rndout, size_t len);
/* ISO 7816-8 related functions */
@ -313,6 +363,10 @@ int sc_reset_retry_counter(struct sc_card *card, int ref, const u8 *puk,
int sc_create_file(struct sc_card *card, const struct sc_file *file);
int sc_delete_file(struct sc_card *card, int file_id);
inline int sc_file_valid(const struct sc_file *file);
void sc_format_path(const char *path_in, struct sc_path *path_out);
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen);
/* Possibly only on Setec cards */
int sc_list_files(struct sc_card *card, u8 * buf, int buflen);

View File

@ -241,7 +241,7 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card,
sc_unlock(p15card->card);
return SC_ERROR_OUT_OF_MEMORY;
}
r = sc_read_binary(p15card->card, 0, data, file.size);
r = sc_read_binary(p15card->card, 0, data, file.size, 0);
if (r < 0) {
sc_unlock(p15card->card);
free(data);
@ -335,7 +335,7 @@ static int get_certs_from_file(struct sc_pkcs15_card *card,
return r;
if (file->size > sizeof(buf))
return SC_ERROR_BUFFER_TOO_SMALL;
r = sc_read_binary(card->card, 0, buf, file->size);
r = sc_read_binary(card->card, 0, buf, file->size, 0);
if (r < 0)
return r;
bytes_left = r;

View File

@ -87,8 +87,7 @@ void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin)
printf("PIN [%s]\n", pin->com_attr.label);
printf("\tFlags : %d\n", pin->com_attr.flags);
printf("\tLength : %d..%d\n", pin->min_length, pin->stored_length);
printf("\tPad char : ");
sc_print_binary(stdout, &pin->pad_char, 1);
printf("\tPad char : 0x%02X", pin->pad_char);
printf("\n");
printf("\tPath : %s\n", path);
printf("\tAuth ID : ");
@ -108,7 +107,7 @@ static int get_pins_from_file(struct sc_pkcs15_card *card,
return r;
if (file->size > sizeof(buf))
return SC_ERROR_BUFFER_TOO_SMALL;
r = sc_read_binary(card->card, 0, buf, file->size);
r = sc_read_binary(card->card, 0, buf, file->size, 0);
if (r < 0)
return r;
bytes_left = r;
@ -196,8 +195,8 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_pin_info *pin,
const char *oldpin, int oldpinlen,
const char *newpin, int newpinlen)
const u8 *oldpin, int oldpinlen,
const u8 *newpin, int newpinlen)
{
int r;
struct sc_file file;

View File

@ -104,7 +104,7 @@ static int get_prkeys_from_file(struct sc_pkcs15_card *card,
return r;
if (file->size > sizeof(buf))
return SC_ERROR_BUFFER_TOO_SMALL;
r = sc_read_binary(card->card, 0, buf, file->size);
r = sc_read_binary(card->card, 0, buf, file->size, 0);
if (r < 0)
return r;
bytes_left = r;

View File

@ -274,7 +274,7 @@ int sc_pkcs15_bind(struct sc_card *card,
error(ctx, "Error selecting EF(DIR): %s\n", sc_strerror(err));
goto error;
}
err = sc_read_binary(card, 0, buf, p15card->file_dir.size);
err = sc_read_binary(card, 0, buf, p15card->file_dir.size, 0);
if (err < 0) {
error(ctx, "Error reading EF(DIR): %s\n", sc_strerror(err));
goto error;
@ -303,7 +303,7 @@ int sc_pkcs15_bind(struct sc_card *card,
err = sc_select_file(card, &tmppath, &p15card->file_odf);
if (err) /* FIXME: finish writing error stuff */
goto error;
err = sc_read_binary(card, 0, buf, p15card->file_odf.size);
err = sc_read_binary(card, 0, buf, p15card->file_odf.size, 0);
if (err < 0)
goto error;
if (err < 2) {
@ -328,7 +328,7 @@ int sc_pkcs15_bind(struct sc_card *card,
err = sc_select_file(card, &tmppath, &p15card->file_tokeninfo);
if (err)
goto error;
err = sc_read_binary(card, 0, buf, p15card->file_tokeninfo.size);
err = sc_read_binary(card, 0, buf, p15card->file_tokeninfo.size, 0);
if (err < 0)
goto error;
if (err <= 2) {

View File

@ -220,8 +220,8 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *card,
const u8 *pincode, int pinlen);
int sc_pkcs15_change_pin(struct sc_pkcs15_card *card,
struct sc_pkcs15_pin_info *pin,
const char *oldpincode, int oldpinlen,
const char *newpincode, int newpinlen);
const u8 *oldpincode, int oldpinlen,
const u8 *newpincode, int newpinlen);
int sc_pkcs15_find_pin_by_auth_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_pin_info **out);

View File

@ -19,6 +19,7 @@
*/
#include "sc-internal.h"
#include "sc-log.h"
static struct sc_card_operations emv_ops;
static const struct sc_card_driver emv_drv = {
@ -32,20 +33,85 @@ static int emv_finish(struct sc_card *card)
return 0;
}
static int parse_atr(const u8 *atr, size_t atr_len, int *t0_out, int *tx1, int *tx2,
u8 *hist_bytes, int *hbcount)
{
const u8 *p = atr;
int len = atr_len;
int nr_hist_bytes, tx, i;
if (len < 2)
return -1;
p++;
len--;
*t0_out = *p;
nr_hist_bytes = *p & 0x0F;
tx = *p >> 4;
p++;
for (i = 0; i < 4; i++)
tx1[i] = tx2[i] = -1;
for (i = 0; i < 4; i++)
if (tx & (1 << i)) {
if (len <= 0)
return -1;
tx1[i] = *p++;
len--;
}
if (tx1[3] != -1) {
tx = tx1[3] >> 4;
for (i = 0; i < 4; i++)
if (tx & (1 << i)) {
if (len <= 0)
return -1;
tx2[i] = *p++;
len--;
}
}
/* FIXME: possibly check TD2 */
if (hist_bytes == NULL || nr_hist_bytes == 0)
return 0;
if (len < nr_hist_bytes)
return -1;
memcpy(hist_bytes, p, nr_hist_bytes);
*hbcount = nr_hist_bytes;
return 0;
}
static int emv_match_card(struct sc_card *card)
{
int i, match = -1;
const char *str = "BWAVANT";
int i, r, hbcount = 0, match = 1;
int tx1[4], tx2[4], t0;
char line[200], *linep = line;
u8 hist_bytes[32];
for (i = 0; i < card->atr_len - strlen(str); i++)
if (memcmp(card->atr + i, str, strlen(str)) == 0) {
match = 1;
break;
r = parse_atr(card->atr, card->atr_len, &t0, tx1, tx2, hist_bytes, &hbcount);
if (r)
return 0;
for (i = 0; i < 4; i++)
if (tx1[i] != -1)
linep += sprintf(linep, "T%c1 = 0x%02X ", 'A' + i, tx1[i]);
for (i = 0; i < 4; i++)
if (tx2[i] != -1)
linep += sprintf(linep, "T%c2 = 0x%02X ", 'A' + i, tx2[i]);
if (card->ctx->debug >= 4) {
debug(card->ctx, "ATR parse: %s\n", line);
if (hbcount) {
sc_hex_dump(card->ctx, hist_bytes, hbcount, line, sizeof(line));
debug(card->ctx, "historic bytes:\n%s", line);
}
if (match == 1)
return 1;
return 0;
}
if ((t0 & 0xF0) != 0x60)
match = 0;
if (match && tx1[1] != 0x00)
match = 0;
if (match && tx1[2] == -1)
match = 0;
if (match)
for (i = 0; i < 4; i++)
if (tx2[i] != -1)
match = 0;
return match;
}
static int emv_init(struct sc_card *card)
@ -66,6 +132,8 @@ static int emv_select_file(struct sc_card *card, const struct sc_path *path,
r = ops->select_file(card, path, file);
if (file != NULL && path->len == 2 && memcmp(path->value, "\x3F\x00", 2) == 0)
file->type = SC_FILE_TYPE_DF;
if (file->namelen)
file->type = SC_FILE_TYPE_DF;
return r;
}

View File

@ -31,12 +31,6 @@
#define SC_CARD_MAGIC 0x27182818
/* Internal use only */
inline int sc_card_valid(const struct sc_card *card);
inline int sc_file_valid(const struct sc_file *file);
void sc_print_binary(FILE *f, const u8 *buf, int len);
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen);
int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2);
void sc_format_path(const char *path_in, struct sc_path *path_out);
#endif

View File

@ -37,22 +37,6 @@ const char *sc_version = VERSION;
const char *sc_version = "(undef)";
#endif
void sc_print_binary(FILE *f, const u8 *buf, int count)
{
int i;
for (i = 0; i < count; i++) {
unsigned char c = buf[i];
const char *format;
if (!isalnum(c) && !ispunct(c) && !isspace(c))
format = "\\x%02X";
else
format = "%c";
fprintf(f, format, c);
}
(void) fflush(f);
}
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen)
{
int err = 0;
@ -279,6 +263,9 @@ const char *sc_strerror(int error)
"Required ASN.1 object not found",
"Premature end of ASN.1 stream",
"Too many objects",
"Card is invalid or cannot be handled",
"Wrong length",
"Record not found"
};
int nr_errors = sizeof(errors) / sizeof(errors[0]);

View File

@ -8,7 +8,6 @@
#include <string.h>
#include <opensc.h>
#include <opensc-pkcs15.h>
#include <sc-internal.h>
#include "sc-test.h"
struct sc_pkcs15_card *p15card;

View File

@ -6,5 +6,6 @@ LDFLAGS = @LDFLAGS@ \
bin_PROGRAMS = opensc-crypt opensc-tool
opensc_crypt_SOURCES = opensc-crypt.c
opensc_tool_SOURCES = opensc-tool.c
opensc_crypt_SOURCES = opensc-crypt.c util.c
opensc_tool_SOURCES = opensc-tool.c util.c
noinst_HEADERS = util.h

View File

@ -27,7 +27,7 @@
#include <opensc.h>
#include <opensc-pkcs15.h>
#include <sc-internal.h>
#include "util.h"
int opt_reader = 0, opt_pin = 0, quiet = 0;
int opt_debug = 0;
@ -155,7 +155,7 @@ int write_output(const u8 *buf, int len)
output_binary = 0;
}
if (output_binary == 0)
sc_print_binary(outf, buf, len);
print_binary(outf, buf, len);
else
fwrite(buf, len, 1, outf);
if (outf != stdout)

View File

@ -29,7 +29,7 @@
#include <sys/stat.h>
#include <ctype.h>
#include <sc-internal.h>
#include "util.h"
#define OPT_CHANGE_PIN 0x100
#define OPT_LIST_PINS 0x101
@ -119,40 +119,6 @@ void print_usage_and_die()
exit(2);
}
void hex_dump(const u8 *in, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%02X ", in[i]);
}
void hex_dump_asc(const u8 *in, size_t count)
{
int lines = 0;
while (count) {
char ascbuf[17];
int i;
for (i = 0; i < count && i < 16; i++) {
printf("%02X ", *in);
if (isprint(*in))
ascbuf[i] = *in;
else
ascbuf[i] = '.';
in++;
}
count -= i;
ascbuf[i] = 0;
for (; i < 16 && lines; i++)
printf(" ");
printf("%s\n", ascbuf);
lines++;
}
}
int list_readers()
{
int i;
@ -401,70 +367,132 @@ int change_pin()
return 0;
}
const char * print_acl(unsigned int acl)
{
static char line[80];
if (acl == SC_AC_UNKNOWN)
return "UNKN";
if (acl == SC_AC_NEVER)
return "NEVR";
if (acl == SC_AC_NONE)
return "NONE";
line[0] = 0;
if (acl & SC_AC_CHV1)
strcat(line, "CHV1 ");
if (acl & SC_AC_CHV2)
strcat(line, "CHV2 ");
if (acl & SC_AC_TERM)
strcat(line, "TERM ");
if (acl & SC_AC_PRO)
strcat(line, "PROT ");
line[strlen(line)-1] = 0; /* get rid of trailing space */
return line;
}
int print_file(struct sc_card *card, const struct sc_file *file, const struct sc_path *path, int depth)
{
int r;
const char *tmps;
const char *ac_ops_df[] = {
"select", "lock", "delete", "create", "rehab", "inval"
};
const char *ac_ops_ef[] = {
"read", "update", "write", "erase", "rehab", "inval"
};
for (r = 0; r < depth; r++)
printf(" ");
for (r = 0; r < path->len; r++) {
printf("%02X", path->value[r]);
if (r && (r & 1) == 1)
printf(" ");
}
if (file->namelen) {
printf("[");
print_binary(stdout, file->name, file->namelen);
printf("] ");
}
switch (file->type) {
case SC_FILE_TYPE_WORKING_EF:
tmps = "wEF";
break;
case SC_FILE_TYPE_INTERNAL_EF:
tmps = "iEF";
break;
case SC_FILE_TYPE_DF:
tmps = " DF";
break;
default:
tmps = "unknown";
break;
}
printf("type: %-3s, ", tmps);
if (file->type != SC_FILE_TYPE_DF) {
const char *structs[] = {
"unknown", "transpnt", "linrfix", "linrfix(TLV)",
"linvar", "linvar(TLV)", "lincyc", "lincyc(TLV)"
};
printf("ef structure: %s, ", structs[file->ef_structure]);
}
printf("size: %d\n", file->size);
for (r = 0; r < depth; r++)
printf(" ");
if (file->type == SC_FILE_TYPE_DF)
for (r = 0; r < sizeof(ac_ops_df)/sizeof(ac_ops_df[0]); r++)
printf("%s[%s] ", ac_ops_df[r], print_acl(file->acl[r]));
else
for (r = 0; r < sizeof(ac_ops_ef)/sizeof(ac_ops_ef[0]); r++)
printf("%s[%s] ", ac_ops_ef[r], print_acl(file->acl[r]));
if (file->sec_attr_len) {
printf("sec: ");
/* Octets are as follows:
* DF: select, lock, delete, create, rehab, inval
* EF: read, update, write, erase, rehab, inval
* 4 MSB's of the octet mean:
* 0 = ALW, 1 = PIN1, 2 = PIN2, 4 = SYS,
* 15 = NEV */
hex_dump(stdout, file->sec_attr, file->sec_attr_len);
}
if (file->prop_attr_len) {
printf("\n");
for (r = 0; r < depth; r++)
printf(" ");
printf("prop: ");
hex_dump(stdout, file->prop_attr, file->prop_attr_len);
}
printf("\n\n");
#if 0
if (file->type != SC_FILE_TYPE_DF) {
u8 buf[2048];
if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
r = sc_read_binary(card, 0, buf, file->size, 0);
if (r > 0)
hex_dump_asc(stdout, buf, r);
} else {
r = sc_read_record(card, 0, buf, file->size, 0);
if (r > 0)
hex_dump_asc(stdout, buf, r);
}
}
#endif
return 0;
}
int enum_dir(struct sc_path path, int depth)
{
struct sc_file file;
int r;
u8 files[MAX_BUFFER_SIZE];
u8 buf[2048];
const char *tmps;
r = sc_select_file(card, &path, &file);
if (r) {
fprintf(stderr, "SELECT FILE failed: %s\n", sc_strerror(r));
return 1;
}
for (r = 0; r < depth; r++) {
printf(" ");
}
for (r = 0; r < path.len; r++) {
printf("%02X", path.value[r]);
if (r && (r & 1) == 1)
printf(" ");
}
if (sc_file_valid(&file)) {
if (file.namelen) {
printf("[");
sc_print_binary(stdout, file.name, file.namelen);
printf("] ");
}
switch (file.type) {
case SC_FILE_TYPE_WORKING_EF:
tmps = "wEF";
break;
case SC_FILE_TYPE_INTERNAL_EF:
tmps = "iEF";
break;
case SC_FILE_TYPE_DF:
tmps = "DF";
break;
default:
tmps = "unknown";
break;
}
printf("type: %-3s ", tmps);
if (file.type != SC_FILE_TYPE_DF)
printf("ef structure: %d ", file.ef_structure);
printf("size: %d ", file.size);
if (file.sec_attr_len) {
printf("sec: ");
/* Octets are as follows:
* DF: select, lock, delete, create, rehab, inval
* EF: read, update, write, erase, rehab, inval
* 4 MSB's of the octet mean:
* 0 = ALW, 1 = PIN1, 2 = PIN2, 4 = SYS,
* 15 = NEV */
hex_dump(file.sec_attr, file.sec_attr_len);
}
printf("\n");
if (file.type != SC_FILE_TYPE_DF && 1) {
r = sc_read_binary(card, 0, buf, file.size);
if (r > 0)
hex_dump_asc(buf, r);
}
} else {
printf("\n");
}
if (sc_file_valid(&file))
print_file(card, &file, &path, depth);
if (!sc_file_valid(&file) || file.type == SC_FILE_TYPE_DF) {
int i;
@ -599,7 +627,6 @@ int send_apdu()
apdu.resplen = sizeof(rbuf);
apdu.data = NULL;
apdu.datalen = 0;
apdu.no_response = 0;
len -= 4;
if (len > 1) {
apdu.lc = *p++;
@ -643,7 +670,7 @@ int send_apdu()
printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2,
apdu.resplen ? ":" : "");
if (apdu.resplen)
hex_dump_asc(apdu.resp, apdu.resplen);
hex_dump_asc(stdout, apdu.resp, apdu.resplen);
return 0;
}
@ -771,7 +798,7 @@ int main(int argc, char * const argv[])
err = 1;
goto end;
}
printf("Using card driver: %s\n", card->driver->name);
r = sc_lock(card);
if (r) {
fprintf(stderr, "Unable to lock card: %s\n", sc_strerror(r));