diff --git a/src/pkcs15init/etoken.profile b/src/pkcs15init/etoken.profile index 7709cd98..ea6a2874 100644 --- a/src/pkcs15init/etoken.profile +++ b/src/pkcs15init/etoken.profile @@ -28,19 +28,19 @@ filesystem { type = internal-ef; file-id = 4B01; # This is the base FileID size = 266; # 266 is enough for 1024-bit keys - ACL = *=NEVER, UPDATE=$PIN; + ACL = *=NEVER, UPDATE=$PIN, ERASE=$PIN; } EF template-public-key { file-id = 5501; - ACL = *=NEVER, READ=NONE, UPDATE=$PIN; + ACL = *=NEVER, READ=NONE, UPDATE=$PIN, ERASE=$PIN; } EF template-certificate { file-id = 4301; - ACL = *=NEVER, READ=NONE, UPDATE=$PIN; + ACL = *=NEVER, READ=NONE, UPDATE=$PIN, ERASE=$PIN; } EF template-extractable-key { file-id = 7000; - ACL = *=NEVER, READ=$PIN, UPDATE=$PIN; + ACL = *=NEVER, READ=$PIN, UPDATE=$PIN, ERASE=$PIN; } EF tempfile { file-id = 7EAD; diff --git a/src/pkcs15init/pkcs15-etoken.c b/src/pkcs15init/pkcs15-etoken.c index 36b42c90..b49e5873 100644 --- a/src/pkcs15init/pkcs15-etoken.c +++ b/src/pkcs15init/pkcs15-etoken.c @@ -70,10 +70,11 @@ static void error(struct sc_profile *, const char *, ...); #define ETOKEN_SE_ID(idx) (0x40 + (idx)) #define ETOKEN_AC_NEVER 0xFF -#define ETOKEN_ALGO_RSA_SIG_SHA1 0xCC -#define ETOKEN_ALGO_RSA_SIG 0x88 -#define ETOKEN_ALGO_RSA ETOKEN_ALGO_RSA_SIG -#define ETOKEN_ALGO_PIN 0x87 +#define ETOKEN_ALGO_RSA_SIG_SHA1 0xCC +#define ETOKEN_ALGO_RSA_SIG 0x88 +#define ETOKEN_ALGO_RSA_PURE_SIG 0x8C +#define ETOKEN_ALGO_RSA ETOKEN_ALGO_RSA_PURE_SIG +#define ETOKEN_ALGO_PIN 0x87 static inline void tlv_init(struct tlv *tlv, u8 *base, size_t size) @@ -457,7 +458,14 @@ etoken_store_key_component(struct sc_card *card, tlv_next(&tlv, 0x86); tlv_add(&tlv, pin_id); /* AC USE */ tlv_add(&tlv, pin_id); /* AC CHANGE */ - tlv_add(&tlv, pin_id); /* AC GENKEY? */ + tlv_add(&tlv, pin_id); /* UNKNOWN */ + /* The next 4 AC bytes are sent by the eToken run-time + * as well, but aren't documented anywhere. + * Key generation won't work without them, however. */ + tlv_add(&tlv, 0); + tlv_add(&tlv, 0); + tlv_add(&tlv, 0); + tlv_add(&tlv, 0); /* SM bytes */ tlv_next(&tlv, 0x8B); @@ -470,6 +478,7 @@ etoken_store_key_component(struct sc_card *card, tlv_add(&tlv, 0); while (len--) tlv_add(&tlv, *data++); + //tlv_add(&tlv, data[len]); args.data = buffer; args.len = tlv_len(&tlv); @@ -601,17 +610,45 @@ etoken_new_file(struct sc_profile *profile, struct sc_card *card, return 0; } +/* + * Extract a key component from the public key file populated by + * GENERATE KEY PAIR + */ +static int +etoken_extract_pubkey(struct sc_card *card, int nr, u8 tag, + sc_pkcs15_bignum_t *bn) +{ + u8 buf[256]; + int r, count; + + r = sc_read_record(card, nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR); + if (r < 0) + return r; + count = r - 4; + if (count <= 0 || buf[0] != tag || buf[1] != count + 2 + || buf[2] != count + 1 || buf[3] != 0) + return SC_ERROR_INTERNAL; + bn->len = count; + bn->data = malloc(count); + memcpy(bn->data, buf + 4, count); + return 0; +} + +/* + * Key generation + */ static int etoken_generate_key(struct sc_profile *profile, struct sc_card *card, unsigned int index, unsigned int keybits, - sc_pkcs15_pubkey_t *pubkey) + sc_pkcs15_pubkey_t *pubkey, + struct sc_pkcs15_prkey_info *info) { struct sc_pkcs15_prkey_rsa key_obj; struct sc_cardctl_etoken_genkey_info args; struct sc_file *temp; u8 abignum[RSAKEY_MAX_SIZE]; u8 randbuf[64], key_id; - int r; + int r, delete_it = 0; keybits &= ~7UL; if (keybits > RSAKEY_MAX_BITS) { @@ -625,8 +662,11 @@ etoken_generate_key(struct sc_profile *profile, struct sc_card *card, "for key generation.\n"); return SC_ERROR_NOT_SUPPORTED; } + memset(pubkey, 0, sizeof(*pubkey)); + if ((r = sc_pkcs15init_create_file(profile, card, temp)) < 0) goto out; + delete_it = 1; key_id = ETOKEN_KEY_ID(index); @@ -663,9 +703,29 @@ etoken_generate_key(struct sc_profile *profile, struct sc_card *card, if (r < 0) goto out; - /* XXX: extract public key from file and delete it */ + /* extract public key from file and delete it */ + if ((r = sc_select_file(card, &temp->path, NULL)) < 0) + goto out; + r = etoken_extract_pubkey(card, 1, 0x10, &pubkey->u.rsa.modulus); + if (r < 0) + goto out; + r = etoken_extract_pubkey(card, 2, 0x11, &pubkey->u.rsa.exponent); + if (r < 0) + goto out; + pubkey->algorithm = SC_ALGORITHM_RSA; + info->key_reference = key_id; + info->path = profile->df_info->file->path; -out: sc_file_free(temp); +out: if (delete_it) { + etoken_rm_rf(profile, card, temp); + } + sc_file_free(temp); + if (r < 0) { + if (pubkey->u.rsa.modulus.data) + free (pubkey->u.rsa.modulus.data); + if (pubkey->u.rsa.exponent.data) + free (pubkey->u.rsa.exponent.data); + } return r; } diff --git a/src/pkcs15init/pkcs15-init.h b/src/pkcs15init/pkcs15-init.h index 40b65e51..13f88733 100644 --- a/src/pkcs15init/pkcs15-init.h +++ b/src/pkcs15init/pkcs15-init.h @@ -60,7 +60,8 @@ struct sc_pkcs15init_operations { */ int (*generate_key)(struct sc_profile *, struct sc_card *, unsigned int index, unsigned int keybits, - sc_pkcs15_pubkey_t *pubkey_res); + sc_pkcs15_pubkey_t *pubkey_res, + struct sc_pkcs15_prkey_info *); }; diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index cd6b35b1..7abac0bb 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -79,14 +79,17 @@ static int sc_pkcs15init_add_object(struct sc_pkcs15_card *, static int sc_pkcs15init_map_usage(unsigned long, int); static int set_so_pin_from_card(struct sc_pkcs15_card *, struct sc_profile *); +static int set_user_pin_from_authid(struct sc_pkcs15_card *, + struct sc_profile *, struct sc_pkcs15_id *); static int do_select_parent(struct sc_profile *, struct sc_card *, struct sc_file *, struct sc_file **); static int aodf_add_pin(struct sc_pkcs15_card *, struct sc_profile *, const struct sc_pkcs15_pin_info *, const char *); static int check_key_compatibility(struct sc_pkcs15_card *, struct sc_pkcs15_prkey *, unsigned int, unsigned int); -static int fixup_rsa_key(struct sc_pkcs15_prkey_rsa *); -static int fixup_dsa_key(struct sc_pkcs15_prkey_dsa *); +static int prkey_fixup(sc_pkcs15_prkey_t *); +static int prkey_bits(sc_pkcs15_prkey_t *); +static int prkey_pkcs15_algo(sc_pkcs15_prkey_t *); static struct sc_pkcs15_df * find_df_by_type(struct sc_pkcs15_card *, int); static void default_error_handler(const char *fmt, ...); static void default_debug_handler(const char *fmt, ...); @@ -363,6 +366,53 @@ aodf_add_pin(struct sc_pkcs15_card *p15card, struct sc_profile *profile, SC_PKCS15_AODF, object); } +/* + * Prepare private key download, and initialize a prkdf entry + */ +static int +sc_pkcs15init_init_prkdf(struct sc_pkcs15init_prkeyargs *keyargs, + sc_pkcs15_prkey_t *key, int keybits, + struct sc_pkcs15_object **res_obj + ) +{ + struct sc_pkcs15_prkey_info *key_info; + struct sc_pkcs15_object *object; + const char *label; + unsigned int usage; + int r = 0; + + if (!keybits && (keybits = prkey_bits(key)) < 0) + return r; + + if (keyargs->id.len == 0) + sc_pkcs15_format_id(DEFAULT_ID, &keyargs->id); + if ((usage = keyargs->usage) == 0) { + usage = SC_PKCS15_PRKEY_USAGE_SIGN; + if (keyargs->x509_usage) + usage = sc_pkcs15init_map_usage(keyargs->x509_usage, 1); + } + if ((label = keyargs->label) == NULL) + label = "Private Key"; + + key_info = (struct sc_pkcs15_prkey_info *) calloc(1, sizeof(*key_info)); + key_info->id = keyargs->id; + key_info->usage = usage; + key_info->native = 1; + key_info->key_reference = 0; + key_info->modulus_length = keybits; + /* path set by card driver */ + + object = (struct sc_pkcs15_object *) calloc(1, sizeof(*object)); + object->type = prkey_pkcs15_algo(key); + object->data = key_info; + object->flags = DEFAULT_PRKEY_FLAGS; + object->auth_id = keyargs->auth_id; + strncpy(object->label, label, sizeof(object->label)); + + *res_obj = object; + return r; +} + /* * Generate a new private key */ @@ -374,6 +424,8 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object **res_obj) { struct sc_pkcs15init_pubkeyargs pubkey_args; + struct sc_pkcs15_object *object; + struct sc_pkcs15_prkey_info *key_info; int r, index; /* For now, we support just RSA key pair generation */ @@ -384,29 +436,48 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, if (profile->ops->generate_key == NULL) return SC_ERROR_NOT_SUPPORTED; - if (keyargs->auth_id.len != 0) { - struct sc_pkcs15_pin_info *pin_info; - struct sc_pkcs15_object *objp; - - r = sc_pkcs15_find_pin_by_auth_id(p15card, - &keyargs->auth_id, &objp); - if (r < 0) - return r; - pin_info = (struct sc_pkcs15_pin_info *) objp->data; - sc_profile_set_pin_info(profile, - SC_PKCS15INIT_USER_PIN, pin_info); - } - - memset(&pubkey_args, 0, sizeof(pubkey_args)); - - index = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, NULL, 0); - r = profile->ops->generate_key(profile, p15card->card, index, keybits, - &pubkey_args.key); + /* Set the USER PIN reference from args */ + r = set_user_pin_from_authid(p15card, profile, &keyargs->auth_id); if (r < 0) return r; - /* XXX: add PrKDF entrye and write public key */ - return SC_ERROR_INTERNAL; + /* Set the SO PIN reference from card */ + if ((r = set_so_pin_from_card(p15card, profile)) < 0) + return r; + + /* Set up the PrKDF object */ + if ((r = sc_pkcs15init_init_prkdf(keyargs, &keyargs->key, keybits, &object)) < 0) + return r; + key_info = (struct sc_pkcs15_prkey_info *) object->data; + + /* Set up the PuKDF info. The public key will be filled in + * by the card driver's generate_key function called below */ + memset(&pubkey_args, 0, sizeof(pubkey_args)); + pubkey_args.id = keyargs->id; + pubkey_args.label = keyargs->label; + pubkey_args.usage = keyargs->usage; + pubkey_args.x509_usage = keyargs->x509_usage; + + /* Generate the private key on card */ + index = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, NULL, 0); + r = profile->ops->generate_key(profile, p15card->card, index, keybits, + &pubkey_args.key, key_info); + + /* update PrKDF entry */ + if (r >= 0) { + r = sc_pkcs15init_add_object(p15card, profile, + SC_PKCS15_PRKDF, object); + } + if (r >= 0) { + r = sc_pkcs15init_store_public_key(p15card, profile, + &pubkey_args, NULL); + } + + if (r >= 0 && res_obj) + *res_obj = object; + sc_pkcs15_erase_pubkey(&pubkey_args.key); + + return r; } @@ -419,56 +490,18 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card, struct sc_pkcs15init_prkeyargs *keyargs, struct sc_pkcs15_object **res_obj) { - struct sc_pkcs15_pin_info *pin_info = NULL; struct sc_pkcs15_object *object; struct sc_pkcs15_prkey_info *key_info; sc_pkcs15_prkey_t key; - const char *label; - unsigned int keybits, type, index, usage; - int r = 0; + int keybits, index, r = 0; /* Create a copy of the key first */ key = keyargs->key; - switch (key.algorithm) { - case SC_ALGORITHM_RSA: - keybits = sc_pkcs15init_keybits(&key.u.rsa.modulus); - type = SC_PKCS15_TYPE_PRKEY_RSA; - r = fixup_rsa_key(&key.u.rsa); - break; -#ifdef SC_PKCS15_TYPE_PRKEY_DSA - case SC_ALGORITHM_DSA: - keybits = sc_pkcs15init_keybits(&key.u.dsa.q); - type = SC_PKCS15_TYPE_PRKEY_DSA; - r = fixup_dsa_key(&key.u.dsa); - break; -#endif - default: - p15init_error("Unsupported key algorithm.\n"); - return SC_ERROR_NOT_SUPPORTED; - } - - if (keyargs->auth_id.len != 0) { - struct sc_pkcs15_object *objp; - - r = sc_pkcs15_find_pin_by_auth_id(p15card, - &keyargs->auth_id, &objp); - if (r < 0) - return r; - pin_info = (struct sc_pkcs15_pin_info *) objp->data; - sc_profile_set_pin_info(profile, - SC_PKCS15INIT_USER_PIN, pin_info); - } - - if (keyargs->id.len == 0) - sc_pkcs15_format_id(DEFAULT_ID, &keyargs->id); - if ((usage = keyargs->usage) == 0) { - usage = SC_PKCS15_PRKEY_USAGE_SIGN; - if (keyargs->x509_usage) - usage = sc_pkcs15init_map_usage(keyargs->x509_usage, 1); - } - if ((label = keyargs->label) == NULL) - label = "Private Key"; + if ((r = prkey_fixup(&key)) < 0) + return r; + if ((keybits = prkey_bits(&key)) < 0) + return r; /* Now check whether the card is able to handle this key */ if (!check_key_compatibility(p15card, &key, keybits, 0)) { @@ -485,25 +518,21 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card, } } - key_info = (struct sc_pkcs15_prkey_info *) calloc(1, sizeof(*key_info)); - key_info->id = keyargs->id; - key_info->usage = usage; - key_info->native = 1; - key_info->key_reference = 0; - key_info->modulus_length = keybits; - /* path set by card driver */ - - object = (struct sc_pkcs15_object *) calloc(1, sizeof(*object)); - object->type = type; - object->data = key_info; - object->flags = DEFAULT_PRKEY_FLAGS; - object->auth_id = keyargs->auth_id; - strncpy(object->label, label, sizeof(object->label)); + /* Set the USER PIN reference from args */ + r = set_user_pin_from_authid(p15card, profile, &keyargs->auth_id); + if (r < 0) + return r; /* Set the SO PIN reference from card */ if ((r = set_so_pin_from_card(p15card, profile)) < 0) return r; + /* Set up the PrKDF object */ + r = sc_pkcs15init_init_prkdf(keyargs, &key, 0, &object); + if (r < 0) + return r; + key_info = (struct sc_pkcs15_prkey_info *) object->data; + /* Get the number of private keys already on this card */ index = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, NULL, 0); if (!keyargs->extractable) { @@ -627,7 +656,8 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, type, &der_encoded, &key_info->path); /* Update the PuKDF */ - r = sc_pkcs15init_add_object(p15card, profile, + if (r >= 0) + r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_PUKDF, object); if (r >= 0 && res_obj) @@ -793,6 +823,8 @@ sc_pkcs15init_keybits(sc_pkcs15_bignum_t *bn) { unsigned int mask, bits; + if (!bn || !bn->len) + return 0; bits = bn->len << 3; for (mask = 0x80; !(bn->data[0] & mask); mask >>= 1) bits--; @@ -843,7 +875,7 @@ check_key_compatibility(struct sc_pkcs15_card *p15card, * CRT elements */ int -fixup_rsa_key(struct sc_pkcs15_prkey_rsa *key) +prkey_fixup_rsa(struct sc_pkcs15_prkey_rsa *key) { if (!key->modulus.len || !key->exponent.len || !key->d.len || !key->p.len || !key->q.len) { @@ -910,12 +942,44 @@ fixup_rsa_key(struct sc_pkcs15_prkey_rsa *key) } static int -fixup_dsa_key(struct sc_pkcs15_prkey_dsa *key) +prkey_fixup(sc_pkcs15_prkey_t *key) { - /* for now */ + switch (key->algorithm) { + case SC_ALGORITHM_RSA: + return prkey_fixup_rsa(&key->u.rsa); + case SC_ALGORITHM_DSA: + /* for now */ + return 0; + } return 0; } +static int +prkey_bits(sc_pkcs15_prkey_t *key) +{ + switch (key->algorithm) { + case SC_ALGORITHM_RSA: + return sc_pkcs15init_keybits(&key->u.rsa.modulus); + case SC_ALGORITHM_DSA: + return sc_pkcs15init_keybits(&key->u.dsa.q); + } + p15init_error("Unsupported key algorithm.\n"); + return SC_ERROR_NOT_SUPPORTED; +} + +static int +prkey_pkcs15_algo(sc_pkcs15_prkey_t *key) +{ + switch (key->algorithm) { + case SC_ALGORITHM_RSA: + return SC_PKCS15_TYPE_PRKEY_RSA; + case SC_ALGORITHM_DSA: + return SC_PKCS15_TYPE_PRKEY_DSA; + } + p15init_error("Unsupported key algorithm.\n"); + return SC_ERROR_NOT_SUPPORTED; +} + static struct sc_pkcs15_df * find_df_by_type(struct sc_pkcs15_card *p15card, int type) { @@ -1174,6 +1238,30 @@ set_so_pin_from_card(struct sc_pkcs15_card *p15card, struct sc_profile *profile) return 0; } +/* + * If the user specified an auth_id, select the corresponding + * PIN entry and set the reference data + */ +static int +set_user_pin_from_authid(struct sc_pkcs15_card *p15card, + struct sc_profile *profile, + struct sc_pkcs15_id *auth_id) +{ + struct sc_pkcs15_object *objp; + int r; + + if (auth_id->len == 0) + return 0; + + r = sc_pkcs15_find_pin_by_auth_id(p15card, auth_id, &objp); + if (r < 0) + return r; + + sc_profile_set_pin_info(profile, SC_PKCS15INIT_USER_PIN, + (struct sc_pkcs15_pin_info *) objp->data); + return 0; +} + /* * Present any authentication info as required by the file. * @@ -1338,9 +1426,19 @@ sc_pkcs15init_fixup_file(struct sc_profile *profile, struct sc_file *file) so_acl.key_ref = 0; } +#if 0 /* If we haven't got a user pin, barf */ user_acl.method = SC_AC_CHV; user_acl.key_ref = user_pin.reference; +#else + /* Not setting a user pin is legitimate. */ + user_acl.method = SC_AC_CHV; + user_acl.key_ref = user_pin.reference; + if (user_acl.key_ref == -1) { + user_acl.method = SC_AC_NONE; + user_acl.key_ref = 0; + } +#endif return sc_pkcs15init_fixup_acls(profile, file, &so_acl, &user_acl); }