- 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_CONFIG_SRCDIR(src/sc.c)
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.

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-pin.c sc-pkcs15-prkey.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
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 "sc-asn1.h"
#include "sc-log.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
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;
}
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)
{
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++;
if (outlen < octets_left)
return SC_ERROR_INVALID_ARGUMENTS;
return SC_ERROR_BUFFER_TOO_SMALL;
while (octets_left) {
/* 1st octet of input: ABCDEFGH, where A is the MSB */
/* 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--;
count++;
}
return (count * 8) - zero_bits;
return (count * 8) - zero_bits;
}
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;
}
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)
{
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;
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
#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 */
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_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);
@ -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_object_id(const u8 * inbuf, int inlen,
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_UNIVERSAL 0x00

View File

@ -31,10 +31,14 @@ extern "C" {
#define SC_PKCS15_PIN_MAGIC 0x31415926
#define SC_PKCS15_MAX_PINS 2
#define SC_PKCS15_MAX_CERTS 3
#define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32
#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 {
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];
int pin_count;
struct sc_file file_dir, file_ao1, file_app;
struct sc_file file_dir, file_app;
/* in app DF */
struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf;
struct sc_file file_aodf, file_ao2;
struct sc_file file_cdf1, file_cdf2, file_cdf3;
struct sc_file file_cdf[SC_PKCS15_MAX_CDFS];
int cdf_count;
struct sc_file file_aodf[SC_PKCS15_MAX_AODFS];
int aodf_count;
struct sc_file file_dodf;
};

View File

@ -56,6 +56,9 @@ extern "C" {
#define SC_ERROR_UNKNOWN_REPLY -1023
#define SC_ERROR_OBJECT_NOT_FOUND -1024
#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_1 1
@ -111,6 +114,7 @@ struct sc_object_id {
struct sc_path {
u8 value[SC_MAX_PATH_SIZE];
int len;
int index;
};
struct sc_file {

View File

@ -329,25 +329,26 @@ static int get_certs_from_file(struct sc_pkcs15_card *card,
int r, taglen, left;
u8 buf[MAX_BUFFER_SIZE];
const u8 *tag, *p;
int count = 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;
left = r;
p = buf;
count = 0;
while (card->cert_count < SC_PKCS15_MAX_CERTS) {
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE */
if (tag == NULL)
break;
if (parse_x509_cert_info(&card->cert_info[card->cert_count], tag, taglen))
break;
while ((tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen)) != NULL) {
if (card->cert_count >= SC_PKCS15_MAX_CERTS)
return SC_ERROR_TOO_MANY_OBJECTS;
r = parse_x509_cert_info(&card->cert_info[card->cert_count],
tag, taglen);
if (r)
return r;
card->cert_count++;
}
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 r;
int r, i;
assert(card != NULL);
if (card->cert_count)
return card->cert_count; /* already enumerated */
card->cert_count = 0;
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);
for (i = 0; i < card->cdf_count; i++) {
r = get_certs_from_file(card, &card->file_cdf[i]);
if (r != 0)
return r;
}
r = get_certs_from_file(card, &card->file_cdf3);
if (r != 0)
return r;
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;
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_cdf1, "50154403", 0);
format_file_struct(&card->file_cdf2, "50154404", 0);
format_file_struct(&card->file_cdf3, "50154405", 0);
card->cdf_count = 3;
format_file_struct(&card->file_cdf[0], "50154403", 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_odf, "50155031", 0);
format_file_struct(&card->file_tokeninfo, "50155032", 0);

View File

@ -21,6 +21,7 @@
#include "opensc.h"
#include "opensc-pkcs15.h"
#include "sc-asn1.h"
#include "sc-log.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
@ -119,15 +120,45 @@ 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,
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 r, i;
u8 buf[MAX_BUFFER_SIZE];
const u8 *tag, *p;
int taglen, buflen;
struct sc_context *ctx = p15card->card->ctx;
assert(p15card != NULL);
SC_FUNC_CALLED(ctx);
if (p15card->pin_count) {
for (i = 0; i < p15card->pin_count; i++) {
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)
return i; /* Already enumerated */
}
r = sc_select_file(p15card->card, &p15card->file_aodf,
&p15card->file_aodf.path,
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;
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");
}
return p15card->pin_count;
}

View File

@ -55,84 +55,51 @@ void sc_pkcs15_print_card(const struct sc_pkcs15_card *card)
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)
{
const u8 *tag, *p = buf;
int i, taglen, left = buflen;
int i, r;
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 */
if (p == NULL)
struct sc_asn1_struct asn1_tokeninfo[] = {
{ "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;
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;
card->version = tag[0] + 1;
tag = sc_asn1_skip_tag(&p, &left, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
goto err;
card->serial_number = malloc(taglen * 2 + 1);
}
card->version += 1;
card->serial_number = malloc(serial_len * 2 + 1);
card->serial_number[0] = 0;
for (i = 0; i < taglen; i++) {
for (i = 0; i < serial_len; i++) {
char byte[3];
sprintf(byte, "%02X", tag[i]);
sprintf(byte, "%02X", serial[i]);
strcat(card->serial_number, byte);
}
tag = sc_asn1_skip_tag(&p, &left, 0x0C, &taglen); /* UTF8 STRING */
if (tag == NULL)
goto err;
card->manufacturer_id = malloc(taglen + 1);
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));
if (asn1_tokeninfo[2].flags & SC_ASN1_PRESENT)
card->manufacturer_id = strdup(mnfid);
else
card->manufacturer_id = strdup("(unknown)");
return;
err:
err:
if (card->serial_number == NULL)
card->serial_number = strdup("(unknown)");
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)
{
const u8 *tag;
int taglen;
const char *aid = "\xA0\x00\x00\x00\x63PKCS-15";
const int aidlen = 12;
const u8 *aidref = "\xA0\x00\x00\x00\x63PKCS-15";
const int aidref_len = 12;
int r;
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);
if (buf == NULL)
if (buf == NULL) {
error(card->card->ctx, "No [APPLICATION 1] tag in EF(DIR)\n");
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;
}
static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
{
const u8 *tag;
int taglen;
/* authObjects */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA8, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_aodf.path))
return -1;
/* CDF #1 -- Card holder certificates */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA4, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_cdf1.path))
return -1;
/* CDF #2 -- New certificates */
tag += taglen;
taglen += 2;
if ((tag = sc_asn1_verify_tag(tag, taglen, 0xA4, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_cdf2.path))
return -1;
/* CDF #3 -- Trusted CA certificates */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA5, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_cdf3.path))
return -1;
/* PrKDF */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA0, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_prkdf.path))
return -1;
/* DODF */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA7, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_dodf.path))
return -1;
const u8 *p = buf;
int r, left = buflen;
struct sc_path path;
struct sc_asn1_struct asn1_obj_or_path[] = {
{ "path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0, &path },
{ NULL } };
struct sc_asn1_struct asn1_odf[] = {
{ "privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "certificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "trustedCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 5 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "dataObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 7 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "authObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 8 | SC_ASN1_CONS, 0, asn1_obj_or_path },
};
while (left > 0) {
r = sc_asn1_parse_choice(card->card->ctx, asn1_odf, p, left, &p, &left);
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
break;
if (r < 0)
return r;
switch (r) {
case 0:
card->file_prkdf.path = path;
break;
case 1:
case 2:
if (card->cdf_count == SC_PKCS15_MAX_CDFS) {
error(card->card->ctx, "too many CDFs on card\n");
break;
}
card->file_cdf[card->cdf_count].path = path;
card->cdf_count++;
break;
case 3:
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;
}
@ -274,11 +265,15 @@ int sc_pkcs15_init(struct sc_card *card,
err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error;
}
defaults = find_defaults(buf, err);
if (p15card->card->ctx->use_cache)
defaults = find_defaults(buf, err);
if (defaults == NULL) {
memcpy(&tmppath, &p15card->file_app.path, sizeof(struct sc_path));
memcpy(tmppath.value + tmppath.len, "\x50\x31", 2);
tmppath.len += 2;
if (p15card->file_odf.path.len == 0) {
tmppath = p15card->file_app.path;
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,
SC_SELECT_FILE_BY_PATH);
if (err)
@ -295,9 +290,12 @@ int sc_pkcs15_init(struct sc_card *card,
err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error;
}
tmppath.len -= 2;
memcpy(tmppath.value + tmppath.len, "\x50\x32", 2);
tmppath.len += 2;
if (p15card->file_tokeninfo.path.len == 0) {
tmppath.len -= 2;
memcpy(tmppath.value + tmppath.len, "\x50\x32", 2);
tmppath.len += 2;
} else
tmppath = p15card->file_tokeninfo.path;
} else {
defaults->defaults_func(p15card, defaults->arg);
tmppath = p15card->file_tokeninfo.path;
@ -316,7 +314,7 @@ int sc_pkcs15_init(struct sc_card *card,
parse_tokeninfo(p15card, buf, err);
*p15card_out = p15card;
return 0;
error:
error:
free(p15card);
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;
/* FIXME: parse rest */
attr->auth_id.len = 0;
attr->user_consent = 0;
return 0;

View File

@ -31,10 +31,14 @@ extern "C" {
#define SC_PKCS15_PIN_MAGIC 0x31415926
#define SC_PKCS15_MAX_PINS 2
#define SC_PKCS15_MAX_CERTS 3
#define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32
#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 {
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];
int pin_count;
struct sc_file file_dir, file_ao1, file_app;
struct sc_file file_dir, file_app;
/* in app DF */
struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf;
struct sc_file file_aodf, file_ao2;
struct sc_file file_cdf1, file_cdf2, file_cdf3;
struct sc_file file_cdf[SC_PKCS15_MAX_CDFS];
int cdf_count;
struct sc_file file_aodf[SC_PKCS15_MAX_AODFS];
int aodf_count;
struct sc_file file_dodf;
};

View File

@ -21,8 +21,24 @@
#ifndef _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 */
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_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);
@ -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_object_id(const u8 * inbuf, int inlen,
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_UNIVERSAL 0x00

View File

@ -114,33 +114,33 @@ int sc_hex_to_bin(const char *in, u8 *out, int *outlen)
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) {
case SC_APDU_CASE_1:
if (apdu->datalen)
return SC_ERROR_INVALID_ARGUMENTS;
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break;
case SC_APDU_CASE_2_SHORT:
if (apdu->datalen)
return SC_ERROR_INVALID_ARGUMENTS;
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
if (apdu->resplen < apdu->le)
return SC_ERROR_INVALID_ARGUMENTS;
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break;
case SC_APDU_CASE_3_SHORT:
if (apdu->datalen == 0 || apdu->data == NULL)
return SC_ERROR_INVALID_ARGUMENTS;
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break;
case SC_APDU_CASE_4_SHORT:
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)
return SC_ERROR_INVALID_ARGUMENTS;
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
break;
case SC_APDU_CASE_2_EXT:
case SC_APDU_CASE_3_EXT:
case SC_APDU_CASE_4_EXT:
return SC_ERROR_NOT_SUPPORTED;
SC_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
return 0;
}
@ -195,6 +195,8 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
dwSendLength = data - s;
dwRecvLength = apdu->resplen + 2;
if (dwRecvLength > 255) /* FIXME: PC/SC Lite quirk */
dwRecvLength = 255;
if (sc_debug > 3) {
char buf[2048];
@ -239,7 +241,7 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
int r;
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");
r = sc_transceive_t0(card, apdu);
SC_TEST_RET(card->ctx, r, "transceive_t0() failed");
@ -396,7 +398,9 @@ int sc_select_file(struct sc_card *card,
ctx = card->ctx;
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);
pathlen = in_path->len;
@ -760,6 +764,9 @@ const char *sc_strerror(int error)
"Unknown reply from SmartCard",
"Requested object not found",
"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]);