2002-01-09 01:03:10 +00:00
|
|
|
/*
|
2005-06-16 19:35:31 +00:00
|
|
|
* opensc-explorer.c: A shell for accessing smart cards with libopensc
|
2002-01-09 01:03:10 +00:00
|
|
|
*
|
2006-12-19 21:35:42 +00:00
|
|
|
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
2002-01-09 01:03:10 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2004-06-24 17:25:23 +00:00
|
|
|
#include <ctype.h>
|
2002-01-09 01:03:10 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_READLINE
|
2002-02-10 18:04:03 +00:00
|
|
|
#include <readline/readline.h>
|
2002-03-15 10:40:35 +00:00
|
|
|
#include <readline/history.h>
|
2002-02-10 18:04:03 +00:00
|
|
|
#endif
|
2010-03-04 08:14:36 +00:00
|
|
|
|
|
|
|
#include "libopensc/opensc.h"
|
|
|
|
#include "libopensc/asn1.h"
|
|
|
|
#include "libopensc/cardctl.h"
|
2002-01-09 01:03:10 +00:00
|
|
|
#include "util.h"
|
|
|
|
|
2002-03-15 10:40:35 +00:00
|
|
|
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
|
|
|
|
2007-06-29 13:19:19 +00:00
|
|
|
static const char *app_name = "opensc-explorer";
|
2002-03-24 14:12:38 +00:00
|
|
|
|
2010-01-24 15:29:47 +00:00
|
|
|
static int opt_wait = 0, verbose = 0;
|
2007-06-21 12:01:39 +00:00
|
|
|
static const char *opt_driver = NULL;
|
2010-01-24 15:29:47 +00:00
|
|
|
static const char *opt_reader = NULL;
|
2010-08-18 13:42:26 +00:00
|
|
|
static const char *opt_startfile = NULL;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
2007-06-21 12:01:39 +00:00
|
|
|
static sc_file_t *current_file = NULL;
|
|
|
|
static sc_path_t current_path;
|
|
|
|
static sc_context_t *ctx = NULL;
|
|
|
|
static sc_card_t *card = NULL;
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2007-06-29 13:19:19 +00:00
|
|
|
static const struct option options[] = {
|
2007-06-21 12:01:39 +00:00
|
|
|
{ "reader", 1, NULL, 'r' },
|
|
|
|
{ "card-driver", 1, NULL, 'c' },
|
2010-08-20 22:51:39 +00:00
|
|
|
{ "mf", 1, NULL, 'm' },
|
2010-05-11 14:30:15 +00:00
|
|
|
{ "wait", 0, NULL, 'w' },
|
2007-06-21 12:01:39 +00:00
|
|
|
{ "verbose", 0, NULL, 'v' },
|
|
|
|
{ NULL, 0, NULL, 0 }
|
2002-01-20 21:20:09 +00:00
|
|
|
};
|
2007-06-29 13:19:19 +00:00
|
|
|
static const char *option_help[] = {
|
2002-01-20 21:20:09 +00:00
|
|
|
"Uses reader number <arg> [0]",
|
2002-02-11 15:55:34 +00:00
|
|
|
"Forces the use of driver <arg> [auto-detect]",
|
2010-08-20 22:51:39 +00:00
|
|
|
"Selects path <arg> on start-up, or none if empty [3F00]",
|
2003-01-03 17:07:56 +00:00
|
|
|
"Wait for card insertion",
|
2004-06-13 20:13:12 +00:00
|
|
|
"Verbose operation. Use several times to enable debug output.",
|
2002-01-20 21:20:09 +00:00
|
|
|
};
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2006-10-30 18:51:48 +00:00
|
|
|
static size_t hex2binary(u8 *out, size_t outlen, const char *in);
|
|
|
|
|
2002-02-21 18:53:23 +00:00
|
|
|
struct command {
|
|
|
|
const char * name;
|
2002-03-15 10:40:35 +00:00
|
|
|
int (*func)(int, char **);
|
2002-02-21 18:53:23 +00:00
|
|
|
const char * help;
|
2002-01-09 01:03:10 +00:00
|
|
|
};
|
2002-01-10 23:02:48 +00:00
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static void die(int ret)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
2002-02-20 09:56:47 +00:00
|
|
|
if (current_file != NULL)
|
|
|
|
sc_file_free(current_file);
|
2002-01-09 01:03:10 +00:00
|
|
|
if (card) {
|
|
|
|
sc_unlock(card);
|
2010-01-24 15:29:47 +00:00
|
|
|
sc_disconnect_card(card);
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
if (ctx)
|
2002-03-24 14:12:38 +00:00
|
|
|
sc_release_context(ctx);
|
2002-01-09 01:03:10 +00:00
|
|
|
exit(ret);
|
|
|
|
}
|
|
|
|
|
2010-11-06 16:53:11 +00:00
|
|
|
static void select_current_path_or_die(void)
|
2010-08-20 22:51:42 +00:00
|
|
|
{
|
|
|
|
if (current_path.type || current_path.len) {
|
|
|
|
int r = sc_select_file(card, ¤t_path, NULL);
|
|
|
|
if (r) {
|
|
|
|
printf("unable to select parent DF: %s\n", sc_strerror(r));
|
|
|
|
die(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-21 18:53:23 +00:00
|
|
|
static struct command *
|
|
|
|
ambiguous_match(struct command *table, const char *cmd)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
2002-02-21 18:53:23 +00:00
|
|
|
struct command *last_match = NULL;
|
2002-01-09 01:03:10 +00:00
|
|
|
int matches = 0;
|
|
|
|
|
2002-02-21 18:53:23 +00:00
|
|
|
for (; table->name; table++) {
|
2005-02-11 20:09:34 +00:00
|
|
|
if (strncasecmp(cmd, table->name, strlen(cmd)) == 0) {
|
2002-02-21 18:53:23 +00:00
|
|
|
last_match = table;
|
2002-01-09 01:03:10 +00:00
|
|
|
matches++;
|
|
|
|
}
|
|
|
|
}
|
2002-02-21 18:53:23 +00:00
|
|
|
if (matches > 1) {
|
|
|
|
printf("Ambiguous command: %s\n", cmd);
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-01-09 01:03:10 +00:00
|
|
|
return last_match;
|
|
|
|
}
|
|
|
|
|
2005-03-09 00:04:44 +00:00
|
|
|
static void check_ret(int r, int op, const char *err, const sc_file_t *file)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: %s\n", err, sc_strerror(r));
|
|
|
|
if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
|
2008-03-06 16:06:59 +00:00
|
|
|
fprintf(stderr, "ACL for operation: %s\n", util_acl_to_str(sc_file_get_acl_entry(file, op)));
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
|
2005-03-09 00:04:44 +00:00
|
|
|
static int arg_to_path(const char *arg, sc_path_t *path, int is_id)
|
2002-01-13 23:56:13 +00:00
|
|
|
{
|
2006-10-30 18:51:48 +00:00
|
|
|
if (strncasecmp(arg, "aid:", strlen("aid:")) == 0) {
|
2006-11-09 21:26:19 +00:00
|
|
|
/* DF aid */
|
2006-10-30 18:51:48 +00:00
|
|
|
const char *p = arg + strlen("aid:");
|
|
|
|
path->len = hex2binary(path->value, sizeof(path->value), p);
|
|
|
|
path->type = SC_PATH_TYPE_DF_NAME;
|
2002-02-11 15:55:34 +00:00
|
|
|
} else {
|
2006-11-09 21:26:19 +00:00
|
|
|
/* file id */
|
2008-05-05 13:00:01 +00:00
|
|
|
unsigned int buf[2];
|
2006-10-30 18:51:48 +00:00
|
|
|
u8 cbuf[2];
|
|
|
|
|
|
|
|
if (strlen(arg) != 4) {
|
|
|
|
printf("Wrong ID length.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (sscanf(arg, "%02X%02X", &buf[0], &buf[1]) != 2) {
|
|
|
|
printf("Invalid ID.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
cbuf[0] = buf[0];
|
|
|
|
cbuf[1] = buf[1];
|
|
|
|
if ((cbuf[0] == 0x3F && cbuf[1] == 0x00) || is_id) {
|
|
|
|
path->len = 2;
|
|
|
|
memcpy(path->value, cbuf, 2);
|
|
|
|
if (is_id)
|
|
|
|
path->type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
else
|
|
|
|
path->type = SC_PATH_TYPE_PATH;
|
|
|
|
} else {
|
|
|
|
*path = current_path;
|
|
|
|
sc_append_path_id(path, cbuf, 2);
|
|
|
|
}
|
2002-02-11 15:55:34 +00:00
|
|
|
}
|
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-09 00:04:44 +00:00
|
|
|
static void print_file(const sc_file_t *file)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
|
|
|
const char *st;
|
|
|
|
|
|
|
|
if (file->type == SC_FILE_TYPE_DF)
|
|
|
|
printf("[");
|
|
|
|
else
|
2005-02-11 20:09:34 +00:00
|
|
|
printf(" ");
|
2002-01-09 01:03:10 +00:00
|
|
|
printf("%02X%02X", file->id >> 8, file->id & 0xFF);
|
|
|
|
if (file->type == SC_FILE_TYPE_DF)
|
|
|
|
printf("]");
|
|
|
|
else
|
2005-02-11 20:09:34 +00:00
|
|
|
printf(" ");
|
2002-01-09 01:03:10 +00:00
|
|
|
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);
|
2006-08-02 19:43:13 +00:00
|
|
|
printf(" %5lu", (unsigned long)file->size);
|
2002-01-09 01:03:10 +00:00
|
|
|
if (file->namelen) {
|
|
|
|
printf("\tName: ");
|
2008-03-06 16:06:59 +00:00
|
|
|
util_print_binary(stdout, file->name, file->namelen);
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
printf("\n");
|
2002-01-09 01:03:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_ls(int argc, char **argv)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
|
|
|
u8 buf[256], *cur = buf;
|
|
|
|
int r, count;
|
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
if (argc)
|
|
|
|
goto usage;
|
2002-01-09 01:03:10 +00:00
|
|
|
r = sc_list_files(card, buf, sizeof(buf));
|
|
|
|
if (r < 0) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", current_file);
|
2002-01-09 01:03:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
count = r;
|
2005-02-11 20:09:34 +00:00
|
|
|
printf("FileID\tType Size\n");
|
2002-01-09 01:03:10 +00:00
|
|
|
while (count >= 2) {
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
|
|
|
sc_file_t *file = NULL;
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2006-10-30 18:51:48 +00:00
|
|
|
if (current_path.type != SC_PATH_TYPE_DF_NAME) {
|
|
|
|
path = current_path;
|
|
|
|
sc_append_path_id(&path, cur, 2);
|
|
|
|
} else {
|
|
|
|
if (sc_path_set(&path, SC_PATH_TYPE_FILE_ID, cur, 2, 0, 0) != SC_SUCCESS) {
|
|
|
|
printf("unable to set path.\n");
|
|
|
|
die(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-09 01:03:10 +00:00
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
2007-12-28 18:18:57 +00:00
|
|
|
printf(" %02X%02X unable to select file, %s\n", cur[0], cur[1], sc_strerror(r));
|
|
|
|
} else {
|
|
|
|
file->id = (cur[0] << 8) | cur[1];
|
|
|
|
print_file(file);
|
|
|
|
sc_file_free(file);
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
cur += 2;
|
2002-01-09 01:03:10 +00:00
|
|
|
count -= 2;
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
return 0;
|
2002-03-15 10:40:35 +00:00
|
|
|
usage:
|
|
|
|
puts("Usage: ls");
|
|
|
|
return -1;
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_cd(int argc, char **argv)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
|
|
|
sc_file_t *file;
|
2002-01-09 01:03:10 +00:00
|
|
|
int r;
|
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
if (argc != 1)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (strcmp(argv[0], "..") == 0) {
|
2002-01-09 01:03:10 +00:00
|
|
|
if (current_path.len < 4) {
|
|
|
|
printf("unable to go up, already in MF.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
path = current_path;
|
2002-01-09 01:03:10 +00:00
|
|
|
path.len -= 2;
|
2002-02-20 09:56:47 +00:00
|
|
|
r = sc_select_file(card, &path, &file);
|
2002-01-09 01:03:10 +00:00
|
|
|
if (r) {
|
|
|
|
printf("unable to go up: %s\n", sc_strerror(r));
|
|
|
|
return -1;
|
|
|
|
}
|
2010-08-21 20:12:56 +00:00
|
|
|
if (current_file)
|
|
|
|
sc_file_free(current_file);
|
2002-02-20 09:56:47 +00:00
|
|
|
current_file = file;
|
2002-01-09 01:03:10 +00:00
|
|
|
current_path = path;
|
|
|
|
return 0;
|
|
|
|
}
|
2002-03-15 10:40:35 +00:00
|
|
|
if (arg_to_path(argv[0], &path, 0) != 0)
|
2005-02-11 20:09:34 +00:00
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2002-01-09 01:03:10 +00:00
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_SELECT, "unable to select DF", current_file);
|
2002-01-09 01:03:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2005-02-01 07:52:40 +00:00
|
|
|
if ((file->type != SC_FILE_TYPE_DF) && !(card->caps & SC_CARD_CAP_NO_FCI)) {
|
2002-01-10 12:33:56 +00:00
|
|
|
printf("Error: file is not a DF.\n");
|
2002-02-20 09:56:47 +00:00
|
|
|
sc_file_free(file);
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2002-01-10 12:33:56 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2002-02-11 15:55:34 +00:00
|
|
|
current_path = path;
|
2010-08-21 20:12:56 +00:00
|
|
|
if (current_file)
|
|
|
|
sc_file_free(current_file);
|
2002-02-20 09:56:47 +00:00
|
|
|
current_file = file;
|
2002-01-09 01:03:10 +00:00
|
|
|
|
|
|
|
return 0;
|
2002-03-15 10:40:35 +00:00
|
|
|
usage:
|
2006-10-30 18:51:48 +00:00
|
|
|
puts("Usage: cd <file_id>|aid:<DF name>");
|
2002-03-15 10:40:35 +00:00
|
|
|
return -1;
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
|
2008-03-06 16:06:59 +00:00
|
|
|
static int read_and_util_print_binary_file(sc_file_t *file)
|
2002-02-10 18:04:03 +00:00
|
|
|
{
|
|
|
|
unsigned int idx = 0;
|
|
|
|
u8 buf[128];
|
|
|
|
size_t count;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
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);
|
|
|
|
return -1;
|
|
|
|
}
|
2005-02-01 07:52:40 +00:00
|
|
|
if ((r != c) && !(card->caps & SC_CARD_CAP_NO_FCI)) {
|
2002-02-10 18:04:03 +00:00
|
|
|
printf("expecting %d, got only %d bytes.\n", c, r);
|
|
|
|
return -1;
|
|
|
|
}
|
2005-02-01 07:52:40 +00:00
|
|
|
if ((r == 0) && (card->caps & SC_CARD_CAP_NO_FCI))
|
|
|
|
break;
|
2008-03-06 16:06:59 +00:00
|
|
|
util_hex_dump_asc(stdout, buf, r, idx);
|
2005-02-01 07:52:40 +00:00
|
|
|
idx += r;
|
|
|
|
count -= r;
|
2002-02-10 18:04:03 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-02 22:58:31 +00:00
|
|
|
static int read_and_print_record_file(sc_file_t *file, unsigned char sfi)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
|
|
|
u8 buf[256];
|
2002-02-10 18:04:03 +00:00
|
|
|
int rec, r;
|
|
|
|
|
2002-02-11 15:55:34 +00:00
|
|
|
for (rec = 1; ; rec++) {
|
2010-08-21 20:12:59 +00:00
|
|
|
r = sc_read_record(card, rec, buf, sizeof(buf),
|
|
|
|
SC_RECORD_BY_REC_NR | sfi);
|
2002-02-10 18:04:03 +00:00
|
|
|
if (r == SC_ERROR_RECORD_NOT_FOUND)
|
|
|
|
return 0;
|
|
|
|
if (r < 0) {
|
|
|
|
check_ret(r, SC_AC_OP_READ, "read failed", file);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
printf("Record %d:\n", rec);
|
2008-03-06 16:06:59 +00:00
|
|
|
util_hex_dump_asc(stdout, buf, r, 0);
|
2002-02-10 18:04:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_cat(int argc, char **argv)
|
2002-02-10 18:04:03 +00:00
|
|
|
{
|
2008-05-26 10:46:16 +00:00
|
|
|
int r, err = 1;
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
2008-05-26 10:46:16 +00:00
|
|
|
sc_file_t *file = NULL;
|
2002-01-09 01:03:10 +00:00
|
|
|
int not_current = 1;
|
2010-08-21 20:12:59 +00:00
|
|
|
int sfi = 0;
|
|
|
|
const char sfi_prefix[] = "sfi:";
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
if (argc > 1)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (!argc) {
|
2002-01-09 01:03:10 +00:00
|
|
|
path = current_path;
|
|
|
|
file = current_file;
|
|
|
|
not_current = 0;
|
|
|
|
} else {
|
2010-08-21 20:12:59 +00:00
|
|
|
if (strncmp(argv[0], sfi_prefix, sizeof(sfi_prefix)-1)) {
|
|
|
|
if (arg_to_path(argv[0], &path, 1) != 0)
|
|
|
|
goto usage;
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
|
|
|
check_ret(r, SC_AC_OP_SELECT, "unable to select file",
|
|
|
|
current_file);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
} else {
|
2010-09-13 08:08:42 +00:00
|
|
|
const char *sfi_n = &argv[0][sizeof(sfi_prefix)-1];
|
|
|
|
|
2010-08-21 20:12:59 +00:00
|
|
|
if(!current_file) {
|
|
|
|
printf("A DF must be selected to read by SFI\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
path = current_path;
|
|
|
|
file = current_file;
|
|
|
|
not_current = 0;
|
|
|
|
sfi = atoi(sfi_n);
|
|
|
|
if ((sfi < 1) || (sfi > 30)) {
|
|
|
|
printf("Invalid SFI: %s\n", sfi_n);
|
|
|
|
goto usage;
|
|
|
|
}
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
}
|
2010-08-21 20:12:59 +00:00
|
|
|
if (file->type != SC_FILE_TYPE_WORKING_EF &&
|
|
|
|
!(file->type == SC_FILE_TYPE_DF && sfi)) {
|
2002-02-26 11:23:25 +00:00
|
|
|
printf("only working EFs may be read\n");
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
2010-08-21 20:12:59 +00:00
|
|
|
if (file->ef_structure == SC_FILE_EF_TRANSPARENT && !sfi)
|
2008-03-06 16:06:59 +00:00
|
|
|
read_and_util_print_binary_file(file);
|
2002-02-10 18:04:03 +00:00
|
|
|
else
|
2010-08-21 20:12:59 +00:00
|
|
|
read_and_print_record_file(file, sfi);
|
2008-05-26 10:46:16 +00:00
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
|
|
|
err:
|
2002-01-09 01:03:10 +00:00
|
|
|
if (not_current) {
|
2008-05-26 10:46:16 +00:00
|
|
|
if (file != NULL) {
|
|
|
|
sc_file_free(file);
|
|
|
|
}
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
2008-05-26 10:46:16 +00:00
|
|
|
|
|
|
|
return -err;
|
2005-02-11 20:09:34 +00:00
|
|
|
usage:
|
2010-08-21 20:12:59 +00:00
|
|
|
puts("Usage: cat [file_id] or");
|
|
|
|
puts(" cat sfi:<sfi_id>");
|
2005-02-11 20:09:34 +00:00
|
|
|
return -1;
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_info(int argc, char **argv)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_file_t *file;
|
|
|
|
sc_path_t path;
|
2005-02-04 18:10:23 +00:00
|
|
|
size_t i;
|
2002-01-09 01:03:10 +00:00
|
|
|
const char *st;
|
2005-02-04 18:10:23 +00:00
|
|
|
int r, not_current = 1;
|
2002-03-15 10:40:35 +00:00
|
|
|
|
|
|
|
if (!argc) {
|
2002-01-09 01:03:10 +00:00
|
|
|
path = current_path;
|
|
|
|
file = current_file;
|
|
|
|
not_current = 0;
|
2002-03-15 10:40:35 +00:00
|
|
|
} else if (argc == 1) {
|
|
|
|
if (arg_to_path(argv[0], &path, 0) != 0)
|
2005-02-11 20:09:34 +00:00
|
|
|
goto usage;
|
2002-02-11 15:55:34 +00:00
|
|
|
r = sc_select_file(card, &path, &file);
|
2002-01-09 01:03:10 +00:00
|
|
|
if (r) {
|
|
|
|
printf("unable to select file: %s\n", sc_strerror(r));
|
|
|
|
return -1;
|
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
} else
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
switch (file->type) {
|
2002-01-09 01:03:10 +00:00
|
|
|
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;
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
printf("\n%s ID %04X\n\n", st, file->id);
|
2002-01-09 01:03:10 +00:00
|
|
|
printf("%-15s", "File path:");
|
|
|
|
for (i = 0; i < path.len; i++) {
|
|
|
|
for (i = 0; i < path.len; i++) {
|
2005-02-11 20:09:34 +00:00
|
|
|
if ((i & 1) == 0 && i)
|
2002-01-09 01:03:10 +00:00
|
|
|
printf("/");
|
|
|
|
printf("%02X", path.value[i]);
|
|
|
|
}
|
|
|
|
}
|
2006-05-01 10:02:50 +00:00
|
|
|
printf("\n%-15s%lu bytes\n", "File size:", (unsigned long) file->size);
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
2002-01-09 01:03:10 +00:00
|
|
|
const char *ops[] = {
|
|
|
|
"SELECT", "LOCK", "DELETE", "CREATE", "REHABILITATE",
|
2007-01-20 12:46:40 +00:00
|
|
|
"INVALIDATE", "LIST FILES", "CRYPTO", "DELETE SELF"
|
2002-01-09 01:03:10 +00:00
|
|
|
};
|
2002-02-20 09:56:47 +00:00
|
|
|
if (file->namelen) {
|
2002-01-09 01:03:10 +00:00
|
|
|
printf("%-15s", "DF name:");
|
2008-03-06 16:06:59 +00:00
|
|
|
util_print_binary(stdout, file->name, file->namelen);
|
2002-01-09 01:03:10 +00:00
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
|
|
|
|
char buf[80];
|
|
|
|
|
|
|
|
sprintf(buf, "ACL for %s:", ops[i]);
|
2008-03-06 16:06:59 +00:00
|
|
|
printf("%-25s%s\n", buf, util_acl_to_str(sc_file_get_acl_entry(file, i)));
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
} else {
|
2005-02-11 20:09:34 +00:00
|
|
|
const char *structs[] = {
|
|
|
|
"Unknown", "Transparent", "Linear fixed",
|
2002-01-09 01:03:10 +00:00
|
|
|
"Linear fixed, SIMPLE-TLV", "Linear variable",
|
2002-06-11 18:17:16 +00:00
|
|
|
"Linear variable TLV", "Cyclic, SIMPLE-TLV",
|
2005-02-11 20:09:34 +00:00
|
|
|
};
|
2010-08-14 12:18:27 +00:00
|
|
|
const struct {
|
|
|
|
const char * label;
|
|
|
|
int op;
|
|
|
|
} ops[] = {
|
|
|
|
{ "READ", SC_AC_OP_READ },
|
|
|
|
{ "UPDATE", SC_AC_OP_UPDATE },
|
|
|
|
{ "DELETE", SC_AC_OP_DELETE },
|
|
|
|
{ "WRITE", SC_AC_OP_WRITE },
|
|
|
|
{ "REHABILITATE", SC_AC_OP_REHABILITATE },
|
|
|
|
{ "INVALIDATE", SC_AC_OP_INVALIDATE },
|
|
|
|
{ "LIST_FILES", SC_AC_OP_LIST_FILES },
|
|
|
|
{ "CRYPTO", SC_AC_OP_CRYPTO },
|
2002-01-13 23:56:13 +00:00
|
|
|
};
|
2002-02-20 09:56:47 +00:00
|
|
|
printf("%-15s%s\n", "EF structure:", structs[file->ef_structure]);
|
2002-01-13 23:56:13 +00:00
|
|
|
for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
|
|
|
|
char buf[80];
|
|
|
|
|
2010-08-14 12:18:27 +00:00
|
|
|
sprintf(buf, "ACL for %s:", ops[i].label);
|
|
|
|
printf("%-25s%s\n", buf, util_acl_to_str(sc_file_get_acl_entry(file, ops[i].op)));
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
if (file->prop_attr_len) {
|
2002-01-13 23:56:13 +00:00
|
|
|
printf("%-25s", "Proprietary attributes:");
|
2002-02-20 09:56:47 +00:00
|
|
|
for (i = 0; i < file->prop_attr_len; i++)
|
|
|
|
printf("%02X ", file->prop_attr[i]);
|
2002-01-13 23:56:13 +00:00
|
|
|
printf("\n");
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
if (file->sec_attr_len) {
|
2002-02-11 15:55:34 +00:00
|
|
|
printf("%-25s", "Security attributes:");
|
2002-02-20 09:56:47 +00:00
|
|
|
for (i = 0; i < file->sec_attr_len; i++)
|
|
|
|
printf("%02X ", file->sec_attr[i]);
|
2002-02-11 15:55:34 +00:00
|
|
|
printf("\n");
|
|
|
|
}
|
2002-01-09 01:03:10 +00:00
|
|
|
printf("\n");
|
|
|
|
if (not_current) {
|
2002-02-20 09:56:47 +00:00
|
|
|
sc_file_free(file);
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
usage:
|
|
|
|
puts("Usage: info [file_id]");
|
|
|
|
return -1;
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
|
2005-03-09 00:04:44 +00:00
|
|
|
static int create_file(sc_file_t *file)
|
2002-01-16 23:59:18 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sc_create_file(card, file);
|
|
|
|
if (r) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_CREATE, "CREATE FILE failed", current_file);
|
2002-01-16 23:59:18 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* Make sure we're back in the parent directory, because on some cards
|
|
|
|
* CREATE FILE also selects the newly created file. */
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2002-01-16 23:59:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_create(int argc, char **argv)
|
2002-01-10 23:02:48 +00:00
|
|
|
{
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
|
|
|
sc_file_t *file;
|
2002-01-21 10:56:30 +00:00
|
|
|
unsigned int size;
|
2002-11-07 14:48:03 +00:00
|
|
|
int r, op;
|
2002-01-10 23:02:48 +00:00
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
if (argc != 2)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (arg_to_path(argv[0], &path, 1) != 0)
|
2002-01-10 23:02:48 +00:00
|
|
|
goto usage;
|
2002-01-15 18:54:53 +00:00
|
|
|
/* %z isn't supported everywhere */
|
2008-05-05 13:00:01 +00:00
|
|
|
if (sscanf(argv[1], "%u", &size) != 1)
|
2002-01-10 23:02:48 +00:00
|
|
|
goto usage;
|
2002-02-20 09:56:47 +00:00
|
|
|
file = sc_file_new();
|
|
|
|
file->id = (path.value[0] << 8) | path.value[1];
|
|
|
|
file->type = SC_FILE_TYPE_WORKING_EF;
|
|
|
|
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
|
|
|
file->size = (size_t) size;
|
|
|
|
file->status = SC_FILE_STATUS_ACTIVATED;
|
2002-11-07 14:48:03 +00:00
|
|
|
for (op = 0; op < SC_MAX_AC_OPS; op++)
|
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_NONE, 0);
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
r = create_file(file);
|
|
|
|
sc_file_free(file);
|
|
|
|
return r;
|
2002-03-15 10:40:35 +00:00
|
|
|
usage:
|
2002-01-10 23:02:48 +00:00
|
|
|
printf("Usage: create <file_id> <file_size>\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_mkdir(int argc, char **argv)
|
2002-01-16 23:59:18 +00:00
|
|
|
{
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
|
|
|
sc_file_t *file;
|
2002-01-21 10:56:30 +00:00
|
|
|
unsigned int size;
|
2002-11-07 14:48:03 +00:00
|
|
|
int r, op;
|
2002-01-16 23:59:18 +00:00
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
if (argc != 2)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (arg_to_path(argv[0], &path, 1) != 0)
|
2002-01-16 23:59:18 +00:00
|
|
|
goto usage;
|
2008-05-05 13:00:01 +00:00
|
|
|
if (sscanf(argv[1], "%u", &size) != 1)
|
2002-01-16 23:59:18 +00:00
|
|
|
goto usage;
|
2002-02-20 09:56:47 +00:00
|
|
|
file = sc_file_new();
|
|
|
|
file->id = (path.value[0] << 8) | path.value[1];
|
|
|
|
file->type = SC_FILE_TYPE_DF;
|
|
|
|
file->size = size;
|
|
|
|
file->status = SC_FILE_STATUS_ACTIVATED;
|
2002-11-07 14:48:03 +00:00
|
|
|
for (op = 0; op < SC_MAX_AC_OPS; op++)
|
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_NONE, 0);
|
2002-02-20 09:56:47 +00:00
|
|
|
|
|
|
|
r = create_file(file);
|
|
|
|
sc_file_free(file);
|
|
|
|
return r;
|
2002-03-15 10:40:35 +00:00
|
|
|
usage:
|
2002-01-16 23:59:18 +00:00
|
|
|
printf("Usage: mkdir <file_id> <df_size>\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_delete(int argc, char **argv)
|
2002-01-10 23:02:48 +00:00
|
|
|
{
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
2002-01-10 23:02:48 +00:00
|
|
|
int r;
|
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
if (argc != 1)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (arg_to_path(argv[0], &path, 1) != 0)
|
2002-02-20 09:56:47 +00:00
|
|
|
goto usage;
|
|
|
|
if (path.len != 2)
|
2002-01-10 23:02:48 +00:00
|
|
|
goto usage;
|
2002-02-20 09:56:47 +00:00
|
|
|
path.type = SC_PATH_TYPE_FILE_ID;
|
2002-01-10 23:02:48 +00:00
|
|
|
r = sc_delete_file(card, &path);
|
|
|
|
if (r) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_DELETE, "DELETE FILE failed", current_file);
|
2002-01-10 23:02:48 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
usage:
|
|
|
|
printf("Usage: delete <file_id>\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_verify(int argc, char **argv)
|
2002-01-10 23:02:48 +00:00
|
|
|
{
|
2002-11-07 14:48:03 +00:00
|
|
|
struct {
|
|
|
|
const char * name;
|
|
|
|
int type;
|
|
|
|
} typeNames[] = {
|
|
|
|
{ "CHV", SC_AC_CHV },
|
|
|
|
{ "KEY", SC_AC_AUT },
|
|
|
|
{ "AUT", SC_AC_AUT },
|
|
|
|
{ "PRO", SC_AC_PRO },
|
2005-02-04 18:10:23 +00:00
|
|
|
{ NULL, SC_AC_NONE }
|
2002-01-10 23:02:48 +00:00
|
|
|
};
|
2005-02-04 18:10:23 +00:00
|
|
|
int r, tries_left = -1;
|
2005-08-09 18:21:50 +00:00
|
|
|
u8 buf[64];
|
2005-02-11 20:09:34 +00:00
|
|
|
const char *s;
|
2005-02-04 18:10:23 +00:00
|
|
|
size_t buflen = sizeof(buf), i;
|
2003-11-03 06:54:30 +00:00
|
|
|
struct sc_pin_cmd_data data;
|
|
|
|
|
2002-03-15 10:40:35 +00:00
|
|
|
if (argc < 1 || argc > 2)
|
2005-02-11 20:09:34 +00:00
|
|
|
goto usage;
|
2003-11-03 06:54:30 +00:00
|
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
data.cmd = SC_PIN_CMD_VERIFY;
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
data.pin_type = SC_AC_NONE;
|
2002-11-07 14:48:03 +00:00
|
|
|
for (i = 0; typeNames[i].name; i++) {
|
|
|
|
if (strncasecmp(argv[0], typeNames[i].name, 3) == 0) {
|
2003-11-03 06:54:30 +00:00
|
|
|
data.pin_type = typeNames[i].type;
|
2002-01-10 23:02:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
}
|
2005-02-04 18:10:23 +00:00
|
|
|
if (data.pin_type == SC_AC_NONE) {
|
2002-01-10 23:02:48 +00:00
|
|
|
printf("Invalid type.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
2003-11-03 06:54:30 +00:00
|
|
|
if (sscanf(argv[0] + 3, "%d", &data.pin_reference) != 1) {
|
2002-01-10 23:02:48 +00:00
|
|
|
printf("Invalid key reference.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
2003-11-03 06:54:30 +00:00
|
|
|
|
2005-02-11 20:09:34 +00:00
|
|
|
if (argc < 2) {
|
2010-01-24 15:29:47 +00:00
|
|
|
if (!(card->reader->capabilities & SC_READER_CAP_PIN_PAD)) {
|
2003-11-03 06:54:30 +00:00
|
|
|
printf("Card reader or driver doesn't support PIN PAD\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
printf("Please enter PIN on the reader's pin pad.\n");
|
|
|
|
data.pin1.prompt = "Please enter PIN";
|
2005-02-11 20:09:34 +00:00
|
|
|
data.flags |= SC_PIN_CMD_USE_PINPAD;
|
|
|
|
} else if (argv[1][0] == '"') {
|
2002-03-15 10:40:35 +00:00
|
|
|
for (s=argv[1]+1, i=0; i < sizeof(buf) && *s && *s != '"';i++)
|
|
|
|
buf[i] = *s++;
|
2003-11-03 06:54:30 +00:00
|
|
|
data.pin1.data = buf;
|
|
|
|
data.pin1.len = i;
|
2003-11-26 15:49:09 +00:00
|
|
|
} else {
|
2005-02-11 20:09:34 +00:00
|
|
|
r = sc_hex_to_bin(argv[1], buf, &buflen);
|
2003-11-26 15:49:09 +00:00
|
|
|
if (0 != r) {
|
2003-11-20 16:01:56 +00:00
|
|
|
printf("Invalid key value.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
data.pin1.data = buf;
|
|
|
|
data.pin1.len = buflen;
|
2002-01-10 23:02:48 +00:00
|
|
|
}
|
2003-11-03 06:54:30 +00:00
|
|
|
r = sc_pin_cmd(card, &data, &tries_left);
|
|
|
|
|
2002-01-10 23:02:48 +00:00
|
|
|
if (r) {
|
|
|
|
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
|
|
|
|
if (tries_left >= 0)
|
2002-01-20 21:20:09 +00:00
|
|
|
printf("Incorrect code, %d tries left.\n", tries_left);
|
2002-01-10 23:02:48 +00:00
|
|
|
else
|
|
|
|
printf("Incorrect code.\n");
|
2002-04-04 20:37:27 +00:00
|
|
|
} else
|
|
|
|
printf("Unable to verify PIN code: %s\n", sc_strerror(r));
|
2002-01-10 23:02:48 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
printf("Code correct.\n");
|
|
|
|
return 0;
|
|
|
|
usage:
|
2002-03-15 10:40:35 +00:00
|
|
|
printf("Usage: verify <key type><key ref> [<key in hex>]\n");
|
2002-01-10 23:02:48 +00:00
|
|
|
printf("Possible values of <key type>:\n");
|
2002-11-07 14:48:03 +00:00
|
|
|
for (i = 0; typeNames[i].name; i++)
|
|
|
|
printf("\t%s\n", typeNames[i].name);
|
2002-01-10 23:02:48 +00:00
|
|
|
printf("Example: verify CHV2 31:32:33:34:00:00:00:00\n");
|
2003-11-03 06:54:30 +00:00
|
|
|
printf("If key is omitted, card reader's keypad will be used to collect PIN.\n");
|
2002-01-10 23:02:48 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_change(int argc, char **argv)
|
2002-03-15 10:40:35 +00:00
|
|
|
{
|
2005-02-04 18:10:23 +00:00
|
|
|
int ref, r, tries_left = -1;
|
2002-03-15 10:40:35 +00:00
|
|
|
u8 oldpin[30];
|
|
|
|
u8 newpin[30];
|
2005-01-21 18:47:41 +00:00
|
|
|
const char *s;
|
2005-02-04 18:10:23 +00:00
|
|
|
size_t oldpinlen = sizeof(oldpin), i;
|
2002-03-15 10:40:35 +00:00
|
|
|
size_t newpinlen = sizeof(newpin);
|
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
if (argc < 1 || argc > 3)
|
2002-03-15 10:40:35 +00:00
|
|
|
goto usage;
|
2005-01-21 18:47:41 +00:00
|
|
|
if (strncasecmp(argv[0], "CHV", 3)) {
|
2002-03-15 10:40:35 +00:00
|
|
|
printf("Invalid type.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
if (sscanf(argv[0] + 3, "%d", &ref) != 1) {
|
|
|
|
printf("Invalid key reference.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
2005-01-19 08:00:41 +00:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
if (argc == 0) {
|
|
|
|
/* set without verification */
|
|
|
|
oldpinlen = 0;
|
|
|
|
newpinlen = 0;
|
|
|
|
} else if (argc == 1) {
|
2005-01-19 08:00:41 +00:00
|
|
|
/* set without verification */
|
|
|
|
oldpinlen = 0;
|
|
|
|
} else {
|
2003-10-21 08:59:11 +00:00
|
|
|
if (argv[0][0] == '"') {
|
|
|
|
for (s = argv[0] + 1, i = 0;
|
|
|
|
i < sizeof(oldpin) && *s && *s != '"'; i++)
|
|
|
|
oldpin[i] = *s++;
|
|
|
|
oldpinlen = i;
|
|
|
|
} else if (sc_hex_to_bin(argv[0], oldpin, &oldpinlen) != 0) {
|
|
|
|
printf("Invalid key value.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
argc--;
|
|
|
|
argv++;
|
2002-03-15 10:40:35 +00:00
|
|
|
}
|
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
if (argc) {
|
|
|
|
if (argv[0][0] == '"') {
|
|
|
|
for (s = argv[0] + 1, i = 0;
|
|
|
|
i < sizeof(newpin) && *s && *s != '"'; i++)
|
|
|
|
newpin[i] = *s++;
|
|
|
|
newpinlen = i;
|
|
|
|
} else if (sc_hex_to_bin(argv[0], newpin, &newpinlen) != 0) {
|
|
|
|
printf("Invalid key value.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
2002-03-15 10:40:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_change_reference_data (card, SC_AC_CHV, ref,
|
2009-12-03 11:11:04 +00:00
|
|
|
oldpinlen ? oldpin : NULL, oldpinlen,
|
|
|
|
newpinlen ? newpin : NULL, newpinlen,
|
2002-03-15 10:40:35 +00:00
|
|
|
&tries_left);
|
|
|
|
if (r) {
|
|
|
|
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
|
|
|
|
if (tries_left >= 0)
|
|
|
|
printf("Incorrect code, %d tries left.\n", tries_left);
|
|
|
|
else
|
|
|
|
printf("Incorrect code.\n");
|
|
|
|
}
|
|
|
|
printf("Unable to change PIN code: %s\n", sc_strerror(r));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
printf("PIN changed.\n");
|
|
|
|
return 0;
|
|
|
|
usage:
|
2009-12-03 11:11:04 +00:00
|
|
|
printf("Usage: change CHV<pin ref> [[<old pin>] <new pin>]\n");
|
|
|
|
printf("Examples: \n");
|
|
|
|
printf("\tChange PIN: change CHV2 00:00:00:00:00:00 \"foobar\"\n");
|
|
|
|
printf("\tSet PIN: change CHV2 \"foobar\"\n");
|
|
|
|
printf("\tChange PIN with pinpad': change CHV2\n");
|
2002-03-15 10:40:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_unblock(int argc, char **argv)
|
2002-12-19 19:42:51 +00:00
|
|
|
{
|
2005-02-04 18:10:23 +00:00
|
|
|
int ref, r;
|
2009-12-03 11:11:04 +00:00
|
|
|
u8 puk_buf[30], *puk = NULL;
|
|
|
|
u8 newpin_buf[30], *newpin = NULL;
|
2005-01-21 18:47:41 +00:00
|
|
|
const char *s;
|
2009-12-03 11:11:04 +00:00
|
|
|
size_t puklen = sizeof(puk_buf), i;
|
|
|
|
size_t newpinlen = sizeof(newpin_buf);
|
2002-12-19 19:42:51 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
if (argc < 1 || argc > 3)
|
2002-12-19 19:42:51 +00:00
|
|
|
goto usage;
|
2005-01-21 18:47:41 +00:00
|
|
|
if (strncasecmp(argv[0], "CHV", 3)) {
|
2002-12-19 19:42:51 +00:00
|
|
|
printf("Invalid type.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
if (sscanf(argv[0] + 3, "%d", &ref) != 1) {
|
|
|
|
printf("Invalid key reference.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
2005-01-21 18:47:41 +00:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2002-12-19 19:42:51 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
if (argc == 0) {
|
2005-01-21 18:47:41 +00:00
|
|
|
puklen = 0;
|
2009-12-03 11:11:04 +00:00
|
|
|
puk = NULL;
|
2005-01-21 18:47:41 +00:00
|
|
|
} else {
|
2003-10-21 08:59:11 +00:00
|
|
|
if (argv[0][0] == '"') {
|
|
|
|
for (s = argv[0] + 1, i = 0;
|
2009-12-03 11:11:04 +00:00
|
|
|
i < sizeof(puk_buf) && *s && *s != '"'; i++)
|
|
|
|
puk_buf[i] = *s++;
|
2003-10-21 08:59:11 +00:00
|
|
|
puklen = i;
|
2009-12-03 11:11:04 +00:00
|
|
|
} else if (sc_hex_to_bin(argv[0], puk_buf, &puklen) != 0) {
|
2003-10-21 08:59:11 +00:00
|
|
|
printf("Invalid key value.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
2009-12-03 11:11:04 +00:00
|
|
|
puk = &puk_buf[0];
|
|
|
|
|
2003-10-21 08:59:11 +00:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2002-12-19 19:42:51 +00:00
|
|
|
}
|
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
if (argc) {
|
|
|
|
if (argv[0][0] == '"') {
|
|
|
|
for (s = argv[0] + 1, i = 0;
|
|
|
|
i < sizeof(newpin_buf) && *s && *s != '"'; i++)
|
|
|
|
newpin_buf[i] = *s++;
|
|
|
|
newpinlen = i;
|
|
|
|
} else if (sc_hex_to_bin(argv[0], newpin_buf, &newpinlen) != 0) {
|
|
|
|
printf("Invalid key value.\n");
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
newpin = &newpin_buf[0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newpinlen = 0;
|
|
|
|
newpin = NULL;
|
2002-12-19 19:42:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_reset_retry_counter (card, SC_AC_CHV, ref,
|
|
|
|
puk, puklen,
|
|
|
|
newpin, newpinlen);
|
|
|
|
if (r) {
|
|
|
|
if (r == SC_ERROR_PIN_CODE_INCORRECT)
|
|
|
|
printf("Incorrect code.\n");
|
|
|
|
printf("Unable to unblock PIN code: %s\n", sc_strerror(r));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
printf("PIN unblocked.\n");
|
|
|
|
return 0;
|
|
|
|
usage:
|
2009-12-03 11:11:04 +00:00
|
|
|
printf("Usage: unblock CHV<pin ref> [<puk>] [<new pin>]\n");
|
|
|
|
printf("PUK and PIN values can be hexadecimal, ASCII, empty (\"\") or absent\n");
|
|
|
|
printf("Examples:\n");
|
|
|
|
printf("\tUnblock PIN and set a new value: unblock CHV2 00:00:00:00:00:00 \"foobar\"\n");
|
|
|
|
printf("\tUnblock PIN keeping the old value: unblock CHV2 00:00:00:00:00:00 \"\"\n");
|
|
|
|
printf("\tSet new PIN value: unblock CHV2 \"\" \"foobar\"\n");
|
|
|
|
printf("Examples with pinpad:\n");
|
|
|
|
printf("\tUnblock PIN: new PIN value is prompted by pinpad: unblock CHV2 00:00:00:00:00:00\n");
|
|
|
|
printf("\tSet PIN: new PIN value is prompted by pinpad: unblock CHV2 \"\"\n");
|
|
|
|
printf("\tUnblock PIN: unblock code and new PIN value are prompted by pinpad: unblock CHV2\n");
|
2002-12-19 19:42:51 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_get(int argc, char **argv)
|
2002-01-13 23:56:13 +00:00
|
|
|
{
|
|
|
|
u8 buf[256];
|
2008-05-26 10:46:16 +00:00
|
|
|
int r, err = 1;
|
2002-01-13 23:56:13 +00:00
|
|
|
size_t count = 0;
|
2005-01-21 18:47:41 +00:00
|
|
|
unsigned int idx = 0;
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
2008-05-26 10:46:16 +00:00
|
|
|
sc_file_t *file = NULL;
|
2003-09-25 09:33:16 +00:00
|
|
|
char fbuf[256], *filename;
|
2002-01-13 23:56:13 +00:00
|
|
|
FILE *outf = NULL;
|
|
|
|
|
2005-01-21 18:47:41 +00:00
|
|
|
if (argc < 1 || argc > 2)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (arg_to_path(argv[0], &path, 0) != 0)
|
2002-01-13 23:56:13 +00:00
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (argc == 2)
|
|
|
|
filename = argv[1];
|
2002-01-13 23:56:13 +00:00
|
|
|
else {
|
2005-02-04 18:10:23 +00:00
|
|
|
size_t i = 0;
|
2003-09-25 09:33:16 +00:00
|
|
|
|
2003-05-02 14:57:44 +00:00
|
|
|
while (2*i < path.len) {
|
|
|
|
sprintf(&fbuf[5*i], "%02X%02X_", path.value[2*i], path.value[2*i+1]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
fbuf[5*i-1] = 0;
|
2003-09-25 09:33:16 +00:00
|
|
|
filename = fbuf;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2003-07-18 09:32:41 +00:00
|
|
|
outf = fopen(filename, "wb");
|
2002-01-13 23:56:13 +00:00
|
|
|
if (outf == NULL) {
|
|
|
|
perror(filename);
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2002-02-26 11:23:25 +00:00
|
|
|
if (file->type != SC_FILE_TYPE_WORKING_EF) {
|
|
|
|
printf("only working EFs may be read\n");
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
count = file->size;
|
2002-01-13 23:56:13 +00:00
|
|
|
while (count) {
|
|
|
|
int c = count > sizeof(buf) ? sizeof(buf) : count;
|
|
|
|
|
|
|
|
r = sc_read_binary(card, idx, buf, c, 0);
|
|
|
|
if (r < 0) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_READ, "read failed", file);
|
2005-01-21 18:47:41 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2005-02-01 07:52:40 +00:00
|
|
|
if ((r != c) && !(card->caps & SC_CARD_CAP_NO_FCI)) {
|
2002-01-13 23:56:13 +00:00
|
|
|
printf("expecting %d, got only %d bytes.\n", c, r);
|
2005-01-21 18:47:41 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2005-02-01 07:52:40 +00:00
|
|
|
if ((r == 0) && (card->caps & SC_CARD_CAP_NO_FCI))
|
|
|
|
break;
|
|
|
|
fwrite(buf, r, 1, outf);
|
|
|
|
idx += r;
|
|
|
|
count -= r;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2003-05-02 14:57:44 +00:00
|
|
|
printf("Total of %d bytes read from %s and saved to %s.\n",
|
2005-01-21 18:47:41 +00:00
|
|
|
idx, argv[0], filename);
|
2008-05-26 10:46:16 +00:00
|
|
|
|
|
|
|
err = 0;
|
2002-01-13 23:56:13 +00:00
|
|
|
err:
|
2008-05-26 10:46:16 +00:00
|
|
|
if (file)
|
|
|
|
sc_file_free(file);
|
|
|
|
if (outf)
|
|
|
|
fclose(outf);
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2005-02-04 18:10:23 +00:00
|
|
|
return -err;
|
2002-01-13 23:56:13 +00:00
|
|
|
usage:
|
|
|
|
printf("Usage: get <file id> [output file]\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-06-24 17:25:23 +00:00
|
|
|
static size_t hex2binary(u8 *out, size_t outlen, const char *in)
|
|
|
|
{
|
|
|
|
size_t inlen = strlen(in), len = outlen;
|
|
|
|
const char *p = in;
|
|
|
|
int s = 0;
|
|
|
|
|
|
|
|
out--;
|
2010-09-22 11:46:33 +00:00
|
|
|
while (inlen && (len || s)) {
|
2004-06-24 17:25:23 +00:00
|
|
|
char c = *p++;
|
|
|
|
inlen--;
|
|
|
|
if (!isxdigit(c))
|
|
|
|
continue;
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
c -= '0';
|
|
|
|
else if (c >= 'a' && c <= 'f')
|
|
|
|
c -= 'a' - 10;
|
|
|
|
else /* (c >= 'A' && c <= 'F') */
|
|
|
|
c -= 'A' - 10;
|
|
|
|
if (s)
|
|
|
|
*out <<= 4;
|
|
|
|
else {
|
|
|
|
len--;
|
|
|
|
*(++out) = 0;
|
|
|
|
}
|
|
|
|
s = !s;
|
|
|
|
*out |= (u8)c;
|
|
|
|
}
|
|
|
|
if (s) {
|
|
|
|
printf("Error: the number of hex digits must be even.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return outlen - len;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_update_binary(int argc, char **argv)
|
2004-06-24 17:25:23 +00:00
|
|
|
{
|
|
|
|
u8 buf[240];
|
2005-02-04 18:10:23 +00:00
|
|
|
int r, err = 1, in_len;
|
2004-06-24 17:25:23 +00:00
|
|
|
int offs;
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
|
|
|
sc_file_t *file;
|
2004-06-24 17:25:23 +00:00
|
|
|
char *in_str;
|
|
|
|
|
|
|
|
if (argc < 2 || argc > 3)
|
|
|
|
goto usage;
|
|
|
|
if (arg_to_path(argv[0], &path, 0) != 0)
|
|
|
|
goto usage;
|
|
|
|
offs = strtol(argv[1],NULL,10);
|
|
|
|
|
|
|
|
in_str = argv[2];
|
|
|
|
printf("in: %i; %s\n", offs, in_str);
|
|
|
|
if (*in_str=='\"') {
|
2006-04-26 09:58:47 +00:00
|
|
|
in_len = strlen(in_str)-2 >= sizeof(buf) ? sizeof(buf)-1 : strlen(in_str)-2;
|
2004-12-15 13:53:36 +00:00
|
|
|
strncpy((char *) buf, in_str+1, in_len);
|
2004-06-24 17:25:23 +00:00
|
|
|
} else {
|
|
|
|
in_len = hex2binary(buf, sizeof(buf), in_str);
|
|
|
|
if (!in_len) {
|
|
|
|
printf("unable to parse hex value\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
|
|
|
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file->ef_structure != SC_FILE_EF_TRANSPARENT) {
|
|
|
|
printf("EF structure should be SC_FILE_EF_TRANSPARENT\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_update_binary(card, offs, buf, in_len, 0);
|
|
|
|
if (r < 0) {
|
|
|
|
printf("Cannot update %04X; return %i\n", file->id, r);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Total of %d bytes written to %04X at %i offset.\n",
|
2005-01-21 18:47:41 +00:00
|
|
|
r, file->id, offs);
|
2008-05-26 10:46:16 +00:00
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
err = 0;
|
2008-05-26 10:46:16 +00:00
|
|
|
|
2004-06-24 17:25:23 +00:00
|
|
|
err:
|
|
|
|
sc_file_free(file);
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2005-02-04 18:10:23 +00:00
|
|
|
return -err;
|
2004-06-24 17:25:23 +00:00
|
|
|
usage:
|
|
|
|
printf("Usage: update <file id> offs <hex value> | <'\"' enclosed string>\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_update_record(int argc, char **argv)
|
2004-06-24 17:25:23 +00:00
|
|
|
{
|
|
|
|
u8 buf[240];
|
2005-02-04 18:10:23 +00:00
|
|
|
int r, i, err = 1;
|
2004-06-24 17:25:23 +00:00
|
|
|
int rec, offs;
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
|
|
|
sc_file_t *file;
|
2004-06-24 17:25:23 +00:00
|
|
|
char *in_str;
|
|
|
|
|
|
|
|
if (argc < 3 || argc > 4)
|
|
|
|
goto usage;
|
|
|
|
if (arg_to_path(argv[0], &path, 0) != 0)
|
|
|
|
goto usage;
|
|
|
|
rec = strtol(argv[1],NULL,10);
|
|
|
|
offs = strtol(argv[2],NULL,10);
|
|
|
|
|
|
|
|
in_str = argv[3];
|
|
|
|
printf("in: %i; %i; %s\n", rec, offs, in_str);
|
|
|
|
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
|
|
|
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file->ef_structure != SC_FILE_EF_LINEAR_VARIABLE) {
|
|
|
|
printf("EF structure should be SC_FILE_EF_LINEAR_VARIABLE\n");
|
|
|
|
goto err;
|
|
|
|
} else if (rec < 1 || rec > file->record_count) {
|
|
|
|
printf("Invalid record number %i\n", rec);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
|
|
|
|
if (r<0) {
|
|
|
|
printf("Cannot read record %i; return %i\n", rec, r);
|
|
|
|
goto err;;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = hex2binary(buf + offs, sizeof(buf) - offs, in_str);
|
|
|
|
if (!i) {
|
|
|
|
printf("unable to parse hex value\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_update_record(card, rec, buf, r, SC_RECORD_BY_REC_NR);
|
|
|
|
if (r<0) {
|
|
|
|
printf("Cannot update record %i; return %i\n", rec, r);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Total of %d bytes written to record %i at %i offset.\n",
|
2005-01-21 18:47:41 +00:00
|
|
|
i, rec, offs);
|
2005-02-04 18:10:23 +00:00
|
|
|
err = 0;
|
2008-05-26 10:46:16 +00:00
|
|
|
|
2004-06-24 17:25:23 +00:00
|
|
|
err:
|
|
|
|
sc_file_free(file);
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2005-02-04 18:10:23 +00:00
|
|
|
return -err;
|
2004-06-24 17:25:23 +00:00
|
|
|
usage:
|
|
|
|
printf("Usage: update_record <file id> rec_nr rec_offs <hex value>\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_put(int argc, char **argv)
|
2002-01-13 23:56:13 +00:00
|
|
|
{
|
|
|
|
u8 buf[256];
|
2008-05-26 10:46:16 +00:00
|
|
|
int r, err = 1;
|
2002-01-13 23:56:13 +00:00
|
|
|
size_t count = 0;
|
2005-01-21 18:47:41 +00:00
|
|
|
unsigned int idx = 0;
|
2005-03-09 00:04:44 +00:00
|
|
|
sc_path_t path;
|
2008-05-26 10:46:16 +00:00
|
|
|
sc_file_t *file = NULL;
|
2002-01-13 23:56:13 +00:00
|
|
|
const char *filename;
|
|
|
|
FILE *outf = NULL;
|
2005-01-21 18:47:41 +00:00
|
|
|
|
|
|
|
if (argc < 1 || argc > 2)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (arg_to_path(argv[0], &path, 0) != 0)
|
2002-01-13 23:56:13 +00:00
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
if (argc == 2)
|
|
|
|
filename = argv[1];
|
2002-01-13 23:56:13 +00:00
|
|
|
else {
|
2002-01-15 18:54:53 +00:00
|
|
|
sprintf((char *) buf, "%02X%02X", path.value[0], path.value[1]);
|
|
|
|
filename = (char *) buf;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2003-07-18 09:32:41 +00:00
|
|
|
outf = fopen(filename, "rb");
|
2002-01-13 23:56:13 +00:00
|
|
|
if (outf == NULL) {
|
|
|
|
perror(filename);
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
count = file->size;
|
2002-01-13 23:56:13 +00:00
|
|
|
while (count) {
|
|
|
|
int c = count > sizeof(buf) ? sizeof(buf) : count;
|
|
|
|
|
|
|
|
r = fread(buf, 1, c, outf);
|
|
|
|
if (r < 0) {
|
|
|
|
perror("fread");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (r != c)
|
|
|
|
count = c = r;
|
|
|
|
r = sc_update_binary(card, idx, buf, c, 0);
|
|
|
|
if (r < 0) {
|
2002-02-20 09:56:47 +00:00
|
|
|
check_ret(r, SC_AC_OP_READ, "update failed", file);
|
2005-01-21 18:47:41 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
|
|
|
if (r != c) {
|
|
|
|
printf("expecting %d, wrote only %d bytes.\n", c, r);
|
2005-01-21 18:47:41 +00:00
|
|
|
goto err;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
|
|
|
idx += c;
|
|
|
|
count -= c;
|
|
|
|
}
|
|
|
|
printf("Total of %d bytes written.\n", idx);
|
2008-05-26 10:46:16 +00:00
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
err:
|
2008-05-26 10:46:16 +00:00
|
|
|
|
|
|
|
if (file)
|
|
|
|
sc_file_free(file);
|
|
|
|
if (outf)
|
|
|
|
fclose(outf);
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2005-02-04 18:10:23 +00:00
|
|
|
return -err;
|
2002-01-13 23:56:13 +00:00
|
|
|
usage:
|
2002-11-28 15:44:32 +00:00
|
|
|
printf("Usage: put <file id> [input file]\n");
|
2002-01-13 23:56:13 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_debug(int argc, char **argv)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
2005-01-21 18:47:41 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!argc)
|
|
|
|
printf("Current debug level is %d\n", ctx->debug);
|
|
|
|
else {
|
|
|
|
if (sscanf(argv[0], "%d", &i) != 1)
|
|
|
|
return -1;
|
|
|
|
printf("Debug level set to %d\n", i);
|
|
|
|
ctx->debug = i;
|
|
|
|
if (i) {
|
2010-10-20 12:33:07 +00:00
|
|
|
ctx->debug_file = stderr;
|
2005-01-21 18:47:41 +00:00
|
|
|
} else {
|
|
|
|
ctx->debug_file = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2002-03-15 10:40:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-05 15:04:35 +00:00
|
|
|
static int
|
|
|
|
do_erase(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (argc != 0)
|
|
|
|
goto usage;
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2002-04-05 15:04:35 +00:00
|
|
|
r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL);
|
|
|
|
if (r) {
|
|
|
|
printf("Failed to erase card: %s\n", sc_strerror (r));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
usage:
|
|
|
|
printf("Usage: erase\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2003-01-15 13:20:22 +00:00
|
|
|
static int
|
|
|
|
do_random(int argc, char **argv)
|
|
|
|
{
|
|
|
|
unsigned char buffer[128];
|
2005-01-21 18:47:41 +00:00
|
|
|
int r, count;
|
2003-01-15 13:20:22 +00:00
|
|
|
|
|
|
|
if (argc != 1)
|
|
|
|
goto usage;
|
|
|
|
|
|
|
|
count = atoi(argv[0]);
|
|
|
|
if (count < 0 || count > 128) {
|
|
|
|
printf("Number must be in range 0..128\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_get_challenge(card, buffer, count);
|
|
|
|
if (r < 0) {
|
|
|
|
printf("Failed to get random bytes: %s\n", sc_strerror(r));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-03-06 16:06:59 +00:00
|
|
|
util_hex_dump_asc(stdout, buffer, count, 0);
|
2003-01-15 13:20:22 +00:00
|
|
|
return 0;
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2003-01-15 13:20:22 +00:00
|
|
|
usage:
|
|
|
|
printf("Usage: random count\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_get_data(int argc, char **argv)
|
2003-10-30 17:04:50 +00:00
|
|
|
{
|
2005-01-21 18:47:41 +00:00
|
|
|
unsigned char buffer[256];
|
|
|
|
unsigned int tag;
|
|
|
|
FILE *fp;
|
|
|
|
int r;
|
2003-10-30 17:04:50 +00:00
|
|
|
|
|
|
|
if (argc != 1 && argc != 2)
|
|
|
|
goto usage;
|
|
|
|
|
|
|
|
tag = strtoul(argv[0], NULL, 16);
|
|
|
|
r = sc_get_data(card, tag, buffer, sizeof(buffer));
|
|
|
|
if (r < 0) {
|
|
|
|
printf("Failed to get data object: %s\n", sc_strerror(r));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc == 2) {
|
|
|
|
const char *filename = argv[1];
|
|
|
|
|
|
|
|
if (!(fp = fopen(filename, "w"))) {
|
|
|
|
perror(filename);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fwrite(buffer, r, 1, fp);
|
|
|
|
fclose(fp);
|
|
|
|
} else {
|
|
|
|
printf("Object %04x:\n", tag & 0xFFFF);
|
2008-03-06 16:06:59 +00:00
|
|
|
util_hex_dump_asc(stdout, buffer, r, 0);
|
2003-10-30 17:04:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2003-12-18 21:37:34 +00:00
|
|
|
usage: printf("Usage: do_get hex_tag [dest_file]\n");
|
2003-10-30 17:04:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_put_data(int argc, char **argv)
|
2003-10-30 17:04:50 +00:00
|
|
|
{
|
2003-12-18 21:37:34 +00:00
|
|
|
printf("Usage: do_put hex_tag source_file\n"
|
|
|
|
"or: do_put hex_tag aa:bb:cc\n"
|
|
|
|
"or: do_put hex_tag \"foobar...\"\n");
|
2003-10-30 17:04:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-09-27 18:19:17 +00:00
|
|
|
static int do_apdu(int argc, char **argv)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
u8 *p;
|
2010-07-01 12:31:52 +00:00
|
|
|
size_t len, len0, r, ii;
|
2007-09-27 18:19:17 +00:00
|
|
|
|
2010-07-01 12:31:52 +00:00
|
|
|
if (argc < 1) {
|
2007-09-27 18:19:17 +00:00
|
|
|
puts("Usage: apdu [apdu:hex:codes:...]");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-07-01 12:31:52 +00:00
|
|
|
for (ii = 0, len = 0; ii < argc; ii++) {
|
|
|
|
len0 = strlen(argv[ii]);
|
|
|
|
sc_hex_to_bin(argv[ii], buf + len, &len0);
|
|
|
|
len += len0;
|
|
|
|
}
|
|
|
|
|
2007-09-27 18:19:17 +00:00
|
|
|
if (len < 4) {
|
|
|
|
puts("APDU too short (must be at least 4 bytes)");
|
|
|
|
return 1;
|
|
|
|
}
|
2009-11-14 21:55:17 +00:00
|
|
|
len0 = len;
|
2007-09-27 18:19:17 +00:00
|
|
|
|
|
|
|
memset(&apdu, 0, sizeof(apdu));
|
|
|
|
p = buf;
|
|
|
|
apdu.cla = *p++;
|
|
|
|
apdu.ins = *p++;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
len -= apdu.lc;
|
|
|
|
p += apdu.lc;
|
|
|
|
if (len) {
|
|
|
|
apdu.le = *p++;
|
|
|
|
if (apdu.le == 0)
|
|
|
|
apdu.le = 256;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
} 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);
|
|
|
|
|
|
|
|
printf("Sending: ");
|
|
|
|
for (r = 0; r < len0; r++)
|
|
|
|
printf("%02X ", buf[r]);
|
|
|
|
printf("\n");
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
|
|
|
if (r) {
|
|
|
|
fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2,
|
|
|
|
apdu.resplen ? ":" : "");
|
|
|
|
if (apdu.resplen)
|
2008-03-06 16:06:59 +00:00
|
|
|
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
2007-09-27 18:19:17 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_asn1(int argc, char **argv)
|
|
|
|
{
|
2008-05-26 10:46:16 +00:00
|
|
|
int r, err = 1;
|
2007-09-27 18:19:17 +00:00
|
|
|
sc_path_t path;
|
2008-05-26 10:46:16 +00:00
|
|
|
sc_file_t *file = NULL;
|
2007-09-27 18:19:17 +00:00
|
|
|
int not_current = 1;
|
|
|
|
size_t len;
|
2008-05-26 10:46:16 +00:00
|
|
|
unsigned char *buf = NULL;
|
2007-09-27 18:19:17 +00:00
|
|
|
|
|
|
|
if (argc > 1) {
|
|
|
|
puts("Usage: asn1 [file_id]");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-05-26 10:46:16 +00:00
|
|
|
/* select file */
|
2007-09-27 18:19:17 +00:00
|
|
|
if (argc) {
|
|
|
|
if (arg_to_path(argv[0], &path, 1) != 0) {
|
|
|
|
puts("Invalid file path");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r) {
|
|
|
|
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2007-09-27 18:19:17 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
path = current_path;
|
|
|
|
file = current_file;
|
|
|
|
not_current = 0;
|
|
|
|
}
|
|
|
|
if (file->type != SC_FILE_TYPE_WORKING_EF) {
|
|
|
|
printf("only working EFs may be read\n");
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2007-09-27 18:19:17 +00:00
|
|
|
}
|
|
|
|
|
2008-05-26 10:46:16 +00:00
|
|
|
/* read */
|
2007-09-27 18:19:17 +00:00
|
|
|
if (file->ef_structure != SC_FILE_EF_TRANSPARENT) {
|
|
|
|
printf("only transparent file type is supported at the moment\n");
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2007-09-27 18:19:17 +00:00
|
|
|
}
|
|
|
|
len = file->size;
|
|
|
|
buf = calloc(1, len);
|
2008-05-26 10:46:16 +00:00
|
|
|
if (!buf) {
|
|
|
|
goto err;
|
|
|
|
}
|
2007-09-27 18:19:17 +00:00
|
|
|
r = sc_read_binary(card, 0, buf, len, 0);
|
|
|
|
if (r < 0) {
|
|
|
|
check_ret(r, SC_AC_OP_READ, "read failed", file);
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2007-09-27 18:19:17 +00:00
|
|
|
}
|
2008-05-26 10:46:16 +00:00
|
|
|
if ((size_t)r != len) {
|
2009-10-22 09:18:16 +00:00
|
|
|
printf("expecting %ld, got only %d bytes.\n", len, r);
|
2008-05-26 10:46:16 +00:00
|
|
|
goto err;
|
2007-09-27 18:19:17 +00:00
|
|
|
}
|
|
|
|
|
2008-05-26 10:46:16 +00:00
|
|
|
/* asn1 dump */
|
2007-09-27 18:19:17 +00:00
|
|
|
sc_asn1_print_tags(buf, len);
|
|
|
|
|
2008-05-26 10:46:16 +00:00
|
|
|
err = 0;
|
|
|
|
err:
|
|
|
|
if (buf)
|
|
|
|
free(buf);
|
2007-09-27 18:19:17 +00:00
|
|
|
if (not_current) {
|
2008-05-26 10:46:16 +00:00
|
|
|
if (file)
|
|
|
|
sc_file_free(file);
|
2010-08-20 22:51:42 +00:00
|
|
|
select_current_path_or_die();
|
2007-09-27 18:19:17 +00:00
|
|
|
}
|
2008-05-26 10:46:16 +00:00
|
|
|
return -err;
|
2007-09-27 18:19:17 +00:00
|
|
|
}
|
|
|
|
|
2005-02-04 18:10:23 +00:00
|
|
|
static int do_quit(int argc, char **argv)
|
2002-02-21 18:53:23 +00:00
|
|
|
{
|
|
|
|
die(0);
|
|
|
|
return 0;
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-21 12:01:39 +00:00
|
|
|
static struct command cmds[] = {
|
2002-02-21 18:53:23 +00:00
|
|
|
{ "ls", do_ls, "list all files in the current DF" },
|
|
|
|
{ "cd", do_cd, "change to another DF" },
|
|
|
|
{ "cat", do_cat, "print the contents of an EF" },
|
|
|
|
{ "info", do_info, "display attributes of card file" },
|
|
|
|
{ "create", do_create, "create a new EF" },
|
|
|
|
{ "delete", do_delete, "remove an EF/DF" },
|
2004-03-14 19:53:23 +00:00
|
|
|
{ "rm", do_delete, "remove an EF/DF" },
|
2002-02-21 18:53:23 +00:00
|
|
|
{ "verify", do_verify, "present a PIN or key to the card" },
|
2002-03-15 10:40:35 +00:00
|
|
|
{ "change", do_change, "change a PIN" },
|
2002-12-19 19:42:51 +00:00
|
|
|
{ "unblock", do_unblock, "unblock a PIN" },
|
2002-02-21 18:53:23 +00:00
|
|
|
{ "put", do_put, "copy a local file to the card" },
|
|
|
|
{ "get", do_get, "copy an EF to a local file" },
|
2003-11-03 06:54:30 +00:00
|
|
|
{ "do_get", do_get_data, "get a data object" },
|
|
|
|
{ "do_put", do_put_data, "put a data object" },
|
2002-02-21 18:53:23 +00:00
|
|
|
{ "mkdir", do_mkdir, "create a DF" },
|
2002-04-05 15:04:35 +00:00
|
|
|
{ "erase", do_erase, "erase card" },
|
2003-01-15 13:20:22 +00:00
|
|
|
{ "random", do_random, "obtain N random bytes from card" },
|
2002-02-21 18:53:23 +00:00
|
|
|
{ "quit", do_quit, "quit this program" },
|
2004-03-14 19:53:23 +00:00
|
|
|
{ "exit", do_quit, "quit this program" },
|
2004-06-24 17:25:23 +00:00
|
|
|
{ "update_record", do_update_record, "update record" },
|
|
|
|
{ "update_binary", do_update_binary, "update binary" },
|
2007-08-14 06:02:51 +00:00
|
|
|
{ "debug", do_debug, "set the debug level" },
|
2007-09-27 18:19:17 +00:00
|
|
|
{ "apdu", do_apdu, "send a custom apdu command" },
|
|
|
|
{ "asn1", do_asn1, "decode an asn1 file" },
|
2007-06-21 12:01:39 +00:00
|
|
|
{ NULL, NULL, NULL }
|
2002-02-21 18:53:23 +00:00
|
|
|
};
|
|
|
|
|
2007-06-21 12:01:39 +00:00
|
|
|
static void usage(void)
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
2002-02-21 18:53:23 +00:00
|
|
|
struct command *cmd;
|
|
|
|
|
2002-01-09 01:03:10 +00:00
|
|
|
printf("Supported commands:\n");
|
2002-02-21 18:53:23 +00:00
|
|
|
for (cmd = cmds; cmd->name; cmd++)
|
|
|
|
printf(" %-10s %s\n", cmd->name, cmd->help);
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
|
2002-03-15 10:40:35 +00:00
|
|
|
static int parse_line(char *in, char **argv, int maxargc)
|
2002-02-10 18:04:03 +00:00
|
|
|
{
|
|
|
|
int argc;
|
|
|
|
|
2002-03-15 10:40:35 +00:00
|
|
|
for (argc = 0; argc < maxargc; argc++) {
|
2002-02-10 18:04:03 +00:00
|
|
|
in += strspn(in, " \t\n");
|
|
|
|
if (*in == '\0')
|
|
|
|
return argc;
|
|
|
|
if (*in == '"') {
|
|
|
|
/* Parse quoted string */
|
|
|
|
argv[argc] = in++;
|
|
|
|
in += strcspn(in, "\"");
|
|
|
|
if (*in++ != '"')
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
/* White space delimited word */
|
|
|
|
argv[argc] = in;
|
|
|
|
in += strcspn(in, " \t\n");
|
|
|
|
}
|
|
|
|
if (*in != '\0')
|
|
|
|
*in++ = '\0';
|
|
|
|
}
|
|
|
|
return argc;
|
|
|
|
}
|
|
|
|
|
2002-03-18 13:24:06 +00:00
|
|
|
static char * my_readline(char *prompt)
|
2002-02-10 18:04:03 +00:00
|
|
|
{
|
2002-03-15 10:40:35 +00:00
|
|
|
static char buf[256];
|
2005-01-21 18:47:41 +00:00
|
|
|
static int initialized;
|
|
|
|
static int interactive;
|
2002-02-10 18:04:03 +00:00
|
|
|
|
2005-01-21 18:47:41 +00:00
|
|
|
if (!initialized) {
|
|
|
|
initialized = 1;
|
|
|
|
interactive = isatty(fileno(stdin));
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_READLINE
|
2005-01-21 18:47:41 +00:00
|
|
|
if (interactive)
|
|
|
|
using_history ();
|
2002-03-15 10:40:35 +00:00
|
|
|
#endif
|
2005-01-21 18:47:41 +00:00
|
|
|
}
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_READLINE
|
2005-01-21 18:47:41 +00:00
|
|
|
if (interactive) {
|
|
|
|
char *line = readline(prompt);
|
|
|
|
if (line && strlen(line) > 2 )
|
|
|
|
add_history(line);
|
|
|
|
return line;
|
|
|
|
}
|
2002-03-15 10:40:35 +00:00
|
|
|
#endif
|
2005-01-21 18:47:41 +00:00
|
|
|
/* Either we don't have readline or we are not running
|
|
|
|
interactively */
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifndef ENABLE_READLINE
|
2002-02-10 18:04:03 +00:00
|
|
|
printf("%s", prompt);
|
2002-03-15 10:40:35 +00:00
|
|
|
#endif
|
2002-02-10 18:04:03 +00:00
|
|
|
fflush(stdout);
|
|
|
|
if (fgets(buf, sizeof(buf), stdin) == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (strlen(buf) == 0)
|
|
|
|
return NULL;
|
|
|
|
if (buf[strlen(buf)-1] == '\n')
|
|
|
|
buf[strlen(buf)-1] = '\0';
|
2005-01-21 18:47:41 +00:00
|
|
|
return buf;
|
2002-02-10 18:04:03 +00:00
|
|
|
}
|
|
|
|
|
2002-01-20 21:20:09 +00:00
|
|
|
int main(int argc, char * const argv[])
|
2002-01-09 01:03:10 +00:00
|
|
|
{
|
2002-01-20 21:20:09 +00:00
|
|
|
int r, c, long_optind = 0, err = 0;
|
2002-03-15 10:40:35 +00:00
|
|
|
char *line;
|
2005-01-21 18:47:41 +00:00
|
|
|
int cargc;
|
2010-07-01 12:31:52 +00:00
|
|
|
char *cargv[260];
|
2006-02-07 20:14:43 +00:00
|
|
|
sc_context_param_t ctx_param;
|
2010-09-13 08:08:42 +00:00
|
|
|
int lcycle = SC_CARDCTRL_LIFECYCLE_ADMIN;
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2002-06-14 12:52:56 +00:00
|
|
|
printf("OpenSC Explorer version %s\n", sc_get_version());
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2002-01-20 21:20:09 +00:00
|
|
|
while (1) {
|
2010-08-20 22:51:39 +00:00
|
|
|
c = getopt_long(argc, argv, "r:c:vwm:", options, &long_optind);
|
2002-01-20 21:20:09 +00:00
|
|
|
if (c == -1)
|
|
|
|
break;
|
|
|
|
if (c == '?')
|
2008-03-06 16:06:59 +00:00
|
|
|
util_print_usage_and_die(app_name, options, option_help);
|
2002-01-20 21:20:09 +00:00
|
|
|
switch (c) {
|
|
|
|
case 'r':
|
2010-01-24 15:29:47 +00:00
|
|
|
opt_reader = optarg;
|
2002-01-20 21:20:09 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
opt_driver = optarg;
|
|
|
|
break;
|
2003-01-03 16:58:32 +00:00
|
|
|
case 'w':
|
|
|
|
opt_wait = 1;
|
|
|
|
break;
|
2004-06-13 20:13:12 +00:00
|
|
|
case 'v':
|
|
|
|
verbose++;
|
|
|
|
break;
|
2010-08-20 22:51:39 +00:00
|
|
|
case 'm':
|
2010-08-18 13:42:26 +00:00
|
|
|
opt_startfile = optarg;
|
|
|
|
break;
|
2002-01-20 21:20:09 +00:00
|
|
|
}
|
|
|
|
}
|
2002-03-15 10:40:35 +00:00
|
|
|
|
2006-02-07 20:14:43 +00:00
|
|
|
memset(&ctx_param, 0, sizeof(ctx_param));
|
|
|
|
ctx_param.ver = 0;
|
|
|
|
ctx_param.app_name = app_name;
|
|
|
|
|
|
|
|
r = sc_context_create(&ctx, &ctx_param);
|
2002-01-09 01:03:10 +00:00
|
|
|
if (r) {
|
2002-01-20 21:20:09 +00:00
|
|
|
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
|
2002-01-09 01:03:10 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2010-10-20 12:33:07 +00:00
|
|
|
|
|
|
|
if (verbose > 1) {
|
|
|
|
ctx->debug = verbose;
|
|
|
|
ctx->debug_file = stderr;
|
|
|
|
}
|
2003-01-03 16:58:32 +00:00
|
|
|
|
2002-01-20 21:20:09 +00:00
|
|
|
if (opt_driver != NULL) {
|
|
|
|
err = sc_set_card_driver(ctx, opt_driver);
|
|
|
|
if (err) {
|
|
|
|
fprintf(stderr, "Driver '%s' not found!\n", opt_driver);
|
|
|
|
err = 1;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
2003-01-03 16:58:32 +00:00
|
|
|
|
2010-01-24 15:29:47 +00:00
|
|
|
err = util_connect_card(ctx, &card, opt_reader, opt_wait, 0);
|
2003-01-03 16:58:32 +00:00
|
|
|
if (err)
|
2002-01-20 21:20:09 +00:00
|
|
|
goto end;
|
2003-01-03 16:58:32 +00:00
|
|
|
|
2010-08-18 13:42:26 +00:00
|
|
|
if (opt_startfile) {
|
2010-08-20 22:51:39 +00:00
|
|
|
if(*opt_startfile) {
|
|
|
|
char startpath[1024];
|
|
|
|
char *argv[] = { startpath };
|
2010-09-13 08:08:42 +00:00
|
|
|
|
|
|
|
strncpy(startpath, opt_startfile, sizeof(startpath)-1);
|
2010-08-18 13:42:26 +00:00
|
|
|
r = do_cd(1, argv);
|
2010-08-20 22:51:39 +00:00
|
|
|
if (r) {
|
|
|
|
printf("unable to select file %s: %s\n",
|
|
|
|
opt_startfile, sc_strerror(r));
|
2010-08-18 13:42:26 +00:00
|
|
|
return -1;
|
2010-08-20 22:51:39 +00:00
|
|
|
}
|
2010-08-18 13:42:26 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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;
|
|
|
|
}
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
2010-09-13 08:08:42 +00:00
|
|
|
|
|
|
|
r = sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &lcycle);
|
|
|
|
if (r && r != SC_ERROR_NOT_SUPPORTED)
|
|
|
|
printf("unable to change lifecycle: %s\n", sc_strerror(r));
|
|
|
|
|
2002-01-09 01:03:10 +00:00
|
|
|
while (1) {
|
2005-02-04 18:10:23 +00:00
|
|
|
struct command *cmd;
|
|
|
|
size_t i;
|
2002-02-10 18:04:03 +00:00
|
|
|
char prompt[40];
|
2002-01-09 01:03:10 +00:00
|
|
|
|
2002-02-10 18:04:03 +00:00
|
|
|
sprintf(prompt, "OpenSC [");
|
2002-01-09 01:03:10 +00:00
|
|
|
for (i = 0; i < current_path.len; i++) {
|
2006-10-30 18:51:48 +00:00
|
|
|
if ((i & 1) == 0 && i && current_path.type != SC_PATH_TYPE_DF_NAME)
|
2002-02-10 18:04:03 +00:00
|
|
|
sprintf(prompt+strlen(prompt), "/");
|
2002-03-15 10:40:35 +00:00
|
|
|
sprintf(prompt+strlen(prompt), "%02X",
|
2005-01-21 18:47:41 +00:00
|
|
|
current_path.value[i]);
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
2005-01-21 18:47:41 +00:00
|
|
|
sprintf(prompt+strlen(prompt), "]> ");
|
2002-03-15 10:40:35 +00:00
|
|
|
line = my_readline(prompt);
|
2005-01-21 18:47:41 +00:00
|
|
|
if (line == NULL)
|
|
|
|
break;
|
|
|
|
cargc = parse_line(line, cargv, DIM(cargv));
|
2002-03-15 10:40:35 +00:00
|
|
|
if (cargc < 1)
|
2002-01-09 01:03:10 +00:00
|
|
|
continue;
|
2005-02-04 18:10:23 +00:00
|
|
|
for (r=cargc; r < (int)DIM(cargv); r++)
|
2002-03-15 10:40:35 +00:00
|
|
|
cargv[r] = "";
|
2005-02-04 18:10:23 +00:00
|
|
|
cmd = ambiguous_match(cmds, cargv[0]);
|
|
|
|
if (cmd == NULL) {
|
2002-01-09 01:03:10 +00:00
|
|
|
usage();
|
2002-02-21 18:53:23 +00:00
|
|
|
} else {
|
2005-02-04 18:10:23 +00:00
|
|
|
cmd->func(cargc-1, cargv+1);
|
2002-01-09 01:03:10 +00:00
|
|
|
}
|
|
|
|
}
|
2002-01-20 21:20:09 +00:00
|
|
|
end:
|
|
|
|
die(err);
|
2002-01-09 01:03:10 +00:00
|
|
|
|
|
|
|
return 0; /* not reached */
|
|
|
|
}
|