Hello Viktor,

On Tue, 2010-10-26 at 17:23 +0200, Viktor TARASOV wrote:
> I've got this conclusion from the 'Unambiguous descriptions of ASN.1 
> tagging'
> (http://powerasn.ncottin.net/download/ASN1_Tagging.pdf) .
> 
> I agree that it's not a supreme authority on the subject,
> nevertheless the natively PKCS#15 cards that I'm using (Oberthur, 
> Morpho, Gemalto) have the encoding
> of the 'lastUpdate' presented in the second dump.

Exactly that information I need. Thank you very much.

Please can you try the attached patch with the other p15 cards you have.
Only "pkcs15-tool -D" will produce meaningful output. And "pkcs15-init
-C -c cardos -p pkcs15 --so-pin=xxxx" will encode a conforming TokenInfo
(may work for other cards too).

Notes:
* the path of PKCS#15 Application (3F005015) is hard coded in
  pkcs15.c line 665
* you could remove line 756 in pkcs15.c but I assume that something
  will fail, because encoding of all other objects is wrong too

Kind Regards
Andre Zepezauer
Index: tools/pkcs15-tool.c
===================================================================
--- tools/pkcs15-tool.c	(revision 4829)
+++ tools/pkcs15-tool.c	(working copy)
@@ -1093,37 +1093,202 @@
 	return 0;
 }
 
-static int dump(void)
+static char buf[1024];
+
+static const char *get_parameters(sc_pkcs15_der_t der)
 {
+	if (der.len < (sizeof(buf) / 2 - 1)) {
+		sc_bin_to_hex(der.value, der.len, buf, sizeof(buf), ' ');
+	} else {
+		buf[0] = '\0';
+	}
 
-	const char *flags[] = {
-		"Read-only",
-		"Login required",
-		"PRN generation",
-		"EID compliant"
-	};
+	return buf;
+}
 
