- started to implement eToken key generation

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@635 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
okir 2002-06-06 09:17:52 +00:00
parent cdeff04e58
commit 8535127ba8
3 changed files with 217 additions and 13 deletions

View File

@ -472,6 +472,9 @@ static int etoken_create_file(struct sc_card *card, struct sc_file *file)
} }
r = iso_ops->create_file(card, file); r = iso_ops->create_file(card, file);
/* FIXME: if this is a DF and there's an AID, set it here
* using PUT_DATA_FCI */
out: SC_FUNC_RETURN(card->ctx, 1, r); out: SC_FUNC_RETURN(card->ctx, 1, r);
} }
@ -551,6 +554,48 @@ etoken_put_data_fci(struct sc_card *card,
return r; return r;
} }
static int
etoken_generate_key(struct sc_card *card,
struct sc_cardctl_etoken_genkey_info *args)
{
struct sc_apdu apdu;
u8 data[8];
int r;
if (args->random_len) {
/* XXX FIXME: do a GIVE_RANDOM command with this data */
error(card->ctx,
"initialization of card's random pool "
"not yet implemented\n");
return SC_ERROR_INTERNAL;
}
data[0] = 0x20; /* store as PSO object */
data[1] = args->key_id;
data[2] = args->fid >> 8;
data[3] = args->fid & 0xff;
data[4] = 0; /* additional Rabin Miller tests */
data[5] = 0; /* length difference between p, q (bits) */
data[6] = 0; /* default length of exponent, MSB */
data[7] = 0; /* default length of exponent, LSB */
memset(&apdu, 0, sizeof(apdu));
apdu.cse = SC_APDU_CASE_3_SHORT;
apdu.cla = 0x00;
apdu.ins = 0x46;
apdu.p1 = 0x00;
apdu.p2 = args->key_id;/* doc is not clear, it just says "ID" */
apdu.data= data;
apdu.datalen = apdu.lc = sizeof(data);
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, r, "GENERATE_KEY failed");
return r;
}
static int static int
etoken_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr) etoken_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
{ {
@ -561,6 +606,9 @@ etoken_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
return etoken_put_data_fci(card, return etoken_put_data_fci(card,
(struct sc_cardctl_etoken_pin_info *) ptr); (struct sc_cardctl_etoken_pin_info *) ptr);
break; break;
case SC_CARDCTL_ETOKEN_GENERATE_KEY:
return etoken_generate_key(card,
(struct sc_cardctl_etoken_genkey_info *) ptr);
} }
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
} }

View File

@ -58,7 +58,8 @@ enum {
*/ */
SC_CARDCTL_ETOKEN_BASE = _CTL_PREFIX('E', 'T', 'K'), SC_CARDCTL_ETOKEN_BASE = _CTL_PREFIX('E', 'T', 'K'),
SC_CARDCTL_ETOKEN_PUT_DATA_FCI, SC_CARDCTL_ETOKEN_PUT_DATA_FCI,
SC_CARDCTL_ETOKEN_PUT_DATA_OCI SC_CARDCTL_ETOKEN_PUT_DATA_OCI,
SC_CARDCTL_ETOKEN_GENERATE_KEY
}; };
/* /*
@ -113,8 +114,16 @@ struct sc_cardctl_miocos_ac_info {
* eToken PIN info * eToken PIN info
*/ */
struct sc_cardctl_etoken_pin_info { struct sc_cardctl_etoken_pin_info {
u8 *data; u8 * data;
size_t len; size_t len;
};
struct sc_cardctl_etoken_genkey_info {
u8 * random_data;
size_t random_len;
unsigned int key_id;
unsigned int key_bits;
unsigned short fid;
}; };
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -28,6 +28,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <opensc/opensc.h> #include <opensc/opensc.h>
#include <opensc/cardctl.h> #include <opensc/cardctl.h>
#include <opensc/scrandom.h>
#include "pkcs15-init.h" #include "pkcs15-init.h"
#include "profile.h" #include "profile.h"
@ -41,6 +42,14 @@ struct tlv {
unsigned char * current; unsigned char * current;
unsigned char * next; unsigned char * next;
}; };
#define RSAKEY_MAX_BITS 1024
#define RSAKEY_MAX_SIZE (RSAKEY_MAX_BITS/8)
struct rsakey {
struct bignum {
size_t len;
u8 data[RSAKEY_MAX_SIZE];
} n, d;
};
/* /*
* Local functions * Local functions
@ -57,8 +66,10 @@ static void error(struct sc_profile *, const char *, ...);
#define ETOKEN_PIN_ID(idx) (((idx) << 1) + 0x01) #define ETOKEN_PIN_ID(idx) (((idx) << 1) + 0x01)
#define ETOKEN_PUK_ID(idx) (((idx) << 1) + 0x02) #define ETOKEN_PUK_ID(idx) (((idx) << 1) + 0x02)
#define ETOKEN_MAX_PINS 0x10 #define ETOKEN_MAX_PINS 0x10
#define ETOKEN_KEY_ID(idx) (0x40 + (idx))
#define ETOKEN_AC_NEVER 0xFF #define ETOKEN_AC_NEVER 0xFF
#define ETOKEN_ALGO_RSA 0x08
#define ETOKEN_ALGO_PIN 0x87 #define ETOKEN_ALGO_PIN 0x87
#if 0 #if 0
@ -195,7 +206,7 @@ static int
etoken_erase(struct sc_profile *profile, struct sc_card *card) etoken_erase(struct sc_profile *profile, struct sc_card *card)
{ {
struct sc_pkcs15_pin_info sopin, temp; struct sc_pkcs15_pin_info sopin, temp;
struct sc_file *df = profile->df_info->file; struct sc_file *df = profile->df_info->file, *dir;
int r; int r;
/* Frob: need to tell the upper layers about the SO PIN id */ /* Frob: need to tell the upper layers about the SO PIN id */
@ -214,8 +225,12 @@ etoken_erase(struct sc_profile *profile, struct sc_card *card)
r = etoken_rm_rf(profile, card, df); r = etoken_rm_rf(profile, card, df);
sc_file_free(df); sc_file_free(df);
if (r >= 0) { /* Delete EF(DIR) as well. This may not be very nice
/* Delete 2F00? */ * against other applications that use this file, but
* extremely useful for testing :) */
if (r >= 0 && sc_profile_get_file(profile, "DIR", &dir) >= 0) {
r = etoken_rm_rf(profile, card, dir);
sc_file_free(dir);
} }
/* Unfrob the SO pin reference, and return */ /* Unfrob the SO pin reference, and return */
@ -228,7 +243,7 @@ out: sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
* Initialize pin file * Initialize pin file
*/ */
static int static int
etoken_new_pin(struct sc_profile *profile, struct sc_card *card, etoken_store_pin(struct sc_profile *profile, struct sc_card *card,
int pin_type, unsigned int pin_id, unsigned int puk_id, int pin_type, unsigned int pin_id, unsigned int puk_id,
const u8 *pin, size_t pin_len) const u8 *pin, size_t pin_len)
{ {
@ -330,13 +345,13 @@ etoken_init_app(struct sc_profile *profile, struct sc_card *card,
if (r >= 0 && puk && puk_len) { if (r >= 0 && puk && puk_len) {
puk_id = ETOKEN_PUK_ID(0); puk_id = ETOKEN_PUK_ID(0);
r = etoken_new_pin(profile, card, r = etoken_store_pin(profile, card,
SC_PKCS15INIT_SO_PUK, SC_PKCS15INIT_SO_PUK,
puk_id, ETOKEN_AC_NEVER, puk_id, ETOKEN_AC_NEVER,
puk, puk_len); puk, puk_len);
} }
if (r >= 0) { if (r >= 0) {
r = etoken_new_pin(profile, card, r = etoken_store_pin(profile, card,
SC_PKCS15INIT_SO_PIN, SC_PKCS15INIT_SO_PIN,
ETOKEN_PIN_ID(0), puk_id, ETOKEN_PIN_ID(0), puk_id,
pin, pin_len); pin, pin_len);
@ -350,7 +365,7 @@ etoken_init_app(struct sc_profile *profile, struct sc_card *card,
* Store a PIN * Store a PIN
*/ */
static int static int
etoken_put_pin(struct sc_profile *profile, struct sc_card *card, etoken_new_pin(struct sc_profile *profile, struct sc_card *card,
struct sc_pkcs15_pin_info *info, unsigned int index, struct sc_pkcs15_pin_info *info, unsigned int index,
const u8 *pin, size_t pin_len, const u8 *pin, size_t pin_len,
const u8 *puk, size_t puk_len) const u8 *puk, size_t puk_len)
@ -371,7 +386,7 @@ etoken_put_pin(struct sc_profile *profile, struct sc_card *card,
if (puk && puk_len) { if (puk && puk_len) {
puk_id = ETOKEN_PUK_ID(index); puk_id = ETOKEN_PUK_ID(index);
r = etoken_new_pin(profile, card, r = etoken_store_pin(profile, card,
SC_PKCS15INIT_USER_PUK, SC_PKCS15INIT_USER_PUK,
puk_id, ETOKEN_AC_NEVER, puk_id, ETOKEN_AC_NEVER,
puk, puk_len); puk, puk_len);
@ -379,7 +394,7 @@ etoken_put_pin(struct sc_profile *profile, struct sc_card *card,
if (r >= 0) { if (r >= 0) {
pin_id = ETOKEN_PIN_ID(index); pin_id = ETOKEN_PIN_ID(index);
r = etoken_new_pin(profile, card, r = etoken_store_pin(profile, card,
SC_PKCS15INIT_USER_PIN, SC_PKCS15INIT_USER_PIN,
pin_id, puk_id, pin_id, puk_id,
pin, pin_len); pin, pin_len);
@ -390,6 +405,73 @@ etoken_put_pin(struct sc_profile *profile, struct sc_card *card,
return r; return r;
} }
/*
* Create a private key object
*/
#define ETOKEN_KEY_OPTIONS 0x82
#define ETOKEN_KEY_FLAGS 0x40
static int
etoken_store_key_component(struct sc_card *card,
unsigned int key_id, unsigned int pin_id,
unsigned int num,
const u8 *data, size_t len,
int last)
{
struct sc_cardctl_etoken_pin_info args;
struct tlv tlv;
unsigned char buffer[256];
/* Initialize the TLV encoder */
tlv_init(&tlv, buffer, sizeof(buffer));
/* Object address */
tlv_next(&tlv, 0x83);
tlv_add(&tlv, 0x20|num); /* PSO, n-th component */
tlv_add(&tlv, key_id);
/* Object parameters */
tlv_next(&tlv, 0x85);
tlv_add(&tlv, ETOKEN_KEY_OPTIONS|(last? 0x00 : 0x20));
tlv_add(&tlv, ETOKEN_KEY_FLAGS);
tlv_add(&tlv, ETOKEN_ALGO_RSA);
tlv_add(&tlv, 0x00);
tlv_add(&tlv, 0xFF);
tlv_add(&tlv, 0x00);
tlv_add(&tlv, 0x00);
tlv_add(&tlv, 0x00);
/* AC bytes */
tlv_next(&tlv, 0x86);
tlv_add(&tlv, pin_id); /* AC USE */
tlv_add(&tlv, pin_id); /* AC CHANGE */
tlv_add(&tlv, 0x00); /* AC GENKEY? */
/* modulus */
tlv_next(&tlv, 0x8f);
while (len--)
tlv_add(&tlv, *data++);
args.data = buffer;
args.len = tlv_len(&tlv);
return sc_card_ctl(card, SC_CARDCTL_ETOKEN_PUT_DATA_OCI, &args);
}
static int
etoken_store_key(struct sc_profile *profile, struct sc_card *card,
unsigned int key_id, unsigned int pin_id,
struct rsakey *key)
{
int r;
r = etoken_store_key_component(card, key_id, pin_id,
0, key->n.data, key->n.len, 0);
if (r < 0)
return r;
r = etoken_store_key_component(card, key_id, pin_id,
1, key->d.data, key->d.len, 1);
return r;
}
/* /*
* Store a private key * Store a private key
*/ */
@ -479,6 +561,70 @@ etoken_new_file(struct sc_profile *profile, struct sc_card *card,
return 0; return 0;
} }
static int
etoken_generate_key(struct sc_profile *profile, struct sc_card *card,
unsigned int index, unsigned int keybits,
sc_pkcs15_pubkey_t *pubkey)
{
struct sc_cardctl_etoken_genkey_info args;
struct sc_file *temp;
struct rsakey key_obj;
u8 randbuf[64], key_id, pin_id;
int r;
keybits &= ~7UL;
if (keybits > RSAKEY_MAX_BITS) {
error(profile, "Unable to generate key, max size is %d\n",
RSAKEY_MAX_BITS);
return SC_ERROR_INVALID_ARGUMENTS;
}
if (sc_profile_get_file(profile, "tempfile", &temp) < 0) {
error(profile, "Profile doesn't define temporary file "
"for key generation.\n");
return SC_ERROR_NOT_SUPPORTED;
}
if ((r = sc_pkcs15init_create_file(profile, card, temp)) < 0)
goto out;
key_id = ETOKEN_KEY_ID(index);
pin_id = 0x00; /* XXX extract user pin id */
/* Create a key object, initializing components to 0xff */
memset(&key_obj, 0xff, sizeof(key_obj));
key_obj.n.len = keybits >> 3;
key_obj.d.len = keybits >> 3;
r = etoken_store_key(profile, card, key_id, pin_id, &key_obj);
if (r < 0)
goto out;
memset(&args, 0, sizeof(args));
#ifdef notyet
if ((r = scrandom_get_data(randbuf, sizeof(randbuf))) < 0)
goto out;
/* For now, we have to rely on the card's internal number
* generator because libscrandom is static, which causes
* all sorts of headaches when linking against it
* (some platforms don't allow non-PIC code in a shared lib,
* such as ia64).
*/
args.random_data = randbuf;
args.random_len = sizeof(randbuf);
#endif
args.key_id = key_id;
args.key_bits = keybits;
args.fid = temp->id;
r = sc_card_ctl(card, SC_CARDCTL_ETOKEN_GENERATE_KEY, &args);
memset(randbuf, 0, sizeof(randbuf));
if (r < 0)
goto out;
/* XXX: extract public key from file and delete it */
out: sc_file_free(temp);
return r;
}
static void static void
error(struct sc_profile *profile, const char *fmt, ...) error(struct sc_profile *profile, const char *fmt, ...)
@ -496,7 +642,8 @@ error(struct sc_profile *profile, const char *fmt, ...)
struct sc_pkcs15init_operations sc_pkcs15init_etoken_operations = { struct sc_pkcs15init_operations sc_pkcs15init_etoken_operations = {
etoken_erase, etoken_erase,
etoken_init_app, etoken_init_app,
etoken_put_pin, etoken_new_pin,
etoken_new_key, etoken_new_key,
etoken_new_file, etoken_new_file,
etoken_generate_key
}; };