- 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);
/* 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);
}
@ -551,6 +554,48 @@ etoken_put_data_fci(struct sc_card *card,
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
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,
(struct sc_cardctl_etoken_pin_info *) ptr);
break;
case SC_CARDCTL_ETOKEN_GENERATE_KEY:
return etoken_generate_key(card,
(struct sc_cardctl_etoken_genkey_info *) ptr);
}
return SC_ERROR_NOT_SUPPORTED;
}

View File

@ -58,7 +58,8 @@ enum {
*/
SC_CARDCTL_ETOKEN_BASE = _CTL_PREFIX('E', 'T', 'K'),
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
*/
struct sc_cardctl_etoken_pin_info {
u8 *data;
size_t len;
u8 * data;
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

View File

@ -28,6 +28,7 @@
#include <stdarg.h>
#include <opensc/opensc.h>
#include <opensc/cardctl.h>
#include <opensc/scrandom.h>
#include "pkcs15-init.h"
#include "profile.h"
@ -41,6 +42,14 @@ struct tlv {
unsigned char * current;
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
@ -57,8 +66,10 @@ static void error(struct sc_profile *, const char *, ...);
#define ETOKEN_PIN_ID(idx) (((idx) << 1) + 0x01)
#define ETOKEN_PUK_ID(idx) (((idx) << 1) + 0x02)
#define ETOKEN_MAX_PINS 0x10
#define ETOKEN_KEY_ID(idx) (0x40 + (idx))
#define ETOKEN_AC_NEVER 0xFF
#define ETOKEN_ALGO_RSA 0x08
#define ETOKEN_ALGO_PIN 0x87
#if 0
@ -195,7 +206,7 @@ static int
etoken_erase(struct sc_profile *profile, struct sc_card *card)
{
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;
/* 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);
sc_file_free(df);
if (r >= 0) {
/* Delete 2F00? */
/* Delete EF(DIR) as well. This may not be very nice
* 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 */
@ -228,7 +243,7 @@ out: sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
* Initialize pin file
*/
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,
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) {
puk_id = ETOKEN_PUK_ID(0);
r = etoken_new_pin(profile, card,
r = etoken_store_pin(profile, card,
SC_PKCS15INIT_SO_PUK,
puk_id, ETOKEN_AC_NEVER,
puk, puk_len);
}
if (r >= 0) {
r = etoken_new_pin(profile, card,
r = etoken_store_pin(profile, card,
SC_PKCS15INIT_SO_PIN,
ETOKEN_PIN_ID(0), puk_id,
pin, pin_len);
@ -350,7 +365,7 @@ etoken_init_app(struct sc_profile *profile, struct sc_card *card,
* Store a PIN
*/
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,
const u8 *pin, size_t pin_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) {
puk_id = ETOKEN_PUK_ID(index);
r = etoken_new_pin(profile, card,
r = etoken_store_pin(profile, card,
SC_PKCS15INIT_USER_PUK,
puk_id, ETOKEN_AC_NEVER,
puk, puk_len);
@ -379,7 +394,7 @@ etoken_put_pin(struct sc_profile *profile, struct sc_card *card,
if (r >= 0) {
pin_id = ETOKEN_PIN_ID(index);
r = etoken_new_pin(profile, card,
r = etoken_store_pin(profile, card,
SC_PKCS15INIT_USER_PIN,
pin_id, puk_id,
pin, pin_len);
@ -390,6 +405,73 @@ etoken_put_pin(struct sc_profile *profile, struct sc_card *card,
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
*/
@ -479,6 +561,70 @@ etoken_new_file(struct sc_profile *profile, struct sc_card *card,
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
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 = {
etoken_erase,
etoken_init_app,
etoken_put_pin,
etoken_new_pin,
etoken_new_key,
etoken_new_file,
etoken_generate_key
};