- bumped version number up to 0.4.0

- improved ASN.1 decoding _lots_


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@80 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2001-12-16 18:46:32 +00:00
parent 9423884172
commit 5e00917fcc
13 changed files with 535 additions and 211 deletions

View File

@ -2,7 +2,7 @@
AC_INIT(libopensc) AC_INIT(libopensc)
AC_CONFIG_SRCDIR(src/sc.c) AC_CONFIG_SRCDIR(src/sc.c)
AM_CONFIG_HEADER(config.h:config.h.in) AM_CONFIG_HEADER(config.h:config.h.in)
AM_INIT_AUTOMAKE(libopensc, 0.3.5) AM_INIT_AUTOMAKE(libopensc, 0.4.0)
# Checks for programs. # Checks for programs.

View File

@ -7,7 +7,7 @@ libopensc_la_SOURCES = sc-asn1.c sc-base64.c sc-defaults.c \
sc-pkcs15.c sc-pkcs15-cert.c \ sc-pkcs15.c sc-pkcs15-cert.c \
sc-pkcs15-pin.c sc-pkcs15-prkey.c \ sc-pkcs15-pin.c sc-pkcs15-prkey.c \
sc-pkcs15-defaults.c sc-pkcs15-sec.c sc-pkcs15-defaults.c sc-pkcs15-sec.c
libopensc_la_LDFLAGS = -version-info 0:3:0 libopensc_la_LDFLAGS = -version-info 0:4:0
libopensc_la_CFLAGS = $(AM_CFLAGS) -Werror libopensc_la_CFLAGS = $(AM_CFLAGS) -Werror
include_HEADERS = opensc.h opensc-pkcs15.h include_HEADERS = opensc.h opensc-pkcs15.h
noinst_HEADERS = sc-asn1.h noinst_HEADERS = sc-asn1.h sc-log.h

View File

