- created opensc-explorer tool
- increased support for CryptoFlex cards git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@152 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
6778d0b929
commit
269df3a6da
|
@ -165,9 +165,10 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path,
|
|||
{
|
||||
int r, i;
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[MAX_BUFFER_SIZE];
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
const u8 *pathptr = path->value;
|
||||
size_t pathlen = path->len;
|
||||
int locked = 0;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 3);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0);
|
||||
|
@ -182,15 +183,22 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path,
|
|||
if (pathlen != 2 || memcmp(pathptr, "\x3F\x00", 2) != 0) {
|
||||
struct sc_path tmppath;
|
||||
|
||||
locked = 1;
|
||||
r = sc_lock(card);
|
||||
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
|
||||
if (memcmp(pathptr, "\x3F\x00", 2) != 0) {
|
||||
sc_format_path("I3F00", &tmppath);
|
||||
r = mflex_select_file(card, &tmppath, NULL);
|
||||
if (r)
|
||||
sc_unlock(card);
|
||||
SC_TEST_RET(card->ctx, r, "Unable to select Master File (MF)");
|
||||
}
|
||||
while (pathlen > 2) {
|
||||
memcpy(tmppath.value, pathptr, 2);
|
||||
tmppath.len = 2;
|
||||
r = mflex_select_file(card, &tmppath, NULL);
|
||||
if (r)
|
||||
sc_unlock(card);
|
||||
SC_TEST_RET(card->ctx, r, "Unable to select DF");
|
||||
pathptr += 2;
|
||||
pathlen -= 2;
|
||||
|
@ -211,13 +219,21 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path,
|
|||
|
||||
/* No need to get file information, if file is NULL or already
|
||||
* valid. */
|
||||
#if 0
|
||||
if (file == NULL || sc_file_valid(file))
|
||||
#endif
|
||||
if (file == NULL)
|
||||
apdu.resplen = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (locked)
|
||||
sc_unlock(card);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
SC_TEST_RET(card->ctx, r, "Card returned error");
|
||||
#if 0
|
||||
if (file == NULL || sc_file_valid(file))
|
||||
#endif
|
||||
if (file == NULL)
|
||||
return 0;
|
||||
|
||||
if (apdu.resplen < 14)
|
||||
|
@ -235,6 +251,39 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path,
|
|||
return parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file);
|
||||
}
|
||||
|
||||
static int mflex_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
||||
{
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[4];
|
||||
int r;
|
||||
size_t count = 0;
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA8, 0, 0);
|
||||
apdu.cla = 0xF0;
|
||||
apdu.le = 4;
|
||||
apdu.resplen = 4;
|
||||
apdu.resp = rbuf;
|
||||
while (buflen > 2) {
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r)
|
||||
return r;
|
||||
if (apdu.sw1 == 0x6A && apdu.sw2 == 0x82)
|
||||
break;
|
||||
r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
if (r)
|
||||
return r;
|
||||
if (apdu.resplen != 4) {
|
||||
error(card->ctx, "expected 4 bytes, got %d.\n", apdu.resplen);
|
||||
return SC_ERROR_ILLEGAL_RESPONSE;
|
||||
}
|
||||
memcpy(buf, rbuf + 2, 2);
|
||||
buf += 2;
|
||||
count += 2;
|
||||
buflen -= 2;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct sc_card_driver * sc_get_driver(void)
|
||||
{
|
||||
const struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
||||
|
@ -244,6 +293,7 @@ static const struct sc_card_driver * sc_get_driver(void)
|
|||
mflex_ops.init = mflex_init;
|
||||
mflex_ops.finish = mflex_finish;
|
||||
mflex_ops.select_file = mflex_select_file;
|
||||
mflex_ops.list_files = mflex_list_files;
|
||||
|
||||
return &mflex_drv;
|
||||
}
|
||||
|
|
|
@ -506,21 +506,16 @@ int sc_unlock(struct sc_card *card)
|
|||
SC_FUNC_RETURN(card->ctx, 2, r);
|
||||
}
|
||||
|
||||
int sc_list_files(struct sc_card *card, u8 *buf, int buflen)
|
||||
int sc_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
||||
{
|
||||
struct sc_apdu apdu;
|
||||
int r;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0);
|
||||
apdu.resp = buf;
|
||||
apdu.resplen = buflen;
|
||||
apdu.le = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.resplen == 0)
|
||||
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
return apdu.resplen;
|
||||
assert(card != NULL);
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
if (card->ops->list_files == NULL)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
|
||||
r = card->ops->list_files(card, buf, buflen);
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
int sc_create_file(struct sc_card *card, const struct sc_file *file)
|
||||
|
|
|
@ -277,11 +277,17 @@ static int iso7816_select_file(struct sc_card *card,
|
|||
memcpy(&file->path.value, path, pathlen);
|
||||
file->path.len = pathlen;
|
||||
}
|
||||
#if 0
|
||||
if (file == NULL || sc_file_valid(file))
|
||||
#endif
|
||||
if (file == NULL)
|
||||
apdu.resplen = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (file == NULL || sc_file_valid(file)) {
|
||||
#if 0
|
||||
if (file == NULL || sc_file_valid(file))
|
||||
#endif
|
||||
if (file == NULL) {
|
||||
if (apdu.sw1 == 0x61)
|
||||
SC_FUNC_RETURN(card->ctx, 2, 0);
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2));
|
||||
|
@ -421,6 +427,22 @@ static int iso7816_delete_file(struct sc_card *card, const struct sc_path *path)
|
|||
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
}
|
||||
|
||||
static int iso7816_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
||||
{
|
||||
struct sc_apdu apdu;
|
||||
int r;
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0);
|
||||
apdu.resp = buf;
|
||||
apdu.resplen = buflen;
|
||||
apdu.le = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.resplen == 0)
|
||||
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||
return apdu.resplen;
|
||||
}
|
||||
|
||||
static struct sc_card_operations iso_ops = {
|
||||
NULL,
|
||||
};
|
||||
|
@ -449,6 +471,7 @@ const struct sc_card_driver * sc_get_iso7816_driver(void)
|
|||
iso_ops.get_challenge = iso7816_get_challenge;
|
||||
iso_ops.create_file = iso7816_create_file;
|
||||
iso_ops.delete_file = iso7816_delete_file;
|
||||
iso_ops.list_files = iso7816_list_files;
|
||||
}
|
||||
return &iso_driver;
|
||||
}
|
||||
|
|
|
@ -58,14 +58,39 @@ void do_log(struct sc_context *ctx, int facility, const char *file,
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
int use_color(struct sc_context *ctx, FILE *outf)
|
||||
{
|
||||
static char *term = NULL;
|
||||
static const char *terms[] = { "linux", "xterm", "Eterm" };
|
||||
int term_count = sizeof(terms)/sizeof(terms[0]);
|
||||
int do_color = 0;
|
||||
int i;
|
||||
|
||||
if (!ctx->use_std_output)
|
||||
return 0;
|
||||
if (term == NULL) {
|
||||
term = getenv("TERM");
|
||||
if (term == NULL)
|
||||
return 0;
|
||||
}
|
||||
do_color = 0;
|
||||
for (i = 0; i < term_count; i++)
|
||||
if (strcmp(terms[i], term) == 0) {
|
||||
do_color = 1;
|
||||
break;
|
||||
}
|
||||
if (!do_color)
|
||||
return 0;
|
||||
if (!isatty(fileno(outf)))
|
||||
return 0;
|
||||
return do_color;
|
||||
}
|
||||
|
||||
void do_log2(struct sc_context *ctx, int type, const char *file,
|
||||
int line, const char *func, const char *format, va_list args)
|
||||
{
|
||||
FILE *outf = NULL;
|
||||
char buf[1024], *p;
|
||||
static char *term = NULL;
|
||||
const char *terms[] = { "linux", "xterm", "Eterm" };
|
||||
int term_count = sizeof(terms)/sizeof(terms[0]);
|
||||
int left, r;
|
||||
struct timeval tv;
|
||||
|
||||
|
@ -96,23 +121,7 @@ void do_log2(struct sc_context *ctx, int type, const char *file,
|
|||
return;
|
||||
if (ctx->use_std_output) {
|
||||
const char *color_pfx = "", *color_sfx = "";
|
||||
int do_color = 0;
|
||||
int i;
|
||||
if (term == NULL)
|
||||
term = getenv("TERM");
|
||||
if (term != NULL)
|
||||
do_color = 1;
|
||||
if (do_color) {
|
||||
do_color = 0;
|
||||
for (i = 0; i < term_count; i++)
|
||||
if (strcmp(terms[i], term) == 0) {
|
||||
do_color = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (do_color && !isatty(fileno(outf)))
|
||||
do_color = 0;
|
||||
if (do_color) {
|
||||
if (use_color(ctx, outf)) {
|
||||
color_sfx = "\33[0m";
|
||||
switch (type) {
|
||||
case SC_LOG_TYPE_ERROR:
|
||||
|
|
|
@ -293,7 +293,7 @@ struct sc_card_operations {
|
|||
int (*decipher)(struct sc_card *card, const u8 * crgram,
|
||||
size_t crgram_len, u8 * out, size_t outlen);
|
||||
/* compute_signature: Generates a digital signature on the card. Similiar
|
||||
* to the function decipher. */
|
||||
* to the function decipher. */
|
||||
int (*compute_signature)(struct sc_card *card, const u8 * data,
|
||||
size_t data_len, u8 * out, size_t outlen);
|
||||
int (*change_reference_data)(struct sc_card *card, int ref_qualifier,
|
||||
|
@ -308,6 +308,10 @@ struct sc_card_operations {
|
|||
*/
|
||||
int (*create_file)(struct sc_card *card, const struct sc_file *file);
|
||||
int (*delete_file)(struct sc_card *card, const struct sc_path *path);
|
||||
/* list_files: Enumerates all the files in the current DF, and
|
||||
* writes the corresponding file identifiers to <buf>. Returns
|
||||
* the number of bytes stored. */
|
||||
int (*list_files)(struct sc_card *card, u8 *buf, size_t buflen);
|
||||
};
|
||||
|
||||
struct sc_card_driver {
|
||||
|
@ -411,7 +415,7 @@ void sc_format_path(const char *path_in, struct sc_path *path_out);
|
|||
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen);
|
||||
|
||||
/* Possibly only valid on Setec cards */
|
||||
int sc_list_files(struct sc_card *card, u8 * buf, int buflen);
|
||||
int sc_list_files(struct sc_card *card, u8 * buf, size_t buflen);
|
||||
|
||||
const char *sc_strerror(int error);
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
INCLUDES = @CFLAGS_PCSC@ @CFLAGS_OPENSC@
|
||||
LDFLAGS = @LDFLAGS@ @LIBOPENSC@
|
||||
|
||||
bin_PROGRAMS = opensc-tool pkcs15-crypt pkcs15-tool
|
||||
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-crypt pkcs15-tool
|
||||
|
||||
opensc_tool_SOURCES = opensc-tool.c util.c
|
||||
opensc_tool_LDADD = @GETOPTSRC@
|
||||
opensc_explorer_SOURCES = opensc-explorer.c util.c
|
||||
opensc_explorer_LDADD = @GETOPTSRC@
|
||||
pkcs15_tool_SOURCES = pkcs15-tool.c util.c
|
||||
pkcs15_tool_LDADD = @GETOPTSRC@
|
||||
pkcs15_crypt_SOURCES = pkcs15-crypt.c util.c
|
||||
|
|
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* opensc-explorer.c: A shell for accessing SmartCards with libopensc
|
||||
*
|
||||
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <opensc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "util.h"
|
||||
|
||||
struct sc_context *ctx = NULL;
|
||||
struct sc_card *card = NULL;
|
||||
struct sc_file current_file;
|
||||
struct sc_path current_path;
|
||||
|
||||
const struct option options[] = { { NULL } };
|
||||
const char *option_help[] = { NULL };
|
||||
|
||||
const char *cmds[] = {
|
||||
"ls", "cd", "debug", "cat", "info"
|
||||
};
|
||||
const int nr_cmds = sizeof(cmds)/sizeof(cmds[0]);
|
||||
|
||||
int die(int ret)
|
||||
{
|
||||
if (card) {
|
||||
sc_unlock(card);
|
||||
sc_disconnect_card(card);
|
||||
}
|
||||
if (ctx)
|
||||
sc_destroy_context(ctx);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
static int ambiguous_match(const char **table, int nr_entries, const char *cmd)
|
||||
{
|
||||
int matches = 0;
|
||||
int last_match = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_entries; i++) {
|
||||
if (strncasecmp(cmd, table[i], strlen(cmd)) == 0) {
|
||||
matches++;
|
||||
last_match = i;
|
||||
}
|
||||
}
|
||||
if (matches > 1)
|
||||
return -1;
|
||||
if (matches == 0)
|
||||
return -2;
|
||||
return last_match;
|
||||
}
|
||||
|
||||
void check_ret(int r, int op, const char *err, const struct sc_file *file)
|
||||
{
|
||||
fprintf(stderr, "%s: %s\n", err, sc_strerror(r));
|
||||
if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
|
||||
fprintf(stderr, "ACL for operation: %s\n", acl_to_str(file->acl[op]));
|
||||
}
|
||||
|
||||
void print_file(const struct sc_file *file)
|
||||
{
|
||||
const char *st;
|
||||
|
||||
if (file->type == SC_FILE_TYPE_DF)
|
||||
printf("[");
|
||||
else
|
||||
printf(" ");
|
||||
printf("%02X%02X", file->id >> 8, file->id & 0xFF);
|
||||
if (file->type == SC_FILE_TYPE_DF)
|
||||
printf("]");
|
||||
else
|
||||
printf(" ");
|
||||
switch (file->type) {
|
||||
case SC_FILE_TYPE_WORKING_EF:
|
||||
st = "wEF";
|
||||
break;
|
||||
case SC_FILE_TYPE_INTERNAL_EF:
|
||||
st = "iEF";
|
||||
break;
|
||||
case SC_FILE_TYPE_DF:
|
||||
st = "DF";
|
||||
break;
|
||||
default:
|
||||
st = "???";
|
||||
break;
|
||||
}
|
||||
printf("\t%4s", st);
|
||||
printf(" %5d", file->size);
|
||||
if (file->namelen) {
|
||||
printf("\tName: ");
|
||||
print_binary(stdout, file->name, file->namelen);
|
||||
}
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int do_ls()
|
||||
{
|
||||
u8 buf[256], *cur = buf;
|
||||
int r, count;
|
||||
|
||||
r = sc_list_files(card, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", ¤t_file);
|
||||
return -1;
|
||||
}
|
||||
count = r;
|
||||
printf("FileID\tType Size\n");
|
||||
while (count >= 2) {
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
|
||||
memcpy(path.value, cur, 2);
|
||||
path.len = 2;
|
||||
path.type = SC_PATH_TYPE_FILE_ID;
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", ¤t_file);
|
||||
return -1;
|
||||
}
|
||||
cur += 2;
|
||||
count -= 2;
|
||||
print_file(&file);
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent DF: %s\n", sc_strerror(r));
|
||||
die(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_cd(const char *arg)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
char buf[6];
|
||||
int r;
|
||||
|
||||
if (strcmp(arg, "..") == 0) {
|
||||
if (current_path.len < 4) {
|
||||
printf("unable to go up, already in MF.\n");
|
||||
return -1;
|
||||
}
|
||||
path = current_path;
|
||||
path.len -= 2;
|
||||
r = sc_select_file(card, &path, ¤t_file);
|
||||
if (r) {
|
||||
printf("unable to go up: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
current_path = path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strlen(arg) != 4) {
|
||||
printf("Usage: cd <file_id>\n");
|
||||
return -1;
|
||||
}
|
||||
strcpy(buf, "I");
|
||||
strcat(buf, arg);
|
||||
sc_format_path(buf, &path);
|
||||
if (path.len != 2) {
|
||||
printf("Usage: cd <file_id>\n");
|
||||
return -1;
|
||||
}
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select DF", ¤t_file);
|
||||
return -1;
|
||||
}
|
||||
memcpy(current_path.value + current_path.len, path.value, path.len);
|
||||
current_path.len += path.len;
|
||||
current_file = file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int do_cat(const char *arg)
|
||||
{
|
||||
u8 buf[256];
|
||||
int r, error = 0;
|
||||
size_t count = 0;
|
||||
unsigned int idx = 0;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
int not_current = 1;
|
||||
|
||||
if (strlen(arg) == 0) {
|
||||
path = current_path;
|
||||
file = current_file;
|
||||
not_current = 0;
|
||||
} else {
|
||||
if (strlen(arg) != 4) {
|
||||
printf("Usage: cat [file_id]\n");
|
||||
return -1;
|
||||
}
|
||||
strcpy(buf, "I");
|
||||
strcat(buf, arg);
|
||||
sc_format_path(buf, &path);
|
||||
if (path.len != 2) {
|
||||
printf("Usage: cat [file_id]\n");
|
||||
return -1;
|
||||
}
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", ¤t_file);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
count = file.size;
|
||||
while (count) {
|
||||
int c = count > sizeof(buf) ? sizeof(buf) : count;
|
||||
|
||||
r = sc_read_binary(card, idx, buf, c, 0);
|
||||
if (r < 0) {
|
||||
check_ret(r, SC_AC_OP_READ, "read failed", &file);
|
||||
error = 1;
|
||||
goto err;
|
||||
}
|
||||
if (r != c) {
|
||||
printf("expecting %d, got only %d bytes.\n", c, r);
|
||||
error = 1;
|
||||
goto err;
|
||||
}
|
||||
hex_dump_asc(stdout, buf, c, idx);
|
||||
idx += c;
|
||||
count -= c;
|
||||
}
|
||||
err:
|
||||
if (not_current) {
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent file: %s\n", sc_strerror(r));
|
||||
die(1);
|
||||
}
|
||||
}
|
||||
return -error;
|
||||
}
|
||||
|
||||
int do_info(const char *arg)
|
||||
{
|
||||
struct sc_file file;
|
||||
struct sc_path path;
|
||||
int r, i;
|
||||
const char *st;
|
||||
int not_current = 1;
|
||||
|
||||
if (strlen(arg) == 0) {
|
||||
path = current_path;
|
||||
file = current_file;
|
||||
not_current = 0;
|
||||
} else {
|
||||
char buf[6];
|
||||
struct sc_path tmppath;
|
||||
|
||||
if (strlen(arg) != 4) {
|
||||
printf("Usage: info [file_id]\n");
|
||||
return -1;
|
||||
}
|
||||
strcpy(buf, "I");
|
||||
strcat(buf, arg);
|
||||
sc_format_path(buf, &tmppath);
|
||||
if (tmppath.len != 2) {
|
||||
printf("Usage: info [file_id]\n");
|
||||
return -1;
|
||||
}
|
||||
r = sc_select_file(card, &tmppath, &file);
|
||||
if (r) {
|
||||
printf("unable to select file: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
path = current_path;
|
||||
memcpy(path.value + path.len, tmppath.value, 2);
|
||||
path.len += 2;
|
||||
}
|
||||
switch (file.type) {
|
||||
case SC_FILE_TYPE_WORKING_EF:
|
||||
case SC_FILE_TYPE_INTERNAL_EF:
|
||||
st = "Elementary File";
|
||||
break;
|
||||
case SC_FILE_TYPE_DF:
|
||||
st = "Dedicated File";
|
||||
break;
|
||||
default:
|
||||
st = "Unknown File";
|
||||
break;
|
||||
}
|
||||
printf("\n%s ID %04X\n\n", st, file.id);
|
||||
printf("%-15s", "File path:");
|
||||
for (i = 0; i < path.len; i++) {
|
||||
for (i = 0; i < path.len; i++) {
|
||||
if ((i & 1) == 0 && i)
|
||||
printf("/");
|
||||
printf("%02X", path.value[i]);
|
||||
}
|
||||
}
|
||||
printf("\n%-15s%d bytes\n", "File size:", file.size);
|
||||
|
||||
if (file.type == SC_FILE_TYPE_DF) {
|
||||
const char *ops[] = {
|
||||
"SELECT", "LOCK", "DELETE", "CREATE", "REHABILITATE",
|
||||
"INVALIDATE", "LIST FILES"
|
||||
};
|
||||
if (file.namelen) {
|
||||
printf("%-15s", "DF name:");
|
||||
print_binary(stdout, file.name, file.namelen);
|
||||
printf("\n");
|
||||
}
|
||||
for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
|
||||
char buf[80];
|
||||
|
||||
sprintf(buf, "ACL for %s:", ops[i]);
|
||||
printf("%-25s%s\n", buf, acl_to_str(file.acl[i]));
|
||||
}
|
||||
} else {
|
||||
const char *structs[] = {
|
||||
"Unknown", "Transparent", "Linear fixed",
|
||||
"Linear fixed, SIMPLE-TLV", "Linear variable",
|
||||
"Cyclic", "Cyclic, SIMPLE-TLV",
|
||||
};
|
||||
printf("%-15s%s\n", "EF structure:", structs[file.ef_structure]);
|
||||
}
|
||||
printf("\n");
|
||||
if (not_current) {
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent file: %s\n", sc_strerror(r));
|
||||
die(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_cmd(int cmd, const char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (cmd) {
|
||||
case 0:
|
||||
return do_ls();
|
||||
case 1:
|
||||
return do_cd(arg);
|
||||
case 2:
|
||||
if (sscanf(arg, "%d", &i) != 1)
|
||||
return -1;
|
||||
printf("Debug level set to %d\n", i);
|
||||
ctx->debug = i;
|
||||
if (i) {
|
||||
ctx->use_std_output = 1;
|
||||
} else
|
||||
ctx->use_std_output = 0;
|
||||
return 0;
|
||||
case 3:
|
||||
return do_cat(arg);
|
||||
case 4:
|
||||
return do_info(arg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("Supported commands:\n");
|
||||
for (i = 0; i < nr_cmds; i++)
|
||||
printf(" %s\n", cmds[i]);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int r;
|
||||
char line[80], cmd[80], arg[80];
|
||||
|
||||
printf("OpenSC Explorer version %s\n", sc_version);
|
||||
|
||||
r = sc_establish_context(&ctx);
|
||||
if (r) {
|
||||
printf("est ctx failed: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
r = sc_connect_card(ctx, 0, &card);
|
||||
if (r) {
|
||||
printf("connect card failed: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
sc_lock(card);
|
||||
|
||||
sc_format_path("3F00", ¤t_path);
|
||||
r = sc_select_file(card, ¤t_path, ¤t_file);
|
||||
if (r) {
|
||||
printf("unable to select MF: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
while (1) {
|
||||
int i;
|
||||
|
||||
printf("OpenSC [");
|
||||
for (i = 0; i < current_path.len; i++) {
|
||||
if ((i & 1) == 0 && i)
|
||||
printf("/");
|
||||
printf("%02X", current_path.value[i]);
|
||||
}
|
||||
printf("]> ");
|
||||
fflush(stdout);
|
||||
fflush(stdin);
|
||||
if (fgets(line, sizeof(line), stdin) == NULL)
|
||||
break;
|
||||
if (strlen(line) == 0)
|
||||
break;
|
||||
r = sscanf(line, "%s %s", cmd, arg);
|
||||
if (r < 1)
|
||||
continue;
|
||||
if (r == 1)
|
||||
arg[0] = 0;
|
||||
r = ambiguous_match(cmds, nr_cmds, cmd);
|
||||
if (r < 0) {
|
||||
usage();
|
||||
continue;
|
||||
}
|
||||
handle_cmd(r, arg);
|
||||
}
|
||||
die(0);
|
||||
|
||||
return 0; /* not reached */
|
||||
}
|
|
@ -97,32 +97,6 @@ int list_drivers(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char * print_acl(unsigned int acl)
|
||||
{
|
||||
static char line[80];
|
||||
|
||||
if (acl == SC_AC_UNKNOWN)
|
||||
return "UNKN";
|
||||
if (acl == SC_AC_NEVER)
|
||||
return "NEVR";
|
||||
if (acl == SC_AC_NONE)
|
||||
return "NONE";
|
||||
line[0] = 0;
|
||||
if (acl & SC_AC_CHV1)
|
||||
strcat(line, "CHV1 ");
|
||||
if (acl & SC_AC_CHV2)
|
||||
strcat(line, "CHV2 ");
|
||||
if (acl & SC_AC_TERM)
|
||||
strcat(line, "TERM ");
|
||||
if (acl & SC_AC_PRO)
|
||||
strcat(line, "PROT ");
|
||||
if (acl & SC_AC_AUT)
|
||||
strcat(line, "AUTH ");
|
||||
|
||||
line[strlen(line)-1] = 0; /* get rid of trailing space */
|
||||
return line;
|
||||
}
|
||||
|
||||
int print_file(struct sc_card *card, const struct sc_file *file, const struct sc_path *path, int depth)
|
||||
{
|
||||
int r;
|
||||
|
@ -174,10 +148,10 @@ int print_file(struct sc_card *card, const struct sc_file *file, const struct sc
|
|||
printf(" ");
|
||||
if (file->type == SC_FILE_TYPE_DF)
|
||||
for (r = 0; r < sizeof(ac_ops_df)/sizeof(ac_ops_df[0]); r++)
|
||||
printf("%s[%s] ", ac_ops_df[r], print_acl(file->acl[r]));
|
||||
printf("%s[%s] ", ac_ops_df[r], acl_to_str(file->acl[r]));
|
||||
else
|
||||
for (r = 0; r < sizeof(ac_ops_ef)/sizeof(ac_ops_ef[0]); r++)
|
||||
printf("%s[%s] ", ac_ops_ef[r], print_acl(file->acl[r]));
|
||||
printf("%s[%s] ", ac_ops_ef[r], acl_to_str(file->acl[r]));
|
||||
|
||||
if (file->sec_attr_len) {
|
||||
printf("sec: ");
|
||||
|
@ -197,17 +171,17 @@ int print_file(struct sc_card *card, const struct sc_file *file, const struct sc
|
|||
hex_dump(stdout, file->prop_attr, file->prop_attr_len);
|
||||
}
|
||||
printf("\n\n");
|
||||
#if 0
|
||||
#if 1
|
||||
if (file->type != SC_FILE_TYPE_DF) {
|
||||
u8 buf[2048];
|
||||
if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
|
||||
r = sc_read_binary(card, 0, buf, file->size, 0);
|
||||
if (r > 0)
|
||||
hex_dump_asc(stdout, buf, r);
|
||||
hex_dump_asc(stdout, buf, r, 0);
|
||||
} else {
|
||||
r = sc_read_record(card, 0, buf, file->size, 0);
|
||||
if (r > 0)
|
||||
hex_dump_asc(stdout, buf, r);
|
||||
hex_dump_asc(stdout, buf, r, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -220,6 +194,7 @@ int enum_dir(struct sc_path path, int depth)
|
|||
int r;
|
||||
u8 files[MAX_BUFFER_SIZE];
|
||||
|
||||
file.magic = 0; /* make sure the file is invalid */
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
fprintf(stderr, "SELECT FILE failed: %s\n", sc_strerror(r));
|
||||
|
@ -329,7 +304,7 @@ int send_apdu(void)
|
|||
printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2,
|
||||
apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
hex_dump_asc(stdout, apdu.resp, apdu.resplen);
|
||||
hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -31,14 +31,18 @@ void hex_dump(FILE *f, const u8 *in, int len)
|
|||
fprintf(f, "%02X ", in[i]);
|
||||
}
|
||||
|
||||
void hex_dump_asc(FILE *f, const u8 *in, size_t count)
|
||||
void hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr)
|
||||
{
|
||||
int lines = 0;
|
||||
|
||||
while (count) {
|
||||
char ascbuf[17];
|
||||
int i;
|
||||
|
||||
|
||||
if (addr >= 0) {
|
||||
fprintf(f, "%08X: ", addr);
|
||||
addr += 16;
|
||||
}
|
||||
for (i = 0; i < count && i < 16; i++) {
|
||||
fprintf(f, "%02X ", *in);
|
||||
if (isprint(*in))
|
||||
|
@ -87,3 +91,28 @@ void print_usage_and_die(const char *pgmname)
|
|||
exit(2);
|
||||
}
|
||||
|
||||
const char * acl_to_str(unsigned int acl)
|
||||
{
|
||||
static char line[80];
|
||||
|
||||
if (acl == SC_AC_UNKNOWN)
|
||||
return "UNKN";
|
||||
if (acl == SC_AC_NEVER)
|
||||
return "NEVR";
|
||||
if (acl == SC_AC_NONE)
|
||||
return "NONE";
|
||||
line[0] = 0;
|
||||
if (acl & SC_AC_CHV1)
|
||||
strcat(line, "CHV1 ");
|
||||
if (acl & SC_AC_CHV2)
|
||||
strcat(line, "CHV2 ");
|
||||
if (acl & SC_AC_TERM)
|
||||
strcat(line, "TERM ");
|
||||
if (acl & SC_AC_PRO)
|
||||
strcat(line, "PROT ");
|
||||
if (acl & SC_AC_AUT)
|
||||
strcat(line, "AUTH ");
|
||||
|
||||
line[strlen(line)-1] = 0; /* get rid of trailing space */
|
||||
return line;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ extern const char *option_help[];
|
|||
|
||||
void print_binary(FILE *f, const u8 *buf, int count);
|
||||
void hex_dump(FILE *f, const u8 *in, int len);
|
||||
void hex_dump_asc(FILE *f, const u8 *in, size_t count);
|
||||
void hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr);
|
||||
void print_usage_and_die(const char *pgmname);
|
||||
const char * acl_to_str(unsigned int acl);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue