- Added support for Cyberflex Access 16K, based on a patch by

Martin Buechler


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1662 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
okir 2003-12-08 11:43:21 +00:00
parent 85fa4ed0da
commit b15bd6c453
5 changed files with 315 additions and 38 deletions

View File

@ -8,6 +8,7 @@ CFLAGS = @CFLAGS@ -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\"
LDFLAGS = @LDFLAGS@ @LIBOPENSC@
PROFILES = \
cyberflex.profile \
flex.profile \
gpk.profile \
miocos.profile \

View File

@ -0,0 +1,113 @@
#
# General purpose PKCS15 profile for Cyberflex Access cards
#
cardinfo {
max-pin-length = 8;
pin-encoding = ascii-numeric;
pin-pad-char = 0x00;
pin-domains = yes;
# This profile does not PIN-protect certificates
# stored on the card. If you enable this, you MUST
# adjust the sizes of the pin-domain and key-dir DFs
# accordingly.
protect-certificates = no;
}
# Define reasonable limits for PINs and PUK
# The user pin must always be CHV1, otherwise things
# won't work (crypto operations are protected by CHV1)
PIN user-pin {
attempts = 3;
}
PIN user-puk {
attempts = 10;
}
# Additional filesystem info.
# This is added to the file system info specified in the
# main profile.
filesystem {
# Define default ACLs and file ids for CHV1/CHV2
EF CHV1 {
file-id = 0000;
ACL = *=NEVER, UPDATE=CHV1;
}
EF CHV2 {
file-id = 0100;
ACL = *=NEVER, UPDATE=CHV2;
}
DF MF {
ACL = *=AUT0;
# The DELETE=NONE ACLs will go away once the code
# works. It's here to make sure I can erase the card
# even if I mess up big time.
#
# If you have a 16K card and wish to store
# two cert/key pairs.
# Note if you want the two keys to be protected by the
# same pin, you need to increase the size of the pin-dir.
DF PKCS15-AppDF {
ACL = *=$SOPIN, FILES=NONE, DELETE=NONE;
# Cyberflex Access 16K
size = 13000;
# This "pin-domain" DF is a template that is
# instantiated for each PIN created on the card.
#
# When instantiating the template, each file id will be
# combined with the last octet of the object's pkcs15 id
# to form a unique file ID. That is, PIN 01 will reside
# in 4b01, PIN 02 will reside in 4b02, etc.
template pin-domain {
DF pin-dir {
ACL = *=$SOPIN, FILES=NONE, DELETE=NONE;
file-id = 4B00;
# The minimum size for a 2048 bit key is 1396
size = 2800;
}
}
# For PIN-protected files, instantiate this template
# below the pin directory.
# For unprotected objects, install within the application DF.
#
# When instantiating the template, each file id will be
# combined with the last octet of the object's pkcs15 id
# to form a unique file ID.
template key-domain {
# In order to support more than one key per PIN,
# each key must be within its own subdirectory.
DF key-directory {
ACL = *=$PIN, FILES=NONE;
file-id = 3000;
size = 1400;
EF private-key {
file-id = 0012;
ACL = *=NEVER, CRYPTO=$PIN, UPDATE=$PIN;
}
EF internal-pubkey-file {
file-id = 1012;
ACL = *=$PIN, READ=NONE;
}
}
EF extractable-key {
file-id = 4300;
ACL = *=NEVER, READ=$PIN, UPDATE=$PIN;
}
EF public-key {
file-id = 4400;
ACL = *=$PIN, READ=NONE;
}
EF certificate {
file-id = 4500;
ACL = *=$PIN, READ=NONE;
}
}
}
}
}

View File