@ -20,10 +20,12 @@
#include "opensc.h" #include "opensc.h"
#include "sc-asn1.h" #include "sc-asn1.h"
#include "sc-log.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h>
const char *tag2str(int tag) const char *tag2str(int tag)
{ {
@ -286,6 +288,50 @@ const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag_in, int *taglen
return p; return p;
} }
static const u8 *sc_asn1_skip_tag2(const u8 ** buf, int *buflen, unsigned int tag_in, int *taglen_out)
{
const u8 *p = *buf;
int len = *buflen, cla, tag, taglen;
if (read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != 1)
return NULL;
switch (cla & 0xC0) {
case ASN1_TAG_UNIVERSAL:
if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_UNI)
return NULL;
break;
case ASN1_TAG_APPLICATION:
if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_APP)
return NULL;
break;
case ASN1_TAG_CONTEXT:
if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_CTX)
return NULL;
break;
case ASN1_TAG_PRIVATE:
if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_PRV)
return NULL;
break;
}
if (cla & ASN1_TAG_CONSTRUCTED) {
if ((tag_in & SC_ASN1_CONS) == 0)
return NULL;
} else
if (tag_in & SC_ASN1_CONS)
return NULL;
if ((tag_in & SC_ASN1_TAG_MASK) != tag)
return NULL;
len -= (p - *buf); /* header size */
if (taglen > len) {
fprintf(stderr, "skip_tag(): too long tag\n");
return NULL;
}
*buflen -= (p - *buf) + taglen;
*buf = p + taglen; /* point to next tag */
*taglen_out = taglen;
return p;
}
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag_in, int *taglen_out) const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag_in, int *taglen_out)
{ {
return sc_asn1_skip_tag(&buf, &buflen, tag_in, taglen_out); return sc_asn1_skip_tag(&buf, &buflen, tag_in, taglen_out);
@ -302,7 +348,7 @@ static int decode_bit_string(const u8 * inbuf, int inlen, void *outbuf,
in++; in++;
if (outlen < octets_left) if (outlen < octets_left)
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_BUFFER_TOO_SMALL;
while (octets_left) { while (octets_left) {
/* 1st octet of input: ABCDEFGH, where A is the MSB */ /* 1st octet of input: ABCDEFGH, where A is the MSB */
/* 1st octet of output: HGFEDCBA, where A is the LSB */ /* 1st octet of output: HGFEDCBA, where A is the LSB */
@ -326,7 +372,7 @@ static int decode_bit_string(const u8 * inbuf, int inlen, void *outbuf,
octets_left--; octets_left--;
count++; count++;
} }
return (count * 8) - zero_bits; return (count * 8) - zero_bits;
} }
int sc_asn1_decode_bit_string(const u8 * inbuf, int sc_asn1_decode_bit_string(const u8 * inbuf,
@ -390,6 +436,17 @@ int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
return 0; return 0;
} }
int sc_asn1_decode_utf8string(const u8 * inbuf, int inlen,
u8 *out, int *outlen)
{
if (inlen+1 > *outlen)
return SC_ERROR_BUFFER_TOO_SMALL;
*outlen = inlen+1;
memcpy(out, inbuf, inlen);
out[inlen] = 0;
return 0;
}
int sc_asn1_put_tag(int tag, const u8 * data, int datalen, u8 * out, int outlen, u8 **ptr) int sc_asn1_put_tag(int tag, const u8 * data, int datalen, u8 * out, int outlen, u8 **ptr)
{ {
u8 *p = out; u8 *p = out;
@ -411,3 +468,148 @@ int sc_asn1_put_tag(int tag, const u8 * data, int datalen, u8 * out, int outlen,
*ptr = p; *ptr = p;
return 0; return 0;
} }
int sc_asn1_parse_path(struct sc_context *ctx, const u8 *in, int len,
struct sc_path *path)
{
int idx, r;
struct sc_asn1_struct asn1_path[] = {
{ "path", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, &path->value, &path->len },
{ "index", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, &idx },
{ NULL }
};
path->len = SC_MAX_PATH_SIZE;
r = sc_asn1_parse(ctx, asn1_path, in, len, NULL, NULL);
if (r)
return r;
return 0;
}
static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entry,
const u8 *obj, int objlen)
{
void *parm = entry->parm;
int *len = entry->len;
int r = 0;
switch (entry->type) {
case SC_ASN1_STRUCT:
assert(parm != NULL);
r = sc_asn1_parse(ctx, (struct sc_asn1_struct *) parm, obj, objlen, NULL, NULL);
break;
case SC_ASN1_INTEGER:
if (parm != NULL)
r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm);
break;
case SC_ASN1_BIT_STRING:
if (parm != NULL && len != NULL) {
r = sc_asn1_decode_bit_string(obj, objlen, (u8 *) parm, *len);
if (r >= 0) {
*len = r;
r = 0;
}
}
break;
case SC_ASN1_OCTET_STRING:
if (parm != NULL && len != NULL) {
int c = objlen > *len ? *len : objlen;
memcpy(parm, obj, c);
*len = c;
}
break;
case SC_ASN1_OBJECT:
if (parm != NULL)
r = sc_asn1_decode_object_id(obj, objlen, (struct sc_object_id *) parm);
break;
case SC_ASN1_UTF8STRING:
if (parm != NULL && len != NULL)
r = sc_asn1_decode_utf8string(obj, objlen, parm, len);
break;
case SC_ASN1_PATH:
if (entry->parm != NULL)
r = sc_asn1_parse_path(ctx, obj, objlen, (struct sc_path *) entry->parm);
break;
default:
error(ctx, "invalid ASN.1 type: %d\n", entry->type);
assert(0);
}
if (r) {
error(ctx, "decoding of ASN.1 object failed: %s\n", entry->name);
return r;
}
entry->flags |= SC_ASN1_PRESENT;
return 0;
}
int sc_asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
const u8 *in, int len, const u8 **newp, int *len_left)
{
int r;
const u8 *p = in, *obj;
struct sc_asn1_struct *entry = asn1;
int left = len, objlen;
SC_FUNC_CALLED(ctx);
while (entry->name != NULL) {
r = 0;
obj = sc_asn1_skip_tag2(&p, &left, entry->tag, &objlen);
if (obj == NULL) {
if (entry->flags & SC_ASN1_OPTIONAL) {
entry++;
continue;
}
error(ctx, "mandatory ASN.1 object not found: %s\n", entry->name);
return SC_ERROR_ASN1_OBJECT_NOT_FOUND;
}
r = asn1_decode_entry(ctx, entry, obj, objlen);
if (r)
return r;
entry++;
}
if (newp != NULL)
*newp = p;
if (len_left != NULL)
*len_left = left;
return 0;
}
int sc_asn1_parse_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1,
const u8 *in, int len, const u8 **newp, int *len_left)
{
int r, idx = 0;
const u8 *p = in, *obj;
struct sc_asn1_struct *entry;
int left = len, objlen;
SC_FUNC_CALLED(ctx);
entry = asn1;
while (entry->name) {
entry->flags &= ~SC_ASN1_PRESENT;
entry++;
}
if (left < 2)
return SC_ERROR_ASN1_END_OF_CONTENTS;
if (p[0] == 0 && p[1] == 0)
return SC_ERROR_ASN1_END_OF_CONTENTS;
entry = asn1;
while (entry->name) {
r = 0;
obj = sc_asn1_skip_tag2(&p, &left, entry->tag, &objlen);
if (obj == NULL) {
idx++;
entry++;
continue;
}
r = asn1_decode_entry(ctx, entry, obj, objlen);
if (r)
return r;
if (newp != NULL)
*newp = p;
if (len_left != NULL)
*len_left = left;
return idx;
}
return SC_ERROR_ASN1_OBJECT_NOT_FOUND;
}

View File

