- Rewrote sc_pkcs15_bind_synthetic a little

- Started work on pkcs15 emulation for OpenPGP card


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1584 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
okir 2003-10-31 12:27:14 +00:00
parent d91ecdc245
commit 16ec507738
3 changed files with 525 additions and 2 deletions

View File

@ -18,7 +18,7 @@ libopensc_la_SOURCES = \
\
pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \
pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \
pkcs15-wrap.c pkcs15-algo.c pkcs15-cache.c \
pkcs15-wrap.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
\
emv.c \
\
@ -27,7 +27,9 @@ libopensc_la_SOURCES = \
\
card-setcos.c card-miocos.c card-flex.c card-gpk.c \
card-etoken.c card-tcos.c card-emv.c card-default.c \
card-mcrd.c card-starcos.c card-openpgp.c
card-mcrd.c card-starcos.c card-openpgp.c \
\
pkcs15-openpgp.c
libopensc_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
libopensc_la_LIBADD = @LIBSCCONF@ ../scdl/libscdl.la @LIBDL@ @LIBCRYPTO@ @OPENCT_LIBS@ @LIBPCSC@

View File

@ -0,0 +1,312 @@
/*
* PKCS15 emulation layer for OpenPGP card.
*
* Copyright (C) 2003, Olaf Kirch <okir@suse.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 "internal.h"
#include "pkcs15.h"
#include "asn1.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
/*
* Much of this code probably needs to be shared between
* emulators. Will move this to pkcs15-syn.c when needed.
*/
static sc_pkcs15_df_t *
sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card, int type)
{
sc_pkcs15_df_t *df;
sc_file_t *file;
int created = 0;
while (1) {
for (df = p15card->df_list; df; df = df->next) {
if (df->type == type) {
if (created)
df->enumerated = 1;
return df;
}
}
assert(created == 0);
file = sc_file_new();
sc_format_path("DEAD", &file->path);
sc_pkcs15_add_df(p15card, type, &file->path, file);
created++;
}
}
static sc_pkcs15_object_t *
sc_pkcs15emu_add_object(sc_pkcs15_card_t *p15card, int type,
const char *label, void *data)
{
sc_pkcs15_object_t *obj;
int df_type;
obj = calloc(1, sizeof(*obj));
obj->type = type;
obj->data = data;
if (label)
strncpy(obj->label, label, sizeof(obj->label)-1);
if (!(p15card->flags & SC_PKCS15_CARD_FLAG_READONLY))
obj->flags |= SC_PKCS15_CO_FLAG_MODIFIABLE;
switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
case SC_PKCS15_TYPE_AUTH:
obj->flags |= SC_PKCS15_CO_FLAG_PRIVATE;
df_type = SC_PKCS15_AODF;
break;
case SC_PKCS15_TYPE_PRKEY:
obj->flags |= SC_PKCS15_CO_FLAG_PRIVATE;
df_type = SC_PKCS15_PRKDF;
break;
case SC_PKCS15_TYPE_PUBKEY:
df_type = SC_PKCS15_PUKDF;
break;
case SC_PKCS15_TYPE_CERT:
df_type = SC_PKCS15_CDF;
break;
default:
sc_error(p15card->card->ctx,
"Unknown PKCS15 object type %d\n", type);
return NULL;
}
obj->df = sc_pkcs15emu_get_df(p15card, df_type);
sc_pkcs15_add_object(p15card, obj);
return obj;
}
static int
sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card,
unsigned int id, const char *label,
const sc_path_t *path, int ref, int type,
unsigned int min_length,
unsigned int max_length,
int flags, int tries_left)
{
sc_pkcs15_pin_info_t *info;
info = (sc_pkcs15_pin_info_t *) calloc(1, sizeof(*info));
info->auth_id.value[0] = id;
info->auth_id.len = 1;
info->min_length = min_length;
info->max_length = max_length;
info->stored_length = max_length;
info->type = type;
info->reference = ref;
info->flags = flags;
info->tries_left = tries_left;
if (path)
info->path = *path;
if (type == SC_PKCS15_PIN_TYPE_BCD)
info->stored_length /= 2;
sc_pkcs15emu_add_object(p15card, SC_PKCS15_TYPE_AUTH_PIN, label, info);
return 0;
}
static void
set_string(char **strp, const char *value)
{
if (*strp)
free(strp);
*strp = value? strdup(value) : NULL;
}
/*
* This function pretty much follows what find_tlv in the GNUpg
* code does.
*/
static int
get_tlv(sc_context_t *ctx, unsigned int match_tag,
const u8 *in, size_t in_len,
u8 *out, size_t out_len)
{
const u8 *end = in + in_len;
int r;
while (in < end) {
unsigned int tag, len;
int composite = 0;
unsigned char c;
c = *in++;
if (c == 0x00 || c == 0xFF)
continue;
tag = c;
if (tag & 0x20)
composite = 1;
while ((c & 0x1f) == 0x1f) {
if (in >= end)
goto eoc;
c = *in++;
tag = (tag << 8) | c;
}
if (in >= end)
goto eoc;
c = *in++;
if (c < 0x80) {
len = c;
} else {
len = 0;
c &= 0x7F;
while (c--) {
if (in >= end)
goto eoc;
len = (len << 8) | *in++;
}
}
/* Don't search past end of content */
if (in + len > end)
goto eoc;
if (tag == match_tag) {
if (len > out_len)
len = out_len;
memcpy(out, in, len);
return len;
}
/* Recurse into composite object.
* No need for recursion check, as we check the buffer
* length and each recursion consumes at least 2 bytes */
if (composite) {
r = get_tlv(ctx, match_tag, in, len, out, out_len);
if (r != SC_ERROR_OBJECT_NOT_FOUND)
return r;
}
in += len;
}
return SC_ERROR_OBJECT_NOT_FOUND;
eoc: sc_error(ctx, "Unexpected end of contentsn");
return SC_ERROR_OBJECT_NOT_VALID;
}
int
sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
{
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx;
sc_path_t path;
sc_file_t *file;
char string[256];
u8 buffer[256], value[256];
size_t length;
int r, i;
/* Select OpenPGP application.
* We must specify a file, because the card expects a
* case 4 APDU and barfs if it's case 2.
*/
sc_format_path("D276:0001:2401", &path);
path.type = SC_PATH_TYPE_DF_NAME;
if ((r = sc_select_file(card, &path, &file)) < 0)
goto failed;
sc_file_free(file);
set_string(&p15card->label, "OpenPGP Card");
set_string(&p15card->manufacturer_id, "OpenPGP project");
if ((r = sc_get_data(card, 0x004f, buffer, sizeof(buffer))) < 0)
goto failed;
sc_bin_to_hex(buffer, r, string, sizeof(string), 0);
set_string(&p15card->serial_number, string);
p15card->version = (buffer[6] << 8) | buffer[7];
p15card->flags = SC_PKCS15_CARD_FLAG_LOGIN_REQUIRED |
SC_PKCS15_CARD_FLAG_PRN_GENERATION |
SC_PKCS15_CARD_FLAG_EID_COMPLIANT;
/* Get Card Holder Related Data (0065) */
if ((r = sc_get_data(card, 0x0065, buffer, sizeof(buffer))) < 0)
goto failed;
length = r;
/* Extract preferred language */
r = get_tlv(ctx, 0x5F2D, buffer, length, string, sizeof(string)-1);
if (r > 0) {
string[r] = '\0';
set_string(&p15card->preferred_language, string);
} else if (r != SC_ERROR_OBJECT_NOT_FOUND) {
goto failed;
}
/* Get Application Related Data (006E) */
if ((r = sc_get_data(card, 0x006E, buffer, sizeof(buffer))) < 0)
goto failed;
length = r;
/* TBD: extract algorithm info */
/* Get CHV status bytes:
* 00: ??
* 01-03: max length of pins 1-3
* 04-07: tries left for pins 1-3
*/
r = get_tlv(ctx, 0x00c4, buffer, length, value, sizeof(value));
if (r < 0)
goto failed;
if (r != 7) {
sc_error(ctx,
"CHV status bytes have unexpected length "
"(expected 7, got %d)\n", r);
return SC_ERROR_OBJECT_NOT_VALID;
}
for (i = 0; i < 3; i++) {
static char *pin_name[3] = {
"User PIN",
"User PIN 2",
"Admin PIN"
};
int flags;
flags = SC_PKCS15_PIN_FLAG_CASE_SENSITIVE |
SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_LOCAL;
if (i == 2) {
flags |= SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED |
SC_PKCS15_PIN_FLAG_SO_PIN;
}
sc_pkcs15emu_add_pin(p15card, i+1, pin_name[i], NULL, i+1,
SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
0, value[1+i], flags, value[4+i]);
}
return 0;
failed: sc_error(card->ctx, "Failed to initialize OpenPGP emulation: %s\n",
sc_strerror(r));
return r;
}

