add initial PIV card support; patch supplied by Douglas E. Engert <deengert@anl.gov>
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2842 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
d02aaf37de
commit
b051b08584
|
@ -29,7 +29,9 @@ libopensc_la_SOURCES = \
|
||||||
card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
|
card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
|
||||||
card-oberthur.c card-belpic.c card-atrust-acos.c \
|
card-oberthur.c card-belpic.c card-atrust-acos.c \
|
||||||
card-incrypto34.c \
|
card-incrypto34.c \
|
||||||
|
card-piv.c \
|
||||||
\
|
\
|
||||||
|
pkcs15-piv.c \
|
||||||
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
|
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
|
||||||
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafe.c \
|
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafe.c \
|
||||||
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c
|
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -108,7 +108,11 @@ enum {
|
||||||
|
|
||||||
/* incrypto34 driver */
|
/* incrypto34 driver */
|
||||||
SC_CARD_TYPE_INCRYPTO34_BASE = 13000,
|
SC_CARD_TYPE_INCRYPTO34_BASE = 13000,
|
||||||
SC_CARD_TYPE_INCRYPTO34_GENERIC
|
SC_CARD_TYPE_INCRYPTO34_GENERIC,
|
||||||
|
|
||||||
|
/* PIV-II type cards */
|
||||||
|
SC_CARD_TYPE_PIV_II_BASE = 14000,
|
||||||
|
SC_CARD_TYPE_PIV_II_GENERIC
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -72,6 +72,9 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
|
||||||
{ "atrust-acos",(void *(*)(void))sc_get_atrust_acos_driver },
|
{ "atrust-acos",(void *(*)(void))sc_get_atrust_acos_driver },
|
||||||
{ "emv", (void *(*)(void)) sc_get_emv_driver },
|
{ "emv", (void *(*)(void)) sc_get_emv_driver },
|
||||||
{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },
|
{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
{ "PIV-II",(void *) sc_get_piv_driver },
|
||||||
|
#endif
|
||||||
/* The default driver should be last, as it handles all the
|
/* The default driver should be last, as it handles all the
|
||||||
* unrecognized cards. */
|
* unrecognized cards. */
|
||||||
{ "default", (void *(*)(void)) sc_get_default_driver },
|
{ "default", (void *(*)(void)) sc_get_default_driver },
|
||||||
|
|
|
@ -1073,6 +1073,7 @@ extern sc_card_driver_t *sc_get_oberthur_driver(void);
|
||||||
extern sc_card_driver_t *sc_get_belpic_driver(void);
|
extern sc_card_driver_t *sc_get_belpic_driver(void);
|
||||||
extern sc_card_driver_t *sc_get_atrust_acos_driver(void);
|
extern sc_card_driver_t *sc_get_atrust_acos_driver(void);
|
||||||
extern sc_card_driver_t *sc_get_incrypto34_driver(void);
|
extern sc_card_driver_t *sc_get_incrypto34_driver(void);
|
||||||
|
extern sc_card_driver_t *sc_get_piv_driver(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,428 @@
|
||||||
|
/*
|
||||||
|
* partial PKCS15 emulation for PIV-II cards
|
||||||
|
* only minimal use of the authentication cert and key
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005, Douglas E. Engert <deengert@anl.gov>
|
||||||
|
* 2004, Nils Larsch <larsch@trustcenter.de>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <opensc/pkcs15.h>
|
||||||
|
#include <opensc/log.h>
|
||||||
|
#include <opensc/cardctl.h>
|
||||||
|
#include <opensc/cards.h>
|
||||||
|
#include "../tools/util.h"
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
|
#define MANU_ID "piv_II "
|
||||||
|
|
||||||
|
int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct objdata_st {
|
||||||
|
const char *id;
|
||||||
|
const char *label;
|
||||||
|
char *aoid;
|
||||||
|
int authority;
|
||||||
|
const char *path;
|
||||||
|
int obj_flags;
|
||||||
|
} objdata;
|
||||||
|
|
||||||
|
typedef struct cdata_st {
|
||||||
|
const char *id;
|
||||||
|
const char *label;
|
||||||
|
int authority;
|
||||||
|
const char *path;
|
||||||
|
int obj_flags;
|
||||||
|
} cdata;
|
||||||
|
|
||||||
|
typedef struct pdata_st {
|
||||||
|
const char *id;
|
||||||
|
const char *label;
|
||||||
|
const char *path;
|
||||||
|
int ref;
|
||||||
|
int type;
|
||||||
|
unsigned int maxlen;
|
||||||
|
unsigned int minlen;
|
||||||
|
unsigned int storedlen;
|
||||||
|
int flags;
|
||||||
|
int tries_left;
|
||||||
|
const char pad_char;
|
||||||
|
int obj_flags;
|
||||||
|
} pindata;
|
||||||
|
|
||||||
|
typedef struct pubdata_st {
|
||||||
|
const char *id;
|
||||||
|
const char *label;
|
||||||
|
unsigned int modulus_len;
|
||||||
|
int usage;
|
||||||
|
const char *path;
|
||||||
|
int ref;
|
||||||
|
const char *auth_id;
|
||||||
|
int obj_flags;
|
||||||
|
} pubdata;
|
||||||
|
|
||||||
|
typedef struct prdata_st {
|
||||||
|
const char *id;
|
||||||
|
const char *label;
|
||||||
|
unsigned int modulus_len;
|
||||||
|
int usage;
|
||||||
|
const char *path;
|
||||||
|
int ref;
|
||||||
|
const char *auth_id;
|
||||||
|
int obj_flags;
|
||||||
|
} prdata;
|
||||||
|
|
||||||
|
typedef struct keyinfo_st {
|
||||||
|
int fileid;
|
||||||
|
sc_pkcs15_id_t id;
|
||||||
|
unsigned int modulus_len;
|
||||||
|
u8 modulus[1024/8];
|
||||||
|
} keyinfo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define USAGE_NONREP SC_PKCS15_PRKEY_USAGE_NONREPUDIATION
|
||||||
|
#define USAGE_KE SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
|
||||||
|
SC_PKCS15_PRKEY_USAGE_DECRYPT | \
|
||||||
|
SC_PKCS15_PRKEY_USAGE_WRAP | \
|
||||||
|
SC_PKCS15_PRKEY_USAGE_UNWRAP
|
||||||
|
#define USAGE_AUT SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
|
||||||
|
SC_PKCS15_PRKEY_USAGE_DECRYPT | \
|
||||||
|
SC_PKCS15_PRKEY_USAGE_WRAP | \
|
||||||
|
SC_PKCS15_PRKEY_USAGE_UNWRAP | \
|
||||||
|
SC_PKCS15_PRKEY_USAGE_SIGN
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* copied from util.c to get around link problems in tests etc */
|
||||||
|
static int
|
||||||
|
piv_parse_application_id(struct sc_object_id *oid, char *oid_str)
|
||||||
|
{
|
||||||
|
int ii, ret = SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
if (!oid)
|
||||||
|
return ret;
|
||||||
|
/* init oid */
|
||||||
|
for (ii=0; ii<SC_MAX_OBJECT_ID_OCTETS; ii++)
|
||||||
|
oid->value[ii] = -1;
|
||||||
|
|
||||||
|
if (!(p = oid_str))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (ii=0; ii < SC_MAX_OBJECT_ID_OCTETS; ii++) {
|
||||||
|
oid->value[ii] = strtol(p, &q, 10);
|
||||||
|
if (!*q)
|
||||||
|
break;
|
||||||
|
if (!(q[0] == '.' && isdigit(q[1]))) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
p = q + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int piv_detect_card(sc_pkcs15_card_t *p15card)
|
||||||
|
{
|
||||||
|
sc_card_t *card = p15card->card;
|
||||||
|
|
||||||
|
SC_FUNC_CALLED(card->ctx, 1);
|
||||||
|
if (card->type < SC_CARD_TYPE_PIV_II_GENERIC
|
||||||
|
|| card->type >= SC_CARD_TYPE_PIV_II_GENERIC+1000)
|
||||||
|
return SC_ERROR_INVALID_CARD;
|
||||||
|
return SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
|
||||||
|
{
|
||||||
|
const objdata objects[] = {
|
||||||
|
{"1", "Card Capability Container",
|
||||||
|
"2.16.840.1.101.3.7.1.219.0", 0, "DB00", 0},
|
||||||
|
{"2", "Card Holder Unique Identifier",
|
||||||
|
"2.16.840.1.101.3.7.2.48.0", 0 , "3000", 0},
|
||||||
|
{"3", "Card Holder Fingerprint I",
|
||||||
|
"2.16.840.1.101.3.7.2.96.16", 0, "6010", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{"4", "Card Holder Fingerprint II",
|
||||||
|
"2.16.840.1.101.3.7.2.96.17", 0, "6011", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{"5", "Printed Information",
|
||||||
|
"2.16.840.1.101.3.7.2.48.1", 0, "3001", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{"6", "Card Holder Facial Image",
|
||||||
|
"2.16.840.1.101.3.7.2.96.48", 0, "6030", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{"7", "Security Object",
|
||||||
|
"2.16.840.1.101.3.7.2.144.0", 0, "9000", 0},
|
||||||
|
{NULL, NULL, NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* PIV certs are not modifiable by the user, and need PIN control */
|
||||||
|
/* But not all beta cards enforce this, and most applications cant handle */
|
||||||
|
/* code later will turn off the SC_PKCS15_CO_FLAG_PRIVATE */
|
||||||
|
const cdata certs[] = {
|
||||||
|
{"1", "Certificate for PIV Authentication",
|
||||||
|
0, "0101", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{"2", "Certificate for Digital Signature",
|
||||||
|
0, "0100", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{"3", "Certificate for Key Management",
|
||||||
|
0, "0102", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{"4", "Certificate for Card Authentication",
|
||||||
|
0, "0500", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{NULL, NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pindata pins[] = {
|
||||||
|
{ "1", "PIV Card Holder pin", "", 0x80,
|
||||||
|
SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
|
||||||
|
8, 4, 8,
|
||||||
|
SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
|
||||||
|
SC_PKCS15_PIN_FLAG_LOCAL,
|
||||||
|
-1, 0xFF,
|
||||||
|
SC_PKCS15_CO_FLAG_PRIVATE },
|
||||||
|
{ "2", "PIV PUK", "", 0x81,
|
||||||
|
SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
|
||||||
|
8, 4, 8,
|
||||||
|
SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
|
||||||
|
SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_SO_PIN |
|
||||||
|
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN,
|
||||||
|
-1, 0xFF,
|
||||||
|
SC_PKCS15_CO_FLAG_PRIVATE },
|
||||||
|
/* there are some more key, but dont need for now */
|
||||||
|
/* The admin 9b might fall in here */
|
||||||
|
{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The size of the key or the algid is not really known
|
||||||
|
* but can be derived from the certificates.
|
||||||
|
* DEE need to fix - We will still refer to the "key files" as 06 even of not.
|
||||||
|
* 07 is 2048, 05 is 3072.
|
||||||
|
*/
|
||||||
|
const pubdata pubkeys[] = {
|
||||||
|
|
||||||
|
{ "1", "AUTH pubkey", 1024, USAGE_AUT, "9A06",
|
||||||
|
0x9A, "1", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ "2", "SIGN pubkey", 1024, USAGE_AUT, "9C06",
|
||||||
|
0x9C, "1", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ "3", "KEY MAN pubkey", 1024, USAGE_AUT, "9D06",
|
||||||
|
0x9D, "1", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ "4", "ADMIN pubkey", 1024, USAGE_AUT, "9B06",
|
||||||
|
0x9B, "1", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const prdata prkeys[] = {
|
||||||
|
{ "1", "AUTH key", 1024, USAGE_AUT, "",
|
||||||
|
0x9A, "1", SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_NONE | SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ "2", " SIGN key", 1024, USAGE_AUT, "",
|
||||||
|
0x9B, "1", SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_NONE | SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ "3", "KEY MAN key", 1024, USAGE_AUT, "",
|
||||||
|
0x9C, "1", SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_NONE | SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ "4", "ADMIN key", 1024, USAGE_AUT, "",
|
||||||
|
0x9D, "1", SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_NONE | SC_PKCS15_CO_FLAG_PRIVATE},
|
||||||
|
{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
int r, i;
|
||||||
|
int dfpath;
|
||||||
|
sc_card_t *card = p15card->card;
|
||||||
|
|
||||||
|
SC_FUNC_CALLED(card->ctx, 1);
|
||||||
|
|
||||||
|
/* could read this off card if needed */
|
||||||
|
|
||||||
|
/* CSP does not like a - in the name */
|
||||||
|
p15card->label = strdup("PIV_II");
|
||||||
|
p15card->manufacturer_id = strdup(MANU_ID);
|
||||||
|
/* get serial number */
|
||||||
|
/* We could also use the CCC or CHUID info here */
|
||||||
|
// r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
|
||||||
|
// r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
|
||||||
|
// if (r != SC_SUCCESS)
|
||||||
|
// return SC_ERROR_INTERNAL;
|
||||||
|
// p15card->serial_number = strdup(buf);
|
||||||
|
p15card->serial_number = strdup("9876543210");
|
||||||
|
|
||||||
|
sc_debug(card->ctx, "PIV-II adding objects...");
|
||||||
|
|
||||||
|
/* set other objects */
|
||||||
|
for (i = 0; objects[i].label; i++) {
|
||||||
|
struct sc_pkcs15_data_info obj_info;
|
||||||
|
struct sc_pkcs15_object obj_obj;
|
||||||
|
|
||||||
|
memset(&obj_info, 0, sizeof(obj_info));
|
||||||
|
memset(&obj_obj, 0, sizeof(obj_obj));
|
||||||
|
sc_pkcs15_format_id(objects[i].id, &obj_info.id);
|
||||||
|
sc_format_path(objects[i].path, &obj_info.path);
|
||||||
|
strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
||||||
|
piv_parse_application_id(&obj_info.app_oid, objects[i].aoid);
|
||||||
|
|
||||||
|
strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
||||||
|
obj_obj.flags = objects[i].obj_flags;
|
||||||
|
|
||||||
|
r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT,
|
||||||
|
&obj_obj, &obj_info);
|
||||||
|
if (r < 0)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set certs */
|
||||||
|
for (i = 0; certs[i].label; i++) {
|
||||||
|
struct sc_pkcs15_cert_info cert_info;
|
||||||
|
struct sc_pkcs15_object cert_obj;
|
||||||
|
|
||||||
|
memset(&cert_info, 0, sizeof(cert_info));
|
||||||
|
memset(&cert_obj, 0, sizeof(cert_obj));
|
||||||
|
|
||||||
|
sc_pkcs15_format_id(certs[i].id, &cert_info.id);
|
||||||
|
cert_info.authority = certs[i].authority;
|
||||||
|
sc_format_path(certs[i].path, &cert_info.path);
|
||||||
|
|
||||||
|
strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
||||||
|
cert_obj.flags = certs[i].obj_flags;
|
||||||
|
|
||||||
|
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
|
||||||
|
if (r < 0)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* set pins */
|
||||||
|
|
||||||
|
for (i = 0; pins[i].label; i++) {
|
||||||
|
struct sc_pkcs15_pin_info pin_info;
|
||||||
|
struct sc_pkcs15_object pin_obj;
|
||||||
|
|
||||||
|
memset(&pin_info, 0, sizeof(pin_info));
|
||||||
|
memset(&pin_obj, 0, sizeof(pin_obj));
|
||||||
|
|
||||||
|
sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
|
||||||
|
pin_info.reference = pins[i].ref;
|
||||||
|
pin_info.flags = pins[i].flags;
|
||||||
|
pin_info.type = pins[i].type;
|
||||||
|
pin_info.min_length = pins[i].minlen;
|
||||||
|
pin_info.stored_length = pins[i].storedlen;
|
||||||
|
pin_info.max_length = pins[i].maxlen;
|
||||||
|
pin_info.pad_char = pins[i].pad_char;
|
||||||
|
sc_format_path(pins[i].path, &pin_info.path);
|
||||||
|
pin_info.path.value[2] = dfpath >> 8;
|
||||||
|
pin_info.path.value[3] = dfpath & 0xff;
|
||||||
|
pin_info.tries_left = -1;
|
||||||
|
|
||||||
|
strncpy(pin_obj.label, pins[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
||||||
|
pin_obj.flags = pins[i].obj_flags;
|
||||||
|
|
||||||
|
r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
|
||||||
|
if (r < 0)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* set public keys */
|
||||||
|
/* We may only need this during initialzation when genkey
|
||||||
|
* gets the pubkey, but it can not be read from the card
|
||||||
|
* at a later time. The piv-tool can stach in file
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0; pubkeys[i].label; i++) {
|
||||||
|
struct sc_pkcs15_pubkey_info pubkey_info;
|
||||||
|
struct sc_pkcs15_object pubkey_obj;
|
||||||
|
|
||||||
|
memset(&pubkey_info, 0, sizeof(pubkey_info));
|
||||||
|
memset(&pubkey_obj, 0, sizeof(pubkey_obj));
|
||||||
|
|
||||||
|
sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id);
|
||||||
|
pubkey_info.usage = pubkeys[i].usage;
|
||||||
|
pubkey_info.native = 1;
|
||||||
|
pubkey_info.key_reference = pubkeys[i].ref;
|
||||||
|
pubkey_info.modulus_length= pubkeys[i].modulus_len;
|
||||||
|
/* we really don't know how many bits or module length,
|
||||||
|
* we will assume 1024 for now
|
||||||
|
*/
|
||||||
|
sc_format_path(pubkeys[i].path, &pubkey_info.path);
|
||||||
|
|
||||||
|
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
||||||
|
|
||||||
|
pubkey_obj.flags = pubkeys[i].obj_flags;
|
||||||
|
|
||||||
|
if (pubkeys[i].auth_id)
|
||||||
|
sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id);
|
||||||
|
|
||||||
|
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||||
|
if (r < 0)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* set private keys */
|
||||||
|
for (i = 0; prkeys[i].label; i++) {
|
||||||
|
struct sc_pkcs15_prkey_info prkey_info;
|
||||||
|
struct sc_pkcs15_object prkey_obj;
|
||||||
|
|
||||||
|
memset(&prkey_info, 0, sizeof(prkey_info));
|
||||||
|
memset(&prkey_obj, 0, sizeof(prkey_obj));
|
||||||
|
|
||||||
|
sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
|
||||||
|
prkey_info.usage = prkeys[i].usage;
|
||||||
|
prkey_info.native = 1;
|
||||||
|
prkey_info.key_reference = prkeys[i].ref;
|
||||||
|
prkey_info.modulus_length= prkeys[i].modulus_len;
|
||||||
|
/* we really don't know how many bits or module length,
|
||||||
|
* we will assume 1024 for now
|
||||||
|
*/
|
||||||
|
sc_format_path(prkeys[i].path, &prkey_info.path);
|
||||||
|
|
||||||
|
strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
||||||
|
|
||||||
|
prkey_obj.flags = prkeys[i].obj_flags;
|
||||||
|
|
||||||
|
if (prkeys[i].auth_id)
|
||||||
|
sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);
|
||||||
|
|
||||||
|
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
|
||||||
|
if (r < 0)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *p15card,
|
||||||
|
sc_pkcs15emu_opt_t *opts)
|
||||||
|
{
|
||||||
|
sc_card_t *card = p15card->card;
|
||||||
|
sc_context_t *ctx = card->ctx;
|
||||||
|
|
||||||
|
SC_FUNC_CALLED(ctx, 1);
|
||||||
|
|
||||||
|
if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)
|
||||||
|
return sc_pkcs15emu_piv_init(p15card);
|
||||||
|
else {
|
||||||
|
int r = piv_detect_card(p15card);
|
||||||
|
if (r)
|
||||||
|
return SC_ERROR_WRONG_CARD;
|
||||||
|
return sc_pkcs15emu_piv_init(p15card);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,8 @@ extern int sc_pkcs15emu_esteid_init_ex(sc_pkcs15_card_t *,
|
||||||
sc_pkcs15emu_opt_t *);
|
sc_pkcs15emu_opt_t *);
|
||||||
extern int sc_pkcs15emu_postecert_init_ex(sc_pkcs15_card_t *,
|
extern int sc_pkcs15emu_postecert_init_ex(sc_pkcs15_card_t *,
|
||||||
sc_pkcs15emu_opt_t *);
|
sc_pkcs15emu_opt_t *);
|
||||||
|
extern int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *p15card,
|
||||||
|
sc_pkcs15emu_opt_t *opts);
|
||||||
extern int sc_pkcs15emu_gemsafe_init_ex(sc_pkcs15_card_t *p15card,
|
extern int sc_pkcs15emu_gemsafe_init_ex(sc_pkcs15_card_t *p15card,
|
||||||
sc_pkcs15emu_opt_t *opts);
|
sc_pkcs15emu_opt_t *opts);
|
||||||
extern int sc_pkcs15emu_actalis_init_ex(sc_pkcs15_card_t *p15card,
|
extern int sc_pkcs15emu_actalis_init_ex(sc_pkcs15_card_t *p15card,
|
||||||
|
@ -58,6 +60,7 @@ static struct {
|
||||||
{ "tcos", sc_pkcs15emu_tcos_init_ex },
|
{ "tcos", sc_pkcs15emu_tcos_init_ex },
|
||||||
{ "esteid", sc_pkcs15emu_esteid_init_ex },
|
{ "esteid", sc_pkcs15emu_esteid_init_ex },
|
||||||
{ "postecert", sc_pkcs15emu_postecert_init_ex },
|
{ "postecert", sc_pkcs15emu_postecert_init_ex },
|
||||||
|
{ "PIV-II", sc_pkcs15emu_piv_init_ex },
|
||||||
{ "gemsafe", sc_pkcs15emu_gemsafe_init_ex },
|
{ "gemsafe", sc_pkcs15emu_gemsafe_init_ex },
|
||||||
{ "actalis", sc_pkcs15emu_actalis_init_ex },
|
{ "actalis", sc_pkcs15emu_actalis_init_ex },
|
||||||
{ "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex},
|
{ "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex},
|
||||||
|
|
|
@ -119,8 +119,7 @@ int sc_pkcs15emu_tcos_init_ex(sc_pkcs15_card_t *p15card, sc_pkcs15emu_opt_t *opt
|
||||||
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
|
||||||
SC_PKCS15_PIN_FLAG_INITIALIZED},
|
SC_PKCS15_PIN_FLAG_INITIALIZED},
|
||||||
{3, 1, 2, 6, 0x00, "5000", "globale PIN",
|
{3, 1, 2, 6, 0x00, "5000", "globale PIN",
|
||||||
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED },
|
||||||
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN},
|
|
||||||
{3, 2, 0, 8, 0x01, "5008", "globale PUK",
|
{3, 2, 0, 8, 0x01, "5008", "globale PUK",
|
||||||
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
|
||||||
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN},
|
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN},
|
||||||
|
|
|
@ -12,11 +12,14 @@ PROGRAMS_OPENSSL = cryptoflex-tool pkcs15-init netkey-tool
|
||||||
endif
|
endif
|
||||||
|
|
||||||
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
|
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
|
||||||
|
piv-tool \
|
||||||
pkcs11-tool cardos-info eidenv \
|
pkcs11-tool cardos-info eidenv \
|
||||||
$(PROGRAMS_OPENSSL)
|
$(PROGRAMS_OPENSSL)
|
||||||
|
|
||||||
opensc_tool_SOURCES = opensc-tool.c util.c
|
opensc_tool_SOURCES = opensc-tool.c util.c
|
||||||
opensc_tool_LDADD = @GETOPTSRC@
|
opensc_tool_LDADD = @GETOPTSRC@
|
||||||
|
piv_tool_SOURCES = piv-tool.c util.c
|
||||||
|
piv_tool_LDADD = @GETOPTSRC@
|
||||||
opensc_explorer_SOURCES = opensc-explorer.c util.c
|
opensc_explorer_SOURCES = opensc-explorer.c util.c
|
||||||
opensc_explorer_LDADD = @GETOPTSRC@ $(LIBREADLINE)
|
opensc_explorer_LDADD = @GETOPTSRC@ $(LIBREADLINE)
|
||||||
pkcs15_tool_SOURCES = pkcs15-tool.c util.c
|
pkcs15_tool_SOURCES = pkcs15-tool.c util.c
|
||||||
|
|
|
@ -4,6 +4,7 @@ TOPDIR = ..\..
|
||||||
!INCLUDE $(TOPDIR)\win32\Make.rules.mak
|
!INCLUDE $(TOPDIR)\win32\Make.rules.mak
|
||||||
|
|
||||||
TARGETS = opensc-explorer.exe opensc-tool.exe \
|
TARGETS = opensc-explorer.exe opensc-tool.exe \
|
||||||
|
piv-tool.exe \
|
||||||
pkcs15-tool.exe pkcs15-crypt.exe pkcs11-tool.exe cardos-info.exe eidenv.exe $(PKCS15_INIT)
|
pkcs15-tool.exe pkcs15-crypt.exe pkcs11-tool.exe cardos-info.exe eidenv.exe $(PKCS15_INIT)
|
||||||
|
|
||||||
all: util.obj $(TARGETS)
|
all: util.obj $(TARGETS)
|
||||||
|
|
|
@ -0,0 +1,497 @@
|
||||||
|
/*
|
||||||
|
* piv-tool.c: Tool for accessing smart cards with libopensc
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||||
|
* Copyright (C) 2005, Douglas E. Engert <deengert@anl.gov>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <opensc/opensc.h>
|
||||||
|
#include <opensc/cardctl.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
const char *app_name = "opensc-tool";
|
||||||
|
|
||||||
|
static int opt_reader = -1,
|
||||||
|
opt_wait = 0;
|
||||||
|
static char ** opt_apdus;
|
||||||
|
static int opt_apdu_count = 0;
|
||||||
|
static int verbose = 0;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPT_SERIAL = 0x100,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct option options[] = {
|
||||||
|
{ "serial", 0, 0, OPT_SERIAL },
|
||||||
|
{ "name", 0, 0, 'n' },
|
||||||
|
{ "admin", 0, 0, 'A' },
|
||||||
|
{ "usepin", 0, 0, 'P' }, /* some beta cards want user pin for put_data */
|
||||||
|
{ "genkey", 0, 0, 'G' },
|
||||||
|
{ "cert", 0, 0, 'C' },
|
||||||
|
{ "req", 0, 0, 'R' },
|
||||||
|
{ "out", 0, 0, 'o' },
|
||||||
|
{ "in", 0, 0, 'o' },
|
||||||
|
{ "send-apdu", 1, 0, 's' },
|
||||||
|
{ "reader", 1, 0, 'r' },
|
||||||
|
{ "card-driver", 1, 0, 'c' },
|
||||||
|
{ "wait", 0, 0, 'w' },
|
||||||
|
{ "verbose", 0, 0, 'v' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *option_help[] = {
|
||||||
|
"Prints the card serial number",
|
||||||
|
"Identify the card and print its name",
|
||||||
|
"authenticate using default 3des key",
|
||||||
|
"authenticate using user pin",
|
||||||
|
"Generate key <ref>:<alg> 9A:06 on card, and output pubkey",
|
||||||
|
"Load the AUTH cert onto card from file <arg>",
|
||||||
|
"Generate a cert req",
|
||||||
|
"Output file for cert or key or req",
|
||||||
|
"Inout file for cert",
|
||||||
|
"Sends an APDU in format AA:BB:CC:DD:EE:FF...",
|
||||||
|
"Uses reader number <arg> [0]",
|
||||||
|
"Forces the use of driver <arg> [auto-detect]",
|
||||||
|
"Wait for a card to be inserted",
|
||||||
|
"Verbose operation. Use several times to enable debug output.",
|
||||||
|
};
|
||||||
|
|
||||||
|
sc_context_t *ctx = NULL;
|
||||||
|
sc_card_t *card = NULL;
|
||||||
|
BIO * bp = NULL;
|
||||||
|
RSA * newkey = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static int load_cert(char * cert_id, char * cert_file)
|
||||||
|
{
|
||||||
|
X509 * cert = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
u8 buf[1];
|
||||||
|
size_t buflen = 1;
|
||||||
|
sc_path_t path;
|
||||||
|
u8 *der = NULL;
|
||||||
|
u8 *p;
|
||||||
|
size_t derlen;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
|
||||||
|
if((fp=fopen(cert_file, "r"))==NULL){
|
||||||
|
printf("Cannot open cert file, %s %s\n",
|
||||||
|
cert_file, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cert = PEM_read_X509(fp, &cert, NULL, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
if(cert == NULL){
|
||||||
|
printf("file %s does not conatin PEM-encoded certificate\n",
|
||||||
|
cert_file);
|
||||||
|
return-1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
derlen = i2d_X509(cert, NULL);
|
||||||
|
der = (u8 *) malloc(derlen);
|
||||||
|
p = der;
|
||||||
|
i2d_X509(cert, &p);
|
||||||
|
|
||||||
|
sc_hex_to_bin(cert_id, buf,&buflen);
|
||||||
|
|
||||||
|
switch (buf[0]) {
|
||||||
|
case 0x9a: sc_format_path("0101",&path); break;
|
||||||
|
case 0x9b: sc_format_path("0500",&path); break;
|
||||||
|
case 0x9c: sc_format_path("0100",&path); break;
|
||||||
|
case 0x9d: sc_format_path("0102",&path); break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr,"cert must be 9A, 9B, 9C or 9D\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sc_select_file(card, &path, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
fprintf(stderr, "select file failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
r = sc_write_binary(card, 0, der, derlen, 0);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
|
}
|
||||||
|
static int admin_mode(char* admin_info)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
u8 opts[3];
|
||||||
|
size_t buflen = 2;
|
||||||
|
|
||||||
|
|
||||||
|
if (strlen(admin_info) == 7 &&
|
||||||
|
(admin_info[0] == 'A' || admin_info[0] == 'M') &&
|
||||||
|
admin_info[1] == ':' &&
|
||||||
|
(sc_hex_to_bin(admin_info+2, opts+1, &buflen) == 0) &&
|
||||||
|
buflen == 2) {
|
||||||
|
opts[0] = admin_info[0];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, " admin_mode params <M|A>:<keyref>:<alg>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &opts);
|
||||||
|
if (r)
|
||||||
|
fprintf(stderr, " admin_mode failed %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate a req using xxx as subject */
|
||||||
|
static int req()
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Not Implemented yet\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate a new key pair, and save public key in newkey */
|
||||||
|
static int gen_key(char * key_info)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
u8 buf[2];
|
||||||
|
size_t buflen = 2;
|
||||||
|
struct sc_cardctl_cryptoflex_genkey_info
|
||||||
|
keydata = { 0x9a, 1024, 0, NULL, 0};
|
||||||
|
unsigned long expl;
|
||||||
|
u8 expc[4];
|
||||||
|
|
||||||
|
sc_hex_to_bin(key_info, buf, &buflen);
|
||||||
|
if (buflen != 2) {
|
||||||
|
fprintf(stderr, "<keyref>:<algid> invalid, example: 9A:06\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
switch (buf[0]) {
|
||||||
|
case 0x9a:
|
||||||
|
case 0x9b:
|
||||||
|
case 0x9c:
|
||||||
|
case 0x9d:
|
||||||
|
keydata.key_num = buf[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "<keyref>:<algid> must be 9A, 9B, 9C or 9D\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (buf[1]) {
|
||||||
|
case 5: keydata.key_bits = 3072; break;
|
||||||
|
case 6: keydata.key_bits = 1024; break;
|
||||||
|
case 7: keydata.key_bits = 2048; break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "<keyref>:<algid> algid, 05, 06, 07 for 3072, 1024, 2048\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sc_card_ctl(card, SC_CARDCTL_CRYPTOFLEX_GENERATE_KEY, &keydata);
|
||||||
|
if (r) {
|
||||||
|
fprintf(stderr, "gen_key failed %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
newkey = RSA_new();
|
||||||
|
if (newkey == NULL) {
|
||||||
|
fprintf(stderr, "gen_key RSA_new failed %d\n",r);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
newkey->n = BN_bin2bn(keydata.pubkey, keydata.pubkey_len, newkey->n);
|
||||||
|
expl = keydata.exponent;
|
||||||
|
expc[3] = (u8) expl & 0xff;
|
||||||
|
expc[2] = (u8) (expl >>8) & 0xff;
|
||||||
|
expc[1] = (u8) (expl >>16) & 0xff;
|
||||||
|
expc[0] = (u8) (expl >>24) & 0xff;
|
||||||
|
newkey->e = BN_bin2bn(expc, 4, newkey->e);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
RSA_print_fp(stdout, newkey,0);
|
||||||
|
|
||||||
|
if (bp)
|
||||||
|
PEM_write_bio_RSAPublicKey(bp, newkey);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_apdu(void)
|
||||||
|
{
|
||||||
|
sc_apdu_t apdu;
|
||||||
|
u8 buf[SC_MAX_APDU_BUFFER_SIZE], sbuf[SC_MAX_APDU_BUFFER_SIZE],
|
||||||
|
rbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
|
||||||
|
size_t len, len0, r;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (c = 0; c < opt_apdu_count; c++) {
|
||||||
|
len0 = sizeof(buf);
|
||||||
|
sc_hex_to_bin(opt_apdus[c], buf, &len0);
|
||||||
|
if (len0 < 4) {
|
||||||
|
fprintf(stderr, "APDU too short (must be at least 4 bytes).\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
len = len0;
|
||||||
|
p = buf;
|
||||||
|
memset(&apdu, 0, sizeof(apdu));
|
||||||
|
apdu.cla = *p++;
|
||||||
|
apdu.ins = *p++;
|
||||||
|
apdu.p1 = *p++;
|
||||||
|
apdu.p2 = *p++;
|
||||||
|
apdu.resp = rbuf;
|
||||||
|
apdu.resplen = sizeof(rbuf);
|
||||||
|
len -= 4;
|
||||||
|
if (len > 1) {
|
||||||
|
apdu.lc = *p++;
|
||||||
|
len--;
|
||||||
|
memcpy(sbuf, p, apdu.lc);
|
||||||
|
apdu.data = sbuf;
|
||||||
|
apdu.datalen = apdu.lc;
|
||||||
|
if (len < apdu.lc) {
|
||||||
|
fprintf(stderr, "APDU too short (need %d bytes).\n",
|
||||||
|
apdu.lc-len);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
len -= 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) {
|
||||||
|
fprintf(stderr, "APDU too long (%d bytes extra).\n", len);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
} else if (len == 1) {
|
||||||
|
apdu.le = *p++;
|
||||||
|
if (apdu.le == 0)
|
||||||
|
apdu.le = 256;
|
||||||
|
len--;
|
||||||
|
apdu.cse = SC_APDU_CASE_2_SHORT;
|
||||||
|
} else
|
||||||
|
apdu.cse = SC_APDU_CASE_1;
|
||||||
|
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)
|
||||||
|
hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_serial(sc_card_t *in_card)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
sc_serial_number_t serial;
|
||||||
|
|
||||||
|
r = sc_card_ctl(in_card, SC_CARDCTL_GET_SERIALNR, &serial);
|
||||||
|
if (r)
|
||||||
|
fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_GET_SERIALNR, *) failed\n");
|
||||||
|
else
|
||||||
|
hex_dump_asc(stdout, serial.value, serial.len, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * const argv[])
|
||||||
|
{
|
||||||
|
int err = 0, r, c, long_optind = 0;
|
||||||
|
int do_send_apdu = 0;
|
||||||
|
int do_admin_mode = 0;
|
||||||
|
int do_gen_key = 0;
|
||||||
|
int do_load_cert = 0;
|
||||||
|
int do_req = 0;
|
||||||
|
int do_print_serial = 0;
|
||||||
|
int do_print_name = 0;
|
||||||
|
int action_count = 0;
|
||||||
|
const char *opt_driver = NULL;
|
||||||
|
const char *out_file = NULL;
|
||||||
|
const char *in_file = NULL;
|
||||||
|
const char *cert_id = NULL;
|
||||||
|
const char *key_info = NULL;
|
||||||
|
const char *admin_info = NULL;
|
||||||
|
|
||||||
|
setbuf(stderr, NULL);
|
||||||
|
setbuf(stdout, NULL);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = getopt_long(argc, argv, "nA:G:C:Ri:o:fvs:c:w", options, &long_optind);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
if (c == '?')
|
||||||
|
print_usage_and_die();
|
||||||
|
switch (c) {
|
||||||
|
case 's':
|
||||||
|
opt_apdus = (char **) realloc(opt_apdus,
|
||||||
|
(opt_apdu_count + 1) * sizeof(char *));
|
||||||
|
opt_apdus[opt_apdu_count] = optarg;
|
||||||
|
do_send_apdu++;
|
||||||
|
if (opt_apdu_count == 0)
|
||||||
|
action_count++;
|
||||||
|
opt_apdu_count++;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
do_print_name = 1;
|
||||||
|
action_count++;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
do_admin_mode = 1;
|
||||||
|
admin_info = optarg;
|
||||||
|
action_count++;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
do_gen_key = 1;
|
||||||
|
key_info = optarg;
|
||||||
|
action_count++;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
do_load_cert = 1;
|
||||||
|
cert_id = optarg;
|
||||||
|
action_count++;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
do_req = 1;
|
||||||
|
action_count++;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
in_file = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
out_file = optarg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
opt_reader = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
opt_driver = optarg;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
opt_wait = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (action_count == 0)
|
||||||
|
print_usage_and_die();
|
||||||
|
|
||||||
|
CRYPTO_malloc_init();
|
||||||
|
ERR_load_crypto_strings();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
|
|
||||||
|
if (out_file) {
|
||||||
|
bp = BIO_new(BIO_s_file());
|
||||||
|
BIO_write_filename(bp, out_file);
|
||||||
|
} else {
|
||||||
|
bp = BIO_new(BIO_s_file());
|
||||||
|
BIO_set_fp(bp,stdout,BIO_NOCLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sc_establish_context(&ctx, app_name);
|
||||||
|
if (r) {
|
||||||
|
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (verbose > 1)
|
||||||
|
ctx->debug = verbose-1;
|
||||||
|
|
||||||
|
if (action_count <= 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = connect_card(ctx, &card, opt_reader, 0, opt_wait, verbose);
|
||||||
|
if (err)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (do_admin_mode) {
|
||||||
|
if ((err = admin_mode(admin_info)))
|
||||||
|
goto end;
|
||||||
|
action_count--;
|
||||||
|
}
|
||||||
|
if (do_send_apdu) { /* can use pin before load cert for a beta card */
|
||||||
|
if ((err = send_apdu()))
|
||||||
|
goto end;
|
||||||
|
action_count--;
|
||||||
|
}
|
||||||
|
if (do_gen_key) {
|
||||||
|
if ((err = gen_key(key_info)))
|
||||||
|
goto end;
|
||||||
|
action_count--;
|
||||||
|
}
|
||||||
|
if (do_load_cert) {
|
||||||
|
if ((err = load_cert(cert_id, in_file)))
|
||||||
|
goto end;
|
||||||
|
action_count--;
|
||||||
|
}
|
||||||
|
if (do_print_serial) {
|
||||||
|
if (verbose)
|
||||||
|
printf("Card serial number:");
|
||||||
|
print_serial(card);
|
||||||
|
action_count--;
|
||||||
|
}
|
||||||
|
if (do_print_name) {
|
||||||
|
if (verbose)
|
||||||
|
printf("Card name: ");
|
||||||
|
printf("%s\n", card->name);
|
||||||
|
action_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (bp)
|
||||||
|
BIO_free(bp);
|
||||||
|
if (card) {
|
||||||
|
sc_unlock(card);
|
||||||
|
sc_disconnect_card(card, 0);
|
||||||
|
}
|
||||||
|
if (ctx)
|
||||||
|
sc_release_context(ctx);
|
||||||
|
return err;
|
||||||
|
}
|
|
@ -325,6 +325,8 @@ static int read_data_object(void)
|
||||||
r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
|
r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
|
fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
|
||||||
|
if (r == SC_ERROR_FILE_NOT_FOUND)
|
||||||
|
continue; /* DEE emulation may say there is a file */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
r = print_data_object("Data Object", data_object->data, data_object->data_len);
|
r = print_data_object("Data Object", data_object->data, data_object->data_len);
|
||||||
|
@ -369,6 +371,8 @@ static int list_data_objects(void)
|
||||||
r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
|
r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
|
fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
|
||||||
|
if (r == SC_ERROR_FILE_NOT_FOUND)
|
||||||
|
continue; /* DEE emulation may say there is a file */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
r = list_data_object("Data Object", data_object->data, data_object->data_len);
|
r = list_data_object("Data Object", data_object->data, data_object->data_len);
|
||||||
|
|
Loading…
Reference in New Issue