@ -21,8 +21,24 @@
#ifndef _SC_ASN1_H #ifndef _SC_ASN1_H
#define _SC_ASN1_H #define _SC_ASN1_H
#include "opensc.h"
struct sc_asn1_struct {
const char *name;
unsigned int type;
unsigned int tag;
unsigned int flags;
void *parm;
int *len;
};
/* DER tag and length parsing */ /* DER tag and length parsing */
int sc_asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
const u8 *in, int len, const u8 **newp, int *left);
int sc_asn1_parse_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1,
const u8 *in, int len, const u8 **newp, int *left);
const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag, int *taglen); const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag, int *taglen);
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag, int *taglen); const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag, int *taglen);
const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag, int *taglen); const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag, int *taglen);
@ -47,6 +63,38 @@ int sc_asn1_decode_bit_string_ni(const u8 * inbuf, int inlen,
int sc_asn1_decode_integer(const u8 * inbuf, int inlen, int *out); int sc_asn1_decode_integer(const u8 * inbuf, int inlen, int *out);
int sc_asn1_decode_object_id(const u8 * inbuf, int inlen, int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
struct sc_object_id *id); struct sc_object_id *id);
#define SC_ASN1_CLASS_MASK 0x30000000
#define SC_ASN1_UNI 0x00000000 /* Universal */
#define SC_ASN1_APP 0x10000000 /* Application */
#define SC_ASN1_CTX 0x20000000 /* Context */
#define SC_ASN1_PRV 0x30000000 /* Private */
#define SC_ASN1_CONS 0x01000000
#define SC_ASN1_TAG_MASK 0x00FFFFFF
#define SC_ASN1_PRESENT 0x00000001
#define SC_ASN1_OPTIONAL 0x00000002
#define SC_ASN1_BOOLEAN 1
#define SC_ASN1_INTEGER 2
#define SC_ASN1_BIT_STRING 3
#define SC_ASN1_OCTET_STRING 4
#define SC_ASN1_NULL 5
#define SC_ASN1_OBJECT 6
#define SC_ASN1_ENUMERATED 10
#define SC_ASN1_UTF8STRING 12
#define SC_ASN1_SEQUENCE 16
#define SC_ASN1_SET 17
#define SC_ASN1_PRINTABLESTRING 19
#define SC_ASN1_UTCTIME 23
#define SC_ASN1_GENERALIZEDTIME 24
/* internal structures */
#define SC_ASN1_STRUCT 128
#define SC_ASN1_CHOICE 129
/* PKCS#15 structures */
#define SC_ASN1_PATH 256
#define ASN1_TAG_CLASS 0xC0 #define ASN1_TAG_CLASS 0xC0
#define ASN1_TAG_UNIVERSAL 0x00 #define ASN1_TAG_UNIVERSAL 0x00

View File

@ -31,10 +31,14 @@ extern "C" {
#define SC_PKCS15_PIN_MAGIC 0x31415926 #define SC_PKCS15_PIN_MAGIC 0x31415926
#define SC_PKCS15_MAX_PINS 2 #define SC_PKCS15_MAX_PINS 2
#define SC_PKCS15_MAX_CERTS 3
#define SC_PKCS15_MAX_PRKEYS 2 #define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32 #define SC_PKCS15_MAX_LABEL_SIZE 32
#define SC_PKCS15_MAX_ID_SIZE 16 #define SC_PKCS15_MAX_ID_SIZE 16
#define SC_PKCS15_MAX_CDFS 4 /* Certificate Directory
* Files */
#define SC_PKCS15_MAX_AODFS 4 /* Authentication Object
* Directory Files */
#define SC_PKCS15_MAX_CERTS 4 /* Total certificates */
struct sc_pkcs15_id { struct sc_pkcs15_id {
u8 value[SC_PKCS15_MAX_ID_SIZE]; u8 value[SC_PKCS15_MAX_ID_SIZE];
@ -147,12 +151,14 @@ struct sc_pkcs15_card {
struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS]; struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS];
int pin_count; int pin_count;
struct sc_file file_dir, file_ao1, file_app; struct sc_file file_dir, file_app;
/* in app DF */ /* in app DF */
struct sc_file file_tokeninfo, file_odf; struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf; struct sc_file file_prkdf;
struct sc_file file_aodf, file_ao2; struct sc_file file_cdf[SC_PKCS15_MAX_CDFS];
struct sc_file file_cdf1, file_cdf2, file_cdf3; int cdf_count;
struct sc_file file_aodf[SC_PKCS15_MAX_AODFS];
int aodf_count;
struct sc_file file_dodf; struct sc_file file_dodf;
}; };

View File

