2002-02-22 07:18:43 +00:00
|
|
|
/*
|
|
|
|
* Initialize Cards according to PKCS#15.
|
|
|
|
*
|
|
|
|
* This is a fill in the blanks sort of exercise. You need a
|
|
|
|
* profile that describes characteristics of your card, and the
|
|
|
|
* application specific layout on the card. This program will
|
|
|
|
* set up the card according to this specification (including
|
|
|
|
* PIN initialization etc) and create the corresponding PKCS15
|
|
|
|
* structure.
|
|
|
|
*
|
|
|
|
* There are a very few tasks that are too card specific to have
|
|
|
|
* a generic implementation; that is how PINs and keys are stored
|
2002-03-09 17:54:16 +00:00
|
|
|
* on the card. These should be implemented in pkcs15-<cardname>.c
|
2002-02-22 07:18:43 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2002, Olaf Kirch <okir@lst.de>
|
2002-02-25 18:50:29 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2002-02-22 07:18:43 +00:00
|
|
|
*/
|
|
|
|
|
2002-02-25 16:30:38 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
2002-02-22 07:18:43 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdarg.h>
|
2002-03-24 14:12:38 +00:00
|
|
|
#include <assert.h>
|
2002-02-23 13:38:01 +00:00
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/rand.h>
|
2002-03-06 17:49:47 +00:00
|
|
|
#include <openssl/rsa.h>
|
2002-03-12 16:27:21 +00:00
|
|
|
#include <openssl/pkcs12.h>
|
2002-04-05 13:48:00 +00:00
|
|
|
#include <opensc/pkcs15.h>
|
|
|
|
#include <opensc/pkcs15-init.h>
|
2002-02-22 07:18:43 +00:00
|
|
|
#include "util.h"
|
|
|
|
|
2002-03-24 14:12:38 +00:00
|
|
|
const char *app_name = "pkcs15-init";
|
|
|
|
|
2002-02-22 07:18:43 +00:00
|
|
|
/* Handle encoding of PKCS15 on the card */
|
|
|
|
typedef int (*pkcs15_encoder)(struct sc_context *,
|
|
|
|
struct sc_pkcs15_card *, u8 **, size_t *);
|
|
|
|
|
|
|
|
/* Local functions */
|
|
|
|
static int connect(int);
|
2002-04-02 13:28:31 +00:00
|
|
|
static int do_init_app(struct sc_profile *);
|
|
|
|
static int do_store_pin(struct sc_profile *);
|
2002-03-06 17:49:47 +00:00
|
|
|
static int do_generate_key(struct sc_profile *, const char *);
|
|
|
|
static int do_store_private_key(struct sc_profile *profile);
|
|
|
|
static int do_store_public_key(struct sc_profile *profile);
|
2002-03-12 10:08:18 +00:00
|
|
|
static int do_store_certificate(struct sc_profile *profile);
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
|
|
|
|
static int read_one_pin(struct sc_profile *, const char *,
|
|
|
|
const struct sc_pkcs15_pin_info *, int, char **);
|
|
|
|
static int get_pin_callback(struct sc_profile *profile,
|
|
|
|
int id, const struct sc_pkcs15_pin_info *info,
|
|
|
|
u8 *pinbuf, size_t *pinsize);
|
2002-03-12 10:08:18 +00:00
|
|
|
|
2002-03-12 16:27:21 +00:00
|
|
|
static int do_read_private_key(const char *, const char *,
|
|
|
|
EVP_PKEY **, X509 **);
|
2002-03-12 10:08:18 +00:00
|
|
|
static int do_read_public_key(const char *, const char *, EVP_PKEY **);
|
2002-02-23 13:38:01 +00:00
|
|
|
static int do_write_public_key(const char *, const char *, EVP_PKEY *);
|
2002-03-12 10:08:18 +00:00
|
|
|
static int do_read_certificate(const char *, const char *, X509 **);
|
2002-02-23 13:38:01 +00:00
|
|
|
static void parse_commandline(int argc, char **argv);
|
|
|
|
static void read_options_file(const char *);
|
|
|
|
static void ossl_print_errors(void);
|
2002-02-22 07:18:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
enum {
|
2002-02-23 13:38:01 +00:00
|
|
|
OPT_OPTIONS = 0x100,
|
|
|
|
OPT_PASSPHRASE,
|
2002-04-02 13:28:31 +00:00
|
|
|
OPT_PUBKEY,
|
2002-02-23 13:38:01 +00:00
|
|
|
|
2002-02-22 07:18:43 +00:00
|
|
|
OPT_PIN1 = 0x10000, /* don't touch these values */
|
|
|
|
OPT_PUK1 = 0x10001,
|
|
|
|
OPT_PIN2 = 0x10002,
|
|
|
|
OPT_PUK2 = 0x10003,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct option options[] = {
|
|
|
|
{ "erase-card", no_argument, 0, 'E' },
|
|
|
|
{ "create-pkcs15", no_argument, 0, 'C' },
|
2002-04-02 13:28:31 +00:00
|
|
|
{ "store-pin", no_argument, 0, 'P' },
|
|
|
|
{ "pin", required_argument, 0, OPT_PIN1 },
|
|
|
|
{ "puk", required_argument, 0, OPT_PUK1 },
|
|
|
|
{ "so-pin", required_argument, 0, OPT_PIN2 },
|
|
|
|
{ "so-puk", required_argument, 0, OPT_PUK2 },
|
|
|
|
{ "auth-id", required_argument, 0, 'a' },
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "id", required_argument, 0, 'i' },
|
2002-04-02 13:28:31 +00:00
|
|
|
{ "label", required_argument, 0, 'l' },
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "generate-key", required_argument, 0, 'G' },
|
2002-03-12 10:08:18 +00:00
|
|
|
{ "output-file", required_argument, 0, 'o' },
|
|
|
|
{ "store-private-key", required_argument, 0, 'S' },
|
2002-04-02 13:28:31 +00:00
|
|
|
{ "store-public-key", required_argument, 0, OPT_PUBKEY },
|
2002-03-12 10:08:18 +00:00
|
|
|
{ "format", required_argument, 0, 'f' },
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "passphrase", required_argument, 0, OPT_PASSPHRASE },
|
2002-03-12 10:08:18 +00:00
|
|
|
{ "store-certificate", required_argument, 0, 'X' },
|
2002-02-25 18:50:29 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "profile", required_argument, 0, 'p' },
|
|
|
|
{ "options-file", required_argument, 0, OPT_OPTIONS },
|
2002-02-22 07:18:43 +00:00
|
|
|
{ "debug", no_argument, 0, 'd' },
|
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
const char * option_help[] = {
|
|
|
|
"Erase the smart card",
|
|
|
|
"Creates a new PKCS #15 structure",
|
2002-04-02 13:28:31 +00:00
|
|
|
"Store a new PIN/PUK on the card",
|
|
|
|
"Specify PIN",
|
|
|
|
"Specify unblock PIN",
|
|
|
|
"Specify security officer (SO) PIN",
|
|
|
|
"Specify unblock PIN for SO PIN",
|
|
|
|
"Specify ID of PIN to use/create",
|
2002-02-23 13:38:01 +00:00
|
|
|
"Specify ID of key/certificate",
|
2002-04-02 13:28:31 +00:00
|
|
|
"Specify label of PIN/key",
|
2002-02-23 13:38:01 +00:00
|
|
|
"Generate a new key and store it on the card",
|
|
|
|
"Output public portion of generated key to file",
|
|
|
|
"Store private key",
|
2002-03-12 10:08:18 +00:00
|
|
|
"Store public key",
|
2002-02-23 13:38:01 +00:00
|
|
|
"Specify key file format (default PEM)",
|
2002-02-25 18:50:29 +00:00
|
|
|
"Specify passphrase for unlocking secret key",
|
2002-03-12 10:08:18 +00:00
|
|
|
"Store an X.509 certificate",
|
2002-02-25 18:50:29 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
"Specify the profile to use",
|
|
|
|
"Read additional command line options from file",
|
2002-02-22 07:18:43 +00:00
|
|
|
"Enable debugging output",
|
|
|
|
};
|
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
enum {
|
|
|
|
ACTION_NONE = 0,
|
|
|
|
ACTION_INIT,
|
2002-04-02 13:28:31 +00:00
|
|
|
ACTION_STORE_PIN,
|
2002-02-23 13:38:01 +00:00
|
|
|
ACTION_GENERATE_KEY,
|
2002-03-06 17:49:47 +00:00
|
|
|
ACTION_STORE_PRIVKEY,
|
|
|
|
ACTION_STORE_PUBKEY,
|
2002-02-23 13:38:01 +00:00
|
|
|
ACTION_STORE_CERT
|
|
|
|
};
|
2002-04-02 13:28:31 +00:00
|
|
|
static char * action_names[] = {
|
|
|
|
"do nothing",
|
|
|
|
"create PKCS #15 meta structure",
|
|
|
|
"store PIN",
|
|
|
|
"generate key",
|
|
|
|
"store private key",
|
|
|
|
"store public key",
|
|
|
|
"store certificate"
|
|
|
|
};
|
2002-02-23 13:38:01 +00:00
|
|
|
|
2002-02-22 07:18:43 +00:00
|
|
|
static struct sc_context * ctx = NULL;
|
|
|
|
static struct sc_card * card = NULL;
|
2002-03-06 17:49:47 +00:00
|
|
|
static struct sc_pkcs15_card * p15card = NULL;
|
2002-02-22 07:18:43 +00:00
|
|
|
static int opt_debug = 0,
|
2002-02-23 13:38:01 +00:00
|
|
|
opt_quiet = 0,
|
|
|
|
opt_action = 0,
|
2002-04-02 13:28:31 +00:00
|
|
|
opt_erase = 0,
|
|
|
|
opt_unprotected = 0;
|
2002-03-06 17:49:47 +00:00
|
|
|
static char * opt_profile = "pkcs15";
|
2002-03-12 10:08:18 +00:00
|
|
|
static char * opt_infile = 0;
|
2002-02-23 13:38:01 +00:00
|
|
|
static char * opt_format = 0;
|
2002-04-02 13:28:31 +00:00
|
|
|
static char * opt_authid = 0;
|
2002-02-23 13:38:01 +00:00
|
|
|
static char * opt_objectid = 0;
|
2002-03-06 17:49:47 +00:00
|
|
|
static char * opt_objectlabel = 0;
|
2002-02-22 07:18:43 +00:00
|
|
|
static char * opt_pins[4];
|
2002-02-23 13:38:01 +00:00
|
|
|
static char * opt_passphrase = 0;
|
|
|
|
static char * opt_newkey = 0;
|
|
|
|
static char * opt_outkey = 0;
|
2002-04-02 13:28:31 +00:00
|
|
|
|
|
|
|
static struct sc_pkcs15init_callbacks callbacks = {
|
|
|
|
error, /* error() */
|
|
|
|
NULL, /* debug() */
|
|
|
|
get_pin_callback, /* get_pin() */
|
|
|
|
NULL /* get_secret() */
|
|
|
|
};
|
2002-02-22 07:18:43 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
2002-04-05 10:06:10 +00:00
|
|
|
struct sc_profile *profile;
|
2002-02-22 07:18:43 +00:00
|
|
|
int opt_reader = 0;
|
2002-02-23 13:38:01 +00:00
|
|
|
int r = 0;
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
/* OpenSSL magic */
|
|
|
|
SSLeay_add_all_algorithms();
|
|
|
|
CRYPTO_malloc_init();
|
2002-04-02 13:28:31 +00:00
|
|
|
#ifdef RANDOM_POOL
|
|
|
|
if (!RAND_load_file(RANDOM_POOL, 32))
|
|
|
|
fatal("Unable to seed random number pool for key generation");
|
|
|
|
#endif
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
parse_commandline(argc, argv);
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
if (optind != argc)
|
|
|
|
print_usage_and_die("pkcs15-init");
|
|
|
|
if (opt_action == ACTION_NONE) {
|
|
|
|
fprintf(stderr, "No action specified.\n");
|
|
|
|
print_usage_and_die("pkcs15-init");
|
|
|
|
}
|
2002-03-04 10:33:35 +00:00
|
|
|
if (!opt_profile) {
|
|
|
|
fprintf(stderr, "No profile specified.\n");
|
|
|
|
print_usage_and_die("pkcs15-init");
|
|
|
|
}
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/* Connect to the card */
|
|
|
|
if (!connect(opt_reader))
|
|
|
|
return 1;
|
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
sc_pkcs15init_set_callbacks(&callbacks);
|
2002-02-25 18:50:29 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
/* Bind the card-specific operations and load the profile */
|
2002-04-05 10:06:10 +00:00
|
|
|
if ((r = sc_pkcs15init_bind(card, opt_profile, &profile)) < 0)
|
2002-04-02 13:28:31 +00:00
|
|
|
return 1;
|
2002-02-23 13:38:01 +00:00
|
|
|
|
|
|
|
if (opt_action == ACTION_INIT) {
|
2002-04-05 10:06:10 +00:00
|
|
|
r = do_init_app(profile);
|
2002-02-23 13:38:01 +00:00
|
|
|
goto done;
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
2002-02-23 13:38:01 +00:00
|
|
|
|
|
|
|
if (opt_erase)
|
|
|
|
fatal("Option --erase can be used only with --create-pkcs15\n");
|
|
|
|
|
|
|
|
/* Read the PKCS15 structure from the card */
|
|
|
|
r = sc_pkcs15_bind(card, &p15card);
|
|
|
|
if (r) {
|
2002-02-25 18:50:29 +00:00
|
|
|
fprintf(stderr, "PKCS#15 initialization failed: %s\n",
|
|
|
|
sc_strerror(r));
|
2002-02-23 13:38:01 +00:00
|
|
|
goto done;
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
2002-02-23 13:38:01 +00:00
|
|
|
if (!opt_quiet)
|
|
|
|
printf("Found %s\n", p15card->label);
|
|
|
|
|
|
|
|
/* XXX: should compare card to profile here to make sure
|
|
|
|
* we're not messing things up */
|
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
if (opt_action == ACTION_STORE_PIN)
|
2002-04-05 10:06:10 +00:00
|
|
|
r = do_store_pin(profile);
|
2002-04-02 13:28:31 +00:00
|
|
|
else if (opt_action == ACTION_STORE_PRIVKEY)
|
2002-04-05 10:06:10 +00:00
|
|
|
r = do_store_private_key(profile);
|
2002-03-06 17:49:47 +00:00
|
|
|
else if (opt_action == ACTION_STORE_PUBKEY)
|
2002-04-05 10:06:10 +00:00
|
|
|
r = do_store_public_key(profile);
|
2002-03-12 10:08:18 +00:00
|
|
|
else if (opt_action == ACTION_STORE_CERT)
|
2002-04-05 10:06:10 +00:00
|
|
|
r = do_store_certificate(profile);
|
2002-02-23 13:38:01 +00:00
|
|
|
else if (opt_action == ACTION_GENERATE_KEY)
|
2002-04-05 10:06:10 +00:00
|
|
|
r = do_generate_key(profile, opt_newkey);
|
2002-02-23 13:38:01 +00:00
|
|
|
else
|
|
|
|
fatal("Action not yet implemented\n");
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
done: if (r < 0) {
|
|
|
|
fprintf(stderr, "Failed to %s: %s\n",
|
|
|
|
action_names[opt_action],
|
|
|
|
sc_strerror(r));
|
|
|
|
} else if (!opt_quiet) {
|
|
|
|
printf("Was able to %s successfully.\n",
|
|
|
|
action_names[opt_action]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (card) {
|
2002-02-22 07:18:43 +00:00
|
|
|
sc_unlock(card);
|
2002-02-24 19:32:14 +00:00
|
|
|
sc_disconnect_card(card, 0);
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
2002-03-24 14:12:38 +00:00
|
|
|
sc_release_context(ctx);
|
2002-04-03 11:56:59 +00:00
|
|
|
return r < 0? 1 : 0;
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
connect(int reader)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
2002-03-24 14:12:38 +00:00
|
|
|
r = sc_establish_context(&ctx, app_name);
|
2002-02-22 07:18:43 +00:00
|
|
|
if (r) {
|
|
|
|
error("Failed to establish context: %s\n", sc_strerror(r));
|
|
|
|
return 0;
|
|
|
|
}
|
2002-04-02 13:28:31 +00:00
|
|
|
if (opt_debug) {
|
2002-03-24 21:56:13 +00:00
|
|
|
ctx->debug = opt_debug;
|
2002-04-02 13:28:31 +00:00
|
|
|
ctx->debug_file = stderr;
|
|
|
|
}
|
2002-02-22 07:18:43 +00:00
|
|
|
if (reader >= ctx->reader_count || reader < 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Illegal reader number. Only %d reader%s configured.\n",
|
|
|
|
ctx->reader_count,
|
|
|
|
ctx->reader_count == 1? "" : "s");
|
|
|
|
return 0;
|
|
|
|
}
|
2002-02-24 19:32:14 +00:00
|
|
|
if (sc_detect_card_presence(ctx->reader[reader], 0) != 1) {
|
2002-02-22 07:18:43 +00:00
|
|
|
error("Card not present.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!opt_quiet) {
|
|
|
|
printf("Connecting to card in reader %s...\n",
|
2002-02-24 19:32:14 +00:00
|
|
|
ctx->reader[reader]->name);
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
|
|
|
|
2002-02-24 19:32:14 +00:00
|
|
|
r = sc_connect_card(ctx->reader[reader], 0, &card);
|
2002-02-22 07:18:43 +00:00
|
|
|
if (r) {
|
|
|
|
error("Failed to connect to card: %s\n", sc_strerror(r));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Using card driver: %s\n", card->driver->name);
|
|
|
|
r = sc_lock(card);
|
|
|
|
if (r) {
|
|
|
|
error("Unable to lock card: %s\n", sc_strerror(r));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
/*
|
|
|
|
* Initialize pkcs15 application
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_init_app(struct sc_profile *profile)
|
|
|
|
{
|
2002-04-02 14:46:32 +00:00
|
|
|
struct sc_pkcs15init_initargs args;
|
2002-04-02 13:28:31 +00:00
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
if (opt_erase)
|
2002-04-05 10:06:10 +00:00
|
|
|
r = sc_pkcs15init_erase_card(card, profile);
|
2002-04-02 14:46:32 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
2002-04-02 20:58:18 +00:00
|
|
|
args.so_pin = (const u8 *) opt_pins[OPT_PIN2 & 3];
|
2002-04-02 14:46:32 +00:00
|
|
|
if (args.so_pin)
|
2002-04-02 20:58:18 +00:00
|
|
|
args.so_pin_len = strlen((char *) args.so_pin);
|
|
|
|
args.so_puk = (const u8 *) opt_pins[OPT_PUK2 & 3];
|
2002-04-02 14:46:32 +00:00
|
|
|
if (args.so_puk)
|
2002-04-02 20:58:18 +00:00
|
|
|
args.so_puk_len = strlen((char *) args.so_puk);
|
2002-04-02 14:46:32 +00:00
|
|
|
return sc_pkcs15init_add_app(card, profile, &args);
|
2002-04-02 13:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store a PIN/PUK pair
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_store_pin(struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15init_pinargs args;
|
|
|
|
struct sc_pkcs15_pin_info info;
|
|
|
|
|
|
|
|
if (!opt_authid) {
|
|
|
|
error("No auth id specified\n");
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt_pins[0] == NULL) {
|
2002-04-05 10:06:10 +00:00
|
|
|
sc_pkcs15init_get_pin_info(profile,
|
|
|
|
SC_PKCS15INIT_USER_PIN, &info);
|
2002-04-02 13:28:31 +00:00
|
|
|
read_one_pin(profile, "New user PIN", &info, 0,
|
|
|
|
&opt_pins[0]);
|
|
|
|
}
|
|
|
|
if (*opt_pins[0] == '\0') {
|
|
|
|
error("You must specify a PIN\n");
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
if (opt_pins[1] == NULL) {
|
2002-04-05 10:06:10 +00:00
|
|
|
sc_pkcs15init_get_pin_info(profile,
|
|
|
|
SC_PKCS15INIT_SO_PIN, &info);
|
2002-04-02 13:28:31 +00:00
|
|
|
read_one_pin(profile, "Unlock code for new user PIN",
|
|
|
|
&info, 1, &opt_pins[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
sc_pkcs15_format_id(opt_authid, &args.auth_id);
|
|
|
|
args.pin = (u8 *) opt_pins[0];
|
|
|
|
args.pin_len = strlen(opt_pins[0]);
|
|
|
|
args.puk = (u8 *) opt_pins[1];
|
|
|
|
args.puk_len = opt_pins[1]? strlen(opt_pins[1]) : 0;
|
|
|
|
args.label = opt_objectlabel;
|
|
|
|
|
|
|
|
return sc_pkcs15init_store_pin(p15card, profile, &args);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/*
|
|
|
|
* Store a private key
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_store_private_key(struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15init_keyargs args;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
if (opt_objectid)
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &args.id);
|
2002-04-02 13:28:31 +00:00
|
|
|
if (opt_authid) {
|
|
|
|
sc_pkcs15_format_id(opt_authid, &args.auth_id);
|
|
|
|
} else if (!opt_unprotected) {
|
|
|
|
error("no PIN given for key - either use --unprotected or "
|
|
|
|
"specify a PIN using --auth-id");
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
args.label = opt_objectlabel;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-03-12 16:27:21 +00:00
|
|
|
r = do_read_private_key(opt_infile, opt_format, &args.pkey, &args.cert);
|
2002-03-07 12:26:17 +00:00
|
|
|
if (r < 0)
|
2002-04-02 13:28:31 +00:00
|
|
|
return r;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15init_store_private_key(p15card, profile, &args);
|
2002-03-07 12:26:17 +00:00
|
|
|
if (r < 0)
|
2002-04-02 13:28:31 +00:00
|
|
|
return r;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-03-12 16:27:21 +00:00
|
|
|
/* If there's a certificate as well (e.g. when reading the
|
|
|
|
* private key from a PKCS #12 file) store it, too.
|
|
|
|
* Otherwise store the public key.
|
|
|
|
*/
|
|
|
|
if (args.cert) {
|
|
|
|
struct sc_pkcs15init_certargs cargs;
|
|
|
|
|
|
|
|
memset(&cargs, 0, sizeof(cargs));
|
|
|
|
cargs.id = args.id;
|
|
|
|
cargs.cert = args.cert;
|
2002-04-02 13:28:31 +00:00
|
|
|
r = sc_pkcs15init_store_certificate(p15card, profile, &cargs);
|
2002-03-12 16:27:21 +00:00
|
|
|
} else {
|
|
|
|
r = sc_pkcs15init_store_public_key(p15card, profile, &args);
|
|
|
|
}
|
2002-03-11 11:52:04 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
return r;
|
2002-03-06 17:49:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store a public key
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_store_public_key(struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15init_keyargs args;
|
2002-03-07 12:26:17 +00:00
|
|
|
int r;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
if (opt_objectid)
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &args.id);
|
|
|
|
if (opt_objectlabel)
|
|
|
|
args.label = opt_objectlabel;
|
|
|
|
|
2002-03-12 10:08:18 +00:00
|
|
|
r = do_read_public_key(opt_infile, opt_format, &args.pkey);
|
2002-04-02 13:28:31 +00:00
|
|
|
if (r >= 0)
|
|
|
|
r = sc_pkcs15init_store_public_key(p15card, profile, &args);
|
2002-03-07 12:26:17 +00:00
|
|
|
|
|
|
|
return -1;
|
2002-03-06 17:49:47 +00:00
|
|
|
}
|
|
|
|
|
2002-03-12 10:08:18 +00:00
|
|
|
/*
|
|
|
|
* Download certificate to card
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_store_certificate(struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15init_certargs args;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
|
|
|
|
if (opt_objectid)
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &args.id);
|
|
|
|
args.label = opt_objectlabel;
|
|
|
|
|
|
|
|
r = do_read_certificate(opt_infile, opt_format, &args.cert);
|
2002-04-02 13:28:31 +00:00
|
|
|
if (r >= 0)
|
|
|
|
r = sc_pkcs15init_store_certificate(p15card, profile, &args);
|
2002-03-12 10:08:18 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
return r;
|
2002-03-12 10:08:18 +00:00
|
|
|
}
|
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/*
|
|
|
|
* Generate a new private key
|
|
|
|
*/
|
2002-02-22 07:18:43 +00:00
|
|
|
static int
|
2002-03-06 17:49:47 +00:00
|
|
|
do_generate_key(struct sc_profile *profile, const char *spec)
|
2002-02-22 07:18:43 +00:00
|
|
|
{
|
2002-04-02 13:28:31 +00:00
|
|
|
struct sc_pkcs15init_keyargs args;
|
2002-03-06 17:49:47 +00:00
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Parse the key spec given on the command line */
|
2002-04-02 13:28:31 +00:00
|
|
|
memset(&args, 0, sizeof(args));
|
2002-03-06 17:49:47 +00:00
|
|
|
if (!strncasecmp(spec, "rsa", 3)) {
|
2002-04-02 13:28:31 +00:00
|
|
|
args.algorithm = SC_ALGORITHM_RSA;
|
2002-03-06 17:49:47 +00:00
|
|
|
spec += 3;
|
|
|
|
} else if (!strncasecmp(spec, "dsa", 3)) {
|
2002-04-02 13:28:31 +00:00
|
|
|
args.algorithm = SC_ALGORITHM_DSA;
|
2002-03-06 17:49:47 +00:00
|
|
|
spec += 3;
|
|
|
|
} else {
|
2002-04-02 13:28:31 +00:00
|
|
|
error("Unknown algorithm \"%s\"", spec);
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2002-03-06 17:49:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*spec == '/' || *spec == '-')
|
|
|
|
spec++;
|
|
|
|
if (*spec) {
|
2002-04-02 13:28:31 +00:00
|
|
|
char *end;
|
|
|
|
|
|
|
|
args.keybits = strtoul(spec, &end, 10);
|
|
|
|
if (*end) {
|
|
|
|
error("Invalid number of key bits \"%s\"", spec);
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2002-03-06 17:49:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt_objectid)
|
2002-04-02 13:28:31 +00:00
|
|
|
sc_pkcs15_format_id(opt_objectid, &args.id);
|
|
|
|
if (opt_authid)
|
|
|
|
sc_pkcs15_format_id(opt_authid, &args.auth_id);
|
|
|
|
else if (!opt_unprotected) {
|
|
|
|
error("no PIN given for key - either use --unprotected or "
|
|
|
|
"specify a PIN using --auth-id");
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
args.label = opt_objectlabel;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
|
|
|
while (1) {
|
2002-04-02 13:28:31 +00:00
|
|
|
r = sc_pkcs15init_generate_key(p15card, profile, &args);
|
|
|
|
if (r != SC_ERROR_NOT_SUPPORTED || !args.onboard_keygen)
|
2002-03-06 17:49:47 +00:00
|
|
|
break;
|
|
|
|
if (!opt_quiet)
|
|
|
|
printf("Warning: card doesn't support on-board "
|
|
|
|
"key generation; using software generation\n");
|
2002-04-02 13:28:31 +00:00
|
|
|
args.onboard_keygen = 0;
|
2002-03-06 17:49:47 +00:00
|
|
|
}
|
2002-04-02 13:28:31 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
|
|
|
/* Store public key portion on card */
|
2002-04-02 13:28:31 +00:00
|
|
|
r = sc_pkcs15init_store_public_key(p15card, profile, &args);
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
if (r >= 0 && opt_outkey) {
|
2002-03-06 17:49:47 +00:00
|
|
|
if (!opt_quiet)
|
|
|
|
printf("Writing public key to %s\n", opt_outkey);
|
2002-04-02 13:28:31 +00:00
|
|
|
r = do_write_public_key(opt_outkey, opt_format, args.pkey);
|
2002-03-12 10:08:18 +00:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/*
|
2002-04-02 13:28:31 +00:00
|
|
|
* Callbacks from the pkcs15init to retrieve PINs
|
2002-03-06 17:49:47 +00:00
|
|
|
*/
|
2002-03-11 14:13:11 +00:00
|
|
|
static int
|
2002-04-02 13:28:31 +00:00
|
|
|
read_one_pin(struct sc_profile *profile, const char *name,
|
|
|
|
const struct sc_pkcs15_pin_info *info,
|
|
|
|
int optional, char **out)
|
2002-03-11 14:13:11 +00:00
|
|
|
{
|
2002-04-02 13:28:31 +00:00
|
|
|
char *pin;
|
|
|
|
size_t len;
|
2002-03-11 14:13:11 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
printf("%s required.\n", name);
|
|
|
|
while (1) {
|
|
|
|
pin = getpass("Please enter code: ");
|
|
|
|
len = strlen(pin);
|
2002-03-11 14:13:11 +00:00
|
|
|
if (info == NULL)
|
2002-04-02 13:28:31 +00:00
|
|
|
break;
|
|
|
|
if (len == 0 && optional)
|
|
|
|
return 0;
|
|
|
|
if (len < info->min_length) {
|
2002-03-02 14:03:41 +00:00
|
|
|
error("Password too short (%u characters min)",
|
2002-04-02 13:28:31 +00:00
|
|
|
info->min_length);
|
2002-03-02 14:03:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
2002-04-02 13:28:31 +00:00
|
|
|
if (len > info->stored_length) {
|
2002-03-02 14:03:41 +00:00
|
|
|
error("Password too long (%u characters max)",
|
2002-04-02 13:28:31 +00:00
|
|
|
info->stored_length);
|
2002-02-22 07:18:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
break;
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
2002-04-02 13:28:31 +00:00
|
|
|
|
|
|
|
*out = strdup(pin);
|
|
|
|
memset(pin, 0, len);
|
|
|
|
return 1;
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2002-04-02 13:28:31 +00:00
|
|
|
get_pin_callback(struct sc_profile *profile,
|
|
|
|
int id, const struct sc_pkcs15_pin_info *info,
|
|
|
|
u8 *pinbuf, size_t *pinsize)
|
|
|
|
{
|
|
|
|
char *name = NULL, *secret = NULL;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
switch (id) {
|
|
|
|
case SC_PKCS15INIT_USER_PIN:
|
|
|
|
name = "User PIN";
|
|
|
|
secret = opt_pins[OPT_PIN1 & 3]; break;
|
|
|
|
case SC_PKCS15INIT_USER_PUK:
|
|
|
|
name = "User PIN unlock key";
|
|
|
|
secret = opt_pins[OPT_PUK1 & 3]; break;
|
|
|
|
case SC_PKCS15INIT_SO_PIN:
|
|
|
|
name = "Security officer PIN";
|
|
|
|
secret = opt_pins[OPT_PIN2 & 3]; break;
|
|
|
|
case SC_PKCS15INIT_SO_PUK:
|
|
|
|
name = "Security officer PIN unlock key";
|
|
|
|
secret = opt_pins[OPT_PUK2 & 3]; break;
|
|
|
|
default:
|
|
|
|
return SC_ERROR_INTERNAL;
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
if (secret == NULL
|
|
|
|
&& !read_one_pin(profile, name, NULL, 0, &secret))
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
len = strlen(secret);
|
|
|
|
if (len + 1 > *pinsize)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
memcpy(pinbuf, secret, len + 1);
|
|
|
|
*pinsize = len;
|
2002-03-06 17:49:47 +00:00
|
|
|
return 0;
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
/*
|
2002-03-12 16:27:21 +00:00
|
|
|
* Read a private key
|
2002-02-23 13:38:01 +00:00
|
|
|
*/
|
|
|
|
static EVP_PKEY *
|
|
|
|
do_read_pem_private_key(const char *filename, const char *passphrase)
|
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
EVP_PKEY *pk;
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_read_filename(bio, filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
pk = PEM_read_bio_PrivateKey(bio, 0, 0, (char *) passphrase);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (pk == NULL)
|
|
|
|
ossl_print_errors();
|
|
|
|
return pk;
|
|
|
|
}
|
|
|
|
|
2002-03-12 16:27:21 +00:00
|
|
|
static EVP_PKEY *
|
|
|
|
do_read_pkcs12_private_key(const char *filename, const char *passphrase,
|
|
|
|
X509 **xp)
|
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
PKCS12 *p12;
|
|
|
|
EVP_PKEY *pk = NULL;
|
|
|
|
|
2002-03-13 20:23:18 +00:00
|
|
|
*xp = NULL;
|
2002-03-12 16:27:21 +00:00
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_read_filename(bio, filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
p12 = d2i_PKCS12_bio(bio, NULL);
|
|
|
|
BIO_free(bio);
|
2002-03-13 20:23:18 +00:00
|
|
|
if (p12) {
|
2002-03-12 16:27:21 +00:00
|
|
|
PKCS12_parse(p12, passphrase, &pk, xp, NULL);
|
2002-03-13 20:23:18 +00:00
|
|
|
if (pk)
|
|
|
|
CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY);
|
|
|
|
if (*xp)
|
|
|
|
CRYPTO_add(&(*xp)->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
}
|
2002-03-12 16:27:21 +00:00
|
|
|
PKCS12_free(p12);
|
|
|
|
if (pk == NULL)
|
|
|
|
ossl_print_errors();
|
|
|
|
return pk;
|
|
|
|
}
|
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
static int
|
2002-03-12 16:27:21 +00:00
|
|
|
do_read_private_key(const char *filename, const char *format,
|
|
|
|
EVP_PKEY **pk, X509 **xp)
|
2002-02-23 13:38:01 +00:00
|
|
|
{
|
|
|
|
char *passphrase = NULL;
|
|
|
|
|
2002-03-12 16:27:21 +00:00
|
|
|
*xp = NULL;
|
2002-02-23 13:38:01 +00:00
|
|
|
while (1) {
|
|
|
|
if (!format || !strcasecmp(format, "pem")) {
|
|
|
|
*pk = do_read_pem_private_key(filename, passphrase);
|
2002-03-12 16:27:21 +00:00
|
|
|
} else if (!strcasecmp(format, "pkcs12")) {
|
|
|
|
*pk = do_read_pkcs12_private_key(filename,
|
|
|
|
passphrase, xp);
|
2002-02-23 13:38:01 +00:00
|
|
|
} else {
|
|
|
|
error("Error when reading private key. "
|
|
|
|
"Key file format \"%s\" not supported.\n",
|
|
|
|
format);
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*pk || passphrase)
|
|
|
|
break;
|
|
|
|
if ((passphrase = opt_passphrase) != 0)
|
|
|
|
continue;
|
|
|
|
passphrase = getpass("Please enter passphrase "
|
|
|
|
"to unlock secret key: ");
|
|
|
|
if (!passphrase)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (passphrase)
|
|
|
|
memset(passphrase, 0, strlen(passphrase));
|
|
|
|
if (!*pk)
|
|
|
|
fatal("Unable to read private key from %s\n", filename);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-03-12 10:08:18 +00:00
|
|
|
* Read a public key
|
|
|
|
*/
|
|
|
|
static EVP_PKEY *
|
|
|
|
do_read_pem_public_key(const char *filename)
|
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
EVP_PKEY *pk;
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_read_filename(bio, filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
pk = PEM_read_bio_PUBKEY(bio, 0, 0, NULL);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (pk == NULL)
|
|
|
|
ossl_print_errors();
|
|
|
|
return pk;
|
|
|
|
}
|
|
|
|
|
|
|
|
static EVP_PKEY *
|
|
|
|
do_read_der_public_key(const char *filename)
|
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
EVP_PKEY *pk;
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_read_filename(bio, filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
pk = d2i_PUBKEY_bio(bio, NULL);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (pk == NULL)
|
|
|
|
ossl_print_errors();
|
|
|
|
return pk;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_read_public_key(const char *name, const char *format, EVP_PKEY **out)
|
|
|
|
{
|
|
|
|
if (!format || !strcasecmp(format, "pem")) {
|
|
|
|
*out = do_read_pem_public_key(name);
|
|
|
|
} else if (!strcasecmp(format, "der")) {
|
|
|
|
*out = do_read_der_public_key(name);
|
|
|
|
} else {
|
|
|
|
fatal("Error when reading public key. "
|
|
|
|
"File format \"%s\" not supported.\n",
|
|
|
|
format);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*out)
|
|
|
|
fatal("Unable to read public key from %s\n", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a PEM encoded public key
|
2002-02-23 13:38:01 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_write_pem_public_key(const char *filename, EVP_PKEY *pk)
|
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_write_filename(bio, (char *) filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
r = PEM_write_bio_PUBKEY(bio, pk);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (r == 0) {
|
|
|
|
ossl_print_errors();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_write_public_key(const char *filename, const char *format, EVP_PKEY *pk)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!format || !strcasecmp(format, "pem")) {
|
|
|
|
r = do_write_pem_public_key(filename, pk);
|
|
|
|
} else {
|
|
|
|
error("Error when writing public key. "
|
|
|
|
"Key file format \"%s\" not supported.\n",
|
|
|
|
format);
|
|
|
|
r = SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2002-03-12 10:08:18 +00:00
|
|
|
/*
|
|
|
|
* Read a certificate
|
|
|
|
*/
|
|
|
|
static X509 *
|
|
|
|
do_read_pem_certificate(const char *filename)
|
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
X509 *xp;
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_read_filename(bio, filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
xp = PEM_read_bio_X509(bio, 0, 0, 0);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (xp == NULL)
|
|
|
|
ossl_print_errors();
|
|
|
|
return xp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static X509 *
|
|
|
|
do_read_der_certificate(const char *filename)
|
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
X509 *xp;
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_read_filename(bio, filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
xp = d2i_X509_bio(bio, NULL);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (xp == NULL)
|
|
|
|
ossl_print_errors();
|
|
|
|
return xp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_read_certificate(const char *name, const char *format, X509 **out)
|
|
|
|
{
|
|
|
|
if (!format || !strcasecmp(format, "pem")) {
|
|
|
|
*out = do_read_pem_certificate(name);
|
|
|
|
} else if (!strcasecmp(format, "der")) {
|
|
|
|
*out = do_read_der_certificate(name);
|
|
|
|
} else {
|
|
|
|
fatal("Error when reading certificate. "
|
|
|
|
"File format \"%s\" not supported.\n",
|
|
|
|
format);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*out)
|
|
|
|
fatal("Unable to read certificate from %s\n", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
/*
|
|
|
|
* Handle one option
|
|
|
|
*/
|
2002-02-22 07:18:43 +00:00
|
|
|
static void
|
2002-02-23 13:38:01 +00:00
|
|
|
handle_option(int c)
|
2002-02-22 07:18:43 +00:00
|
|
|
{
|
2002-02-23 13:38:01 +00:00
|
|
|
switch (c) {
|
2002-04-02 13:28:31 +00:00
|
|
|
case 'a':
|
|
|
|
opt_authid = optarg;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
case 'C':
|
|
|
|
opt_action = ACTION_INIT;
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
opt_erase++;
|
|
|
|
break;
|
|
|
|
case 'G':
|
|
|
|
opt_action = ACTION_GENERATE_KEY;
|
|
|
|
opt_newkey = optarg;
|
|
|
|
break;
|
|
|
|
case 'S':
|
2002-03-06 17:49:47 +00:00
|
|
|
opt_action = ACTION_STORE_PRIVKEY;
|
2002-03-12 10:08:18 +00:00
|
|
|
opt_infile = optarg;
|
|
|
|
break;
|
|
|
|
case 'P':
|
2002-04-02 13:28:31 +00:00
|
|
|
opt_action = ACTION_STORE_PIN;
|
2002-03-12 10:08:18 +00:00
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
opt_action = ACTION_STORE_CERT;
|
|
|
|
opt_infile = optarg;
|
2002-02-23 13:38:01 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
opt_debug++;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
opt_format = optarg;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
opt_objectid = optarg;
|
|
|
|
break;
|
2002-04-02 13:28:31 +00:00
|
|
|
case 'l':
|
|
|
|
opt_objectlabel = optarg;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
case 'o':
|
|
|
|
opt_outkey = optarg;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
opt_profile = optarg;
|
|
|
|
break;
|
|
|
|
case OPT_OPTIONS:
|
|
|
|
read_options_file(optarg);
|
|
|
|
break;
|
|
|
|
case OPT_PIN1: case OPT_PUK1:
|
|
|
|
case OPT_PIN2: case OPT_PUK2:
|
|
|
|
opt_pins[c & 3] = optarg;
|
|
|
|
break;
|
|
|
|
case OPT_PASSPHRASE:
|
|
|
|
opt_passphrase = optarg;
|
|
|
|
break;
|
2002-04-02 13:28:31 +00:00
|
|
|
case OPT_PUBKEY:
|
|
|
|
opt_action = ACTION_STORE_PUBKEY;
|
|
|
|
opt_infile = optarg;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
default:
|
|
|
|
print_usage_and_die("pkcs15-init");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the command line.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
parse_commandline(int argc, char **argv)
|
|
|
|
{
|
|
|
|
const struct option *o;
|
|
|
|
char shortopts[64], *sp;
|
|
|
|
int c, i;
|
|
|
|
|
|
|
|
/* We make sure the list of short options is always
|
|
|
|
* consistent with the long options */
|
|
|
|
for (o = options, sp = shortopts; o->name; o++) {
|
|
|
|
if (o->val <= 0 || o->val >= 256)
|
|
|
|
continue;
|
|
|
|
*sp++ = o->val;
|
|
|
|
switch (o->has_arg) {
|
|
|
|
case optional_argument:
|
|
|
|
*sp++ = ':';
|
|
|
|
case required_argument:
|
|
|
|
*sp++ = ':';
|
|
|
|
case no_argument:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fatal("Internal: bad has_arg value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sp[0] = 0;
|
|
|
|
|
|
|
|
while ((c = getopt_long(argc, argv, shortopts, options, &i)) != -1)
|
|
|
|
handle_option(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a file containing more command line options.
|
|
|
|
* This allows you to specify PINs to pkcs15-init without
|
|
|
|
* exposing them through ps.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
read_options_file(const char *filename)
|
|
|
|
{
|
|
|
|
const struct option *o;
|
|
|
|
char buffer[1024], *name;
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
if ((fp = fopen(filename, "r")) == NULL)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
|
|
|
|
buffer[strcspn(buffer, "\n")] = '\0';
|
|
|
|
|
|
|
|
name = strtok(buffer, " \t");
|
|
|
|
while (name) {
|
|
|
|
if (*name == '#')
|
|
|
|
break;
|
|
|
|
for (o = options; o->name; o++)
|
|
|
|
if (!strcmp(o->name, name))
|
|
|
|
break;
|
|
|
|
if (!o->name) {
|
|
|
|
error("Unknown option \"%s\"\n", name);
|
|
|
|
print_usage_and_die("pkcs15-init");
|
|
|
|
}
|
|
|
|
if (o->has_arg != no_argument) {
|
|
|
|
optarg = strtok(NULL, "");
|
|
|
|
if (optarg) {
|
2002-03-24 12:14:19 +00:00
|
|
|
while (isspace((int) *optarg))
|
2002-02-23 13:38:01 +00:00
|
|
|
optarg++;
|
|
|
|
optarg = strdup(optarg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (o->has_arg == required_argument
|
|
|
|
&& (!optarg || !*optarg)) {
|
|
|
|
error("Option %s: missing argument\n", name);
|
|
|
|
print_usage_and_die("pkcs15-init");
|
|
|
|
}
|
|
|
|
handle_option(o->val);
|
|
|
|
name = strtok(NULL, " \t");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* OpenSSL helpers
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ossl_print_errors()
|
|
|
|
{
|
|
|
|
static int loaded = 0;
|
|
|
|
long err;
|
|
|
|
|
|
|
|
if (!loaded) {
|
|
|
|
ERR_load_crypto_strings();
|
|
|
|
loaded = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((err = ERR_get_error()) != 0)
|
2002-03-12 16:27:21 +00:00
|
|
|
fprintf(stderr, "%s\n", ERR_error_string(err, NULL));
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|