-	int i, count = 0;
+static const char *get_operations(int ops)
+{
+	memset(buf, '-', 8);
+	if (ops & 0x01) buf[0] = 'c';  // compute-checksum
+	if (ops & 0x02)	buf[1] = 's';  // compute-signature
+	if (ops & 0x04) buf[2] = 'q';  // verify-checksum
+	if (ops & 0x08) buf[3] = 'v';  // verify-signature
+	if (ops & 0x10) buf[4] = 'e';  // encipher
+	if (ops & 0x20) buf[5] = 'd';  // decipher
+	if (ops & 0x40) buf[6] = 'h';  // hash
+	if (ops & 0x80) buf[7] = 'g';  // generate-key
+	buf[8] = 0;
 
-	printf("PKCS#15 Card [%s]:\n", p15card->tokeninfo->label);
-	printf("\tVersion        : %d\n", p15card->tokeninfo->version);
-	printf("\tSerial number  : %s\n", p15card->tokeninfo->serial_number);
-	printf("\tManufacturer ID: %s\n", p15card->tokeninfo->manufacturer_id);
-	if (p15card->tokeninfo->last_update)
-		printf("\tLast update    : %s\n", p15card->tokeninfo->last_update);
-	if (p15card->tokeninfo->preferred_language)
-		printf("\tLanguage       : %s\n", p15card->tokeninfo->preferred_language);
-	printf("\tFlags          : ");
-	for (i = 0; i < 4; i++) {
-		if ((p15card->tokeninfo->flags >> i) & 1) {
-			if (count)
-				printf(", ");
-			printf("%s", flags[i]);
-			count++;
+	return buf;
+}
+
+static const char *get_oid(struct sc_object_id oid)
+{
+	char comp[32];	/* temporary storage of decimal encoded integers */
+	buf[0] = 0;
+	if (oid.value[0] != -1) {
+		sprintf(comp, "%d", oid.value[0]);
+		strcat(buf, comp);
+		int i = 1;
+		while (i < SC_MAX_OBJECT_ID_OCTETS && oid.value[i] != -1) {
+			sprintf(comp, ".%d", oid.value[i]);
+			strcat(buf, comp);
+			i++;
 		}
 	}
-	printf("\n\n");
 
+	return buf;
+}
+
+static void conditional_fprintf(FILE *fd, const char *str, const char *pre, const char *val)
+{
+	if (val)
+		fprintf(fd, str, pre, val);
+}
+
+void strcpy_bp(u8 * dst, const char *src, size_t dstsize)
+{
+        size_t c;
+
+        if (!dst || !src || !dstsize)
+                return;
+
+        memset((char *)dst, ' ', dstsize);
+
+        c = strlen(src) > dstsize ? dstsize : strlen(src);
+
+        memcpy((char *)dst, src, c);
+}
+
+static void fprint_algorithm_infos(FILE *fd, const sc_pkcs15_algorithm_info_t **alg, const char *pre)
+{
+	int i, num, max[6];
+
+	/* determine number of items */
+	if (alg) {
+		num = -1;
+		while (alg[++num]);
+	} else {
+		num = 0;
+	}
+
+	for (i = 0; i < 6; i++)
+		max[i] = 0;
+
+	/* determine max width of columns */
+	for (i = 0; i < num; i++) {
+		/* max[0] := reference / not required */
+		if (alg[i]->algorithm > max[1])
+			max[1] = alg[i]->algorithm;
+		if (strlen(get_parameters(alg[i]->parameters)) > max[2])
+			max[2] = strlen(get_parameters(alg[i]->parameters));
+		if (strlen(get_operations(alg[i]->operations)) > max[3])
+			max[3] = strlen(get_operations(alg[i]->operations));
+		if (strlen(get_oid(alg[i]->oid)) > max[4])
+			max[4] = strlen(get_oid(alg[i]->oid));
+		/* max[5] := alg_ref / not required */
+	}
+
+	char *par = calloc(1, max[2] + 1);
+	char *ops = calloc(1, max[3] + 1);
+	char *oid = calloc(1, max[4] + 1);
+
+	/* write num rows to fd (one row for each algorithm) */
+	for (i = 0; i < num; i++) {
+		strcpy_bp(par, get_parameters(alg[i]->parameters), max[2]);
+		strcpy_bp(ops, get_operations(alg[i]->operations), max[3]);
+		strcpy_bp(oid, get_oid(alg[i]->oid), max[4]);
+		if (max[1] < 256) {
+			fprintf(fd, "%s%3d:  0x%02x  [%s]  %s  %s  0x%02x\n", pre,
+				alg[i]->reference, alg[i]->algorithm, par, ops, oid, alg[i]->alg_ref);
+		} else {
+			fprintf(fd, "%s%3d:  0x%04x  [%s]  %s  %s  0x%02x\n", pre,
+				alg[i]->reference, alg[i]->algorithm, par, ops, oid, alg[i]->alg_ref);
+		}
+	}
+
+	free(par);
+	free(ops);
+	free(oid);
+}
+
+
+void fprint_tokeninfo(FILE *fd, const sc_pkcs15_tokeninfo_t *ti, const char *pre)
+{
+	            fprintf(fd, "%sVersion       : %d\n", pre, ti->version);
+	conditional_fprintf(fd, "%sSerial Number : %s\n", pre, ti->serial_number);
+	conditional_fprintf(fd, "%sManufacturer  : %s\n", pre, ti->manufacturer_id);
+	conditional_fprintf(fd, "%sLabel         : %s\n", pre, ti->label);
+	if (ti->flags) {
+		const char *flags[] = {
+			"Read-only",
+			"Login required",
+			"PRN generation",
+			"EID compliant"
+		};
+		int i, count = 0;
+
+		fprintf(fd, "%sFlags         : ", pre);
+		for (i = 0; i < 4; i++) {
+			if ((ti->flags >> i) & 1) {
+				if (count)
+					printf(", ");
+				fprintf(fd, "%s", flags[i]);
+				count++;
+			}
+		}
+		fprintf(fd, "\n");
+	}
+	if (ti->record_info) {
+		char buf[7][10];
+		int i, val[7];
+
+		val[0] = ti->record_info->od_record_length;
+		val[1] = ti->record_info->prkd_record_length;
+		val[2] = ti->record_info->pukd_record_length;
+		val[3] = ti->record_info->skd_record_length;
+		val[4] = ti->record_info->cd_record_length;
+		val[5] = ti->record_info->dcod_record_length;
+		val[6] = ti->record_info->aod_record_length;
+
+		for (i = 0; i < 7; i++) {
+			if (val[i] < 0) {
+				sprintf(buf[i], "t");		/* transparent EF */
+			} else if (val[i] == 0) {
+				sprintf(buf[i], "v");		/* variable length records */
+			} else if (val[i] >= (1 << 16)) {
+				sprintf(buf[i], "?");		/* value too large */
+			} else {
+				sprintf(buf[i], "%d", val[i]);	/* fixed length records */
+			}
+		}
+
+		fprintf(fd, "%sRecord Info   : o=%s pr=%s pu=%s s=%s c=%s d=%s a=%s\n",
+			pre, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+	}
+	if (ti->algorithm_infos[0] && (strlen(pre) < 128)) {
+		fprintf(fd, "%sAlgorithms    : [reference: algorithm parameters operations oid algRef]\n", pre);
+		char buf[132]; buf[0] = 0; strcat(buf, pre); strcat(buf, "\t");
+		fprint_algorithm_infos(fd, (const sc_pkcs15_algorithm_info_t **) ti->algorithm_infos, buf);
+	}
+	conditional_fprintf(fd, "%sIssuer Id     : %s\n", pre, ti->issuer_id);
+	conditional_fprintf(fd, "%sHolder Id     : %s\n", pre, ti->holder_id);
+	conditional_fprintf(fd, "%sLast Update   : %s\n", pre, ti->last_update);
+	conditional_fprintf(fd, "%sLanguage      : %s\n", pre, ti->preferred_language);
+}
+
+static int dump(void)
+{
+	if (p15card->tokeninfo->version == 0) {
+		printf("TokenInfo [PKCS#15]\n");
+	} else if (p15card->tokeninfo->version == 1) {
+		printf("TokenInfo [ISO/IEC 7816-15:2004]\n");
+	} else {
+		printf("TokenInfo [unknown]\n");
+	}
+
+	fprint_tokeninfo(stdout, p15card->tokeninfo, "\t");
+	printf("\n");
 	list_pins();
 	list_private_keys();
 	list_public_keys();
Index: libopensc/pkcs15.c
===================================================================
--- libopensc/pkcs15.c	(revision 4829)
+++ libopensc/pkcs15.c	(working copy)
@@ -30,162 +30,194 @@
 #include "pkcs15.h"
 #include "asn1.h"
 
-static const struct sc_asn1_entry c_asn1_twlabel[] = {
-	{ "twlabel", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, 0, NULL, NULL },
-	{ NULL, 0, 0, 0, NULL, NULL }
-};
 
-static const struct sc_asn1_entry c_asn1_algorithm_info[7] = {
-	{ "reference",		SC_ASN1_INTEGER,	SC_ASN1_TAG_INTEGER,	0, NULL, NULL },
-	{ "algorithmPKCS#11",	SC_ASN1_INTEGER,	SC_ASN1_TAG_INTEGER,	0, NULL, NULL },
-	{ "parameters",		SC_ASN1_NULL,		SC_ASN1_TAG_NULL,	0, NULL, NULL },
-	{ "supportedOperations",SC_ASN1_BIT_FIELD,	SC_ASN1_TAG_BIT_STRING,	0, NULL, NULL },
-	{ "objId",		SC_ASN1_OBJECT,		SC_ASN1_TAG_OBJECT,	0, NULL, NULL },
-	{ "algRef",		SC_ASN1_INTEGER,	SC_ASN1_TAG_INTEGER,	0, NULL, NULL },
+static const struct sc_asn1_entry DEF_TokenInfo[] = {
+	{ "version",             SC_ASN1_INTEGER,         0,               0,                NULL, NULL },
+	{ "serialNumber",        SC_ASN1_OCTET_STRING,    0,               SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "manufacturerID",      SC_ASN1_UTF8STRING,      0,               SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "label",               SC_ASN1_UTF8STRING,      SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "cardflags",           SC_ASN1_BIT_FIELD,       0,               0,                NULL, NULL },
+	{ "seInfo",              SC_ASN1_SEQUENCE,        0,               SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "recordInfo",	         SC_ASN1_SEQUENCE,        SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "supportedAlgorithms", SC_ASN1_SEQUENCE,        SC_ASN1_CTX | 2, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "issuerId",            SC_ASN1_UTF8STRING,      SC_ASN1_CTX | 3, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "holderId",            SC_ASN1_UTF8STRING,      SC_ASN1_CTX | 4, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "lastUpdate",          SC_ASN1_CHOICE,          SC_ASN1_CTX | 5, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "preferredLanguage",   SC_ASN1_PRINTABLESTRING, 0,               SC_ASN1_OPTIONAL, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-/*
- * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS  defined as 8
- */
-static const struct sc_asn1_entry c_asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1] = {
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
+static const struct sc_asn1_entry DEF_RecordInfo[] = {
+	{ "oDRecordLength",   SC_ASN1_INTEGER, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "prKDRecordLength", SC_ASN1_INTEGER, SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "puKDRecordLength", SC_ASN1_INTEGER, SC_ASN1_CTX | 2, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "sKDRecordLength",  SC_ASN1_INTEGER, SC_ASN1_CTX | 3, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "cDRecordLength",   SC_ASN1_INTEGER, SC_ASN1_CTX | 4, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "dCODRecordLength", SC_ASN1_INTEGER, SC_ASN1_CTX | 5, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "aODRecordLength",  SC_ASN1_INTEGER, SC_ASN1_CTX | 6, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-static const struct sc_asn1_entry c_asn1_toki[] = {
-	{ "version",        SC_ASN1_INTEGER,      SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
-	{ "serialNumber",   SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "manufacturerID", SC_ASN1_UTF8STRING,   SC_ASN1_TAG_UTF8STRING, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "label",	    SC_ASN1_UTF8STRING,   SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL },
-	/* XXX the Taiwanese ID card erroneously uses explicit tagging */
-	{ "label-tw",       SC_ASN1_STRUCT,       SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "tokenflags",	    SC_ASN1_BIT_FIELD,    SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL },
-	{ "seInfo",	    SC_ASN1_SE_INFO,	  SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "recordInfo",	    SC_ASN1_STRUCT,       SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "supportedAlgorithms", SC_ASN1_STRUCT,  SC_ASN1_CONS | SC_ASN1_CTX | 2, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "issuerId",       SC_ASN1_UTF8STRING,   SC_ASN1_CTX | 3, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "holderId",       SC_ASN1_UTF8STRING,   SC_ASN1_CTX | 4, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "lastUpdate",     SC_ASN1_GENERALIZEDTIME, SC_ASN1_CTX | 5, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "preferredLanguage", SC_ASN1_PRINTABLESTRING, SC_ASN1_TAG_PRINTABLESTRING, SC_ASN1_OPTIONAL, NULL, NULL },
+static const struct sc_asn1_entry DEF_AlgorithmInfo[] = {
+	{ "reference",           SC_ASN1_INTEGER,   0, 0,                NULL, NULL },
+	{ "algorithm",           SC_ASN1_INTEGER,   0, 0,                NULL, NULL },
+	{ "parameters",          SC_ASN1_NULL,      0, 0,                NULL, NULL },
+	{ "supportedOperations", SC_ASN1_BIT_FIELD, 0, 0,                NULL, NULL },
+	{ "objId",               SC_ASN1_OBJECT,    0, SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "algRef",              SC_ASN1_INTEGER,   0, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-static const struct sc_asn1_entry c_asn1_tokeninfo[] = {
-	{ "TokenInfo", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, 0, NULL, NULL },
+static const struct sc_asn1_entry DEF_LastUpdate[] = {
+	{ "generalizedTime", SC_ASN1_GENERALIZEDTIME, 0, 0, NULL, NULL },
+//	{ "referencedTime",  SC_ASN1_CHOICE,          0, 0, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-int sc_pkcs15_parse_tokeninfo(sc_context_t *ctx,
-	sc_pkcs15_tokeninfo_t *ti, const u8 *buf, size_t blen)
+static int decode_sequence(sc_context_t *ctx, struct sc_asn1_entry *DEF_TYPE,
+			const u8 *in, size_t in_len, const u8 **newp, size_t *len_left)
 {
-	int r, ii;
-	u8 serial[128];
-	size_t serial_len = sizeof(serial);
-	u8 mnfid[SC_PKCS15_MAX_LABEL_SIZE];
-	size_t mnfid_len  = sizeof(mnfid);
-	u8 label[SC_PKCS15_MAX_LABEL_SIZE];
-	size_t label_len = sizeof(label);
-	u8 last_update[32];
-	size_t lupdate_len = sizeof(last_update) - 1;
-	size_t flags_len   = sizeof(ti->flags);
-	struct sc_asn1_entry asn1_toki[14], asn1_tokeninfo[3], asn1_twlabel[3];
-	u8 preferred_language[3];
-	size_t lang_length = sizeof(preferred_language);
-	struct sc_asn1_entry asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1],
-			     asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7];
-	size_t reference_len = sizeof(ti->supported_algos[0].reference);
-	size_t mechanism_len = sizeof(ti->supported_algos[0].mechanism);
-	size_t operations_len = sizeof(ti->supported_algos[0].operations);
-	size_t algo_ref_len = sizeof(ti->supported_algos[0].algo_ref);
+	struct sc_asn1_entry asn1_sequence[] = {
+		{ "SEQUENCE", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, 0, DEF_TYPE, NULL },
+		{ NULL, 0, 0, 0, NULL, NULL }
+	};
 
-	memset(last_update, 0, sizeof(last_update));
-	sc_copy_asn1_entry(c_asn1_twlabel, asn1_twlabel);
-	sc_copy_asn1_entry(c_asn1_toki, asn1_toki);
-	sc_copy_asn1_entry(c_asn1_tokeninfo, asn1_tokeninfo);
-	sc_format_asn1_entry(asn1_twlabel, label, &label_len, 0);
-	
-	for (ii=0; ii<SC_MAX_SUPPORTED_ALGORITHMS; ii++)
-		sc_copy_asn1_entry(c_asn1_algorithm_info, asn1_algo_infos[ii]);
-	sc_copy_asn1_entry(c_asn1_supported_algorithms, asn1_supported_algorithms);
+	return sc_asn1_decode(ctx, asn1_sequence, in, in_len, newp, len_left);
+}
 
-	for (ii=0; ii<SC_MAX_SUPPORTED_ALGORITHMS; ii++)   {
-		sc_format_asn1_entry(asn1_algo_infos[ii] + 0, &ti->supported_algos[ii].reference, &reference_len, 0);
-		sc_format_asn1_entry(asn1_algo_infos[ii] + 1, &ti->supported_algos[ii].mechanism, &mechanism_len, 0);
-		sc_format_asn1_entry(asn1_algo_infos[ii] + 2, NULL, NULL, 0);
-		sc_format_asn1_entry(asn1_algo_infos[ii] + 3, &ti->supported_algos[ii].operations, &operations_len, 0);
-		sc_format_asn1_entry(asn1_algo_infos[ii] + 4, &ti->supported_algos[ii].algo_id, NULL, 1);
-		sc_format_asn1_entry(asn1_algo_infos[ii] + 5, &ti->supported_algos[ii].algo_ref, &algo_ref_len, 0);
-		sc_format_asn1_entry(asn1_supported_algorithms + ii, asn1_algo_infos[ii], NULL, 0);
+
+int sc_pkcs15_parse_tokeninfo(sc_context_t *ctx, sc_pkcs15_tokeninfo_t *ti, const u8 *in, size_t in_len)
+{
+	u8 *buf_sn, *buf_si, *buf_ri, *buf_ai;
+	size_t buf_sn_len, buf_si_len, buf_ri_len, buf_ai_len, l, l_update;
+	struct sc_asn1_entry TokenInfo[14], RecordInfo[8], AlgorithmInfo[7], LastUpdate[3];
+
+	sc_pkcs15_record_info_t ri;
+		ri.od_record_length   = -1;
+		ri.prkd_record_length = -1;
+		ri.pukd_record_length = -1;
+		ri.skd_record_length  = -1;
+		ri.cd_record_length   = -1;
+		ri.dcod_record_length = -1;
+		ri.aod_record_length  = -1;
+
+	/* assamble RecordInfo */
+	sc_copy_asn1_entry(DEF_RecordInfo, RecordInfo);
+        sc_format_asn1_entry(RecordInfo + 0, &ri.od_record_length,   NULL, 0);
+        sc_format_asn1_entry(RecordInfo + 1, &ri.prkd_record_length, NULL, 0);
+        sc_format_asn1_entry(RecordInfo + 2, &ri.pukd_record_length, NULL, 0);
+        sc_format_asn1_entry(RecordInfo + 3, &ri.skd_record_length,  NULL, 0);
+        sc_format_asn1_entry(RecordInfo + 4, &ri.cd_record_length,   NULL, 0);
+        sc_format_asn1_entry(RecordInfo + 5, &ri.dcod_record_length, NULL, 0);
+        sc_format_asn1_entry(RecordInfo + 6, &ri.aod_record_length,  NULL, 0);
+
+	/* assamble LastUpdate */
+	sc_copy_asn1_entry(DEF_LastUpdate, LastUpdate);
+	sc_format_asn1_entry(LastUpdate + 0, &ti->last_update, &l_update,   0);
+	sc_format_asn1_entry(LastUpdate + 1, NULL,             NULL, 0);
+	LastUpdate[0].flags |= SC_ASN1_ALLOC;
+
+	/* assamble TokenInfo */
+	sc_copy_asn1_entry(DEF_TokenInfo, TokenInfo);
+	sc_format_asn1_entry(TokenInfo +  0, &ti->version, NULL, 0);
+	sc_format_asn1_entry(TokenInfo +  1, &buf_sn, &buf_sn_len, 0);
+	sc_format_asn1_entry(TokenInfo +  2, &ti->manufacturer_id, &l, 0);
+	sc_format_asn1_entry(TokenInfo +  3, &ti->label, &l, 0);
+	sc_format_asn1_entry(TokenInfo +  4, &ti->flags, NULL, 0);
+	sc_format_asn1_entry(TokenInfo +  5, &buf_si, &buf_si_len, 0);
+	sc_format_asn1_entry(TokenInfo +  6, &buf_ri, &buf_ri_len, 0);
+	sc_format_asn1_entry(TokenInfo +  7, &buf_ai, &buf_ai_len, 0);
+	sc_format_asn1_entry(TokenInfo +  8, &ti->issuer_id, &l, 0);
+	sc_format_asn1_entry(TokenInfo +  9, &ti->holder_id, &l, 0);
+	sc_format_asn1_entry(TokenInfo + 10, LastUpdate, NULL, 0);
+	sc_format_asn1_entry(TokenInfo + 11, &ti->preferred_language, &l, 0);
+
+        /* allocate everything where entry->arg != NULL */
+        l = -1;
+	while (TokenInfo[++l].name)
+		if (TokenInfo[l].arg != NULL)
+			TokenInfo[l].flags |= SC_ASN1_ALLOC;
+
+	if(decode_sequence(ctx, TokenInfo, in, in_len, NULL, NULL))
+		goto error;
+
+	/* encode serial number in hex, if present */
+	if (TokenInfo[1].flags & SC_ASN1_PRESENT) {
+		l = buf_sn_len * 2 + 1;
+		ti->serial_number = malloc(l);
+		if (ti->serial_number == NULL) goto error;
+		sc_bin_to_hex(buf_sn, buf_sn_len, ti->serial_number, l, 0);
+		free(buf_sn);
 	}
 
-	sc_format_asn1_entry(asn1_toki + 0, &ti->version, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 1, serial, &serial_len, 0);
-	sc_format_asn1_entry(asn1_toki + 2, mnfid, &mnfid_len, 0);
-	sc_format_asn1_entry(asn1_toki + 3, label, &label_len, 0);
-	sc_format_asn1_entry(asn1_toki + 4, asn1_twlabel, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 5, &ti->flags, &flags_len, 0);
-	sc_format_asn1_entry(asn1_toki + 6, &ti->seInfo, &ti->num_seInfo, 0);
-	sc_format_asn1_entry(asn1_toki + 7, NULL, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 8, asn1_supported_algorithms, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 9, NULL, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 10, NULL, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 11, last_update, &lupdate_len, 0);
-	sc_format_asn1_entry(asn1_toki + 12, preferred_language, &lang_length, 0);
-	sc_format_asn1_entry(asn1_tokeninfo, asn1_toki, NULL, 0);
-	
-	r = sc_asn1_decode(ctx, asn1_tokeninfo, buf, blen, NULL, NULL);
-	if (r) {
-		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "ASN.1 parsing of EF(TokenInfo) failed: %s",
-			sc_strerror(r));
-		return r;
+	/* TODO: process seInfo */
+	if (TokenInfo[5].flags & SC_ASN1_PRESENT) {
+		u8 buf[4096];
+		sc_hex_dump(ctx, 0, buf_si, buf_si_len, buf, sizeof(buf));
+		printf("seInfo:\n%s\n", buf);
+		free(buf_si);
 	}
-	ti->serial_number = malloc(serial_len * 2 + 1);
-	if (ti->serial_number == NULL)
-		return SC_ERROR_OUT_OF_MEMORY;
-	ti->serial_number[0] = 0;
-	for (ii = 0; ii < serial_len; ii++) {
-		char byte[3];
 
-		sprintf(byte, "%02X", serial[ii]);
-		strcat(ti->serial_number, byte);
+	/* decode RecordInfo */
+	if (TokenInfo[6].flags & SC_ASN1_PRESENT) {
+		if(sc_asn1_decode(ctx, RecordInfo, buf_ri, buf_ri_len, NULL, NULL))
+			goto error;;
+		ti->record_info = malloc(sizeof(sc_pkcs15_record_info_t));
+		if (ti->record_info == NULL) goto error;
+		*ti->record_info = ri;
+		free(buf_ri);
 	}
-	if (ti->manufacturer_id == NULL) {
-		if (asn1_toki[2].flags & SC_ASN1_PRESENT)
-			ti->manufacturer_id = strdup((char *) mnfid);
-		else
-			ti->manufacturer_id = strdup("(unknown)");
-		if (ti->manufacturer_id == NULL)
-			return SC_ERROR_OUT_OF_MEMORY;
+			
+	/* decode supportedAlgorithms */
+	if (TokenInfo[7].flags & SC_ASN1_PRESENT) {
+		u8 *buf_orig = buf_ai;
+		sc_pkcs15_algorithm_info_t ai;
+		ai.parameters.len = 0; /* required as long not parsed (see below (AlgorithmInfo + 2)) */
+
+		sc_copy_asn1_entry(DEF_AlgorithmInfo, AlgorithmInfo);
+		sc_format_asn1_entry(AlgorithmInfo + 0, &ai.reference, &l, 0);
+		sc_format_asn1_entry(AlgorithmInfo + 1, &ai.algorithm, &l, 0);
+		sc_format_asn1_entry(AlgorithmInfo + 2, NULL, NULL, 0);
+		sc_format_asn1_entry(AlgorithmInfo + 3, &ai.operations, NULL, 0);
+		sc_format_asn1_entry(AlgorithmInfo + 4, &ai.oid, &l, 0);
+		sc_format_asn1_entry(AlgorithmInfo + 5, &ai.alg_ref, &l, 0);
+
+		while (buf_ai_len) {
+			if(decode_sequence(ctx, AlgorithmInfo, buf_ai, buf_ai_len, (const u8 **) &buf_ai, &buf_ai_len))
+				goto error;
+
+			/* fix OPTIONAL attributes, if they are not present */
+			if ((AlgorithmInfo[4].flags & SC_ASN1_PRESENT) == 0)
+				ai.oid.value[0] = -1;
+			if ((AlgorithmInfo[5].flags & SC_ASN1_PRESENT) == 0)
+				ai.alg_ref = -1;
+
+			/* append one item to ti->algorithm_infos */
+			int i = -1; while (ti->algorithm_infos[++i] != NULL);
+			ti->algorithm_infos = realloc(ti->algorithm_infos, sizeof(void *) * (i + 2));
+			if (ti->algorithm_infos == NULL) goto error;
+			ti->algorithm_infos[i + 0] = malloc(sizeof(sc_pkcs15_algorithm_info_t));
+			if (ti->algorithm_infos[i + 0] == NULL)	goto error;
+			ti->algorithm_infos[i + 1] = NULL;
+
+			/* copy current info to new item of list */
+			*ti->algorithm_infos[i + 0] = ai;
+		}
+		free(buf_orig);
 	}
-	if (ti->label == NULL) {
-		if (asn1_toki[3].flags & SC_ASN1_PRESENT ||
-		    asn1_toki[4].flags & SC_ASN1_PRESENT)
-			ti->label = strdup((char *) label);
-		else
-			ti->label = strdup("(unknown)");
-		if (ti->label == NULL)
-			return SC_ERROR_OUT_OF_MEMORY;
+
+	/* fix LastUpdate */
+	if ((TokenInfo[10].flags & SC_ASN1_PRESENT) && (LastUpdate[0].flags & SC_ASN1_PRESENT)) {
+		ti->last_update = realloc(ti->last_update, l_update + 1);
+		if (ti->last_update == NULL) goto error;
+		ti->last_update[l_update] = '\0';
 	}
-	if (asn1_toki[11].flags & SC_ASN1_PRESENT) {
-		ti->last_update = strdup((char *)last_update);
-		if (ti->last_update == NULL)
-			return SC_ERROR_OUT_OF_MEMORY;
-	}
-	if (asn1_toki[12].flags & SC_ASN1_PRESENT) {
-		preferred_language[2] = 0;
-		ti->preferred_language = strdup((char *)preferred_language);
-		if (ti->preferred_language == NULL)
-			return SC_ERROR_OUT_OF_MEMORY;
-	}
+
 	return SC_SUCCESS;
+
+error:
+	/* TODO: free allocated memory */
+	return SC_ERROR_INTERNAL;
 }
 
 int sc_pkcs15_encode_tokeninfo(sc_context_t *ctx,
@@ -195,10 +227,9 @@
 	int r;
 	size_t serial_len, mnfid_len, label_len, flags_len, last_upd_len;
 	
-	struct sc_asn1_entry asn1_toki[14], asn1_tokeninfo[2];
+	struct sc_asn1_entry asn1_toki[14];
 
-	sc_copy_asn1_entry(c_asn1_toki, asn1_toki);
-	sc_copy_asn1_entry(c_asn1_tokeninfo, asn1_tokeninfo);
+	sc_copy_asn1_entry(DEF_TokenInfo, asn1_toki);
 	sc_format_asn1_entry(asn1_toki + 0, &ti->version, NULL, 1);
 	if (ti->serial_number != NULL) {
 		u8 serial[128];
@@ -223,22 +254,30 @@
 		sc_format_asn1_entry(asn1_toki + 3, NULL, NULL, 0);
 	if (ti->flags) {
 		flags_len = sizeof(ti->flags);
-		sc_format_asn1_entry(asn1_toki + 5, &ti->flags, &flags_len, 1);
+		sc_format_asn1_entry(asn1_toki + 4, &ti->flags, &flags_len, 1);
 	} else
-		sc_format_asn1_entry(asn1_toki + 5, NULL, NULL, 0);
+		sc_format_asn1_entry(asn1_toki + 4, NULL, NULL, 0);
+	sc_format_asn1_entry(asn1_toki + 5, NULL, NULL, 0);
 	sc_format_asn1_entry(asn1_toki + 6, NULL, NULL, 0);
 	sc_format_asn1_entry(asn1_toki + 7, NULL, NULL, 0);
 	sc_format_asn1_entry(asn1_toki + 8, NULL, NULL, 0);
 	sc_format_asn1_entry(asn1_toki + 9, NULL, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 10, NULL, NULL, 0);
 	if (ti->last_update != NULL) {
 		last_upd_len = strlen(ti->last_update);
-		sc_format_asn1_entry(asn1_toki + 11, ti->last_update, &last_upd_len, 1);
-	} else
-		sc_format_asn1_entry(asn1_toki + 11, NULL, NULL, 0);
-	sc_format_asn1_entry(asn1_toki + 12, NULL, NULL, 0);
-	sc_format_asn1_entry(asn1_tokeninfo, asn1_toki, NULL, 1);
+		struct sc_asn1_entry LastUpdate[3];
+		sc_copy_asn1_entry(DEF_LastUpdate, LastUpdate);
+		sc_format_asn1_entry(LastUpdate + 0, ti->last_update, &last_upd_len, 1);
+		sc_format_asn1_entry(asn1_toki + 10, &LastUpdate, NULL, 1);
+	} else {
+		sc_format_asn1_entry(asn1_toki + 10, NULL, NULL, 0);
+	}
+	sc_format_asn1_entry(asn1_toki + 11, NULL, NULL, 0);
 
+	struct sc_asn1_entry asn1_tokeninfo[] = {
+		{ "TokenInfo", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, SC_ASN1_PRESENT, asn1_toki, NULL },
+		{ NULL, 0, 0, 0, NULL, NULL }
+	};
+
 	r = sc_asn1_encode(ctx, asn1_tokeninfo, buf, buflen);
 	if (r) {
 		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "sc_asn1_encode() failed: %s", sc_strerror(r));
@@ -462,7 +501,10 @@
 		return NULL;
 	}
 
+	p15card->tokeninfo->se_infos = calloc(1, sizeof(void *));
+	p15card->tokeninfo->algorithm_infos = calloc(1, sizeof(void *));
 	p15card->magic = SC_PKCS15_CARD_MAGIC;
+
 	return p15card;
 }
 
@@ -507,17 +549,24 @@
 		free(p15card->tokeninfo->last_update);
 	if (p15card->tokeninfo->preferred_language != NULL)
 		free(p15card->tokeninfo->preferred_language);
-	if (p15card->tokeninfo->seInfo != NULL) {
-		for (i = 0; i < p15card->tokeninfo->num_seInfo; i++)
-			free(p15card->tokeninfo->seInfo[i]);
-		free(p15card->tokeninfo->seInfo);
-	}
+	i = -1;
+	while (p15card->tokeninfo->se_infos[++i])
+		free(p15card->tokeninfo->se_infos[i]);
+	free(p15card->tokeninfo->se_infos);
+	if (p15card->tokeninfo->record_info != NULL)
+                free(p15card->tokeninfo->record_info);
+	i = -1;
+	while (p15card->tokeninfo->algorithm_infos[++i])
+		free(p15card->tokeninfo->algorithm_infos[i]);
+	free(p15card->tokeninfo->algorithm_infos);
 	free(p15card->tokeninfo);
 	free(p15card);
 }
 
 void sc_pkcs15_card_clear(sc_pkcs15_card_t *p15card)
 {
+	size_t i;
+
 	if (p15card == NULL)
 		return;
 
@@ -573,14 +622,20 @@
 		free(p15card->tokeninfo->preferred_language);
 		p15card->tokeninfo->preferred_language = NULL;
 	}
-	if (p15card->tokeninfo->seInfo != NULL) {
-		size_t i;
-		for (i = 0; i < p15card->tokeninfo->num_seInfo; i++)
-			free(p15card->tokeninfo->seInfo[i]);
-		free(p15card->tokeninfo->seInfo);
-		p15card->tokeninfo->seInfo     = NULL;
-		p15card->tokeninfo->num_seInfo = 0;
+	i = -1;
+	while (p15card->tokeninfo->se_infos[++i])
+		free(p15card->tokeninfo->se_infos[i]);
+	free(p15card->tokeninfo->se_infos);
+	p15card->tokeninfo->se_infos = calloc(1, sizeof(void *));
+	if (p15card->tokeninfo->record_info != NULL) {
+		free(p15card->tokeninfo->record_info);
+		p15card->tokeninfo->record_info = NULL;
 	}
+	i = -1;
+	while (p15card->tokeninfo->algorithm_infos[++i])
+		free(p15card->tokeninfo->algorithm_infos[i]);
+	free(p15card->tokeninfo->algorithm_infos);
+	p15card->tokeninfo->algorithm_infos = calloc(1, sizeof(void *));
 }
 
 static int sc_pkcs15_bind_internal(sc_pkcs15_card_t *p15card)
@@ -591,7 +646,6 @@
 	sc_path_t tmppath;
 	sc_card_t    *card = p15card->card;
 	sc_context_t *ctx  = card->ctx;
-	sc_pkcs15_tokeninfo_t tokeninfo;
 
 	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "trying normal pkcs15 processing");
 
@@ -699,6 +753,8 @@
 		}
 	}
 
+p15card->df_list = NULL;
+
 	if (p15card->file_tokeninfo == NULL) {
 		tmppath = p15card->file_app->path;
 		sc_append_path_id(&tmppath, (const u8 *) "\x50\x32", 2);
@@ -721,30 +777,11 @@
 	err = sc_read_binary(card, 0, buf, len, 0);
 	if (err < 0)
 		goto end;
-	if (err <= 2) {
-		err = SC_ERROR_PKCS15_APP_NOT_FOUND;
-		goto end;
-	}
-
-	memset(&tokeninfo, 0, sizeof(tokeninfo));
-	err = sc_pkcs15_parse_tokeninfo(ctx, &tokeninfo, buf, (size_t)err);
+	len = err;
+	err = sc_pkcs15_parse_tokeninfo(ctx, p15card->tokeninfo, buf, len);
 	if (err != SC_SUCCESS)
 		goto end;
 
-	*(p15card->tokeninfo) = tokeninfo;
-
-	if (!p15card->tokeninfo->serial_number && card->serialnr.len)   {
-		char *serial = calloc(1, card->serialnr.len*2 + 1);
-		size_t ii;
-		
-		for(ii=0;ii<card->serialnr.len;ii++)
-			sprintf(serial + ii*2, "%02X", *(card->serialnr.value + ii));
-
-		p15card->tokeninfo->serial_number = serial;
-		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "p15card->tokeninfo->serial_number %s",
-			p15card->tokeninfo->serial_number);
-	}
-
 	ok = 1;
 end:
 	if(buf != NULL)
Index: libopensc/pkcs15.h
===================================================================
--- libopensc/pkcs15.h	(revision 4829)
+++ libopensc/pkcs15.h	(working copy)
@@ -416,18 +416,38 @@
 	size_t			aid_len;
 } sc_pkcs15_sec_env_info_t;
 
+typedef struct sc_pkcs15_record_info {
+	int   od_record_length;
+	int prkd_record_length;
+	int pukd_record_length;
+	int  skd_record_length;
+	int   cd_record_length;
+	int dcod_record_length;
+	int  aod_record_length;
+}  sc_pkcs15_record_info_t;
+
+typedef struct sc_pkcs15_algorithm_info {
+	int reference;			/* used to link with keys */
+	int algorithm;			/* possibly references a PKCS#11 mechanism (CKM_*) */
+	sc_pkcs15_der_t parameters;	/* parameters of algorithm */
+	unsigned int operations;	/* bitmap of supported operations */
+	struct sc_object_id oid;	/* OID of algorithm OPTIONAL */
+	int alg_ref;			/* algorithm reference according ISO 7816-4 OPTIONAL */
+} sc_pkcs15_algorithm_info_t;
+
 typedef struct sc_pkcs15_tokeninfo {
-	unsigned int version;
+	int version;
+	char *serial_number;
+	char *manufacturer_id;
+	char *label;
 	unsigned int flags;
-	char *label;
-	char *serial_number;
-	char *manufacturer_id;	
+	sc_pkcs15_sec_env_info_t **se_infos;
+	sc_pkcs15_record_info_t *record_info;
+	sc_pkcs15_algorithm_info_t **algorithm_infos;
+	char *issuer_id;
+	char *holder_id;
 	char *last_update;
 	char *preferred_language;
-	sc_pkcs15_sec_env_info_t **seInfo;
-	size_t num_seInfo;
-
-	struct sc_supported_algo_info supported_algos[SC_MAX_SUPPORTED_ALGORITHMS];
 } sc_pkcs15_tokeninfo_t;
 
 struct sc_pkcs15_operations   {
Index: libopensc/types.h
===================================================================
--- libopensc/types.h	(revision 4829)
+++ libopensc/types.h	(working copy)
@@ -40,11 +40,6 @@
 #define SC_MAX_PATH_SIZE		16
 #define SC_MAX_PATH_STRING_SIZE		(SC_MAX_PATH_SIZE * 2 + 1)
 
-/* When changing this value, pay attention to the initialization of the ASN1 
- * static variables that use this macro, like, for example, 
- * 'c_asn1_supported_algorithms' in src/libopensc/pkcs15.c 
- */
-#define SC_MAX_SUPPORTED_ALGORITHMS     8
 
 
 struct sc_object_id {
Index: libopensc/asn1.c
===================================================================
--- libopensc/asn1.c	(revision 4829)
+++ libopensc/asn1.c	(working copy)
@@ -1040,6 +1040,27 @@
 	sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sdecoding '%s'\n", depth, depth, "", entry->name);
 
 	switch (entry->type) {
+	case SC_ASN1_SEQUENCE:
+		if (parm != NULL) {
+			assert(len != NULL);
+			if (entry->flags & SC_ASN1_ALLOC) {
+				u8 **buf = (u8 **) parm;
+				*buf = malloc(objlen);
+				if (*buf == NULL) {
+					r = SC_ERROR_OUT_OF_MEMORY;
+					break;
+				}
+				*len = objlen;
+				parm = *buf;
+			} else if (*len >= objlen) {
+				*len = objlen;
+			} else {
+				r = SC_ERROR_BUFFER_TOO_SMALL;
+				break;
+			}
+			memcpy(parm, obj, objlen);
+		}
+		break;
 	case SC_ASN1_STRUCT:
 		if (parm != NULL)
 			r = asn1_decode(ctx, (struct sc_asn1_entry *) parm, obj,
@@ -1092,7 +1113,7 @@
 		break;
 	case SC_ASN1_BIT_FIELD:
 		if (parm != NULL)
-			r = decode_bit_field(obj, objlen, (u8 *) parm, *len);
+			r = decode_bit_field(obj, objlen, (u8 *) parm, sizeof(unsigned int));
 		break;
 	case SC_ASN1_OCTET_STRING:
 		if (parm != NULL) {
@@ -1209,6 +1230,30 @@
 	return 0;
 }
 
+/* Maps TYPE to TAG (if possible) */
+
+static int asn1_foo(int type, int tag)
+{
+	if (tag == 0) {
+		if (type == SC_ASN1_BIT_FIELD || type == SC_ASN1_BIT_STRING_NI) {
+			tag = SC_ASN1_BIT_STRING;
+		} else if (type == SC_ASN1_SEQUENCE) {
+			tag = SC_ASN1_CONS | SC_ASN1_SEQUENCE;
+		} else if (type > 0 && type < 0x1F) {
+			tag = type;
+		} else if (type == SC_ASN1_CHOICE) {
+			tag = 0;
+		} else {
+			tag = -1;
+		}
+	} else if ((type == SC_ASN1_SEQUENCE || type == SC_ASN1_SET || type == SC_ASN1_CHOICE) && 
+			((tag & SC_ASN1_APP) || (tag & SC_ASN1_CTX))) {
+		tag |= SC_ASN1_CONS;
+	}
+
+	return tag;
+}
+
 static int asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1,
 		       const u8 *in, size_t len, const u8 **newp, size_t *len_left,
 		       int choice, int depth)
@@ -1218,6 +1263,8 @@
 	struct sc_asn1_entry *entry = asn1;
 	size_t left = len, objlen;
 
+	assert(asn1 != NULL);
+
 	sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*scalled, left=%u, depth %d%s\n",
 			       	depth, depth, "",
 				left, depth,
@@ -1247,13 +1294,24 @@
 			entry->name, entry->tag, choice? ", CHOICE" : "",
 			(entry->flags & SC_ASN1_OPTIONAL)? ", OPTIONAL": "");
 
-		/* Special case CHOICE has no tag */
-		if (entry->type == SC_ASN1_CHOICE) {
+		/* complete tag */
+		r = asn1_foo(entry->type, entry->tag);
+		if (r < 0)
+			goto decode_ok;
+		entry->tag = r;
+		r = 0;
+
+		/* Special case CHOICE sometimes has no tag */
+		if ((entry->type == SC_ASN1_CHOICE) && (entry->tag == 0)) {
 			r = asn1_decode(ctx,
 				(struct sc_asn1_entry *) entry->parm,
 				p, left, &p, &left, 1, depth + 1);
-			if (r >= 0)
+			if (r >= 0) {
+				entry->flags |= SC_ASN1_PRESENT;
 				r = 0;
+			} else if (entry->flags & SC_ASN1_OPTIONAL || choice) {
+				continue;
+			}
 			goto decode_ok;
 		}
 
@@ -1278,8 +1336,22 @@
 			}
 			SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_ASN1_OBJECT_NOT_FOUND);
 		}
-		r = asn1_decode_entry(ctx, entry, obj, objlen, depth);
+		if (entry->type == SC_ASN1_CHOICE) {
 
+			/* Case with explicit tagging (usualaly of context class).
+			   Tag was present, verified and skipped. Current tag
+			   belongs to choice item. */
+
+			r = asn1_decode(ctx, (struct sc_asn1_entry *) entry->parm,
+				obj, objlen, &obj, &objlen, 1, depth + 1);
+			if (r >= 0) {
+				entry->flags |= SC_ASN1_PRESENT;
+				r = 0;
+			}
+		} else {
+			r = asn1_decode_entry(ctx, entry, obj, objlen, depth);
+		}
+
 decode_ok:
 		if (r)
 			return r;
@@ -1322,6 +1394,13 @@
 
 	callback_func = parm;
 
+	/* complete tag */
+	r = asn1_foo(entry->type, entry->tag);
+	if (r < 0)
+		return r;
+	((struct sc_asn1_entry *) entry)->tag = r;
+	r = 0;
+
 	sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sencoding '%s'%s\n",
 	       	depth, depth, "", entry->name,
 		(entry->flags & SC_ASN1_PRESENT)? "" : " (not present)");
@@ -1353,7 +1432,12 @@
 		}
 		if (choice == NULL)
 			goto no_object;
-		return asn1_encode_entry(ctx, choice, obj, objlen, depth + 1);
+		if (entry->tag == 0)
+			return asn1_encode_entry(ctx, choice, obj, objlen, depth + 1);
+		r = asn1_encode_entry(ctx, choice, &buf, &buflen, depth + 1);
+		if (r < 0)
+			return r;
+		goto no_object;
 	}
 
 	if (entry->type != SC_ASN1_NULL && parm == NULL) {
Index: libopensc/opensc.h
===================================================================
--- libopensc/opensc.h	(revision 4829)
+++ libopensc/opensc.h	(working copy)
@@ -115,14 +115,6 @@
 #define SC_EVENT_READER_DETACHED	0x0008
 #define SC_EVENT_READER_EVENTS		SC_EVENT_READER_ATTACHED|SC_EVENT_READER_DETACHED
 
-struct sc_supported_algo_info {
-	unsigned int reference;
-	unsigned int mechanism;
-	unsigned int operations;
-	struct sc_object_id algo_id;
-	unsigned int algo_ref;
-};
-
 typedef struct sc_security_env {
 	unsigned long flags;
 	int operation;
@@ -132,8 +124,6 @@
 	struct sc_path file_ref;
 	u8 key_ref[8];
 	size_t key_ref_len;
-
-	struct sc_supported_algo_info supported_algos[SC_MAX_SUPPORTED_ALGORITHMS];
 } sc_security_env_t;
 
 struct sc_algorithm_id {
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to