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
[email protected]
From af08131050655c05111cc10548c6e0156351e502 Mon Sep 17 00:00:00 2001
From: Peter Marschall <[email protected]>
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 <[email protected]>
---
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 <[email protected]>
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 <[email protected]>
---
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 <[email protected]>
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 <[email protected]>
---
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
[email protected]
http://www.opensc-project.org/mailman/listinfo/opensc-devel