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>
|
2003-04-11 11:47:41 +00:00
|
|
|
#include <opensc/cardctl.h>
|
2002-04-05 13:48:00 +00:00
|
|
|
#include <opensc/pkcs15.h>
|
|
|
|
#include <opensc/pkcs15-init.h>
|
2003-10-13 16:13:12 +00:00
|
|
|
#include <opensc/log.h>
|
2003-10-24 13:20:18 +00:00
|
|
|
#include <opensc/ui.h>
|
2002-02-22 07:18:43 +00:00
|
|
|
#include "util.h"
|
|
|
|
|
2003-04-11 11:47:41 +00:00
|
|
|
|
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);
|
2003-05-16 19:12:54 +00:00
|
|
|
static int do_assert_pristine(struct sc_card *);
|
2003-05-15 15:29:42 +00:00
|
|
|
static int do_erase(struct sc_card *, struct sc_profile *);
|
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_store_data_object(struct sc_profile *profile);
|
2002-04-02 13:28:31 +00:00
|
|
|
|
2003-05-18 10:08:26 +00:00
|
|
|
static void set_secrets(struct sc_profile *);
|
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 get_pin_callback(struct sc_profile *profile,
|
|
|
|
int id, const struct sc_pkcs15_pin_info *info,
|
2003-05-15 11:31:46 +00:00
|
|
|
const char *label,
|
2002-04-02 13:28:31 +00:00
|
|
|
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 *,
|
2003-04-16 11:50:49 +00:00
|
|
|
EVP_PKEY **, X509 **, unsigned int);
|
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,
|
2003-04-17 12:38:08 +00:00
|
|
|
OPT_SPLIT_KEY,
|
2003-05-16 19:12:54 +00:00
|
|
|
OPT_ASSERT_PRISTINE,
|
2003-05-18 10:08:26 +00:00
|
|
|
OPT_SECRET,
|
2002-02-23 13:38:01 +00:00
|
|
|
|
2003-05-14 16:22:14 +00:00
|
|
|
OPT_PIN1 = 0x10000, /* don't touch these values */
|
|
|
|
OPT_PUK1 = 0x10001,
|
|
|
|
OPT_PIN2 = 0x10002,
|
|
|
|
OPT_PUK2 = 0x10003,
|
|
|
|
OPT_SERIAL = 0x10004,
|
|
|
|
OPT_NO_SOPIN = 0x10005,
|
2003-05-15 13:33:31 +00:00
|
|
|
OPT_NO_PROMPT= 0x10006,
|
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 },
|
2003-05-14 16:22:14 +00:00
|
|
|
{ "no-so-pin", no_argument, 0, OPT_NO_SOPIN },
|
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' },
|
2003-04-17 12:38:08 +00:00
|
|
|
{ "split-key", no_argument, 0, OPT_SPLIT_KEY },
|
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' },
|
2003-05-15 13:33:31 +00:00
|
|
|
{ "no-prompt", no_argument, 0, OPT_NO_PROMPT },
|
2002-04-17 20:47:18 +00:00
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "profile", required_argument, 0, 'p' },
|
2003-06-18 08:07:12 +00:00
|
|
|
{ "card-profile", required_argument, 0, 'c' },
|
2002-02-23 13:38:01 +00:00
|
|
|
{ "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' },
|
2003-05-16 19:12:54 +00:00
|
|
|
{ "quiet", no_argument, 0, 'q' },
|
2003-05-18 10:08:26 +00:00
|
|
|
{ "help", no_argument, 0, 'h' },
|
2003-05-16 19:12:54 +00:00
|
|
|
|
|
|
|
/* Hidden options for testing */
|
|
|
|
{ "assert-pristine", no_argument, 0, OPT_ASSERT_PRISTINE },
|
2003-05-18 10:08:26 +00:00
|
|
|
{ "secret", required_argument, 0, OPT_SECRET },
|
2002-02-22 07:18:43 +00:00
|
|
|
{ 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",
|
2003-05-14 16:22:14 +00:00
|
|
|
"Do not install a SO PIN, and dont prompt for it",
|
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)",
|
2003-04-17 12:38:08 +00:00
|
|
|
"Automatically create two keys with same ID and different usage (sign vs decipher)",
|
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",
|
2003-05-15 15:29:42 +00:00
|
|
|
"Do not prompt the user, except for PINs",
|
2002-04-17 20:47:18 +00:00
|
|
|
|
2003-06-18 08:07:12 +00:00
|
|
|
"Specify the general profile to use",
|
2003-10-13 16:13:12 +00:00
|
|
|
"Specify the card profile to use",
|
2002-02-23 13:38:01 +00:00
|
|
|
"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",
|
2003-05-16 19:12:54 +00:00
|
|
|
"Be less verbose",
|
2003-05-18 10:08:26 +00:00
|
|
|
"Display this message",
|
2003-05-16 19:12:54 +00:00
|
|
|
|
|
|
|
NULL,
|
2003-05-18 10:08:26 +00:00
|
|
|
NULL,
|
2002-02-22 07:18:43 +00:00
|
|
|
};
|
|
|
|
|
2002-02-23 13:38:01 +00:00
|
|
|
enum {
|
|
|
|
ACTION_NONE = 0,
|
2003-05-16 19:12:54 +00:00
|
|
|
ACTION_ASSERT_PRISTINE,
|
2003-05-15 15:29:42 +00:00
|
|
|
ACTION_ERASE,
|
2002-02-23 13:38:01 +00:00
|
|
|
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,
|
2003-05-16 19:12:54 +00:00
|
|
|
ACTION_STORE_DATA,
|
|
|
|
|
|
|
|
ACTION_MAX
|
2002-02-23 13:38:01 +00:00
|
|
|
};
|
2002-04-02 13:28:31 +00:00
|
|
|
static char * action_names[] = {
|
|
|
|
"do nothing",
|
2003-05-16 19:12:54 +00:00
|
|
|
"verify that card is pristine",
|
2003-05-15 15:29:42 +00:00
|
|
|
"erase card",
|
2002-04-02 13:28:31 +00:00
|
|
|
"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
|
|
|
|
2003-05-15 15:29:42 +00:00
|
|
|
#define MAX_CERTS 4
|
2003-05-18 10:08:26 +00:00
|
|
|
#define MAX_SECRETS 16
|
|
|
|
struct secret {
|
|
|
|
int type;
|
|
|
|
int reference;
|
|
|
|
sc_pkcs15_id_t id;
|
|
|
|
unsigned char key[64];
|
|
|
|
size_t len;
|
|
|
|
};
|
2003-05-15 15:29:42 +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;
|
2003-05-16 19:12:54 +00:00
|
|
|
static unsigned int opt_actions;
|
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,
|
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,
|
2003-05-15 13:33:31 +00:00
|
|
|
opt_no_prompt = 0,
|
2003-05-14 16:22:14 +00:00
|
|
|
opt_no_sopin = 0,
|
2003-01-03 17:07:42 +00:00
|
|
|
opt_use_defkeys = 0,
|
2003-04-17 12:38:08 +00:00
|
|
|
opt_split_key = 0,
|
2003-01-03 17:07:42 +00:00
|
|
|
opt_wait = 0;
|
2002-03-06 17:49:47 +00:00
|
|
|
static char * opt_profile = "pkcs15";
|
2003-06-18 08:07:12 +00:00
|
|
|
static char * opt_card_profile = NULL;
|
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;
|
2003-05-15 15:29:42 +00:00
|
|
|
static int ignore_cmdline_pins = 0;
|
2003-05-18 10:08:26 +00:00
|
|
|
static struct secret opt_secrets[MAX_SECRETS];
|
|
|
|
static unsigned int opt_secret_count;
|
2002-04-02 13:28:31 +00:00
|
|
|
|
|
|
|
static struct sc_pkcs15init_callbacks callbacks = {
|
|
|
|
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;
|
2003-05-15 15:29:42 +00:00
|
|
|
unsigned int n;
|
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();
|
2003-05-16 19:12:54 +00:00
|
|
|
if (opt_actions == 0) {
|
2002-02-23 13:38:01 +00:00
|
|
|
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 */
|
2003-06-18 08:07:12 +00:00
|
|
|
if ((r = sc_pkcs15init_bind(card, opt_profile,
|
|
|
|
opt_card_profile, &profile)) < 0)
|
2002-04-02 13:28:31 +00:00
|
|
|
return 1;
|
2002-02-23 13:38:01 +00:00
|
|
|
|
2003-05-18 10:08:26 +00:00
|
|
|
set_secrets(profile);
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
for (n = 0; n < ACTION_MAX; n++) {
|
|
|
|
unsigned int action = n;
|
|
|
|
|
|
|
|
if (!(opt_actions & (1 << action)))
|
|
|
|
continue;
|
2003-05-15 15:29:42 +00:00
|
|
|
|
|
|
|
if (action != ACTION_ERASE
|
|
|
|
&& action != ACTION_INIT
|
2003-05-16 19:12:54 +00:00
|
|
|
&& action != ACTION_ASSERT_PRISTINE
|
2003-05-15 15:29:42 +00:00
|
|
|
&& p15card == NULL) {
|
|
|
|
/* Read the PKCS15 structure from the card */
|
|
|
|
r = sc_pkcs15_bind(card, &p15card);
|
|
|
|
if (r) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"PKCS#15 initialization failed: %s\n",
|
|
|
|
sc_strerror(r));
|
|
|
|
break;
|
|
|
|
}
|
2002-02-23 13:38:01 +00:00
|
|
|
|
2003-05-15 15:29:42 +00:00
|
|
|
/* XXX: should compare card to profile here to make
|
|
|
|
* sure we're not messing things up */
|
2002-02-23 13:38:01 +00:00
|
|
|
|
2003-05-15 15:29:42 +00:00
|
|
|
if (!opt_quiet)
|
|
|
|
printf("Found %s\n", p15card->label);
|
2003-10-21 13:30:12 +00:00
|
|
|
|
|
|
|
sc_pkcs15init_set_p15card(profile, p15card);
|
2003-05-15 15:29:42 +00:00
|
|
|
}
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
if (!opt_quiet && action != ACTION_ASSERT_PRISTINE)
|
|
|
|
printf("About to %s.\n", action_names[action]);
|
|
|
|
|
2003-05-15 15:29:42 +00:00
|
|
|
switch (action) {
|
2003-05-16 19:12:54 +00:00
|
|
|
case ACTION_ASSERT_PRISTINE:
|
|
|
|
/* skip printing error message */
|
|
|
|
if ((r = do_assert_pristine(card)) < 0)
|
|
|
|
goto out;
|
|
|
|
continue;
|
2003-05-15 15:29:42 +00:00
|
|
|
case ACTION_ERASE:
|
|
|
|
r = do_erase(card, profile);
|
|
|
|
break;
|
|
|
|
case ACTION_INIT:
|
|
|
|
r = do_init_app(profile);
|
|
|
|
break;
|
|
|
|
case ACTION_STORE_PIN:
|
|
|
|
r = do_store_pin(profile);
|
|
|
|
break;
|
|
|
|
case ACTION_STORE_PRIVKEY:
|
|
|
|
r = do_store_private_key(profile);
|
|
|
|
break;
|
|
|
|
case ACTION_STORE_PUBKEY:
|
|
|
|
r = do_store_public_key(profile, NULL);
|
|
|
|
break;
|
|
|
|
case ACTION_STORE_CERT:
|
|
|
|
r = do_store_certificate(profile);
|
|
|
|
break;
|
|
|
|
case ACTION_STORE_DATA:
|
|
|
|
r = do_store_data_object(profile);
|
|
|
|
break;
|
|
|
|
case ACTION_GENERATE_KEY:
|
|
|
|
r = do_generate_key(profile, opt_newkey);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fatal("Action not yet implemented\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
fprintf(stderr, "Failed to %s: %s\n",
|
|
|
|
action_names[action], sc_strerror(r));
|
|
|
|
break;
|
|
|
|
}
|
2002-04-02 13:28:31 +00:00
|
|
|
}
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
out:
|
2002-04-02 13:28:31 +00:00
|
|
|
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;
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
if (!opt_quiet)
|
|
|
|
printf("Using card driver: %s\n", card->driver->name);
|
2002-02-22 07:18:43 +00:00
|
|
|
r = sc_lock(card);
|
|
|
|
if (r) {
|
|
|
|
error("Unable to lock card: %s\n", sc_strerror(r));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
/*
|
|
|
|
* Make sure there's no pkcs15 structure on the card
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_assert_pristine(struct sc_card *card)
|
|
|
|
{
|
|
|
|
sc_path_t path;
|
|
|
|
int r, res = 0;
|
|
|
|
|
2003-10-14 09:57:50 +00:00
|
|
|
card->ctx->suppress_errors++;
|
2003-05-16 19:12:54 +00:00
|
|
|
sc_format_path("2F00", &path);
|
|
|
|
if ((r = sc_select_file(card, &path, NULL)) >= 0
|
|
|
|
|| r != SC_ERROR_FILE_NOT_FOUND)
|
|
|
|
res = -1;
|
|
|
|
sc_format_path("5015", &path);
|
|
|
|
if ((r = sc_select_file(card, &path, NULL)) >= 0
|
|
|
|
|| r != SC_ERROR_FILE_NOT_FOUND)
|
|
|
|
res = -1;
|
2003-10-14 09:57:50 +00:00
|
|
|
card->ctx->suppress_errors--;
|
2003-05-16 19:12:54 +00:00
|
|
|
|
|
|
|
if (res < 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Card not pristine; detected (possibly incomplete) "
|
|
|
|
"PKCS#15 structure\n");
|
|
|
|
} else if (!opt_quiet) {
|
|
|
|
printf("Pristine card.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2003-05-15 15:29:42 +00:00
|
|
|
/*
|
|
|
|
* Erase card
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_erase(struct sc_card *card, struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
ignore_cmdline_pins++;
|
|
|
|
r = sc_pkcs15init_erase_card(card, profile);
|
|
|
|
ignore_cmdline_pins--;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
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;
|
2003-10-24 13:20:18 +00:00
|
|
|
sc_pkcs15_pin_info_t info;
|
|
|
|
sc_ui_hints_t hints;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.usage = SC_UI_USAGE_NEW_PIN;
|
|
|
|
hints.flags = SC_UI_PIN_RETYPE
|
|
|
|
| SC_UI_PIN_OPTIONAL
|
|
|
|
| SC_UI_PIN_CHECK_LENGTH
|
|
|
|
| SC_UI_PIN_MISMATCH_RETRY;
|
|
|
|
hints.card = card;
|
|
|
|
hints.p15card = NULL;
|
|
|
|
hints.info.pin = &info;
|
2002-04-02 14:46:32 +00:00
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
2003-05-15 13:33:31 +00:00
|
|
|
if (!opt_pins[2] && !opt_no_prompt && !opt_no_sopin) {
|
2002-09-30 20:24:16 +00:00
|
|
|
sc_pkcs15init_get_pin_info(profile,
|
|
|
|
SC_PKCS15INIT_SO_PIN, &info);
|
2003-10-24 13:20:18 +00:00
|
|
|
|
|
|
|
hints.dialog_name = "pkcs15init.new_so_pin";
|
|
|
|
hints.prompt = "New security officer (SO) PIN";
|
|
|
|
hints.obj_label = "Security Officer PIN";
|
|
|
|
|
|
|
|
if ((r = sc_ui_get_pin(&hints, &opt_pins[2])) < 0)
|
2002-09-30 20:24:16 +00:00
|
|
|
goto failed;
|
|
|
|
}
|
2003-10-24 13:20:18 +00:00
|
|
|
|
2003-05-15 13:33:31 +00:00
|
|
|
if (opt_pins[2] && !opt_pins[3] && !opt_no_prompt) {
|
2002-09-30 20:24:16 +00:00
|
|
|
sc_pkcs15init_get_pin_info(profile,
|
|
|
|
SC_PKCS15INIT_SO_PUK, &info);
|
2003-10-24 13:20:18 +00:00
|
|
|
|
|
|
|
hints.dialog_name = "pkcs15init.new_so_puk";
|
|
|
|
hints.prompt = "Unblock code for new SO PIN";
|
|
|
|
hints.obj_label = "Security Officer Unblock PIN (PUK)";
|
|
|
|
|
|
|
|
if ((r = sc_ui_get_pin(&hints, &opt_pins[3])) < 0)
|
2002-09-30 20:24:16 +00:00
|
|
|
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;
|
2003-10-13 16:13:12 +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
|
|
|
|
2003-10-24 13:20:18 +00:00
|
|
|
failed: sc_error(card->ctx, "Failed to read PIN: %s\n", sc_strerror(r));
|
2002-09-30 20:24:16 +00:00
|
|
|
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;
|
2003-10-24 13:20:18 +00:00
|
|
|
sc_pkcs15_pin_info_t info;
|
|
|
|
sc_ui_hints_t hints;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.usage = SC_UI_USAGE_NEW_PIN;
|
|
|
|
hints.flags = SC_UI_PIN_RETYPE
|
|
|
|
| SC_UI_PIN_CHECK_LENGTH
|
|
|
|
| SC_UI_PIN_MISMATCH_RETRY;
|
|
|
|
hints.card = card;
|
|
|
|
hints.p15card = p15card;
|
|
|
|
hints.info.pin = &info;
|
2002-04-02 13:28:31 +00:00
|
|
|
|
|
|
|
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);
|
2003-10-24 13:20:18 +00:00
|
|
|
|
|
|
|
hints.dialog_name = "pkcs15init.new_user_pin";
|
|
|
|
hints.prompt = "New user PIN";
|
|
|
|
hints.obj_label = "New User PIN";
|
|
|
|
|
|
|
|
if ((r = sc_ui_get_pin(&hints, &opt_pins[0])) < 0)
|
2002-09-30 20:03:10 +00:00
|
|
|
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);
|
2003-10-24 13:20:18 +00:00
|
|
|
|
|
|
|
hints.dialog_name = "pkcs15init.new_user_pin";
|
|
|
|
hints.prompt = "Unblock code for New user PIN";
|
|
|
|
hints.obj_label = "New User Unblock PIN (PUK)";
|
|
|
|
hints.flags |= SC_UI_PIN_OPTIONAL;
|
|
|
|
|
|
|
|
if ((r = sc_ui_get_pin(&hints, &opt_pins[1])) < 0)
|
2002-09-30 20:03:10 +00:00
|
|
|
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
|
|
|
|
2003-10-24 13:20:18 +00:00
|
|
|
failed: sc_error(card->ctx, "Failed to read PIN: %s\n", sc_strerror(r));
|
2002-09-30 20:03:10 +00:00
|
|
|
return SC_ERROR_PKCS15INIT;
|
2002-04-02 13:28:31 +00:00
|
|
|
}
|
|
|
|
|
2003-05-15 11:31:46 +00:00
|
|
|
/*
|
|
|
|
* Display split key error message
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
split_key_error(void)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "\n"
|
|
|
|
"Error - this token requires a more restrictive key usage.\n"
|
|
|
|
"Keys stored on this token can be used either for signing or decipherment,\n"
|
|
|
|
"but not both. You can either specify a more restrictive usage through\n"
|
|
|
|
"the --key-usage command line argument, or allow me to transparently\n"
|
|
|
|
"create two key objects with separate usage by specifying --split-key\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
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;
|
2003-04-16 11:50:49 +00:00
|
|
|
X509 *cert[MAX_CERTS];
|
|
|
|
int r, i, ncerts;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
if ((r = init_keyargs(&args)) < 0)
|
|
|
|
return r;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2003-04-16 11:50:49 +00:00
|
|
|
r = do_read_private_key(opt_infile, opt_format, &pkey, cert, MAX_CERTS);
|
2002-03-07 12:26:17 +00:00
|
|
|
if (r < 0)
|
2002-04-02 13:28:31 +00:00
|
|
|
return r;
|
2003-04-16 11:50:49 +00:00
|
|
|
ncerts = r;
|
|
|
|
|
|
|
|
if (ncerts) {
|
|
|
|
char namebuf[256];
|
|
|
|
|
|
|
|
printf("Importing %d certificates:\n", ncerts);
|
|
|
|
for (i = 0; i < ncerts; i++) {
|
|
|
|
printf(" %d: %s\n",
|
|
|
|
i, X509_NAME_oneline(cert[i]->cert_info->subject,
|
|
|
|
namebuf, sizeof(namebuf)));
|
|
|
|
}
|
|
|
|
}
|
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;
|
2003-04-16 11:50:49 +00:00
|
|
|
if (ncerts) {
|
2003-04-17 12:38:08 +00:00
|
|
|
unsigned int usage = cert[0]->ex_kusage;
|
|
|
|
|
|
|
|
/* No certificate usage? Assume ordinary
|
|
|
|
* user cert */
|
|
|
|
usage = 0x1F;
|
|
|
|
|
2002-10-02 10:50:53 +00:00
|
|
|
/* If the user requested a specific key usage on the
|
|
|
|
* command line check if it includes _more_
|
2003-04-17 09:39:09 +00:00
|
|
|
* usage bits than the one specified by the cert,
|
|
|
|
* and complain if it does.
|
|
|
|
* If the usage specified on the command line
|
|
|
|
* is more restrictive, use that.
|
|
|
|
*/
|
2003-04-17 12:38:08 +00:00
|
|
|
if (~usage & opt_x509_usage) {
|
2002-10-02 10:50:53 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"Warning: requested key usage incompatible with "
|
|
|
|
"key usage specified by X.509 certificate\n");
|
|
|
|
}
|
2003-04-17 09:39:09 +00:00
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
args.x509_usage = opt_x509_usage? opt_x509_usage : usage;
|
|
|
|
}
|
|
|
|
|
2003-05-15 11:31:46 +00:00
|
|
|
if (sc_pkcs15init_requires_restrictive_usage(p15card, &args, 0)) {
|
|
|
|
if (!opt_split_key)
|
|
|
|
split_key_error();
|
2003-04-17 12:38:08 +00:00
|
|
|
|
2003-05-15 11:31:46 +00:00
|
|
|
r = sc_pkcs15init_store_split_key(p15card, profile,
|
|
|
|
&args, NULL, NULL);
|
2003-04-17 12:38:08 +00:00
|
|
|
} else {
|
|
|
|
r = sc_pkcs15init_store_private_key(p15card, profile, &args, NULL);
|
2002-10-02 10:50:53 +00:00
|
|
|
}
|
2002-04-15 13:42:10 +00:00
|
|
|
|
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
|
|
|
|
2003-04-16 11:50:49 +00:00
|
|
|
/* If there are certificate as well (e.g. when reading the
|
|
|
|
* private key from a PKCS #12 file) store them, too.
|
2002-03-12 16:27:21 +00:00
|
|
|
*/
|
2003-04-16 11:50:49 +00:00
|
|
|
for (i = 0; i < ncerts; i++) {
|
2002-03-12 16:27:21 +00:00
|
|
|
struct sc_pkcs15init_certargs cargs;
|
2003-04-16 14:16:08 +00:00
|
|
|
char namebuf[SC_PKCS15_MAX_LABEL_SIZE-1];
|
2002-03-12 16:27:21 +00:00
|
|
|
|
|
|
|
memset(&cargs, 0, sizeof(cargs));
|
2003-04-16 11:50:49 +00:00
|
|
|
/* Just the first certificate gets the same ID
|
|
|
|
* as the private key. All others get
|
|
|
|
* an ID of their own */
|
|
|
|
if (i == 0)
|
|
|
|
cargs.id = args.id;
|
|
|
|
else
|
|
|
|
cargs.authority = 1;
|
|
|
|
|
2003-04-16 14:16:08 +00:00
|
|
|
cargs.label = X509_NAME_oneline(cert[i]->cert_info->subject,
|
|
|
|
namebuf, sizeof(namebuf));
|
|
|
|
|
2003-04-16 11:50:49 +00:00
|
|
|
cargs.x509_usage = cert[i]->ex_kusage;
|
|
|
|
r = do_convert_cert(&cargs.der_encoded, cert[i]);
|
2002-04-15 13:42:10 +00:00
|
|
|
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);
|
2003-04-16 11:50:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* No certificates - store the public key */
|
|
|
|
if (ncerts == 0) {
|
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;
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_object_t *dummy;
|
2002-04-15 13:42:10 +00:00
|
|
|
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,
|
2003-10-13 16:13:12 +00:00
|
|
|
&args, &dummy);
|
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);
|
2003-06-12 21:23:01 +00:00
|
|
|
if (opt_authid)
|
|
|
|
sc_pkcs15_format_id(opt_authid, &args.auth_id);
|
2002-12-18 10:17:01 +00:00
|
|
|
args.label = opt_label;
|
|
|
|
|
|
|
|
r = do_read_data_object(opt_infile, &data, &datalen);
|
2003-08-20 14:15:02 +00:00
|
|
|
if (r >= 0) {
|
|
|
|
/* der_encoded contains the plain data, nothing DER encoded */
|
|
|
|
args.der_encoded.value = data;
|
|
|
|
args.der_encoded.len = datalen;
|
2002-12-18 10:17:01 +00:00
|
|
|
r = sc_pkcs15init_store_data_object(p15card, profile,
|
|
|
|
&args, NULL);
|
2003-08-20 14:15:02 +00:00
|
|
|
}
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
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;
|
2003-05-15 11:31:46 +00:00
|
|
|
int r, split_key = 0;
|
2002-03-06 17:49:47 +00:00
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-15 11:31:46 +00:00
|
|
|
/* If the card doesn't support keys that can both sign _and_
|
|
|
|
* decipher, make sure the user specified --split-key */
|
|
|
|
if (sc_pkcs15init_requires_restrictive_usage(p15card, &args, keybits)) {
|
|
|
|
if (!opt_split_key)
|
|
|
|
split_key_error();
|
|
|
|
split_key = 1;
|
|
|
|
}
|
|
|
|
|
2003-05-15 11:39:02 +00:00
|
|
|
if (!opt_softkeygen && !split_key) {
|
2002-06-11 18:16:50 +00:00
|
|
|
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 */
|
2003-05-15 11:31:46 +00:00
|
|
|
if ((r = do_generate_key_soft(evp_algo, keybits, &pkey)) < 0
|
|
|
|
|| (r = do_convert_private_key(&args.key, pkey) ) < 0)
|
|
|
|
goto out;
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2003-05-15 11:31:46 +00:00
|
|
|
if (split_key) {
|
|
|
|
sc_pkcs15init_store_split_key(p15card,
|
|
|
|
profile, &args, NULL, NULL);
|
|
|
|
} else {
|
|
|
|
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
|
|
|
|
2003-05-15 11:31:46 +00:00
|
|
|
out:
|
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) {
|
2003-04-17 12:38:08 +00:00
|
|
|
args->flags |= SC_PKCS15INIT_EXTRACTABLE;
|
2002-04-17 20:47:18 +00:00
|
|
|
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;
|
|
|
|
}
|
2003-04-17 12:38:08 +00:00
|
|
|
args->flags |= SC_PKCS15INIT_NO_PASSPHRASE;
|
2002-04-17 20:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
2003-05-18 10:08:26 +00:00
|
|
|
/*
|
|
|
|
* Intern secrets given on the command line (mostly for testing)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
parse_secret(struct secret *secret, const char *arg)
|
|
|
|
{
|
|
|
|
char *copy, *str, *value;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
str = copy = strdup(arg);
|
|
|
|
if (!(value = strchr(str, '=')))
|
|
|
|
goto parse_err;
|
|
|
|
*value++ = '\0';
|
|
|
|
|
|
|
|
if (*str == '@') {
|
|
|
|
sc_pkcs15_format_id(str+1, &secret->id);
|
|
|
|
secret->type = SC_AC_CHV;
|
|
|
|
secret->reference = -1;
|
|
|
|
} else {
|
|
|
|
if (strncasecmp(str, "chv", 3))
|
|
|
|
secret->type = SC_AC_CHV;
|
|
|
|
else if (strncasecmp(str, "aut", 3))
|
|
|
|
secret->type = SC_AC_AUT;
|
|
|
|
else if (strncasecmp(str, "pro", 3))
|
|
|
|
secret->type = SC_AC_PRO;
|
|
|
|
else
|
|
|
|
goto parse_err;
|
|
|
|
str += 3;
|
|
|
|
if (!isdigit(str[3]))
|
|
|
|
goto parse_err;
|
|
|
|
secret->reference = strtoul(str, &str, 10);
|
|
|
|
if (*str != '\0')
|
|
|
|
goto parse_err;
|
|
|
|
}
|
|
|
|
if ((len = strlen(value)) < 3 || value[2] != ':') {
|
|
|
|
memcpy(secret->key, value, len);
|
|
|
|
} else {
|
|
|
|
len = sizeof(secret->key);
|
|
|
|
if (sc_hex_to_bin(value, secret->key, &len) < 0)
|
|
|
|
goto parse_err;
|
|
|
|
}
|
|
|
|
secret->len = len;
|
|
|
|
free(copy);
|
|
|
|
return;
|
|
|
|
|
|
|
|
parse_err:
|
|
|
|
fatal("Cannot parse secret \"%s\"\n", arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
set_secrets(struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
for (n = 0; n < opt_secret_count; n++) {
|
|
|
|
struct secret *secret = &opt_secrets[n];
|
|
|
|
|
|
|
|
if (secret->reference < 0)
|
|
|
|
continue;
|
|
|
|
sc_pkcs15init_set_secret(profile,
|
|
|
|
secret->type,
|
|
|
|
secret->reference,
|
|
|
|
secret->key,
|
|
|
|
secret->len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/*
|
2003-10-24 13:20:18 +00:00
|
|
|
* PIN retrieval callback
|
2002-03-06 17:49:47 +00:00
|
|
|
*/
|
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,
|
2003-05-15 11:31:46 +00:00
|
|
|
const char *label,
|
2002-04-02 13:28:31 +00:00
|
|
|
u8 *pinbuf, size_t *pinsize)
|
|
|
|
{
|
2003-05-15 11:31:46 +00:00
|
|
|
char namebuf[64];
|
2002-04-02 13:28:31 +00:00
|
|
|
char *name = NULL, *secret = NULL;
|
2003-05-18 10:08:26 +00:00
|
|
|
size_t len = 0;
|
|
|
|
int allocated = 0;
|
2002-04-02 13:28:31 +00:00
|
|
|
|
2003-05-18 10:08:26 +00:00
|
|
|
if (label) {
|
|
|
|
snprintf(namebuf, sizeof(namebuf), "PIN [%s]", label);
|
|
|
|
} else {
|
|
|
|
snprintf(namebuf, sizeof(namebuf),
|
|
|
|
"Unspecified PIN [reference %u]",
|
|
|
|
info->reference);
|
|
|
|
}
|
|
|
|
name = namebuf;
|
|
|
|
|
|
|
|
if (!ignore_cmdline_pins) {
|
|
|
|
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;
|
2003-05-15 11:31:46 +00:00
|
|
|
}
|
2003-05-18 10:08:26 +00:00
|
|
|
if (secret)
|
|
|
|
len = strlen(secret);
|
2002-02-22 07:18:43 +00:00
|
|
|
}
|
2002-03-06 17:49:47 +00:00
|
|
|
|
2003-05-18 10:08:26 +00:00
|
|
|
/* See if we were given --secret @ID=.... */
|
|
|
|
if (!secret) {
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
for (n = 0; n < opt_secret_count; n++) {
|
|
|
|
struct secret *s = &opt_secrets[n];
|
|
|
|
|
|
|
|
if (sc_pkcs15_compare_id(&info->auth_id, &s->id)) {
|
2003-09-10 22:20:26 +00:00
|
|
|
secret = (char *) s->key;
|
2003-05-18 10:08:26 +00:00
|
|
|
len = s->len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!secret) {
|
2003-10-24 13:20:18 +00:00
|
|
|
sc_ui_hints_t hints;
|
|
|
|
char prompt[128];
|
|
|
|
int r;
|
|
|
|
|
|
|
|
snprintf(prompt, sizeof(prompt), "%s required", name);
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.dialog_name = "pkcs15init.get_pin";
|
|
|
|
hints.prompt = prompt;
|
|
|
|
hints.obj_label = name;
|
|
|
|
hints.usage = SC_UI_USAGE_OTHER;
|
|
|
|
hints.card = card;
|
|
|
|
hints.p15card = p15card;
|
|
|
|
|
|
|
|
if ((r = sc_ui_get_pin(&hints, &secret)) < 0) {
|
|
|
|
sc_error(card->ctx,
|
|
|
|
"Failed to read PIN from user: %s\n",
|
|
|
|
sc_strerror(r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2003-05-18 10:08:26 +00:00
|
|
|
len = strlen(secret);
|
|
|
|
allocated = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len > *pinsize)
|
2002-04-02 13:28:31 +00:00
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
memcpy(pinbuf, secret, len + 1);
|
|
|
|
*pinsize = len;
|
2003-05-18 10:08:26 +00:00
|
|
|
if (allocated)
|
|
|
|
free(secret);
|
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);
|
2003-05-15 13:33:31 +00:00
|
|
|
if (opt_no_prompt) {
|
|
|
|
printf("\n"
|
|
|
|
"Refusing to prompt for transport key because --no-prompt\n"
|
|
|
|
"was specified on the command line. Please invoke without\n"
|
|
|
|
"--no-prompt, or specify the --use-default-transport-keys\n"
|
|
|
|
"option to use the default transport keys without being\n"
|
|
|
|
"prompted.\n");
|
|
|
|
fprintf(stderr, "Aborting.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2002-12-04 11:56:51 +00:00
|
|
|
printf("Please enter key in hexadecimal notation "
|
2003-05-14 16:22:14 +00:00
|
|
|
"(e.g. 00:11:22:aa:bb:cc)%s.\n\n",
|
|
|
|
def_key_size? ",\nor 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"
|
2003-05-14 16:22:14 +00:00
|
|
|
"command line (or -T for short), or press Ctrl-C to abort.\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
|
|
|
*/
|
2003-04-16 11:50:49 +00:00
|
|
|
static int
|
|
|
|
do_read_pem_private_key(const char *filename, const char *passphrase,
|
|
|
|
EVP_PKEY **key)
|
2002-02-23 13:38:01 +00:00
|
|
|
{
|
2003-04-16 11:50:49 +00:00
|
|
|
BIO *bio;
|
2002-02-23 13:38:01 +00:00
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
if (BIO_read_filename(bio, filename) < 0)
|
|
|
|
fatal("Unable to open %s: %m", filename);
|
2003-04-16 11:50:49 +00:00
|
|
|
*key = PEM_read_bio_PrivateKey(bio, 0, 0, (char *) passphrase);
|
2002-02-23 13:38:01 +00:00
|
|
|
BIO_free(bio);
|
2003-04-16 11:50:49 +00:00
|
|
|
if (*key == NULL) {
|
2002-02-23 13:38:01 +00:00
|
|
|
ossl_print_errors();
|
2003-04-16 11:50:49 +00:00
|
|
|
return SC_ERROR_CANNOT_LOAD_KEY;
|
|
|
|
}
|
|
|
|
return 0;
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
|
|
|
|
2003-04-16 11:50:49 +00:00
|
|
|
static int
|
2002-03-12 16:27:21 +00:00
|
|
|
do_read_pkcs12_private_key(const char *filename, const char *passphrase,
|
2003-04-16 11:50:49 +00:00
|
|
|
EVP_PKEY **key, X509 **certs, unsigned int max_certs)
|
2002-03-12 16:27:21 +00:00
|
|
|
{
|
|
|
|
BIO *bio;
|
|
|
|
PKCS12 *p12;
|
2003-04-16 11:50:49 +00:00
|
|
|
EVP_PKEY *user_key = NULL;
|
|
|
|
X509 *user_cert = NULL;
|
|
|
|
STACK_OF(X509) *cacerts = NULL;
|
|
|
|
int i, ncerts = 0;
|
|
|
|
|
|
|
|
*key = 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);
|
2003-04-16 11:50:49 +00:00
|
|
|
|
|
|
|
if (p12 == NULL
|
|
|
|
|| !PKCS12_parse(p12, passphrase, &user_key, &user_cert, &cacerts))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!user_key) {
|
|
|
|
error("No key in pkcs12 file?!\n");
|
|
|
|
return SC_ERROR_CANNOT_LOAD_KEY;
|
2002-03-13 20:23:18 +00:00
|
|
|
}
|
2003-04-16 11:50:49 +00:00
|
|
|
|
|
|
|
CRYPTO_add(&user_key->references, 1, CRYPTO_LOCK_EVP_PKEY);
|
|
|
|
if (user_cert && max_certs)
|
|
|
|
certs[ncerts++] = user_cert;
|
|
|
|
|
|
|
|
/* Extract CA certificates, if any */
|
|
|
|
for(i = 0; cacerts && ncerts < max_certs && i < sk_X509_num(cacerts); i++)
|
|
|
|
certs[ncerts++] = sk_X509_value(cacerts, i);
|
|
|
|
|
|
|
|
/* bump reference counts for certificates */
|
|
|
|
for (i = 0; i < ncerts; i++) {
|
|
|
|
CRYPTO_add(&certs[i]->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cacerts)
|
|
|
|
sk_X509_free(cacerts);
|
|
|
|
|
|
|
|
*key = user_key;
|
|
|
|
return ncerts;
|
|
|
|
|
|
|
|
error: ossl_print_errors();
|
|
|
|
return SC_ERROR_CANNOT_LOAD_KEY;
|
2002-03-12 16:27:21 +00:00
|
|
|
}
|
|
|
|
|
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,
|
2003-04-16 11:50:49 +00:00
|
|
|
EVP_PKEY **pk, X509 **certs, unsigned int max_certs)
|
2002-02-23 13:38:01 +00:00
|
|
|
{
|
|
|
|
char *passphrase = NULL;
|
2003-04-16 11:50:49 +00:00
|
|
|
int r;
|
2002-02-23 13:38:01 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (!format || !strcasecmp(format, "pem")) {
|
2003-04-16 11:50:49 +00:00
|
|
|
r = do_read_pem_private_key(filename, passphrase, pk);
|
2002-03-12 16:27:21 +00:00
|
|
|
} else if (!strcasecmp(format, "pkcs12")) {
|
2003-04-16 11:50:49 +00:00
|
|
|
r = do_read_pkcs12_private_key(filename,
|
|
|
|
passphrase,
|
|
|
|
pk, certs, max_certs);
|
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;
|
|
|
|
}
|
|
|
|
|
2003-04-16 11:50:49 +00:00
|
|
|
if (r >= 0 || passphrase)
|
2002-02-23 13:38:01 +00:00
|
|
|
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));
|
2003-04-16 11:50:49 +00:00
|
|
|
if (r < 0)
|
2002-02-23 13:38:01 +00:00
|
|
|
fatal("Unable to read private key from %s\n", filename);
|
2003-04-16 11:50:49 +00:00
|
|
|
return r;
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
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;
|
|
|
|
|
2003-09-30 20:43:45 +00:00
|
|
|
if ((fp = fopen(filename,"rb")) == NULL) {
|
2002-12-18 10:17:01 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2003-09-30 20:43:45 +00:00
|
|
|
inf = fopen(name, "rb");
|
2002-12-18 10:17:01 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2003-05-16 19:12:54 +00:00
|
|
|
handle_option(const struct option *opt)
|
2002-02-22 07:18:43 +00:00
|
|
|
{
|
2003-05-16 19:12:54 +00:00
|
|
|
unsigned int this_action = ACTION_NONE;
|
|
|
|
|
|
|
|
switch (opt->val) {
|
2002-04-02 13:28:31 +00:00
|
|
|
case 'a':
|
|
|
|
opt_authid = optarg;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
case 'C':
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_INIT;
|
2002-02-23 13:38:01 +00:00
|
|
|
break;
|
|
|
|
case 'E':
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_ERASE;
|
2002-02-23 13:38:01 +00:00
|
|
|
break;
|
|
|
|
case 'G':
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_GENERATE_KEY;
|
2002-02-23 13:38:01 +00:00
|
|
|
opt_newkey = optarg;
|
|
|
|
break;
|
|
|
|
case 'S':
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_STORE_PRIVKEY;
|
2002-03-12 10:08:18 +00:00
|
|
|
opt_infile = optarg;
|
|
|
|
break;
|
|
|
|
case 'P':
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_STORE_PIN;
|
2002-03-12 10:08:18 +00:00
|
|
|
break;
|
|
|
|
case 'X':
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_STORE_CERT;
|
2002-03-12 10:08:18 +00:00
|
|
|
opt_infile = optarg;
|
2002-12-18 10:17:01 +00:00
|
|
|
break;
|
|
|
|
case 'W':
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_STORE_DATA;
|
2002-12-18 10:17:01 +00:00
|
|
|
opt_infile = optarg;
|
2002-02-23 13:38:01 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
opt_debug++;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
opt_format = optarg;
|
|
|
|
break;
|
2003-05-18 10:08:26 +00:00
|
|
|
case 'h':
|
|
|
|
print_usage_and_die();
|
2002-02-23 13:38:01 +00:00
|
|
|
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;
|
2003-06-18 08:07:12 +00:00
|
|
|
case 'c':
|
|
|
|
opt_card_profile = optarg;
|
|
|
|
break;
|
2003-05-16 19:12:54 +00:00
|
|
|
case 'q':
|
|
|
|
opt_quiet = 1;
|
|
|
|
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:
|
2003-05-16 19:12:54 +00:00
|
|
|
opt_pins[opt->val & 3] = optarg;
|
2002-02-23 13:38:01 +00:00
|
|
|
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:
|
2003-05-16 19:12:54 +00:00
|
|
|
this_action = ACTION_STORE_PUBKEY;
|
2002-04-02 13:28:31 +00:00
|
|
|
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;
|
2003-04-17 12:38:08 +00:00
|
|
|
case OPT_SPLIT_KEY:
|
|
|
|
opt_split_key = 1;
|
|
|
|
break;
|
2003-05-14 16:22:14 +00:00
|
|
|
case OPT_NO_SOPIN:
|
|
|
|
opt_no_sopin = 1;
|
|
|
|
break;
|
2003-05-15 13:33:31 +00:00
|
|
|
case OPT_NO_PROMPT:
|
|
|
|
opt_no_prompt = 1;
|
|
|
|
break;
|
2003-05-16 19:12:54 +00:00
|
|
|
case OPT_ASSERT_PRISTINE:
|
|
|
|
this_action = ACTION_ASSERT_PRISTINE;
|
|
|
|
break;
|
2003-05-18 10:08:26 +00:00
|
|
|
case OPT_SECRET:
|
|
|
|
parse_secret(&opt_secrets[opt_secret_count], optarg);
|
|
|
|
opt_secret_count++;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
default:
|
2002-04-19 14:23:31 +00:00
|
|
|
print_usage_and_die();
|
2003-05-14 16:22:14 +00:00
|
|
|
}
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
if ((opt_actions & (1 << this_action)) && opt->has_arg != no_argument) {
|
|
|
|
fprintf(stderr, "Error: you cannot specify option");
|
|
|
|
if (opt->name)
|
|
|
|
fprintf(stderr, " --%s", opt->name);
|
|
|
|
if (isprint(opt->val))
|
|
|
|
fprintf(stderr, " -%c", opt->val);
|
|
|
|
fprintf(stderr, " more than once.\n");
|
|
|
|
print_usage_and_die();
|
|
|
|
}
|
|
|
|
if (this_action)
|
|
|
|
opt_actions |= (1 << this_action);
|
|
|
|
|
2003-05-14 16:22:14 +00:00
|
|
|
if ((opt_pins[OPT_PIN2&3] || opt_pins[OPT_PUK2&3]) && opt_no_sopin) {
|
|
|
|
fprintf(stderr, "Error: "
|
|
|
|
"The --no-so-pin option and --so-pin/--so-puk are mutually\n"
|
|
|
|
"exclusive.\n");
|
|
|
|
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;
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
while ((c = getopt_long(argc, argv, shortopts, options, &i)) != -1) {
|
|
|
|
/* The optindex seems to be off with some glibc
|
|
|
|
* getopt implementations */
|
|
|
|
for (o = options; o->name; o++) {
|
|
|
|
if (o->val == c) {
|
|
|
|
handle_option(o);
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fatal("Internal error in options handling, option %u\n", c);
|
|
|
|
|
|
|
|
next: ;
|
|
|
|
}
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
}
|
2003-05-16 19:12:54 +00:00
|
|
|
handle_option(o);
|
2002-02-23 13:38:01 +00:00
|
|
|
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
|
|
|
}
|