@ -56,6 +56,9 @@ extern "C" {
#define SC_ERROR_UNKNOWN_REPLY -1023 #define SC_ERROR_UNKNOWN_REPLY -1023
#define SC_ERROR_OBJECT_NOT_FOUND -1024 #define SC_ERROR_OBJECT_NOT_FOUND -1024
#define SC_ERROR_CARD_RESET -1025 #define SC_ERROR_CARD_RESET -1025
#define SC_ERROR_ASN1_OBJECT_NOT_FOUND -1026
#define SC_ERROR_ASN1_END_OF_CONTENTS -1027
#define SC_ERROR_TOO_MANY_OBJECTS -1028
#define SC_APDU_CASE_NONE 0 #define SC_APDU_CASE_NONE 0
#define SC_APDU_CASE_1 1 #define SC_APDU_CASE_1 1
@ -111,6 +114,7 @@ struct sc_object_id {
struct sc_path { struct sc_path {
u8 value[SC_MAX_PATH_SIZE]; u8 value[SC_MAX_PATH_SIZE];
int len; int len;
int index;
}; };
struct sc_file { struct sc_file {

View File

@ -329,25 +329,26 @@ static int get_certs_from_file(struct sc_pkcs15_card *card,
int r, taglen, left; int r, taglen, left;
u8 buf[MAX_BUFFER_SIZE]; u8 buf[MAX_BUFFER_SIZE];
const u8 *tag, *p; const u8 *tag, *p;
int count = 0;
r = sc_select_file(card->card, file, &file->path, r = sc_select_file(card->card, file, &file->path,
SC_SELECT_FILE_BY_PATH); SC_SELECT_FILE_BY_PATH);
if (r) if (r)
return r; 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);
if (r < 0) if (r < 0)
return r; return r;
left = r; left = r;
p = buf; p = buf;
count = 0; while ((tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen)) != NULL) {
while (card->cert_count < SC_PKCS15_MAX_CERTS) { if (card->cert_count >= SC_PKCS15_MAX_CERTS)
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE */ return SC_ERROR_TOO_MANY_OBJECTS;
if (tag == NULL) r = parse_x509_cert_info(&card->cert_info[card->cert_count],
break; tag, taglen);
if (parse_x509_cert_info(&card->cert_info[card->cert_count], tag, taglen)) if (r)
break; return r;
card->cert_count++; card->cert_count++;
} }
return 0; return 0;
@ -355,24 +356,16 @@ static int get_certs_from_file(struct sc_pkcs15_card *card,
int sc_pkcs15_enum_certificates(struct sc_pkcs15_card *card) int sc_pkcs15_enum_certificates(struct sc_pkcs15_card *card)
{ {
int r; int r, i;
assert(card != NULL); assert(card != NULL);
if (card->cert_count) if (card->cert_count)
return card->cert_count; /* already enumerated */ return card->cert_count; /* already enumerated */
for (i = 0; i < card->cdf_count; i++) {
card->cert_count = 0; r = get_certs_from_file(card, &card->file_cdf[i]);
r = get_certs_from_file(card, &card->file_cdf1);
if (r != 0)
return r;
if (card->file_cdf2.path.len) {
r = get_certs_from_file(card, &card->file_cdf2);
if (r != 0) if (r != 0)
return r; return r;
} }
r = get_certs_from_file(card, &card->file_cdf3);
if (r != 0)
return r;
return card->cert_count; return card->cert_count;
} }

View File

@ -99,11 +99,13 @@ static int fineid_pkcs15_defaults(struct sc_pkcs15_card *arg,
card->alg_info[0].supported_operations = 0xa2; card->alg_info[0].supported_operations = 0xa2;
format_file_struct(&card->file_app, "5015", 7); /* 7 = DF, 0 = EF */ format_file_struct(&card->file_app, "5015", 7); /* 7 = DF, 0 = EF */
format_file_struct(&card->file_aodf, "50154401", 0); card->aodf_count = 1;
format_file_struct(&card->file_aodf[0], "50154401", 0);
format_file_struct(&card->file_prkdf, "50154402", 0); format_file_struct(&card->file_prkdf, "50154402", 0);
format_file_struct(&card->file_cdf1, "50154403", 0); card->cdf_count = 3;
format_file_struct(&card->file_cdf2, "50154404", 0); format_file_struct(&card->file_cdf[0], "50154403", 0);
format_file_struct(&card->file_cdf3, "50154405", 0); format_file_struct(&card->file_cdf[1], "50154404", 0);
format_file_struct(&card->file_cdf[2], "50154405", 0);
format_file_struct(&card->file_dodf, "50154406", 0); format_file_struct(&card->file_dodf, "50154406", 0);
format_file_struct(&card->file_odf, "50155031", 0); format_file_struct(&card->file_odf, "50155031", 0);
format_file_struct(&card->file_tokeninfo, "50155032", 0); format_file_struct(&card->file_tokeninfo, "50155032", 0);

View File

@ -21,6 +21,7 @@
#include "opensc.h" #include "opensc.h"
#include "opensc-pkcs15.h" #include "opensc-pkcs15.h"
#include "sc-asn1.h" #include "sc-asn1.h"
#include "sc-log.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -119,15 +120,45 @@ void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin)
printf("\n"); printf("\n");
} }
static int get_pins_from_file(struct sc_pkcs15_card *p15card,
struct sc_file *file)
{
int r, taglen, left;
const u8 *p, *tag;
u8 buf[MAX_BUFFER_SIZE];
r = sc_select_file(p15card->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);
if (r < 0)
return r;
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]);
if (r)
return r;
p15card->pin_count++;
}
return 0;
}
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card) int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
{ {
int r, i; int r, i;
u8 buf[MAX_BUFFER_SIZE]; struct sc_context *ctx = p15card->card->ctx;
const u8 *tag, *p;
int taglen, buflen;
assert(p15card != NULL); assert(p15card != NULL);
SC_FUNC_CALLED(ctx);
if (p15card->pin_count) { if (p15card->pin_count) {
for (i = 0; i < p15card->pin_count; i++) { for (i = 0; i < p15card->pin_count; i++) {
if (p15card->pin_info[i].magic != SC_PKCS15_PIN_MAGIC) if (p15card->pin_info[i].magic != SC_PKCS15_PIN_MAGIC)
@ -136,29 +167,9 @@ int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
if (i == p15card->pin_count) if (i == p15card->pin_count)
return i; /* Already enumerated */ return i; /* Already enumerated */
} }
for (i = 0; i < p15card->aodf_count; i++) {
r = sc_select_file(p15card->card, &p15card->file_aodf, r = get_pins_from_file(p15card, &p15card->file_aodf[i]);
&p15card->file_aodf.path, SC_TEST_RET(ctx, r, "Failed to read PINs from AODF");
SC_SELECT_FILE_BY_PATH);
if (r)
return r;
r = sc_read_binary(p15card->card, 0, buf, p15card->file_aodf.size);
if (r < 0)
return r;
buflen = r;
p = buf;
i = 0;
p15card->pin_count = 0;
while ((tag = sc_asn1_skip_tag(&p, &buflen, 0x30, &taglen)) != NULL) {
r = decode_pin_info(tag, taglen,
&p15card->pin_info[p15card->
pin_count]);
if (r)
break;
p15card->pin_count++;
if (p15card->pin_count >= SC_PKCS15_MAX_PINS)
break;
} }
return p15card->pin_count; return p15card->pin_count;
} }

View File

@ -55,84 +55,51 @@ void sc_pkcs15_print_card(const struct sc_pkcs15_card *card)
printf("\n"); printf("\n");
} }
static int extract_path(const u8 * buf, int buflen, struct sc_path *path)
{
const u8 *tag;
int taglen;
tag = sc_asn1_verify_tag(buf, buflen, 0x30, &taglen);
if (tag == NULL)
return -1;
tag = sc_asn1_verify_tag(tag, taglen, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
return -1;
memcpy(path->value, tag, taglen);
path->len = taglen;
return 0;
}
void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, int buflen) void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, int buflen)
{ {
const u8 *tag, *p = buf; int i, r;
int i, taglen, left = buflen; u8 serial[128];
int serial_len = sizeof(serial);
u8 mnfid[128];
int mnfid_len = sizeof(mnfid);
int flags_len = sizeof(card->flags);
p = sc_asn1_verify_tag(buf, buflen, 0x30, &left); /* SEQUENCE */ struct sc_asn1_struct asn1_tokeninfo[] = {
if (p == NULL) { "version", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &card->version },
{ "serialNumber", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, serial, &serial_len },
{ "manufacturerID", SC_ASN1_UTF8STRING, ASN1_UTF8STRING, SC_ASN1_OPTIONAL, mnfid, &mnfid_len },
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL },
{ "tokenflags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, 0, &card->flags, &flags_len },
{ "seInfo", SC_ASN1_SEQUENCE, SC_ASN1_CONS | ASN1_SEQUENCE, SC_ASN1_OPTIONAL, NULL },
{ "recordInfo", SC_ASN1_SEQUENCE, SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL },
{ "supportedAlgorithms", SC_ASN1_SEQUENCE,SC_ASN1_CTX | 2, SC_ASN1_OPTIONAL, NULL },
{ NULL } };
buf = sc_asn1_verify_tag(buf, buflen, 0x30, &buflen); /* SEQUENCE */
if (buf == NULL) {
error(card->card->ctx, "invalid EF(TokenInfo)\n");
goto err; goto err;
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */ }
if (tag == NULL) r = sc_asn1_parse(card->card->ctx, asn1_tokeninfo, buf, buflen, NULL, NULL);
if (r) {
error(card->card->ctx, "ASN.1 parsing failed: %s\n", sc_strerror(r));
goto err; goto err;
card->version = tag[0] + 1; }
tag = sc_asn1_skip_tag(&p, &left, 0x04, &taglen); /* OCTET STRING */ card->version += 1;
if (tag == NULL) card->serial_number = malloc(serial_len * 2 + 1);
goto err;
card->serial_number = malloc(taglen * 2 + 1);
card->serial_number[0] = 0; card->serial_number[0] = 0;
for (i = 0; i < taglen; i++) { for (i = 0; i < serial_len; i++) {
char byte[3]; char byte[3];
sprintf(byte, "%02X", tag[i]); sprintf(byte, "%02X", serial[i]);
strcat(card->serial_number, byte); strcat(card->serial_number, byte);
} }
tag = sc_asn1_skip_tag(&p, &left, 0x0C, &taglen); /* UTF8 STRING */ if (asn1_tokeninfo[2].flags & SC_ASN1_PRESENT)
if (tag == NULL) card->manufacturer_id = strdup(mnfid);
goto err; else
card->manufacturer_id = malloc(taglen + 1); card->manufacturer_id = strdup("(unknown)");
memcpy(card->manufacturer_id, tag, taglen);
card->manufacturer_id[taglen] = 0;
tag = sc_asn1_skip_tag(&p, &left, 0x80, &taglen); /* Label */
if (tag != NULL) { /* skip this tag */
}
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen); /* BIT STRING */
if (tag == NULL)
goto err;
sc_asn1_decode_bit_string(tag, taglen, &card->flags,
sizeof(card->flags));
tag = sc_asn1_find_tag(p, left, 0xA2, &taglen); /* supportedAlgo */
if (tag == NULL)
goto err;
p = sc_asn1_skip_tag(&tag, &taglen, 0x30, &left); /* SEQUENCE */
if (p == NULL)
goto err;
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag == NULL)
goto err;
card->alg_info[0].reference = tag[0];
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag == NULL)
goto err;
card->alg_info[0].algorithm = tag[0];
tag = sc_asn1_find_tag(p, left, 0x03, &taglen); /* BIT STRING */ ;
if (tag == NULL)
goto err;
sc_asn1_decode_bit_string(tag, taglen,
&card->alg_info[0].supported_operations,
sizeof(card->alg_info[0].
supported_operations));
return; return;
err: err:
if (card->serial_number == NULL) if (card->serial_number == NULL)
card->serial_number = strdup("(unknown)"); card->serial_number = strdup("(unknown)");
if (card->manufacturer_id == NULL) if (card->manufacturer_id == NULL)
@ -142,77 +109,101 @@ void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, int buflen)
static int parse_dir(const u8 * buf, int buflen, struct sc_pkcs15_card *card) static int parse_dir(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
{ {
const u8 *tag; const u8 *aidref = "\xA0\x00\x00\x00\x63PKCS-15";
int taglen; const int aidref_len = 12;
const char *aid = "\xA0\x00\x00\x00\x63PKCS-15"; int r;
const int aidlen = 12; u8 aid[128], label[128], path[128];
int aid_len = sizeof(aid), label_len = sizeof(label),
path_len = sizeof(path);
struct sc_asn1_struct asn1_ddo[] = {
{ "oid", SC_ASN1_OBJECT, ASN1_OBJECT, 0, NULL },
{ "odfPath", SC_ASN1_PATH, SC_ASN1_CONS | ASN1_SEQUENCE, SC_ASN1_OPTIONAL, &card->file_odf.path },
{ "tokenInfoPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, &card->file_tokeninfo.path },
{ "unusedPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL },
{ NULL }
};
struct sc_asn1_struct asn1_dir[] = {
{ "aid", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 15, 0, aid, &aid_len },
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_APP | 16, SC_ASN1_OPTIONAL, label, &label_len },
{ "path", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 17, 0, path, &path_len },
{ "ddo", SC_ASN1_STRUCT, SC_ASN1_APP | 19 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_ddo },
{ NULL }
};
buf = sc_asn1_verify_tag(buf, buflen, 0x61, &buflen); buf = sc_asn1_verify_tag(buf, buflen, 0x61, &buflen);
if (buf == NULL) if (buf == NULL) {
error(card->card->ctx, "No [APPLICATION 1] tag in EF(DIR)\n");
return -1; return -1;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x4F, &taglen);
if (taglen != aidlen || memcmp(aid, tag, aidlen) != 0)
return -1;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x50, &taglen);
if (taglen > 0) {
card->label = malloc(taglen + 1);
if (card->label != NULL) {
memcpy(card->label, tag, taglen);
card->label[taglen] = 0;
}
} else
card->label = strdup("(unknown)");
tag = sc_asn1_skip_tag(&buf, &buflen, 0x51, &taglen);
if (tag == NULL)
return -1;
memcpy(card->file_app.path.value, tag, taglen);
card->file_app.path.len = taglen;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x73, &taglen);
if (taglen > 2) {
/* FIXME: process DDO */
} }
r = sc_asn1_parse(card->card->ctx, asn1_dir, buf, buflen, NULL, NULL);
if (r) {
error(card->card->ctx, "EF(DIR) parsing failed: %s\n",
sc_strerror(r));
return r;
}
if (aid_len != aidref_len || memcmp(aidref, aid, aid_len) != 0) {
error(card->card->ctx, "AID in EF(DIR) is invalid\n");
return -1;
}
if (asn1_dir[1].flags & SC_ASN1_PRESENT)
card->label = strdup(label);
else
card->label = strdup("(unknown)");
memcpy(card->file_app.path.value, path, path_len);
card->file_app.path.len = path_len;
return 0; return 0;
} }
static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card) static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
{ {
const u8 *tag; const u8 *p = buf;
int taglen; int r, left = buflen;
struct sc_path path;
/* authObjects */ struct sc_asn1_struct asn1_obj_or_path[] = {
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA8, &taglen)) == NULL) { "path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0, &path },
return -1; { NULL } };
if (extract_path(tag, taglen, &card->file_aodf.path)) struct sc_asn1_struct asn1_odf[] = {
return -1; { "privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, asn1_obj_or_path },
/* CDF #1 -- Card holder certificates */ { "certificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, 0, asn1_obj_or_path },
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA4, &taglen)) == NULL) { "trustedCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 5 | SC_ASN1_CONS, 0, asn1_obj_or_path },
return -1; { "dataObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 7 | SC_ASN1_CONS, 0, asn1_obj_or_path },
if (extract_path(tag, taglen, &card->file_cdf1.path)) { "authObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 8 | SC_ASN1_CONS, 0, asn1_obj_or_path },
return -1; };
/* CDF #2 -- New certificates */
tag += taglen; while (left > 0) {
taglen += 2; r = sc_asn1_parse_choice(card->card->ctx, asn1_odf, p, left, &p, &left);
if ((tag = sc_asn1_verify_tag(tag, taglen, 0xA4, &taglen)) == NULL) if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
return -1; break;
if (extract_path(tag, taglen, &card->file_cdf2.path)) if (r < 0)
return -1; return r;
/* CDF #3 -- Trusted CA certificates */ switch (r) {
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA5, &taglen)) == NULL) case 0:
return -1; card->file_prkdf.path = path;
if (extract_path(tag, taglen, &card->file_cdf3.path)) break;
return -1; case 1:
/* PrKDF */ case 2:
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA0, &taglen)) == NULL) if (card->cdf_count == SC_PKCS15_MAX_CDFS) {
return -1; error(card->card->ctx, "too many CDFs on card\n");
if (extract_path(tag, taglen, &card->file_prkdf.path)) break;
return -1; }
/* DODF */ card->file_cdf[card->cdf_count].path = path;
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA7, &taglen)) == NULL) card->cdf_count++;
return -1; break;
if (extract_path(tag, taglen, &card->file_dodf.path)) case 3:
return -1; card->file_dodf.path = path;
break;
case 4:
if (card->aodf_count == SC_PKCS15_MAX_AODFS) {
error(card->card->ctx, "too many AODFs on card\n");
break;
}
card->file_aodf[card->aodf_count].path = path;
card->aodf_count++;
break;
}
}
return 0; return 0;
} }
@ -274,11 +265,15 @@ int sc_pkcs15_init(struct sc_card *card,
err = SC_ERROR_PKCS15_CARD_NOT_FOUND; err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error; goto error;
} }
defaults = find_defaults(buf, err); if (p15card->card->ctx->use_cache)
defaults = find_defaults(buf, err);
if (defaults == NULL) { if (defaults == NULL) {
memcpy(&tmppath, &p15card->file_app.path, sizeof(struct sc_path)); if (p15card->file_odf.path.len == 0) {
memcpy(tmppath.value + tmppath.len, "\x50\x31", 2); tmppath = p15card->file_app.path;
tmppath.len += 2; memcpy(tmppath.value + tmppath.len, "\x50\x31", 2);
tmppath.len += 2;
} else
tmppath = p15card->file_odf.path;
err = sc_select_file(card, &p15card->file_odf, &tmppath, err = sc_select_file(card, &p15card->file_odf, &tmppath,
SC_SELECT_FILE_BY_PATH); SC_SELECT_FILE_BY_PATH);
if (err) if (err)
@ -295,9 +290,12 @@ int sc_pkcs15_init(struct sc_card *card,
err = SC_ERROR_PKCS15_CARD_NOT_FOUND; err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error; goto error;
} }
tmppath.len -= 2; if (p15card->file_tokeninfo.path.len == 0) {
memcpy(tmppath.value + tmppath.len, "\x50\x32", 2); tmppath.len -= 2;
tmppath.len += 2; memcpy(tmppath.value + tmppath.len, "\x50\x32", 2);
tmppath.len += 2;
} else
tmppath = p15card->file_tokeninfo.path;
} else { } else {
defaults->defaults_func(p15card, defaults->arg); defaults->defaults_func(p15card, defaults->arg);
tmppath = p15card->file_tokeninfo.path; tmppath = p15card->file_tokeninfo.path;
@ -316,7 +314,7 @@ int sc_pkcs15_init(struct sc_card *card,
parse_tokeninfo(p15card, buf, err); parse_tokeninfo(p15card, buf, err);
*p15card_out = p15card; *p15card_out = p15card;
return 0; return 0;
error: error:
free(p15card); free(p15card);
return err; return err;
} }
@ -355,7 +353,6 @@ int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
attr->auth_id.len = 0; attr->auth_id.len = 0;
/* FIXME: parse rest */ /* FIXME: parse rest */
attr->auth_id.len = 0;
attr->user_consent = 0; attr->user_consent = 0;
return 0; return 0;