@ -46,10 +46,6 @@ static int cflex_create_empty_pin_file(sc_profile_t *, sc_card_t *,
sc_path_t *, int, sc_file_t **);
static int cflex_get_keyfiles(sc_profile_t *, sc_card_t *,
const sc_path_t *, sc_file_t **, sc_file_t **);
static int cflex_encode_private_key(struct sc_pkcs15_prkey_rsa *,
u8 *, size_t *, int);
static int cflex_encode_public_key(struct sc_pkcs15_prkey_rsa *,
u8 *, size_t *, int);
static int
cflex_delete_file(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
@ -338,7 +334,7 @@ cflex_store_key(sc_profile_t *profile, sc_card_t *card,
sc_file_t *prkf, *pukf;
unsigned char keybuf[1024];
size_t size;
int r, key_num;
int r;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
sc_error(card->ctx, "Cryptoflex supports only RSA keys.");
@ -350,18 +346,28 @@ cflex_store_key(sc_profile_t *profile, sc_card_t *card,
if (r < 0)
return r;
key_num = key_info->key_reference + 1;
/* Write the private key */
size = sizeof(keybuf);
if ((r = cflex_encode_private_key(&key->u.rsa, keybuf, &size, key_num)) < 0
|| (r = sc_pkcs15init_update_file(profile, card, prkf, keybuf, size)) < 0)
r = profile->ops->encode_private_key(profile, card,
&key->u.rsa, keybuf, &size,
key_info->key_reference);
if (r < 0)
goto out;
size = sizeof(keybuf);
if ((r = cflex_encode_public_key(&key->u.rsa, keybuf, &size, key_num)) < 0
|| (r = sc_pkcs15init_update_file(profile, card, pukf, keybuf, size)) < 0)
r = sc_pkcs15init_update_file(profile, card, prkf, keybuf, size);
if (r < 0)
goto out;
/* Write the public key */
size = sizeof(keybuf);
r = profile->ops->encode_public_key(profile, card,
&key->u.rsa, keybuf, &size,
key_info->key_reference);
if (r < 0)
goto out;
r = sc_pkcs15init_update_file(profile, card, pukf, keybuf, size);
out: sc_file_free(prkf);
sc_file_free(pukf);
return r;
@ -611,11 +617,29 @@ bn2cf(sc_pkcs15_bignum_t *num, u8 *buf, size_t bufsize)
}
static int
cflex_encode_private_key(struct sc_pkcs15_prkey_rsa *rsa,
u8 *key, size_t *keysize, int key_num)
bn2cft(sc_pkcs15_bignum_t *num, u8 tag, u8 *buf, size_t bufsize)
{
size_t base;
int r;
size_t len = num->len;
if (len + 3 > bufsize)
return SC_ERROR_INVALID_ARGUMENTS;
memset(buf, 0, bufsize);
buf[0] = tag;
buf[1] = len + 1;
memcpy(buf + 2, num->data, len);
return 0;
}
/*
* Cryptoflex key encoding
*/
static int
cryptoflex_encode_private_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa,
u8 *key, size_t *keysize, int key_ref)
{
size_t base = rsa->modulus.len / 2, key_blob_size;
int r, key_num = key_ref + 1;
switch (rsa->modulus.len) {
case 512 / 8:
@ -627,13 +651,13 @@ cflex_encode_private_key(struct sc_pkcs15_prkey_rsa *rsa,
return SC_ERROR_INVALID_ARGUMENTS;
}
base = rsa->modulus.len / 2;
if (*keysize < (5 * base + 6))
key_blob_size = 5 * base + 3;
if (*keysize < key_blob_size + 3)
return SC_ERROR_BUFFER_TOO_SMALL;
*keysize = 5 * base + 6;
*keysize = key_blob_size + 3;
*key++ = (5 * base + 3) >> 8;
*key++ = (5 * base + 3) & 0xFF;
*key++ = key_blob_size >> 8;
*key++ = key_blob_size & 0xFF;
*key++ = key_num;
if ((r = bn2cf(&rsa->p, key + 0 * base, base)) < 0
@ -652,11 +676,12 @@ cflex_encode_private_key(struct sc_pkcs15_prkey_rsa *rsa,
}
static int
cflex_encode_public_key(struct sc_pkcs15_prkey_rsa *rsa,
u8 *key, size_t *keysize, int key_num)
cryptoflex_encode_public_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa,
u8 *key, size_t *keysize, int key_ref)
{
size_t base;
int r;
int r, key_num = key_ref + 1;
switch (rsa->modulus.len) {
case 512 / 8:
@ -694,18 +719,139 @@ cflex_encode_public_key(struct sc_pkcs15_prkey_rsa *rsa,
return 0;
}
static struct sc_pkcs15init_operations sc_pkcs15init_cflex_operations;
struct sc_pkcs15init_operations *sc_pkcs15init_get_cflex_ops(void)
/*
* Cyberflex key encoding
*/
static int
cyberflex_encode_private_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa,
u8 *key, size_t *keysize, int key_ref)
{
sc_pkcs15init_cflex_operations.erase_card = cflex_erase_card;
sc_pkcs15init_cflex_operations.create_dir = cflex_create_dir;
sc_pkcs15init_cflex_operations.create_domain = cflex_create_domain;
sc_pkcs15init_cflex_operations.select_pin_reference = cflex_select_pin_reference;
sc_pkcs15init_cflex_operations.create_pin = cflex_create_pin;
sc_pkcs15init_cflex_operations.create_key = cflex_create_key;
sc_pkcs15init_cflex_operations.generate_key = cflex_generate_key;
sc_pkcs15init_cflex_operations.store_key = cflex_store_key;
size_t base = rsa->modulus.len / 2, key_blob_size, bnlen;
int r, key_num = key_ref + 1, alg_id;
switch (rsa->modulus.len) {
case 512 / 8: alg_id = 0xC4; break;
case 768 / 8: alg_id = 0xC6; break;
case 1024 / 8: alg_id = 0xC8; break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
return &sc_pkcs15init_cflex_operations;
key_blob_size = 12 + 5 * (base + 3) + 4;
if (*keysize < key_blob_size)
return SC_ERROR_BUFFER_TOO_SMALL;
*keysize = key_blob_size;
memset(key, 0, *keysize);
*key++ = key_blob_size >> 8;
*key++ = key_blob_size & 0xFF;
*key++ = key_num;
*key++ = alg_id;
/* key blob header:
* "C2:06:C1:08:13:00:00:05"
*/
memcpy(key, "\xc2\x06\xc1\x08\x12\x00\x00\x05", 8);
key += 8;
/* Each bignum is encoded with a 2 byte header and a
* NULL pad byte */
bnlen = base + 3;
if ((r = bn2cft(&rsa->p, 0xC2, key + 0 * bnlen, bnlen)) < 0
|| (r = bn2cft(&rsa->q, 0xC2, key + 1 * bnlen, bnlen)) < 0
|| (r = bn2cft(&rsa->iqmp, 0xC2, key + 2 * bnlen, bnlen)) < 0
|| (r = bn2cft(&rsa->dmp1, 0xC2, key + 3 * bnlen, bnlen)) < 0
|| (r = bn2cft(&rsa->dmq1, 0xC2, key + 4 * bnlen, bnlen)) < 0)
return r;
key += 5 * bnlen;
*key++ = 0;
*key++ = 0;
*key++ = 0;
return 0;
}
static int
cyberflex_encode_public_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa,
u8 *key, size_t *keysize, int key_ref)
{
size_t base = rsa->modulus.len, key_blob_size, bnlen;
int r, key_num = key_ref + 1, alg_id;
switch (rsa->modulus.len) {
case 512 / 8: alg_id = 0xC5; break;
case 768 / 8: alg_id = 0xC7; break;
case 1024 / 8: alg_id = 0xC9; break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
key_blob_size = 12 + base + 3 + 7;
if (*keysize < key_blob_size)
return SC_ERROR_BUFFER_TOO_SMALL;
*keysize = key_blob_size;
memset(key, 0, *keysize);
*key++ = key_blob_size >> 8;
*key++ = key_blob_size & 0xFF;
*key++ = key_num;
*key++ = alg_id;
/* Key blob header */
memcpy(key, "\xC1\x06\xC0\x08\x13\x00\x00\x05", 8);
key += 8;
bnlen = rsa->modulus.len + 3;
if ((r = bn2cft(&rsa->modulus, 0xC0, key, bnlen)) < 0
|| (r = bn2cft(&rsa->exponent, 0xC0, key + bnlen, 3 + 4)) < 0)
return r;
return 0;
}
static struct sc_pkcs15init_operations sc_pkcs15init_cryptoflex_operations;
static struct sc_pkcs15init_operations sc_pkcs15init_cyberflex_operations;
struct sc_pkcs15init_operations *
sc_pkcs15init_get_cryptoflex_ops(void)
{
struct sc_pkcs15init_operations *ops;
ops = &sc_pkcs15init_cryptoflex_operations;
ops->erase_card = cflex_erase_card;
ops->create_dir = cflex_create_dir;
ops->create_domain = cflex_create_domain;
ops->select_pin_reference = cflex_select_pin_reference;
ops->create_pin = cflex_create_pin;
ops->create_key = cflex_create_key;
ops->generate_key = cflex_generate_key;
ops->store_key = cflex_store_key;
ops->encode_private_key = cryptoflex_encode_private_key;
ops->encode_public_key = cryptoflex_encode_public_key;
return ops;
}
struct sc_pkcs15init_operations *
sc_pkcs15init_get_cyberflex_ops(void)
{
struct sc_pkcs15init_operations *ops;
ops = &sc_pkcs15init_cyberflex_operations;
ops->erase_card = cflex_erase_card;
ops->create_dir = cflex_create_dir;
ops->create_domain = cflex_create_domain;
ops->select_pin_reference = cflex_select_pin_reference;
ops->create_pin = cflex_create_pin;
ops->create_key = cflex_create_key;
ops->generate_key = cflex_generate_key;
ops->store_key = cflex_store_key;
ops->encode_private_key = cyberflex_encode_private_key;
ops->encode_public_key = cyberflex_encode_public_key;
return ops;
}

View File

@ -87,6 +87,21 @@ struct sc_pkcs15init_operations {
sc_pkcs15_object_t *,
sc_pkcs15_pubkey_t *);
/*
* Encode private/public key
* These are used mostly by the Cryptoflex/Cyberflex drivers.
*/
int (*encode_private_key)(sc_profile_t *, sc_card_t *,
struct sc_pkcs15_prkey_rsa *,
u8 *buf, size_t *bufsize, int key_ref);
int (*encode_public_key)(sc_profile_t *, sc_card_t *,
struct sc_pkcs15_prkey_rsa *,
u8 *buf, size_t *bufsize, int key_ref);
/*
* Old-style API
*/
/*
* Initialize application, and optionally set a SO pin
*/
@ -321,7 +336,8 @@ extern int sc_pkcs15_create_pin_domain(sc_profile_t *, sc_card_t *,
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_gpk_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_miocos_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cflex_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cryptoflex_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cyberflex_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_etoken_ops(void);
#ifdef __cplusplus

View File

@ -131,7 +131,8 @@ static struct profile_operations {
} profile_operations[] = {
{ "gpk", (void *) sc_pkcs15init_get_gpk_ops },
{ "miocos", (void *) sc_pkcs15init_get_miocos_ops },
{ "flex", (void *) sc_pkcs15init_get_cflex_ops },
{ "flex", (void *) sc_pkcs15init_get_cryptoflex_ops },
{ "cyberflex", (void *) sc_pkcs15init_get_cyberflex_ops },
{ "etoken", (void *) sc_pkcs15init_get_etoken_ops },
{ NULL, NULL },
};