209
src/libopensc/pkcs15-syn.c Normal file
View File

@ -0,0 +1,209 @@
/*
* pkcs15-syn.c: PKCS #15 emaulation of non-pkcs15 cards
*
* Copyright (C) 2003 Olaf Kirch <okir@suse.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 "internal.h"
#include "pkcs15.h"
#include "asn1.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
static int sc_pkcs15_bind_emulation(sc_pkcs15_card_t *, const char *,
scconf_block *, int);
extern int sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *);
static struct {
const char * name;
int (*handler)(sc_pkcs15_card_t *);
} builtin_emulators[] = {
{ "openpgp", sc_pkcs15emu_openpgp_init },
{ NULL }
};
int
sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *p15card, int check_atr)
{
sc_context_t *ctx = p15card->card->ctx;
const scconf_list *clist, *tmp;
scconf_block *conf_block, **blocks, *blk;
int i, r;
SC_FUNC_CALLED(ctx, 1);
assert(p15card);
conf_block = NULL;
for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
"framework", "pkcs15");
if (blocks[0] != NULL)
conf_block = blocks[0];
free(blocks);
}
if (!conf_block)
return SC_ERROR_WRONG_CARD;
/* Old-style: get the pkcs15_syn libs from the conf file */
clist = scconf_find_list(conf_block, "pkcs15_syn");
for (tmp = clist; tmp != NULL; tmp = tmp->next) {
const char *module = tmp->data;
if (module == NULL)
continue;
r = sc_pkcs15_bind_emulation(p15card, module, NULL, check_atr);
if (r != SC_ERROR_WRONG_CARD)
goto out;
}
/* New-style: get lib name, function name, ATR list */
blocks = scconf_find_blocks(ctx->conf, conf_block, "emulate", NULL);
for (i = 0; (blk = blocks[i]) != NULL; i++) {
const char *module;
module = scconf_get_str(blk, "module", NULL);
if (!module)
continue;
r = sc_pkcs15_bind_emulation(p15card, module, blk, check_atr);
if (r != SC_ERROR_WRONG_CARD) {
free(blocks);
goto out;
}
}
free(blocks);
/* Total failure */
return SC_ERROR_WRONG_CARD;
out: if (r == SC_SUCCESS) {
/* p15card->flags |= SC_PKCS15_CARD_FLAG_READONLY; */
p15card->magic = 0x10203040;
} else if (r != SC_ERROR_WRONG_CARD) {
sc_error(ctx, "Failed to load card emulator: %s\n",
sc_strerror(r));
}
return r;
}
int
sc_pkcs15_bind_emulation(sc_pkcs15_card_t *p15card,
const char *module_name,
scconf_block *conf,
int check_atr)
{
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx;
const scconf_list *list, *item;
void *dll = NULL;
int (*init_func)(sc_pkcs15_card_t *);
int r;
if (conf && (list = scconf_find_list(conf, "atr"))) {
int match = 0;
if (!check_atr)
return SC_ERROR_WRONG_CARD;
for (item = list; item; item = item->next) {
u8 atr[SC_MAX_ATR_SIZE];
size_t len = sizeof(atr);
if (!item->data)
continue;
if (sc_hex_to_bin(item->data, atr, &len))
continue;
if (len > card->atr_len
|| memcmp(card->atr, atr, len))
continue;
match = 1;
break;
}
if (!match)
return SC_ERROR_WRONG_CARD;
} else if (!check_atr) {
/* ATR checking required, but no ATR list to match against */
return SC_ERROR_WRONG_CARD;
}
init_func = NULL;
if (!strcmp(module_name, "builtin")) {
int i;
/* This function is built into libopensc itself.
* Look it up in the table of emulators */
if (conf == NULL || !conf->name)
return SC_ERROR_INTERNAL;
module_name = conf->name->data;
for (i = 0; builtin_emulators[i].name; i++) {
if (!strcmp(builtin_emulators[i].name, module_name)) {
init_func = builtin_emulators[i].handler;
break;
}
}
} else {
const char *function_name = NULL;
void *address;
if (ctx->debug >= 4)
sc_debug(ctx, "Loading %s\n", module_name);
/* try to open dynamic library */
r = sc_module_open(ctx, &dll, module_name);
if (r != SC_SUCCESS)
return r;
/* get a handle to the pkcs15 init function
* XXX the init_func should not modify the contents of
* sc_pkcs15_card_t unless the card is really the one
* the driver is intended for -- Nils
*/
if (conf)
function_name = scconf_get_str(conf, "function", NULL);
if (function_name == NULL)
function_name = "sc_pkcs15_init_func";
r = sc_module_get_address(ctx, dll, &address, function_name);
if (r != SC_SUCCESS)
return r;
/* try to initialize synthetic pkcs15 structures */
init_func = (int (*)(sc_pkcs15_card_t *)) address;
}
r = init_func(p15card);
if (r >= 0) {
sc_debug(card->ctx, "%s succeeded, card bound\n",
module_name);
p15card->dll_handle = dll;
} else if (ctx->debug >= 4) {
sc_debug(card->ctx, "%s failed: %s\n",
module_name, sc_strerror(r));
if (dll)
sc_module_close(ctx, dll);
}
return r;
}