View File

@ -31,10 +31,14 @@ extern "C" {
#define SC_PKCS15_PIN_MAGIC 0x31415926 #define SC_PKCS15_PIN_MAGIC 0x31415926
#define SC_PKCS15_MAX_PINS 2 #define SC_PKCS15_MAX_PINS 2
#define SC_PKCS15_MAX_CERTS 3
#define SC_PKCS15_MAX_PRKEYS 2 #define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32 #define SC_PKCS15_MAX_LABEL_SIZE 32
#define SC_PKCS15_MAX_ID_SIZE 16 #define SC_PKCS15_MAX_ID_SIZE 16
#define SC_PKCS15_MAX_CDFS 4 /* Certificate Directory
* Files */
#define SC_PKCS15_MAX_AODFS 4 /* Authentication Object
* Directory Files */
#define SC_PKCS15_MAX_CERTS 4 /* Total certificates */
struct sc_pkcs15_id { struct sc_pkcs15_id {
u8 value[SC_PKCS15_MAX_ID_SIZE]; u8 value[SC_PKCS15_MAX_ID_SIZE];
@ -147,12 +151,14 @@ struct sc_pkcs15_card {
struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS]; struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS];
int pin_count; int pin_count;
struct sc_file file_dir, file_ao1, file_app; struct sc_file file_dir, file_app;
/* in app DF */ /* in app DF */
struct sc_file file_tokeninfo, file_odf; struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf; struct sc_file file_prkdf;
struct sc_file file_aodf, file_ao2; struct sc_file file_cdf[SC_PKCS15_MAX_CDFS];
struct sc_file file_cdf1, file_cdf2, file_cdf3; int cdf_count;
struct sc_file file_aodf[SC_PKCS15_MAX_AODFS];
int aodf_count;
struct sc_file file_dodf; struct sc_file file_dodf;
}; };

