Hi,

please find attached 3 patches to opensc-tool and opensc-explorer:

* [PATCH 1/3] opensc-tool: make list_algorithms() table driven
  Use easily extensible tables instead of explicit coding to display
  algorithm names and options in list_algorithms.

  Leverage the new tables to add more RSA hashes

* [PATCH 2/3] opensc-tool: convert print_file() to using tables
  Use ID<->name tables in print_file() innstead of arrays of strings where
  the index was treated like some "magic" constant. With the new mapping
  tables, the meaning is obvious.

  While on it, fix a bug with ac_ops_df[]: before the conversion, it was a list
  of pointers to strings but was in one case treated like it was a mapping
  table.
  With the conversion to a mapping table, and the adaption of other code parts
  this bug got fixed "automagically" ;-)

* [PATCH 3/3] opensc-{explorer,tool}: allow sending extended APDUs
  In do_apdu() resp. send_apdu/(, flexibilize parsing the APDU string passed
  so that extended APDUs are accepted a valid APDUs too.

  While at it, fix a bug where more data than available would have been copied,
  potentially leading to a SIGSEGV.


Please consider including them into trunk, as they
a) fix potential bugs
b) help development: send extedned APDUs
c) allow tools to give more complete information

Thanks in advance 
PEter
-- 
Peter Marschall
pe...@adpm.de
From af08131050655c05111cc10548c6e0156351e502 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sat, 16 Apr 2011 14:28:03 +0200
Subject: [PATCH 1/3] opensc-tool: make list_algorithms() table driven

Use easily extensible tables instead of explicit coding to display
algorithm names and options in list_algorithms.

Leverage the new tables to add more RSA hashes.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/tools/opensc-tool.c |  122 ++++++++++++++++++++++++++---------------------
 1 files changed, 67 insertions(+), 55 deletions(-)

diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c
index 529e842..5857228 100644
--- a/src/tools/opensc-tool.c
+++ b/src/tools/opensc-tool.c
@@ -34,6 +34,12 @@
 #include "libopensc/cardctl.h"
 #include "util.h"
 
+/* type for associations of IDs to names */
+typedef struct _id2str {
+	unsigned int id;
+	const char *str;
+} id2str_t;
+
 static const char *app_name = "opensc-tool";
 
 static int	opt_wait = 0;
