- continued improving ASN.1 decoding
- improved debug levels - added some PC/SC Lite workarounds git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@87 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
41416437e5
commit
c17ff3ebdf
@ -354,6 +354,7 @@ static int decode_bit_string(const u8 * inbuf, int inlen, void *outbuf,
|
||||
int octets_left = inlen - 1;
|
||||
int i, count = 0;
|
||||
|
||||
memset(outbuf, 0, outlen);
|
||||
in++;
|
||||
if (outlen < octets_left)
|
||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||
@ -527,7 +528,7 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr
|
||||
int *len = entry->len;
|
||||
int r = 0;
|
||||
|
||||
if (ctx->debug > 2) {
|
||||
if (ctx->debug >= 3) {
|
||||
u8 line[128], *linep = line;
|
||||
int i;
|
||||
|
||||
@ -556,6 +557,7 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr
|
||||
}
|
||||
break;
|
||||
case SC_ASN1_INTEGER:
|
||||
case SC_ASN1_ENUMERATED:
|
||||
if (parm != NULL)
|
||||
r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm);
|
||||
break;
|
||||
@ -627,7 +629,7 @@ static int asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||
struct sc_asn1_struct *entry = asn1;
|
||||
int left = len, objlen;
|
||||
|
||||
if (ctx->debug > 2)
|
||||
if (ctx->debug >= 3)
|
||||
debug(ctx, "called, depth %d%s\n", depth, choice ? ", choice" : "");
|
||||
if (left < 2)
|
||||
return SC_ERROR_ASN1_END_OF_CONTENTS;
|
||||
@ -640,8 +642,12 @@ static int asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||
if (obj == NULL) {
|
||||
if (choice)
|
||||
continue;
|
||||
if (entry->flags & SC_ASN1_OPTIONAL)
|
||||
if (entry->flags & SC_ASN1_OPTIONAL) {
|
||||
if (ctx->debug >= 3)
|
||||
debug(ctx, "optional ASN.1 object '%s' not present\n",
|
||||
entry->name);
|
||||
continue;
|
||||
}
|
||||
error(ctx, "mandatory ASN.1 object '%s' not found\n", entry->name);
|
||||
if (ctx->debug && left) {
|
||||
u8 line[128], *linep = line;
|
||||
@ -654,7 +660,7 @@ static int asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||
}
|
||||
debug(ctx, "next tag: %s\n", line);
|
||||
}
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_ASN1_OBJECT_NOT_FOUND);
|
||||
SC_FUNC_RETURN(ctx, 3, SC_ERROR_ASN1_OBJECT_NOT_FOUND);
|
||||
}
|
||||
r = asn1_decode_entry(ctx, entry, obj, objlen, depth);
|
||||
if (r)
|
||||
@ -663,14 +669,14 @@ static int asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||
break;
|
||||
}
|
||||
if (choice && asn1[idx].name == NULL) /* No match */
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_ASN1_OBJECT_NOT_FOUND);
|
||||
SC_FUNC_RETURN(ctx, 3, SC_ERROR_ASN1_OBJECT_NOT_FOUND);
|
||||
if (newp != NULL)
|
||||
*newp = p;
|
||||
if (len_left != NULL)
|
||||
*len_left = left;
|
||||
if (choice)
|
||||
SC_FUNC_RETURN(ctx, idx);
|
||||
SC_FUNC_RETURN(ctx, 0);
|
||||
SC_FUNC_RETURN(ctx, 3, idx);
|
||||
SC_FUNC_RETURN(ctx, 3, 0);
|
||||
}
|
||||
|
||||
int sc_asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||
|
@ -32,16 +32,7 @@ void error(struct sc_context *ctx, const char *format, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
do_log2(ctx, SC_LOG_ERROR, "", format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log(struct sc_context *ctx, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
do_log2(ctx, SC_LOG_NORMAL, "", format, ap);
|
||||
do_log2(ctx, SC_LOG_TYPE_ERROR, "", format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@ -50,7 +41,7 @@ void debug(struct sc_context *ctx, const char *format, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
do_log2(ctx, SC_LOG_DEBUG, "", format, ap);
|
||||
do_log2(ctx, SC_LOG_TYPE_DEBUG, "", format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@ -79,12 +70,11 @@ void do_log2(struct sc_context *ctx, int type, const char *file,
|
||||
assert(ctx != NULL);
|
||||
if (ctx->use_std_output) {
|
||||
switch (type) {
|
||||
case SC_LOG_ERROR:
|
||||
case SC_LOG_TYPE_ERROR:
|
||||
outf = stderr;
|
||||
break;
|
||||
case SC_LOG_NORMAL:
|
||||
case SC_LOG_DEBUG:
|
||||
case SC_LOG_DEBUG2:
|
||||
|
||||
case SC_LOG_TYPE_DEBUG:
|
||||
outf = stdout;
|
||||
}
|
||||
if (outf == NULL)
|
||||
@ -122,14 +112,15 @@ void do_log2(struct sc_context *ctx, int type, const char *file,
|
||||
if (do_color) {
|
||||
color_sfx = "\e[0m";
|
||||
switch (type) {
|
||||
case SC_LOG_ERROR:
|
||||
case SC_LOG_TYPE_ERROR:
|
||||
color_pfx = "\e[01;31m";
|
||||
break;
|
||||
case SC_LOG_NORMAL:
|
||||
#if 0
|
||||
case SC_LOG_TYPE_NORMAL:
|
||||
color_pfx = "\e[01;33m";
|
||||
break;
|
||||
case SC_LOG_DEBUG:
|
||||
case SC_LOG_DEBUG2:
|
||||
#endif
|
||||
case SC_LOG_TYPE_DEBUG:
|
||||
color_pfx = "\e[00;32m";
|
||||
break;
|
||||
}
|
||||
|
@ -24,34 +24,29 @@
|
||||
#include "opensc.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SC_LOG_ERROR 0
|
||||
#define SC_LOG_NORMAL 1
|
||||
#define SC_LOG_VERBOSE 2
|
||||
#define SC_LOG_DEBUG 3
|
||||
#define SC_LOG_DEBUG2 4
|
||||
#define SC_LOG_TYPE_ERROR 0
|
||||
#define SC_LOG_TYPE_VERBOSE 1
|
||||
#define SC_LOG_TYPE_DEBUG 2
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define error(ctx, format, args...) do_log(ctx, SC_LOG_ERROR, __FILE__, __LINE__, __FUNCTION__ , format , ## args)
|
||||
#define log(ctx, format, args...) do_log(ctx, SC_LOG_NORMAL, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
#define debug(ctx, format, args...) do_log(ctx, SC_LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
#define debug2(ctx, format, args...) do_log(ctx, SC_LOG_DEBUG2, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
#define error(ctx, format, args...) do_log(ctx, SC_LOG_TYPE_ERROR, __FILE__, __LINE__, __FUNCTION__ , format , ## args)
|
||||
#define debug(ctx, format, args...) do_log(ctx, SC_LOG_TYPE_DEBUG, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
|
||||
#else
|
||||
|
||||
void error(struct sc_context *ctx, const char *format, ...);
|
||||
void log(struct sc_context *ctx, const char *format, ...);
|
||||
void debug(struct sc_context *ctx, const char *format, ...);
|
||||
void debug2(struct sc_context *ctx, const char *format, ...);
|
||||
|
||||
#endif
|
||||
|
||||
#define SC_FUNC_CALLED(ctx) {\
|
||||
if ((ctx)->debug > 2)\
|
||||
#define SC_FUNC_CALLED(ctx, level) {\
|
||||
if ((ctx)->debug >= level)\
|
||||
debug(ctx, "called\n"); }
|
||||
#define SC_FUNC_RETURN(ctx, r) {\
|
||||
#define SC_FUNC_RETURN(ctx, level, r) {\
|
||||
int _ret = r;\
|
||||
if (_ret < 0) {\
|
||||
error(ctx, "returning with: %s\n", sc_strerror(_ret));\
|
||||
} else if ((ctx)->debug > 2) {\
|
||||
} else if ((ctx)->debug >= level) {\
|
||||
debug(ctx, "returning with: %d\n", _ret);\
|
||||
}\
|
||||
return _ret; }
|
||||
|
@ -58,6 +58,7 @@ struct sc_pkcs15_pin_info {
|
||||
struct sc_pkcs15_common_obj_attr com_attr;
|
||||
|
||||
struct sc_pkcs15_id auth_id;
|
||||
int reference;
|
||||
int flags, type;
|
||||
int min_length, stored_length;
|
||||
u8 pad_char;
|
||||
@ -129,7 +130,7 @@ struct sc_pkcs15_prkey_info {
|
||||
struct sc_pkcs15_common_obj_attr com_attr;
|
||||
|
||||
struct sc_pkcs15_id id; /* correlates to public certificate id */
|
||||
int usage, access_flags;
|
||||
int usage, access_flags, native;
|
||||
int key_reference;
|
||||
|
||||
struct sc_path file_id;
|
||||
@ -173,9 +174,12 @@ struct sc_pkcs15_defaults {
|
||||
int arg;
|
||||
};
|
||||
|
||||
int sc_pkcs15_init(struct sc_card *card,
|
||||
/* Binds a card object to a PKCS#15 card object and initializes
|
||||
* a new PKCS#15 card object */
|
||||
int sc_pkcs15_bind(struct sc_card *card,
|
||||
struct sc_pkcs15_card **pkcs15_card);
|
||||
int sc_pkcs15_destroy(struct sc_pkcs15_card *card);
|
||||
|
||||
int sc_pkcs15_unbind(struct sc_pkcs15_card *card);
|
||||
|
||||
int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
|
||||
const struct sc_pkcs15_prkey_info *prkey,
|
||||
|
@ -42,7 +42,7 @@ extern "C" {
|
||||
#define SC_ERROR_OUT_OF_MEMORY -1009
|
||||
#define SC_ERROR_NO_READERS_FOUND -1010
|
||||
#define SC_ERROR_OBJECT_NOT_VALID -1011
|
||||
#define SC_ERROR_UNKNOWN_RESPONSE -1012
|
||||
#define SC_ERROR_ILLEGAL_RESPONSE -1012
|
||||
#define SC_ERROR_PIN_CODE_INCORRECT -1013
|
||||
#define SC_ERROR_SECURITY_STATUS_NOT_SATISFIED -1014
|
||||
#define SC_ERROR_CONNECTING_TO_RES_MGR -1015
|
||||
@ -106,7 +106,6 @@ extern "C" {
|
||||
#define SC_ASN1_MAX_OBJECT_ID_OCTETS 16
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
struct sc_object_id {
|
||||
int value[SC_ASN1_MAX_OBJECT_ID_OCTETS];
|
||||
@ -132,6 +131,9 @@ struct sc_file {
|
||||
unsigned int magic;
|
||||
};
|
||||
|
||||
#define SC_SEC_OPERATION_DECIPHER 0
|
||||
#define SC_SEC_OPERATION_SIGN 1
|
||||
|
||||
struct sc_security_env {
|
||||
int algorithm_ref;
|
||||
struct sc_path key_file_id;
|
||||
@ -146,19 +148,19 @@ struct sc_card_operations {
|
||||
int (*init)(struct sc_card *card);
|
||||
int (*finish)(struct sc_card *card);
|
||||
|
||||
int (*read_binary)(struct sc_card *card, uint32 idx,
|
||||
int (*read_binary)(struct sc_card *card, unsigned int idx,
|
||||
u8 * buf, size_t count);
|
||||
int (*write_binary)(struct sc_card *card, uint32 idx,
|
||||
int (*write_binary)(struct sc_card *card, unsigned int idx,
|
||||
const u8 * buf, size_t count);
|
||||
int (*update_binary)(struct sc_card *card, uint32 idx,
|
||||
int (*update_binary)(struct sc_card *card, unsigned int idx,
|
||||
const u8 * buf, size_t count);
|
||||
int (*erase_binary)(struct sc_card *card, uint32 idx,
|
||||
int (*erase_binary)(struct sc_card *card, unsigned int idx,
|
||||
size_t count);
|
||||
int (*read_binary_large)(struct sc_card *card, uint32 idx,
|
||||
int (*read_binary_large)(struct sc_card *card, unsigned int idx,
|
||||
u8 * buf, size_t count);
|
||||
int (*write_binary_large)(struct sc_card *card, uint32 idx,
|
||||
int (*write_binary_large)(struct sc_card *card, unsigned int idx,
|
||||
const u8 * buf, size_t count);
|
||||
int (*update_binary_large)(struct sc_card *card, uint32 idx,
|
||||
int (*update_binary_large)(struct sc_card *card, unsigned int idx,
|
||||
const u8 * buf, size_t count);
|
||||
/* possibly TODO: record handling */
|
||||
int (*select_file)(struct sc_card *card, struct sc_file *file,
|
||||
|
@ -224,7 +224,7 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card,
|
||||
struct sc_pkcs15_cert *cert;
|
||||
|
||||
assert(p15card != NULL && info != NULL && cert_out != NULL);
|
||||
SC_FUNC_CALLED(p15card->card->ctx);
|
||||
SC_FUNC_CALLED(p15card->card->ctx, 1);
|
||||
r = find_cached_cert(p15card, info, &data, &len);
|
||||
if (r) {
|
||||
r = sc_select_file(p15card->card, &file, &info->path,
|
||||
@ -290,7 +290,7 @@ static int parse_x509_cert_info(struct sc_context *ctx,
|
||||
struct sc_pkcs15_object cert_obj = { &cert->com_attr, asn1_com_cert_attr, NULL,
|
||||
asn1_type_cert_attr };
|
||||
struct sc_asn1_struct asn1_cert[] = {
|
||||
{ "x509Certificate", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &cert_obj, },
|
||||
{ "x509Certificate", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &cert_obj },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -332,15 +332,17 @@ static int get_certs_from_file(struct sc_pkcs15_card *card,
|
||||
return r;
|
||||
bytes_left = r;
|
||||
do {
|
||||
if (card->cert_count >= SC_PKCS15_MAX_CERTS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
struct sc_pkcs15_cert_info tmp;
|
||||
|
||||
r = parse_x509_cert_info(card->card->ctx,
|
||||
&card->cert_info[card->cert_count],
|
||||
&p, &bytes_left);
|
||||
&tmp, &p, &bytes_left);
|
||||
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
|
||||
break;
|
||||
if (r)
|
||||
return r;
|
||||
if (card->cert_count >= SC_PKCS15_MAX_CERTS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
card->cert_info[card->cert_count] = tmp;
|
||||
card->cert_count++;
|
||||
} while (bytes_left);
|
||||
|
||||
|
@ -27,73 +27,49 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int decode_pin_info(const u8 *buf,
|
||||
int buflen, struct sc_pkcs15_pin_info *pin)
|
||||
static int parse_pin_info(struct sc_context *ctx,
|
||||
struct sc_pkcs15_pin_info *pin,
|
||||
const u8 ** buf, int *buflen)
|
||||
{
|
||||
const u8 *tag, *p = buf;
|
||||
int taglen, left = buflen;
|
||||
int r;
|
||||
struct sc_asn1_struct asn1_com_ao_attr[] = {
|
||||
{ "authId", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, 0, &pin->auth_id },
|
||||
{ NULL }
|
||||
};
|
||||
int flags_len = sizeof(pin->flags);
|
||||
int padchar_len = 1;
|
||||
struct sc_asn1_struct asn1_pin_attr[] = {
|
||||
{ "pinFlags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, 0, &pin->flags, &flags_len},
|
||||
{ "pinType", SC_ASN1_ENUMERATED, ASN1_ENUMERATED, 0, &pin->type },
|
||||
{ "minLength", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &pin->min_length },
|
||||
{ "storedLength", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &pin->stored_length },
|
||||
{ "maxLength", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, NULL },
|
||||
{ "pinReference", SC_ASN1_INTEGER, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, &pin->reference },
|
||||
{ "padChar", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, SC_ASN1_OPTIONAL, &pin->pad_char, &padchar_len },
|
||||
{ "lastPinChange",SC_ASN1_GENERALIZEDTIME, ASN1_GENERALIZEDTIME, SC_ASN1_OPTIONAL, NULL },
|
||||
{ "path", SC_ASN1_PATH, ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, &pin->path },
|
||||
{ NULL }
|
||||
};
|
||||
struct sc_asn1_struct asn1_type_pin_attr[] = {
|
||||
{ "pinAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_pin_attr},
|
||||
{ NULL }
|
||||
};
|
||||
struct sc_pkcs15_object pin_obj = { &pin->com_attr, asn1_com_ao_attr, NULL,
|
||||
asn1_type_pin_attr };
|
||||
struct sc_asn1_struct asn1_pin[] = {
|
||||
{ "pin", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &pin_obj },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
pin->reference = 0;
|
||||
|
||||
memset(pin, 0, sizeof(*pin));
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
sc_pkcs15_parse_common_object_attr(&pin->com_attr, tag, taglen);
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
tag = sc_asn1_verify_tag(tag, taglen, 0x04, &taglen); /* OCTET STRING */
|
||||
if (tag == NULL || taglen == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
if (taglen > SC_PKCS15_MAX_ID_SIZE)
|
||||
taglen = SC_PKCS15_MAX_ID_SIZE;
|
||||
memcpy(pin->auth_id.value, tag, taglen);
|
||||
pin->auth_id.len = taglen;
|
||||
r = sc_asn1_parse(ctx, asn1_pin, *buf, *buflen, buf, buflen);
|
||||
if (r == 0)
|
||||
pin->magic = SC_PKCS15_PIN_MAGIC;
|
||||
|
||||
p = sc_asn1_verify_tag(p, left, 0xA1, &left); /* CONS */
|
||||
if (left == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
p = sc_asn1_verify_tag(p, left, 0x30, &left);
|
||||
if (left == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen);
|
||||
if (taglen == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
sc_asn1_decode_bit_string(tag, taglen, &pin->flags,
|
||||
sizeof(pin->flags));
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x0A, &taglen);
|
||||
if (taglen == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
pin->type = tag[0];
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen);
|
||||
if (taglen == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
pin->min_length = tag[0];
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen);
|
||||
if (taglen == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
pin->stored_length = tag[0];
|
||||
|
||||
tag = sc_asn1_find_tag(p, left, 0x04, &taglen);
|
||||
if (taglen == 0)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
pin->pad_char = tag[0];
|
||||
|
||||
tag = sc_asn1_find_tag(p, left, 0x30, &taglen);
|
||||
if (taglen != 0) {
|
||||
tag = sc_asn1_find_tag(tag, taglen, 0x04, &taglen);
|
||||
if (taglen >= 0) {
|
||||
memcpy(pin->path.value, tag, taglen);
|
||||
pin->path.len = taglen;
|
||||
}
|
||||
}
|
||||
pin->magic = SC_PKCS15_PIN_MAGIC;
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin)
|
||||
@ -120,36 +96,40 @@ void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int get_pins_from_file(struct sc_pkcs15_card *p15card,
|
||||
static int get_pins_from_file(struct sc_pkcs15_card *card,
|
||||
struct sc_file *file)
|
||||
{
|
||||
int r, taglen, left;
|
||||
const u8 *p, *tag;
|
||||
u8 buf[MAX_BUFFER_SIZE];
|
||||
int r, bytes_left;
|
||||
u8 buf[2048];
|
||||
const u8 *p = buf;
|
||||
|
||||
r = sc_select_file(p15card->card, file, &file->path,
|
||||
r = sc_select_file(card->card, file, &file->path,
|
||||
SC_SELECT_FILE_BY_PATH);
|
||||
if (r)
|
||||
return r;
|
||||
if (file->size > sizeof(buf))
|
||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||
r = sc_read_binary(p15card->card, 0, buf, file->size);
|
||||
r = sc_read_binary(card->card, 0, buf, file->size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
bytes_left = r;
|
||||
do {
|
||||
struct sc_pkcs15_pin_info tmp;
|
||||
|
||||
left = r;
|
||||
p = buf;
|
||||
while ((tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen)) != NULL) {
|
||||
if (p15card->pin_count >= SC_PKCS15_MAX_PINS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
r = decode_pin_info(tag, taglen,
|
||||
&p15card->pin_info[p15card->pin_count]);
|
||||
r = parse_pin_info(card->card->ctx,
|
||||
&tmp, &p, &bytes_left);
|
||||
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
|
||||
break;
|
||||
if (r)
|
||||
return r;
|
||||
if (card->pin_count >= SC_PKCS15_MAX_CERTS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
card->pin_info[card->pin_count] = tmp;
|
||||
card->pin_count++;
|
||||
} while (bytes_left);
|
||||
|
||||
p15card->pin_count++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
|
||||
@ -158,7 +138,7 @@ int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
|
||||
struct sc_context *ctx = p15card->card->ctx;
|
||||
|
||||
assert(p15card != NULL);
|
||||
SC_FUNC_CALLED(ctx);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
if (p15card->pin_count) {
|
||||
for (i = 0; i < p15card->pin_count; i++) {
|
||||
if (p15card->pin_info[i].magic != SC_PKCS15_PIN_MAGIC)
|
||||
@ -167,6 +147,7 @@ int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
|
||||
if (i == p15card->pin_count)
|
||||
return i; /* Already enumerated */
|
||||
}
|
||||
p15card->pin_count = 0;
|
||||
for (i = 0; i < p15card->aodf_count; i++) {
|
||||
r = get_pins_from_file(p15card, &p15card->file_aodf[i]);
|
||||
SC_TEST_RET(ctx, r, "Failed to read PINs from AODF");
|
||||
|
@ -47,105 +47,97 @@ void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int parse_prkey_info(const u8 * buf,
|
||||
int buflen, struct sc_pkcs15_prkey_info *prkey)
|
||||
static int parse_rsa_prkey_info(struct sc_context *ctx,
|
||||
struct sc_pkcs15_prkey_info *prkey,
|
||||
const u8 **buf, int *buflen)
|
||||
{
|
||||
const u8 *tag, *p;
|
||||
int taglen, left;
|
||||
int r;
|
||||
int usage_len = sizeof(prkey->usage);
|
||||
int af_len = sizeof(prkey->access_flags);
|
||||
struct sc_asn1_struct asn1_com_key_attr[] = {
|
||||
{ "iD", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, 0, &prkey->id, NULL },
|
||||
{ "usage", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, 0, &prkey->usage, &usage_len },
|
||||
{ "native", SC_ASN1_BOOLEAN, ASN1_BOOLEAN, SC_ASN1_OPTIONAL, &prkey->native },
|
||||
{ "accessFlags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, SC_ASN1_OPTIONAL, &prkey->access_flags, &af_len },
|
||||
{ "keyReference",SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, &prkey->key_reference },
|
||||
{ NULL }
|
||||
};
|
||||
struct sc_asn1_struct asn1_com_prkey_attr[] = {
|
||||
{ NULL }
|
||||
};
|
||||
struct sc_asn1_struct asn1_rsakey_attr[] = {
|
||||
{ "value", SC_ASN1_PATH, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &prkey->file_id },
|
||||
{ "modulusLength", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &prkey->modulus_length },
|
||||
{ "keyInfo", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
struct sc_asn1_struct asn1_type_attr[] = {
|
||||
{ "publicRSAKeyAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_rsakey_attr },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
tag = sc_asn1_skip_tag(&buf, &buflen, 0x30, &taglen); /* SEQUENCE */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
sc_pkcs15_parse_common_object_attr(&prkey->com_attr, tag, taglen);
|
||||
struct sc_pkcs15_object prkey_obj = { &prkey->com_attr, asn1_com_key_attr,
|
||||
asn1_com_prkey_attr, asn1_type_attr };
|
||||
struct sc_asn1_struct asn1_prkey[] = {
|
||||
{ "privateRSAKey", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &prkey_obj },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
p = sc_asn1_skip_tag(&buf, &buflen, 0x30, &left); /* SEQUENCE */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
prkey->key_reference = -1;
|
||||
prkey->native = 1;
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x04, &taglen); /* OCTET STRING */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
memcpy(prkey->id.value, tag, taglen);
|
||||
prkey->id.len = taglen;
|
||||
r = sc_asn1_parse(ctx, asn1_prkey, *buf, *buflen, buf, buflen);
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen); /* BIT STRING */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
sc_asn1_decode_bit_string(tag, taglen, &prkey->usage,
|
||||
sizeof(prkey->usage));
|
||||
return r;
|
||||
}
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x01, &taglen); /* BOOLEAN */
|
||||
if (tag != NULL) {
|
||||
/* FIXME */
|
||||
}
|
||||
static int get_prkeys_from_file(struct sc_pkcs15_card *card,
|
||||
struct sc_file *file)
|
||||
{
|
||||
int r, bytes_left;
|
||||
u8 buf[2048];
|
||||
const u8 *p = buf;
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen); /* BIT STRING */
|
||||
if (tag != NULL) {
|
||||
sc_asn1_decode_bit_string(tag, taglen,
|
||||
&prkey->access_flags,
|
||||
sizeof(prkey->access_flags));
|
||||
} else
|
||||
prkey->access_flags = 0;
|
||||
r = sc_select_file(card->card, file, &file->path,
|
||||
SC_SELECT_FILE_BY_PATH);
|
||||
if (r)
|
||||
return r;
|
||||
if (file->size > sizeof(buf))
|
||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||
r = sc_read_binary(card->card, 0, buf, file->size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
bytes_left = r;
|
||||
do {
|
||||
struct sc_pkcs15_prkey_info tmp;
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
|
||||
if (tag != NULL && taglen) {
|
||||
prkey->key_reference = tag[0];
|
||||
} else
|
||||
prkey->key_reference = -1;
|
||||
|
||||
|
||||
/* FIXME */
|
||||
p = sc_asn1_find_tag(buf, buflen, 0xA1, &left);
|
||||
if (p == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
p = sc_asn1_verify_tag(p, left, 0x30, &left); /* SEQUENCE 1 */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE 2 */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
tag = sc_asn1_verify_tag(tag, taglen, 0x04, &taglen); /* OCTET STRING */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
memcpy(prkey->file_id.value, tag, taglen);
|
||||
prkey->file_id.len = taglen;
|
||||
|
||||
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
|
||||
if (tag == NULL)
|
||||
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
|
||||
sc_asn1_decode_integer(tag, taglen, &prkey->modulus_length);
|
||||
r = parse_rsa_prkey_info(card->card->ctx,
|
||||
&tmp, &p, &bytes_left);
|
||||
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
|
||||
break;
|
||||
if (r)
|
||||
return r;
|
||||
if (card->prkey_count >= SC_PKCS15_MAX_PRKEYS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
card->prkey_info[card->prkey_count] = tmp;
|
||||
card->prkey_count++;
|
||||
} while (bytes_left);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card)
|
||||
{
|
||||
int r, left, taglen;
|
||||
const u8 *p, *tag;
|
||||
u8 buf[1024];
|
||||
|
||||
int r, i;
|
||||
assert(card != NULL);
|
||||
|
||||
if (card->prkey_count)
|
||||
return card->prkey_count; /* already enumerated */
|
||||
card->prkey_count = 0;
|
||||
r = sc_select_file(card->card, &card->file_prkdf,
|
||||
&card->file_prkdf.path, SC_SELECT_FILE_BY_PATH);
|
||||
if (r)
|
||||
return r;
|
||||
r = sc_read_binary(card->card, 0, buf, card->file_prkdf.size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
left = r;
|
||||
p = buf;
|
||||
while ((tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen)) != NULL) {
|
||||
struct sc_pkcs15_prkey_info *prkey =
|
||||
&card->prkey_info[card->prkey_count];
|
||||
|
||||
if (parse_prkey_info(tag, taglen, prkey))
|
||||
break;
|
||||
card->prkey_count++;
|
||||
for (i = 0; i < 1; i++) {
|
||||
r = get_prkeys_from_file(card, &card->file_prkdf);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
return card->prkey_count;
|
||||
}
|
||||
|
@ -40,13 +40,14 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
|
||||
senv.operation = 0;
|
||||
senv.key_ref = prkey->key_reference;
|
||||
|
||||
SC_FUNC_CALLED(ctx);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
r = sc_select_file(p15card->card, &p15card->file_app,
|
||||
&p15card->file_app.path, SC_SELECT_FILE_BY_PATH);
|
||||
SC_TEST_RET(ctx, r, "sc_select_file() failed");
|
||||
r = sc_select_file(p15card->card, &p15card->file_app,
|
||||
&p15card->file_app.path, SC_SELECT_FILE_BY_PATH);
|
||||
SC_TEST_RET(ctx, r, "sc_select_file() failed");
|
||||
usleep(100*1000); /* PC/SC Lite quirks */
|
||||
r = sc_restore_security_env(p15card->card, 0); /* empty SE */
|
||||
SC_TEST_RET(ctx, r, "sc_restore_security_env() failed");
|
||||
r = sc_set_security_env(p15card->card, &senv);
|
||||
@ -78,10 +79,11 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
|
||||
senv.operation = 1;
|
||||
senv.key_ref = prkey->key_reference;
|
||||
|
||||
SC_FUNC_CALLED(ctx);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
r = sc_select_file(p15card->card, &p15card->file_app,
|
||||
&p15card->file_app.path, SC_SELECT_FILE_BY_PATH);
|
||||
SC_TEST_RET(ctx, r, "sc_select_file() failed");
|
||||
usleep(100*1000); /* PC/SC Lite quirks */
|
||||
r = sc_restore_security_env(p15card->card, 0); /* empty SE */
|
||||
SC_TEST_RET(ctx, r, "sc_restore_security_env() failed");
|
||||
r = sc_set_security_env(p15card->card, &senv);
|
||||
|
@ -236,7 +236,7 @@ static const struct sc_pkcs15_defaults * find_defaults(u8 *dir, int dirlen)
|
||||
return match;
|
||||
}
|
||||
|
||||
int sc_pkcs15_init(struct sc_card *card,
|
||||
int sc_pkcs15_bind(struct sc_card *card,
|
||||
struct sc_pkcs15_card **p15card_out)
|
||||
{
|
||||
unsigned char buf[MAX_BUFFER_SIZE];
|
||||
@ -324,7 +324,7 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
int sc_pkcs15_destroy(struct sc_pkcs15_card *p15card)
|
||||
int sc_pkcs15_unbind(struct sc_pkcs15_card *p15card)
|
||||
{
|
||||
free(p15card->label);
|
||||
free(p15card->serial_number);
|
||||
|
@ -58,6 +58,7 @@ struct sc_pkcs15_pin_info {
|
||||
struct sc_pkcs15_common_obj_attr com_attr;
|
||||
|
||||
struct sc_pkcs15_id auth_id;
|
||||
int reference;
|
||||
int flags, type;
|
||||
int min_length, stored_length;
|
||||
u8 pad_char;
|
||||
@ -129,7 +130,7 @@ struct sc_pkcs15_prkey_info {
|
||||
struct sc_pkcs15_common_obj_attr com_attr;
|
||||
|
||||
struct sc_pkcs15_id id; /* correlates to public certificate id */
|
||||
int usage, access_flags;
|
||||
int usage, access_flags, native;
|
||||
int key_reference;
|
||||
|
||||
struct sc_path file_id;
|
||||
@ -173,9 +174,12 @@ struct sc_pkcs15_defaults {
|
||||
int arg;
|
||||
};
|
||||
|
||||
int sc_pkcs15_init(struct sc_card *card,
|
||||
/* Binds a card object to a PKCS#15 card object and initializes
|
||||
* a new PKCS#15 card object */
|
||||
int sc_pkcs15_bind(struct sc_card *card,
|
||||
struct sc_pkcs15_card **pkcs15_card);
|
||||
int sc_pkcs15_destroy(struct sc_pkcs15_card *card);
|
||||
|
||||
int sc_pkcs15_unbind(struct sc_pkcs15_card *card);
|
||||
|
||||
int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
|
||||
const struct sc_pkcs15_prkey_info *prkey,
|
||||
|
@ -24,34 +24,29 @@
|
||||
#include "opensc.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SC_LOG_ERROR 0
|
||||
#define SC_LOG_NORMAL 1
|
||||
#define SC_LOG_VERBOSE 2
|
||||
#define SC_LOG_DEBUG 3
|
||||
#define SC_LOG_DEBUG2 4
|
||||
#define SC_LOG_TYPE_ERROR 0
|
||||
#define SC_LOG_TYPE_VERBOSE 1
|
||||
#define SC_LOG_TYPE_DEBUG 2
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define error(ctx, format, args...) do_log(ctx, SC_LOG_ERROR, __FILE__, __LINE__, __FUNCTION__ , format , ## args)
|
||||
#define log(ctx, format, args...) do_log(ctx, SC_LOG_NORMAL, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
#define debug(ctx, format, args...) do_log(ctx, SC_LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
#define debug2(ctx, format, args...) do_log(ctx, SC_LOG_DEBUG2, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
#define error(ctx, format, args...) do_log(ctx, SC_LOG_TYPE_ERROR, __FILE__, __LINE__, __FUNCTION__ , format , ## args)
|
||||
#define debug(ctx, format, args...) do_log(ctx, SC_LOG_TYPE_DEBUG, __FILE__, __LINE__, __FUNCTION__, format , ## args)
|
||||
|
||||
#else
|
||||
|
||||
void error(struct sc_context *ctx, const char *format, ...);
|
||||
void log(struct sc_context *ctx, const char *format, ...);
|
||||
void debug(struct sc_context *ctx, const char *format, ...);
|
||||
void debug2(struct sc_context *ctx, const char *format, ...);
|
||||
|
||||
#endif
|
||||
|
||||
#define SC_FUNC_CALLED(ctx) {\
|
||||
if ((ctx)->debug > 2)\
|
||||
#define SC_FUNC_CALLED(ctx, level) {\
|
||||
if ((ctx)->debug >= level)\
|
||||
debug(ctx, "called\n"); }
|
||||
#define SC_FUNC_RETURN(ctx, r) {\
|
||||
#define SC_FUNC_RETURN(ctx, level, r) {\
|
||||
int _ret = r;\
|
||||
if (_ret < 0) {\
|
||||
error(ctx, "returning with: %s\n", sc_strerror(_ret));\
|
||||
} else if ((ctx)->debug > 2) {\
|
||||
} else if ((ctx)->debug >= level) {\
|
||||
debug(ctx, "returning with: %d\n", _ret);\
|
||||
}\
|
||||
return _ret; }
|
||||
|
@ -118,28 +118,28 @@ int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
|
||||
switch (apdu->cse) {
|
||||
case SC_APDU_CASE_1:
|
||||
if (apdu->datalen)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
break;
|
||||
case SC_APDU_CASE_2_SHORT:
|
||||
if (apdu->datalen)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
if (apdu->resplen < apdu->le)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
break;
|
||||
case SC_APDU_CASE_3_SHORT:
|
||||
if (apdu->datalen == 0 || apdu->data == NULL)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
break;
|
||||
case SC_APDU_CASE_4_SHORT:
|
||||
if (apdu->datalen == 0 || apdu->data == NULL)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
if (apdu->resplen < apdu->le)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
break;
|
||||
case SC_APDU_CASE_2_EXT:
|
||||
case SC_APDU_CASE_3_EXT:
|
||||
case SC_APDU_CASE_4_EXT:
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -196,7 +196,7 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
|
||||
dwRecvLength = apdu->resplen + 2;
|
||||
if (dwRecvLength > 255) /* FIXME: PC/SC Lite quirk */
|
||||
dwRecvLength = 255;
|
||||
if (card->ctx->debug > 3) {
|
||||
if (card->ctx->debug >= 5) {
|
||||
char buf[2048];
|
||||
|
||||
sc_hex_dump(card->ctx, s, dwSendLength, buf, sizeof(buf));
|
||||
@ -221,7 +221,7 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
|
||||
}
|
||||
}
|
||||
if (dwRecvLength < 2)
|
||||
return SC_ERROR_UNKNOWN_RESPONSE;
|
||||
return SC_ERROR_ILLEGAL_RESPONSE;
|
||||
apdu->sw1 = r[dwRecvLength-2];
|
||||
apdu->sw2 = r[dwRecvLength-1];
|
||||
dwRecvLength -= 2;
|
||||
@ -239,12 +239,12 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
|
||||
{
|
||||
int r;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx);
|
||||
SC_FUNC_CALLED(card->ctx, 4);
|
||||
r = sc_check_apdu(card->ctx, apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU sanity check failed");
|
||||
r = sc_transceive_t0(card, apdu);
|
||||
SC_TEST_RET(card->ctx, r, "transceive_t0() failed");
|
||||
if (card->ctx->debug > 3) {
|
||||
if (card->ctx->debug >= 5) {
|
||||
char buf[2048];
|
||||
|
||||
buf[0] = 0;
|
||||
@ -273,7 +273,7 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
|
||||
sc_strerror(r));
|
||||
return r;
|
||||
}
|
||||
if (card->ctx->debug > 3) {
|
||||
if (card->ctx->debug >= 5) {
|
||||
char buf[2048];
|
||||
buf[0] = 0;
|
||||
if (rspapdu.resplen) {
|
||||
@ -315,7 +315,7 @@ int sc_detect_card(struct sc_context *ctx, int reader)
|
||||
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
|
||||
|
||||
assert(ctx != NULL);
|
||||
SC_FUNC_CALLED(ctx);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
if (reader >= ctx->reader_count || reader < 0)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
@ -324,11 +324,16 @@ int sc_detect_card(struct sc_context *ctx, int reader)
|
||||
ret = SCardGetStatusChange(ctx->pcsc_ctx, 0, rgReaderStates, 1);
|
||||
if (ret != 0) {
|
||||
error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(ret));
|
||||
SC_FUNC_RETURN(ctx, -1); /* FIXME */
|
||||
SC_FUNC_RETURN(ctx, 1, -1); /* FIXME */
|
||||
}
|
||||
if (rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT)
|
||||
SC_FUNC_RETURN(ctx, 1);
|
||||
SC_FUNC_RETURN(ctx, 0);
|
||||
if (rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT) {
|
||||
if (ctx->debug >= 1)
|
||||
debug(ctx, "card present\n");
|
||||
return 1;
|
||||
}
|
||||
if (ctx->debug >= 1)
|
||||
debug(ctx, "card absent\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout)
|
||||
@ -338,13 +343,13 @@ int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout)
|
||||
int count = 0, i;
|
||||
|
||||
assert(ctx != NULL);
|
||||
SC_FUNC_CALLED(ctx);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
if (reader >= ctx->reader_count)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
if (reader < 0) {
|
||||
if (ctx->reader_count == 0)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_NO_READERS_FOUND);
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_NO_READERS_FOUND);
|
||||
for (i = 0; i < ctx->reader_count; i++) {
|
||||
rgReaderStates[i].szReader = ctx->readers[i];
|
||||
rgReaderStates[i].dwCurrentState =
|
||||
@ -360,13 +365,13 @@ int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout)
|
||||
count);
|
||||
if (ret != 0) {
|
||||
error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(ret));
|
||||
SC_FUNC_RETURN(ctx, -1);
|
||||
SC_FUNC_RETURN(ctx, 1, -1);
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
if (rgReaderStates[i].dwEventState & SCARD_STATE_CHANGED)
|
||||
SC_FUNC_RETURN(ctx, 1);
|
||||
SC_FUNC_RETURN(ctx, 1, 1);
|
||||
}
|
||||
SC_FUNC_RETURN(ctx, 0);
|
||||
SC_FUNC_RETURN(ctx, 1, 0);
|
||||
}
|
||||
|
||||
int sc_establish_context(struct sc_context **ctx_out)
|
||||
@ -417,7 +422,7 @@ int sc_destroy_context(struct sc_context *ctx)
|
||||
int i;
|
||||
|
||||
assert(ctx != NULL);
|
||||
SC_FUNC_CALLED(ctx);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
for (i = 0; i < ctx->reader_count; i++)
|
||||
free(ctx->readers[i]);
|
||||
free(ctx);
|
||||
@ -462,23 +467,23 @@ int sc_connect_card(struct sc_context *ctx,
|
||||
const struct sc_defaults *defaults;
|
||||
|
||||
assert(card_out != NULL);
|
||||
SC_FUNC_CALLED(ctx);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
if (reader >= ctx->reader_count || reader < 0)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_FOUND);
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OBJECT_NOT_FOUND);
|
||||
|
||||
rgReaderStates[0].szReader = ctx->readers[reader];
|
||||
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
|
||||
rv = SCardGetStatusChange(ctx->pcsc_ctx, 0, rgReaderStates, 1);
|
||||
if (rv != 0) {
|
||||
error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(rv));
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_RESOURCE_MANAGER); /* FIXME */
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_RESOURCE_MANAGER); /* FIXME */
|
||||
}
|
||||
if (!(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT))
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_CARD_NOT_PRESENT);
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_CARD_NOT_PRESENT);
|
||||
|
||||
card = malloc(sizeof(struct sc_card));
|
||||
if (card == NULL)
|
||||
SC_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
|
||||
memset(card, 0, sizeof(struct sc_card));
|
||||
rv = SCardConnect(ctx->pcsc_ctx, ctx->readers[reader],
|
||||
SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0,
|
||||
@ -506,17 +511,18 @@ int sc_connect_card(struct sc_context *ctx,
|
||||
pthread_mutex_init(&card->mutex, NULL);
|
||||
*card_out = card;
|
||||
|
||||
return 0;
|
||||
SC_FUNC_RETURN(ctx, 1, 0);
|
||||
}
|
||||
|
||||
int sc_disconnect_card(struct sc_card *card)
|
||||
{
|
||||
struct sc_context *ctx = card->ctx;
|
||||
assert(card != NULL);
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD);
|
||||
pthread_mutex_destroy(&card->mutex);
|
||||
free(card);
|
||||
|
||||
return 0;
|
||||
SC_FUNC_RETURN(ctx, 1, 0);
|
||||
}
|
||||
|
||||
const char *sc_strerror(int error)
|
||||
@ -578,8 +584,9 @@ int _sc_lock_int(struct sc_card *card)
|
||||
|
||||
int sc_lock(struct sc_card *card)
|
||||
{
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
pthread_mutex_lock(&card->mutex);
|
||||
return _sc_lock_int(card);
|
||||
SC_FUNC_RETURN(card->ctx, 2, _sc_lock_int(card));
|
||||
}
|
||||
|
||||
int _sc_unlock_int(struct sc_card *card)
|
||||
@ -596,22 +603,23 @@ int _sc_unlock_int(struct sc_card *card)
|
||||
|
||||
int sc_unlock(struct sc_card *card)
|
||||
{
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
pthread_mutex_unlock(&card->mutex);
|
||||
return _sc_unlock_int(card);
|
||||
SC_FUNC_RETURN(card->ctx, 2, _sc_unlock_int(card));
|
||||
}
|
||||
|
||||
int sc_list_files(struct sc_card *card, u8 *buf, int buflen)
|
||||
{
|
||||
struct sc_apdu apdu;
|
||||
int r;
|
||||
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0);
|
||||
apdu.resp = buf;
|
||||
apdu.resplen = buflen;
|
||||
apdu.le = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r)
|
||||
return r;
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.resplen == 0)
|
||||
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
return apdu.resplen;
|
||||
@ -658,10 +666,10 @@ int sc_create_file(struct sc_card *card, const struct sc_file *file)
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
struct sc_apdu apdu;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
len = SC_MAX_APDU_BUFFER_SIZE;
|
||||
r = construct_fci(file, sbuf, &len);
|
||||
if (r)
|
||||
return r;
|
||||
SC_TEST_RET(card->ctx, r, "construct_fci() failed");
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
|
||||
apdu.lc = len;
|
||||
@ -671,9 +679,8 @@ int sc_create_file(struct sc_card *card, const struct sc_file *file)
|
||||
apdu.resp = rbuf;
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r)
|
||||
return r;
|
||||
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_delete_file(struct sc_card *card, int file_id)
|
||||
@ -683,6 +690,7 @@ int sc_delete_file(struct sc_card *card, int file_id)
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
struct sc_apdu apdu;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
sbuf[0] = (file_id >> 8) & 0xFF;
|
||||
sbuf[1] = file_id & 0xFF;
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
|
||||
@ -693,11 +701,10 @@ int sc_delete_file(struct sc_card *card, int file_id)
|
||||
apdu.resp = rbuf;
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r)
|
||||
return r;
|
||||
if (apdu.resplen != 2)
|
||||
return -1;
|
||||
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.resplen != 0)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_ILLEGAL_RESPONSE);
|
||||
SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_file_valid(const struct sc_file *file)
|
||||
|
@ -33,7 +33,7 @@ int sc_set_security_env(struct sc_card *card,
|
||||
int r;
|
||||
|
||||
assert(card != NULL && env != NULL);
|
||||
SC_FUNC_CALLED(card->ctx);
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
|
||||
if (env->operation == 1) {
|
||||
apdu.p1 = 0x81;
|
||||
@ -61,7 +61,7 @@ int sc_set_security_env(struct sc_card *card,
|
||||
apdu.resplen = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
SC_FUNC_RETURN(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_restore_security_env(struct sc_card *card, int num)
|
||||
@ -71,13 +71,13 @@ int sc_restore_security_env(struct sc_card *card, int num)
|
||||
u8 rbuf[MAX_BUFFER_SIZE];
|
||||
|
||||
assert(card != NULL);
|
||||
SC_FUNC_CALLED(card->ctx);
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0xF3, num);
|
||||
apdu.resplen = sizeof(rbuf) > 250 ? 250 : sizeof(rbuf);
|
||||
apdu.resp = rbuf;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
SC_FUNC_RETURN(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_decipher(struct sc_card *card,
|
||||
@ -89,9 +89,9 @@ int sc_decipher(struct sc_card *card,
|
||||
u8 sbuf[MAX_BUFFER_SIZE];
|
||||
|
||||
assert(card != NULL && crgram != NULL && out != NULL);
|
||||
SC_FUNC_CALLED(card->ctx);
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
if (crgram_len > 255)
|
||||
SC_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x80, 0x86);
|
||||
apdu.resp = rbuf;
|
||||
@ -108,9 +108,9 @@ int sc_decipher(struct sc_card *card,
|
||||
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
|
||||
|
||||
memcpy(out, apdu.resp, len);
|
||||
SC_FUNC_RETURN(card->ctx, len);
|
||||
SC_FUNC_RETURN(card->ctx, 2, len);
|
||||
}
|
||||
SC_FUNC_RETURN(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_compute_signature(struct sc_card *card,
|
||||
@ -123,9 +123,9 @@ int sc_compute_signature(struct sc_card *card,
|
||||
u8 sbuf[MAX_BUFFER_SIZE];
|
||||
|
||||
assert(card != NULL && data != NULL && out != NULL);
|
||||
SC_FUNC_CALLED(card->ctx);
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
if (datalen > 255)
|
||||
SC_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x9E,
|
||||
0x9A);
|
||||
@ -142,9 +142,9 @@ int sc_compute_signature(struct sc_card *card,
|
||||
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
|
||||
|
||||
memcpy(out, apdu.resp, len);
|
||||
SC_FUNC_RETURN(card->ctx, len);
|
||||
SC_FUNC_RETURN(card->ctx, 2, len);
|
||||
}
|
||||
SC_FUNC_RETURN(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_verify(struct sc_card *card, int ref, const u8 *pin, int pinlen,
|
||||
@ -154,9 +154,9 @@ int sc_verify(struct sc_card *card, int ref, const u8 *pin, int pinlen,
|
||||
u8 sbuf[MAX_BUFFER_SIZE];
|
||||
int r;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx);
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
if (pinlen >= MAX_BUFFER_SIZE)
|
||||
SC_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0, ref);
|
||||
memcpy(sbuf, pin, pinlen);
|
||||
apdu.lc = pinlen;
|
||||
@ -170,9 +170,9 @@ int sc_verify(struct sc_card *card, int ref, const u8 *pin, int pinlen,
|
||||
if (apdu.sw1 == 0x63 && (apdu.sw2 & 0xF0) == 0xC0) {
|
||||
if (tries_left != NULL)
|
||||
*tries_left = apdu.sw2 & 0x0F;
|
||||
SC_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
|
||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_PIN_CODE_INCORRECT);
|
||||
}
|
||||
SC_FUNC_RETURN(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_change_reference_data(struct sc_card *card, int ref, const u8 *old,
|
||||
@ -183,9 +183,9 @@ int sc_change_reference_data(struct sc_card *card, int ref, const u8 *old,
|
||||
u8 sbuf[MAX_BUFFER_SIZE];
|
||||
int r, p1 = 0, len = oldlen + newlen;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx);
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
if (len >= MAX_BUFFER_SIZE)
|
||||
SC_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
|
||||
if (oldlen == 0)
|
||||
p1 = 1;
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, p1, ref);
|
||||
@ -202,9 +202,9 @@ int sc_change_reference_data(struct sc_card *card, int ref, const u8 *old,
|
||||
if (apdu.sw1 == 0x63 && (apdu.sw2 & 0xF0) == 0xC0) {
|
||||
if (tries_left != NULL)
|
||||
*tries_left = apdu.sw2 & 0x0F;
|
||||
SC_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_PIN_CODE_INCORRECT);
|
||||
}
|
||||
SC_FUNC_RETURN(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
int sc_reset_retry_counter(struct sc_card *card, int ref, const u8 *puk,
|
||||
@ -215,7 +215,7 @@ int sc_reset_retry_counter(struct sc_card *card, int ref, const u8 *puk,
|
||||
int r, p1 = 0, len = puklen + newlen;
|
||||
|
||||
if (len >= MAX_BUFFER_SIZE)
|
||||
SC_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
|
||||
if (puklen == 0) {
|
||||
if (newlen == 0)
|
||||
p1 = 3;
|
||||
@ -238,5 +238,5 @@ int sc_reset_retry_counter(struct sc_card *card, int ref, const u8 *puk,
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
memset(sbuf, 0, len);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
SC_FUNC_RETURN(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user