View File

@ -21,8 +21,24 @@
#ifndef _SC_ASN1_H #ifndef _SC_ASN1_H
#define _SC_ASN1_H #define _SC_ASN1_H
#include "opensc.h"
struct sc_asn1_struct {
const char *name;
unsigned int type;
unsigned int tag;
unsigned int flags;
void *parm;
int *len;
};
/* DER tag and length parsing */ /* DER tag and length parsing */
int sc_asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
const u8 *in, int len, const u8 **newp, int *left);
int sc_asn1_parse_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1,
const u8 *in, int len, const u8 **newp, int *left);
const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag, int *taglen); const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag, int *taglen);
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag, int *taglen); const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag, int *taglen);
const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag, int *taglen); const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag, int *taglen);
@ -47,6 +63,38 @@ int sc_asn1_decode_bit_string_ni(const u8 * inbuf, int inlen,
int sc_asn1_decode_integer(const u8 * inbuf, int inlen, int *out); int sc_asn1_decode_integer(const u8 * inbuf, int inlen, int *out);
int sc_asn1_decode_object_id(const u8 * inbuf, int inlen, int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
struct sc_object_id *id); struct sc_object_id *id);
#define SC_ASN1_CLASS_MASK 0x30000000
#define SC_ASN1_UNI 0x00000000 /* Universal */
#define SC_ASN1_APP 0x10000000 /* Application */
#define SC_ASN1_CTX 0x20000000 /* Context */
#define SC_ASN1_PRV 0x30000000 /* Private */
#define SC_ASN1_CONS 0x01000000
#define SC_ASN1_TAG_MASK 0x00FFFFFF
#define SC_ASN1_PRESENT 0x00000001
#define SC_ASN1_OPTIONAL 0x00000002
#define SC_ASN1_BOOLEAN 1
#define SC_ASN1_INTEGER 2
#define SC_ASN1_BIT_STRING 3
#define SC_ASN1_OCTET_STRING 4
#define SC_ASN1_NULL 5
#define SC_ASN1_OBJECT 6
#define SC_ASN1_ENUMERATED 10
#define SC_ASN1_UTF8STRING 12
#define SC_ASN1_SEQUENCE 16
#define SC_ASN1_SET 17
#define SC_ASN1_PRINTABLESTRING 19
#define SC_ASN1_UTCTIME 23
#define SC_ASN1_GENERALIZEDTIME 24
/* internal structures */
#define SC_ASN1_STRUCT 128
#define SC_ASN1_CHOICE 129
/* PKCS#15 structures */
#define SC_ASN1_PATH 256
#define ASN1_TAG_CLASS 0xC0 #define ASN1_TAG_CLASS 0xC0
#define ASN1_TAG_UNIVERSAL 0x00 #define ASN1_TAG_UNIVERSAL 0x00