@@ -556,81 +562,87 @@ static void print_serial(sc_card_t *in_card)
 static int list_algorithms(void) 
 {
 	int i; 
-	const char *aname; 
+	const char *aname = "unknown";
+
+	const id2str_t alg_type_names[] = {
+		{ SC_ALGORITHM_RSA,       "rsa"    },
+		{ SC_ALGORITHM_DSA,       "ec"     },
+		{ SC_ALGORITHM_DES,       "des"    },
+		{ SC_ALGORITHM_3DES,      "3des"   },
+		{ SC_ALGORITHM_MD5,       "md5"    },
+		{ SC_ALGORITHM_SHA1,      "sha1"   },
+		{ SC_ALGORITHM_PBKDF2,    "pbkdf2" },
+		{ SC_ALGORITHM_PBES2,     "pbes2"  },
+		{ SC_ALGORITHM_GOSTR3410, "gost"   },
+		{ 0, NULL }
+	};
+	const id2str_t alg_flag_names[] = {
+		{ SC_ALGORITHM_ONBOARD_KEY_GEN, "onboard key generation" },
+		{ SC_ALGORITHM_NEED_USAGE,      "needs usage"            },
+		{ 0, NULL }
+	};
+	const id2str_t rsa_flag_names[] = {
+	//	{ SC_ALGORITHM_RSA_PAD_NONE,       "none"      },
+		{ SC_ALGORITHM_RSA_PAD_PKCS1,      "pkcs1"     },
+		{ SC_ALGORITHM_RSA_PAD_ANSI,       "ansi"      },
+		{ SC_ALGORITHM_RSA_PAD_ISO9796,    "iso9796"   },
+	//	{ SC_ALGORITHM_RSA_HASH_NONE,      "none"      },
+		{ SC_ALGORITHM_RSA_HASH_SHA1,      "sha1"      },
+		{ SC_ALGORITHM_RSA_HASH_MD5,       "MD5"       },
+		{ SC_ALGORITHM_RSA_HASH_MD5_SHA1,  "md5-sha1"  },
+		{ SC_ALGORITHM_RSA_HASH_RIPEMD160, "ripemd160" },
+		{ SC_ALGORITHM_RSA_HASH_SHA256,    "sha256"    },
+		{ SC_ALGORITHM_RSA_HASH_SHA384,    "sha384"    },
+		{ SC_ALGORITHM_RSA_HASH_SHA512,    "sha512"    },
+		{ SC_ALGORITHM_RSA_HASH_SHA224,    "sha224"    },
+		{ 0, NULL }
+	};
 
 	if (verbose)
 		printf("Card supports %d algorithm(s)\n\n",card->algorithm_count); 
   
 	for (i=0; i < card->algorithm_count; i++) { 
-		switch (card->algorithms[i].algorithm) { 
-		case SC_ALGORITHM_RSA: 
-			aname = "rsa"; 
-			break; 
-		case SC_ALGORITHM_DSA: 
-			aname = "dsa"; 
-			aname = "ec"; 
-			break; 
-		case SC_ALGORITHM_DES: 
-			aname = "des"; 
-			break; 
-		case SC_ALGORITHM_3DES: 
-			aname = "3des"; 
-			break; 
-		case SC_ALGORITHM_MD5: 
-			aname = "md5"; 
-			break; 
-		case SC_ALGORITHM_SHA1: 
-			aname = "sha1"; 
-			break; 
-		case SC_ALGORITHM_PBKDF2: 
-			aname = "pbkdf2"; 
-			break; 
-		case SC_ALGORITHM_PBES2: 
-			aname = "pbes2"; 
-			break;
-		case SC_ALGORITHM_GOSTR3410:
-			aname = "gost";
-			break;
-		default: 
-			aname = "unknown"; 
-			break; 
-		} 
-  
+		int j;
+
+		/* find algorithm name */
+		for (j = 0; alg_type_names[j].str != NULL; j++) {
+			if (card->algorithms[i].algorithm == alg_type_names[j].id) {
+				aname = alg_type_names[j].str;
+				break;
+			}
+		}
+
 		printf("Algorithm: %s\n", aname); 
 		printf("Key length: %d\n", card->algorithms[i].key_length); 
 		printf("Flags:"); 
-		if (card->algorithms[i].flags & SC_ALGORITHM_ONBOARD_KEY_GEN) 
-			printf(" onboard key generation"); 
-		if (card->algorithms[i].flags & SC_ALGORITHM_NEED_USAGE) 
-			printf(" needs usage"); 
+
+		/* print general flags */
+		for (j = 0; alg_flag_names[j].str != NULL; j++)
+			if (card->algorithms[i].flags & alg_flag_names[j].id)
+				printf(" %s", alg_flag_names[j].str);
+
+		/* print RSA spcific flags */
 		if ( card->algorithms[i].algorithm == SC_ALGORITHM_RSA) { 
 			int padding = card->algorithms[i].flags 
 					& SC_ALGORITHM_RSA_PADS; 
 			int hashes =  card->algorithms[i].flags 
 					& SC_ALGORITHM_RSA_HASHES; 
 					 
+			/* print RSA padding flags */
 			printf(" padding ("); 
+			for (j = 0; rsa_flag_names[j].str != NULL; j++)
+				if (padding & rsa_flag_names[j].id)
+					printf(" %s", rsa_flag_names[j].str);
 			if (padding == SC_ALGORITHM_RSA_PAD_NONE)  
 				printf(" none"); 
-			if (padding & SC_ALGORITHM_RSA_PAD_PKCS1) 
-				printf(" pkcs1"); 
-			if (padding & SC_ALGORITHM_RSA_PAD_ANSI) 
-				printf(" ansi"); 
-			if (padding & SC_ALGORITHM_RSA_PAD_ISO9796) 
-				printf(" iso9796"); 
-  
 			printf(" ) "); 
+			/* print RSA hash flags */
 			printf("hashes ("); 
-			if (hashes & SC_ALGORITHM_RSA_HASH_NONE) 
+			for (j = 0; rsa_flag_names[j].str != NULL; j++)
+				if (hashes & rsa_flag_names[j].id)
+					printf(" %s", rsa_flag_names[j].str);
+			if (hashes == SC_ALGORITHM_RSA_HASH_NONE) 
 				printf(" none"); 
-			if (hashes & SC_ALGORITHM_RSA_HASH_SHA1) 
-				printf(" sha1"); 
-			if (hashes & SC_ALGORITHM_RSA_HASH_MD5) 
-				printf(" MD5"); 
-			if (hashes & SC_ALGORITHM_RSA_HASH_MD5_SHA1) 
-				printf(" md5-sha1"); 
-			if (hashes & SC_ALGORITHM_RSA_HASH_RIPEMD160) 
-				printf(" ripemd160"); 
 			printf(" )"); 
 		} 
 		printf("\n"); 
-- 
1.7.4.1

From 63ca17be3ca86f906f7cbd3bc79ba2e68383da55 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sat, 16 Apr 2011 15:20:36 +0200
Subject: [PATCH 2/3] opensc-tool: convert print_file() to using tables

Use ID<->name tables in print_file() innstead of arrays of strings where
the index was treated like some "magic" constant. With the new mapping tables,
the meaning is obvious.

While on it, fix a bug with ac_ops_df[]: before the conversion, it was a list
of pointers to strings but was in one case treated like it was a mapping table.
With the conversion to a mapping table, and the adaption of other code parts
this bug got fixed "automagically" ;-)

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/tools/opensc-tool.c |   74 +++++++++++++++++++++++++++++------------------
 1 files changed, 46 insertions(+), 28 deletions(-)

diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c
index 5857228..d71d07a 100644
--- a/src/tools/opensc-tool.c
+++ b/src/tools/opensc-tool.c
@@ -315,21 +315,6 @@ static int print_file(sc_card_t *in_card, const sc_file_t *file,
 {
 	int r;
 	const char *tmps;
-	const char *ac_ops_df[] = {
-		"select", "lock", "delete", "create", "rehab", "inval",
-		"list"
-	};
-	struct ac_op_str {
-		unsigned int ac_op;
-		const char *str;
-	} const ac_ops_ef[] = {
-		{ SC_AC_OP_READ, "read" },
-		{ SC_AC_OP_UPDATE, "update" },
-		{ SC_AC_OP_ERASE, "erase" },
-		{ SC_AC_OP_WRITE, "write" },
-		{ SC_AC_OP_REHABILITATE, "rehab" },
-		{ SC_AC_OP_INVALIDATE, "inval" }
-	};
 
 	for (r = 0; r < depth; r++)
 		printf("  ");
@@ -355,25 +340,58 @@ static int print_file(sc_card_t *in_card, const sc_file_t *file,
 	}
 	printf("type: %-3s, ", tmps);
 	if (file->type != SC_FILE_TYPE_DF) {
-		const char *structs[] = {
-			"unknown", "transpnt", "linrfix", "linrfix(TLV)",
-			"linvar", "linvar(TLV)", "lincyc", "lincyc(TLV)"
+		const id2str_t ef_type_name[] = {
+			{ SC_FILE_EF_TRANSPARENT,         "transpnt"     },
+			{ SC_FILE_EF_LINEAR_FIXED,        "linrfix"      },
+			{ SC_FILE_EF_LINEAR_FIXED_TLV,    "linrfix(TLV)" },
+			{ SC_FILE_EF_LINEAR_VARIABLE,     "linvar"       },
+			{ SC_FILE_EF_LINEAR_VARIABLE_TLV, "linvar(TLV)"  },
+			{ SC_FILE_EF_CYCLIC,              "lincyc"       },
+			{ SC_FILE_EF_CYCLIC_TLV,          "lincyc(TLV)"  },
+			{ 0, NULL }
 		};
-		int ef_type = file->ef_structure;
-		if (ef_type < 0 || ef_type > 7)
-			ef_type = 0;	/* invalid or unknow ef type */
-		printf("ef structure: %s, ", structs[ef_type]);
+		const char *ef_type = "unknown";
+
+		for (r = 0; ef_type_name[r].str != NULL; r++)
+			if (file->ef_structure == ef_type_name[r].id)
+				ef_type = ef_type_name[r].str;
+
+		printf("ef structure: %s, ", ef_type);
 	}
 	printf("size: %lu\n", (unsigned long) file->size);
 	for (r = 0; r < depth; r++)
 		printf("  ");
-	if (file->type == SC_FILE_TYPE_DF)
-		for (r = 0; r < (int) (sizeof(ac_ops_df)/sizeof(ac_ops_df[0])); r++)
-			printf("%s[%s] ", ac_ops_df[r], util_acl_to_str(sc_file_get_acl_entry(file, r)));
-	else
-		for (r = 0; r < (int) (sizeof(ac_ops_ef)/sizeof(ac_ops_ef[0])); r++)
+	if (file->type == SC_FILE_TYPE_DF) {
+		const id2str_t ac_ops_df[] = {
+			{ SC_AC_OP_SELECT,       "select" },
+			{ SC_AC_OP_LOCK,         "lock"   },
+			{ SC_AC_OP_DELETE,       "delete" },
+			{ SC_AC_OP_CREATE,       "create" },
+			{ SC_AC_OP_REHABILITATE, "rehab"  },
+			{ SC_AC_OP_INVALIDATE,   "inval"  },
+			{ SC_AC_OP_LIST_FILES,   "list"   },
+			{ 0, NULL }
+		};
+
+		for (r = 0; ac_ops_df[r].str != NULL; r++)
+			printf("%s[%s] ", ac_ops_df[r].str,
+					 util_acl_to_str(sc_file_get_acl_entry(file, ac_ops_df[r].id)));
+	}
+	else {
+		const id2str_t ac_ops_ef[] = {
+			{ SC_AC_OP_READ,         "read"   },
+			{ SC_AC_OP_UPDATE,       "update" },
+			{ SC_AC_OP_ERASE,        "erase"  },
+			{ SC_AC_OP_WRITE,        "write"  },
+			{ SC_AC_OP_REHABILITATE, "rehab"  },
+			{ SC_AC_OP_INVALIDATE,   "inval"  },
+			{ 0, NULL }
+		};
+
+		for (r = 0; ac_ops_ef[r].str != NULL; r++)
 			printf("%s[%s] ", ac_ops_ef[r].str,
-					util_acl_to_str(sc_file_get_acl_entry(file, ac_ops_ef[r].ac_op)));
+					util_acl_to_str(sc_file_get_acl_entry(file, ac_ops_ef[r].id)));
+	}
 
 	if (file->sec_attr_len) {
 		printf("sec: ");
-- 
1.7.4.1

From 71657809317604f3e9b05fe8b8b0fbfbf86b0f98 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sun, 17 Apr 2011 11:00:49 +0200
Subject: [PATCH 3/3] opensc-{explorer,tool}: allow sending extended APDUs

In do_apdu() resp send_apdu/(, flexibilize parsing the APDU string passed
so that extended APDUs are accepted a valid APDUs too.

While at it, fix a bug where more data than available would have been copied,
potentially leading to a SIGSEGV.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/tools/opensc-explorer.c |   93 +++++++++++++++++++++++++++--------------
 src/tools/opensc-tool.c     |   96 +++++++++++++++++++++++++++++--------------
 2 files changed, 127 insertions(+), 62 deletions(-)

diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c
index b5ab2b5..02fc65a 100644
--- a/src/tools/opensc-explorer.c
+++ b/src/tools/opensc-explorer.c
@@ -1304,6 +1304,7 @@ static int do_apdu(int argc, char **argv)
 	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
 	u8 *p;
 	size_t len, len0, r, ii;
+	int cse = 0;
 
 	if (argc < 1) {
 		puts("Usage: apdu [apdu:hex:codes:...]");
@@ -1329,41 +1330,71 @@ static int do_apdu(int argc, char **argv)
 	apdu.p1 = *p++;
 	apdu.p2 = *p++;
 	len -= 4;
-	if (len > 1) {
-		apdu.lc = *p++;
-		len--;
-		memcpy(sbuf, p, apdu.lc);
-		apdu.data = sbuf;
-		apdu.datalen = apdu.lc;
-		if (len < apdu.lc) {
-			printf("APDU too short (need %lu bytes)\n",
-				(unsigned long) apdu.lc - len);
-			return 1;
+
+	if (len == 0) {
+		apdu.cse = SC_APDU_CASE_1;
+	}
+	else {
+		size_t size = 0;
+
+		if ((*p == 0) && (len >= 3)) {
+			cse |= SC_APDU_EXT;
+			p++;
+			size = (*p++) << 8;
+			size += *p++;
+			len -= 3;
 		}
-		len -= apdu.lc;
-		p += apdu.lc;
-		if (len) {
-			apdu.le = *p++;
-			if (apdu.le == 0)
-				apdu.le = 256;
+		else {
+			size = *p++;
 			len--;
-			apdu.cse = SC_APDU_CASE_4_SHORT;
-		} else {
-			apdu.cse = SC_APDU_CASE_3_SHORT;
 		}
-		if (len) {
-			printf("APDU too long (%lu bytes extra)\n",
-				(unsigned long) len);
-			return 1;
+		if (len == 0) {
+			apdu.le = (size == 0) ? 256 : size;
+			if ((apdu.le == 0) && (cse & SC_APDU_EXT))
+				apdu.le <<= 8;
+			apdu.cse = SC_APDU_CASE_2_SHORT | cse;
+		}
+		else {
+			apdu.lc = size;
+			if (len < apdu.lc) {
+				printf("APDU too short (need %lu bytes)\n",
+					(unsigned long) apdu.lc - len);
+				return 1;
+			}
+			memcpy(sbuf, p, apdu.lc);
+			apdu.data = sbuf;
+			apdu.datalen = apdu.lc;
+			len -= apdu.lc;
+			p += apdu.lc;
+			if (len == 0) {
+				apdu.cse = SC_APDU_CASE_3_SHORT | cse;
+			}
+			else {
+				apdu.le = 0;
+				if (cse & SC_APDU_EXT) {
+					if (len < 2) {
+						printf("APDU too short (need %lu bytes)\n",
+							(unsigned long) apdu.lc - len);
+						return 1;
+					}
+					size = (*p++) << 8;
+					size += *p++;
+					len -= 2;
+					apdu.le = (size == 0) ? 65536 : size;
+				}
+				else {
+					size = *p++;
+					len--;
+					apdu.le = (size == 0) ? 256 : size;
+				}
+				apdu.cse = SC_APDU_CASE_4_SHORT | cse;
+				if (len) {
+					printf("APDU too long (%lu bytes extra)\n",
+						(unsigned long) len);
+					return 1;
+				}
+			}
 		}
-	} else if (len == 1) {
-		apdu.le = *p++;
-		if (apdu.le == 0)
-			apdu.le = 256;
-		len--;
-		apdu.cse = SC_APDU_CASE_2_SHORT;
-	} else {
-		apdu.cse = SC_APDU_CASE_1;
 	}
 	apdu.resp = rbuf;
 	apdu.resplen = sizeof(rbuf);
diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c
index d71d07a..f209ebf 100644
--- a/src/tools/opensc-tool.c
+++ b/src/tools/opensc-tool.c
@@ -496,6 +496,7 @@ static int send_apdu(void)
 	  rbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
 	size_t len, len0, r;
 	int c;
+	int cse = 0;
 
 	for (c = 0; c < opt_apdu_count; c++) {
 		len0 = sizeof(buf);
@@ -514,40 +515,73 @@ static int send_apdu(void)
 		apdu.resp = rbuf;
 		apdu.resplen = sizeof(rbuf);
 		len -= 4;
-		if (len > 1) {
-			apdu.lc = *p++;
-			len--;
-			memcpy(sbuf, p, apdu.lc);
-			apdu.data = sbuf;
-			apdu.datalen = apdu.lc;
-			if (len < apdu.lc) {
-				fprintf(stderr, "APDU too short (need %lu bytes).\n",
-					(unsigned long) apdu.lc-len);
-				return 2;
+
+		if (len == 0) {
+			apdu.cse = SC_APDU_CASE_1;
+		}
+		else {
+			size_t size = 0;
+
+			if ((*p == 0) && (len >= 3)) {
+				cse |= SC_APDU_EXT;
+				p++;
+				size = (*p++) << 8;
+				size += *p++;
+				len -= 3;
 			}
-			len -= apdu.lc;
-			p   += apdu.lc;
-			if (len) {
-				apdu.le = *p++;
-				if (apdu.le == 0)
-					apdu.le = 256;
+			else {
+				size = *p++;
 				len--;
-				apdu.cse = SC_APDU_CASE_4_SHORT;
-			} else
-				apdu.cse = SC_APDU_CASE_3_SHORT;
-			if (len) {
-				fprintf(stderr, "APDU too long (%lu bytes extra).\n",
-					(unsigned long) len);
-				return 2;
 			}
-		} else if (len == 1) {
-			apdu.le = *p++;
-			if (apdu.le == 0)
-				apdu.le = 256;
-			len--;
-			apdu.cse = SC_APDU_CASE_2_SHORT;
-		} else
-			apdu.cse = SC_APDU_CASE_1;
+			if (len == 0) {
+				apdu.le = (size == 0) ? 256 : size;
+				if ((apdu.le == 0) && (cse & SC_APDU_EXT))
+					apdu.le <<= 8;
+				apdu.cse = SC_APDU_CASE_2_SHORT | cse;
+			}
+			else {
+				apdu.lc = size;
+				if (len < apdu.lc) {
+					printf("APDU too short (need %lu bytes)\n",
+						(unsigned long) apdu.lc - len);
+					return 1;
+				}
+				memcpy(sbuf, p, apdu.lc);
+				apdu.data = sbuf;
+				apdu.datalen = apdu.lc;
+				len -= apdu.lc;
+				p += apdu.lc;
+				if (len == 0) {
+					apdu.cse = SC_APDU_CASE_3_SHORT | cse;
+				}
+				else {
+					apdu.le = 0;
+					if (cse & SC_APDU_EXT) {
+						if (len < 2) {
+							printf("APDU too short (need %lu bytes)\n",
+								(unsigned long) apdu.lc - len);
+							return 1;
+						}
+						size = (*p++) << 8;
+						size += *p++;
+						len -= 2;
+						apdu.le = (size == 0) ? 65536 : size;
+					}
+					else {
+						size = *p++;
+						len--;
+						apdu.le = (size == 0) ? 256 : size;
+					}
+					apdu.cse = SC_APDU_CASE_4_SHORT | cse;
+					if (len) {
+						printf("APDU too long (%lu bytes extra)\n",
+							(unsigned long) len);
+						return 1;
+					}
+				}
+			}
+		}
+
 		printf("Sending: ");
 		for (r = 0; r < len0; r++)
 			printf("%02X ", buf[r]);
-- 
1.7.4.1

_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to