- Fixed PKCS #15 structure generation on Cryptoflex cards

and implemented a default profile
- Cryptoflex now reports its supported PK algorithms
  correctly
- Various pkcs15-init fixes


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@295 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2002-03-12 13:00:57 +00:00
parent 2c7a0ac27b
commit 23e956cf9b
12 changed files with 399 additions and 528 deletions

View File

@ -6,7 +6,7 @@ dnl $Id$
AC_PREREQ(2.52)
AC_INIT(src/libopensc/sc.c)
AM_INIT_AUTOMAKE(opensc, 0.5.0)
AM_INIT_AUTOMAKE(opensc, 0.6.0)
AM_CONFIG_HEADER(config.h)
AC_CANONICAL_HOST

View File

@ -76,7 +76,19 @@ static int flex_init(struct sc_card *card)
if (card->drv_data == NULL)
return SC_ERROR_OUT_OF_MEMORY;
card->cla = 0xC0;
/* FIXME: Card type detection */
if (1) {
unsigned long flags;
flags = SC_ALGORITHM_RSA_RAW;
flags |= SC_ALGORITHM_RSA_HASH_NONE;
_sc_card_add_rsa_alg(card, 512, flags, 0);
_sc_card_add_rsa_alg(card, 768, flags, 0);
_sc_card_add_rsa_alg(card, 1024, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
}
return 0;
}
@ -97,10 +109,8 @@ static void add_acl_entry(struct sc_file *file, unsigned int op,
sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
break;
case 4:
if (is_mf)
sc_file_add_acl_entry(file, op, SC_AC_AUT, 1);
else
sc_file_add_acl_entry(file, op, SC_AC_AUT, SC_AC_KEY_REF_NONE);
/* Assume the key is the AAK */
sc_file_add_acl_entry(file, op, SC_AC_AUT, 1);
break;
case 6:
sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
@ -112,11 +122,13 @@ static void add_acl_entry(struct sc_file *file, unsigned int op,
break;
case 8:
sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
sc_file_add_acl_entry(file, op, SC_AC_AUT, SC_AC_KEY_REF_NONE);
/* Assume the key is the AAK */
sc_file_add_acl_entry(file, op, SC_AC_AUT, 1);
break;
case 9:
sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
sc_file_add_acl_entry(file, op, SC_AC_AUT, SC_AC_KEY_REF_NONE);
/* Assume the key is the AAK */
sc_file_add_acl_entry(file, op, SC_AC_AUT, 1);
break;
case 15:
sc_file_add_acl_entry(file, op, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
@ -615,6 +627,15 @@ static int flex_set_security_env(struct sc_card *card,
error(card->ctx, "Invalid crypto operation supplied.\n");
return SC_ERROR_NOT_SUPPORTED;
}
if (env->algorithm != SC_ALGORITHM_RSA) {
error(card->ctx, "Invalid crypto algorithm supplied.\n");
return SC_ERROR_NOT_SUPPORTED;
}
if ((env->algorithm_flags & SC_ALGORITHM_RSA_PADS) ||
(env->algorithm_flags & SC_ALGORITHM_RSA_HASHES)) {
error(card->ctx, "Card supports only raw RSA.\n");
return SC_ERROR_NOT_SUPPORTED;
}
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
if (env->key_ref_len != 1 ||
(env->key_ref[0] != 0 && env->key_ref[0] != 1)) {

View File

@ -178,7 +178,10 @@ static int encode_file_structure(struct sc_card *card, const struct sc_file *fil
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
for (i = 0; i < 8; i++) {
if (file->sec_attr_len == 4) {
memcpy(p, file->sec_attr, 4);
p += 4;
} else for (i = 0; i < 8; i++) {
u8 nibble;
if (ops[i] == -1)

View File

@ -139,7 +139,7 @@ int sc_enum_apps(struct sc_card *card)
struct sc_path path;
int ef_structure;
size_t file_size;
int r;
int r, log_errors;
if (card->app_count < 0)
card->app_count = 0;
@ -148,7 +148,10 @@ int sc_enum_apps(struct sc_card *card)
sc_file_free(card->ef_dir);
card->ef_dir = NULL;
}
log_errors = card->ctx->log_errors;
card->ctx->log_errors = 0;
r = sc_select_file(card, &path, &card->ef_dir);
card->ctx->log_errors = log_errors;
if (r)
return r;
if (card->ef_dir->type != SC_FILE_TYPE_WORKING_EF) {

View File

@ -46,7 +46,7 @@ const static struct sc_card_error iso7816_errors[] = {
{ 0x6900, SC_ERROR_UNKNOWN_REPLY, "Command not allowed" },
{ 0x6981, SC_ERROR_UNKNOWN_REPLY, "Command incompatible with file structure" },
{ 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied" },
{ 0x6983, SC_ERROR_UNKNOWN_REPLY, "Authentication method blocked" },
{ 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "Authentication method blocked" },
{ 0x6984, SC_ERROR_UNKNOWN_REPLY, "Referenced data invalidated" },
{ 0x6985, SC_ERROR_UNKNOWN_REPLY, "Conditions of use not satisfied" },
{ 0x6986, SC_ERROR_UNKNOWN_REPLY, "Command not allowed (no current EF)" },

View File

@ -81,6 +81,7 @@ extern "C" {
#define SC_ERROR_CLASS_NOT_SUPPORTED -1033
#define SC_ERROR_SLOT_NOT_FOUND -1034
#define SC_ERROR_SLOT_ALREADY_CONNECTED -1035
#define SC_ERROR_AUTH_METHOD_BLOCKED -1036
/* Different APDU cases */
#define SC_APDU_CASE_NONE 0
@ -237,6 +238,7 @@ struct sc_file {
#define SC_ALGORITHM_RSA_RAW 0x00000001
/* If the card is willing to produce a cryptogram padded with the following
* methods, set these flags accordingly. */
#define SC_ALGORITHM_RSA_PADS 0x0000000E
#define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002
#define SC_ALGORITHM_RSA_PAD_ANSI 0x00000004
#define SC_ALGORITHM_RSA_PAD_ISO9796 0x00000008
@ -244,6 +246,7 @@ struct sc_file {
/* If the card is willing to produce a cryptogram with the following
* hash values, set these flags accordingly. */
#define SC_ALGORITHM_RSA_HASH_NONE 0x00000010
#define SC_ALGORITHM_RSA_HASHES 0x000000E0
#define SC_ALGORITHM_RSA_HASH_SHA1 0x00000020
#define SC_ALGORITHM_RSA_HASH_MD5 0x00000040
#define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000080

View File

@ -344,6 +344,7 @@ const char *sc_strerror(int error)
"Invalid CLA byte in APDU",
"Slot not found",
"Slot already connected",
"Authentication method blocked",
};
int nr_errors = sizeof(errors) / sizeof(errors[0]);

View File

@ -7,45 +7,105 @@ CardInfo
MinPinLength 1
MaxPinLength 8
PinEncoding ascii-numeric
PinPadChar 0x2d # '-'
PinPadChar 0x00
PrKeyAccessFlags RSA 0x1D
# This is the AAK (ie. transport key) required for
# creating files in the MF
Key AUT1 0x0001 "=Muscle00"
EF chv1file
DF MF
Path 3F00
ACL *=AUT1
DF key1df
Parent PKCS15-AppDF
FileID 4B01
Size 750 # Sufficient for a 1024-bit key
ACL *=AUT1 FILES=NONE
DF key2df
Parent PKCS15-AppDF
FileID 4B02
Size 750 # Sufficient for a 1024-bit key
ACL *=AUT1 FILES=NONE
EF pinfile-chv1
Parent key1df
FileID 0000
Path 50154B01
Structure transparent
Size 23
ACL *=NEVER UPDATE=AUT1
EF chv2file
EF pinfile-chv2
Parent key2df
FileID 0000
Path 50154B02
Structure transparent
Size 23
ACL *=NEVER UPDATE=AUT1
EF template-private-key
FileID 0012 # This is the base FileID
EF template-private-key-1
Parent key1df
FileID 0012
Structure transparent
ACL *=NEVER UPDATE=AUT1
Size 330
ACL *=AUT1 READ=NEVER
EF template-public-key
FileID 1012
EF template-private-key-2
Parent key2df
FileID 0012
Structure transparent
ACL *=NONE
Size 330
ACL *=AUT1 READ=NEVER
# CVH1. 3 attempts for the PIN, and 10 for the PUK
EF template-public-key-1
Parent PKCS15-AppDF
FileID 5201
Structure transparent
ACL *=AUT1 READ=NONE
EF template-public-key-2
Parent PKCS15-AppDF
FileID 5202
Structure transparent
ACL *=AUT1 READ=NONE
EF PKCS15-DIR
ACL *=NEVER READ=NONE UPDATE=AUT1
EF PKCS15-ODF
ACL *=NEVER READ=NONE UPDATE=AUT1
EF PKCS15-AODF
ACL *=NEVER READ=NONE UPDATE=AUT1
EF PKCS15-PrKDF
ACL *=NEVER READ=NONE UPDATE=AUT1
EF PKCS15-PuKDF
ACL *=NEVER READ=NONE UPDATE=AUT1
EF PKCS15-CDF
ACL *=NEVER READ=NONE UPDATE=AUT1
# CHV1. 3 attempts for the PIN, and 10 for the PUK
PIN CHV1
File chv1file
Reference 0x1
File pinfile-chv1
Reference 0x01
Attempts 3 10
# CVH2. 3 attempts for the PIN, and 10 for the PUK
# CHV2. 3 attempts for the PIN, and 10 for the PUK
PIN CHV2
File chv2file
Reference 0x1
File pinfile-chv2
Reference 0x01
Attempts 3 10
PrivateKey AuthKey
Reference 0x00
Index 1
File template-private-key-1
PrivateKey SignKey
Reference 0x00
Index 1
File template-private-key-2

View File

@ -74,14 +74,20 @@ static int cflex_store_pin(struct sc_profile *profile, struct sc_card *card,
sc_file_dup(&pinfile, info->file->file);
/* Now create the file */
if ((r = sc_pkcs15init_create_file(profile, pinfile)) < 0)
card->ctx->log_errors = 0;
r = sc_select_file(card, &pinfile->path, NULL);
card->ctx->log_errors = 1;
if (r == SC_ERROR_FILE_NOT_FOUND) {
/* Now create the file */
if ((r = sc_pkcs15init_create_file(profile, pinfile)) < 0)
goto out;
/* The PIN EF is automatically selected */
} else if (r < 0)
goto out;
/* If messing with the PIN file requires any sort of
* authentication, send it to the card now */
if ((r = sc_select_file(card, &pinfile->path, NULL)) < 0
|| (r = sc_pkcs15init_authenticate(profile, pinfile, SC_AC_OP_UPDATE)) < 0)
if ((r = sc_pkcs15init_authenticate(profile, pinfile, SC_AC_OP_UPDATE)) < 0)
goto out;
r = cflex_update_pin(card, info);
@ -96,21 +102,38 @@ out: sc_file_free(pinfile);
*/
static int cflex_init_app(struct sc_profile *profile, struct sc_card *card)
{
struct pin_info *pin1, *pin2;
struct pin_info *pin1, *pin2, *pin3;
int r;
pin1 = sc_profile_find_pin(profile, "CHV1");
pin2 = sc_profile_find_pin(profile, "CHV2");
pin3 = sc_profile_find_pin(profile, "CHV3");
if (pin1 == NULL) {
fprintf(stderr, "No CHV1 defined\n");
return 1;
}
/* XXX TODO:
* if the CHV2 pin file is required to create files
* in the application DF, create that file first */
card->ctx->log_errors = 0;
r = sc_select_file(card, &profile->df_info.file->path, NULL);
card->ctx->log_errors = 1;
if (r == SC_ERROR_FILE_NOT_FOUND) {
/* Create the application DF */
if (sc_pkcs15init_create_file(profile, profile->df_info.file))
return 1;
} else if (r < 0) {
fprintf(stderr, "Unable to select application DF: %s\n",
sc_strerror(r));
return 1;
}
/* Create the application DF */
if (sc_pkcs15init_create_file(profile, profile->df_info.file))
/* Store CHV3 (ie. SO PIN) */
if (pin3) {
if (cflex_store_pin(profile, card, pin3))
return 1;
}
/* Store CHV1 */
if (cflex_store_pin(profile, card, pin1))
return 1;
/* Store CHV2 */
@ -118,10 +141,6 @@ static int cflex_init_app(struct sc_profile *profile, struct sc_card *card)
if (cflex_store_pin(profile, card, pin2))
return 1;
}
/* Store CHV1 */
if (cflex_store_pin(profile, card, pin1))
return 1;
return 0;
}
@ -134,8 +153,6 @@ static int cflex_allocate_file(struct sc_profile *profile, struct sc_card *card,
struct sc_file **out)
{
struct file_info *templ;
struct sc_file *file;
struct sc_path *p;
char name[64], *tag, *desc;
desc = tag = NULL;
@ -171,514 +188,237 @@ static int cflex_allocate_file(struct sc_profile *profile, struct sc_card *card,
type &= SC_PKCS15_TYPE_CLASS_MASK;
}
snprintf(name, sizeof(name), "template-%s", tag);
snprintf(name, sizeof(name), "template-%s-%d", tag, num + 1);
if (!(templ = sc_profile_find_file(profile, name))) {
error("Profile doesn't define %s template (%s)\n",
error("Profile doesn't define %s template (%s)",
desc, name);
return SC_ERROR_NOT_SUPPORTED;
}
sc_file_dup(out, templ->file);
/* Now construct file from template */
sc_file_dup(&file, templ->file);
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 invert_buf(u8 *dest, const u8 *src, size_t c)
{
int i;
for (i = 0; i < c; i++)
dest[i] = src[c-1-i];
}
static int bn2cf(const BIGNUM *num, u8 *buf)
{
u8 tmp[512];
int r;
r = BN_bn2bin(num, tmp);
if (r <= 0)
return r;
invert_buf(buf, tmp, r);
return r;
}
#if 0
/*
* Create the PK file
*/
static int gpk_pkfile_create(struct sc_profile *profile, struct sc_card *card,
struct sc_file *file)
static int gen_d(RSA *rsa)
{
struct sc_file *found = NULL;
int r;
card->ctx->log_errors = 0;
r = sc_select_file(card, &file->path, &found);
card->ctx->log_errors = 1;
if (r == SC_ERROR_FILE_NOT_FOUND) {
r = sc_pkcs15init_create_file(profile, file);
if (r >= 0)
r = sc_select_file(card, &file->path, &found);
} else {
/* XXX: make sure the file has correct type and size? */
}
if (r >= 0)
r = sc_pkcs15init_authenticate(profile, file, SC_AC_OP_UPDATE);
if (found)
sc_file_free(found);
return r;
BN_CTX *ctx, *ctx2;
BIGNUM *r0, *r1, *r2;
ctx = BN_CTX_new();
ctx2 = BN_CTX_new();
BN_CTX_start(ctx);
r0 = BN_CTX_get(ctx);
r1 = BN_CTX_get(ctx);
r2 = BN_CTX_get(ctx);
BN_sub(r1, rsa->p, BN_value_one());
BN_sub(r2, rsa->q, BN_value_one());
BN_mul(r0, r1, r2, ctx);
if ((rsa->d = BN_mod_inverse(NULL, rsa->e, r0, ctx2)) == NULL) {
fprintf(stderr, "BN_mod_inverse() failed.\n");
return -1;
}
BN_CTX_end(ctx);
BN_CTX_free(ctx);
BN_CTX_free(ctx2);
return 0;
}
#endif
/*
* Set up the public key record for a signature only public key
*/
static int
gpk_pkfile_init_public(struct sc_card *card, struct sc_file *file,
unsigned int algo, unsigned int bits,
unsigned int usage, struct sc_acl_entry *acl)
static int cflex_encode_private_key(RSA *rsa, u8 *key, size_t *keysize, int key_num)
{
u8 sysrec[7], buffer[256];
unsigned int npins, n;
int r;
u8 buf[512], *p = buf;
u8 bnbuf[256];
int base = 0;
int r;
switch (BN_num_bits(rsa->n)) {
case 512:
base = 32;
break;
case 768:
base = 48;
break;
case 1024:
base = 64;
break;
case 2048:
base = 128;
break;
}
if (base == 0) {
fprintf(stderr, "Key length invalid.\n");
return 2;
}
*p++ = (5 * base + 3) >> 8;
*p++ = (5 * base + 3) & 0xFF;
*p++ = key_num;
r = bn2cf(rsa->p, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
/* Set up the system record */
memset(sysrec, 0, sizeof(sysrec));
r = bn2cf(rsa->q, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
/* XXX: How to map keyUsage to sysrec[2]?
* 0x00 sign & unwrap
* 0x10 sign only
* 0x20 unwrap only
* 0x30 CA key
* Which PKCS15 key usage values map to which flag?
*/
sysrec[2] = 0x00; /* no restriction for now */
r = bn2cf(rsa->iqmp, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
/* Set the key type and algorithm */
if ((r = gpk_pkfile_keybits(bits, &sysrec[1])) < 0
|| (r = gpk_pkfile_keyalgo(algo, &sysrec[5])) < 0)
return r;
r = bn2cf(rsa->dmp1, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
/* Set PIN protection if requested. */
for (npins = 0; acl; acl = acl->next) {
if (acl->method == SC_AC_NONE
|| acl->method == SC_AC_NEVER)
continue;
if (acl->method == SC_AC_CHV) {
if (++npins >= 2) {
error("Too many pins for PrKEY file!\n");
return SC_ERROR_NOT_SUPPORTED;
}
sysrec[2] += 0x40;
sysrec[3] >>= 4;
sysrec[3] |= acl->key_ref << 4;
}
}
/* compute checksum - yet another slightly different
* checksum algorithm courtesy of Gemplus */
/* XXX: This is different from what the GPK reference
* manual says which tells you to start with 0xA5 -- but
* maybe that's just for the GPK8000 */
for (sysrec[6] = 0xFF, n = 0; n < 6; n++)
sysrec[6] ^= sysrec[n];
card->ctx->log_errors = 0;
r = sc_read_record(card, 1, buffer, sizeof(buffer),
SC_RECORD_BY_REC_NR);
card->ctx->log_errors = 1;
if (r >= 0) {
if (r != 7 || buffer[0] != 0) {
error("first record of public key file is not Lsys0");
return SC_ERROR_OBJECT_NOT_VALID;
}
r = sc_update_record(card, 1, sysrec, sizeof(sysrec),
SC_RECORD_BY_REC_NR);
} else {
r = sc_append_record(card, sysrec, sizeof(sysrec), 0);
}
return r;
}
static int
gpk_pkfile_update_public(struct sc_card *card, struct pkpart *part)
{
struct pkcomp *pe;
unsigned char buffer[256];
unsigned int m, n, tag;
int r = 0, found;
if (card->ctx->debug > 1)
printf("Updating public key elements\n");
/* If we've been given a key with public parts, write them now */
for (n = 2; n < 256; n++) {
card->ctx->log_errors = 0;
r = sc_read_record(card, n, buffer, sizeof(buffer),
SC_RECORD_BY_REC_NR);
card->ctx->log_errors = 1;
if (r < 0) {
r = 0;
break;
}
/* Check for bad record */
if (r < 2) {
error("key file format error: "
"record %u too small (%u bytes)\n",
n, r);
return SC_ERROR_OBJECT_NOT_VALID;
}
tag = buffer[0];
for (m = 0, found = 0; m < part->count; m++) {
pe = part->components + m;
if (pe->tag == tag) {
r = sc_update_record(card, n,
pe->data, pe->size,
SC_RECORD_BY_REC_NR);
if (r < 0)
return r;
pe->tag = 0; /* mark as stored */
found++;
break;
}
}
if (!found && card->ctx->debug)
printf("GPK unknown PK tag %u\n", tag);
}
/* Write all remaining elements */
for (m = 0; r >= 0 && m < part->count; m++) {
pe = part->components + m;
if (pe->tag != 0)
r = sc_append_record(card, pe->data, pe->size, 0);
}
return r;
}
static int
gpk_pkfile_init_private(struct sc_card *card,
struct sc_file *file, unsigned int privlen)
{
struct sc_cardctl_gpk_pkinit args;
if (card->ctx->debug > 1)
printf("Initializing private key portion of file\n");
args.file = file;
args.privlen = privlen;
return sc_card_ctl(card, SC_CARDCTL_GPK_PKINIT, &args);
}
static int
gpk_pkfile_load_private(struct sc_card *card, struct sc_file *file,
u8 *data, unsigned int len, unsigned int datalen)
{
struct sc_cardctl_gpk_pkload args;
args.file = file;
args.data = data;
args.len = len;
args.datalen = datalen;
return sc_card_ctl(card, SC_CARDCTL_GPK_PKLOAD, &args);
}
static int
gpk_pkfile_update_private(struct sc_profile *profile,
struct sc_card *card, struct sc_file *file,
struct pkpart *part)
{
struct auth_info *sm;
unsigned int m, size, nb, cks;
struct pkcomp *pe;
u8 data[256];
int r = 0;
if (card->ctx->debug > 1)
printf("Updating private key elements\n");
/* We must set a secure messaging key before each Load Private Key
* command. Any key will do...
* The GPK _is_ weird. */
sm = sc_profile_find_key(profile, SC_AC_PRO, -1);
if (sm == NULL) {
error("No secure messaging key defined by profile");
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
}
for (m = 0; m < part->count; m++) {
pe = part->components + m;
if (pe->size + 8 > sizeof(data))
return SC_ERROR_BUFFER_TOO_SMALL;
memcpy(data, pe->data, pe->size);
size = pe->size;
r = sc_verify(card, SC_AC_PRO,
sm->ref, sm->key, sm->key_len, NULL);
if (r < 0)
break;
/* Pad out data to a multiple of 8 and checksum.
* The GPK manual is a bit unclear about whether you
* checksum first and then pad, or vice versa.
* The following code does seem to work though: */
for (nb = 0, cks = 0xff; nb < size; nb++)
cks ^= data[nb];
data[nb++] = cks;
while (nb & 7)
data[nb++] = 0;
r = gpk_pkfile_load_private(card, file, data, size, nb);
if (r < 0)
break;
pe++;
}
return r;
}
/* Sum up the size of the public key elements
* Each element is type + tag + bignum
*/
static void
gpk_compute_publen(struct pkpart *part)
{
unsigned int n, publen = 8; /* length of sysrec0 */
for (n = 0; n < part->count; n++)
publen += 2 + part->components[n].size;
part->size = (publen + 3) & ~3UL;
}
/* Sum up the size of the private key elements
* Each element is type + tag + bignum + checksum, padded to a multiple
* of eight
*/
static void
gpk_compute_privlen(struct pkpart *part)
{
unsigned int n, privlen = 8;
for (n = 0; n < part->count; n++)
privlen += (3 + part->components[n].size + 7) & ~7UL;
part->size = privlen;
}
/*
* Convert BIGNUM to GPK representation, optionally zero padding to size.
* Note OpenSSL stores BIGNUMs big endian while the GPK wants them
* little endian
*/
static void
gpk_bn2bin(const BIGNUM *bn, unsigned char *dest, unsigned int size)
{
u8 temp[256], *src;
unsigned int n, len;
assert(BN_num_bytes(bn) <= sizeof(temp));
len = BN_bn2bin(bn, temp);
assert(len <= size);
for (n = 0, src = temp + len - 1; n < len; n++)
dest[n] = *src--;
for (; n < size; n++)
dest[n] = '\0';
}
/*
* Add a BIGNUM component, optionally padding out the number to size bytes
*/
static void
gpk_add_bignum(struct pkpart *part, unsigned int tag, BIGNUM *bn, size_t size)
{
struct pkcomp *comp;
r = bn2cf(rsa->dmq1, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
*p++ = 0;
*p++ = 0;
*p++ = 0;
if (size == 0)
size = BN_num_bytes(bn);
memcpy(key, buf, p - buf);
*keysize = p - buf;
comp = &part->components[part->count++];
memset(comp, 0, sizeof(*comp));
comp->tag = tag;
comp->size = size + 1;
comp->data = malloc(size + 1);
/* Add the tag */
comp->data[0] = tag;
/* Add the BIGNUM */
gpk_bn2bin(bn, comp->data + 1, size);
/* printf("TAG 0x%02x, len=%u\n", tag, comp->size); */
return 0;
}
int
gpk_encode_rsa_key(RSA *rsa, struct pkdata *p, unsigned int usage)
static int cflex_encode_public_key(RSA *rsa, u8 *key, size_t *keysize, int key_num)
{
if (!rsa->n || !rsa->e) {
error("incomplete RSA public key");
return SC_ERROR_INVALID_ARGUMENTS;
}
u8 buf[512], *p = buf;
u8 bnbuf[256];
int base = 0;
int r;
switch (BN_num_bits(rsa->n)) {
case 512:
base = 32;
break;
case 768:
base = 48;
break;
case 1024:
base = 64;
break;
case 2048:
base = 128;
break;
}
if (base == 0) {
fprintf(stderr, "Key length invalid.\n");
return 2;
}
*p++ = (5 * base + 7) >> 8;
*p++ = (5 * base + 7) & 0xFF;
*p++ = key_num;
r = bn2cf(rsa->n, bnbuf);
if (r != 2*base) {
fprintf(stderr, "Invalid public key.\n");
return 2;
}
memcpy(p, bnbuf, 2*base);
p += 2*base;
/* Make sure the exponent is 0x10001 because that's
* the only exponent supported by GPK4000 and GPK8000 */
if (!BN_is_word(rsa->e, RSA_F4)) {
error("unsupported RSA exponent");
return SC_ERROR_INVALID_ARGUMENTS;
}
memset(p, 0, base);
p += base;
memset(p, 0, sizeof(*p));
p->algo = SC_ALGORITHM_RSA;
p->usage = usage;
p->bits = BN_num_bits(rsa->n);
p->bytes = BN_num_bytes(rsa->n);
memset(bnbuf, 0, 2*base);
memcpy(p, bnbuf, 2*base);
p += 2*base;
r = bn2cf(rsa->e, bnbuf);
memcpy(p, bnbuf, 4);
p += 4;
*p++ = 0;
*p++ = 0;
*p++ = 0;
/* Set up the list of public elements */
gpk_add_bignum(&p->public, 0x01, rsa->n, 0);
gpk_add_bignum(&p->public, 0x07, rsa->e, 0);
memcpy(key, buf, p - buf);
*keysize = p - buf;
/* Set up the list of private elements */
if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) {
/* No or incomplete CRT information */
if (!rsa->d) {
error("incomplete RSA private key");
return SC_ERROR_INVALID_ARGUMENTS;
}
gpk_add_bignum(&p->private, 0x04, rsa->d, 0);
} else if (5 * (p->bytes / 2) < 256) {
/* All CRT elements are stored in one record */
struct pkcomp *comp;
unsigned int K = p->bytes / 2;
u8 *crtbuf;
crtbuf = malloc(5 * K + 1);
crtbuf[0] = 0x05;
gpk_bn2bin(rsa->p, crtbuf + 1, K);
gpk_bn2bin(rsa->q, crtbuf + 1 + 1 * K, K);
gpk_bn2bin(rsa->iqmp, crtbuf + 1 + 2 * K, K);
gpk_bn2bin(rsa->dmp1, crtbuf + 1 + 3 * K, K);
gpk_bn2bin(rsa->dmq1, crtbuf + 1 + 4 * K, K);
comp = &p->private.components[p->private.count++];
comp->tag = 0x05;
comp->size = 5 * K + 1;
comp->data = crtbuf;
} else {
/* CRT elements stored in individual records.
* Make sure they're all fixed length even if they're
* shorter */
gpk_add_bignum(&p->private, 0x51, rsa->p, p->bytes/2);
gpk_add_bignum(&p->private, 0x52, rsa->q, p->bytes/2);
gpk_add_bignum(&p->private, 0x53, rsa->iqmp, p->bytes/2);
gpk_add_bignum(&p->private, 0x54, rsa->dmp1, p->bytes/2);
gpk_add_bignum(&p->private, 0x55, rsa->dmq1, p->bytes/2);
}
return 0;
}
/*
* Encode a DSA key.
* Confusingly, the GPK manual says that the GPK8000 can handle
* DSA with 512 as well as 1024 bits, but all byte sizes shown
* in the tables are 512 bits only...
*/
int
gpk_encode_dsa_key(DSA *dsa, struct pkdata *p, unsigned int usage)
{
if (!dsa->p || !dsa->q || !dsa->g || !dsa->pub_key || !dsa->priv_key) {
error("incomplete DSA public key");
return SC_ERROR_INVALID_ARGUMENTS;
}
memset(p, 0, sizeof(*p));
p->algo = SC_ALGORITHM_RSA;
p->usage = usage;
p->bits = BN_num_bits(dsa->p);
p->bytes = BN_num_bytes(dsa->p);
/* Make sure the key is either 512 or 1024 bits */
if (p->bytes <= 64) {
p->bits = 512;
p->bytes = 64;
} else if (p->bytes <= 128) {
p->bits = 1024;
p->bytes = 128;
} else {
error("incompatible DSA key size (%u bits)", p->bits);
return SC_ERROR_INVALID_ARGUMENTS;
}
/* Set up the list of public elements */
gpk_add_bignum(&p->public, 0x09, dsa->p, 0);
gpk_add_bignum(&p->public, 0x0a, dsa->q, 0);
gpk_add_bignum(&p->public, 0x0b, dsa->g, 0);
gpk_add_bignum(&p->public, 0x0c, dsa->pub_key, 0);
/* Set up the list of private elements */
gpk_add_bignum(&p->private, 0x0d, dsa->priv_key, 0);
return 0;
}
static int
gpk_store_pk(struct sc_profile *profile, struct sc_card *card,
struct sc_file *file, struct pkdata *p,
struct sc_acl_entry *key_acl)
{
int r;
/* Compute length of private/public key parts */
gpk_compute_publen(&p->public);
gpk_compute_privlen(&p->private);
if (card->ctx->debug)
printf("Storing pk: %u bits, pub %u bytes, priv %u bytes\n",
p->bits, p->bytes, p->private.size);
/* Strange, strange, strange... when I create the public part with
* the exact size of 8 + PK elements, the card refuses to store
* the last record even though there's enough room in the file.
* XXX: Check why */
file->size = p->public.size + 8 + p->private.size + 8;
r = gpk_pkfile_create(profile, card, file);
if (r < 0)
return r;
/* Put the system record */
r = gpk_pkfile_init_public(card, file, p->algo,
p->bits, p->usage, key_acl);
if (r < 0)
return r;
/* Put the public key elements */
r = gpk_pkfile_update_public(card, &p->public);
if (r < 0)
return r;
/* Create the private key part */
r = gpk_pkfile_init_private(card, file, p->private.size);
if (r < 0)
return r;
/* Now store the private key elements */
r = gpk_pkfile_update_private(profile, card, file, &p->private);
return r;
return 0;
}
/*
* Store a RSA key on the card
*/
static int gpk_store_rsa_key(struct sc_profile *profile, struct sc_card *card,
static int cflex_store_rsa_key(struct sc_profile *profile, struct sc_card *card,
struct sc_key_template *info, RSA *rsa)
{
struct pkdata data;
int r;
u8 prv[1024], pub[1024];
size_t prvsize, pubsize;
struct sc_file *tmpfile;
int r;
if ((r = gpk_encode_rsa_key(rsa, &data, info->pkcs15.priv.usage)) < 0)
r = cflex_encode_private_key(rsa, prv, &prvsize, 1);
if (r)
return -1;
r = cflex_encode_public_key(rsa, pub, &pubsize, 1);
if (r)
return -1;
info->file->size = prvsize;
printf("Updating RSA private key...\n");
r = sc_pkcs15init_update_file(profile, info->file, prv, prvsize);
if (r < 0)
return r;
return gpk_store_pk(profile, card, info->file, &data, info->key_acl);
sc_file_dup(&tmpfile, info->file);
sc_file_clear_acl_entries(tmpfile, SC_AC_OP_READ);
sc_file_add_acl_entry(tmpfile, SC_AC_OP_READ, SC_AC_NONE, SC_AC_KEY_REF_NONE);
tmpfile->path.len -= 2;
sc_append_path_id(&tmpfile->path, "\x10\x12", 2);
tmpfile->id = 0x1012;
tmpfile->size = pubsize;
printf("Updating RSA public key...\n");
r = sc_pkcs15init_update_file(profile, tmpfile, pub, pubsize);
sc_file_free(tmpfile);
if (r)
return r;
return 0;
}
#endif
void bind_cflex_operations(struct pkcs15_init_operations *ops)
{
ops->init_app = cflex_init_app;
ops->allocate_file = cflex_allocate_file;
// ops->store_rsa = gpk_store_rsa_key;
ops->store_rsa = cflex_store_rsa_key;
}

View File

@ -558,6 +558,8 @@ sc_pkcs15init_add_app(struct sc_card *card, struct sc_profile *profile)
app->aid_len = p15card->file_app->namelen;
memcpy(app->aid, p15card->file_app->name, app->aid_len);
}
if (p15card->label)
app->label = strdup(p15card->label);
/* XXX: encode the DDO? */
r = sc_pkcs15init_update_dir(card, profile, app);
@ -574,7 +576,7 @@ sc_pkcs15init_add_app(struct sc_card *card, struct sc_profile *profile)
return 1;
}
printf("Successfully created PKCS15 meta structure\n");
printf("Successfully created PKCS #15 meta structure\n");
return 0;
}
@ -1184,7 +1186,7 @@ sc_pkcs15init_update_df(struct sc_pkcs15_card *p15card,
unsigned int df_type)
{
struct sc_pkcs15_df *df;
struct sc_file *file;
struct sc_file *file = NULL;
u8 *buf = NULL;
size_t bufsize;
unsigned int j;
@ -1204,11 +1206,16 @@ sc_pkcs15init_update_df(struct sc_pkcs15_card *p15card,
}
for (j = 0; r >= 0 && j < df->count; j++) {
struct file_info *info;
file = df->file[j];
info = sc_profile_find_file_by_path(profile, &file->path);
if (info != NULL)
file = info->file;
r = sc_pkcs15_encode_df(card->ctx, df, j, &buf, &bufsize);
if (r >= 0) {
r = sc_pkcs15init_update_file(profile,
df->file[j],
buf, bufsize);
file, buf, bufsize);
free(buf);
}
}
@ -1281,10 +1288,10 @@ read_one_pin(struct pin_info *info, unsigned int n)
static int
do_read_pins(struct sc_profile *pro)
{
static char *types[2] = { "CHV1", "CHV2" };
static char *types[3] = { "CHV1", "CHV2", "CHV3" };
int n, r;
for (n = 0; n < 2; n++) {
for (n = 0; n < 3; n++) {
struct pin_info *info;
struct sc_file *file;
int i, npins = 2;
@ -1296,7 +1303,7 @@ do_read_pins(struct sc_profile *pro)
file = info->file->file;
ctx->log_errors = 0;
if (!sc_select_file(card, &file->path, NULL)) {
printf("PIN file for %s already exists.", info->ident);
printf("PIN file for %s already exists.\n", info->ident);
npins = 1;
}
ctx->log_errors = 1;
@ -1322,6 +1329,7 @@ do_verify_pin(struct sc_profile *pro, unsigned int type, unsigned int reference)
struct pin_info *info;
char *pin;
int r;
u8 pinbuf[32];
ident = "authentication data";
if (type == SC_AC_CHV)
@ -1357,8 +1365,13 @@ do_verify_pin(struct sc_profile *pro, unsigned int type, unsigned int reference)
return r;
pin = info->secret[0];
assert(pro->pin_maxlen < sizeof(pinbuf));
memset(pinbuf, pro->pin_pad_char, pro->pin_maxlen);
/* FIXME: shouldn't assume that encoding is ascii-numeric */
strncpy(pinbuf, pin, strlen(pin));
return sc_verify(card, SC_AC_CHV, reference,
(u8 *) pin, strlen(pin), NULL);
pinbuf, pro->pin_maxlen, NULL);
no_secret:
/* No secret found that we could present.
@ -1390,6 +1403,7 @@ do_select_parent(struct sc_profile *pro, struct sc_file *file,
struct sc_file **parent)
{
struct sc_path path;
struct file_info *info = NULL;
int r;
/* Get the parent's path */
@ -1399,18 +1413,22 @@ do_select_parent(struct sc_profile *pro, struct sc_file *file,
if (path.len == 0)
sc_format_path("3F00", &path);
/* Select the parent DF. */
r = sc_select_file(card, &path, parent);
info = sc_profile_find_file_by_path(pro, &path);
ctx->log_errors = 0;
if (info != NULL) {
sc_file_dup(parent, info->file);
r = sc_select_file(card, &path, NULL);
} else {
/* Select the parent DF. */
r = sc_select_file(card, &path, parent);
}
ctx->log_errors = 1;
/* If DF doesn't exist, create it (unless it's the MF,
* but then something's badly broken anyway :-) */
if (r == SC_ERROR_FILE_NOT_FOUND && path.len != 2) {
struct file_info *info;
info = sc_profile_find_file_by_path(pro, &path);
if (info != NULL
&& (r = sc_pkcs15init_create_file(pro, info->file)) == 0)
r = sc_select_file(card, &path, parent);
r = sc_select_file(card, &path, NULL);
}
return r;
}
@ -1439,7 +1457,9 @@ sc_pkcs15init_update_file(struct sc_profile *profile,
{
int r;
if ((r = sc_select_file(card, &file->path, &file)) < 0) {
ctx->log_errors = 0;
if ((r = sc_select_file(card, &file->path, NULL)) < 0) {
ctx->log_errors = 1;
/* Create file if it doesn't exist */
if (file->size < datalen)
file->size = datalen;
@ -1448,6 +1468,7 @@ sc_pkcs15init_update_file(struct sc_profile *profile,
|| (r = sc_select_file(card, &file->path, NULL)) < 0)
return r;
}
ctx->log_errors = 1;
/* Present authentication info needed */
r = sc_pkcs15init_authenticate(profile, file, SC_AC_OP_UPDATE);

View File

@ -94,6 +94,7 @@ static struct map fileOpNames[] = {
{ "UPDATE", SC_AC_OP_UPDATE },
{ "WRITE", SC_AC_OP_WRITE },
{ "ERASE", SC_AC_OP_ERASE },
{ "CRYPTO", SC_AC_OP_CRYPTO },
{ 0, 0 }
};
static struct map efTypeNames[] = {
@ -372,6 +373,9 @@ sc_profile_finish(struct sc_profile *pro)
res = 1;
}
pi->pkcs15.path = pi->file->file->path;
/* Use only the parent DF path. */
if (pi->pkcs15.path.len > 2)
pi->pkcs15.path.len -= 2;
}
/* Loop over all files and fix up their security references */
@ -565,6 +569,18 @@ do_mf(int argc, char **argv)
return 0;
}
static void
find_parent(struct file_info *fi)
{
struct sc_path path = fi->file->path;
fi->parent = NULL;
if (path.len > 2) {
path.len -= 2;
fi->parent = sc_profile_find_file_by_path(parser.profile, &path);
}
}
static int
do_df(int argc, char **argv)
{
@ -582,6 +598,7 @@ do_df(int argc, char **argv)
cur_file->next = parser.profile->ef_list;
parser.profile->ef_list = cur_file;
}
find_parent(cur_file);
cur_parent = NULL;
return 0;
}
@ -635,6 +652,7 @@ do_ef(int argc, char **argv)
info->next = parser.profile->ef_list;
parser.profile->ef_list = info;
find_parent(info);
out: cur_file = info;
cur_parent = NULL;

View File

@ -31,6 +31,7 @@ struct file_info {
char * ident;
struct file_info * next;
struct sc_file * file;
struct file_info * parent;
/* PKCS15 book-keeping info */
/*