2001-11-22 15:40:51 +00:00
|
|
|
|
/*
|
2001-12-30 21:30:39 +00:00
|
|
|
|
* opensc-tool.c: Tool for accessing SmartCards with libopensc
|
2001-11-22 15:40:51 +00:00
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2001 Juha Yrj<EFBFBD>l<EFBFBD> <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
|
|
|
|
|
*/
|
2001-11-18 01:52:32 +00:00
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdio.h>
|
2001-11-18 01:52:32 +00:00
|
|
|
|
#include <stdlib.h>
|
2001-12-30 21:17:34 +00:00
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#ifdef HAVE_GETOPT_H
|
2001-11-18 01:52:32 +00:00
|
|
|
|
#include <getopt.h>
|
2001-12-30 21:17:34 +00:00
|
|
|
|
#endif
|
2001-11-18 01:52:32 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <string.h>
|
2001-11-24 13:32:52 +00:00
|
|
|
|
#include <opensc.h>
|
|
|
|
|
#include <opensc-pkcs15.h>
|
2001-12-11 14:53:22 +00:00
|
|
|
|
#include <sys/stat.h>
|
2001-12-25 20:45:48 +00:00
|
|
|
|
#include <ctype.h>
|
2001-11-18 01:52:32 +00:00
|
|
|
|
|
2001-12-29 02:07:32 +00:00
|
|
|
|
#include "util.h"
|
2001-12-28 14:19:41 +00:00
|
|
|
|
|
2001-11-18 01:52:32 +00:00
|
|
|
|
#define OPT_CHANGE_PIN 0x100
|
|
|
|
|
#define OPT_LIST_PINS 0x101
|
2001-11-18 20:36:15 +00:00
|
|
|
|
#define OPT_READER 0x102
|
2001-11-30 11:57:21 +00:00
|
|
|
|
#define OPT_PIN_ID 0x103
|
2001-12-20 12:16:05 +00:00
|
|
|
|
#define OPT_NO_CACHE 0x104
|
2001-11-18 01:52:32 +00:00
|
|
|
|
|
2001-12-20 12:16:05 +00:00
|
|
|
|
int opt_reader = 0, opt_no_cache = 0, opt_debug = 0;
|
2001-11-30 11:57:21 +00:00
|
|
|
|
char * opt_pin_id;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
char * opt_cert = NULL;
|
|
|
|
|
char * opt_outfile = NULL;
|
|
|
|
|
char * opt_newpin = NULL;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
char * opt_apdu = NULL;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
int quiet = 0;
|
|
|
|
|
|
|
|
|
|
const struct option options[] = {
|
|
|
|
|
{ "list-readers", 0, 0, 'l' },
|
2001-12-25 20:45:48 +00:00
|
|
|
|
{ "list-drivers", 0, 0, 'D' },
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{ "list-files", 0, 0, 'f' },
|
2001-12-11 14:53:22 +00:00
|
|
|
|
{ "learn-card", 0, 0, 'L' },
|
2001-11-20 22:21:58 +00:00
|
|
|
|
{ "send-apdu", 1, 0, 's' },
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{ "read-certificate", 1, 0, 'r' },
|
|
|
|
|
{ "list-certificates", 0, 0, 'c' },
|
|
|
|
|
{ "list-pins", 0, 0, OPT_LIST_PINS },
|
2001-11-30 11:57:21 +00:00
|
|
|
|
{ "change-pin", 0, 0, OPT_CHANGE_PIN },
|
2001-11-20 22:21:58 +00:00
|
|
|
|
{ "list-private-keys", 0, 0, 'k' },
|
2001-11-18 20:36:15 +00:00
|
|
|
|
{ "reader", 1, 0, OPT_READER },
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{ "output", 1, 0, 'o' },
|
|
|
|
|
{ "quiet", 0, 0, 'q' },
|
2001-11-20 22:21:58 +00:00
|
|
|
|
{ "debug", 0, 0, 'd' },
|
2001-12-20 12:16:05 +00:00
|
|
|
|
{ "no-cache", 0, 0, OPT_NO_CACHE },
|
2001-11-30 11:57:21 +00:00
|
|
|
|
{ "pin-id", 1, 0, 'p' },
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *option_help[] = {
|
|
|
|
|
"Lists all configured readers",
|
2001-12-25 20:45:48 +00:00
|
|
|
|
"Lists all installed card drivers",
|
2001-11-18 01:52:32 +00:00
|
|
|
|
"Recursively lists files stored on card",
|
2001-12-11 14:53:22 +00:00
|
|
|
|
"Stores card info to cache [P15]",
|
2001-11-20 22:21:58 +00:00
|
|
|
|
"Sends an APDU in format AA:BB:CC:DD:EE:FF...",
|
|
|
|
|
"Reads certificate with ID <arg> [P15]",
|
|
|
|
|
"Lists certificates [P15]",
|
|
|
|
|
"Lists PIN codes [P15]",
|
2001-11-30 11:57:21 +00:00
|
|
|
|
"Changes the PIN code [P15]",
|
2001-11-20 22:21:58 +00:00
|
|
|
|
"Lists private keys [P15]",
|
2001-11-18 01:52:32 +00:00
|
|
|
|
"Uses reader number <arg>",
|
|
|
|
|
"Outputs to file <arg>",
|
|
|
|
|
"Quiet operation",
|
2001-11-21 22:40:27 +00:00
|
|
|
|
"Debug output -- may be supplied several times",
|
2001-12-20 12:16:05 +00:00
|
|
|
|
"Disable card caching",
|
2001-11-20 22:21:58 +00:00
|
|
|
|
"The auth ID of the PIN to use [P15]",
|
2001-11-18 01:52:32 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct sc_context *ctx = NULL;
|
|
|
|
|
struct sc_card *card = NULL;
|
|
|
|
|
struct sc_pkcs15_card *p15card = NULL;
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
void print_usage_and_die(void)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
2001-12-30 21:30:39 +00:00
|
|
|
|
printf("Usage: opensc-tool [OPTIONS]\nOptions:\n");
|
2001-11-18 01:52:32 +00:00
|
|
|
|
|
|
|
|
|
while (options[i].name) {
|
|
|
|
|
char buf[40], tmp[5];
|
|
|
|
|
const char *arg_str;
|
|
|
|
|
|
|
|
|
|
if (options[i].val > 0 && options[i].val < 128)
|
|
|
|
|
sprintf(tmp, ", -%c", options[i].val);
|
|
|
|
|
else
|
|
|
|
|
tmp[0] = 0;
|
|
|
|
|
switch (options[i].has_arg) {
|
|
|
|
|
case 1:
|
|
|
|
|
arg_str = " <arg>";
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
arg_str = " [arg]";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
arg_str = "";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sprintf(buf, "--%s%s%s", options[i].name, tmp, arg_str);
|
|
|
|
|
printf(" %-30s%s\n", buf, option_help[i]);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
exit(2);
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int list_readers(void)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2001-12-25 20:45:48 +00:00
|
|
|
|
if (ctx->reader_count == 0) {
|
|
|
|
|
printf("No readers configured!\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-11-18 01:52:32 +00:00
|
|
|
|
printf("Configured readers:\n");
|
|
|
|
|
for (i = 0; i < ctx->reader_count; i++) {
|
|
|
|
|
printf("\t%d - %s\n", i, ctx->readers[i]);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int list_drivers(void)
|
2001-12-25 20:45:48 +00:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (ctx->card_drivers[0] == NULL) {
|
|
|
|
|
printf("No card drivers installed!\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
printf("Configured card drivers:\n");
|
|
|
|
|
for (i = 0; ctx->card_drivers[i] != NULL; i++) {
|
|
|
|
|
printf("\t%s\n", ctx->card_drivers[i]->name);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int list_certificates(void)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_enum_certificates(p15card);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (!quiet)
|
|
|
|
|
printf("Card has %d certificate(s).\n\n", p15card->cert_count);
|
|
|
|
|
for (i = 0; i < p15card->cert_count; i++) {
|
|
|
|
|
struct sc_pkcs15_cert_info *cinfo = &p15card->cert_info[i];
|
|
|
|
|
sc_pkcs15_print_cert_info(cinfo);
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-20 22:21:58 +00:00
|
|
|
|
int print_pem_certificate(struct sc_pkcs15_cert *cert)
|
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
u8 buf[2048];
|
|
|
|
|
FILE *outf;
|
|
|
|
|
|
|
|
|
|
r = sc_base64_encode(cert->data, cert->data_len, buf,
|
|
|
|
|
sizeof(buf), 64);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Base64 encoding failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (opt_outfile != NULL) {
|
|
|
|
|
outf = fopen(opt_outfile, "w");
|
|
|
|
|
if (outf == NULL) {
|
|
|
|
|
fprintf(stderr, "Error opening file '%s': %s\n",
|
|
|
|
|
opt_outfile, strerror(errno));
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
outf = stdout;
|
|
|
|
|
fprintf(outf, "-----BEGIN CERTIFICATE-----\n%s-----END CERTIFICATE-----\n",
|
|
|
|
|
buf);
|
|
|
|
|
if (outf != stdout)
|
|
|
|
|
fclose(outf);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int read_certificate(void)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
|
|
|
|
struct sc_pkcs15_id id;
|
|
|
|
|
|
2001-11-20 22:21:58 +00:00
|
|
|
|
id.len = SC_PKCS15_MAX_ID_SIZE;
|
|
|
|
|
sc_pkcs15_hex_string_to_id(opt_cert, &id);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_enum_certificates(p15card);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2001-11-20 22:21:58 +00:00
|
|
|
|
|
2001-11-18 01:52:32 +00:00
|
|
|
|
for (i = 0; i < p15card->cert_count; i++) {
|
|
|
|
|
struct sc_pkcs15_cert_info *cinfo = &p15card->cert_info[i];
|
|
|
|
|
struct sc_pkcs15_cert *cert;
|
|
|
|
|
|
|
|
|
|
if (sc_pkcs15_compare_id(&id, &cinfo->id) != 1)
|
|
|
|
|
continue;
|
|
|
|
|
|
2001-11-20 22:21:58 +00:00
|
|
|
|
if (!quiet)
|
|
|
|
|
printf("Reading certificate with ID '%s'\n", opt_cert);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Certificate read failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2001-11-20 22:21:58 +00:00
|
|
|
|
r = print_pem_certificate(cert);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
2001-11-20 22:21:58 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "Certificate with ID '%s' not found.\n", opt_cert);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int list_private_keys(void)
|
2001-11-20 22:21:58 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_enum_private_keys(p15card);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Private key enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (!quiet)
|
|
|
|
|
printf("Card has %d private key(s).\n\n", p15card->prkey_count);
|
|
|
|
|
for (i = 0; i < p15card->prkey_count; i++) {
|
|
|
|
|
struct sc_pkcs15_prkey_info *pinfo = &p15card->prkey_info[i];
|
|
|
|
|
sc_pkcs15_print_prkey_info(pinfo);
|
|
|
|
|
printf("\n");
|
2001-11-18 01:52:32 +00:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
u8 * get_pin(const char *prompt, struct sc_pkcs15_pin_info **pin_out)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
char buf[80];
|
|
|
|
|
char *pincode;
|
|
|
|
|
struct sc_pkcs15_pin_info *pinfo;
|
|
|
|
|
|
2001-11-30 11:57:21 +00:00
|
|
|
|
if (pin_out != NULL)
|
|
|
|
|
pinfo = *pin_out;
|
|
|
|
|
|
|
|
|
|
if (pinfo == NULL && opt_pin_id == NULL) {
|
|
|
|
|
r = sc_pkcs15_enum_pins(p15card);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "PIN code enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (r == 0) {
|
|
|
|
|
fprintf(stderr, "No PIN codes found.\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
pinfo = &p15card->pin_info[0];
|
|
|
|
|
} else if (pinfo == NULL) {
|
|
|
|
|
struct sc_pkcs15_id pin_id;
|
|
|
|
|
|
|
|
|
|
sc_pkcs15_hex_string_to_id(opt_pin_id, &pin_id);
|
|
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &pin_id, &pinfo);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Unable to find PIN code: %s\n", sc_strerror(r));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2001-11-18 01:52:32 +00:00
|
|
|
|
}
|
2001-11-30 11:57:21 +00:00
|
|
|
|
|
|
|
|
|
if (pin_out != NULL)
|
|
|
|
|
*pin_out = pinfo;
|
|
|
|
|
|
|
|
|
|
sprintf(buf, "%s [%s]: ", prompt, pinfo->com_attr.label);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
while (1) {
|
|
|
|
|
pincode = getpass(buf);
|
|
|
|
|
if (strlen(pincode) == 0)
|
|
|
|
|
return NULL;
|
2001-11-30 11:57:21 +00:00
|
|
|
|
if (strlen(pincode) < pinfo->min_length) {
|
|
|
|
|
printf("PIN code too short, try again.\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (strlen(pincode) > pinfo->stored_length) {
|
|
|
|
|
printf("PIN code too long, try again.\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2001-12-30 21:17:34 +00:00
|
|
|
|
return (u8 *) strdup(pincode);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int list_pins(void)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_enum_pins(p15card);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "PIN code enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (!quiet)
|
|
|
|
|
printf("Card has %d PIN code(s).\n\n", p15card->pin_count);
|
|
|
|
|
for (i = 0; i < p15card->pin_count; i++) {
|
|
|
|
|
struct sc_pkcs15_pin_info *pinfo = &p15card->pin_info[i];
|
|
|
|
|
sc_pkcs15_print_pin_info(pinfo);
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int change_pin(void)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
2001-11-30 11:57:21 +00:00
|
|
|
|
struct sc_pkcs15_pin_info *pinfo = NULL;
|
2001-12-30 21:17:34 +00:00
|
|
|
|
u8 *pincode, *newpin;
|
2001-11-30 11:57:21 +00:00
|
|
|
|
int r;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
|
2001-11-30 11:57:21 +00:00
|
|
|
|
pincode = get_pin("Enter old PIN", &pinfo);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (pincode == NULL)
|
|
|
|
|
return 2;
|
2001-12-30 21:17:34 +00:00
|
|
|
|
if (strlen((char *) pincode) == 0) {
|
2001-11-18 01:52:32 +00:00
|
|
|
|
fprintf(stderr, "No PIN code supplied.\n");
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2001-11-30 11:57:21 +00:00
|
|
|
|
while (1) {
|
2001-12-30 21:17:34 +00:00
|
|
|
|
u8 *newpin2;
|
|
|
|
|
|
2001-11-30 11:57:21 +00:00
|
|
|
|
newpin = get_pin("Enter new PIN", &pinfo);
|
2001-12-30 21:17:34 +00:00
|
|
|
|
if (newpin == NULL || strlen((char *) newpin) == 0)
|
2001-11-30 11:57:21 +00:00
|
|
|
|
return 2;
|
|
|
|
|
newpin2 = get_pin("Enter new PIN again", &pinfo);
|
2001-12-30 21:17:34 +00:00
|
|
|
|
if (newpin2 == NULL || strlen((char *) newpin2) == 0)
|
2001-11-30 11:57:21 +00:00
|
|
|
|
return 2;
|
2001-12-30 21:17:34 +00:00
|
|
|
|
if (strcmp((char *) newpin, (char *) newpin2) == 0) {
|
2001-11-30 11:57:21 +00:00
|
|
|
|
free(newpin2);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
printf("PIN codes do not match, try again.\n");
|
|
|
|
|
free(newpin);
|
|
|
|
|
free(newpin2);
|
|
|
|
|
}
|
2001-12-30 21:17:34 +00:00
|
|
|
|
r = sc_pkcs15_change_pin(p15card, pinfo, pincode, strlen((char *) pincode),
|
|
|
|
|
newpin, strlen((char *) newpin));
|
2001-11-30 11:57:21 +00:00
|
|
|
|
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
|
|
|
|
|
fprintf(stderr, "PIN code incorrect; tries left: %d\n", pinfo->tries_left);
|
|
|
|
|
return 3;
|
|
|
|
|
} else if (r) {
|
|
|
|
|
fprintf(stderr, "PIN code change failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
if (!quiet)
|
|
|
|
|
printf("PIN code changed successfully.\n");
|
2001-11-18 01:52:32 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-29 02:07:32 +00:00
|
|
|
|
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 ");
|
|
|
|
|
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)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
const char *tmps;
|
2001-12-29 02:07:32 +00:00
|
|
|
|
const char *ac_ops_df[] = {
|
|
|
|
|
"select", "lock", "delete", "create", "rehab", "inval"
|
|
|
|
|
};
|
|
|
|
|
const char *ac_ops_ef[] = {
|
|
|
|
|
"read", "update", "write", "erase", "rehab", "inval"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (r = 0; r < depth; r++)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
printf(" ");
|
2001-12-29 02:07:32 +00:00
|
|
|
|
for (r = 0; r < path->len; r++) {
|
|
|
|
|
printf("%02X", path->value[r]);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (r && (r & 1) == 1)
|
|
|
|
|
printf(" ");
|
|
|
|
|
}
|
2001-12-29 02:07:32 +00:00
|
|
|
|
if (file->namelen) {
|
|
|
|
|
printf("[");
|
|
|
|
|
print_binary(stdout, file->name, file->namelen);
|
|
|
|
|
printf("] ");
|
|
|
|
|
}
|
|
|
|
|
switch (file->type) {
|
|
|
|
|
case SC_FILE_TYPE_WORKING_EF:
|
|
|
|
|
tmps = "wEF";
|
|
|
|
|
break;
|
|
|
|
|
case SC_FILE_TYPE_INTERNAL_EF:
|
|
|
|
|
tmps = "iEF";
|
|
|
|
|
break;
|
|
|
|
|
case SC_FILE_TYPE_DF:
|
|
|
|
|
tmps = " DF";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tmps = "unknown";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
printf("type: %-3s, ", tmps);
|
|
|
|
|
if (file->type != SC_FILE_TYPE_DF) {
|
|
|
|
|
const char *structs[] = {
|
|
|
|
|
"unknown", "transpnt", "linrfix", "linrfix(TLV)",
|
|
|
|
|
"linvar", "linvar(TLV)", "lincyc", "lincyc(TLV)"
|
|
|
|
|
};
|
|
|
|
|
printf("ef structure: %s, ", structs[file->ef_structure]);
|
|
|
|
|
}
|
|
|
|
|
printf("size: %d\n", file->size);
|
|
|
|
|
for (r = 0; r < depth; r++)
|
|
|
|
|
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]));
|
|
|
|
|
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]));
|
|
|
|
|
|
|
|
|
|
if (file->sec_attr_len) {
|
|
|
|
|
printf("sec: ");
|
|
|
|
|
/* Octets are as follows:
|
|
|
|
|
* DF: select, lock, delete, create, rehab, inval
|
|
|
|
|
* EF: read, update, write, erase, rehab, inval
|
|
|
|
|
* 4 MSB's of the octet mean:
|
|
|
|
|
* 0 = ALW, 1 = PIN1, 2 = PIN2, 4 = SYS,
|
|
|
|
|
* 15 = NEV */
|
|
|
|
|
hex_dump(stdout, file->sec_attr, file->sec_attr_len);
|
|
|
|
|
}
|
|
|
|
|
if (file->prop_attr_len) {
|
2001-12-20 12:16:05 +00:00
|
|
|
|
printf("\n");
|
2001-12-29 02:07:32 +00:00
|
|
|
|
for (r = 0; r < depth; r++)
|
|
|
|
|
printf(" ");
|
|
|
|
|
printf("prop: ");
|
|
|
|
|
hex_dump(stdout, file->prop_attr, file->prop_attr_len);
|
|
|
|
|
}
|
|
|
|
|
printf("\n\n");
|
|
|
|
|
#if 0
|
|
|
|
|
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);
|
|
|
|
|
} else {
|
|
|
|
|
r = sc_read_record(card, 0, buf, file->size, 0);
|
2001-12-27 17:25:10 +00:00
|
|
|
|
if (r > 0)
|
2001-12-29 02:07:32 +00:00
|
|
|
|
hex_dump_asc(stdout, buf, r);
|
2001-12-27 17:25:10 +00:00
|
|
|
|
}
|
2001-11-18 01:52:32 +00:00
|
|
|
|
}
|
2001-12-29 02:07:32 +00:00
|
|
|
|
#endif
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int enum_dir(struct sc_path path, int depth)
|
|
|
|
|
{
|
|
|
|
|
struct sc_file file;
|
|
|
|
|
int r;
|
|
|
|
|
u8 files[MAX_BUFFER_SIZE];
|
|
|
|
|
|
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "SELECT FILE failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (sc_file_valid(&file))
|
|
|
|
|
print_file(card, &file, &path, depth);
|
2001-12-27 17:25:10 +00:00
|
|
|
|
if (!sc_file_valid(&file) || file.type == SC_FILE_TYPE_DF) {
|
2001-11-18 01:52:32 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
r = sc_list_files(card, files, sizeof(files));
|
|
|
|
|
if (r <= 0) {
|
|
|
|
|
fprintf(stderr, "sc_list_files() failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < r/2; i++) {
|
|
|
|
|
struct sc_path tmppath;
|
|
|
|
|
|
|
|
|
|
memcpy(&tmppath, &path, sizeof(path));
|
|
|
|
|
memcpy(tmppath.value + tmppath.len, files + 2*i, 2);
|
|
|
|
|
tmppath.len += 2;
|
|
|
|
|
enum_dir(tmppath, depth + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int list_files(void)
|
2001-11-18 01:52:32 +00:00
|
|
|
|
{
|
|
|
|
|
struct sc_path path;
|
|
|
|
|
int r;
|
|
|
|
|
|
2001-12-22 20:52:57 +00:00
|
|
|
|
sc_format_path("3F00", &path);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
r = enum_dir(path, 0);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-11 14:53:22 +00:00
|
|
|
|
static int generate_cert_filename(struct sc_pkcs15_card *p15card,
|
|
|
|
|
const struct sc_pkcs15_cert_info *info,
|
|
|
|
|
char *fname, int len)
|
|
|
|
|
{
|
|
|
|
|
char *homedir;
|
2001-12-30 21:17:34 +00:00
|
|
|
|
char cert_id[SC_PKCS15_MAX_ID_SIZE*2+1];
|
2001-12-11 14:53:22 +00:00
|
|
|
|
int i, r;
|
|
|
|
|
|
|
|
|
|
homedir = getenv("HOME");
|
|
|
|
|
if (homedir == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
cert_id[0] = 0;
|
|
|
|
|
for (i = 0; i < info->id.len; i++) {
|
|
|
|
|
char tmp[3];
|
|
|
|
|
|
|
|
|
|
sprintf(tmp, "%02X", info->id.value[i]);
|
|
|
|
|
strcat(cert_id, tmp);
|
|
|
|
|
}
|
|
|
|
|
r = snprintf(fname, len, "%s/%s/%s_%s_%s.crt", homedir,
|
|
|
|
|
SC_PKCS15_CACHE_DIR, p15card->label,
|
|
|
|
|
p15card->serial_number, cert_id);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int learn_card(void)
|
2001-12-11 14:53:22 +00:00
|
|
|
|
{
|
|
|
|
|
struct stat stbuf;
|
|
|
|
|
char fname[512], *home;
|
|
|
|
|
int r, i;
|
|
|
|
|
|
|
|
|
|
home = getenv("HOME");
|
|
|
|
|
if (home == NULL) {
|
|
|
|
|
fprintf(stderr, "No $HOME environment variable set.\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
sprintf(fname, "%s/%s", home, SC_PKCS15_CACHE_DIR);
|
|
|
|
|
r = stat(fname, &stbuf);
|
|
|
|
|
if (r) {
|
|
|
|
|
printf("No '%s' directory found, creating...\n", fname);
|
|
|
|
|
r = mkdir(fname, 0700);
|
|
|
|
|
if (r) {
|
|
|
|
|
perror("Directory creation failed");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("Using cache directory '%s'.\n", fname);
|
|
|
|
|
r = sc_pkcs15_enum_certificates(p15card);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("Caching %d certificate(s)...\n", r);
|
2001-12-22 20:52:57 +00:00
|
|
|
|
p15card->use_cache = 0;
|
2001-12-11 14:53:22 +00:00
|
|
|
|
for (i = 0; i < p15card->cert_count; i++) {
|
|
|
|
|
struct sc_pkcs15_cert_info *cinfo = &p15card->cert_info[i];
|
|
|
|
|
struct sc_pkcs15_cert *cert;
|
|
|
|
|
FILE *crtf;
|
|
|
|
|
|
|
|
|
|
printf("Reading certificate: %s...\n", cinfo->com_attr.label);
|
|
|
|
|
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Certificate read failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
r = generate_cert_filename(p15card, cinfo, fname, sizeof(fname));
|
|
|
|
|
if (r)
|
|
|
|
|
return 1;
|
|
|
|
|
crtf = fopen(fname, "w");
|
|
|
|
|
if (crtf == NULL) {
|
|
|
|
|
perror(fname);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
fwrite(cert->data, cert->data_len, 1, crtf);
|
|
|
|
|
fclose(crtf);
|
|
|
|
|
|
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 21:17:34 +00:00
|
|
|
|
int send_apdu(void)
|
2001-11-20 22:21:58 +00:00
|
|
|
|
{
|
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
|
u8 buf[MAX_BUFFER_SIZE], sbuf[MAX_BUFFER_SIZE],
|
|
|
|
|
rbuf[MAX_BUFFER_SIZE], *p = buf;
|
2001-12-30 21:17:34 +00:00
|
|
|
|
size_t len = sizeof(buf), len0, r;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
|
2001-12-25 20:45:48 +00:00
|
|
|
|
sc_hex_to_bin(opt_apdu, buf, &len0);
|
2001-12-20 12:16:05 +00:00
|
|
|
|
if (len < 4) {
|
|
|
|
|
fprintf(stderr, "APDU too short (must be at least 4 bytes).\n");
|
2001-11-20 22:21:58 +00:00
|
|
|
|
return 2;
|
|
|
|
|
}
|
2001-12-25 20:45:48 +00:00
|
|
|
|
len = len0;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
apdu.cla = *p++;
|
|
|
|
|
apdu.ins = *p++;
|
|
|
|
|
apdu.p1 = *p++;
|
|
|
|
|
apdu.p2 = *p++;
|
|
|
|
|
apdu.resp = rbuf;
|
|
|
|
|
apdu.resplen = sizeof(rbuf);
|
2001-12-20 12:16:05 +00:00
|
|
|
|
apdu.data = NULL;
|
|
|
|
|
apdu.datalen = 0;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
len -= 4;
|
|
|
|
|
if (len > 1) {
|
|
|
|
|
apdu.lc = *p++;
|
|
|
|
|
len--;
|
|
|
|
|
memcpy(sbuf, p, apdu.lc);
|
|
|
|
|
apdu.data = sbuf;
|
|
|
|
|
apdu.datalen = apdu.lc;
|
|
|
|
|
len -= apdu.lc;
|
2001-12-22 20:52:57 +00:00
|
|
|
|
if (len < 0) {
|
|
|
|
|
fprintf(stderr, "APDU too short (need %d bytes).\n",
|
|
|
|
|
-len);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2001-11-20 22:21:58 +00:00
|
|
|
|
if (len) {
|
|
|
|
|
apdu.le = *p++;
|
|
|
|
|
len--;
|
|
|
|
|
apdu.cse = SC_APDU_CASE_4_SHORT;
|
|
|
|
|
} else
|
|
|
|
|
apdu.cse = SC_APDU_CASE_3_SHORT;
|
|
|
|
|
if (len) {
|
|
|
|
|
fprintf(stderr, "APDU too long (%d bytes extra).\n", len);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
} else if (len == 1) {
|
|
|
|
|
apdu.le = *p++;
|
|
|
|
|
len--;
|
|
|
|
|
apdu.cse = SC_APDU_CASE_2_SHORT;
|
|
|
|
|
} else
|
|
|
|
|
apdu.cse = SC_APDU_CASE_1;
|
2001-12-25 20:45:48 +00:00
|
|
|
|
printf("Sending: ");
|
|
|
|
|
for (r = 0; r < len0; r++)
|
|
|
|
|
printf("%02X ", buf[r]);
|
|
|
|
|
printf("\n");
|
2002-01-03 07:33:28 +00:00
|
|
|
|
#if 0
|
|
|
|
|
ctx->debug = 5;
|
|
|
|
|
#endif
|
2001-11-20 22:21:58 +00:00
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2002-01-03 07:33:28 +00:00
|
|
|
|
#if 0
|
|
|
|
|
ctx->debug = opt_debug;
|
|
|
|
|
#endif
|
2001-11-20 22:21:58 +00:00
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2001-12-25 20:45:48 +00:00
|
|
|
|
printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2,
|
|
|
|
|
apdu.resplen ? ":" : "");
|
|
|
|
|
if (apdu.resplen)
|
2001-12-29 02:07:32 +00:00
|
|
|
|
hex_dump_asc(stdout, apdu.resp, apdu.resplen);
|
2001-11-20 22:21:58 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-18 01:52:32 +00:00
|
|
|
|
int main(int argc, char * const argv[])
|
|
|
|
|
{
|
|
|
|
|
int err = 0, r, c, long_optind = 0;
|
|
|
|
|
int do_list_readers = 0;
|
2001-12-25 20:45:48 +00:00
|
|
|
|
int do_list_drivers = 0;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
int do_read_cert = 0;
|
|
|
|
|
int do_list_certs = 0;
|
|
|
|
|
int do_list_pins = 0;
|
|
|
|
|
int do_list_files = 0;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
int do_list_prkeys = 0;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
int do_change_pin = 0;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
int do_send_apdu = 0;
|
2001-12-11 14:53:22 +00:00
|
|
|
|
int do_learn_card = 0;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
int action_count = 0;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2001-12-25 20:45:48 +00:00
|
|
|
|
c = getopt_long(argc, argv, "lfr:kco:qdp:s:LD", options, &long_optind);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (c == -1)
|
|
|
|
|
break;
|
|
|
|
|
if (c == '?')
|
2001-11-22 15:40:51 +00:00
|
|
|
|
print_usage_and_die();
|
2001-11-18 01:52:32 +00:00
|
|
|
|
switch (c) {
|
|
|
|
|
case 'r':
|
|
|
|
|
opt_cert = optarg;
|
|
|
|
|
do_read_cert = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case 'l':
|
|
|
|
|
do_list_readers = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2001-12-25 20:45:48 +00:00
|
|
|
|
case 'D':
|
|
|
|
|
do_list_drivers = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
case 'f':
|
|
|
|
|
do_list_files = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case 'c':
|
|
|
|
|
do_list_certs = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
case 's':
|
|
|
|
|
opt_apdu = optarg;
|
|
|
|
|
do_send_apdu++;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
case OPT_CHANGE_PIN:
|
|
|
|
|
do_change_pin = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case OPT_LIST_PINS:
|
|
|
|
|
do_list_pins = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
case 'k':
|
|
|
|
|
do_list_prkeys = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2001-12-11 14:53:22 +00:00
|
|
|
|
case 'L':
|
|
|
|
|
do_learn_card = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2001-11-18 20:36:15 +00:00
|
|
|
|
case OPT_READER:
|
|
|
|
|
opt_reader = atoi(optarg);
|
|
|
|
|
break;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
case 'o':
|
|
|
|
|
opt_outfile = optarg;
|
|
|
|
|
break;
|
|
|
|
|
case 'q':
|
|
|
|
|
quiet++;
|
|
|
|
|
break;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
case 'd':
|
2001-12-20 12:16:05 +00:00
|
|
|
|
opt_debug++;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
break;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
case 'p':
|
2001-11-30 11:57:21 +00:00
|
|
|
|
opt_pin_id = optarg;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
break;
|
2001-12-20 12:16:05 +00:00
|
|
|
|
case OPT_NO_CACHE:
|
|
|
|
|
opt_no_cache++;
|
|
|
|
|
break;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (action_count == 0)
|
|
|
|
|
print_usage_and_die();
|
|
|
|
|
r = sc_establish_context(&ctx);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2001-12-14 16:37:45 +00:00
|
|
|
|
ctx->use_std_output = 1;
|
2001-12-20 12:16:05 +00:00
|
|
|
|
ctx->debug = opt_debug;
|
|
|
|
|
if (opt_no_cache)
|
|
|
|
|
ctx->use_cache = 0;
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (do_list_readers) {
|
|
|
|
|
if ((err = list_readers()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2001-12-25 20:45:48 +00:00
|
|
|
|
if (do_list_drivers) {
|
|
|
|
|
if ((err = list_drivers()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (action_count <= 0)
|
|
|
|
|
goto end;
|
|
|
|
|
if (opt_reader >= ctx->reader_count || opt_reader < 0) {
|
|
|
|
|
fprintf(stderr, "Illegal reader number. Only %d reader(s) configured.\n", ctx->reader_count);
|
|
|
|
|
err = 1;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
if (sc_detect_card(ctx, opt_reader) != 1) {
|
|
|
|
|
fprintf(stderr, "Card not present.\n");
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
if (!quiet)
|
|
|
|
|
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
|
|
|
|
|
r = sc_connect_card(ctx, opt_reader, &card);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
|
|
|
|
|
err = 1;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
2001-12-29 02:07:32 +00:00
|
|
|
|
printf("Using card driver: %s\n", card->driver->name);
|
2001-12-25 20:45:48 +00:00
|
|
|
|
r = sc_lock(card);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Unable to lock card: %s\n", sc_strerror(r));
|
|
|
|
|
err = 1;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
2001-11-18 01:52:32 +00:00
|
|
|
|
|
2001-11-20 22:21:58 +00:00
|
|
|
|
if (do_send_apdu) {
|
|
|
|
|
if ((err = send_apdu()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (do_list_files) {
|
|
|
|
|
if ((err = list_files()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action_count <= 0)
|
|
|
|
|
goto end;
|
|
|
|
|
if (!quiet)
|
|
|
|
|
fprintf(stderr, "Trying to find a PKCS#15 compatible card...\n");
|
2001-12-22 20:52:57 +00:00
|
|
|
|
r = sc_pkcs15_bind(card, &p15card);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "PKCS#15 initialization failed: %s\n", sc_strerror(r));
|
|
|
|
|
err = 1;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
if (!quiet)
|
|
|
|
|
fprintf(stderr, "Found %s!\n", p15card->label);
|
2001-12-11 14:53:22 +00:00
|
|
|
|
if (do_learn_card) {
|
|
|
|
|
if ((err = learn_card()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (do_list_certs) {
|
|
|
|
|
if ((err = list_certificates()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
if (do_read_cert) {
|
|
|
|
|
if ((err = read_certificate()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2001-11-20 22:21:58 +00:00
|
|
|
|
if (do_list_prkeys) {
|
|
|
|
|
if ((err = list_private_keys()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (do_list_pins) {
|
|
|
|
|
if ((err = list_pins()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
if (do_change_pin) {
|
|
|
|
|
if ((err = change_pin()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
end:
|
|
|
|
|
if (p15card)
|
2001-12-22 20:52:57 +00:00
|
|
|
|
sc_pkcs15_unbind(p15card);
|
2001-11-18 01:52:32 +00:00
|
|
|
|
if (card) {
|
|
|
|
|
sc_unlock(card);
|
|
|
|
|
sc_disconnect_card(card);
|
|
|
|
|
}
|
|
|
|
|
if (ctx)
|
|
|
|
|
sc_destroy_context(ctx);
|
|
|
|
|
return err;
|
|
|
|
|
}
|