- 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:
parent
2c7a0ac27b
commit
23e956cf9b
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)" },
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue