- added some eToken code (not functional yet)
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@622 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
03559c47d0
commit
0c07f24de0
@ -13,7 +13,8 @@ lib_LTLIBRARIES = libpkcs15init.la
|
||||
|
||||
libpkcs15init_la_SOURCES = \
|
||||
pkcs15-lib.c profile.c \
|
||||
pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c
|
||||
pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c \
|
||||
pkcs15-etoken.c
|
||||
|
||||
include_HEADERS = pkcs15-init.h
|
||||
noinst_HEADERS = profile.h
|
||||
|
382
src/pkcs15init/pkcs15-etoken.c
Normal file
382
src/pkcs15init/pkcs15-etoken.c
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* eToken PRO specific operation for PKCS15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 Olaf Kirch <okir@lst.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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <opensc/opensc.h>
|
||||
#include <opensc/cardctl.h>
|
||||
#include "pkcs15-init.h"
|
||||
#include "profile.h"
|
||||
|
||||
struct tlv {
|
||||
unsigned char * base;
|
||||
unsigned char * end;
|
||||
unsigned char * current;
|
||||
unsigned char * next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Local functions
|
||||
*/
|
||||
static int etoken_new_file(struct sc_profile *, struct sc_card *,
|
||||
unsigned int, unsigned int,
|
||||
struct sc_file **);
|
||||
static void error(struct sc_profile *, const char *, ...);
|
||||
|
||||
/* We should make these object IDs configurable via the profile */
|
||||
#define ETOKEN_SO_PIN_ID 0x01
|
||||
#define ETOKEN_SO_PUK_ID 0x02
|
||||
#define ETOKEN_PIN_ID 0x03
|
||||
#define ETOKEN_PUK_ID 0x04
|
||||
#define ETOKEN_AC_NEVER 0xFF
|
||||
|
||||
#define ETOKEN_ALGO_PIN 0x87
|
||||
|
||||
#define ETOKEN_DEFAULT_PIN "null-pin"
|
||||
#define ETOKEN_DEFAULT_PIN_LEN (sizeof(ETOKEN_DEFAULT_PIN)-1)
|
||||
|
||||
struct etoken_pin_info {
|
||||
int profile_id;
|
||||
u8 id;
|
||||
u8 unblock;
|
||||
};
|
||||
static struct etoken_pin_info etoken_so_pin = {
|
||||
SC_PKCS15INIT_SO_PIN,
|
||||
ETOKEN_SO_PIN_ID,
|
||||
ETOKEN_SO_PUK_ID
|
||||
};
|
||||
static struct etoken_pin_info etoken_so_puk = {
|
||||
SC_PKCS15INIT_SO_PUK,
|
||||
ETOKEN_SO_PUK_ID,
|
||||
ETOKEN_AC_NEVER
|
||||
};
|
||||
static struct etoken_pin_info etoken_user_pin = {
|
||||
SC_PKCS15INIT_USER_PIN,
|
||||
ETOKEN_PIN_ID,
|
||||
ETOKEN_PUK_ID
|
||||
};
|
||||
static struct etoken_pin_info etoken_user_puk = {
|
||||
SC_PKCS15INIT_USER_PUK,
|
||||
ETOKEN_PUK_ID,
|
||||
ETOKEN_SO_PIN_ID
|
||||
};
|
||||
|
||||
static inline void
|
||||
tlv_init(struct tlv *tlv, u8 *base, size_t size)
|
||||
{
|
||||
tlv->base = base;
|
||||
tlv->end = base + size;
|
||||
tlv->current = tlv->next = base;
|
||||
}
|
||||
|
||||
static inline void
|
||||
tlv_next(struct tlv *tlv, u8 tag)
|
||||
{
|
||||
assert(tlv->next + 2 < tlv->end);
|
||||
tlv->current = tlv->next;
|
||||
*(tlv->next++) = tag;
|
||||
*(tlv->next++) = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
tlv_add(struct tlv *tlv, u8 val)
|
||||
{
|
||||
assert(tlv->next + 1 < tlv->end);
|
||||
*(tlv->next++) = val;
|
||||
tlv->current[1]++;
|
||||
}
|
||||
|
||||
static size_t
|
||||
tlv_len(struct tlv *tlv)
|
||||
{
|
||||
return tlv->next - tlv->base;
|
||||
}
|
||||
|
||||
static int
|
||||
etoken_set_ac(struct sc_file *file, int op, struct sc_acl_entry *acl)
|
||||
{
|
||||
/* XXX TBD */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize pin file
|
||||
*/
|
||||
static int
|
||||
etoken_new_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct etoken_pin_info *info,
|
||||
const u8 *pin, size_t pin_len)
|
||||
{
|
||||
struct sc_pkcs15_pin_info params;
|
||||
struct sc_cardctl_etoken_pin_info args;
|
||||
unsigned char buffer[256];
|
||||
struct tlv tlv;
|
||||
unsigned int pin_id, puk_id, attempts, minlen;
|
||||
|
||||
/* XXX hack for testing */
|
||||
if (!pin_len) {
|
||||
pin = ETOKEN_DEFAULT_PIN;
|
||||
pin_len = ETOKEN_DEFAULT_PIN_LEN;
|
||||
}
|
||||
|
||||
sc_profile_get_pin_info(profile, info->profile_id, ¶ms);
|
||||
attempts = params.tries_left;
|
||||
minlen = params.min_length;
|
||||
|
||||
pin_id = info->id;
|
||||
puk_id = info->unblock;
|
||||
|
||||
tlv_init(&tlv, buffer, sizeof(buffer));
|
||||
|
||||
/* object address: class, id */
|
||||
tlv_next(&tlv, 0x83);
|
||||
tlv_add(&tlv, 0x00); /* class byte: usage TEST, k=0 */
|
||||
tlv_add(&tlv, pin_id);
|
||||
|
||||
/* parameters */
|
||||
tlv_next(&tlv, 0x85);
|
||||
tlv_add(&tlv, 0x02); /* options byte */
|
||||
tlv_add(&tlv, attempts & 0xf); /* flags byte */
|
||||
tlv_add(&tlv, ETOKEN_ALGO_PIN); /* algorithm = pin-test */
|
||||
tlv_add(&tlv, attempts & 0xf); /* errcount = attempts */
|
||||
tlv_add(&tlv, 0x00); /* usecount = 0 */
|
||||
tlv_add(&tlv, 0x00); /* DEK (?) */
|
||||
tlv_add(&tlv, 0x00); /* ARA counter (?) */
|
||||
tlv_add(&tlv, minlen);
|
||||
|
||||
/* data: PIN */
|
||||
tlv_next(&tlv, 0x8f);
|
||||
while (pin_len--)
|
||||
tlv_add(&tlv, *pin++);
|
||||
|
||||
/* AC conditions */
|
||||
tlv_next(&tlv, 0x86);
|
||||
tlv_add(&tlv, 0x00); /* use: always */
|
||||
tlv_add(&tlv, puk_id); /* change: PUK */
|
||||
tlv_add(&tlv, puk_id); /* unblock: PUK */
|
||||
|
||||
args.data = buffer;
|
||||
args.len = tlv_len(&tlv);
|
||||
|
||||
return sc_card_ctl(card, SC_CARDCTL_ETOKEN_PUT_DATA_OCI, &args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the Application DF and pin file
|
||||
*/
|
||||
static int
|
||||
etoken_init_app(struct sc_profile *profile, struct sc_card *card,
|
||||
const unsigned char *pin, size_t pin_len,
|
||||
const unsigned char *puk, size_t puk_len)
|
||||
{
|
||||
struct sc_file *df = profile->df_info->file;
|
||||
int r;
|
||||
|
||||
/* Create the application DF */
|
||||
r = sc_pkcs15init_create_file(profile, card, df);
|
||||
|
||||
if (r >= 0)
|
||||
r = sc_select_file(card, &df->path, NULL);
|
||||
|
||||
/* Create the PIN objects */
|
||||
if (r >= 0)
|
||||
r = etoken_new_pin(profile, card,
|
||||
&etoken_so_puk, puk, puk_len);
|
||||
if (r >= 0)
|
||||
r = etoken_new_pin(profile, card,
|
||||
&etoken_so_pin, pin, pin_len);
|
||||
if (r >= 0)
|
||||
r = etoken_new_pin(profile, card, &etoken_user_pin, 0, 0);
|
||||
if (r >= 0)
|
||||
r = etoken_new_pin(profile, card, &etoken_user_puk, 0, 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a PIN
|
||||
*/
|
||||
static int
|
||||
etoken_put_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_pin_info *info, unsigned int index,
|
||||
const u8 *pin, size_t pin_len,
|
||||
const u8 *puk, size_t puk_len)
|
||||
{
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
#if 0
|
||||
unsigned char nulpin[8];
|
||||
int r;
|
||||
|
||||
/* Profile must define a "pinfile" */
|
||||
if (sc_profile_get_path(profile, "pinfile", &info->path) < 0) {
|
||||
error(profile, "Profile doesn't define a \"pinfile\"");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
if (info->path.len > 2)
|
||||
info->path.len -= 2;
|
||||
|
||||
r = sc_select_file(card, &info->path, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
index <<= 2;
|
||||
if (index >= GPK_MAX_PINS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
if (puk == NULL || puk_len == 0) {
|
||||
puk = pin;
|
||||
puk_len = pin_len;
|
||||
}
|
||||
|
||||
/* Current PIN is 00:00:00:00:00:00:00:00 */
|
||||
memset(nulpin, 0, sizeof(nulpin));
|
||||
r = sc_change_reference_data(card, SC_AC_CHV,
|
||||
0x8 | index,
|
||||
nulpin, sizeof(nulpin),
|
||||
pin, pin_len, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Current PUK is 00:00:00:00:00:00:00:00 */
|
||||
r = sc_change_reference_data(card, SC_AC_CHV,
|
||||
0x8 | (index + 1),
|
||||
nulpin, sizeof(nulpin),
|
||||
puk, puk_len, NULL);
|
||||
|
||||
info->reference = 0x8 | index;
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a private key
|
||||
*/
|
||||
static int
|
||||
etoken_new_key(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_prkey *key, unsigned int index,
|
||||
struct sc_pkcs15_prkey_info *info)
|
||||
{
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a file
|
||||
*/
|
||||
static int
|
||||
etoken_new_file(struct sc_profile *profile, struct sc_card *card,
|
||||
unsigned int type, unsigned int num,
|
||||
struct sc_file **out)
|
||||
{
|
||||
struct sc_file *file;
|
||||
struct sc_path *p;
|
||||
char name[64], *tag, *desc;
|
||||
|
||||
desc = tag = NULL;
|
||||
while (1) {
|
||||
switch (type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
desc = "RSA private key";
|
||||
tag = "private-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
||||
desc = "RSA public key";
|
||||
tag = "public-key";
|
||||
break;
|
||||
#ifdef SC_PKCS15_TYPE_PRKEY_DSA
|
||||
case SC_PKCS15_TYPE_PRKEY_DSA:
|
||||
desc = "DSA private key";
|
||||
tag = "private-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_DSA:
|
||||
desc = "DSA public key";
|
||||
tag = "public-key";
|
||||
break;
|
||||
#endif
|
||||
case SC_PKCS15_TYPE_PRKEY:
|
||||
desc = "extractable private key";
|
||||
tag = "extractable-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_CERT:
|
||||
desc = "certificate";
|
||||
tag = "certificate";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_DATA_OBJECT:
|
||||
desc = "data object";
|
||||
tag = "data";
|
||||
break;
|
||||
}
|
||||
if (tag)
|
||||
break;
|
||||
/* If this is a specific type such as
|
||||
* SC_PKCS15_TYPE_CERT_FOOBAR, fall back to
|
||||
* the generic class (SC_PKCS15_TYPE_CERT)
|
||||
*/
|
||||
if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) {
|
||||
error(profile, "File type not supported by card driver");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
type &= SC_PKCS15_TYPE_CLASS_MASK;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "template-%s", tag);
|
||||
if (sc_profile_get_file(profile, name, &file) < 0) {
|
||||
error(profile, "Profile doesn't define %s template (%s)\n",
|
||||
desc, name);
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Now construct file from template */
|
||||
file->id += num;
|
||||
|
||||
p = &file->path;
|
||||
*p = profile->df_info->file->path;
|
||||
p->value[p->len++] = file->id >> 8;
|
||||
p->value[p->len++] = file->id;
|
||||
|
||||
*out = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
error(struct sc_profile *profile, const char *fmt, ...)
|
||||
{
|
||||
char buffer[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
if (profile->cbs)
|
||||
profile->cbs->error("%s", buffer);
|
||||
}
|
||||
|
||||
struct sc_pkcs15init_operations sc_pkcs15init_etoken_operations = {
|
||||
NULL,
|
||||
etoken_init_app,
|
||||
etoken_put_pin,
|
||||
etoken_new_key,
|
||||
etoken_new_file,
|
||||
};
|
@ -56,6 +56,7 @@ struct sc_pkcs15init_operations {
|
||||
unsigned int, unsigned int, struct sc_file **out);
|
||||
};
|
||||
|
||||
/* Do not change these or reorder these */
|
||||
#define SC_PKCS15INIT_SO_PIN 0
|
||||
#define SC_PKCS15INIT_SO_PUK 1
|
||||
#define SC_PKCS15INIT_USER_PIN 2
|
||||
|
@ -93,6 +93,7 @@ static void default_debug_handler(const char *fmt, ...);
|
||||
extern struct sc_pkcs15init_operations sc_pkcs15init_gpk_operations;
|
||||
extern struct sc_pkcs15init_operations sc_pkcs15init_miocos_operations;
|
||||
extern struct sc_pkcs15init_operations sc_pkcs15init_cflex_operations;
|
||||
extern struct sc_pkcs15init_operations sc_pkcs15init_etoken_operations;
|
||||
|
||||
static struct sc_pkcs15init_callbacks default_callbacks = {
|
||||
default_error_handler,
|
||||
@ -133,6 +134,8 @@ sc_pkcs15init_bind(struct sc_card *card, const char *name,
|
||||
profile->ops = &sc_pkcs15init_miocos_operations;
|
||||
else if (!strcasecmp(driver, "flex"))
|
||||
profile->ops = &sc_pkcs15init_cflex_operations;
|
||||
else if (!strcasecmp(driver, "eToken"))
|
||||
profile->ops = &sc_pkcs15init_etoken_operations;
|
||||
else {
|
||||
p15init_error("Unsupported card driver %s", driver);
|
||||
sc_profile_free(profile);
|
||||
@ -141,8 +144,13 @@ sc_pkcs15init_bind(struct sc_card *card, const char *name,
|
||||
|
||||
if ((r = sc_profile_load(profile, name)) < 0
|
||||
|| (r = sc_profile_load(profile, driver)) < 0
|
||||
|| (r = sc_profile_finish(profile)) < 0)
|
||||
|| (r = sc_profile_finish(profile)) < 0) {
|
||||
fprintf(stderr,
|
||||
"Failed to load profile: %s\n",
|
||||
sc_strerror(r));
|
||||
sc_profile_free(profile);
|
||||
return r;
|
||||
}
|
||||
*result = profile;
|
||||
|
||||
if (r == 0)
|
||||
|
Loading…
Reference in New Issue
Block a user