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-04-15 13:42:10 +00:00
|
|
|
#include <openssl/dsa.h>
|
|
|
|
#include <openssl/bn.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-12-04 11:56:51 +00:00
|
|
|
#undef GET_KEY_ECHO_OFF
|
|
|
|
|
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 */
|
2003-02-28 11:07:37 +00:00
|
|
|
static int open_reader_and_card(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 *);
|
2002-04-15 13:42:10 +00:00
|
|
|
static int do_store_private_key(struct sc_profile *);
|
|
|
|
static int do_store_public_key(struct sc_profile *, EVP_PKEY *);
|
|
|
|
static int do_store_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 *);
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-12-18 10:17:01 +00:00
|
|
|
static int do_read_data_object(const char *name, u8 **out, size_t *outlen);
|
|
|
|
static int do_convert_data_object(struct sc_context *ctx, sc_pkcs15_der_t *der, u8 *data,size_t datalen);
|
|
|
|
static int do_store_data_object(struct sc_profile *profile);
|
|
|
|
extern int asn1_encode_data_object(struct sc_context *ctx, u8 *dataobj,size_t datalen,
|
|
|
|
u8 **buf, size_t *buflen, int depth);
|
2002-04-02 13:28:31 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
static int init_keyargs(struct sc_pkcs15init_prkeyargs *);
|
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-12-04 11:56:51 +00:00
|
|
|
static int get_key_callback(struct sc_profile *,
|
|
|
|
int method, int reference,
|
|
|
|
const u8 *, size_t, u8 *, size_t *);
|
2002-03-12 10:08:18 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
static int do_generate_key_soft(int, unsigned int, EVP_PKEY **);
|
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 **);
|
|
|
|
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-04-17 20:47:18 +00:00
|
|
|
OPT_EXTRACTABLE,
|
|
|
|
OPT_UNPROTECTED,
|
2002-04-22 18:37:57 +00:00
|
|
|
OPT_AUTHORITY,
|
2002-06-11 18:16:50 +00:00
|
|
|
OPT_SOFT_KEYGEN,
|
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,
|
2002-04-07 13:15:31 +00:00
|
|
|
OPT_SERIAL=0x10004,
|
2002-02-22 07:18:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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' },
|
2003-01-09 09:09:25 +00:00
|
|
|
{ "generate-key", required_argument, 0, 'G' },
|
|
|
|
{ "store-private-key", required_argument, 0, 'S' },
|
|
|
|
{ "store-public-key", required_argument, 0, OPT_PUBKEY },
|
|
|
|
{ "store-certificate", required_argument, 0, 'X' },
|
|
|
|
{ "store-data", required_argument, 0, 'W' },
|
|
|
|
|
|
|
|
{ "reader", required_argument, 0, 'r' },
|
2002-04-02 13:28:31 +00:00
|
|
|
{ "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 },
|
2002-04-07 13:15:31 +00:00
|
|
|
{ "serial", required_argument, 0, OPT_SERIAL },
|
2002-04-02 13:28:31 +00:00
|
|
|
{ "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-03-12 10:08:18 +00:00
|
|
|
{ "output-file", required_argument, 0, 'o' },
|
|
|
|
{ "format", required_argument, 0, 'f' },
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "passphrase", required_argument, 0, OPT_PASSPHRASE },
|
2002-04-22 18:37:57 +00:00
|
|
|
{ "authority", no_argument, 0, OPT_AUTHORITY },
|
2002-10-02 10:50:53 +00:00
|
|
|
{ "key-usage", required_argument, 0, 'u' },
|
2002-02-25 18:50:29 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
{ "extractable", no_argument, 0, OPT_EXTRACTABLE },
|
|
|
|
{ "insecure", no_argument, 0, OPT_UNPROTECTED },
|
2002-06-11 18:16:50 +00:00
|
|
|
{ "soft", no_argument, 0, OPT_SOFT_KEYGEN },
|
2002-12-04 11:56:51 +00:00
|
|
|
{ "use-default-transport-keys",
|
|
|
|
no_argument, 0, 'T' },
|
2002-04-17 20:47:18 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "profile", required_argument, 0, 'p' },
|
|
|
|
{ "options-file", required_argument, 0, OPT_OPTIONS },
|
2003-01-03 17:07:42 +00:00
|
|
|
{ "wait", no_argument, 0, 'w' },
|
2002-02-22 07:18:43 +00:00
|
|
|
{ "debug", no_argument, 0, 'd' },
|
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
const char * option_help[] = {
|
2003-01-09 09:09:25 +00:00
|
|
|
"Erase the smart card (can be used with --create-pkcs15)",
|
2002-02-22 07:18:43 +00:00
|
|
|
"Creates a new PKCS #15 structure",
|
2002-04-02 13:28:31 +00:00
|
|
|
"Store a new PIN/PUK on the card",
|
2003-01-09 09:09:25 +00:00
|
|
|
"Generate a new key and store it on the card",
|
|
|
|
"Store private key",
|
|
|
|
"Store public key",
|
|
|
|
"Store an X.509 certificate",
|
|
|
|
"Store a data object",
|
|
|
|
|
|
|
|
"Specify which reader to use",
|
2002-04-02 13:28:31 +00:00
|
|
|
"Specify PIN",
|
|
|
|
"Specify unblock PIN",
|
|
|
|
"Specify security officer (SO) PIN",
|
|
|
|
"Specify unblock PIN for SO PIN",
|
2002-04-07 13:15:31 +00:00
|
|
|
"Specify the serial number of the card",
|
2002-04-02 13:28:31 +00:00
|
|
|
"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
|
|
|
"Output public portion of generated key to file",
|
|
|
|
"Specify key file format (default PEM)",
|
2002-02-25 18:50:29 +00:00
|
|
|
"Specify passphrase for unlocking secret key",
|
2002-06-05 17:51:44 +00:00
|
|
|
"Mark certificate as a CA certificate",
|
2002-10-02 10:50:53 +00:00
|
|
|
"Specify X.509 key usage (use \"--key-usage help\" for more information)",
|
2002-02-25 18:50:29 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
"Private key stored as an extractable key",
|
|
|
|
"Insecure mode: do not require PIN/passphrase for private key",
|
2002-06-11 18:16:50 +00:00
|
|
|
"Use software key generation, even if the card supports on-board key generation",
|
2002-12-04 11:56:51 +00:00
|
|
|
"Always ask for transport keys etc, even if the driver thinks it knows the key",
|
2002-04-17 20:47:18 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
"Specify the profile to use",
|
|
|
|
"Read additional command line options from file",
|
2003-01-03 17:07:42 +00:00
|
|
|
"Wait for card insertion",
|
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-12-18 10:17:01 +00:00
|
|
|
ACTION_STORE_CERT,
|
|
|
|
ACTION_STORE_DATA
|
2002-02-23 13:38:01 +00:00
|
|
|
};
|
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",
|
2002-12-18 10:17:01 +00:00
|
|
|
"store certificate",
|
|
|
|
"store data object"
|
2002-04-02 13:28:31 +00:00
|
|
|
};
|
2002-02-23 13:38:01 +00:00
|
|
|
|
2002-09-30 20:03:10 +00:00
|
|
|
/* Flags for read_one_pin */
|
|
|
|
#define READ_PIN_OPTIONAL 0x01
|
|
|
|
#define READ_PIN_RETYPE 0x02
|
|
|
|
|
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;
|
2003-01-03 17:07:42 +00:00
|
|
|
static int opt_reader = -1,
|
2002-10-02 10:50:53 +00:00
|
|
|
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,
|
2002-04-17 20:47:18 +00:00
|
|
|
opt_extractable = 0,
|
2002-04-22 18:37:57 +00:00
|
|
|
opt_unprotected = 0,
|
2002-06-11 18:16:50 +00:00
|
|
|
opt_authority = 0,
|
2002-09-30 20:24:16 +00:00
|
|
|
opt_softkeygen = 0,
|
2002-12-04 11:56:51 +00:00
|
|
|
opt_noprompts = 0,
|
2003-01-03 17:07:42 +00:00
|
|
|
opt_use_defkeys = 0,
|
|
|
|
opt_wait = 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-12-04 14:56:50 +00:00
|
|
|
static char * opt_label = 0;
|
2002-02-22 07:18:43 +00:00
|
|
|
static char * opt_pins[4];
|
2002-04-07 13:15:31 +00:00
|
|
|
static char * opt_serial = 0;
|
2002-02-23 13:38:01 +00:00
|
|
|
static char * opt_passphrase = 0;
|
|
|
|
static char * opt_newkey = 0;
|
|
|
|
static char * opt_outkey = 0;
|
2002-10-02 10:50:53 +00:00
|
|
|
static unsigned int opt_x509_usage = 0;
|
2002-04-02 13:28:31 +00:00
|
|
|
|
|
|
|
static struct sc_pkcs15init_callbacks callbacks = {
|
|
|
|
error, /* error() */
|
|
|
|
NULL, /* debug() */
|
|
|
|
get_pin_callback, /* get_pin() */
|
2002-12-04 11:56:51 +00:00
|
|
|
get_key_callback, /* get_key() */
|
2002-04-02 13:28:31 +00:00
|
|
|
};
|
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-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)
|
2002-04-19 14:23:31 +00:00
|
|
|
print_usage_and_die();
|
2002-02-23 13:38:01 +00:00
|
|
|
if (opt_action == ACTION_NONE) {
|
|
|
|
fprintf(stderr, "No action specified.\n");
|
2002-04-19 14:23:31 +00:00
|
|
|
print_usage_and_die();
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
2002-03-04 10:33:35 +00:00
|
|
|
if (!opt_profile) {
|
|
|
|
fprintf(stderr, "No profile specified.\n");
|
2002-04-19 14:23:31 +00:00
|
|
|
print_usage_and_die();
|
2002-03-04 10:33:35 +00:00
|
|
|
}
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/* Connect to the card */
|
2003-02-28 11:07:37 +00:00
|
|
|
if (!open_reader_and_card(opt_reader))
|
2002-03-06 17:49:47 +00:00
|
|
|
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-15 13:42:10 +00:00
|
|
|
r = do_store_public_key(profile, NULL);
|
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-12-18 10:17:01 +00:00
|
|
|
else if (opt_action == ACTION_STORE_DATA)
|
|
|
|
r = do_store_data_object(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
|
2003-02-28 11:07:37 +00:00
|
|
|
open_reader_and_card(int reader)
|
2002-02-22 07:18:43 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2003-01-03 17:07:42 +00:00
|
|
|
if (connect_card(ctx, &card, reader, 0, opt_wait, opt_quiet))
|
2002-02-22 07:18:43 +00:00
|
|
|
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-09-30 20:24:16 +00:00
|
|
|
struct sc_pkcs15_pin_info info;
|
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-09-30 20:24:16 +00:00
|
|
|
if (!opt_pins[2] && !opt_noprompts) {
|
|
|
|
sc_pkcs15init_get_pin_info(profile,
|
|
|
|
SC_PKCS15INIT_SO_PIN, &info);
|
|
|
|
if (!read_one_pin(profile, "New security officer (SO) PIN",
|
|
|
|
&info, READ_PIN_RETYPE|READ_PIN_OPTIONAL,
|
|
|
|
&opt_pins[2]))
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
if (opt_pins[2] && !opt_pins[3] && !opt_noprompts) {
|
|
|
|
sc_pkcs15init_get_pin_info(profile,
|
|
|
|
SC_PKCS15INIT_SO_PUK, &info);
|
|
|
|
if (!read_one_pin(profile, "Unlock code for new SO PIN",
|
|
|
|
&info, READ_PIN_RETYPE|READ_PIN_OPTIONAL,
|
|
|
|
&opt_pins[3]))
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
args.so_pin = (const u8 *) opt_pins[2];
|
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);
|
2002-09-30 20:24:16 +00:00
|
|
|
args.so_puk = (const u8 *) opt_pins[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-07 13:15:31 +00:00
|
|
|
args.serial = (const char *) opt_serial;
|
2002-12-04 14:56:50 +00:00
|
|
|
args.label = opt_label;
|
2002-04-07 13:15:31 +00:00
|
|
|
|
2002-04-02 14:46:32 +00:00
|
|
|
return sc_pkcs15init_add_app(card, profile, &args);
|
2002-09-30 20:24:16 +00:00
|
|
|
|
|
|
|
failed:
|
|
|
|
return SC_ERROR_PKCS15INIT;
|
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-09-30 20:03:10 +00:00
|
|
|
if (!read_one_pin(profile, "New user PIN", &info,
|
|
|
|
READ_PIN_RETYPE,
|
|
|
|
&opt_pins[0]))
|
|
|
|
goto failed;
|
2002-04-02 13:28:31 +00:00
|
|
|
}
|
|
|
|
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,
|
2002-09-30 20:24:16 +00:00
|
|
|
SC_PKCS15INIT_USER_PUK, &info);
|
2002-09-30 20:03:10 +00:00
|
|
|
if (!read_one_pin(profile,
|
|
|
|
"Unlock code for new user PIN", &info,
|
|
|
|
READ_PIN_RETYPE|READ_PIN_OPTIONAL,
|
|
|
|
&opt_pins[1]))
|
|
|
|
goto failed;
|
2002-04-02 13:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2002-12-04 14:56:50 +00:00
|
|
|
args.label = opt_label;
|
2002-04-02 13:28:31 +00:00
|
|
|
|
|
|
|
return sc_pkcs15init_store_pin(p15card, profile, &args);
|
2002-09-30 20:03:10 +00:00
|
|
|
|
|
|
|
failed:
|
|
|
|
return SC_ERROR_PKCS15INIT;
|
2002-04-02 13:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/*
|
|
|
|
* Store a private key
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_store_private_key(struct sc_profile *profile)
|
|
|
|
{
|
2002-04-15 13:42:10 +00:00
|
|
|
struct sc_pkcs15init_prkeyargs args;
|
|
|
|
EVP_PKEY *pkey = NULL;
|
|
|
|
X509 *cert = NULL;
|
2002-03-06 17:49:47 +00:00
|
|
|
int r;
|
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
if ((r = init_keyargs(&args)) < 0)
|
|
|
|
return r;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
r = do_read_private_key(opt_infile, opt_format, &pkey, &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
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
if ((r = do_convert_private_key(&args.key, pkey)) < 0)
|
|
|
|
return r;
|
2002-10-02 10:50:53 +00:00
|
|
|
if (cert) {
|
|
|
|
/* If the user requested a specific key usage on the
|
|
|
|
* command line check if it includes _more_
|
|
|
|
* usage bits than the one specified by the cert */
|
|
|
|
if (~cert->ex_kusage & opt_x509_usage) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning: requested key usage incompatible with "
|
|
|
|
"key usage specified by X.509 certificate\n");
|
|
|
|
}
|
2002-04-15 13:42:10 +00:00
|
|
|
args.x509_usage = cert->ex_kusage;
|
2002-10-02 10:50:53 +00:00
|
|
|
}
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2002-04-11 15:14:40 +00:00
|
|
|
r = sc_pkcs15init_store_private_key(p15card, profile, &args, NULL);
|
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.
|
|
|
|
*/
|
2002-04-15 13:42:10 +00:00
|
|
|
if (cert) {
|
2002-03-12 16:27:21 +00:00
|
|
|
struct sc_pkcs15init_certargs cargs;
|
|
|
|
|
|
|
|
memset(&cargs, 0, sizeof(cargs));
|
|
|
|
cargs.id = args.id;
|
2002-04-15 13:42:10 +00:00
|
|
|
cargs.x509_usage = cert->ex_kusage;
|
|
|
|
r = do_convert_cert(&cargs.der_encoded, cert);
|
|
|
|
if (r >= 0)
|
|
|
|
r = sc_pkcs15init_store_certificate(p15card, profile,
|
2002-04-11 15:14:40 +00:00
|
|
|
&cargs, NULL);
|
2002-04-15 13:42:10 +00:00
|
|
|
free(cargs.der_encoded.value);
|
2002-03-12 16:27:21 +00:00
|
|
|
} else {
|
2002-04-15 13:42:10 +00:00
|
|
|
r = do_store_public_key(profile, pkey);
|
2002-03-12 16:27:21 +00:00
|
|
|
}
|
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
|
2002-04-15 13:42:10 +00:00
|
|
|
do_store_public_key(struct sc_profile *profile, EVP_PKEY *pkey)
|
2002-03-06 17:49:47 +00:00
|
|
|
{
|
2002-04-15 13:42:10 +00:00
|
|
|
struct sc_pkcs15init_pubkeyargs args;
|
|
|
|
int r = 0;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
if (opt_objectid)
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &args.id);
|
2002-12-04 14:56:50 +00:00
|
|
|
args.label = opt_label;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
if (pkey == NULL)
|
|
|
|
r = do_read_public_key(opt_infile, opt_format, &pkey);
|
|
|
|
if (r >= 0)
|
|
|
|
r = do_convert_public_key(&args.key, pkey);
|
2002-04-02 13:28:31 +00:00
|
|
|
if (r >= 0)
|
2002-04-11 15:14:40 +00:00
|
|
|
r = sc_pkcs15init_store_public_key(p15card, profile,
|
|
|
|
&args, NULL);
|
2002-03-07 12:26:17 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
return r;
|
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;
|
2002-04-15 13:42:10 +00:00
|
|
|
X509 *cert;
|
2002-03-12 10:08:18 +00:00
|
|
|
int r;
|
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
|
|
|
|
if (opt_objectid)
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &args.id);
|
2002-12-04 14:56:50 +00:00
|
|
|
args.label = opt_label;
|
2002-04-22 18:37:57 +00:00
|
|
|
args.authority = opt_authority;
|
2002-03-12 10:08:18 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
r = do_read_certificate(opt_infile, opt_format, &cert);
|
|
|
|
if (r >= 0)
|
|
|
|
r = do_convert_cert(&args.der_encoded, cert);
|
2002-04-02 13:28:31 +00:00
|
|
|
if (r >= 0)
|
2002-04-11 15:14:40 +00:00
|
|
|
r = sc_pkcs15init_store_certificate(p15card, profile,
|
|
|
|
&args, NULL);
|
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-12-18 10:17:01 +00:00
|
|
|
/*
|
|
|
|
* Download data object to card
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_store_data_object(struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15init_dataargs args;
|
|
|
|
u8 *data;
|
|
|
|
size_t datalen;
|
|
|
|
int r=0;
|
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
|
|
|
|
if (opt_objectid)
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &args.id);
|
|
|
|
args.label = opt_label;
|
|
|
|
|
|
|
|
r = do_read_data_object(opt_infile, &data, &datalen);
|
|
|
|
if (r >= 0)
|
|
|
|
r = do_convert_data_object(p15card->card->ctx, &args.der_encoded, data, datalen);
|
|
|
|
if (r >= 0)
|
|
|
|
r = sc_pkcs15init_store_data_object(p15card, profile,
|
|
|
|
&args, NULL);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
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-15 13:42:10 +00:00
|
|
|
struct sc_pkcs15init_prkeyargs args;
|
|
|
|
unsigned int evp_algo, keybits = 1024;
|
2002-06-11 18:16:50 +00:00
|
|
|
EVP_PKEY *pkey;
|
2002-03-06 17:49:47 +00:00
|
|
|
int r;
|
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
if ((r = init_keyargs(&args)) < 0)
|
|
|
|
return r;
|
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/* Parse the key spec given on the command line */
|
|
|
|
if (!strncasecmp(spec, "rsa", 3)) {
|
2002-04-15 13:42:10 +00:00
|
|
|
args.key.algorithm = SC_ALGORITHM_RSA;
|
|
|
|
evp_algo = EVP_PKEY_RSA;
|
2002-03-06 17:49:47 +00:00
|
|
|
spec += 3;
|
|
|
|
} else if (!strncasecmp(spec, "dsa", 3)) {
|
2002-04-15 13:42:10 +00:00
|
|
|
args.key.algorithm = SC_ALGORITHM_DSA;
|
|
|
|
evp_algo = EVP_PKEY_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;
|
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
keybits = strtoul(spec, &end, 10);
|
2002-04-02 13:28:31 +00:00
|
|
|
if (*end) {
|
|
|
|
error("Invalid number of key bits \"%s\"", spec);
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2002-03-06 17:49:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-11 18:16:50 +00:00
|
|
|
if (!opt_softkeygen) {
|
|
|
|
r = sc_pkcs15init_generate_key(p15card, profile,
|
|
|
|
&args, keybits, NULL);
|
|
|
|
if (r >= 0 || r != SC_ERROR_NOT_SUPPORTED)
|
2002-04-15 13:42:10 +00:00
|
|
|
return r;
|
2002-03-06 17:49:47 +00:00
|
|
|
if (!opt_quiet)
|
|
|
|
printf("Warning: card doesn't support on-board "
|
2002-10-02 10:50:53 +00:00
|
|
|
"key generation.\n"
|
|
|
|
"Trying software generation\n");
|
2002-06-11 18:16:50 +00:00
|
|
|
}
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-06-11 18:16:50 +00:00
|
|
|
/* Generate the key ourselves */
|
|
|
|
r = do_generate_key_soft(evp_algo, keybits, &pkey);
|
|
|
|
if (r >= 0) {
|
|
|
|
r = do_convert_private_key(&args.key, pkey);
|
|
|
|
}
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2002-06-11 18:16:50 +00:00
|
|
|
if (r >= 0)
|
|
|
|
r = sc_pkcs15init_store_private_key(p15card, profile,
|
|
|
|
&args, NULL);
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2002-06-11 18:16:50 +00:00
|
|
|
/* Store public key portion on card */
|
|
|
|
if (r >= 0)
|
|
|
|
r = do_store_public_key(profile, pkey);
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2002-06-11 18:16:50 +00:00
|
|
|
EVP_PKEY_free(pkey);
|
2002-03-12 10:08:18 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
int
|
|
|
|
init_keyargs(struct sc_pkcs15init_prkeyargs *args)
|
|
|
|
{
|
|
|
|
memset(args, 0, sizeof(*args));
|
|
|
|
if (opt_objectid)
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &args->id);
|
|
|
|
if (opt_authid) {
|
|
|
|
sc_pkcs15_format_id(opt_authid, &args->auth_id);
|
|
|
|
} else if (!opt_unprotected) {
|
2002-06-05 17:51:44 +00:00
|
|
|
error("no PIN given for key - either use --insecure or \n"
|
2002-04-17 20:47:18 +00:00
|
|
|
"specify a PIN using --auth-id");
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
if (opt_extractable) {
|
|
|
|
args->extractable |= SC_PKCS15INIT_EXTRACTABLE;
|
|
|
|
if (opt_passphrase) {
|
|
|
|
args->passphrase = opt_passphrase;
|
|
|
|
} else {
|
|
|
|
if (!opt_unprotected) {
|
|
|
|
error("no pass phrase given for key - "
|
2002-06-05 17:51:44 +00:00
|
|
|
"either use --insecure or\n"
|
2002-04-17 20:47:18 +00:00
|
|
|
"specify a pass phrase using "
|
|
|
|
"--passphrase");
|
|
|
|
return SC_ERROR_PASSPHRASE_REQUIRED;
|
|
|
|
}
|
|
|
|
args->extractable |= SC_PKCS15INIT_NO_PASSPHRASE;
|
|
|
|
}
|
|
|
|
}
|
2002-12-04 14:56:50 +00:00
|
|
|
args->label = opt_label;
|
2002-10-02 10:50:53 +00:00
|
|
|
args->x509_usage = opt_x509_usage;
|
2002-04-17 20:47:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2002-03-12 10:08:18 +00:00
|
|
|
|
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,
|
2002-09-30 20:03:10 +00:00
|
|
|
int flags, char **out)
|
2002-03-11 14:13:11 +00:00
|
|
|
{
|
2002-04-02 13:28:31 +00:00
|
|
|
char *pin;
|
|
|
|
size_t len;
|
2002-09-30 20:03:10 +00:00
|
|
|
int retries = 5;
|
2002-03-11 14:13:11 +00:00
|
|
|
|
2002-09-30 20:24:16 +00:00
|
|
|
printf("%s required", name);
|
|
|
|
if (flags & READ_PIN_OPTIONAL)
|
|
|
|
printf(" (press return for no PIN)");
|
|
|
|
printf(".\n");
|
|
|
|
|
|
|
|
*out = NULL;
|
2002-09-30 20:03:10 +00:00
|
|
|
while (retries--) {
|
|
|
|
pin = getpass("Please enter PIN: ");
|
2002-12-04 11:56:51 +00:00
|
|
|
if (pin == NULL)
|
|
|
|
return SC_ERROR_INTERNAL;
|
2002-04-02 13:28:31 +00:00
|
|
|
len = strlen(pin);
|
2002-09-30 20:03:10 +00:00
|
|
|
if (len == 0 && (flags & READ_PIN_OPTIONAL))
|
2002-09-30 20:24:16 +00:00
|
|
|
break;
|
2002-09-30 20:03:10 +00:00
|
|
|
|
|
|
|
if (info && 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;
|
|
|
|
}
|
2003-02-20 23:19:01 +00:00
|
|
|
if (info && len > info->max_length) {
|
2002-03-02 14:03:41 +00:00
|
|
|
error("Password too long (%u characters max)",
|
2003-02-20 23:19:01 +00:00
|
|
|
info->max_length);
|
2002-02-22 07:18:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2002-09-30 20:03:10 +00:00
|
|
|
*out = strdup(pin);
|
|
|
|
if (flags & READ_PIN_RETYPE) {
|
|
|
|
memset(pin, 0, len);
|
|
|
|
pin = getpass("Please type again to verify: ");
|
|
|
|
if (strcmp(*out, pin)) {
|
|
|
|
fprintf(stderr, "PINs do not match; "
|
|
|
|
"please try again.\n");
|
|
|
|
free(*out);
|
|
|
|
*out = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memset(pin, 0, len);
|
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
|
|
|
|
2002-09-30 20:03:10 +00:00
|
|
|
if (retries < 0) {
|
|
|
|
error("Giving up.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
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-12-04 11:56:51 +00:00
|
|
|
int
|
|
|
|
get_key_callback(struct sc_profile *profile,
|
|
|
|
int method, int reference,
|
|
|
|
const u8 *def_key, size_t def_key_size,
|
|
|
|
u8 *key_buf, size_t *buf_size)
|
|
|
|
{
|
|
|
|
const char *kind, *prompt, *key;
|
|
|
|
|
|
|
|
if (def_key_size && opt_use_defkeys) {
|
|
|
|
use_default_key:
|
|
|
|
if (*buf_size < def_key_size)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
memcpy(key_buf, def_key, def_key_size);
|
|
|
|
*buf_size = def_key_size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case SC_AC_PRO:
|
|
|
|
kind = "Secure messaging key";
|
|
|
|
break;
|
|
|
|
case SC_AC_AUT:
|
|
|
|
kind = "External authentication key";
|
|
|
|
break;
|
|
|
|
default: /* don't really know what sort of key */
|
|
|
|
kind = "Key";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Transport key (%s #%d) required.\n", kind, reference);
|
|
|
|
printf("Please enter key in hexadecimal notation "
|
|
|
|
"(e.g. 00:11:22:aa:bb:cc)%s\n",
|
|
|
|
def_key_size? ",\n or press return to accept default" : "");
|
2002-12-18 11:34:35 +00:00
|
|
|
printf("To use the default transport keys without being prompted,\n"
|
|
|
|
"specify the --use-default-transport-keys option on the\n"
|
|
|
|
"command line (or -T for short).\n");
|
2002-12-04 11:56:51 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
prompt = "Please enter key";
|
|
|
|
if (def_key_size && def_key_size < 64) {
|
|
|
|
unsigned int j, k = 0;
|
|
|
|
|
|
|
|
sprintf(buffer, "%s [", prompt);
|
|
|
|
k = strlen(buffer);
|
|
|
|
for (j = 0; j < def_key_size; j++, k += 2) {
|
|
|
|
if (j) buffer[k++] = ':';
|
|
|
|
sprintf(buffer+k, "%02x", def_key[j]);
|
|
|
|
}
|
|
|
|
buffer[k++] = ']';
|
|
|
|
buffer[k++] = '\0';
|
|
|
|
prompt = buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GET_KEY_ECHO_OFF
|
|
|
|
/* Read key with echo off - will users really manage? */
|
|
|
|
key = getpass(prompt);
|
|
|
|
#else
|
|
|
|
printf("%s: ", prompt);
|
|
|
|
fflush(stdout);
|
|
|
|
key = fgets(buffer, sizeof(buffer), stdin);
|
|
|
|
if (key)
|
|
|
|
buffer[strcspn(buffer, "\r\n")] = '\0';
|
|
|
|
#endif
|
|
|
|
if (key == NULL)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
|
|
|
if (key[0] == '\0' && def_key_size)
|
|
|
|
goto use_default_key;
|
|
|
|
|
|
|
|
if (sc_hex_to_bin(key, key_buf, buf_size) >= 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
/*
|
|
|
|
* Generate a private key
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
do_generate_key_soft(int algorithm, unsigned int bits, EVP_PKEY **res)
|
|
|
|
{
|
|
|
|
*res = EVP_PKEY_new();
|
|
|
|
switch (algorithm) {
|
|
|
|
case EVP_PKEY_RSA: {
|
|
|
|
RSA *rsa;
|
|
|
|
BIO *err;
|
|
|
|
|
|
|
|
err = BIO_new(BIO_s_mem());
|
|
|
|
rsa = RSA_generate_key(bits, 0x10001, NULL, err);
|
|
|
|
BIO_free(err);
|
|
|
|
if (rsa == 0)
|
|
|
|
fatal("RSA key generation error");
|
|
|
|
EVP_PKEY_assign_RSA(*res, rsa);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EVP_PKEY_DSA: {
|
|
|
|
DSA *dsa;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
dsa = DSA_generate_parameters(bits,
|
|
|
|
NULL, 0, NULL,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
if (dsa)
|
|
|
|
r = DSA_generate_key(dsa);
|
|
|
|
if (r == 0 || dsa == 0)
|
|
|
|
fatal("DSA key generation error");
|
|
|
|
EVP_PKEY_assign_DSA(*res, dsa);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
fatal("Unable to generate key: unsupported algorithm");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
#if 0
|
2002-03-12 10:08:18 +00:00
|
|
|
/*
|
|
|
|
* 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-04-15 13:42:10 +00:00
|
|
|
#endif
|
2002-02-23 13:38:01 +00:00
|
|
|
|
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-12-18 10:17:01 +00:00
|
|
|
static int determine_filesize(const char *filename) {
|
|
|
|
FILE *fp;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
if ((fp = fopen(filename,"r")) == NULL) {
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
|
|
|
}
|
|
|
|
fseek(fp,0L,SEEK_END);
|
|
|
|
size = ftell(fp);
|
|
|
|
fclose(fp);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_read_data_object(const char *name, u8 **out, size_t *outlen)
|
|
|
|
{
|
|
|
|
FILE *inf;
|
|
|
|
size_t filesize = determine_filesize(name);
|
|
|
|
int c;
|
|
|
|
|
2003-01-14 19:55:45 +00:00
|
|
|
*out = (u8 *) malloc(filesize);
|
2002-12-18 10:17:01 +00:00
|
|
|
if (*out == NULL) {
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
inf = fopen(name, "r");
|
|
|
|
if (inf == NULL) {
|
|
|
|
fprintf(stderr, "Unable to open '%s' for reading.\n", name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
c = fread(*out, 1, filesize, inf);
|
|
|
|
fclose(inf);
|
|
|
|
if (c < 0) {
|
|
|
|
perror("read");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*outlen = filesize;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
static int
|
|
|
|
do_convert_bignum(sc_pkcs15_bignum_t *dst, BIGNUM *src)
|
|
|
|
{
|
|
|
|
if (src == 0)
|
|
|
|
return 0;
|
|
|
|
dst->len = BN_num_bytes(src);
|
2002-04-19 14:23:31 +00:00
|
|
|
dst->data = (u8 *) malloc(dst->len);
|
2002-04-15 13:42:10 +00:00
|
|
|
BN_bn2bin(src, dst->data);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
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);
|
2002-04-17 20:47:18 +00:00
|
|
|
break;
|
2002-04-15 13:42:10 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
fatal("Unsupported key algorithm\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
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);
|
2002-04-18 09:12:54 +00:00
|
|
|
do_convert_bignum(&dst->p, src->p);
|
|
|
|
do_convert_bignum(&dst->q, src->q);
|
|
|
|
do_convert_bignum(&dst->g, src->g);
|
2002-04-15 13:42:10 +00:00
|
|
|
DSA_free(src);
|
2002-04-18 09:12:54 +00:00
|
|
|
break;
|
2002-04-15 13:42:10 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
fatal("Unsupported key algorithm\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-12-18 10:17:01 +00:00
|
|
|
int
|
|
|
|
do_convert_data_object(struct sc_context *ctx, sc_pkcs15_der_t *der,
|
|
|
|
u8 *data,size_t datalen)
|
|
|
|
{
|
|
|
|
return asn1_encode_data_object(ctx, data, datalen, &der->value, &der->len, 0);
|
|
|
|
}
|
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
int
|
|
|
|
do_convert_cert(sc_pkcs15_der_t *der, X509 *cert)
|
|
|
|
{
|
2002-04-19 14:23:31 +00:00
|
|
|
u8 *p;
|
2002-04-15 13:42:10 +00:00
|
|
|
|
|
|
|
der->len = i2d_X509(cert, NULL);
|
2002-04-19 14:23:31 +00:00
|
|
|
der->value = p = (u8 *) malloc(der->len);
|
2002-04-15 13:42:10 +00:00
|
|
|
i2d_X509(cert, &p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-10-02 10:50:53 +00:00
|
|
|
/*
|
|
|
|
* Parse X.509 key usage list
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
parse_x509_usage(const char *list, unsigned int *res)
|
|
|
|
{
|
|
|
|
static const char * x509_usage_names[] = {
|
|
|
|
"digitalSignature",
|
|
|
|
"nonRepudiation",
|
|
|
|
"keyEncipherment",
|
|
|
|
"dataEncipherment",
|
|
|
|
"keyAgreement",
|
|
|
|
"keyCertSign",
|
|
|
|
"cRLSign",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static struct {
|
|
|
|
const char * name;
|
|
|
|
const char * list;
|
|
|
|
} x509_usage_aliases[] = {
|
|
|
|
{ "sign", "digitalSignature,nonRepudiation,keyCertSign,cRLSign" },
|
|
|
|
{ "decrypt", "keyEncipherment,dataEncipherment" },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int len, n, match = 0;
|
|
|
|
|
|
|
|
while (*list == ',')
|
|
|
|
list++;
|
|
|
|
if (!*list)
|
|
|
|
break;
|
|
|
|
len = strcspn(list, ",");
|
|
|
|
if (len == 4 && !strncasecmp(list, "help", 4)) {
|
2002-10-02 10:55:52 +00:00
|
|
|
printf("Valid X.509 usage names (case-insensitive):\n");
|
2002-10-02 10:50:53 +00:00
|
|
|
for (n = 0; x509_usage_names[n]; n++)
|
2002-10-02 10:55:52 +00:00
|
|
|
printf(" %s\n", x509_usage_names[n]);
|
2002-10-02 10:50:53 +00:00
|
|
|
printf("\nAliases:\n");
|
|
|
|
for (n = 0; x509_usage_aliases[n].name; n++) {
|
|
|
|
printf(" %-12s %s\n",
|
|
|
|
x509_usage_aliases[n].name,
|
|
|
|
x509_usage_aliases[n].list);
|
|
|
|
}
|
2002-10-02 10:55:52 +00:00
|
|
|
printf("\nUse commas to separate several usage names.\n"
|
|
|
|
"Abbreviated names are okay if unique (e.g. dataEnc)\n");
|
2002-10-02 10:50:53 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
for (n = 0; x509_usage_names[n]; n++) {
|
|
|
|
if (!strncasecmp(x509_usage_names[n], list, len)) {
|
|
|
|
*res |= (1 << n);
|
|
|
|
match++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (n = 0; x509_usage_aliases[n].name; n++) {
|
|
|
|
if (!strncasecmp(x509_usage_aliases[n].name, list, len)) {
|
|
|
|
parse_x509_usage(x509_usage_aliases[n].list, res);
|
|
|
|
match++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (match == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Unknown X.509 key usage %.*s\n", len, list);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (match > 1) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Ambiguous X.509 key usage %.*s\n", len, list);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
list += len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-12-18 10:17:01 +00:00
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
opt_action = ACTION_STORE_DATA;
|
|
|
|
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':
|
2002-12-04 14:56:50 +00:00
|
|
|
opt_label = optarg;
|
2002-04-02 13:28:31 +00:00
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
case 'o':
|
|
|
|
opt_outkey = optarg;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
opt_profile = optarg;
|
|
|
|
break;
|
2002-10-02 10:50:53 +00:00
|
|
|
case 'r':
|
|
|
|
opt_reader = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
parse_x509_usage(optarg, &opt_x509_usage);
|
|
|
|
break;
|
2003-01-06 12:06:50 +00:00
|
|
|
case 'w':
|
|
|
|
opt_wait = 1;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
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;
|
2002-04-07 13:15:31 +00:00
|
|
|
case OPT_SERIAL:
|
|
|
|
opt_serial = optarg;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
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-04-17 20:47:18 +00:00
|
|
|
case OPT_UNPROTECTED:
|
|
|
|
opt_unprotected++;
|
|
|
|
break;
|
|
|
|
case OPT_EXTRACTABLE:
|
|
|
|
opt_extractable++;
|
|
|
|
break;
|
2002-04-22 18:37:57 +00:00
|
|
|
case OPT_AUTHORITY:
|
|
|
|
opt_authority = 1;
|
|
|
|
break;
|
2002-06-11 18:16:50 +00:00
|
|
|
case OPT_SOFT_KEYGEN:
|
|
|
|
opt_softkeygen = 1;
|
|
|
|
break;
|
2002-12-04 11:56:51 +00:00
|
|
|
case 'T':
|
|
|
|
opt_use_defkeys = 1;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
default:
|
2002-04-19 14:23:31 +00:00
|
|
|
print_usage_and_die();
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
2002-04-19 14:23:31 +00:00
|
|
|
print_usage_and_die();
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
|
|
|
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);
|
2002-04-19 14:23:31 +00:00
|
|
|
print_usage_and_die();
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
}
|