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>
|
2005-07-20 17:58:55 +00:00
|
|
|
#include <openssl/x509v3.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>
|
2005-08-24 15:59:01 +00:00
|
|
|
#include <opensc/keycache.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>
|
2005-10-31 19:31:45 +00:00
|
|
|
#include <opensc/cards.h>
|
2002-02-22 07:18:43 +00:00
|
|
|
#include "util.h"
|
2006-07-12 08:12:38 +00:00
|
|
|
#include "strlcpy.h"
|
2002-02-22 07:18:43 +00:00
|
|
|
|
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 */
|
2005-03-09 00:04:44 +00:00
|
|
|
typedef int (*pkcs15_encoder)(sc_context_t *,
|
2002-02-22 07:18:43 +00:00
|
|
|
struct sc_pkcs15_card *, u8 **, size_t *);
|
|
|
|
|
|
|
|
/* Local functions */
|
2003-02-28 11:07:37 +00:00
|
|
|
static int open_reader_and_card(int);
|
2005-03-09 00:04:44 +00:00
|
|
|
static int do_assert_pristine(sc_card_t *);
|
|
|
|
static int do_erase(sc_card_t *, struct sc_profile *);
|
2007-06-21 13:38:16 +00:00
|
|
|
static int do_delete_objects(struct sc_profile *, unsigned int myopt_delete_flags);
|
|
|
|
static int do_change_attributes(struct sc_profile *, unsigned int myopt_type);
|
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 *);
|
2005-09-15 19:40:20 +00:00
|
|
|
static int do_update_certificate(struct sc_profile *);
|
2002-04-15 13:42:10 +00:00
|
|
|
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 *);
|
2003-10-30 11:36:04 +00:00
|
|
|
static int is_cacert_already_present(struct sc_pkcs15init_certargs *);
|
2005-03-09 00:04:44 +00:00
|
|
|
static int do_finalize_card(sc_card_t *, struct sc_profile *);
|
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 *);
|
2003-12-16 14:41:04 +00:00
|
|
|
static int get_new_pin(sc_ui_hints_t *, const char *, const char *,
|
|
|
|
char **);
|
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);
|
2005-08-23 09:01:57 +00:00
|
|
|
static void set_userpin_ref();
|
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,
|
2004-01-05 08:56:32 +00:00
|
|
|
OPT_PUBKEY_LABEL,
|
2004-01-24 20:55:34 +00:00
|
|
|
OPT_CERT_LABEL,
|
2004-07-26 18:47:23 +00:00
|
|
|
OPT_APPLICATION_ID,
|
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[] = {
|
2007-06-21 13:38:16 +00:00
|
|
|
{ "erase-card", no_argument, NULL, 'E' },
|
|
|
|
{ "create-pkcs15", no_argument, NULL, 'C' },
|
|
|
|
{ "store-pin", no_argument, NULL, 'P' },
|
|
|
|
{ "generate-key", required_argument, NULL, 'G' },
|
|
|
|
{ "store-private-key", required_argument, NULL, 'S' },
|
|
|
|
{ "store-public-key", required_argument, NULL, OPT_PUBKEY },
|
|
|
|
{ "store-certificate", required_argument, NULL, 'X' },
|
|
|
|
{ "update-certificate", required_argument, NULL, 'U' },
|
|
|
|
{ "store-data", required_argument, NULL, 'W' },
|
|
|
|
{ "delete-objects", required_argument, NULL, 'D' },
|
|
|
|
{ "change-attributes", required_argument, NULL, 'A' },
|
|
|
|
|
|
|
|
{ "reader", required_argument, NULL, 'r' },
|
|
|
|
{ "pin", required_argument, NULL, OPT_PIN1 },
|
|
|
|
{ "puk", required_argument, NULL, OPT_PUK1 },
|
|
|
|
{ "so-pin", required_argument, NULL, OPT_PIN2 },
|
|
|
|
{ "so-puk", required_argument, NULL, OPT_PUK2 },
|
|
|
|
{ "no-so-pin", no_argument, NULL, OPT_NO_SOPIN },
|
|
|
|
{ "serial", required_argument, NULL, OPT_SERIAL },
|
|
|
|
{ "auth-id", required_argument, NULL, 'a' },
|
|
|
|
{ "id", required_argument, NULL, 'i' },
|
|
|
|
{ "label", required_argument, NULL, 'l' },
|
|
|
|
{ "public-key-label", required_argument, NULL, OPT_PUBKEY_LABEL },
|
|
|
|
{ "cert-label", required_argument, NULL, OPT_CERT_LABEL },
|
|
|
|
{ "application-id", required_argument, NULL, OPT_APPLICATION_ID },
|
|
|
|
{ "output-file", required_argument, NULL, 'o' },
|
|
|
|
{ "format", required_argument, NULL, 'f' },
|
|
|
|
{ "passphrase", required_argument, NULL, OPT_PASSPHRASE },
|
|
|
|
{ "authority", no_argument, NULL, OPT_AUTHORITY },
|
|
|
|
{ "key-usage", required_argument, NULL, 'u' },
|
|
|
|
{ "split-key", no_argument, NULL, OPT_SPLIT_KEY },
|
|
|
|
{ "finalize", no_argument, NULL, 'F' },
|
|
|
|
|
|
|
|
{ "extractable", no_argument, NULL, OPT_EXTRACTABLE },
|
|
|
|
{ "insecure", no_argument, NULL, OPT_UNPROTECTED },
|
|
|
|
{ "soft", no_argument, NULL, OPT_SOFT_KEYGEN },
|
2002-12-04 11:56:51 +00:00
|
|
|
{ "use-default-transport-keys",
|
2007-06-21 13:38:16 +00:00
|
|
|
no_argument, NULL, 'T' },
|
|
|
|
{ "no-prompt", no_argument, NULL, OPT_NO_PROMPT },
|
2002-04-17 20:47:18 +00:00
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
{ "profile", required_argument, NULL, 'p' },
|
|
|
|
{ "card-profile", required_argument, NULL, 'c' },
|
|
|
|
{ "options-file", required_argument, NULL, OPT_OPTIONS },
|
|
|
|
{ "wait", no_argument, NULL, 'w' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "verbose", no_argument, NULL, 'v' },
|
2003-05-16 19:12:54 +00:00
|
|
|
|
|
|
|
/* Hidden options for testing */
|
2007-06-21 13:38:16 +00:00
|
|
|
{ "assert-pristine", no_argument, NULL, OPT_ASSERT_PRISTINE },
|
|
|
|
{ "secret", required_argument, NULL, OPT_SECRET },
|
|
|
|
{ NULL, 0, NULL, 0 }
|
2002-02-22 07:18:43 +00:00
|
|
|
};
|
|
|
|
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",
|
2005-09-15 19:40:20 +00:00
|
|
|
"Update an X.509 certificate (carefull with mail decryption certs!!)",
|
2003-01-09 09:09:25 +00:00
|
|
|
"Store a data object",
|
2005-08-22 09:23:46 +00:00
|
|
|
"Delete object(s) (use \"help\" for more information)",
|
2006-01-03 16:24:54 +00:00
|
|
|
"Change attribute(s) (use \"help\" for more information)",
|
2003-01-09 09:09:25 +00:00
|
|
|
|
|
|
|
"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",
|
2004-01-05 08:56:32 +00:00
|
|
|
"Specify public key label (use with --generate-key)",
|
2004-01-24 20:55:34 +00:00
|
|
|
"Specify user cert label (use with --store-private-key)",
|
2004-07-26 18:47:23 +00:00
|
|
|
"Specify application id of data object (use with --store-data-object)",
|
2002-02-23 13:38:01 +00:00
|
|
|
"Output public portion of generated key to file",
|
2005-09-15 19:40:20 +00:00
|
|
|
"Specify key/cert file format: PEM (=default), DER or PKCS12",
|
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)",
|
2005-06-16 19:35:31 +00:00
|
|
|
"Finish initialization phase of the smart card",
|
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",
|
2003-05-18 10:08:26 +00:00
|
|
|
"Display this message",
|
2004-06-13 20:13:12 +00:00
|
|
|
"Verbose operation. Use several times to enable debug output.",
|
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,
|
2005-09-15 19:40:20 +00:00
|
|
|
ACTION_UPDATE_CERT,
|
2003-05-16 19:12:54 +00:00
|
|
|
ACTION_STORE_DATA,
|
2004-04-17 09:25:30 +00:00
|
|
|
ACTION_FINALIZE_CARD,
|
2005-08-22 09:23:46 +00:00
|
|
|
ACTION_DELETE_OBJECTS,
|
2006-01-03 16:24:54 +00:00
|
|
|
ACTION_CHANGE_ATTRIBUTES,
|
2003-05-16 19:12:54 +00:00
|
|
|
|
|
|
|
ACTION_MAX
|
2002-02-23 13:38:01 +00:00
|
|
|
};
|
2005-02-06 21:01:09 +00:00
|
|
|
static const char *action_names[] = {
|
2002-04-02 13:28:31 +00:00
|
|
|
"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",
|
2005-09-15 19:40:20 +00:00
|
|
|
"update certificate",
|
2004-04-17 09:25:30 +00:00
|
|
|
"store data object",
|
2005-08-22 09:23:46 +00:00
|
|
|
"finalizing card",
|
2006-01-03 16:24:54 +00:00
|
|
|
"delete object(s)",
|
|
|
|
"change attribute(s)",
|
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
|
|
|
|
2006-01-03 16:24:54 +00:00
|
|
|
/* Flags for do_delete_crypto_objects() and do_change_attributes() */
|
|
|
|
#define SC_PKCS15INIT_TYPE_PRKEY 1
|
|
|
|
#define SC_PKCS15INIT_TYPE_PUBKEY 2
|
|
|
|
#define SC_PKCS15INIT_TYPE_CERT 4
|
|
|
|
#define SC_PKCS15INIT_TYPE_CHAIN (8 | 4)
|
|
|
|
#define SC_PKCS15INIT_TYPE_DATA 16
|
2005-08-22 09:23:46 +00:00
|
|
|
|
2005-03-09 00:04:44 +00:00
|
|
|
static sc_context_t * ctx = NULL;
|
|
|
|
static sc_card_t * 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-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;
|
2005-02-06 21:01:09 +00:00
|
|
|
static const char * opt_profile = "pkcs15";
|
2003-06-18 08:07:12 +00:00
|
|
|
static char * opt_card_profile = NULL;
|
2007-06-21 13:38:16 +00:00
|
|
|
static char * opt_infile = NULL;
|
|
|
|
static char * opt_format = NULL;
|
|
|
|
static char * opt_authid = NULL;
|
|
|
|
static char * opt_objectid = NULL;
|
|
|
|
static char * opt_label = NULL;
|
|
|
|
static char * opt_pubkey_label = NULL;
|
|
|
|
static char * opt_cert_label = NULL;
|
2002-02-22 07:18:43 +00:00
|
|
|
static char * opt_pins[4];
|
2007-06-21 13:38:16 +00:00
|
|
|
static char * opt_serial = NULL;
|
|
|
|
static char * opt_passphrase = NULL;
|
|
|
|
static char * opt_newkey = NULL;
|
|
|
|
static char * opt_outkey = NULL;
|
|
|
|
static char * opt_application_id = NULL;
|
2002-10-02 10:50:53 +00:00
|
|
|
static unsigned int opt_x509_usage = 0;
|
2005-08-22 09:23:46 +00:00
|
|
|
static unsigned int opt_delete_flags = 0;
|
2006-01-03 16:24:54 +00:00
|
|
|
static unsigned int opt_type = 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;
|
2004-06-13 20:13:12 +00:00
|
|
|
static int verbose = 0;
|
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)
|
|
|
|
{
|
2004-10-24 17:20:29 +00:00
|
|
|
struct sc_profile *profile = NULL;
|
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)
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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");
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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");
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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,
|
2005-07-05 17:43:50 +00:00
|
|
|
opt_card_profile, &profile)) < 0) {
|
|
|
|
printf("Couldn't bind to the card: %s\n", sc_strerror(r));
|
2002-04-02 13:28:31 +00:00
|
|
|
return 1;
|
2005-07-05 17:43:50 +00:00
|
|
|
}
|
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
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
if (verbose)
|
2003-05-15 15:29:42 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
if (verbose && action != ACTION_ASSERT_PRISTINE)
|
2003-05-16 19:12:54 +00:00
|
|
|
printf("About to %s.\n", action_names[action]);
|
2006-01-03 16:24:54 +00:00
|
|
|
/*
|
|
|
|
{
|
|
|
|
sc_path_t p1, p2, p3, p4;
|
|
|
|
sc_format_path("3F0050156666", &p1); p1.index = 0; p1.count = 50;
|
|
|
|
sc_format_path("3F0050157777", &p2); p2.index = 50; p2.count = 50;
|
|
|
|
sc_format_path("3F0050156666", &p3); p3.index = 200; p3.count = 50;
|
|
|
|
sc_format_path("3F0050156666", &p4); p4.index = 50; p4.count = 150;
|
|
|
|
r = sc_pkcs15init_remove_unusedspace(p15card, profile, &p1, NULL);
|
|
|
|
printf("sc_pkcs15init_add_unusedspace(): %d\n", r);
|
|
|
|
//r = sc_pkcs15init_add_unusedspace(p15card, profile, &p3, NULL);
|
|
|
|
//printf("sc_pkcs15init_add_unusedspace(): %d\n", r);
|
|
|
|
}
|
|
|
|
*/
|
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;
|
2005-09-15 19:40:20 +00:00
|
|
|
case ACTION_UPDATE_CERT:
|
|
|
|
r = do_update_certificate(profile);
|
|
|
|
break;
|
2003-05-15 15:29:42 +00:00
|
|
|
case ACTION_STORE_DATA:
|
|
|
|
r = do_store_data_object(profile);
|
|
|
|
break;
|
2005-08-22 09:23:46 +00:00
|
|
|
case ACTION_DELETE_OBJECTS:
|
|
|
|
r = do_delete_objects(profile, opt_delete_flags);
|
|
|
|
break;
|
2006-01-03 16:24:54 +00:00
|
|
|
case ACTION_CHANGE_ATTRIBUTES:
|
|
|
|
r = do_change_attributes(profile, opt_type);
|
|
|
|
break;
|
2003-05-15 15:29:42 +00:00
|
|
|
case ACTION_GENERATE_KEY:
|
|
|
|
r = do_generate_key(profile, opt_newkey);
|
|
|
|
break;
|
2004-04-17 09:25:30 +00:00
|
|
|
case ACTION_FINALIZE_CARD:
|
|
|
|
r = do_finalize_card(card, profile);
|
|
|
|
break;
|
2003-05-15 15:29:42 +00:00
|
|
|
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:
|
2004-10-24 17:20:29 +00:00
|
|
|
if (profile) {
|
|
|
|
sc_pkcs15init_unbind(profile);
|
|
|
|
}
|
2005-01-21 18:25:26 +00:00
|
|
|
if (p15card) {
|
|
|
|
sc_pkcs15_unbind(p15card);
|
|
|
|
}
|
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;
|
2006-02-07 20:14:43 +00:00
|
|
|
sc_context_param_t ctx_param;
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2006-02-07 20:14:43 +00:00
|
|
|
memset(&ctx_param, 0, sizeof(ctx_param));
|
|
|
|
ctx_param.ver = 0;
|
|
|
|
ctx_param.app_name = app_name;
|
|
|
|
|
|
|
|
r = sc_context_create(&ctx, &ctx_param);
|
2002-02-22 07:18:43 +00:00
|
|
|
if (r) {
|
|
|
|
error("Failed to establish context: %s\n", sc_strerror(r));
|
|
|
|
return 0;
|
|
|
|
}
|
2004-06-13 20:13:12 +00:00
|
|
|
if (verbose > 1) {
|
|
|
|
ctx->debug = verbose-1;
|
2002-04-02 13:28:31 +00:00
|
|
|
ctx->debug_file = stderr;
|
|
|
|
}
|
2002-02-22 07:18:43 +00:00
|
|
|
|
2004-06-13 20:13:12 +00:00
|
|
|
if (connect_card(ctx, &card, reader, 0, opt_wait, verbose))
|
2002-02-22 07:18:43 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
/*
|
|
|
|
* Make sure there's no pkcs15 structure on the card
|
|
|
|
*/
|
|
|
|
static int
|
2005-03-09 00:04:44 +00:00
|
|
|
do_assert_pristine(sc_card_t *in_card)
|
2003-05-16 19:12:54 +00:00
|
|
|
{
|
|
|
|
sc_path_t path;
|
2005-10-31 19:31:45 +00:00
|
|
|
int r, ok = 1;
|
2004-06-13 19:45:24 +00:00
|
|
|
|
|
|
|
/* we need FILE NOT FOUND.
|
2005-10-31 19:31:45 +00:00
|
|
|
* - on starcos card NOT ALLOWED is also ok, as the MF does not exist.
|
|
|
|
* - on setcos 4.4 card, we should get 6F00 (translates to
|
|
|
|
* SC_ERROR_CARD_CMD_FAILED) to indicate that no MF exists. */
|
2003-05-16 19:12:54 +00:00
|
|
|
|
2005-10-30 19:08:06 +00:00
|
|
|
sc_ctx_suppress_errors_on(in_card->ctx);
|
2004-06-13 19:45:24 +00:00
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
sc_format_path("2F00", &path);
|
2005-02-06 21:01:09 +00:00
|
|
|
r = sc_select_file(in_card, &path, NULL);
|
2004-06-13 19:45:24 +00:00
|
|
|
|
2005-10-31 19:31:45 +00:00
|
|
|
if (r != SC_ERROR_FILE_NOT_FOUND) {
|
|
|
|
ok &= (r == SC_ERROR_NOT_ALLOWED &&
|
|
|
|
strcmp(in_card->name, "STARCOS SPK 2.3") == 0) ||
|
|
|
|
(r == SC_ERROR_CARD_CMD_FAILED &&
|
|
|
|
in_card->type == SC_CARD_TYPE_SETCOS_44);
|
|
|
|
}
|
2004-06-13 19:45:24 +00:00
|
|
|
|
2003-05-16 19:12:54 +00:00
|
|
|
sc_format_path("5015", &path);
|
2005-02-06 21:01:09 +00:00
|
|
|
r = sc_select_file(in_card, &path, NULL);
|
2004-06-13 20:04:53 +00:00
|
|
|
|
2005-10-31 19:31:45 +00:00
|
|
|
if (r != SC_ERROR_FILE_NOT_FOUND) {
|
|
|
|
ok &= (r == SC_ERROR_NOT_ALLOWED &&
|
|
|
|
strcmp(in_card->name, "STARCOS SPK 2.3") == 0) ||
|
|
|
|
(r == SC_ERROR_CARD_CMD_FAILED &&
|
|
|
|
in_card->type == SC_CARD_TYPE_SETCOS_44);
|
|
|
|
}
|
|
|
|
|
2004-06-13 19:45:24 +00:00
|
|
|
|
2005-10-30 19:08:06 +00:00
|
|
|
sc_ctx_suppress_errors_off(in_card->ctx);
|
2003-05-16 19:12:54 +00:00
|
|
|
|
2005-10-31 19:31:45 +00:00
|
|
|
if (!ok) {
|
2003-05-16 19:12:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"Card not pristine; detected (possibly incomplete) "
|
|
|
|
"PKCS#15 structure\n");
|
2004-06-13 20:13:12 +00:00
|
|
|
} else if (verbose) {
|
2003-05-16 19:12:54 +00:00
|
|
|
printf("Pristine card.\n");
|
|
|
|
}
|
|
|
|
|
2005-10-31 19:31:45 +00:00
|
|
|
return ok ? 0 : -1;
|
2003-05-16 19:12:54 +00:00
|
|
|
}
|
|
|
|
|
2003-05-15 15:29:42 +00:00
|
|
|
/*
|
|
|
|
* Erase card
|
|
|
|
*/
|
|
|
|
static int
|
2005-03-09 00:04:44 +00:00
|
|
|
do_erase(sc_card_t *in_card, struct sc_profile *profile)
|
2003-05-15 15:29:42 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
ignore_cmdline_pins++;
|
2005-02-06 21:01:09 +00:00
|
|
|
r = sc_pkcs15init_erase_card(in_card, profile);
|
2003-05-15 15:29:42 +00:00
|
|
|
ignore_cmdline_pins--;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-02-06 21:01:09 +00:00
|
|
|
static int do_finalize_card(sc_card_t *in_card, struct sc_profile *profile)
|
2004-04-17 09:25:30 +00:00
|
|
|
{
|
2005-02-06 21:01:09 +00:00
|
|
|
return sc_pkcs15init_finalize_card(in_card, profile);
|
2004-04-17 09:25:30 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2003-12-16 14:41:04 +00:00
|
|
|
const char *role = "so";
|
2003-10-24 13:20:18 +00:00
|
|
|
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 = NULL;
|
|
|
|
hints.info.pin = &info;
|
2002-04-02 14:46:32 +00:00
|
|
|
|
2004-10-06 14:07:18 +00:00
|
|
|
/* If it's the onepin option, we need the user PIN iso the SO PIN */
|
|
|
|
if (opt_profile && strstr(opt_profile, "+onepin")) {
|
|
|
|
if (opt_pins[0])
|
|
|
|
opt_pins[2] = opt_pins[0];
|
|
|
|
if (opt_pins[1])
|
|
|
|
opt_pins[3] = opt_pins[1];
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2003-12-16 14:41:04 +00:00
|
|
|
if (!(info.flags & SC_PKCS15_PIN_FLAG_SO_PIN)) {
|
|
|
|
role = "user";
|
|
|
|
} else {
|
|
|
|
/* SO pin is always optional */
|
|
|
|
hints.flags |= SC_UI_PIN_OPTIONAL;
|
|
|
|
}
|
2003-10-24 13:20:18 +00:00
|
|
|
|
2003-12-16 14:41:04 +00:00
|
|
|
r = get_new_pin(&hints, role, "pin", &opt_pins[2]);
|
|
|
|
if (r < 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
|
|
|
|
2003-12-16 14:41:04 +00:00
|
|
|
if (!(info.flags & SC_PKCS15_PIN_FLAG_SO_PIN))
|
|
|
|
role = "user";
|
2003-10-24 13:20:18 +00:00
|
|
|
|
2003-12-16 14:41:04 +00:00
|
|
|
hints.flags |= SC_UI_PIN_OPTIONAL;
|
|
|
|
r = get_new_pin(&hints, role, "puk", &opt_pins[3]);
|
|
|
|
if (r < 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)
|
2005-02-08 09:51:56 +00:00
|
|
|
args.so_pin_len = strlen((const 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)
|
2005-02-08 09:51:56 +00:00
|
|
|
args.so_puk_len = strlen((const 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;
|
2005-01-13 21:52:39 +00:00
|
|
|
const char *pin_id;
|
2003-10-24 13:20:18 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2005-01-13 21:52:39 +00:00
|
|
|
pin_id = opt_objectid ? opt_objectid : opt_authid;
|
|
|
|
|
|
|
|
if (!pin_id) {
|
|
|
|
error("No pin id specified\n");
|
2002-04-02 13:28:31 +00:00
|
|
|
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
|
|
|
|
2003-12-16 14:41:04 +00:00
|
|
|
if ((r = get_new_pin(&hints, "user", "pin", &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
|
|
|
|
2003-12-16 14:41:04 +00:00
|
|
|
hints.flags |= SC_UI_PIN_OPTIONAL;
|
|
|
|
if ((r = get_new_pin(&hints, "user", "puk", &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));
|
2005-01-13 21:52:39 +00:00
|
|
|
sc_pkcs15_format_id(pin_id, &args.auth_id);
|
2002-04-02 13:28:31 +00:00
|
|
|
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) {
|
2005-07-20 17:58:55 +00:00
|
|
|
unsigned int usage;
|
|
|
|
|
|
|
|
/* tell openssl to cache the extensions */
|
|
|
|
X509_check_purpose(cert[0], -1, -1);
|
|
|
|
usage = cert[0]->ex_kusage;
|
2003-04-17 12:38:08 +00:00
|
|
|
|
|
|
|
/* No certificate usage? Assume ordinary
|
|
|
|
* user cert */
|
2005-07-20 17:58:55 +00:00
|
|
|
if (usage == 0)
|
|
|
|
usage = 0x1F;
|
2003-04-17 12:38:08 +00:00
|
|
|
|
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-10-30 11:36:04 +00:00
|
|
|
|
|
|
|
/* Encode the cert */
|
|
|
|
if ((r = do_convert_cert(&cargs.der_encoded, cert[i])) < 0)
|
|
|
|
return r;
|
|
|
|
|
2005-07-20 17:58:55 +00:00
|
|
|
X509_check_purpose(cert[i], -1, -1);
|
2003-10-30 11:36:04 +00:00
|
|
|
cargs.x509_usage = cert[i]->ex_kusage;
|
|
|
|
cargs.label = X509_NAME_oneline(cert[i]->cert_info->subject,
|
|
|
|
namebuf, sizeof(namebuf));
|
|
|
|
|
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 */
|
2003-10-30 11:36:04 +00:00
|
|
|
if (i == 0) {
|
2003-04-16 11:50:49 +00:00
|
|
|
cargs.id = args.id;
|
2004-01-24 20:55:34 +00:00
|
|
|
if (opt_cert_label != 0)
|
|
|
|
cargs.label = opt_cert_label;
|
2003-10-30 11:36:04 +00:00
|
|
|
} else {
|
|
|
|
if (is_cacert_already_present(&cargs)) {
|
|
|
|
printf("Certificate #%d already present, "
|
|
|
|
"not stored.\n", i);
|
|
|
|
goto next_cert;
|
|
|
|
}
|
2003-04-16 11:50:49 +00:00
|
|
|
cargs.authority = 1;
|
2003-10-30 11:36:04 +00:00
|
|
|
}
|
2003-04-16 11:50:49 +00:00
|
|
|
|
2003-10-30 11:36:04 +00:00
|
|
|
r = sc_pkcs15init_store_certificate(p15card, profile,
|
2002-04-11 15:14:40 +00:00
|
|
|
&cargs, NULL);
|
2003-10-30 11:36:04 +00:00
|
|
|
next_cert:
|
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
|
|
|
}
|
|
|
|
|
2003-10-30 11:36:04 +00:00
|
|
|
/*
|
|
|
|
* Check if the CA certificate is already present
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
is_cacert_already_present(struct sc_pkcs15init_certargs *args)
|
|
|
|
{
|
|
|
|
sc_pkcs15_object_t *objs[32];
|
|
|
|
sc_pkcs15_cert_info_t *cinfo;
|
|
|
|
sc_pkcs15_cert_t *cert;
|
2005-12-05 21:29:54 +00:00
|
|
|
int i, count, r;
|
2003-10-30 11:36:04 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, objs, 32);
|
|
|
|
if (r <= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
count = r;
|
2005-12-05 21:29:54 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
2003-10-30 11:36:04 +00:00
|
|
|
cinfo = (sc_pkcs15_cert_info_t *) objs[i]->data;
|
|
|
|
|
|
|
|
if (!cinfo->authority)
|
|
|
|
continue;
|
|
|
|
if (args->label && objs[i]->label
|
|
|
|
&& strcmp(args->label, objs[i]->label))
|
|
|
|
continue;
|
|
|
|
/* XXX we should also match the usage field here */
|
|
|
|
|
|
|
|
/* Compare the DER representation of the certificates */
|
|
|
|
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
|
2005-12-05 21:29:54 +00:00
|
|
|
if (r < 0 || !cert)
|
2003-10-30 11:36:04 +00:00
|
|
|
continue;
|
|
|
|
|
2005-12-05 21:29:54 +00:00
|
|
|
if (cert->data_len == args->der_encoded.len
|
2003-10-30 11:36:04 +00:00
|
|
|
&& !memcmp(cert->data, args->der_encoded.value,
|
2005-12-05 21:29:54 +00:00
|
|
|
cert->data_len)) {
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
|
|
|
return 1;
|
|
|
|
}
|
2003-10-30 11:36:04 +00:00
|
|
|
sc_pkcs15_free_certificate(cert);
|
2005-12-05 21:29:54 +00:00
|
|
|
cert=NULL;
|
2003-10-30 11:36:04 +00:00
|
|
|
}
|
|
|
|
|
2005-12-05 21:29:54 +00:00
|
|
|
return 0;
|
2003-10-30 11:36:04 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2004-01-24 20:55:34 +00:00
|
|
|
args.label = (opt_pubkey_label != 0 ? opt_pubkey_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;
|
2005-02-06 10:06:21 +00:00
|
|
|
X509 *cert = NULL;
|
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);
|
2004-01-24 20:55:34 +00:00
|
|
|
args.label = (opt_cert_label != 0 ? opt_cert_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
|
|
|
|
2005-01-21 18:25:26 +00:00
|
|
|
if (args.der_encoded.value)
|
|
|
|
free(args.der_encoded.value);
|
|
|
|
|
2002-04-02 13:28:31 +00:00
|
|
|
return r;
|
2002-03-12 10:08:18 +00:00
|
|
|
}
|
|
|
|
|
2005-09-15 19:40:20 +00:00
|
|
|
static int
|
|
|
|
do_read_check_certificate(sc_pkcs15_cert_t *sc_oldcert,
|
|
|
|
const char *filename, const char *format, sc_pkcs15_der_t *newcert_raw)
|
|
|
|
{
|
|
|
|
X509 *oldcert, *newcert;
|
|
|
|
EVP_PKEY *oldpk, *newpk;
|
|
|
|
u8 *ptr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Get the public key from the old cert */
|
|
|
|
ptr = sc_oldcert->data;
|
|
|
|
oldcert = d2i_X509(NULL, &ptr, sc_oldcert->data_len);
|
|
|
|
|
|
|
|
if (oldcert == NULL)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
|
|
|
/* Read the new cert from file and get it's public key */
|
|
|
|
r = do_read_certificate(filename, format, &newcert);
|
|
|
|
if (r < 0) {
|
|
|
|
X509_free(oldcert);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldpk = X509_get_pubkey(oldcert);
|
|
|
|
newpk = X509_get_pubkey(newcert);
|
|
|
|
|
|
|
|
/* Compare the public keys, there's no high level openssl function for this(?) */
|
|
|
|
r = SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
if (oldpk->type == newpk->type)
|
|
|
|
{
|
|
|
|
if ((oldpk->type == EVP_PKEY_DSA) &&
|
|
|
|
!BN_cmp(oldpk->pkey.dsa->p, newpk->pkey.dsa->p) &&
|
|
|
|
!BN_cmp(oldpk->pkey.dsa->q, newpk->pkey.dsa->q) &&
|
|
|
|
!BN_cmp(oldpk->pkey.dsa->g, newpk->pkey.dsa->g))
|
|
|
|
r = 0;
|
|
|
|
else if ((oldpk->type == EVP_PKEY_RSA) &&
|
|
|
|
!BN_cmp(oldpk->pkey.rsa->n, newpk->pkey.rsa->n) &&
|
|
|
|
!BN_cmp(oldpk->pkey.rsa->e, newpk->pkey.rsa->e))
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_PKEY_free(newpk);
|
|
|
|
EVP_PKEY_free(oldpk);
|
|
|
|
X509_free(oldcert);
|
|
|
|
|
|
|
|
if (r == 0)
|
|
|
|
r = do_convert_cert(newcert_raw, newcert);
|
|
|
|
else
|
|
|
|
error("the public keys in the old and new certificate differ");
|
|
|
|
|
|
|
|
X509_free(newcert);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update an existing certificate with a new certificate having
|
|
|
|
* the same public key.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
do_update_certificate(struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
sc_pkcs15_id_t id;
|
|
|
|
sc_pkcs15_object_t *obj;
|
|
|
|
sc_pkcs15_cert_info_t *certinfo;
|
|
|
|
sc_pkcs15_cert_t *oldcert = NULL;
|
|
|
|
sc_pkcs15_der_t newcert_raw;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
set_userpin_ref();
|
|
|
|
|
|
|
|
if (opt_objectid == NULL) {
|
|
|
|
error("no ID given for the cert: use --id");
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &id);
|
|
|
|
if (sc_pkcs15_find_cert_by_id(p15card, &id, &obj) != 0) {
|
|
|
|
error("Couldn't find the cert with ID %s\n", opt_objectid);
|
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
certinfo = (sc_pkcs15_cert_info_t *) obj->data;
|
|
|
|
r = sc_pkcs15_read_certificate(p15card, certinfo, &oldcert);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
newcert_raw.value = NULL;
|
|
|
|
r = do_read_check_certificate(oldcert, opt_infile, opt_format, &newcert_raw);
|
|
|
|
sc_pkcs15_free_certificate(oldcert);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sc_pkcs15init_update_certificate(p15card, profile, obj,
|
|
|
|
newcert_raw.value, newcert_raw.len);
|
|
|
|
|
|
|
|
if (newcert_raw.value)
|
|
|
|
free(newcert_raw.value);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
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));
|
2005-08-10 18:20:04 +00:00
|
|
|
args.app_oid.value[0] = -1;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
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;
|
2004-07-26 18:47:23 +00:00
|
|
|
args.app_label = "pkcs15-init";
|
|
|
|
|
2005-10-30 18:05:30 +00:00
|
|
|
sc_format_oid(&args.app_oid, opt_application_id);
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-08-22 09:23:46 +00:00
|
|
|
static inline int cert_is_root(sc_pkcs15_cert_t *c)
|
|
|
|
{
|
|
|
|
return (c->subject_len == c->issuer_len) &&
|
|
|
|
(memcmp(c->subject, c->issuer, c->subject_len) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the cert has a 'sibling' and return it's parent cert.
|
|
|
|
* Should be made more effcicient for long chains by caching the certs.
|
|
|
|
*/
|
2007-06-21 13:38:16 +00:00
|
|
|
static int get_cert_info(sc_pkcs15_card_t *myp15card, sc_pkcs15_object_t *certobj,
|
2005-08-22 09:23:46 +00:00
|
|
|
int *has_sibling, int *stop, sc_pkcs15_object_t **issuercert)
|
|
|
|
{
|
|
|
|
sc_pkcs15_cert_t *cert = NULL;
|
|
|
|
sc_pkcs15_object_t *otherobj;
|
|
|
|
sc_pkcs15_cert_t *othercert = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
*issuercert = NULL;
|
|
|
|
*has_sibling = 0;
|
|
|
|
*stop = 0;
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
r = sc_pkcs15_read_certificate(myp15card, (sc_pkcs15_cert_info_t *) certobj->data, &cert);
|
2005-08-22 09:23:46 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (cert_is_root(cert)) {
|
|
|
|
*stop = 1; /* root -> no parent and hence no siblings */
|
|
|
|
goto done;
|
|
|
|
}
|
2007-06-21 13:38:16 +00:00
|
|
|
for (otherobj = myp15card->obj_list; otherobj != NULL; otherobj = otherobj->next) {
|
2005-08-22 09:23:46 +00:00
|
|
|
if ((otherobj == certobj) ||
|
|
|
|
!((otherobj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_CERT))
|
|
|
|
continue;
|
2005-12-05 21:29:54 +00:00
|
|
|
if (othercert) {
|
2005-08-22 09:23:46 +00:00
|
|
|
sc_pkcs15_free_certificate(othercert);
|
2005-12-05 21:29:54 +00:00
|
|
|
othercert=NULL;
|
|
|
|
}
|
2007-06-21 13:38:16 +00:00
|
|
|
r = sc_pkcs15_read_certificate(myp15card, (sc_pkcs15_cert_info_t *) otherobj->data, &othercert);
|
2005-12-05 21:29:54 +00:00
|
|
|
if (r < 0 || !othercert)
|
2005-08-22 09:23:46 +00:00
|
|
|
goto done;
|
|
|
|
if ((cert->issuer_len == othercert->subject_len) &&
|
|
|
|
(memcmp(cert->issuer, othercert->subject, cert->issuer_len) == 0)) {
|
|
|
|
/* parent cert found */
|
|
|
|
*issuercert = otherobj;
|
|
|
|
*stop = cert_is_root(othercert);
|
|
|
|
}
|
|
|
|
else if (!cert_is_root(othercert) && (cert->issuer_len == othercert->issuer_len) &&
|
|
|
|
(memcmp(cert->issuer, othercert->issuer, cert->issuer_len) == 0)) {
|
|
|
|
*has_sibling = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (cert)
|
|
|
|
sc_pkcs15_free_certificate(cert);
|
|
|
|
if (othercert)
|
|
|
|
sc_pkcs15_free_certificate(othercert);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete object(s) by ID. The 'which' param can be any combination of
|
2006-01-03 16:24:54 +00:00
|
|
|
* SC_PKCS15INIT_TYPE_PRKEY, SC_PKCS15INIT_TYPE_PUBKEY, SC_PKCS15INIT_TYPE_CERT
|
|
|
|
* and SC_PKCS15INIT_TYPE_CHAIN. In the last case, every cert in the chain is
|
2005-08-22 09:23:46 +00:00
|
|
|
* deleted, starting with the cert with ID 'id' and untill a CA cert is
|
|
|
|
* reached that certified other remaining certs on the card.
|
|
|
|
*/
|
2007-06-21 13:38:16 +00:00
|
|
|
static int do_delete_crypto_objects(sc_pkcs15_card_t *myp15card,
|
2005-08-22 09:23:46 +00:00
|
|
|
sc_profile_t *profile,
|
|
|
|
const sc_pkcs15_id_t id,
|
|
|
|
unsigned int which)
|
|
|
|
{
|
|
|
|
sc_pkcs15_object_t *objs[10]; /* 1 priv + 1 pub + chain of at most 8 certs, should be enough */
|
2007-06-21 13:38:16 +00:00
|
|
|
sc_context_t *myctx = myp15card->card->ctx;
|
2005-08-22 09:23:46 +00:00
|
|
|
int i, r = 0, count = 0, del_cert = 0;
|
|
|
|
|
2006-01-03 16:24:54 +00:00
|
|
|
if (which & SC_PKCS15INIT_TYPE_PRKEY) {
|
2007-06-21 13:38:16 +00:00
|
|
|
if (sc_pkcs15_find_prkey_by_id(myp15card, &id, &objs[count]) != 0)
|
|
|
|
sc_debug(myctx, "NOTE: couldn't find privkey %s to delete\n", sc_pkcs15_print_id(&id));
|
2005-08-22 09:23:46 +00:00
|
|
|
else
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2006-01-03 16:24:54 +00:00
|
|
|
if (which & SC_PKCS15INIT_TYPE_PUBKEY) {
|
2007-06-21 13:38:16 +00:00
|
|
|
if (sc_pkcs15_find_pubkey_by_id(myp15card, &id, &objs[count]) != 0)
|
|
|
|
sc_debug(myctx, "NOTE: couldn't find pubkey %s to delete\n", sc_pkcs15_print_id(&id));
|
2005-08-22 09:23:46 +00:00
|
|
|
else
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2006-01-03 16:24:54 +00:00
|
|
|
if (which & SC_PKCS15INIT_TYPE_CERT) {
|
2007-06-21 13:38:16 +00:00
|
|
|
if (sc_pkcs15_find_cert_by_id(myp15card, &id, &objs[count]) != 0)
|
|
|
|
sc_debug(myctx, "NOTE: couldn't find cert %s to delete\n", sc_pkcs15_print_id(&id));
|
2005-08-22 09:23:46 +00:00
|
|
|
else {
|
|
|
|
count++;
|
|
|
|
del_cert = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-03 16:24:54 +00:00
|
|
|
if (del_cert && ((which & SC_PKCS15INIT_TYPE_CHAIN) == SC_PKCS15INIT_TYPE_CHAIN)) {
|
2005-08-22 09:23:46 +00:00
|
|
|
/* Get the cert chain, stop if there's a CA that is the issuer of
|
|
|
|
* other certs on this card */
|
|
|
|
int has_sibling; /* siblings: certs having the same issuer */
|
|
|
|
int stop;
|
|
|
|
for( ; count < 10 ; count++) {
|
2007-06-21 13:38:16 +00:00
|
|
|
r = get_cert_info(myp15card, objs[count - 1], &has_sibling, &stop, &objs[count]);
|
2005-08-22 09:23:46 +00:00
|
|
|
if (r < 0)
|
2007-06-21 13:38:16 +00:00
|
|
|
sc_error(myctx, "get_cert_info() failed: %s\n", sc_strerror(r));
|
2005-08-22 09:23:46 +00:00
|
|
|
else if (has_sibling)
|
2007-06-21 13:38:16 +00:00
|
|
|
sc_debug(myctx, "Chain deletion stops with cert %s\n", sc_pkcs15_print_id(
|
2005-08-22 09:23:46 +00:00
|
|
|
&((sc_pkcs15_cert_info_t *) objs[count - 1]->data)->id));
|
2005-09-28 14:52:32 +00:00
|
|
|
else if (stop && (objs[count] != NULL))
|
2005-08-22 09:23:46 +00:00
|
|
|
count++;
|
|
|
|
if (stop || (objs[count] == NULL))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
count = -1; /* Something wrong -> don't delete anything */
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2007-06-21 13:38:16 +00:00
|
|
|
r = sc_pkcs15init_delete_object(myp15card, profile, objs[i]);
|
2005-08-22 09:23:46 +00:00
|
|
|
if (r < 0) {
|
2007-06-21 13:38:16 +00:00
|
|
|
sc_error(myctx, "Failed to delete object %d: %s\n", i, sc_strerror(r));
|
2005-08-22 09:23:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r < 0 ? r : count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-06-21 13:38:16 +00:00
|
|
|
do_delete_objects(struct sc_profile *profile, unsigned int myopt_delete_flags)
|
2005-08-22 09:23:46 +00:00
|
|
|
{
|
2005-08-24 15:59:01 +00:00
|
|
|
int r = 0, count = 0;
|
2005-08-22 09:23:46 +00:00
|
|
|
|
2005-08-23 09:01:57 +00:00
|
|
|
set_userpin_ref();
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
if (myopt_delete_flags & SC_PKCS15INIT_TYPE_DATA) {
|
2005-08-22 09:23:46 +00:00
|
|
|
struct sc_object_id app_oid;
|
|
|
|
sc_pkcs15_object_t *obj;
|
|
|
|
if (opt_application_id == NULL)
|
|
|
|
fatal("Specify the --application-id for the data object to be deleted\n");
|
2005-10-30 18:05:30 +00:00
|
|
|
sc_format_oid(&app_oid, opt_application_id);
|
2005-08-22 09:23:46 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15_find_data_object_by_app_oid(p15card, &app_oid, &obj);
|
|
|
|
if (r >= 0) {
|
|
|
|
r = sc_pkcs15init_delete_object(p15card, profile, obj);
|
|
|
|
if (r >= 0)
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
if (myopt_delete_flags & (SC_PKCS15INIT_TYPE_PRKEY | SC_PKCS15INIT_TYPE_PUBKEY | SC_PKCS15INIT_TYPE_CHAIN)) {
|
2005-08-22 09:23:46 +00:00
|
|
|
sc_pkcs15_id_t id;
|
|
|
|
if (opt_objectid == NULL)
|
|
|
|
fatal("Specify the --id for key(s) or cert(s) to be deleted\n");
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &id);
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
r = do_delete_crypto_objects(p15card, profile, id, myopt_delete_flags);
|
2005-08-22 09:23:46 +00:00
|
|
|
if (r >= 0)
|
|
|
|
count += r;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Deleted %d objects\n", count);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2006-01-03 16:24:54 +00:00
|
|
|
static int
|
2007-06-21 13:38:16 +00:00
|
|
|
do_change_attributes(struct sc_profile *profile, unsigned int myopt_type)
|
2006-01-03 16:24:54 +00:00
|
|
|
{
|
2006-02-07 20:14:43 +00:00
|
|
|
int r = 0;
|
2006-01-03 16:24:54 +00:00
|
|
|
sc_pkcs15_id_t id;
|
2006-05-01 10:16:48 +00:00
|
|
|
sc_pkcs15_object_t *obj = NULL;
|
2006-01-03 16:24:54 +00:00
|
|
|
|
|
|
|
if (opt_objectid == NULL) {
|
|
|
|
printf("You have to specify the --id of the object\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
sc_pkcs15_format_id(opt_objectid, &id);
|
|
|
|
|
|
|
|
/* Right now, only changing the label is supported */
|
|
|
|
if (opt_label == NULL) {
|
|
|
|
printf("You should specify a --label\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
switch(myopt_type) {
|
2006-01-03 16:24:54 +00:00
|
|
|
case SC_PKCS15INIT_TYPE_PRKEY:
|
|
|
|
if ((r = sc_pkcs15_find_prkey_by_id(p15card, &id, &obj)) != 0)
|
|
|
|
return r;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15INIT_TYPE_PUBKEY:
|
|
|
|
if ((r = sc_pkcs15_find_pubkey_by_id(p15card, &id, &obj)) != 0)
|
|
|
|
return r;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15INIT_TYPE_CERT:
|
|
|
|
if ((r = sc_pkcs15_find_cert_by_id(p15card, &id, &obj)) != 0)
|
|
|
|
return r;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15INIT_TYPE_DATA:
|
|
|
|
if ((r = sc_pkcs15_find_data_object_by_id(p15card, &id, &obj)) != 0)
|
|
|
|
return r;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (obj == NULL) {
|
|
|
|
printf("No object of the specified type and with id = \"%s\" found\n", opt_objectid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt_label != NULL) {
|
2006-07-12 08:12:38 +00:00
|
|
|
strlcpy(obj->label, opt_label, sizeof(obj->label));
|
2006-01-03 16:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
set_userpin_ref();
|
|
|
|
|
|
|
|
r = sc_pkcs15init_update_any_df(p15card, profile, obj->df, 0);
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2003-12-08 12:02:28 +00:00
|
|
|
struct sc_pkcs15init_keygen_args keygen_args;
|
2002-04-15 13:42:10 +00:00
|
|
|
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
|
|
|
|
2004-01-05 08:56:32 +00:00
|
|
|
memset(&keygen_args, 0, sizeof(keygen_args));
|
|
|
|
keygen_args.pubkey_label = opt_pubkey_label;
|
|
|
|
|
2003-12-08 12:02:28 +00:00
|
|
|
if ((r = init_keyargs(&keygen_args.prkey_args)) < 0)
|
2002-04-17 20:47:18 +00:00
|
|
|
return r;
|
|
|
|
|
2002-03-06 17:49:47 +00:00
|
|
|
/* Parse the key spec given on the command line */
|
|
|
|
if (!strncasecmp(spec, "rsa", 3)) {
|
2003-12-08 12:02:28 +00:00
|
|
|
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_RSA;
|
2002-04-15 13:42:10 +00:00
|
|
|
evp_algo = EVP_PKEY_RSA;
|
2002-03-06 17:49:47 +00:00
|
|
|
spec += 3;
|
|
|
|
} else if (!strncasecmp(spec, "dsa", 3)) {
|
2003-12-08 12:02:28 +00:00
|
|
|
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_DSA;
|
2002-04-15 13:42:10 +00:00
|
|
|
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 */
|
2003-12-08 12:02:28 +00:00
|
|
|
if (sc_pkcs15init_requires_restrictive_usage(p15card,
|
|
|
|
&keygen_args.prkey_args, keybits)) {
|
2003-05-15 11:31:46 +00:00
|
|
|
if (!opt_split_key)
|
|
|
|
split_key_error();
|
|
|
|
split_key = 1;
|
|
|
|
}
|
|
|
|
|
2003-05-15 11:39:02 +00:00
|
|
|
if (!opt_softkeygen && !split_key) {
|
2003-12-08 12:02:28 +00:00
|
|
|
r = sc_pkcs15init_generate_key(p15card, profile, &keygen_args,
|
|
|
|
keybits, NULL);
|
2002-06-11 18:16:50 +00:00
|
|
|
if (r >= 0 || r != SC_ERROR_NOT_SUPPORTED)
|
2002-04-15 13:42:10 +00:00
|
|
|
return r;
|
2004-06-13 20:13:12 +00:00
|
|
|
if (verbose)
|
2002-03-06 17:49:47 +00:00
|
|
|
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
|
2003-12-08 12:02:28 +00:00
|
|
|
|| (r = do_convert_private_key(&keygen_args.prkey_args.key, pkey) ) < 0)
|
2003-05-15 11:31:46 +00:00
|
|
|
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,
|
2003-12-08 12:02:28 +00:00
|
|
|
profile, &keygen_args.prkey_args, NULL, NULL);
|
2003-05-15 11:31:46 +00:00
|
|
|
} else {
|
|
|
|
r = sc_pkcs15init_store_private_key(p15card,
|
2003-12-08 12:02:28 +00:00
|
|
|
profile, &keygen_args.prkey_args, NULL);
|
2003-05-15 11:31:46 +00:00
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
static int init_keyargs(struct sc_pkcs15init_prkeyargs *args)
|
2002-04-17 20:47:18 +00:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
*/
|
2005-02-06 21:01:09 +00:00
|
|
|
static void
|
2003-05-18 10:08:26 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
static void set_secrets(struct sc_profile *profile)
|
2003-05-18 10:08:26 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-16 14:41:04 +00:00
|
|
|
/*
|
|
|
|
* Prompt for a new PIN
|
|
|
|
* @role can be "user" or "so"
|
|
|
|
* @usage can be "pin" or "puk"
|
|
|
|
*/
|
2007-06-21 13:38:16 +00:00
|
|
|
static int get_new_pin(sc_ui_hints_t *hints,
|
2003-12-16 14:41:04 +00:00
|
|
|
const char *role, const char *usage,
|
|
|
|
char **retstr)
|
|
|
|
{
|
|
|
|
char name[32], prompt[64], label[64];
|
|
|
|
|
|
|
|
snprintf(name, sizeof(name), "pkcs15init.new_%s_%s", role, usage);
|
|
|
|
|
|
|
|
if (!strcmp(role, "user"))
|
|
|
|
role = "User";
|
|
|
|
else
|
|
|
|
role = "Security Officer";
|
|
|
|
|
|
|
|
if (!strcmp(usage, "pin")) {
|
|
|
|
snprintf(prompt, sizeof(prompt), "New %s PIN", role);
|
|
|
|
snprintf(label, sizeof(label), "%s PIN", role);
|
|
|
|
} else {
|
|
|
|
snprintf(prompt, sizeof(prompt),
|
|
|
|
"Unblock Code for New %s PIN", role);
|
|
|
|
snprintf(label, sizeof(label),
|
|
|
|
"%s unblocking PIN (PUK)", role);
|
|
|
|
}
|
|
|
|
|
|
|
|
hints->dialog_name = name;
|
|
|
|
hints->prompt = prompt;
|
|
|
|
hints->obj_label = label;
|
|
|
|
|
|
|
|
return sc_ui_get_pin(hints, retstr);
|
|
|
|
}
|
|
|
|
|
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];
|
2005-02-06 21:01:09 +00:00
|
|
|
char *secret = NULL;
|
|
|
|
const char *name;
|
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
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
static int get_key_callback(struct sc_profile *profile,
|
2002-12-04 11:56:51 +00:00
|
|
|
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
|
|
|
|
*/
|
2007-06-21 13:38:16 +00:00
|
|
|
static int do_generate_key_soft(int algorithm, unsigned int bits,
|
|
|
|
EVP_PKEY **res)
|
2002-04-15 13:42:10 +00:00
|
|
|
{
|
|
|
|
*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
|
|
|
*/
|
2004-07-12 08:26:53 +00:00
|
|
|
static int pass_cb(char *buf, int len, int flags, void *d)
|
|
|
|
{
|
|
|
|
int plen;
|
|
|
|
char *pass;
|
|
|
|
if (d)
|
|
|
|
pass = (char *)d;
|
|
|
|
else
|
|
|
|
pass = getpass("Please enter passphrase "
|
|
|
|
"to unlock secret key: ");
|
2004-07-12 08:42:55 +00:00
|
|
|
if (!pass)
|
|
|
|
return 0;
|
2004-07-12 08:26:53 +00:00
|
|
|
plen = strlen(pass);
|
|
|
|
if (plen <= 0)
|
|
|
|
return 0;
|
|
|
|
if (plen > len)
|
|
|
|
plen = len;
|
|
|
|
memcpy(buf, pass, plen);
|
|
|
|
return plen;
|
|
|
|
}
|
|
|
|
|
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());
|
2004-07-12 08:26:53 +00:00
|
|
|
if (BIO_read_filename(bio, filename) <= 0)
|
2002-02-23 13:38:01 +00:00
|
|
|
fatal("Unable to open %s: %m", filename);
|
2007-06-21 13:38:16 +00:00
|
|
|
*key = PEM_read_bio_PrivateKey(bio, NULL, pass_cb, (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());
|
2004-07-12 08:26:53 +00:00
|
|
|
if (BIO_read_filename(bio, filename) <= 0)
|
2002-03-12 16:27:21 +00:00
|
|
|
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 */
|
2005-02-06 21:01:09 +00:00
|
|
|
for(i = 0; cacerts && ncerts < (int)max_certs && i < sk_X509_num(cacerts); i++)
|
2003-04-16 11:50:49 +00:00
|
|
|
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
|
|
|
|
2004-06-25 15:44:33 +00:00
|
|
|
if (opt_passphrase)
|
|
|
|
passphrase = opt_passphrase;
|
|
|
|
|
2004-07-12 08:26:53 +00:00
|
|
|
if (!format || !strcasecmp(format, "pem")) {
|
|
|
|
r = do_read_pem_private_key(filename, passphrase, pk);
|
|
|
|
} else if (!strcasecmp(format, "pkcs12")) {
|
|
|
|
r = do_read_pkcs12_private_key(filename,
|
|
|
|
passphrase, pk, certs, max_certs);
|
|
|
|
if (r < 0 && !passphrase) {
|
|
|
|
/* this makes only sense for PKCS#12
|
|
|
|
* PKCS12_parse must support passphrases with
|
|
|
|
* length zero and NULL because of the specification
|
|
|
|
* of PKCS12 - please see the sourcecode of OpenSSL
|
|
|
|
* therefore OpenSSL does not ask for a passphrase like
|
|
|
|
* the PEM interface
|
|
|
|
* see OpenSSL: crypto/pkcs12/p12_kiss.c
|
|
|
|
*/
|
|
|
|
passphrase = getpass("Please enter passphrase "
|
|
|
|
"to unlock secret key: ");
|
|
|
|
r = do_read_pkcs12_private_key(filename,
|
|
|
|
passphrase, pk, certs, max_certs);
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
2004-07-12 08:26:53 +00:00
|
|
|
} else {
|
|
|
|
error("Error when reading private key. "
|
|
|
|
"Key file format \"%s\" not supported.\n", format);
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2002-02-23 13:38:01 +00:00
|
|
|
}
|
2004-07-12 08:26:53 +00:00
|
|
|
|
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());
|
2004-07-12 08:26:53 +00:00
|
|
|
if (BIO_read_filename(bio, filename) <= 0)
|
2002-03-12 10:08:18 +00:00
|
|
|
fatal("Unable to open %s: %m", filename);
|
2007-06-21 13:38:16 +00:00
|
|
|
pk = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
2002-03-12 10:08:18 +00:00
|
|
|
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());
|
2004-07-12 08:26:53 +00:00
|
|
|
if (BIO_read_filename(bio, filename) <= 0)
|
2002-03-12 10:08:18 +00:00
|
|
|
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());
|
2004-07-12 08:26:53 +00:00
|
|
|
if (BIO_read_filename(bio, filename) <= 0)
|
2002-03-12 10:08:18 +00:00
|
|
|
fatal("Unable to open %s: %m", filename);
|
2007-06-21 13:38:16 +00:00
|
|
|
xp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
2002-03-12 10:08:18 +00:00
|
|
|
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());
|
2004-07-12 08:26:53 +00:00
|
|
|
if (BIO_read_filename(bio, filename) <= 0)
|
2002-03-12 10:08:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
static int do_convert_private_key(struct sc_pkcs15_prkey *key, EVP_PKEY *pk)
|
2002-04-15 13:42:10 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
static int do_convert_public_key(struct sc_pkcs15_pubkey *key, EVP_PKEY *pk)
|
2002-04-15 13:42:10 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:38:16 +00:00
|
|
|
static int do_convert_cert(sc_pkcs15_der_t *der, X509 *cert)
|
2002-04-15 13:42:10 +00:00
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
|
2005-08-22 09:23:46 +00:00
|
|
|
static unsigned int
|
2006-01-03 16:24:54 +00:00
|
|
|
parse_objects(const char *list, unsigned int action)
|
2005-08-22 09:23:46 +00:00
|
|
|
{
|
|
|
|
unsigned int res = 0;
|
|
|
|
static struct {
|
|
|
|
const char *name;
|
|
|
|
unsigned int flag;
|
|
|
|
} del_flags[] = {
|
2006-01-03 16:24:54 +00:00
|
|
|
{"privkey", SC_PKCS15INIT_TYPE_PRKEY},
|
|
|
|
{"pubkey", SC_PKCS15INIT_TYPE_PUBKEY},
|
|
|
|
{"cert", SC_PKCS15INIT_TYPE_CERT},
|
|
|
|
{"chain", SC_PKCS15INIT_TYPE_CHAIN},
|
|
|
|
{"data", SC_PKCS15INIT_TYPE_DATA},
|
2005-08-22 09:23:46 +00:00
|
|
|
{NULL, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
while (1) {
|
2005-08-24 15:59:01 +00:00
|
|
|
int len, n;
|
2005-08-22 09:23:46 +00:00
|
|
|
|
|
|
|
while (*list == ',')
|
|
|
|
list++;
|
|
|
|
if (!*list)
|
|
|
|
break;
|
|
|
|
len = strcspn(list, ",");
|
|
|
|
if (len == 4 && !strncasecmp(list, "help", 4)) {
|
2006-01-03 16:24:54 +00:00
|
|
|
if (action == ACTION_DELETE_OBJECTS) {
|
|
|
|
printf("\nDelete arguments: a comma-separated list containing any of the following:\n");
|
|
|
|
printf(" privkey,pubkey,cert,chain,data\n");
|
|
|
|
printf("When \"data\" is specified, an --application-id must also be specified,\n");
|
|
|
|
printf(" in the other cases an \"--id\" must also be specified\n");
|
|
|
|
printf("When \"chain\" is specified, the certificate chain starting with the cert\n");
|
|
|
|
printf(" with specified ID will be deleted, untill there's a CA cert that certifies\n");
|
|
|
|
printf(" another cert on the card\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("\nChange attribute argument: either privkey, pubkey, cert or data\n");
|
|
|
|
printf("You also have to specify the --id of the object\n");
|
|
|
|
printf("For now, you can only change the --label\n");
|
|
|
|
printf("E.g. pkcs15-init -A cert --id 45 -a 1 --label Jim\n");
|
|
|
|
}
|
2005-08-22 09:23:46 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
for (n = 0; del_flags[n].name; n++) {
|
|
|
|
if (!strncasecmp(del_flags[n].name, list, len)) {
|
|
|
|
res |= del_flags[n].flag;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (del_flags[n].name == NULL) {
|
|
|
|
fprintf(stderr, "Unknown argument for --delete_objects: %.*s\n", len, list);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
list += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-08-23 09:01:57 +00:00
|
|
|
/* If the user PIN and it's ID is given, put the pin ref in the keycache */
|
2007-06-21 13:38:16 +00:00
|
|
|
static void set_userpin_ref(void)
|
2005-08-23 09:01:57 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if ((opt_pins[0] != NULL) && (opt_authid != 0)) {
|
|
|
|
sc_path_t path;
|
|
|
|
sc_pkcs15_id_t auth_id;
|
|
|
|
sc_pkcs15_object_t *pinobj;
|
|
|
|
sc_pkcs15_pin_info_t *pin_info;
|
|
|
|
sc_format_path("3F00", &path);
|
|
|
|
sc_pkcs15_format_id(opt_authid, &auth_id);
|
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &auth_id, &pinobj);
|
|
|
|
if (r < 0)
|
|
|
|
fatal("Searching for user PIN %d failed: %s\n", opt_authid, sc_strerror(r));
|
|
|
|
pin_info = (sc_pkcs15_pin_info_t *) pinobj->data;
|
|
|
|
sc_keycache_set_pin_name(&path, pin_info->reference, SC_PKCS15INIT_USER_PIN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2005-09-06 21:18:26 +00:00
|
|
|
static struct {
|
|
|
|
const char* name;
|
|
|
|
unsigned int flag;
|
|
|
|
} x509_usage_names[] = {
|
2005-09-07 09:32:52 +00:00
|
|
|
{ "digitalSignature", SC_PKCS15INIT_X509_DIGITAL_SIGNATURE },
|
|
|
|
{ "nonRepudiation", SC_PKCS15INIT_X509_NON_REPUDIATION },
|
|
|
|
{ "keyEncipherment", SC_PKCS15INIT_X509_KEY_ENCIPHERMENT },
|
|
|
|
{ "dataEncipherment", SC_PKCS15INIT_X509_DATA_ENCIPHERMENT },
|
|
|
|
{ "keyAgreement", SC_PKCS15INIT_X509_KEY_AGREEMENT },
|
|
|
|
{ "keyCertSign", SC_PKCS15INIT_X509_KEY_CERT_SIGN },
|
|
|
|
{ "cRLSign", SC_PKCS15INIT_X509_CRL_SIGN },
|
2005-09-06 21:18:26 +00:00
|
|
|
{ NULL, 0 }
|
2002-10-02 10:50:53 +00:00
|
|
|
};
|
|
|
|
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");
|
2005-09-06 21:18:26 +00:00
|
|
|
for (n = 0; x509_usage_names[n].name; n++)
|
|
|
|
printf(" %s\n", x509_usage_names[n].name);
|
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);
|
|
|
|
}
|
2005-09-06 21:18:26 +00:00
|
|
|
for (n = 0; x509_usage_names[n].name != NULL; n++) {
|
|
|
|
if (!strncasecmp(x509_usage_names[n].name, list, len)) {
|
|
|
|
*res |= x509_usage_names[n].flag;
|
2002-10-02 10:50:53 +00:00
|
|
|
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;
|
2005-09-15 19:40:20 +00:00
|
|
|
case 'U':
|
|
|
|
this_action = ACTION_UPDATE_CERT;
|
|
|
|
opt_infile = optarg;
|
|
|
|
break;
|
2002-12-18 10:17:01 +00:00
|
|
|
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;
|
2005-08-22 09:23:46 +00:00
|
|
|
case 'D':
|
|
|
|
this_action = ACTION_DELETE_OBJECTS;
|
2006-01-03 16:24:54 +00:00
|
|
|
opt_delete_flags = parse_objects(optarg, ACTION_DELETE_OBJECTS);
|
|
|
|
break;
|
|
|
|
case 'A':
|
|
|
|
this_action = ACTION_CHANGE_ATTRIBUTES;
|
|
|
|
opt_type = parse_objects(optarg, ACTION_CHANGE_ATTRIBUTES);
|
2005-08-22 09:23:46 +00:00
|
|
|
break;
|
2004-06-13 20:13:12 +00:00
|
|
|
case 'v':
|
|
|
|
verbose++;
|
2002-02-23 13:38:01 +00:00
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
opt_format = optarg;
|
|
|
|
break;
|
2003-05-18 10:08:26 +00:00
|
|
|
case 'h':
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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;
|
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;
|
2004-07-26 18:47:23 +00:00
|
|
|
case OPT_APPLICATION_ID:
|
|
|
|
opt_application_id = optarg;
|
|
|
|
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;
|
2004-01-05 08:56:32 +00:00
|
|
|
case OPT_PUBKEY_LABEL:
|
|
|
|
opt_pubkey_label = optarg;
|
|
|
|
break;
|
2004-04-17 09:25:30 +00:00
|
|
|
case 'F':
|
|
|
|
this_action = ACTION_FINALIZE_CARD;
|
|
|
|
break;
|
2004-01-24 20:55:34 +00:00
|
|
|
case OPT_CERT_LABEL:
|
|
|
|
opt_cert_label = optarg;
|
|
|
|
break;
|
2002-02-23 13:38:01 +00:00
|
|
|
default:
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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");
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
2003-05-16 19:12:54 +00:00
|
|
|
}
|
|
|
|
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");
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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);
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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);
|
2007-06-21 13:46:08 +00:00
|
|
|
print_usage_and_die(app_name, options, option_help);
|
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
|
2007-06-21 13:38:16 +00:00
|
|
|
ossl_print_errors(void)
|
2002-02-23 13:38:01 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|