pkcs15-init: 'erase-application', 'update-lastUpdate', ...

New operations:
- 'erase-application' -- erase on-card application indicated by it's AID;
- 'update-lastupdate' -- parse tokenInfo, set 'lastUpdate' value to the current date and write back tokenInfo content;
- 'ignore-ca-certificates' -- when importing PKCS#12 ignore all CA certificates;
This commit is contained in:
Viktor Tarasov 2012-06-01 15:54:17 +02:00
parent fbc9bb35dc
commit 525f61af73
1 changed files with 101 additions and 163 deletions

View File

@ -64,6 +64,7 @@
#include "libopensc/log.h" #include "libopensc/log.h"
#include "libopensc/cards.h" #include "libopensc/cards.h"
#include "pkcs15init/pkcs15-init.h" #include "pkcs15init/pkcs15-init.h"
#include "pkcs15init/profile.h"
#include "util.h" #include "util.h"
#undef GET_KEY_ECHO_OFF #undef GET_KEY_ECHO_OFF
@ -78,6 +79,7 @@ typedef int (*pkcs15_encoder)(sc_context_t *,
static int open_reader_and_card(char *); static int open_reader_and_card(char *);
static int do_assert_pristine(sc_card_t *); static int do_assert_pristine(sc_card_t *);
static int do_erase(sc_card_t *, struct sc_profile *); static int do_erase(sc_card_t *, struct sc_profile *);
static int do_erase_application(sc_card_t *, struct sc_profile *);
static int do_delete_objects(struct sc_profile *, unsigned int myopt_delete_flags); static int do_delete_objects(struct sc_profile *, unsigned int myopt_delete_flags);
static int do_change_attributes(struct sc_profile *, unsigned int myopt_type); static int do_change_attributes(struct sc_profile *, unsigned int myopt_type);
static int do_init_app(struct sc_profile *); static int do_init_app(struct sc_profile *);
@ -87,8 +89,6 @@ static int do_store_private_key(struct sc_profile *);
static int do_store_public_key(struct sc_profile *, EVP_PKEY *); static int do_store_public_key(struct sc_profile *, EVP_PKEY *);
static int do_store_certificate(struct sc_profile *); static int do_store_certificate(struct sc_profile *);
static int do_update_certificate(struct sc_profile *); static int do_update_certificate(struct sc_profile *);
static int do_convert_private_key(struct sc_pkcs15_prkey *, EVP_PKEY *);
static int do_convert_public_key(struct sc_pkcs15_pubkey *, EVP_PKEY *);
static int do_convert_cert(sc_pkcs15_der_t *, X509 *); static int do_convert_cert(sc_pkcs15_der_t *, X509 *);
static int is_cacert_already_present(struct sc_pkcs15init_certargs *); static int is_cacert_already_present(struct sc_pkcs15init_certargs *);
static int do_finalize_card(sc_card_t *, struct sc_profile *); static int do_finalize_card(sc_card_t *, struct sc_profile *);
@ -107,10 +107,10 @@ static int get_key_callback(struct sc_profile *,
int method, int reference, int method, int reference,
const u8 *, size_t, u8 *, size_t *); const u8 *, size_t, u8 *, size_t *);
static int do_read_private_key(const char *, const char *, static int do_read_private_key(const char *, const char *, EVP_PKEY **, X509 **, unsigned int);
EVP_PKEY **, X509 **, unsigned int);
static int do_read_public_key(const char *, const char *, EVP_PKEY **); static int do_read_public_key(const char *, const char *, EVP_PKEY **);
static int do_read_certificate(const char *, const char *, X509 **); static int do_read_certificate(const char *, const char *, X509 **);
static char * cert_common_name(X509 *x509);
static void parse_commandline(int argc, char **argv); static void parse_commandline(int argc, char **argv);
static void read_options_file(const char *); static void read_options_file(const char *);
static void ossl_print_errors(void); static void ossl_print_errors(void);
@ -134,6 +134,9 @@ enum {
OPT_VERIFY_PIN, OPT_VERIFY_PIN,
OPT_SANITY_CHECK, OPT_SANITY_CHECK,
OPT_BIND_TO_AID, OPT_BIND_TO_AID,
OPT_UPDATE_LAST_UPDATE,
OPT_ERASE_APPLICATION,
OPT_IGNORE_CA_CERTIFICATES,
OPT_PIN1 = 0x10000, /* don't touch these values */ OPT_PIN1 = 0x10000, /* don't touch these values */
OPT_PUK1 = 0x10001, OPT_PUK1 = 0x10001,
@ -157,6 +160,7 @@ const struct option options[] = {
{ "delete-objects", required_argument, NULL, 'D' }, { "delete-objects", required_argument, NULL, 'D' },
{ "change-attributes", required_argument, NULL, 'A' }, { "change-attributes", required_argument, NULL, 'A' },
{ "sanity-check", no_argument, NULL, OPT_SANITY_CHECK}, { "sanity-check", no_argument, NULL, OPT_SANITY_CHECK},
{ "erase-application", required_argument, NULL, OPT_ERASE_APPLICATION},
{ "reader", required_argument, NULL, 'r' }, { "reader", required_argument, NULL, 'r' },
{ "pin", required_argument, NULL, OPT_PIN1 }, { "pin", required_argument, NULL, OPT_PIN1 },
@ -181,7 +185,9 @@ const struct option options[] = {
{ "passphrase", required_argument, NULL, OPT_PASSPHRASE }, { "passphrase", required_argument, NULL, OPT_PASSPHRASE },
{ "authority", no_argument, NULL, OPT_AUTHORITY }, { "authority", no_argument, NULL, OPT_AUTHORITY },
{ "key-usage", required_argument, NULL, 'u' }, { "key-usage", required_argument, NULL, 'u' },
{ "finalize", no_argument, NULL, 'F' }, { "finalize", no_argument, NULL, 'F' },
{ "update-last-update", no_argument, NULL, OPT_UPDATE_LAST_UPDATE},
{ "ignore-ca-certificates",no_argument, NULL, OPT_IGNORE_CA_CERTIFICATES},
{ "extractable", no_argument, NULL, OPT_EXTRACTABLE }, { "extractable", no_argument, NULL, OPT_EXTRACTABLE },
{ "insecure", no_argument, NULL, OPT_INSECURE }, { "insecure", no_argument, NULL, OPT_INSECURE },
@ -214,6 +220,7 @@ static const char * option_help[] = {
"Delete object(s) (use \"help\" for more information)", "Delete object(s) (use \"help\" for more information)",
"Change attribute(s) (use \"help\" for more information)", "Change attribute(s) (use \"help\" for more information)",
"Card specific sanity check and possibly update procedure", "Card specific sanity check and possibly update procedure",
"Erase application with AID <arg>",
"Specify which reader to use", "Specify which reader to use",
"Specify PIN", "Specify PIN",
@ -239,6 +246,8 @@ static const char * option_help[] = {
"Mark certificate as a CA certificate", "Mark certificate as a CA certificate",
"Specify X.509 key usage (use \"--key-usage help\" for more information)", "Specify X.509 key usage (use \"--key-usage help\" for more information)",
"Finish initialization phase of the smart card", "Finish initialization phase of the smart card",
"Update 'lastUpdate' attribut of tokenInfo",
"When storing PKCS#12 ignore CA certificates",
"Private key stored as an extractable key", "Private key stored as an extractable key",
"Insecure mode: do not require a PIN for private key", "Insecure mode: do not require a PIN for private key",
@ -272,6 +281,8 @@ enum {
ACTION_DELETE_OBJECTS, ACTION_DELETE_OBJECTS,
ACTION_CHANGE_ATTRIBUTES, ACTION_CHANGE_ATTRIBUTES,
ACTION_SANITY_CHECK, ACTION_SANITY_CHECK,
ACTION_UPDATE_LAST_UPDATE,
ACTION_ERASE_APPLICATION,
ACTION_MAX ACTION_MAX
}; };
@ -348,6 +359,7 @@ static unsigned int opt_type = 0;
static int ignore_cmdline_pins = 0; static int ignore_cmdline_pins = 0;
static struct secret opt_secrets[MAX_SECRETS]; static struct secret opt_secrets[MAX_SECRETS];
static unsigned int opt_secret_count; static unsigned int opt_secret_count;
static int opt_ignore_ca_certs = 0;
static int verbose = 0; static int verbose = 0;
static struct sc_pkcs15init_callbacks callbacks = { static struct sc_pkcs15init_callbacks callbacks = {
@ -437,7 +449,8 @@ main(int argc, char **argv)
sc_pkcs15init_set_callbacks(&callbacks); sc_pkcs15init_set_callbacks(&callbacks);
/* Bind the card-specific operations and load the profile */ /* Bind the card-specific operations and load the profile */
if ((r = sc_pkcs15init_bind(card, opt_profile, opt_card_profile, NULL, &profile)) < 0) { r = sc_pkcs15init_bind(card, opt_profile, opt_card_profile, NULL, &profile);
if (r < 0) {
printf("Couldn't bind to the card: %s\n", sc_strerror(r)); printf("Couldn't bind to the card: %s\n", sc_strerror(r));
return 1; return 1;
} }
@ -544,6 +557,12 @@ main(int argc, char **argv)
case ACTION_SANITY_CHECK: case ACTION_SANITY_CHECK:
r = do_sanity_check(profile); r = do_sanity_check(profile);
break; break;
case ACTION_UPDATE_LAST_UPDATE:
profile->dirty = 1;
break;
case ACTION_ERASE_APPLICATION:
r = do_erase_application(card, profile);
break;
default: default:
util_fatal("Action not yet implemented\n"); util_fatal("Action not yet implemented\n");
} }
@ -670,6 +689,17 @@ do_erase(sc_card_t *in_card, struct sc_profile *profile)
return r; return r;
} }
static int
do_erase_application(sc_card_t *in_card, struct sc_profile *profile)
{
int r;
ignore_cmdline_pins--;
r = do_erase(in_card, profile);
ignore_cmdline_pins++;
return r;
}
static int do_finalize_card(sc_card_t *in_card, struct sc_profile *profile) static int do_finalize_card(sc_card_t *in_card, struct sc_profile *profile)
{ {
return sc_pkcs15init_finalize_card(in_card, profile); return sc_pkcs15init_finalize_card(in_card, profile);
@ -845,15 +875,14 @@ do_store_private_key(struct sc_profile *profile)
if (ncerts) { if (ncerts) {
char namebuf[256]; char namebuf[256];
printf("Importing %d certificates:\n", ncerts); printf("Importing %d certificates:\n", opt_ignore_ca_certs ? 1 : ncerts);
for (i = 0; i < ncerts; i++) { for (i = 0; i < ncerts && !(i && opt_ignore_ca_certs); i++)
printf(" %d: %s\n", printf(" %d: %s\n", i, X509_NAME_oneline(cert[i]->cert_info->subject,
i, X509_NAME_oneline(cert[i]->cert_info->subject,
namebuf, sizeof(namebuf))); namebuf, sizeof(namebuf)));
}
} }
if ((r = do_convert_private_key(&args.key, pkey)) < 0) r = sc_pkcs15_convert_prkey(&args.key, pkey);
if (r < 0)
return r; return r;
init_gost_params(&args.params.gost, pkey); init_gost_params(&args.params.gost, pkey);
@ -902,6 +931,9 @@ do_store_private_key(struct sc_profile *profile)
struct sc_pkcs15init_certargs cargs; struct sc_pkcs15init_certargs cargs;
char namebuf[SC_PKCS15_MAX_LABEL_SIZE-1]; char namebuf[SC_PKCS15_MAX_LABEL_SIZE-1];
if (i && opt_ignore_ca_certs)
break;
memset(&cargs, 0, sizeof(cargs)); memset(&cargs, 0, sizeof(cargs));
/* Encode the cert */ /* Encode the cert */
@ -910,8 +942,9 @@ do_store_private_key(struct sc_profile *profile)
X509_check_purpose(cert[i], -1, -1); X509_check_purpose(cert[i], -1, -1);
cargs.x509_usage = cert[i]->ex_kusage; cargs.x509_usage = cert[i]->ex_kusage;
cargs.label = X509_NAME_oneline(cert[i]->cert_info->subject, cargs.label = cert_common_name(cert[i]);
namebuf, sizeof(namebuf)); if (!cargs.label)
cargs.label = X509_NAME_oneline(cert[i]->cert_info->subject, namebuf, sizeof(namebuf));
/* Just the first certificate gets the same ID /* Just the first certificate gets the same ID
* as the private key. All others get * as the private key. All others get
@ -922,23 +955,20 @@ do_store_private_key(struct sc_profile *profile)
cargs.label = opt_cert_label; cargs.label = opt_cert_label;
} else { } else {
if (is_cacert_already_present(&cargs)) { if (is_cacert_already_present(&cargs)) {
printf("Certificate #%d already present, " printf("Certificate #%d already present, not stored.\n", i);
"not stored.\n", i);
goto next_cert; goto next_cert;
} }
cargs.authority = 1; cargs.authority = 1;
} }
r = sc_pkcs15init_store_certificate(p15card, profile, r = sc_pkcs15init_store_certificate(p15card, profile, &cargs, NULL);
&cargs, NULL);
next_cert: next_cert:
free(cargs.der_encoded.value); free(cargs.der_encoded.value);
} }
/* No certificates - store the public key */ /* No certificates - store the public key */
if (ncerts == 0) { if (ncerts == 0)
r = do_store_public_key(profile, pkey); r = do_store_public_key(profile, pkey);
}
return r; return r;
} }
@ -1006,7 +1036,7 @@ do_store_public_key(struct sc_profile *profile, EVP_PKEY *pkey)
if (pkey == NULL) if (pkey == NULL)
r = do_read_public_key(opt_infile, opt_format, &pkey); r = do_read_public_key(opt_infile, opt_format, &pkey);
if (r >= 0) { if (r >= 0) {
r = do_convert_public_key(&args.key, pkey); r = sc_pkcs15_convert_pubkey(&args.key, pkey);
if (r >= 0) if (r >= 0)
init_gost_params(&args.params.gost, pkey); init_gost_params(&args.params.gost, pkey);
} }
@ -2099,7 +2129,8 @@ do_read_certificate(const char *name, const char *format, X509 **out)
return 0; return 0;
} }
static int determine_filesize(const char *filename) { static int determine_filesize(const char *filename)
{
FILE *fp; FILE *fp;
size_t size; size_t size;
@ -2110,7 +2141,7 @@ static int determine_filesize(const char *filename) {
size = ftell(fp); size = ftell(fp);
fclose(fp); fclose(fp);
return size; return size;
} }
static int static int
do_read_data_object(const char *name, u8 **out, size_t *outlen) do_read_data_object(const char *name, u8 **out, size_t *outlen)
@ -2120,9 +2151,9 @@ do_read_data_object(const char *name, u8 **out, size_t *outlen)
int c; int c;
*out = malloc(filesize); *out = malloc(filesize);
if (*out == NULL) { if (*out == NULL)
return SC_ERROR_OUT_OF_MEMORY; return SC_ERROR_OUT_OF_MEMORY;
}
inf = fopen(name, "rb"); inf = fopen(name, "rb");
if (inf == NULL) { if (inf == NULL) {
@ -2140,141 +2171,39 @@ do_read_data_object(const char *name, u8 **out, size_t *outlen)
return 0; return 0;
} }
static int static char *
do_convert_bignum(sc_pkcs15_bignum_t *dst, const BIGNUM *src) cert_common_name(X509 *x509)
{ {
if (src == 0) X509_NAME_ENTRY *ne = NULL;
return 0; ASN1_STRING *a_str = NULL;
dst->len = BN_num_bytes(src); char *out = NULL;
dst->data = malloc(dst->len); unsigned char *tmp = NULL;
BN_bn2bin(src, dst->data); int idx, out_len = 0;
return 1;
idx = X509_NAME_get_index_by_NID(X509_get_subject_name(x509), NID_commonName, -1);
if (idx < 0)
return NULL;
ne = X509_NAME_get_entry(X509_get_subject_name(x509), idx);
if (!ne)
return NULL;
a_str = X509_NAME_ENTRY_get_data(ne);
if (!a_str)
return NULL;
out_len = ASN1_STRING_to_UTF8(&tmp, a_str);
if (!tmp)
return NULL;
out = calloc(1, out_len + 1);
if (out)
memcpy(out, tmp, out_len);
OPENSSL_free(tmp);
return out;
} }
static int do_convert_private_key(struct sc_pkcs15_prkey *key, EVP_PKEY *pk)
{
switch (pk->type) {
case EVP_PKEY_RSA: {
struct sc_pkcs15_prkey_rsa *dst = &key->u.rsa;
RSA *src = EVP_PKEY_get1_RSA(pk);
key->algorithm = SC_ALGORITHM_RSA;
if (!do_convert_bignum(&dst->modulus, src->n)
|| !do_convert_bignum(&dst->exponent, src->e)
|| !do_convert_bignum(&dst->d, src->d)
|| !do_convert_bignum(&dst->p, src->p)
|| !do_convert_bignum(&dst->q, src->q))
util_fatal("Invalid/incomplete RSA key.\n");
if (src->iqmp && src->dmp1 && src->dmq1) {
do_convert_bignum(&dst->iqmp, src->iqmp);
do_convert_bignum(&dst->dmp1, src->dmp1);
do_convert_bignum(&dst->dmq1, src->dmq1);
}
RSA_free(src);
break;
}
case EVP_PKEY_DSA: {
struct sc_pkcs15_prkey_dsa *dst = &key->u.dsa;
DSA *src = EVP_PKEY_get1_DSA(pk);
key->algorithm = SC_ALGORITHM_DSA;
do_convert_bignum(&dst->pub, src->pub_key);
do_convert_bignum(&dst->p, src->p);
do_convert_bignum(&dst->q, src->q);
do_convert_bignum(&dst->g, src->g);
do_convert_bignum(&dst->priv, src->priv_key);
DSA_free(src);
break;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
case NID_id_GostR3410_2001: {
struct sc_pkcs15_prkey_gostr3410 *dst = &key->u.gostr3410;
EC_KEY *src = EVP_PKEY_get0(pk);
assert(src);
key->algorithm = SC_ALGORITHM_GOSTR3410;
assert(EC_KEY_get0_private_key(src));
do_convert_bignum(&dst->d, EC_KEY_get0_private_key(src));
break;
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) */
default:
util_fatal("Unsupported key algorithm\n");
}
return 0;
}
static int do_convert_public_key(struct sc_pkcs15_pubkey *key, EVP_PKEY *pk)
{
switch (pk->type) {
case EVP_PKEY_RSA: {
struct sc_pkcs15_pubkey_rsa *dst = &key->u.rsa;
RSA *src = EVP_PKEY_get1_RSA(pk);
key->algorithm = SC_ALGORITHM_RSA;
if (!do_convert_bignum(&dst->modulus, src->n)
|| !do_convert_bignum(&dst->exponent, src->e))
util_fatal("Invalid/incomplete RSA key.\n");
RSA_free(src);
break;
}
case EVP_PKEY_DSA: {
struct sc_pkcs15_pubkey_dsa *dst = &key->u.dsa;
DSA *src = EVP_PKEY_get1_DSA(pk);
key->algorithm = SC_ALGORITHM_DSA;
do_convert_bignum(&dst->pub, src->pub_key);
do_convert_bignum(&dst->p, src->p);
do_convert_bignum(&dst->q, src->q);
do_convert_bignum(&dst->g, src->g);
DSA_free(src);
break;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
case NID_id_GostR3410_2001: {
struct sc_pkcs15_pubkey_gostr3410 *dst = &key->u.gostr3410;
EC_KEY *eckey = EVP_PKEY_get0(pk);
const EC_POINT *point;
BIGNUM *X, *Y;
int r = 0;
assert(eckey);
point = EC_KEY_get0_public_key(eckey);
if (!point)
return SC_ERROR_INTERNAL;
X = BN_new();
Y = BN_new();
if (X && Y && EC_KEY_get0_group(eckey))
r = EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(eckey),
point, X, Y, NULL);
if (r == 1) {
dst->xy.len = BN_num_bytes(X) + BN_num_bytes(Y);
dst->xy.data = malloc(dst->xy.len);
if (dst->xy.data) {
BN_bn2bin(Y, dst->xy.data);
BN_bn2bin(X, dst->xy.data + BN_num_bytes(Y));
r = sc_mem_reverse(dst->xy.data, dst->xy.len);
if (!r)
r = 1;
key->algorithm = SC_ALGORITHM_GOSTR3410;
}
else
r = -1;
}
BN_free(X);
BN_free(Y);
if (r != 1)
return SC_ERROR_INTERNAL;
break;
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) */
default:
util_fatal("Unsupported key algorithm\n");
}
return 0;
}
static int do_convert_cert(sc_pkcs15_der_t *der, X509 *cert) static int do_convert_cert(sc_pkcs15_der_t *der, X509 *cert)
{ {
@ -2573,6 +2502,16 @@ handle_option(const struct option *opt)
case OPT_SANITY_CHECK: case OPT_SANITY_CHECK:
this_action = ACTION_SANITY_CHECK; this_action = ACTION_SANITY_CHECK;
break; break;
case OPT_UPDATE_LAST_UPDATE:
this_action = ACTION_UPDATE_LAST_UPDATE;
break;
case OPT_ERASE_APPLICATION:
opt_bind_to_aid = optarg;
this_action = ACTION_ERASE_APPLICATION;
break;
case OPT_IGNORE_CA_CERTIFICATES:
opt_ignore_ca_certs = 1;
break;
default: default:
util_print_usage_and_die(app_name, options, option_help, NULL); util_print_usage_and_die(app_name, options, option_help, NULL);
} }
@ -2719,7 +2658,7 @@ ossl_print_errors(void)
* *
* @hints dialog hints * @hints dialog hints
* @out PIN entered by the user; must be freed. * @out PIN entered by the user; must be freed.
* NULL if dialog was canceled. * NULL if dialog was canceled.
*/ */
int get_pin(sc_ui_hints_t *hints, char **out) int get_pin(sc_ui_hints_t *hints, char **out)
{ {
@ -2728,17 +2667,16 @@ int get_pin(sc_ui_hints_t *hints, char **out)
int flags = hints->flags; int flags = hints->flags;
pin_info = hints->info.pin; pin_info = hints->info.pin;
if (pin_info && pin_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) if (pin_info && (pin_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN))
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
if (!(label = hints->obj_label)) { if (!(label = hints->obj_label)) {
if (pin_info == NULL) { if (pin_info == NULL)
label = "PIN"; label = "PIN";
} else if (pin_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { else if (pin_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
label = "Security Officer PIN"; label = "Security Officer PIN";
} else { else
label = "User PIN"; label = "User PIN";
}
} }
if (hints->p15card) { if (hints->p15card) {