View File

@ -114,33 +114,33 @@ int sc_hex_to_bin(const char *in, u8 *out, int *outlen)
return err; return err;
} }
int sc_check_apdu(const struct sc_apdu *apdu) int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
{ {
switch (apdu->cse) { switch (apdu->cse) {
case SC_APDU_CASE_1: case SC_APDU_CASE_1:
if (apdu->datalen) if (apdu->datalen)
return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break; break;
case SC_APDU_CASE_2_SHORT: case SC_APDU_CASE_2_SHORT:
if (apdu->datalen) if (apdu->datalen)
return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
if (apdu->resplen < apdu->le) if (apdu->resplen < apdu->le)
return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break; break;
case SC_APDU_CASE_3_SHORT: case SC_APDU_CASE_3_SHORT:
if (apdu->datalen == 0 || apdu->data == NULL) if (apdu->datalen == 0 || apdu->data == NULL)
return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break; break;
case SC_APDU_CASE_4_SHORT: case SC_APDU_CASE_4_SHORT:
if (apdu->datalen == 0 || apdu->data == NULL) if (apdu->datalen == 0 || apdu->data == NULL)
return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
if (apdu->resplen < apdu->le) if (apdu->resplen < apdu->le)
return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break; break;
case SC_APDU_CASE_2_EXT: case SC_APDU_CASE_2_EXT:
case SC_APDU_CASE_3_EXT: case SC_APDU_CASE_3_EXT:
case SC_APDU_CASE_4_EXT: case SC_APDU_CASE_4_EXT:
return SC_ERROR_NOT_SUPPORTED; SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
} }
return 0; return 0;
} }
@ -195,6 +195,8 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
dwSendLength = data - s; dwSendLength = data - s;
dwRecvLength = apdu->resplen + 2; dwRecvLength = apdu->resplen + 2;
if (dwRecvLength > 255) /* FIXME: PC/SC Lite quirk */
dwRecvLength = 255;
if (sc_debug > 3) { if (sc_debug > 3) {
char buf[2048]; char buf[2048];
@ -239,7 +241,7 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
int r; int r;
SC_FUNC_CALLED(card->ctx); SC_FUNC_CALLED(card->ctx);
r = sc_check_apdu(apdu); r = sc_check_apdu(card->ctx, apdu);
SC_TEST_RET(card->ctx, r, "APDU sanity check failed"); SC_TEST_RET(card->ctx, r, "APDU sanity check failed");
r = sc_transceive_t0(card, apdu); r = sc_transceive_t0(card, apdu);
SC_TEST_RET(card->ctx, r, "transceive_t0() failed"); SC_TEST_RET(card->ctx, r, "transceive_t0() failed");
@ -396,7 +398,9 @@ int sc_select_file(struct sc_card *card,
ctx = card->ctx; ctx = card->ctx;
if (in_path->len > SC_MAX_PATH_SIZE) if (in_path->len > SC_MAX_PATH_SIZE)
return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
if (in_path->len == 0)
SC_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
memcpy(path, in_path->value, in_path->len); memcpy(path, in_path->value, in_path->len);
pathlen = in_path->len; pathlen = in_path->len;
@ -760,6 +764,9 @@ const char *sc_strerror(int error)
"Unknown reply from SmartCard", "Unknown reply from SmartCard",
"Requested object not found", "Requested object not found",
"Card reset" "Card reset"
"Required ASN.1 object not found",
"Premature end of ASN.1 stream",
"Too many objects",
}; };
int nr_errors = sizeof(errors) / sizeof(errors[0]); int nr_errors = sizeof(errors) / sizeof(errors[0]);