- 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:
parent
9423884172
commit
5e00917fcc
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue