- added some missing files from last commits, whoops
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@217 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
d2a36c88fd
commit
b5736099a2
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* card_ctl command numbers
|
||||
*
|
||||
* There is a range of generic card_ctls, and card-specific
|
||||
* ranges. I've used a 3-letter abbreviation of the card in
|
||||
* the prefix, but that's just a fad :)
|
||||
*
|
||||
* For now, I've reserved these:
|
||||
* 0x0000xxxx generic
|
||||
* 0x4C4658xx Cryptoflex
|
||||
* 0x47504Bxx GPK
|
||||
*/
|
||||
|
||||
#ifndef _OPENSC_CARDCTL_H
|
||||
#define _OPENSC_CARDCTL_H
|
||||
|
||||
#define _CTL_PREFIX(a, b, c) (((a) << 24) | ((b) << 16) || ((c) << 8))
|
||||
|
||||
enum {
|
||||
/*
|
||||
* Generic card_ctl calls
|
||||
*/
|
||||
SC_CARDCTL_GENERIC_BASE = 0x00000000,
|
||||
SC_CARDCTL_ERASE_CARD,
|
||||
|
||||
/*
|
||||
* GPK specific calls
|
||||
*/
|
||||
SC_CARDCTL_GPK_BASE = _CTL_PREFIX('G', 'P', 'K'),
|
||||
SC_CARDCTL_GPK_LOCK,
|
||||
|
||||
/*
|
||||
* Cryptoflex specific calls
|
||||
*/
|
||||
SC_CARDCTL_CRYPTOFLEX_BASE = _CTL_PREFIX('C', 'F', 'X'),
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* GPK lock file.
|
||||
* Parent DF of file must be selected.
|
||||
*/
|
||||
struct sc_cardctl_gpk_lock {
|
||||
struct sc_file * file;
|
||||
unsigned int operation;
|
||||
};
|
||||
|
||||
#endif /* _OPENSC_CARDCTL_H */
|
|
@ -0,0 +1,93 @@
|
|||
#
|
||||
# PKCS 15 r/w profile for GPK cards
|
||||
#
|
||||
CardInfo
|
||||
Label "OpenSC Card (GPK)"
|
||||
Manufacturer "OpenSC Project"
|
||||
MinPinLength 0
|
||||
MaxPinLength 8
|
||||
#PinEncoding
|
||||
|
||||
# This is the secure messaging key required for
|
||||
# creating files in the MF
|
||||
Key PRO 0x0001 "=TEST KEYTEST KEY"
|
||||
|
||||
# This is the application DF
|
||||
DF
|
||||
Path 3F005015
|
||||
AID A0:00:00:00:63:50:4B:43:53:2D:31:35
|
||||
ACL *=NONE
|
||||
|
||||
# Currently we do not support PIN files that can be updated
|
||||
# by CHV2. Far too messy.
|
||||
EF pinfile
|
||||
Path 3F0050150000
|
||||
Structure 0x21 # GPK specific
|
||||
RecordLength 8
|
||||
Size 32
|
||||
ACL *=NEVER
|
||||
|
||||
EF PKCS15-DIR
|
||||
Path 3F002F00
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-ODF
|
||||
Path 3F0050155031
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-TokenInfo
|
||||
Path 3F0050155032
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-AODF
|
||||
Path 3F0050154401
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV2
|
||||
|
||||
EF PKCS15-PrKDF
|
||||
Path 3F0050154402
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV2
|
||||
|
||||
EF PKCS15-CDF
|
||||
Path 3F0050154403
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV2
|
||||
|
||||
EF pk1
|
||||
Path 3F0050150001
|
||||
ACL *=NEVER
|
||||
|
||||
EF pk2
|
||||
Path 3F0050150002
|
||||
ACL *=NEVER
|
||||
|
||||
# CVH1. 7 attempts for the PIN, and 3 for the PUK
|
||||
# Reference 0x8 means "PIN0 in the local EFsc" in GPK parlance
|
||||
PIN CHV1
|
||||
File pinfile
|
||||
Label "Authentication PIN"
|
||||
Reference 0x8
|
||||
Attempts 7 3
|
||||
AuthID 01
|
||||
|
||||
# CVH2. 7 attempts for the PIN, and 3 for the PUK
|
||||
# Reference 0xA means "PIN2 in the local EFsc" in GPK parlance
|
||||
PIN CHV2
|
||||
File pinfile
|
||||
Label "Non-repudiation PIN"
|
||||
Reference 0xA
|
||||
Attempts 7 3
|
||||
Offset 16
|
||||
AuthID 02
|
||||
|
||||
PrivateKey AuthKey
|
||||
Label "Authentication Key"
|
||||
File pk1
|
||||
ID 45
|
||||
AuthID 01 # Requires CHV1
|
||||
KeyUsage sign
|
||||
|
||||
PrivateKey SignKey
|
||||
Label "Non-repudiation Key"
|
||||
File pk2
|
||||
ID 46
|
||||
AuthID 02 # Requires CHV2
|
||||
KeyUsage NonRepudiation
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* GPK specific operation for PKCS15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 Olaf Kirch <okir@lst.de>
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include "opensc.h"
|
||||
#include "cardctl.h"
|
||||
#include "pkcs15-init.h"
|
||||
|
||||
#define GPK_MAX_PINS 8
|
||||
|
||||
/*
|
||||
* Erase the card
|
||||
*/
|
||||
static int
|
||||
gpk_erase_card(struct sc_profile *pro, struct sc_card *card)
|
||||
{
|
||||
return sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock a file operation
|
||||
*/
|
||||
static int
|
||||
gpk_lock(struct sc_card *card, struct sc_file *file, unsigned int op)
|
||||
{
|
||||
struct sc_cardctl_gpk_lock args;
|
||||
|
||||
args.file = file;
|
||||
args.operation = op;
|
||||
return sc_card_ctl(card, SC_CARDCTL_GPK_LOCK, &args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the contents of a PIN file
|
||||
*/
|
||||
static int
|
||||
gpk_update_pins(struct sc_card *card, struct pin_info *info)
|
||||
{
|
||||
u_int8_t buffer[GPK_MAX_PINS * 8], *blk;
|
||||
u_int8_t temp[16];
|
||||
unsigned int npins, i, j, tries, cks;
|
||||
int r;
|
||||
|
||||
npins = info->attempt[1]? 2 : 1;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
for (i = 0, blk = buffer; i < npins; i++, blk += 8) {
|
||||
tries = info->attempt[i];
|
||||
if (tries == 0 || tries > 7) {
|
||||
/*
|
||||
error("invalid number of PIN attempts %u "
|
||||
"(must be 1 ... 7)",
|
||||
tries);
|
||||
*/
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
blk[0] = tries;
|
||||
if (i < npins)
|
||||
blk[2] = 0x8 | (i + 1);
|
||||
|
||||
memset(temp, 0, sizeof(temp));
|
||||
strncpy(temp, info->secret[i], 8);
|
||||
blk[4] = (temp[0] << 4) | (temp[1] & 0xF);
|
||||
blk[5] = (temp[2] << 4) | (temp[3] & 0xF);
|
||||
blk[6] = (temp[4] << 4) | (temp[5] & 0xF);
|
||||
blk[7] = (temp[6] << 4) | (temp[7] & 0xF);
|
||||
|
||||
/* Compute the CKS */
|
||||
for (j = 0, cks = 0; j < 8; j++)
|
||||
cks ^= blk[j];
|
||||
blk[3] = ~cks;
|
||||
}
|
||||
|
||||
/* FIXME: we shouldn't have to know about the offset shift
|
||||
* here. Implement a gpk_update_binary function that just
|
||||
* shifts the offset if required.
|
||||
*/
|
||||
r = sc_update_binary(card, info->file_offset/4, buffer, npins * 8, 0);
|
||||
|
||||
return r < 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the PIN file and write the PINs
|
||||
*/
|
||||
static int
|
||||
gpk_store_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct pin_info *info, int *lockit)
|
||||
{
|
||||
const struct sc_acl_entry *acl;
|
||||
struct sc_file *pinfile;
|
||||
int r;
|
||||
|
||||
sc_file_dup(&pinfile, info->file->file);
|
||||
|
||||
/* Create the PIN file. If the UPDATE AC is NEVER,
|
||||
* we change it to NONE so we're able to init the
|
||||
* file, and then lock it.
|
||||
* If the UPDATE AC is anything else, we assume that
|
||||
* we have the required keys/pins to be granted access. */
|
||||
acl = sc_file_get_acl_entry(pinfile, SC_AC_OP_UPDATE);
|
||||
if (acl->method == SC_AC_NEVER) {
|
||||
sc_file_add_acl_entry(pinfile, SC_AC_OP_UPDATE, SC_AC_NONE, 0);
|
||||
*lockit = 1;
|
||||
}
|
||||
for (; acl; acl = acl->next) {
|
||||
if (acl->method == SC_AC_CHV) {
|
||||
fprintf(stderr,
|
||||
"CHV protected PIN files not supported\n");
|
||||
r = SC_ERROR_INVALID_ARGUMENTS;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now create the file */
|
||||
if ((r = do_create_file(profile, pinfile)) < 0)
|
||||
goto out;
|
||||
|
||||
/* If messing with the PIN file requires any sort of
|
||||
* authentication, send it to the card now */
|
||||
if ((r = sc_select_file(card, &pinfile->path, NULL)) < 0
|
||||
|| (r = do_verify_authinfo(profile, pinfile, SC_AC_OP_UPDATE)) < 0)
|
||||
goto out;
|
||||
|
||||
r = gpk_update_pins(card, info);
|
||||
|
||||
out: sc_file_free(pinfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_lock_pinfile(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *pinfile)
|
||||
{
|
||||
struct sc_file *parent = NULL;
|
||||
int r;
|
||||
|
||||
/* If the UPDATE AC should be NEVER, set the AC now */
|
||||
if ((r = do_select_parent(profile, pinfile, &parent)) != 0
|
||||
|| (r = do_verify_authinfo(profile, parent, SC_AC_OP_LOCK)) != 0)
|
||||
goto out;
|
||||
r = gpk_lock(card, pinfile, SC_AC_OP_UPDATE);
|
||||
out: if (parent)
|
||||
sc_file_free(parent);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the Application DF and store the PINs
|
||||
*
|
||||
* Restrictions:
|
||||
* For the GPK, it's fairly tricky to store the CHV1 in a
|
||||
* file and protect the update operation with CHV2.
|
||||
*
|
||||
* There are two properties of the GPK that make this difficult:
|
||||
* - you can have only one secret key file per DF
|
||||
*
|
||||
* - you cannot create the file without PIN protection, then
|
||||
* write the contents, then set the PIN protection. The GPK
|
||||
* has a somewhat cumbersome feature where you first protect
|
||||
* the file with the global PIN, write to it after presenting
|
||||
* the global PIN, and then "localize" the access condition,
|
||||
* telling it to use the local PIN EF instead of the global
|
||||
* one.
|
||||
*
|
||||
* A. Put CHV2 into the MF. This works, but makes dealing with
|
||||
* CHV2 tricky for applications, because you must first select
|
||||
* the DF in which the PIN file resides, and then call Verify.
|
||||
*
|
||||
* B. Store both CHV1 and CHV2 in the same PIN file in the
|
||||
* application DF. But in order to allow CHV2 to update the
|
||||
* PIN file directly using you need to create a global PIN file in
|
||||
* the MF first, and "localize" the application pin file's
|
||||
* access conditions later.
|
||||
*
|
||||
* Neither option is really appealing, which is why for now, I
|
||||
* simply reject CHV protected pin files.
|
||||
*/
|
||||
static int
|
||||
gpk_init_app(struct sc_profile *profile, struct sc_card *card)
|
||||
{
|
||||
struct pin_info *pin1, *pin2;
|
||||
int lockit = 0;
|
||||
|
||||
pin1 = sc_profile_find_pin(profile, "CHV1");
|
||||
pin2 = sc_profile_find_pin(profile, "CHV2");
|
||||
if (pin1 == NULL) {
|
||||
fprintf(stderr, "No CHV1 defined\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* XXX TODO:
|
||||
* if the CHV2 pin file is required to create files
|
||||
* in the application DF, create that file first */
|
||||
|
||||
/* Create the application DF */
|
||||
if (do_create_file(profile, profile->df_info.file))
|
||||
return 1;
|
||||
|
||||
/* Store CHV2 */
|
||||
lockit = 0;
|
||||
if (pin2) {
|
||||
if (gpk_store_pin(profile, card, pin2, &lockit))
|
||||
return 1;
|
||||
/* If both PINs reside in the same file, don't lock
|
||||
* it yet. */
|
||||
if (pin1->file != pin2->file && lockit) {
|
||||
if (gpk_lock_pinfile(profile, card, pin2->file->file))
|
||||
return 1;
|
||||
lockit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store CHV1 */
|
||||
if (gpk_store_pin(profile, card, pin1, &lockit))
|
||||
return 1;
|
||||
|
||||
if (lockit && gpk_lock_pinfile(profile, card, pin2->file->file))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
bind_gpk_operations(struct sc_profile *profile)
|
||||
{
|
||||
profile->erase_card = gpk_erase_card;
|
||||
profile->init_app = gpk_init_app;
|
||||
}
|
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
* Initialize Cards according to PKCS#15.
|
||||
*
|
||||
* This is a fill in the blanks sort of exercise. You need a
|
||||
* profile that describes characteristics of your card, and the
|
||||
* application specific layout on the card. This program will
|
||||
* set up the card according to this specification (including
|
||||
* PIN initialization etc) and create the corresponding PKCS15
|
||||
* structure.
|
||||
*
|
||||
* There are a very few tasks that are too card specific to have
|
||||
* a generic implementation; that is how PINs and keys are stored
|
||||
* on the card. These should be implemented in pkcs-<cardname>.c
|
||||
*
|
||||
* Copyright (C) 2002, Olaf Kirch <okir@lst.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include "opensc-pkcs15.h"
|
||||
#include "util.h"
|
||||
#include "profile.h"
|
||||
#include "pkcs15-init.h"
|
||||
|
||||
/* Handle encoding of PKCS15 on the card */
|
||||
typedef int (*pkcs15_encoder)(struct sc_context *,
|
||||
struct sc_pkcs15_card *, u8 **, size_t *);
|
||||
|
||||
/* Local functions */
|
||||
static int connect(int);
|
||||
static void bind_operations(struct sc_profile *);
|
||||
static int pkcs15_init(struct sc_profile *);
|
||||
static int pkcs15_write(struct sc_profile *,
|
||||
const char *name, pkcs15_encoder, int);
|
||||
static int pkcs15_write_df(struct sc_profile *,
|
||||
struct sc_pkcs15_df *, unsigned int);
|
||||
static int do_read_pins(struct sc_profile *);
|
||||
static void usage(int);
|
||||
|
||||
|
||||
enum {
|
||||
OPT_PIN1 = 0x10000, /* don't touch these values */
|
||||
OPT_PUK1 = 0x10001,
|
||||
OPT_PIN2 = 0x10002,
|
||||
OPT_PUK2 = 0x10003,
|
||||
};
|
||||
|
||||
const struct option options[] = {
|
||||
{ "erase-card", no_argument, 0, 'E' },
|
||||
{ "create-pkcs15", no_argument, 0, 'C' },
|
||||
{ "pin1", required_argument, 0, OPT_PIN1 },
|
||||
{ "puk1", required_argument, 0, OPT_PUK1 },
|
||||
{ "pin2", required_argument, 0, OPT_PIN2 },
|
||||
{ "puk2", required_argument, 0, OPT_PUK2 },
|
||||
|
||||
{ "debug", no_argument, 0, 'd' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
const char * option_help[] = {
|
||||
"Erase the smart card",
|
||||
"Creates a new PKCS #15 structure",
|
||||
|
||||
"Enable debugging output",
|
||||
};
|
||||
|
||||
static struct sc_context * ctx = NULL;
|
||||
static struct sc_card * card = NULL;
|
||||
static int opt_debug = 0,
|
||||
opt_quiet = 0;
|
||||
static char * opt_pins[4];
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct sc_pkcs15_card *p15card;
|
||||
struct sc_profile profile;
|
||||
int opt_reader = 0;
|
||||
int do_erase = 0,
|
||||
do_init = 0;
|
||||
int c, r = 0, index = -1;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "CEd", options, &index)) != -1) {
|
||||
switch (c) {
|
||||
case 'C':
|
||||
do_init = 1;
|
||||
break;
|
||||
case 'E':
|
||||
do_erase = 1;
|
||||
break;
|
||||
case 'd':
|
||||
opt_debug++;
|
||||
break;
|
||||
case OPT_PIN1: case OPT_PUK1:
|
||||
case OPT_PIN2: case OPT_PUK2:
|
||||
opt_pins[c & 3] = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc - 1)
|
||||
usage(1);
|
||||
|
||||
p15card = sc_pkcs15_card_new();
|
||||
if (p15card == NULL)
|
||||
return 1;
|
||||
|
||||
sc_profile_init(&profile, p15card);
|
||||
|
||||
if (sc_profile_load(&profile, argv[optind]))
|
||||
return 1;
|
||||
|
||||
if (sc_profile_finish(&profile))
|
||||
return 1;
|
||||
|
||||
if (!connect(opt_reader))
|
||||
return 1;
|
||||
|
||||
/* Now bind the card specific operations */
|
||||
bind_operations(&profile);
|
||||
|
||||
if (do_erase) {
|
||||
r = profile.erase_card(&profile, card);
|
||||
if (r != 0)
|
||||
goto done;
|
||||
}
|
||||
if (do_init) {
|
||||
r = pkcs15_init(&profile);
|
||||
if (r != 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
done: if (card) {
|
||||
sc_unlock(card);
|
||||
sc_disconnect_card(card);
|
||||
}
|
||||
sc_destroy_context(ctx);
|
||||
return r? 1 : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bind_operations(struct sc_profile *profile)
|
||||
{
|
||||
const char *driver;
|
||||
|
||||
if ((driver = profile->driver) == 0)
|
||||
driver = card->driver->short_name;
|
||||
|
||||
if (!strcasecmp(driver, "GPK"))
|
||||
bind_gpk_operations(profile);
|
||||
else
|
||||
fatal("Don't know how to handle %s cards", profile->driver);
|
||||
}
|
||||
|
||||
static int
|
||||
connect(int reader)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = sc_establish_context(&ctx);
|
||||
if (r) {
|
||||
error("Failed to establish context: %s\n", sc_strerror(r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->error_file = stderr;
|
||||
ctx->debug_file = stdout;
|
||||
ctx->debug = opt_debug;
|
||||
if (reader >= ctx->reader_count || reader < 0) {
|
||||
fprintf(stderr,
|
||||
"Illegal reader number. Only %d reader%s configured.\n",
|
||||
ctx->reader_count,
|
||||
ctx->reader_count == 1? "" : "s");
|
||||
return 0;
|
||||
}
|
||||
if (sc_detect_card(ctx, reader) != 1) {
|
||||
error("Card not present.\n");
|
||||
return 0;
|
||||
}
|
||||
if (!opt_quiet) {
|
||||
printf("Connecting to card in reader %s...\n",
|
||||
ctx->readers[reader]);
|
||||
}
|
||||
|
||||
r = sc_connect_card(ctx, reader, &card);
|
||||
if (r) {
|
||||
error("Failed to connect to card: %s\n", sc_strerror(r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Using card driver: %s\n", card->driver->name);
|
||||
r = sc_lock(card);
|
||||
if (r) {
|
||||
error("Unable to lock card: %s\n", sc_strerror(r));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pkcs15_init(struct sc_profile *pro)
|
||||
{
|
||||
int i, j, r;
|
||||
|
||||
/* Assemble the PKCS15 structure */
|
||||
if (sc_profile_build_pkcs15(pro))
|
||||
return 1;
|
||||
|
||||
/* Get all necessary PINs from user */
|
||||
if (do_read_pins(pro))
|
||||
return 1;
|
||||
|
||||
/* Create the application DF and store the PINs */
|
||||
if (pro->init_app(pro, card))
|
||||
return 1;
|
||||
|
||||
/* Store the PKCS15 information on the card
|
||||
* We cannot use sc_pkcs15_create() because it makes
|
||||
* all sorts of assumptions about DF and EF names, and
|
||||
* doesn't work if secure messaging is required for the
|
||||
* MF (which is the case with the GPK) */
|
||||
#ifdef notyet
|
||||
/* Create the file (what size?) */
|
||||
r = ...
|
||||
/* Update DIR */
|
||||
r = sc_update_dir(pro->p15_card);
|
||||
#else
|
||||
r = 0;
|
||||
#endif
|
||||
if (r >= 0)
|
||||
r = pkcs15_write(pro, "PKCS15-TokenInfo",
|
||||
sc_pkcs15_encode_tokeninfo, 0);
|
||||
if (r >= 0)
|
||||
r = pkcs15_write(pro, "PKCS15-ODF", sc_pkcs15_encode_odf, 0);
|
||||
|
||||
/* XXX Note we need to fill in the modulus length of PrKEY
|
||||
* objects at some point (is this info optional?).
|
||||
* Now would be a good time. */
|
||||
|
||||
/* Encode all DFs */
|
||||
for (i = 0; r >= 0 && i < SC_PKCS15_DF_TYPE_COUNT; i++) {
|
||||
struct sc_pkcs15_df *df = &pro->p15_card->df[i];
|
||||
|
||||
for (j = 0; r >= 0 && j < df->count; j++)
|
||||
r = pkcs15_write_df(pro, df, j);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
fprintf(stderr,
|
||||
"PKCS #15 structure creation failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Successfully created PKCS15 meta structure\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pkcs15_write(struct sc_profile *pro, const char *name,
|
||||
pkcs15_encoder encode, int required)
|
||||
{
|
||||
struct sc_pkcs15_card *p15card = pro->p15_card;
|
||||
struct file_info *info;
|
||||
struct sc_file *file;
|
||||
u8 *buf = NULL;
|
||||
size_t bufsize;
|
||||
int r;
|
||||
|
||||
info = sc_profile_find_file(pro, name);
|
||||
if (info == NULL) {
|
||||
if (required)
|
||||
fatal("No %s file defined; abort.", name);
|
||||
fprintf(stderr, "No %s file defined; not written\n", name);
|
||||
return 0;
|
||||
}
|
||||
file = info->file;
|
||||
|
||||
printf("Creating %s\n", name);
|
||||
r = encode(card->ctx, p15card, &buf, &bufsize);
|
||||
if (r >= 0)
|
||||
r = do_create_and_update_file(pro, file, buf, bufsize);
|
||||
if (r < 0) {
|
||||
fprintf(stderr,
|
||||
"Error creating %s: %s\n", name, sc_strerror(r));
|
||||
}
|
||||
|
||||
if (buf)
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
pkcs15_write_df(struct sc_profile *pro, struct sc_pkcs15_df *df,
|
||||
unsigned int fileno)
|
||||
{
|
||||
struct sc_file *file = df->file[fileno];
|
||||
struct file_info *info;
|
||||
const char *ident;
|
||||
u8 *buf;
|
||||
size_t bufsize;
|
||||
int r;
|
||||
|
||||
info = sc_profile_file_info(pro, file);
|
||||
ident = info? info->ident : "unknown PKCS15 xDF";
|
||||
|
||||
printf("Creating %s\n", ident);
|
||||
r = sc_pkcs15_encode_df(card->ctx, df, fileno, &buf, &bufsize);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
if (buf == 0) {
|
||||
fprintf(stderr,
|
||||
"Profile doesn't define %s objects, skipped\n",
|
||||
ident);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = do_create_and_update_file(pro, df->file[fileno], buf, bufsize);
|
||||
free(buf);
|
||||
|
||||
out: if (r < 0) {
|
||||
fprintf(stderr, "Error creating %s: %s\n",
|
||||
info? info->ident : "unknown PKCS15 xDF",
|
||||
sc_strerror(r));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find PIN info given the "name" or the reference
|
||||
*/
|
||||
static struct pin_info *
|
||||
do_get_pin_by_name(struct sc_profile *pro, const char *name, int warn)
|
||||
{
|
||||
struct pin_info *info;
|
||||
|
||||
info = sc_profile_find_pin(pro, name);
|
||||
if (info == NULL && warn)
|
||||
error("No PIN info for %s", name);
|
||||
return info;
|
||||
}
|
||||
|
||||
static struct pin_info *
|
||||
do_get_pin_by_reference(struct sc_profile *pro, unsigned int reference)
|
||||
{
|
||||
struct pin_info *info;
|
||||
|
||||
for (info = pro->pin_list; info; info = info->next) {
|
||||
if (info->pkcs15.reference == reference)
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get all the PINs and PUKs we need from the user
|
||||
*/
|
||||
static int
|
||||
do_read_pins(struct sc_profile *pro)
|
||||
{
|
||||
static char *names[2] = { "PIN", "PUK" };
|
||||
static char *types[2] = { "CHV1", "CHV2" };
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 2; n++) {
|
||||
struct pin_info *info;
|
||||
struct sc_file *file;
|
||||
char prompt[64], *pass;
|
||||
int i, passlen, npins = 2;
|
||||
|
||||
if (!(info = do_get_pin_by_name(pro, types[n], 0)))
|
||||
continue;
|
||||
|
||||
/* If the PIN file already exists, read just the PIN */
|
||||
file = info->file->file;
|
||||
ctx->log_errors = 0;
|
||||
if (!sc_select_file(card, &file->path, NULL)) {
|
||||
printf("PIN file for %s already exists.", info->ident);
|
||||
npins = 1;
|
||||
}
|
||||
ctx->log_errors = 1;
|
||||
|
||||
/* Don't ask for a PUK if there's not supposed to be one */
|
||||
if (info->attempt[1] == 0)
|
||||
npins = 1;
|
||||
|
||||
/* Loop over all PINs and PUKs */
|
||||
for (i = 0; i < npins; i++) {
|
||||
sprintf(prompt, "Please enter %s for %s:",
|
||||
names[i], info->ident);
|
||||
|
||||
again: pass = opt_pins[2*n + i];
|
||||
opt_pins[2*n + i] = NULL;
|
||||
if (pass == NULL)
|
||||
pass = getpass(prompt);
|
||||
|
||||
passlen = strlen(pass);
|
||||
if (passlen < info->pkcs15.min_length) {
|
||||
error("Password too short (%u characters min)",
|
||||
info->pkcs15.min_length);
|
||||
goto again;
|
||||
}
|
||||
if (passlen > info->pkcs15.stored_length) {
|
||||
error("Password too long (%u characters max)",
|
||||
info->pkcs15.stored_length);
|
||||
goto again;
|
||||
}
|
||||
info->secret[i] = strdup(pass);
|
||||
memset(pass, 0, passlen);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_verify_pin(struct sc_profile *pro, unsigned int type, unsigned int reference)
|
||||
{
|
||||
const char *ident;
|
||||
struct auth_info *auth;
|
||||
struct pin_info *info;
|
||||
char *pin;
|
||||
int r;
|
||||
|
||||
ident = "authentication data";
|
||||
if (type == SC_AC_CHV)
|
||||
ident = "PIN";
|
||||
else if (type == SC_AC_PRO)
|
||||
ident = "secure messaging key";
|
||||
else if (type == SC_AC_AUT)
|
||||
ident = "authentication key";
|
||||
|
||||
if ((auth = sc_profile_find_key(pro, type, reference))
|
||||
|| (auth = sc_profile_find_key(pro, type, -1))) {
|
||||
r = sc_verify(card, type, reference,
|
||||
auth->key, auth->key_len, NULL);
|
||||
if (r) {
|
||||
error("Failed to verify %s (ref=0x%x)",
|
||||
ident, reference);
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
info = NULL;
|
||||
if (type == SC_AC_CHV)
|
||||
info = do_get_pin_by_reference(pro, reference);
|
||||
if (!info || !(pin = info->secret[0])) {
|
||||
error("Could not find %s (ref=0x%x)", ident, reference);
|
||||
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
return sc_verify(card, SC_AC_CHV, reference, pin, strlen(pin), NULL);
|
||||
}
|
||||
|
||||
int
|
||||
do_verify_authinfo(struct sc_profile *pro, struct sc_file *file, int op)
|
||||
{
|
||||
const struct sc_acl_entry *acl;
|
||||
int r = 0;
|
||||
|
||||
acl = sc_file_get_acl_entry(file, op);
|
||||
for (; r == 0 && acl; acl = acl->next) {
|
||||
if (acl->method == SC_AC_NEVER)
|
||||
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
||||
if (acl->method == SC_AC_NONE)
|
||||
break;
|
||||
r = do_verify_pin(pro, acl->method, acl->key_ref);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_select_parent(struct sc_profile *pro, struct sc_file *file,
|
||||
struct sc_file **parent)
|
||||
{
|
||||
struct sc_path path;
|
||||
|
||||
/* Get the parent's path */
|
||||
path = file->path;
|
||||
if (path.len >= 2)
|
||||
path.len -= 2;
|
||||
if (path.len == 0)
|
||||
sc_format_path("3F00", &path);
|
||||
|
||||
/* Select the parent DF. */
|
||||
return sc_select_file(card, &path, parent);
|
||||
}
|
||||
|
||||
int
|
||||
do_create_file(struct sc_profile *pro, struct sc_file *file)
|
||||
{
|
||||
struct sc_file *parent = NULL;
|
||||
int r;
|
||||
|
||||
/* Select parent DF and verify PINs/key as necessary */
|
||||
if ((r = do_select_parent(pro, file, &parent)) < 0
|
||||
|| (r = do_verify_authinfo(pro, parent, SC_AC_OP_CREATE)) < 0)
|
||||
goto out;
|
||||
|
||||
r = sc_create_file(card, file);
|
||||
|
||||
out: if (parent)
|
||||
sc_file_free(parent);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_create_and_update_file(struct sc_profile *pro, struct sc_file *file,
|
||||
void *data, unsigned int datalen)
|
||||
{
|
||||
struct sc_file copy = *file;
|
||||
int r;
|
||||
|
||||
copy.size += datalen;
|
||||
file = ©
|
||||
|
||||
if ((r = do_create_file(pro, file)) < 0)
|
||||
return r;
|
||||
|
||||
/* Select file and present any authentication info needed */
|
||||
if ((r = sc_select_file(card, &file->path, NULL)) < 0
|
||||
|| (r = do_verify_authinfo(pro, file, SC_AC_OP_UPDATE)) < 0)
|
||||
return r;
|
||||
|
||||
return sc_update_binary(card, 0, data, datalen, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(int exval)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage:\n"
|
||||
"pkcs15-init -d -E -C profile\n"
|
||||
);
|
||||
exit(exval);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Function prototypes for pkcs15-init
|
||||
*
|
||||
* Copyright (C) 2002 Olaf Kirch <okir@lst.de>
|
||||
*/
|
||||
|
||||
#ifndef PKCS15_INIT_H
|
||||
#define PKCS15_INIT_H
|
||||
|
||||
#include "profile.h"
|
||||
|
||||
extern int do_create_file(struct sc_profile *, struct sc_file *);
|
||||
extern int do_create_and_update_file(struct sc_profile *,
|
||||
struct sc_file *, void *, unsigned int);
|
||||
extern int do_select_parent(struct sc_profile *, struct sc_file *,
|
||||
struct sc_file **);
|
||||
extern int do_verify_authinfo(struct sc_profile *, struct sc_file *, int);
|
||||
|
||||
/* Card specific stuff */
|
||||
extern void bind_gpk_operations(struct sc_profile *);
|
||||
|
||||
#endif /* PKCS15_INIT_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Card profile information
|
||||
*
|
||||
* Copyright (C) 2002 Olaf Kirch <okir@lst.de>
|
||||
*/
|
||||
|
||||
#ifndef _OPENSC_PROFILE_H
|
||||
#define _OPENSC_PROFILE_H
|
||||
|
||||
#include "opensc-pkcs15.h"
|
||||
|
||||
struct auth_info {
|
||||
struct auth_info * next;
|
||||
unsigned int type; /* CHV, AUT, PRO */
|
||||
unsigned int id; /* CHV1, KEY0, ... */
|
||||
unsigned int ref;
|
||||
size_t key_len;
|
||||
u_int8_t key[32];
|
||||
};
|
||||
|
||||
struct file_info {
|
||||
char * ident;
|
||||
struct file_info * next;
|
||||
struct sc_file * file;
|
||||
|
||||
/* PKCS15 book-keeping info */
|
||||
struct {
|
||||
unsigned int fileno;
|
||||
unsigned int type;
|
||||
} pkcs15;
|
||||
};
|
||||
|
||||
/* For now, we assume the PUK always resides
|
||||
* in the same file as the PIN
|
||||
*/
|
||||
struct pin_info {
|
||||
char * ident;
|
||||
unsigned int id; /* 1 == CHV1, 2 == CHV2 */
|
||||
struct pin_info * next;
|
||||
struct file_info * file;
|
||||
unsigned int file_offset;
|
||||
unsigned int attempt[2];
|
||||
|
||||
struct sc_pkcs15_pin_info pkcs15;
|
||||
|
||||
/* These are set while initializing the card */
|
||||
char * secret[2];
|
||||
};
|
||||
|
||||
struct prkey_info {
|
||||
char * ident;
|
||||
struct prkey_info * next;
|
||||
struct file_info * file;
|
||||
unsigned int type;
|
||||
unsigned int index; /* translates to file offset */
|
||||
|
||||
struct sc_pkcs15_prkey_info pkcs15;
|
||||
};
|
||||
|
||||
struct sc_profile {
|
||||
char * driver;
|
||||
int (*erase_card)(struct sc_profile *,
|
||||
struct sc_card *);
|
||||
int (*init_app)(struct sc_profile *,
|
||||
struct sc_card *);
|
||||
|
||||
struct file_info mf_info;
|
||||
struct file_info df_info;
|
||||
struct file_info * ef_list;
|
||||
struct pin_info * pin_list;
|
||||
struct auth_info * auth_list;
|
||||
struct prkey_info * prkey_list;
|
||||
|
||||
unsigned int pin_maxlen;
|
||||
unsigned int pin_minlen;
|
||||
unsigned int pin_pad_char;
|
||||
|
||||
/* PKCS15 information */
|
||||
struct sc_pkcs15_card * p15_card;
|
||||
char * p15_label;
|
||||
char * p15_manufacturer;
|
||||
char * p15_serial;
|
||||
};
|
||||
|
||||
void sc_profile_init(struct sc_profile *, struct sc_pkcs15_card *);
|
||||
int sc_profile_load(struct sc_profile *, const char *);
|
||||
int sc_profile_finish(struct sc_profile *);
|
||||
int sc_profile_build_pkcs15(struct sc_profile *);
|
||||
struct file_info *sc_profile_find_file(struct sc_profile *, const char *);
|
||||
struct file_info *sc_profile_file_info(struct sc_profile *, struct sc_file *);
|
||||
struct pin_info *sc_profile_find_pin(struct sc_profile *, const char *);
|
||||
struct prkey_info *sc_profile_find_prkey(struct sc_profile *, const char *);
|
||||
struct auth_info *sc_profile_find_key(struct sc_profile *,
|
||||
unsigned int, unsigned int);
|
||||
|
||||
#endif /* _OPENSC_PROFILE_H */
|
Loading…
Reference in New Issue