2002-01-20 21:20:09 +00:00
|
|
|
|
/*
|
2005-06-16 19:35:31 +00:00
|
|
|
|
* pkcs15-tool.c: Tool for poking with PKCS #15 smart cards
|
2002-01-20 21:20:09 +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
|
|
|
|
|
*/
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2002-02-25 16:30:38 +00:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
2005-06-15 08:57:47 +00:00
|
|
|
|
#ifdef HAVE_OPENSSL
|
2005-06-22 10:32:27 +00:00
|
|
|
|
#ifndef _WIN32
|
2005-06-15 08:57:47 +00:00
|
|
|
|
#include <asm/types.h>
|
|
|
|
|
#include <netinet/in.h>
|
2005-06-22 10:32:27 +00:00
|
|
|
|
#else
|
|
|
|
|
typedef unsigned long __u32;
|
|
|
|
|
#endif
|
2005-06-15 08:57:47 +00:00
|
|
|
|
#include <openssl/bn.h>
|
|
|
|
|
#include <openssl/crypto.h>
|
|
|
|
|
#endif
|
2003-01-09 09:14:15 +00:00
|
|
|
|
#include <limits.h>
|
2002-04-05 13:48:00 +00:00
|
|
|
|
#include <opensc/pkcs15.h>
|
2002-01-08 13:56:50 +00:00
|
|
|
|
#include "util.h"
|
|
|
|
|
|
2005-06-15 08:57:47 +00:00
|
|
|
|
|
2002-03-24 14:12:38 +00:00
|
|
|
|
const char *app_name = "pkcs15-tool";
|
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
|
int opt_reader = -1, opt_wait = 0;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
int opt_no_cache = 0;
|
2003-04-14 14:51:42 +00:00
|
|
|
|
char * opt_auth_id;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
char * opt_cert = NULL;
|
2003-10-02 09:21:17 +00:00
|
|
|
|
char * opt_data = NULL;
|
2002-03-14 16:57:20 +00:00
|
|
|
|
char * opt_pubkey = NULL;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
char * opt_outfile = NULL;
|
2003-12-18 21:37:34 +00:00
|
|
|
|
u8 * opt_newpin = NULL;
|
|
|
|
|
u8 * opt_pin = NULL;
|
|
|
|
|
u8 * opt_puk = NULL;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
|
static int verbose = 0;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2003-04-11 11:28:09 +00:00
|
|
|
|
enum {
|
|
|
|
|
OPT_CHANGE_PIN = 0x100,
|
|
|
|
|
OPT_LIST_PINS,
|
|
|
|
|
OPT_READER,
|
|
|
|
|
OPT_PIN_ID,
|
|
|
|
|
OPT_NO_CACHE,
|
|
|
|
|
OPT_LIST_PUB,
|
|
|
|
|
OPT_READ_PUB,
|
2005-06-15 08:57:47 +00:00
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
OPT_READ_SSH,
|
|
|
|
|
#endif
|
2003-05-17 10:54:27 +00:00
|
|
|
|
OPT_PIN,
|
2003-10-12 19:57:32 +00:00
|
|
|
|
OPT_NEWPIN,
|
|
|
|
|
OPT_PUK,
|
2003-04-11 11:28:09 +00:00
|
|
|
|
};
|
2002-03-14 16:57:20 +00:00
|
|
|
|
|
2002-12-04 11:56:51 +00:00
|
|
|
|
#define NELEMENTS(x) (sizeof(x)/sizeof((x)[0]))
|
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
static int authenticate(sc_pkcs15_object_t *obj);
|
2005-03-09 00:04:44 +00:00
|
|
|
|
static int pem_encode(sc_context_t *, int,
|
2003-11-20 15:42:10 +00:00
|
|
|
|
sc_pkcs15_der_t *, sc_pkcs15_der_t *);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
|
|
|
|
const struct option options[] = {
|
2003-08-08 08:34:02 +00:00
|
|
|
|
{ "learn-card", no_argument, 0, 'L' },
|
|
|
|
|
{ "read-certificate", required_argument, 0, 'r' },
|
2003-05-17 10:54:27 +00:00
|
|
|
|
{ "list-certificates", no_argument, 0, 'c' },
|
2003-08-08 08:34:02 +00:00
|
|
|
|
{ "read-data-object", required_argument, 0, 'R' },
|
2003-05-17 10:54:27 +00:00
|
|
|
|
{ "list-data-objects", no_argument, 0, 'C' },
|
|
|
|
|
{ "list-pins", no_argument, 0, OPT_LIST_PINS },
|
|
|
|
|
{ "unblock-pin", no_argument, 0, 'u' },
|
|
|
|
|
{ "change-pin", no_argument, 0, OPT_CHANGE_PIN },
|
2003-08-08 08:34:02 +00:00
|
|
|
|
{ "list-keys", no_argument, 0, 'k' },
|
2003-05-17 10:54:27 +00:00
|
|
|
|
{ "list-public-keys", no_argument, 0, OPT_LIST_PUB },
|
2003-08-08 08:34:02 +00:00
|
|
|
|
{ "read-public-key", required_argument, 0, OPT_READ_PUB },
|
2005-06-15 08:57:47 +00:00
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
{ "read-ssh-key", required_argument, 0, OPT_READ_SSH },
|
|
|
|
|
#endif
|
2003-08-08 08:34:02 +00:00
|
|
|
|
{ "reader", required_argument, 0, OPT_READER },
|
2003-05-17 10:54:27 +00:00
|
|
|
|
{ "pin", required_argument, 0, OPT_PIN },
|
2003-10-12 19:57:32 +00:00
|
|
|
|
{ "new-pin", required_argument, 0, OPT_NEWPIN },
|
|
|
|
|
{ "puk", required_argument, 0, OPT_PUK },
|
2003-08-08 08:34:02 +00:00
|
|
|
|
{ "output", required_argument, 0, 'o' },
|
2003-05-17 10:54:27 +00:00
|
|
|
|
{ "no-cache", no_argument, 0, OPT_NO_CACHE },
|
2003-08-08 08:34:02 +00:00
|
|
|
|
{ "auth-id", required_argument, 0, 'a' },
|
2003-05-17 10:54:27 +00:00
|
|
|
|
{ "wait", no_argument, 0, 'w' },
|
2004-06-13 20:13:12 +00:00
|
|
|
|
{ "verbose", no_argument, 0, 'v' },
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *option_help[] = {
|
|
|
|
|
"Stores card info to cache",
|
|
|
|
|
"Reads certificate with ID <arg>",
|
|
|
|
|
"Lists certificates",
|
2004-08-14 13:43:17 +00:00
|
|
|
|
"Reads data object with applicationName or OID <arg>",
|
2002-12-18 10:17:01 +00:00
|
|
|
|
"Lists data objects",
|
2002-01-08 13:56:50 +00:00
|
|
|
|
"Lists PIN codes",
|
2003-04-14 14:51:42 +00:00
|
|
|
|
"Unblock PIN code",
|
2002-01-08 13:56:50 +00:00
|
|
|
|
"Changes the PIN code",
|
|
|
|
|
"Lists private keys",
|
2002-03-14 16:57:20 +00:00
|
|
|
|
"Lists public keys",
|
|
|
|
|
"Reads public key with ID <arg>",
|
2005-06-15 08:57:47 +00:00
|
|
|
|
"Reads public key with ID <arg>, outputs ssh format",
|
2002-01-08 13:56:50 +00:00
|
|
|
|
"Uses reader number <arg>",
|
2003-10-12 19:57:32 +00:00
|
|
|
|
"Specify PIN",
|
|
|
|
|
"Specify New PIN (when changing or unblocking)",
|
|
|
|
|
"Specify Unblock PIN",
|
2002-01-08 13:56:50 +00:00
|
|
|
|
"Outputs to file <arg>",
|
|
|
|
|
"Disable card caching",
|
|
|
|
|
"The auth ID of the PIN to use",
|
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-08 13:56:50 +00:00
|
|
|
|
};
|
|
|
|
|
|
2005-03-09 00:04:44 +00:00
|
|
|
|
sc_context_t *ctx = NULL;
|
|
|
|
|
sc_card_t *card = NULL;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
struct sc_pkcs15_card *p15card = NULL;
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static void print_cert_info(const struct sc_pkcs15_object *obj)
|
2002-03-03 00:32:28 +00:00
|
|
|
|
{
|
2002-12-04 11:56:51 +00:00
|
|
|
|
unsigned int i;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
struct sc_pkcs15_cert_info *cert = (struct sc_pkcs15_cert_info *) obj->data;
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
|
|
|
|
printf("X.509 Certificate [%s]\n", obj->label);
|
|
|
|
|
printf("\tFlags : %d\n", obj->flags);
|
|
|
|
|
printf("\tAuthority: %s\n", cert->authority ? "yes" : "no");
|
|
|
|
|
printf("\tPath : ");
|
|
|
|
|
for (i = 0; i < cert->path.len; i++)
|
|
|
|
|
printf("%02X", cert->path.value[i]);
|
|
|
|
|
printf("\n");
|
2003-11-20 15:42:10 +00:00
|
|
|
|
printf("\tID : %s\n", sc_pkcs15_print_id(&cert->id));
|
2002-03-03 00:32:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int list_certificates(void)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2002-03-03 00:32:28 +00:00
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, objs, 32);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("Card has %d certificate(s).\n\n", r);
|
|
|
|
|
for (i = 0; i < r; i++) {
|
|
|
|
|
print_cert_info(objs[i]);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int
|
2002-03-14 16:57:20 +00:00
|
|
|
|
print_pem_object(const char *kind, const u8*data, size_t data_len)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
2004-01-27 09:03:15 +00:00
|
|
|
|
FILE *outf;
|
|
|
|
|
unsigned char *buf = NULL;
|
|
|
|
|
size_t buf_len = 1024;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
/* With base64, every 3 bytes yield 4 characters, and with
|
|
|
|
|
* 64 chars per line we know almost exactly how large a buffer we
|
|
|
|
|
* will need. */
|
|
|
|
|
buf_len = (data_len + 2) / 3 * 4;
|
|
|
|
|
buf_len += 2 * (buf_len / 64 + 2); /* certain platforms use CRLF */
|
|
|
|
|
buf_len += 64; /* slack for checksum etc */
|
|
|
|
|
|
|
|
|
|
if (!(buf = (unsigned char *) malloc(buf_len))) {
|
|
|
|
|
perror("print_pem_object");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sc_base64_encode(data, data_len, buf, buf_len, 64);
|
|
|
|
|
if (r < 0) {
|
2002-01-08 13:56:50 +00:00
|
|
|
|
fprintf(stderr, "Base64 encoding failed: %s\n", sc_strerror(r));
|
2004-01-27 09:03:15 +00:00
|
|
|
|
free(buf);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2004-01-27 09:03:15 +00:00
|
|
|
|
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (opt_outfile != NULL) {
|
|
|
|
|
outf = fopen(opt_outfile, "w");
|
|
|
|
|
if (outf == NULL) {
|
|
|
|
|
fprintf(stderr, "Error opening file '%s': %s\n",
|
|
|
|
|
opt_outfile, strerror(errno));
|
2004-01-27 09:03:15 +00:00
|
|
|
|
free(buf);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
outf = stdout;
|
2002-03-14 16:57:20 +00:00
|
|
|
|
fprintf(outf,
|
|
|
|
|
"-----BEGIN %s-----\n"
|
|
|
|
|
"%s"
|
|
|
|
|
"-----END %s-----\n",
|
|
|
|
|
kind, buf, kind);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (outf != stdout)
|
|
|
|
|
fclose(outf);
|
2004-01-27 09:03:15 +00:00
|
|
|
|
free(buf);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int
|
2002-12-18 10:17:01 +00:00
|
|
|
|
list_data_object(const char *kind, const u8*data, size_t data_len)
|
|
|
|
|
{
|
2005-02-04 22:52:13 +00:00
|
|
|
|
size_t i;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
|
|
printf("%s (%i bytes): <", kind, data_len);
|
|
|
|
|
for (i = 0; i < data_len; i++)
|
|
|
|
|
printf(" %02X", data[i]);
|
|
|
|
|
printf(" >\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int
|
2002-12-18 10:17:01 +00:00
|
|
|
|
print_data_object(const char *kind, const u8*data, size_t data_len)
|
|
|
|
|
{
|
2005-02-04 22:52:13 +00:00
|
|
|
|
size_t i;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
|
|
if (opt_outfile != NULL) {
|
|
|
|
|
FILE *outf;
|
|
|
|
|
outf = fopen(opt_outfile, "w");
|
|
|
|
|
if (outf == NULL) {
|
|
|
|
|
fprintf(stderr, "Error opening file '%s': %s\n",
|
|
|
|
|
opt_outfile, strerror(errno));
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
for (i=0; i < data_len; i++)
|
|
|
|
|
fprintf(outf, "%c", data[i]);
|
|
|
|
|
printf("Dumping (%i bytes) to file <%s>: <", data_len, opt_outfile);
|
|
|
|
|
for (i=0; i < data_len; i++)
|
|
|
|
|
printf(" %02X", data[i]);
|
|
|
|
|
printf(" >\n");
|
|
|
|
|
fclose(outf);
|
|
|
|
|
} else {
|
|
|
|
|
printf("%s (%i bytes): <", kind, data_len);
|
|
|
|
|
for (i=0; i < data_len; i++)
|
|
|
|
|
printf(" %02X", data[i]);
|
|
|
|
|
printf(" >\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int read_certificate(void)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
2002-03-03 00:32:28 +00:00
|
|
|
|
int r, i, count;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
struct sc_pkcs15_id id;
|
2002-03-03 00:32:28 +00:00
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
|
|
|
|
id.len = SC_PKCS15_MAX_ID_SIZE;
|
|
|
|
|
sc_pkcs15_hex_string_to_id(opt_cert, &id);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, objs, 32);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2002-03-03 00:32:28 +00:00
|
|
|
|
count = r;
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2002-04-19 14:23:31 +00:00
|
|
|
|
struct sc_pkcs15_cert_info *cinfo = (struct sc_pkcs15_cert_info *) objs[i]->data;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
struct sc_pkcs15_cert *cert;
|
|
|
|
|
|
|
|
|
|
if (sc_pkcs15_compare_id(&id, &cinfo->id) != 1)
|
|
|
|
|
continue;
|
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
printf("Reading certificate with ID '%s'\n", opt_cert);
|
|
|
|
|
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Certificate read failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2002-03-14 16:57:20 +00:00
|
|
|
|
r = print_pem_object("CERTIFICATE", cert->data, cert->data_len);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "Certificate with ID '%s' not found.\n", opt_cert);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int read_data_object(void)
|
2002-12-18 10:17:01 +00:00
|
|
|
|
{
|
2004-08-14 13:43:17 +00:00
|
|
|
|
int r, i, count, oid_len = 0;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
2004-08-14 13:43:17 +00:00
|
|
|
|
struct sc_object_id oid;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_DATA_OBJECT, objs, 32);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Data object enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
count = r;
|
2004-08-14 13:43:17 +00:00
|
|
|
|
|
|
|
|
|
r = parse_application_id(&oid, opt_data);
|
|
|
|
|
if (r == SC_SUCCESS) {
|
|
|
|
|
while (oid.value[oid_len] >= 0) oid_len++;
|
|
|
|
|
}
|
|
|
|
|
|
2002-12-18 10:17:01 +00:00
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
struct sc_pkcs15_data_info *cinfo = (struct sc_pkcs15_data_info *) objs[i]->data;
|
|
|
|
|
struct sc_pkcs15_data *data_object;
|
|
|
|
|
|
2004-08-14 13:43:17 +00:00
|
|
|
|
if (oid_len) {
|
|
|
|
|
if (memcmp(oid.value, cinfo->app_oid.value, sizeof(int) * oid_len))
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
if (memcmp(opt_data, &cinfo->app_label, strlen(opt_data)))
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2003-10-02 09:21:17 +00:00
|
|
|
|
printf("Reading data object with label '%s'\n", opt_data);
|
2002-12-18 10:17:01 +00:00
|
|
|
|
r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
r = print_data_object("Data Object", data_object->data, data_object->data_len);
|
|
|
|
|
sc_pkcs15_free_data_object(data_object);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2003-10-02 09:21:17 +00:00
|
|
|
|
fprintf(stderr, "Data object with label '%s' not found.\n", opt_data);
|
2002-12-18 10:17:01 +00:00
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int list_data_objects(void)
|
2002-12-18 10:17:01 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i, count;
|
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_DATA_OBJECT, objs, 32);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Data object enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
count = r;
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2004-07-26 19:18:17 +00:00
|
|
|
|
int idx;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
struct sc_pkcs15_data_info *cinfo = (struct sc_pkcs15_data_info *) objs[i]->data;
|
|
|
|
|
struct sc_pkcs15_data *data_object;
|
|
|
|
|
|
2004-07-26 19:18:17 +00:00
|
|
|
|
printf("Reading data object <%i>\n", i);
|
|
|
|
|
printf("applicationName: %s\n", cinfo->app_label);
|
|
|
|
|
printf("applicationOID: ");
|
|
|
|
|
if (cinfo->app_oid.value[0] >= 0) {
|
|
|
|
|
printf("%i", cinfo->app_oid.value[0]);
|
|
|
|
|
idx = 1;
|
|
|
|
|
while (idx < SC_MAX_OBJECT_ID_OCTETS) {
|
|
|
|
|
if (cinfo->app_oid.value[idx] < 0)
|
|
|
|
|
break;
|
|
|
|
|
printf(".%i", cinfo->app_oid.value[idx++]);
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
|
|
|
|
} else
|
|
|
|
|
printf("NONE\n");
|
2004-08-14 13:43:17 +00:00
|
|
|
|
printf("Path : %s\n", sc_print_path(&cinfo->path));
|
2002-12-18 10:17:01 +00:00
|
|
|
|
r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
r = list_data_object("Data Object", data_object->data, data_object->data_len);
|
|
|
|
|
sc_pkcs15_free_data_object(data_object);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static void print_prkey_info(const struct sc_pkcs15_object *obj)
|
2002-03-03 00:32:28 +00:00
|
|
|
|
{
|
2002-12-04 11:56:51 +00:00
|
|
|
|
unsigned int i;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
struct sc_pkcs15_prkey_info *prkey = (struct sc_pkcs15_prkey_info *) obj->data;
|
2002-03-03 00:32:28 +00:00
|
|
|
|
const char *usages[] = {
|
|
|
|
|
"encrypt", "decrypt", "sign", "signRecover",
|
|
|
|
|
"wrap", "unwrap", "verify", "verifyRecover",
|
|
|
|
|
"derive", "nonRepudiation"
|
|
|
|
|
};
|
2005-02-04 22:52:13 +00:00
|
|
|
|
const size_t usage_count = sizeof(usages)/sizeof(usages[0]);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
const char *access_flags[] = {
|
|
|
|
|
"sensitive", "extract", "alwaysSensitive",
|
|
|
|
|
"neverExtract", "local"
|
|
|
|
|
};
|
2002-12-04 11:56:51 +00:00
|
|
|
|
const unsigned int af_count = NELEMENTS(access_flags);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
|
|
|
|
printf("Private RSA Key [%s]\n", obj->label);
|
|
|
|
|
printf("\tCom. Flags : %X\n", obj->flags);
|
|
|
|
|
printf("\tUsage : [0x%X]", prkey->usage);
|
2005-02-11 20:09:34 +00:00
|
|
|
|
for (i = 0; i < usage_count; i++)
|
|
|
|
|
if (prkey->usage & (1 << i)) {
|
|
|
|
|
printf(", %s", usages[i]);
|
|
|
|
|
}
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("\n");
|
|
|
|
|
printf("\tAccess Flags: [0x%X]", prkey->access_flags);
|
2005-02-11 20:09:34 +00:00
|
|
|
|
for (i = 0; i < af_count; i++)
|
|
|
|
|
if (prkey->access_flags & (1 << i)) {
|
|
|
|
|
printf(", %s", access_flags[i]);
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("\tModLength : %d\n", prkey->modulus_length);
|
|
|
|
|
printf("\tKey ref : %d\n", prkey->key_reference);
|
|
|
|
|
printf("\tNative : %s\n", prkey->native ? "yes" : "no");
|
|
|
|
|
printf("\tPath : ");
|
|
|
|
|
for (i = 0; i < prkey->path.len; i++)
|
|
|
|
|
printf("%02X", prkey->path.value[i]);
|
|
|
|
|
printf("\n");
|
2003-11-20 15:42:10 +00:00
|
|
|
|
printf("\tAuth ID : %s\n", sc_pkcs15_print_id(&obj->auth_id));
|
|
|
|
|
printf("\tID : %s\n", sc_pkcs15_print_id(&prkey->id));
|
2002-03-03 00:32:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int list_private_keys(void)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
2002-03-03 00:32:28 +00:00
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2002-03-03 00:32:28 +00:00
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY_RSA, objs, 32);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Private key enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("Card has %d private key(s).\n\n", r);
|
|
|
|
|
for (i = 0; i < r; i++) {
|
|
|
|
|
print_prkey_info(objs[i]);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static void print_pubkey_info(const struct sc_pkcs15_object *obj)
|
2002-03-03 00:32:28 +00:00
|
|
|
|
{
|
2002-12-04 11:56:51 +00:00
|
|
|
|
unsigned int i;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
const struct sc_pkcs15_pubkey_info *pubkey = (const struct sc_pkcs15_pubkey_info *) obj->data;
|
2002-03-03 00:32:28 +00:00
|
|
|
|
const char *usages[] = {
|
|
|
|
|
"encrypt", "decrypt", "sign", "signRecover",
|
|
|
|
|
"wrap", "unwrap", "verify", "verifyRecover",
|
|
|
|
|
"derive", "nonRepudiation"
|
|
|
|
|
};
|
2002-12-04 11:56:51 +00:00
|
|
|
|
const unsigned int usage_count = NELEMENTS(usages);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
const char *access_flags[] = {
|
|
|
|
|
"sensitive", "extract", "alwaysSensitive",
|
|
|
|
|
"neverExtract", "local"
|
|
|
|
|
};
|
2002-12-04 11:56:51 +00:00
|
|
|
|
const unsigned int af_count = NELEMENTS(access_flags);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
|
|
|
|
printf("Public RSA Key [%s]\n", obj->label);
|
|
|
|
|
printf("\tCom. Flags : %X\n", obj->flags);
|
|
|
|
|
printf("\tUsage : [0x%X]", pubkey->usage);
|
2005-02-11 20:09:34 +00:00
|
|
|
|
for (i = 0; i < usage_count; i++)
|
|
|
|
|
if (pubkey->usage & (1 << i)) {
|
|
|
|
|
printf(", %s", usages[i]);
|
|
|
|
|
}
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("\n");
|
|
|
|
|
printf("\tAccess Flags: [0x%X]", pubkey->access_flags);
|
2005-02-11 20:09:34 +00:00
|
|
|
|
for (i = 0; i < af_count; i++)
|
|
|
|
|
if (pubkey->access_flags & (1 << i)) {
|
|
|
|
|
printf(", %s", access_flags[i]);
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("\tModLength : %d\n", pubkey->modulus_length);
|
|
|
|
|
printf("\tKey ref : %d\n", pubkey->key_reference);
|
|
|
|
|
printf("\tNative : %s\n", pubkey->native ? "yes" : "no");
|
|
|
|
|
printf("\tPath : ");
|
|
|
|
|
for (i = 0; i < pubkey->path.len; i++)
|
|
|
|
|
printf("%02X", pubkey->path.value[i]);
|
|
|
|
|
printf("\n");
|
2003-11-20 15:42:10 +00:00
|
|
|
|
printf("\tAuth ID : %s\n", sc_pkcs15_print_id(&obj->auth_id));
|
|
|
|
|
printf("\tID : %s\n", sc_pkcs15_print_id(&pubkey->id));
|
2002-03-03 00:32:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int list_public_keys(void)
|
2002-03-14 16:57:20 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
2002-03-14 16:57:20 +00:00
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PUBKEY_RSA, objs, 32);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Private key enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-03-14 16:57:20 +00:00
|
|
|
|
printf("Card has %d public key(s).\n\n", r);
|
|
|
|
|
for (i = 0; i < r; i++) {
|
|
|
|
|
print_pubkey_info(objs[i]);
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int read_public_key(void)
|
2002-03-14 16:57:20 +00:00
|
|
|
|
{
|
2002-12-10 14:22:26 +00:00
|
|
|
|
int r;
|
2002-03-14 16:57:20 +00:00
|
|
|
|
struct sc_pkcs15_id id;
|
2002-12-10 14:22:26 +00:00
|
|
|
|
struct sc_pkcs15_object *obj;
|
|
|
|
|
sc_pkcs15_pubkey_t *pubkey = NULL;
|
|
|
|
|
sc_pkcs15_cert_t *cert = NULL;
|
|
|
|
|
sc_pkcs15_der_t pem_key;
|
2002-03-14 16:57:20 +00:00
|
|
|
|
|
|
|
|
|
id.len = SC_PKCS15_MAX_ID_SIZE;
|
|
|
|
|
sc_pkcs15_hex_string_to_id(opt_pubkey, &id);
|
|
|
|
|
|
2002-12-10 14:22:26 +00:00
|
|
|
|
r = sc_pkcs15_find_pubkey_by_id(p15card, &id, &obj);
|
|
|
|
|
if (r >= 0) {
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-12-10 14:22:26 +00:00
|
|
|
|
printf("Reading public key with ID '%s'\n", opt_pubkey);
|
2003-11-20 15:42:10 +00:00
|
|
|
|
r = authenticate(obj);
|
|
|
|
|
if (r >= 0)
|
|
|
|
|
r = sc_pkcs15_read_pubkey(p15card, obj, &pubkey);
|
2002-12-10 14:22:26 +00:00
|
|
|
|
} else if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
|
|
|
|
/* No pubkey - try if there's a certificate */
|
|
|
|
|
r = sc_pkcs15_find_cert_by_id(p15card, &id, &obj);
|
|
|
|
|
if (r >= 0) {
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-12-10 14:22:26 +00:00
|
|
|
|
printf("Reading certificate with ID '%s'\n", opt_pubkey);
|
|
|
|
|
r = sc_pkcs15_read_certificate(p15card,
|
|
|
|
|
(sc_pkcs15_cert_info_t *) obj->data,
|
|
|
|
|
&cert);
|
|
|
|
|
}
|
|
|
|
|
if (r >= 0)
|
|
|
|
|
pubkey = &cert->key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
|
|
|
|
fprintf(stderr, "Public key with ID '%s' not found.\n", opt_pubkey);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2002-03-14 16:57:20 +00:00
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Public key enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-12-10 14:22:26 +00:00
|
|
|
|
r = pem_encode(ctx, pubkey->algorithm, &pubkey->data, &pem_key);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Error encoding PEM key: %s\n",
|
|
|
|
|
sc_strerror(r));
|
|
|
|
|
r = 1;
|
|
|
|
|
} else {
|
2002-04-17 12:20:31 +00:00
|
|
|
|
r = print_pem_object("PUBLIC KEY", pem_key.value, pem_key.len);
|
2002-03-14 16:57:20 +00:00
|
|
|
|
}
|
2002-12-10 14:22:26 +00:00
|
|
|
|
|
|
|
|
|
free(pem_key.value);
|
|
|
|
|
if (cert)
|
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
|
|
|
|
else if (pubkey)
|
|
|
|
|
sc_pkcs15_free_pubkey(pubkey);
|
|
|
|
|
|
|
|
|
|
return r;
|
2002-03-14 16:57:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-06-15 08:57:47 +00:00
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
static int read_ssh_key(void)
|
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
struct sc_pkcs15_id id;
|
|
|
|
|
struct sc_pkcs15_object *obj;
|
|
|
|
|
sc_pkcs15_pubkey_t *pubkey = NULL;
|
|
|
|
|
sc_pkcs15_cert_t *cert = NULL;
|
|
|
|
|
|
|
|
|
|
id.len = SC_PKCS15_MAX_ID_SIZE;
|
|
|
|
|
sc_pkcs15_hex_string_to_id(opt_pubkey, &id);
|
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_find_pubkey_by_id(p15card, &id, &obj);
|
|
|
|
|
if (r >= 0) {
|
|
|
|
|
if (verbose)
|
|
|
|
|
printf("Reading ssh key with ID '%s'\n", opt_pubkey);
|
|
|
|
|
r = authenticate(obj);
|
|
|
|
|
if (r >= 0)
|
|
|
|
|
r = sc_pkcs15_read_pubkey(p15card, obj, &pubkey);
|
|
|
|
|
} else if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
|
|
|
|
/* No pubkey - try if there's a certificate */
|
|
|
|
|
r = sc_pkcs15_find_cert_by_id(p15card, &id, &obj);
|
|
|
|
|
if (r >= 0) {
|
|
|
|
|
if (verbose)
|
|
|
|
|
printf("Reading certificate with ID '%s'\n", opt_pubkey);
|
|
|
|
|
r = sc_pkcs15_read_certificate(p15card,
|
|
|
|
|
(sc_pkcs15_cert_info_t *) obj->data,
|
|
|
|
|
&cert);
|
|
|
|
|
}
|
|
|
|
|
if (r >= 0)
|
|
|
|
|
pubkey = &cert->key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
|
|
|
|
fprintf(stderr, "Public key with ID '%s' not found.\n", opt_pubkey);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Public key enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* rsa1 keys */
|
|
|
|
|
if (pubkey->algorithm == SC_ALGORITHM_RSA) {
|
|
|
|
|
int bits;
|
|
|
|
|
BIGNUM *bn;
|
|
|
|
|
char *exp,*mod;
|
|
|
|
|
|
|
|
|
|
bn = BN_new();
|
|
|
|
|
BN_bin2bn((unsigned char*)pubkey->u.rsa.modulus.data,
|
|
|
|
|
pubkey->u.rsa.modulus.len, bn);
|
|
|
|
|
bits = BN_num_bits(bn);
|
|
|
|
|
exp = BN_bn2dec(bn);
|
|
|
|
|
BN_free(bn);
|
|
|
|
|
|
|
|
|
|
bn = BN_new();
|
|
|
|
|
BN_bin2bn((unsigned char*)pubkey->u.rsa.exponent.data,
|
|
|
|
|
pubkey->u.rsa.exponent.len, bn);
|
|
|
|
|
mod = BN_bn2dec(bn);
|
|
|
|
|
BN_free(bn);
|
|
|
|
|
|
|
|
|
|
if (bits && exp && mod) {
|
|
|
|
|
printf("%u %s %s\n", bits,mod,exp);
|
|
|
|
|
} else {
|
|
|
|
|
printf("decoding rsa key failed!\n");
|
|
|
|
|
}
|
|
|
|
|
OPENSSL_free(exp);
|
|
|
|
|
OPENSSL_free(mod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* rsa and des keys - ssh2 */
|
|
|
|
|
/* key_to_blob */
|
|
|
|
|
|
|
|
|
|
if (pubkey->algorithm == SC_ALGORITHM_RSA) {
|
|
|
|
|
char buf[2048];
|
|
|
|
|
char *uu;
|
|
|
|
|
__u32 len;
|
|
|
|
|
__u32 n;
|
|
|
|
|
|
|
|
|
|
buf[0]=0;
|
|
|
|
|
buf[1]=0;
|
|
|
|
|
buf[2]=0;
|
|
|
|
|
buf[3]=7;
|
|
|
|
|
|
|
|
|
|
len = sprintf(buf+4,"ssh-rsa");
|
|
|
|
|
len+=4;
|
|
|
|
|
|
|
|
|
|
if (sizeof(buf)-len < 4+pubkey->u.rsa.exponent.len)
|
|
|
|
|
goto fail;
|
|
|
|
|
n = pubkey->u.rsa.exponent.len;
|
|
|
|
|
if (pubkey->u.rsa.exponent.data[0] & 0x80) n++;
|
|
|
|
|
buf[len++]=(n >>24) & 0xff;
|
|
|
|
|
buf[len++]=(n >>16) & 0xff;
|
|
|
|
|
buf[len++]=(n >>8) & 0xff;
|
|
|
|
|
buf[len++]=(n) & 0xff;
|
|
|
|
|
if (pubkey->u.rsa.exponent.data[0] & 0x80)
|
|
|
|
|
buf[len++]= 0;
|
|
|
|
|
|
|
|
|
|
memcpy(buf+len,pubkey->u.rsa.exponent.data,
|
|
|
|
|
pubkey->u.rsa.exponent.len);
|
|
|
|
|
len += pubkey->u.rsa.exponent.len;
|
|
|
|
|
|
|
|
|
|
if (sizeof(buf)-len < 5+pubkey->u.rsa.modulus.len)
|
|
|
|
|
goto fail;
|
|
|
|
|
n = pubkey->u.rsa.modulus.len;
|
|
|
|
|
if (pubkey->u.rsa.modulus.data[0] & 0x80) n++;
|
|
|
|
|
buf[len++]=(n >>24) & 0xff;
|
|
|
|
|
buf[len++]=(n >>16) & 0xff;
|
|
|
|
|
buf[len++]=(n >>8) & 0xff;
|
|
|
|
|
buf[len++]=(n) & 0xff;
|
|
|
|
|
if (pubkey->u.rsa.modulus.data[0] & 0x80)
|
|
|
|
|
buf[len++]= 0;
|
|
|
|
|
|
|
|
|
|
memcpy(buf+len,pubkey->u.rsa.modulus.data,
|
|
|
|
|
pubkey->u.rsa.modulus.len);
|
|
|
|
|
len += pubkey->u.rsa.modulus.len;
|
|
|
|
|
|
|
|
|
|
uu = malloc(len*2);
|
|
|
|
|
r = sc_base64_encode(buf, len, uu, 2*len, 2*len);
|
|
|
|
|
|
|
|
|
|
printf("ssh-rsa %s", uu);
|
|
|
|
|
free(uu);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pubkey->algorithm == SC_ALGORITHM_DSA) {
|
|
|
|
|
char buf[2048];
|
|
|
|
|
char *uu;
|
|
|
|
|
__u32 len;
|
|
|
|
|
__u32 n;
|
|
|
|
|
|
|
|
|
|
buf[0]=0;
|
|
|
|
|
buf[1]=0;
|
|
|
|
|
buf[2]=0;
|
|
|
|
|
buf[3]=7;
|
|
|
|
|
|
|
|
|
|
len = sprintf(buf+4,"ssh-dss");
|
|
|
|
|
len+=4;
|
|
|
|
|
|
|
|
|
|
if (sizeof(buf)-len < 5+pubkey->u.dsa.p.len)
|
|
|
|
|
goto fail;
|
|
|
|
|
n = pubkey->u.dsa.p.len;
|
|
|
|
|
if (pubkey->u.dsa.p.data[0] & 0x80) n++;
|
|
|
|
|
buf[len++]=(n >>24) & 0xff;
|
|
|
|
|
buf[len++]=(n >>16) & 0xff;
|
|
|
|
|
buf[len++]=(n >>8) & 0xff;
|
|
|
|
|
buf[len++]=(n) & 0xff;
|
|
|
|
|
if (pubkey->u.dsa.p.data[0] & 0x80)
|
|
|
|
|
buf[len++]= 0;
|
|
|
|
|
|
|
|
|
|
memcpy(buf+len,pubkey->u.dsa.p.data,
|
|
|
|
|
pubkey->u.dsa.p.len);
|
|
|
|
|
len += pubkey->u.dsa.p.len;
|
|
|
|
|
|
|
|
|
|
if (sizeof(buf)-len < 5+pubkey->u.dsa.q.len)
|
|
|
|
|
goto fail;
|
|
|
|
|
n = pubkey->u.dsa.q.len;
|
|
|
|
|
if (pubkey->u.dsa.q.data[0] & 0x80) n++;
|
|
|
|
|
buf[len++]=(n >>24) & 0xff;
|
|
|
|
|
buf[len++]=(n >>16) & 0xff;
|
|
|
|
|
buf[len++]=(n >>8) & 0xff;
|
|
|
|
|
buf[len++]=(n) & 0xff;
|
|
|
|
|
if (pubkey->u.dsa.q.data[0] & 0x80)
|
|
|
|
|
buf[len++]= 0;
|
|
|
|
|
|
|
|
|
|
memcpy(buf+len,pubkey->u.dsa.q.data,
|
|
|
|
|
pubkey->u.dsa.q.len);
|
|
|
|
|
len += pubkey->u.dsa.q.len;
|
|
|
|
|
|
|
|
|
|
if (sizeof(buf)-len < 5+pubkey->u.dsa.g.len)
|
|
|
|
|
goto fail;
|
|
|
|
|
n = pubkey->u.dsa.g.len;
|
|
|
|
|
if (pubkey->u.dsa.g.data[0] & 0x80) n++;
|
|
|
|
|
buf[len++]=(n >>24) & 0xff;
|
|
|
|
|
buf[len++]=(n >>16) & 0xff;
|
|
|
|
|
buf[len++]=(n >>8) & 0xff;
|
|
|
|
|
buf[len++]=(n) & 0xff;
|
|
|
|
|
if (pubkey->u.dsa.g.data[0] & 0x80)
|
|
|
|
|
buf[len++]= 0;
|
|
|
|
|
|
|
|
|
|
memcpy(buf+len,pubkey->u.dsa.g.data,
|
|
|
|
|
pubkey->u.dsa.g.len);
|
|
|
|
|
len += pubkey->u.dsa.g.len;
|
|
|
|
|
|
|
|
|
|
if (sizeof(buf)-len < 5+pubkey->u.dsa.pub.len)
|
|
|
|
|
goto fail;
|
|
|
|
|
n = pubkey->u.dsa.pub.len;
|
|
|
|
|
if (pubkey->u.dsa.pub.data[0] & 0x80) n++;
|
|
|
|
|
buf[len++]=(n >>24) & 0xff;
|
|
|
|
|
buf[len++]=(n >>16) & 0xff;
|
|
|
|
|
buf[len++]=(n >>8) & 0xff;
|
|
|
|
|
buf[len++]=(n) & 0xff;
|
|
|
|
|
if (pubkey->u.dsa.pub.data[0] & 0x80)
|
|
|
|
|
buf[len++]= 0;
|
|
|
|
|
|
|
|
|
|
memcpy(buf+len,pubkey->u.dsa.pub.data,
|
|
|
|
|
pubkey->u.dsa.pub.len);
|
|
|
|
|
len += pubkey->u.dsa.pub.len;
|
|
|
|
|
|
|
|
|
|
uu = malloc(len*2);
|
|
|
|
|
r = sc_base64_encode(buf, len, uu, 2*len, 2*len);
|
|
|
|
|
|
|
|
|
|
printf("ssh-dss %s", uu);
|
|
|
|
|
free(uu);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert)
|
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
|
|
|
|
else if (pubkey)
|
|
|
|
|
sc_pkcs15_free_pubkey(pubkey);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
fail:
|
|
|
|
|
printf("can't convert key: buffer too small\n");
|
|
|
|
|
if (cert)
|
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
|
|
|
|
else if (pubkey)
|
|
|
|
|
sc_pkcs15_free_pubkey(pubkey);
|
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
static sc_pkcs15_object_t *
|
2003-10-12 19:57:32 +00:00
|
|
|
|
get_pin_info(void)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
2005-02-11 20:09:34 +00:00
|
|
|
|
sc_pkcs15_object_t *objs[32], *obj;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
int r;
|
|
|
|
|
|
2003-10-12 19:57:32 +00:00
|
|
|
|
if (opt_auth_id == NULL) {
|
2005-02-11 20:09:34 +00:00
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 32);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
|
obj = objs[0];
|
2003-10-12 19:57:32 +00:00
|
|
|
|
} else {
|
2003-04-14 14:51:42 +00:00
|
|
|
|
struct sc_pkcs15_id auth_id;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2003-04-14 14:51:42 +00:00
|
|
|
|
sc_pkcs15_hex_string_to_id(opt_auth_id, &auth_id);
|
|
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &auth_id, &obj);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Unable to find PIN code: %s\n", sc_strerror(r));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
return obj;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static u8 * get_pin(const char *prompt, sc_pkcs15_object_t *pin_obj)
|
2003-10-12 19:57:32 +00:00
|
|
|
|
{
|
2003-11-20 15:42:10 +00:00
|
|
|
|
sc_pkcs15_pin_info_t *pinfo = (sc_pkcs15_pin_info_t *) pin_obj->data;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
char buf[80];
|
|
|
|
|
char *pincode;
|
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
sprintf(buf, "%s [%s]: ", prompt, pin_obj->label);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
while (1) {
|
|
|
|
|
pincode = getpass(buf);
|
|
|
|
|
if (strlen(pincode) == 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (strlen(pincode) < pinfo->min_length) {
|
|
|
|
|
printf("PIN code too short, try again.\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-02-20 23:19:01 +00:00
|
|
|
|
if (strlen(pincode) > pinfo->max_length) {
|
2002-01-08 13:56:50 +00:00
|
|
|
|
printf("PIN code too long, try again.\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
return (u8 *) strdup(pincode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
int
|
|
|
|
|
authenticate(sc_pkcs15_object_t *obj)
|
|
|
|
|
{
|
|
|
|
|
sc_pkcs15_pin_info_t *pin_info;
|
|
|
|
|
sc_pkcs15_object_t *pin_obj;
|
|
|
|
|
u8 *pin;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
if (obj->auth_id.len == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &obj->auth_id, &pin_obj);
|
|
|
|
|
if (r)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
pin_info = (sc_pkcs15_pin_info_t *) pin_obj->data;
|
|
|
|
|
pin = get_pin("Please enter PIN", pin_obj);
|
|
|
|
|
|
|
|
|
|
return sc_pkcs15_verify_pin(p15card, pin_info,
|
2003-12-18 21:37:34 +00:00
|
|
|
|
pin, pin? strlen((char *) pin) : 0);
|
2003-11-20 15:42:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static void print_pin_info(const struct sc_pkcs15_object *obj)
|
2002-03-03 00:32:28 +00:00
|
|
|
|
{
|
|
|
|
|
const char *pin_flags[] = {
|
|
|
|
|
"case-sensitive", "local", "change-disabled",
|
|
|
|
|
"unblock-disabled", "initialized", "needs-padding",
|
|
|
|
|
"unblockingPin", "soPin", "disable_allowed",
|
|
|
|
|
"integrity-protected", "confidentiality-protected",
|
|
|
|
|
"exchangeRefData"
|
|
|
|
|
};
|
2005-01-13 21:52:39 +00:00
|
|
|
|
const char *pin_types[] = {"bcd", "ascii-numeric", "UTF-8",
|
|
|
|
|
"halfnibble bcd", "iso 9664-1"};
|
2005-02-11 20:09:34 +00:00
|
|
|
|
const struct sc_pkcs15_pin_info *pin = (const struct sc_pkcs15_pin_info *) obj->data;
|
2005-02-04 22:52:13 +00:00
|
|
|
|
const size_t pf_count = sizeof(pin_flags)/sizeof(pin_flags[0]);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
char path[SC_MAX_PATH_SIZE * 2 + 1];
|
2005-02-04 22:52:13 +00:00
|
|
|
|
size_t i;
|
2002-03-03 00:32:28 +00:00
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
p = path;
|
|
|
|
|
*p = 0;
|
|
|
|
|
for (i = 0; i < pin->path.len; i++) {
|
|
|
|
|
sprintf(p, "%02X", pin->path.value[i]);
|
|
|
|
|
p += 2;
|
|
|
|
|
}
|
|
|
|
|
printf("PIN [%s]\n", obj->label);
|
|
|
|
|
printf("\tCom. Flags: 0x%X\n", obj->flags);
|
2005-01-13 21:52:39 +00:00
|
|
|
|
printf("\tID : %s\n", sc_pkcs15_print_id(&pin->auth_id));
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("\tFlags : [0x%02X]", pin->flags);
|
|
|
|
|
for (i = 0; i < pf_count; i++)
|
|
|
|
|
if (pin->flags & (1 << i)) {
|
|
|
|
|
printf(", %s", pin_flags[i]);
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
2003-04-03 09:51:46 +00:00
|
|
|
|
printf("\tLength : min_len:%d, max_len:%d, stored_len:%d\n",
|
|
|
|
|
pin->min_length, pin->max_length, pin->stored_length);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("\tPad char : 0x%02X\n", pin->pad_char);
|
|
|
|
|
printf("\tReference : %d\n", pin->reference);
|
2005-01-13 21:52:39 +00:00
|
|
|
|
printf("\tType : %s\n", pin_types[pin->type]);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("\tPath : %s\n", path);
|
2004-09-19 19:47:34 +00:00
|
|
|
|
if (pin->tries_left >= 0)
|
|
|
|
|
printf("\tTries left: %d\n", pin->tries_left);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int list_pins(void)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
|
|
|
|
int r, i;
|
2004-08-25 20:55:07 +00:00
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 32);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (r < 0) {
|
2002-03-03 00:32:28 +00:00
|
|
|
|
fprintf(stderr, "Private key enumeration failed: %s\n", sc_strerror(r));
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("Card has %d PIN code(s).\n\n", r);
|
|
|
|
|
for (i = 0; i < r; i++) {
|
|
|
|
|
print_pin_info(objs[i]);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int unblock_pin(void)
|
2003-04-14 14:51:42 +00:00
|
|
|
|
{
|
|
|
|
|
struct sc_pkcs15_pin_info *pinfo = NULL;
|
2003-11-20 15:42:10 +00:00
|
|
|
|
sc_pkcs15_object_t *pin_obj;
|
2003-04-14 14:51:42 +00:00
|
|
|
|
u8 *pin, *puk;
|
|
|
|
|
int r;
|
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
if (!(pin_obj = get_pin_info()))
|
2003-04-14 14:51:42 +00:00
|
|
|
|
return 2;
|
2003-11-20 15:42:10 +00:00
|
|
|
|
pinfo = (sc_pkcs15_pin_info_t *) pin_obj->data;
|
2003-04-14 14:51:42 +00:00
|
|
|
|
|
2003-10-12 19:57:32 +00:00
|
|
|
|
if ((puk = opt_puk) == NULL) {
|
2003-11-20 15:42:10 +00:00
|
|
|
|
puk = get_pin("Enter PUK", pin_obj);
|
2003-10-12 19:57:32 +00:00
|
|
|
|
if (puk == NULL)
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((pin = opt_pin) == NULL)
|
|
|
|
|
pin = opt_newpin;
|
|
|
|
|
while (pin == NULL) {
|
2003-05-17 10:54:27 +00:00
|
|
|
|
u8 *pin2;
|
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
pin = get_pin("Enter new PIN", pin_obj);
|
2003-04-14 14:51:42 +00:00
|
|
|
|
if (pin == NULL || strlen((char *) pin) == 0)
|
|
|
|
|
return 2;
|
2003-11-20 15:42:10 +00:00
|
|
|
|
pin2 = get_pin("Enter new PIN again", pin_obj);
|
2003-04-14 14:51:42 +00:00
|
|
|
|
if (pin2 == NULL || strlen((char *) pin2) == 0)
|
|
|
|
|
return 2;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
if (strcmp((char *) pin, (char *) pin2) != 0) {
|
|
|
|
|
printf("PIN codes do not match, try again.\n");
|
|
|
|
|
free(pin);
|
|
|
|
|
pin = NULL;
|
2003-04-14 14:51:42 +00:00
|
|
|
|
}
|
|
|
|
|
free(pin2);
|
|
|
|
|
}
|
2003-10-12 19:57:32 +00:00
|
|
|
|
|
2003-04-14 14:51:42 +00:00
|
|
|
|
r = sc_pkcs15_unblock_pin(p15card, pinfo, puk, strlen((char *) puk),
|
|
|
|
|
pin, strlen((char *) pin));
|
|
|
|
|
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
|
|
|
|
|
fprintf(stderr, "PUK code incorrect; tries left: %d\n", pinfo->tries_left);
|
|
|
|
|
return 3;
|
|
|
|
|
} else if (r) {
|
|
|
|
|
fprintf(stderr, "PIN unblocking failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2003-04-14 14:51:42 +00:00
|
|
|
|
printf("PIN successfully unblocked.\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int change_pin(void)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
2003-11-20 15:42:10 +00:00
|
|
|
|
sc_pkcs15_object_t *pin_obj;
|
|
|
|
|
sc_pkcs15_pin_info_t *pinfo = NULL;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
u8 *pincode, *newpin;
|
|
|
|
|
int r;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
if (!(pin_obj = get_pin_info()))
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return 2;
|
2003-11-20 15:42:10 +00:00
|
|
|
|
pinfo = (sc_pkcs15_pin_info_t *) pin_obj->data;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
|
|
|
|
|
if ((pincode = opt_pin) == NULL) {
|
2003-11-20 15:42:10 +00:00
|
|
|
|
pincode = get_pin("Enter old PIN", pin_obj);
|
2003-10-12 19:57:32 +00:00
|
|
|
|
if (pincode == NULL)
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (strlen((char *) pincode) == 0) {
|
|
|
|
|
fprintf(stderr, "No PIN code supplied.\n");
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2003-10-12 19:57:32 +00:00
|
|
|
|
|
|
|
|
|
newpin = opt_newpin;
|
|
|
|
|
while (newpin == NULL) {
|
2002-01-08 13:56:50 +00:00
|
|
|
|
u8 *newpin2;
|
2003-05-17 10:54:27 +00:00
|
|
|
|
|
2003-11-20 15:42:10 +00:00
|
|
|
|
newpin = get_pin("Enter new PIN", pin_obj);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (newpin == NULL || strlen((char *) newpin) == 0)
|
|
|
|
|
return 2;
|
2003-11-20 15:42:10 +00:00
|
|
|
|
newpin2 = get_pin("Enter new PIN again", pin_obj);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (newpin2 == NULL || strlen((char *) newpin2) == 0)
|
|
|
|
|
return 2;
|
|
|
|
|
if (strcmp((char *) newpin, (char *) newpin2) == 0) {
|
|
|
|
|
free(newpin2);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
printf("PIN codes do not match, try again.\n");
|
|
|
|
|
free(newpin);
|
|
|
|
|
free(newpin2);
|
|
|
|
|
}
|
|
|
|
|
r = sc_pkcs15_change_pin(p15card, pinfo, pincode, strlen((char *) pincode),
|
|
|
|
|
newpin, strlen((char *) newpin));
|
|
|
|
|
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;
|
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
printf("PIN code changed successfully.\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-09 00:04:44 +00:00
|
|
|
|
static int read_and_cache_file(const sc_path_t *path)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
2005-03-09 00:04:44 +00:00
|
|
|
|
sc_file_t *tfile;
|
|
|
|
|
const sc_acl_entry_t *e;
|
2002-01-24 16:02:54 +00:00
|
|
|
|
u8 buf[16384];
|
|
|
|
|
int r;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose) {
|
2002-01-24 16:02:54 +00:00
|
|
|
|
printf("Reading file ");
|
|
|
|
|
hex_dump(stdout, path->value, path->len, "");
|
|
|
|
|
printf("...\n");
|
|
|
|
|
}
|
2005-02-04 22:52:13 +00:00
|
|
|
|
r = sc_select_file(card, path, &tfile);
|
2002-01-24 16:02:54 +00:00
|
|
|
|
if (r != 0) {
|
|
|
|
|
fprintf(stderr, "sc_select_file() failed: %s\n", sc_strerror(r));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2005-02-04 22:52:13 +00:00
|
|
|
|
e = sc_file_get_acl_entry(tfile, SC_AC_OP_READ);
|
2002-02-20 09:56:47 +00:00
|
|
|
|
if (e != NULL && e->method != SC_AC_NONE) {
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-01-24 16:02:54 +00:00
|
|
|
|
printf("Skipping; ACL for read operation is not NONE.\n");
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
2005-02-04 22:52:13 +00:00
|
|
|
|
r = sc_read_binary(card, 0, buf, tfile->size, 0);
|
2002-01-24 16:02:54 +00:00
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "sc_read_binary() failed: %s\n", sc_strerror(r));
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return -1;
|
2002-01-24 16:02:54 +00:00
|
|
|
|
}
|
2003-02-01 20:26:12 +00:00
|
|
|
|
r = sc_pkcs15_cache_file(p15card, path, buf, r);
|
2002-01-24 16:02:54 +00:00
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Unable to cache file: %s\n", sc_strerror(r));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2005-02-04 22:52:13 +00:00
|
|
|
|
sc_file_free(tfile);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 22:52:13 +00:00
|
|
|
|
static int learn_card(void)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
{
|
2003-01-09 09:14:15 +00:00
|
|
|
|
char dir[PATH_MAX];
|
2002-03-03 00:32:28 +00:00
|
|
|
|
int r, i, cert_count;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
struct sc_pkcs15_object *certs[32];
|
2002-04-19 09:22:44 +00:00
|
|
|
|
struct sc_pkcs15_df *df;
|
2002-03-03 00:32:28 +00:00
|
|
|
|
|
2002-01-24 16:02:54 +00:00
|
|
|
|
r = sc_get_cache_dir(ctx, dir, sizeof(dir));
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Unable to find cache directory: %s\n", sc_strerror(r));
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2003-01-09 09:14:15 +00:00
|
|
|
|
|
2002-01-24 16:02:54 +00:00
|
|
|
|
printf("Using cache directory '%s'.\n", dir);
|
2005-02-11 20:09:34 +00:00
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, certs, 32);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (r < 0) {
|
|
|
|
|
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
|
cert_count = r;
|
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY_RSA, NULL, 0);
|
2002-01-24 16:02:54 +00:00
|
|
|
|
if (r < 0) {
|
2002-03-03 00:32:28 +00:00
|
|
|
|
fprintf(stderr, "Private key enumeration failed: %s\n", sc_strerror(r));
|
2002-01-24 16:02:54 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, NULL, 0);
|
2002-01-24 16:02:54 +00:00
|
|
|
|
if (r < 0) {
|
2002-03-03 00:32:28 +00:00
|
|
|
|
fprintf(stderr, "PIN code enumeration failed: %s\n", sc_strerror(r));
|
2002-01-24 16:02:54 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2003-01-09 09:14:15 +00:00
|
|
|
|
|
|
|
|
|
/* Cache all relevant DF files. The cache
|
|
|
|
|
* directory is created automatically. */
|
2002-04-19 09:22:44 +00:00
|
|
|
|
for (df = p15card->df_list; df != NULL; df = df->next)
|
|
|
|
|
read_and_cache_file(&df->path);
|
2003-01-09 08:45:27 +00:00
|
|
|
|
printf("Caching %d certificate(s)...\n", cert_count);
|
2002-03-03 00:32:28 +00:00
|
|
|
|
for (i = 0; i < cert_count; i++) {
|
2002-04-19 14:23:31 +00:00
|
|
|
|
struct sc_pkcs15_cert_info *cinfo = (struct sc_pkcs15_cert_info *) certs[i]->data;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
2002-03-03 00:32:28 +00:00
|
|
|
|
printf("[%s]\n", certs[i]->label);
|
2002-01-24 16:02:54 +00:00
|
|
|
|
read_and_cache_file(&cinfo->path);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char * const argv[])
|
|
|
|
|
{
|
|
|
|
|
int err = 0, r, c, long_optind = 0;
|
|
|
|
|
int do_read_cert = 0;
|
|
|
|
|
int do_list_certs = 0;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
int do_read_data_object = 0;
|
|
|
|
|
int do_list_data_objects = 0;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
int do_list_pins = 0;
|
|
|
|
|
int do_list_prkeys = 0;
|
2002-03-14 16:57:20 +00:00
|
|
|
|
int do_list_pubkeys = 0;
|
|
|
|
|
int do_read_pubkey = 0;
|
2005-06-15 08:57:47 +00:00
|
|
|
|
int do_read_sshkey = 0;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
int do_change_pin = 0;
|
2003-04-14 14:51:42 +00:00
|
|
|
|
int do_unblock_pin = 0;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
int do_learn_card = 0;
|
|
|
|
|
int action_count = 0;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2004-06-18 09:12:50 +00:00
|
|
|
|
c = getopt_long(argc, argv, "r:cuko:va:LR:Cw", options, &long_optind);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (c == -1)
|
|
|
|
|
break;
|
|
|
|
|
if (c == '?')
|
2002-04-19 14:23:31 +00:00
|
|
|
|
print_usage_and_die();
|
2002-01-08 13:56:50 +00:00
|
|
|
|
switch (c) {
|
|
|
|
|
case 'r':
|
|
|
|
|
opt_cert = optarg;
|
|
|
|
|
do_read_cert = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case 'c':
|
|
|
|
|
do_list_certs = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
case 'R':
|
2003-10-02 09:21:17 +00:00
|
|
|
|
opt_data = optarg;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
do_read_data_object = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case 'C':
|
|
|
|
|
do_list_data_objects = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
case OPT_CHANGE_PIN:
|
|
|
|
|
do_change_pin = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2003-04-14 14:51:42 +00:00
|
|
|
|
case 'u':
|
|
|
|
|
do_unblock_pin = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
case OPT_LIST_PINS:
|
|
|
|
|
do_list_pins = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case 'k':
|
|
|
|
|
do_list_prkeys = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2002-03-14 16:57:20 +00:00
|
|
|
|
case OPT_LIST_PUB:
|
|
|
|
|
do_list_pubkeys = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case OPT_READ_PUB:
|
|
|
|
|
opt_pubkey = optarg;
|
|
|
|
|
do_read_pubkey = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2005-06-16 19:39:34 +00:00
|
|
|
|
#ifdef HAVE_OPENSSL
|
2005-06-15 08:57:47 +00:00
|
|
|
|
case OPT_READ_SSH:
|
|
|
|
|
opt_pubkey = optarg;
|
|
|
|
|
do_read_sshkey = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
2005-06-16 19:39:34 +00:00
|
|
|
|
#endif
|
2002-01-08 13:56:50 +00:00
|
|
|
|
case 'L':
|
|
|
|
|
do_learn_card = 1;
|
|
|
|
|
action_count++;
|
|
|
|
|
break;
|
|
|
|
|
case OPT_READER:
|
|
|
|
|
opt_reader = atoi(optarg);
|
|
|
|
|
break;
|
2003-05-17 10:54:27 +00:00
|
|
|
|
case OPT_PIN:
|
2003-12-18 21:37:34 +00:00
|
|
|
|
opt_pin = (u8 *) optarg;
|
2003-05-17 10:54:27 +00:00
|
|
|
|
break;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
case OPT_NEWPIN:
|
2003-12-18 21:37:34 +00:00
|
|
|
|
opt_newpin = (u8 *) optarg;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
break;
|
|
|
|
|
case OPT_PUK:
|
2003-12-18 21:37:34 +00:00
|
|
|
|
opt_puk = (u8 *) optarg;
|
2003-10-12 19:57:32 +00:00
|
|
|
|
break;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
case 'o':
|
|
|
|
|
opt_outfile = optarg;
|
|
|
|
|
break;
|
2004-06-13 20:13:12 +00:00
|
|
|
|
case 'v':
|
|
|
|
|
verbose++;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
break;
|
2003-04-14 14:51:42 +00:00
|
|
|
|
case 'a':
|
|
|
|
|
opt_auth_id = optarg;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
break;
|
|
|
|
|
case OPT_NO_CACHE:
|
|
|
|
|
opt_no_cache++;
|
|
|
|
|
break;
|
2003-01-03 16:58:32 +00:00
|
|
|
|
case 'w':
|
|
|
|
|
opt_wait = 1;
|
|
|
|
|
break;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (action_count == 0)
|
2002-04-19 14:23:31 +00:00
|
|
|
|
print_usage_and_die();
|
2002-03-24 14:12:38 +00:00
|
|
|
|
r = sc_establish_context(&ctx, app_name);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose > 1 )
|
|
|
|
|
ctx->debug = verbose-1;
|
2003-01-03 16:58:32 +00:00
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
|
err = connect_card(ctx, &card, opt_reader, 0, opt_wait, verbose);
|
2003-01-03 16:58:32 +00:00
|
|
|
|
if (err)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
goto end;
|
2003-01-03 16:58:32 +00:00
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
fprintf(stderr, "Trying to find a PKCS#15 compatible card...\n");
|
|
|
|
|
r = sc_pkcs15_bind(card, &p15card);
|
|
|
|
|
if (r) {
|
|
|
|
|
fprintf(stderr, "PKCS#15 initialization failed: %s\n", sc_strerror(r));
|
|
|
|
|
err = 1;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
2002-01-24 16:02:54 +00:00
|
|
|
|
if (opt_no_cache)
|
2002-04-19 09:22:44 +00:00
|
|
|
|
p15card->opts.use_cache = 0;
|
2004-06-13 20:13:12 +00:00
|
|
|
|
if (verbose)
|
2002-01-08 13:56:50 +00:00
|
|
|
|
fprintf(stderr, "Found %s!\n", p15card->label);
|
|
|
|
|
if (do_learn_card) {
|
|
|
|
|
if ((err = learn_card()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
if (do_list_certs) {
|
|
|
|
|
if ((err = list_certificates()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
if (do_read_cert) {
|
|
|
|
|
if ((err = read_certificate()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2002-12-18 10:17:01 +00:00
|
|
|
|
if (do_list_data_objects) {
|
|
|
|
|
if ((err = list_data_objects()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
if (do_read_data_object) {
|
|
|
|
|
if ((err = read_data_object()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2002-01-08 13:56:50 +00:00
|
|
|
|
if (do_list_prkeys) {
|
|
|
|
|
if ((err = list_private_keys()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2002-03-14 16:57:20 +00:00
|
|
|
|
if (do_list_pubkeys) {
|
|
|
|
|
if ((err = list_public_keys()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
|
|
|
|
if (do_read_pubkey) {
|
|
|
|
|
if ((err = read_public_key()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2005-06-15 08:57:47 +00:00
|
|
|
|
if (do_read_sshkey) {
|
|
|
|
|
if ((err = read_ssh_key()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2002-01-08 13:56:50 +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--;
|
|
|
|
|
}
|
2003-04-14 14:51:42 +00:00
|
|
|
|
if (do_unblock_pin) {
|
|
|
|
|
if ((err = unblock_pin()))
|
|
|
|
|
goto end;
|
|
|
|
|
action_count--;
|
|
|
|
|
}
|
2002-01-08 13:56:50 +00:00
|
|
|
|
end:
|
|
|
|
|
if (p15card)
|
|
|
|
|
sc_pkcs15_unbind(p15card);
|
|
|
|
|
if (card) {
|
|
|
|
|
sc_unlock(card);
|
2002-02-24 19:32:14 +00:00
|
|
|
|
sc_disconnect_card(card, 0);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
}
|
|
|
|
|
if (ctx)
|
2002-03-24 14:12:38 +00:00
|
|
|
|
sc_release_context(ctx);
|
2002-01-08 13:56:50 +00:00
|
|
|
|
return err;
|
|
|
|
|
}
|
2002-04-17 12:20:31 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Helper function for PEM encoding public key
|
|
|
|
|
*/
|
|
|
|
|
#include "opensc/asn1.h"
|
|
|
|
|
static const struct sc_asn1_entry c_asn1_pem_key_items[] = {
|
|
|
|
|
{ "algorithm", SC_ASN1_ALGORITHM_ID, SC_ASN1_CONS|ASN1_SEQUENCE, },
|
|
|
|
|
{ "key", SC_ASN1_BIT_STRING_NI, ASN1_BIT_STRING },
|
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
static const struct sc_asn1_entry c_asn1_pem_key[] = {
|
|
|
|
|
{ "publicKey", SC_ASN1_STRUCT, SC_ASN1_CONS|ASN1_SEQUENCE, },
|
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
2005-03-09 00:04:44 +00:00
|
|
|
|
pem_encode(sc_context_t *ctx,
|
2002-04-17 12:20:31 +00:00
|
|
|
|
int alg_id, sc_pkcs15_der_t *key, sc_pkcs15_der_t *out)
|
|
|
|
|
{
|
|
|
|
|
struct sc_asn1_entry asn1_pem_key[2],
|
|
|
|
|
asn1_pem_key_items[3];
|
|
|
|
|
struct sc_algorithm_id algorithm;
|
|
|
|
|
int key_len;
|
|
|
|
|
|
|
|
|
|
memset(&algorithm, 0, sizeof(algorithm));
|
|
|
|
|
algorithm.algorithm = alg_id;
|
|
|
|
|
|
|
|
|
|
sc_copy_asn1_entry(c_asn1_pem_key, asn1_pem_key);
|
|
|
|
|
sc_copy_asn1_entry(c_asn1_pem_key_items, asn1_pem_key_items);
|
|
|
|
|
sc_format_asn1_entry(asn1_pem_key + 0, asn1_pem_key_items, NULL, 1);
|
|
|
|
|
sc_format_asn1_entry(asn1_pem_key_items + 0,
|
|
|
|
|
&algorithm, NULL, 1);
|
|
|
|
|
key_len = 8 * key->len;
|
|
|
|
|
sc_format_asn1_entry(asn1_pem_key_items + 1,
|
|
|
|
|
key->value, &key_len, 1);
|
|
|
|
|
|
|
|
|
|
return sc_asn1_encode(ctx, asn1_pem_key, &out->value, &out->len);
|
|
|
|
|
}
|