Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
73 contributors

Users who have contributed to this file

@Jakuje @AlexandreGonzalo @frankmorgner @viktorTarasov @xhanulik @dengert @popovec @nunojpg @mouse07410 @ulrichb @dfortinskiy1 @metsma
/*
* pkcs11-tool.c: Tool for poking around pkcs11 modules/tokens
*
* Copyright (C) 2002 Olaf Kirch <okir@suse.de>
*
* 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
*/
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
#else
#include <windows.h>
#include <io.h>
#endif
#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#include <openssl/opensslconf.h>
#include <openssl/crypto.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/asn1t.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
# include <openssl/core_names.h>
# include <openssl/param_build.h>
#include <openssl/provider.h>
#endif
#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#endif
#include <openssl/bn.h>
#include <openssl/err.h>
#endif
#include "pkcs11/pkcs11.h"
#include "pkcs11/pkcs11-opensc.h"
#include "libopensc/asn1.h"
#include "libopensc/log.h"
#include "common/compat_strlcat.h"
#include "common/compat_strlcpy.h"
#include "common/libpkcs11.h"
#include "util.h"
#include "libopensc/sc-ossl-compat.h"
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
static OSSL_PROVIDER *legacy_provider = NULL;
#endif
#ifdef _WIN32
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#endif
#ifndef ENABLE_SHARED
extern CK_FUNCTION_LIST_3_0 pkcs11_function_list_3_0;
#endif
#if defined(_WIN32) || defined(HAVE_PTHREAD)
#define MAX_TEST_THREADS 10
#endif
#define NEED_SESSION_RO 0x01
#define NEED_SESSION_RW 0x02
static struct ec_curve_info {
const char *name;
const char *oid;
const char *ec_params;
size_t size;
CK_KEY_TYPE mechanism;
} ec_curve_infos[] = {
{"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
{"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
{"prime192v2", "1.2.840.10045.3.1.2", "06082A8648CE3D030102", 192, 0},
{"prime192v3", "1.2.840.10045.3.1.3", "06082A8648CE3D030103", 192, 0},
{"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
{"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
{"secp224r1", "1.3.132.0.33", "06052b81040021", 224, 0},
{"nistp224", "1.3.132.0.33", "06052b81040021", 224, 0},
{"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, 0},
{"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, 0},
{"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, 0},
{"frp256v1", "1.2.250.1.223.101.256.1", "060a2a817a01815f65820001", 256, 0},
{"secp384r1", "1.3.132.0.34", "06052B81040022", 384, 0},
{"prime384v1", "1.3.132.0.34", "06052B81040022", 384, 0},
{"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384, 0},
{"prime521v1", "1.3.132.0.35", "06052B81040023", 521, 0},
{"secp521r1", "1.3.132.0.35", "06052B81040023", 521, 0},
{"nistp521", "1.3.132.0.35", "06052B81040023", 521, 0},
{"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192, 0},
{"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224, 0},
{"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256, 0},
{"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320, 0},
{"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384, 0},
{"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512, 0},
{"secp192k1", "1.3.132.0.31", "06052B8104001F", 192, 0},
{"secp256k1", "1.3.132.0.10", "06052B8104000A", 256, 0},
{"secp521k1", "1.3.132.0.35", "06052B81040023", 521, 0},
{"edwards25519","1.3.6.1.4.1159.15.1", "130c656477617264733235353139", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN},
{"curve25519", "1.3.6.1.4.3029.1.5.1", "130b63757276653235353139", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN},
{NULL, NULL, NULL, 0, 0},
};
static const struct sc_aid GOST_HASH2001_PARAMSET_OID = { { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 }, 9 };
static const struct sc_aid GOST_HASH2012_256_PARAMSET_OID = { { 0x06, 0x08, 0x2A, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02 }, 10 };
static const struct sc_aid GOST_HASH2012_512_PARAMSET_OID = { { 0x06, 0x08, 0x2A, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03 }, 10 };
enum {
OPT_MODULE = 0x100,
OPT_SLOT,
OPT_SLOT_DESCRIPTION,
OPT_SLOT_INDEX,
OPT_TOKEN_LABEL,
OPT_APPLICATION_LABEL,
OPT_APPLICATION_ID,
OPT_ISSUER,
OPT_SUBJECT,
OPT_SO_PIN,
OPT_INIT_TOKEN,
OPT_INIT_PIN,
OPT_ATTR_FROM,
OPT_KEY_TYPE,
OPT_KEY_USAGE_SIGN,
OPT_KEY_USAGE_DECRYPT,
OPT_KEY_USAGE_DERIVE,
OPT_KEY_USAGE_WRAP,
OPT_PRIVATE,
OPT_SENSITIVE,
OPT_EXTRACTABLE,
OPT_UNDESTROYABLE,
OPT_TEST_HOTPLUG,
OPT_UNLOCK_PIN,
OPT_PUK,
OPT_NEW_PIN,
OPT_SESSION_RW,
OPT_LOGIN_TYPE,
OPT_TEST_EC,
OPT_DERIVE,
OPT_DERIVE_PASS_DER,
OPT_DECRYPT,
OPT_ENCRYPT,
OPT_UNWRAP,
OPT_WRAP,
OPT_TEST_FORK,
#if defined(_WIN32) || defined(HAVE_PTHREAD)
OPT_TEST_THREADS,
OPT_USE_LOCKING,
#endif
OPT_GENERATE_KEY,
OPT_GENERATE_RANDOM,
OPT_HASH_ALGORITHM,
OPT_MGF,
OPT_SALT,
OPT_VERIFY,
OPT_SIGNATURE_FILE,
OPT_ALWAYS_AUTH,
OPT_ALLOWED_MECHANISMS,
OPT_OBJECT_INDEX,
OPT_ALLOW_SW,
OPT_LIST_INTERFACES,
OPT_IV
};
static const struct option options[] = {
{ "module", 1, NULL, OPT_MODULE },
{ "show-info", 0, NULL, 'I' },
{ "list-slots", 0, NULL, 'L' },
{ "list-token-slots", 0, NULL, 'T' },
{ "list-mechanisms", 0, NULL, 'M' },
{ "list-objects", 0, NULL, 'O' },
{ "list-interfaces", 0, NULL, OPT_LIST_INTERFACES },
{ "sign", 0, NULL, 's' },
{ "verify", 0, NULL, OPT_VERIFY },
{ "decrypt", 0, NULL, OPT_DECRYPT },
{ "encrypt", 0, NULL, OPT_ENCRYPT },
{ "unwrap", 0, NULL, OPT_UNWRAP },
{ "wrap", 0, NULL, OPT_WRAP },
{ "hash", 0, NULL, 'h' },
{ "derive", 0, NULL, OPT_DERIVE },
{ "derive-pass-der", 0, NULL, OPT_DERIVE_PASS_DER },
{ "mechanism", 1, NULL, 'm' },
{ "hash-algorithm", 1, NULL, OPT_HASH_ALGORITHM },
{ "mgf", 1, NULL, OPT_MGF },
{ "salt-len", 1, NULL, OPT_SALT },
{ "session-rw", 0, NULL, OPT_SESSION_RW },
{ "login", 0, NULL, 'l' },
{ "login-type", 1, NULL, OPT_LOGIN_TYPE },
{ "pin", 1, NULL, 'p' },
{ "puk", 1, NULL, OPT_PUK },
{ "new-pin", 1, NULL, OPT_NEW_PIN },
{ "so-pin", 1, NULL, OPT_SO_PIN },
{ "init-token", 0, NULL, OPT_INIT_TOKEN },
{ "init-pin", 0, NULL, OPT_INIT_PIN },
{ "change-pin", 0, NULL, 'c' },
{ "unlock-pin", 0, NULL, OPT_UNLOCK_PIN },
{ "keypairgen", 0, NULL, 'k' },
{ "keygen", 0, NULL, OPT_GENERATE_KEY },
{ "key-type", 1, NULL, OPT_KEY_TYPE },
{ "usage-sign", 0, NULL, OPT_KEY_USAGE_SIGN },
{ "usage-decrypt", 0, NULL, OPT_KEY_USAGE_DECRYPT },
{ "usage-derive", 0, NULL, OPT_KEY_USAGE_DERIVE },
{ "usage-wrap", 0, NULL, OPT_KEY_USAGE_WRAP },
{ "write-object", 1, NULL, 'w' },
{ "read-object", 0, NULL, 'r' },
{ "delete-object", 0, NULL, 'b' },
{ "application-label", 1, NULL, OPT_APPLICATION_LABEL },
{ "application-id", 1, NULL, OPT_APPLICATION_ID },
{ "issuer", 1, NULL, OPT_ISSUER },
{ "subject", 1, NULL, OPT_SUBJECT },
{ "type", 1, NULL, 'y' },
{ "id", 1, NULL, 'd' },
{ "label", 1, NULL, 'a' },
{ "slot", 1, NULL, OPT_SLOT },
{ "slot-description", 1, NULL, OPT_SLOT_DESCRIPTION },
{ "slot-index", 1, NULL, OPT_SLOT_INDEX },
{ "object-index", 1, NULL, OPT_OBJECT_INDEX },
{ "token-label", 1, NULL, OPT_TOKEN_LABEL },
{ "set-id", 1, NULL, 'e' },
{ "attr-from", 1, NULL, OPT_ATTR_FROM },
{ "input-file", 1, NULL, 'i' },
{ "signature-file", 1, NULL, OPT_SIGNATURE_FILE },
{ "output-file", 1, NULL, 'o' },
{ "signature-format", 1, NULL, 'f' },
{ "allowed-mechanisms", 1, NULL, OPT_ALLOWED_MECHANISMS },
{ "test", 0, NULL, 't' },
{ "test-hotplug", 0, NULL, OPT_TEST_HOTPLUG },
{ "moz-cert", 1, NULL, 'z' },
{ "verbose", 0, NULL, 'v' },
{ "private", 0, NULL, OPT_PRIVATE },
{ "sensitive", 0, NULL, OPT_SENSITIVE },
{ "extractable", 0, NULL, OPT_EXTRACTABLE },
{ "undestroyable", 0, NULL, OPT_UNDESTROYABLE },
{ "always-auth", 0, NULL, OPT_ALWAYS_AUTH },
{ "test-ec", 0, NULL, OPT_TEST_EC },
#ifndef _WIN32
{ "test-fork", 0, NULL, OPT_TEST_FORK },
#endif
#if defined(_WIN32) || defined(HAVE_PTHREAD)
{ "use-locking", 0, NULL, OPT_USE_LOCKING },
{ "test-threads", 1, NULL, OPT_TEST_THREADS },
#endif
{ "generate-random", 1, NULL, OPT_GENERATE_RANDOM },
{ "allow-sw", 0, NULL, OPT_ALLOW_SW },
{ "iv", 1, NULL, OPT_IV },
{ NULL, 0, NULL, 0 }
};
static const char *option_help[] = {
"Specify the module to load (default:" DEFAULT_PKCS11_PROVIDER ")",
"Show global token information",
"List available slots",
"List slots with tokens",
"List mechanisms supported by the token",
"Show objects on token",
"List interfaces of PKCS #11 3.0 library",
"Sign some data",
"Verify a signature of some data",
"Decrypt some data",
"Encrypt some data",
"Unwrap key",
"Wrap key",
"Hash some data",
"Derive a secret key using another key and some data",
"Derive ECDHpass DER encoded pubkey for compatibility with some PKCS#11 implementations",
"Specify mechanism (use -M for a list of supported mechanisms), or by hexadecimal, e.g., 0x80001234",
"Specify hash algorithm used with RSA-PKCS-PSS signature and RSA-PKCS-OAEP decryption",
"Specify MGF (Message Generation Function) used for RSA-PSS signature and RSA-OAEP decryption (possible values are MGF1-SHA1 to MGF1-SHA512)",
"Specify how many bytes should be used for salt in RSA-PSS signatures (default is digest size)",
"Forces to open the PKCS#11 session with CKF_RW_SESSION",
"Log into the token first",
"Specify login type ('so', 'user', 'context-specific'; default:'user')",
"Supply User PIN on the command line (if used in scripts: careful!)",
"Supply User PUK on the command line",
"Supply new User PIN on the command line",
"Supply SO PIN on the command line (if used in scripts: careful!)",
"Initialize the token, its label and its SO PIN (use with --label and --so-pin)",
"Initialize the User PIN (use with --pin and --login)",
"Change User PIN",
"Unlock User PIN (without '--login' unlock in logged in session; otherwise '--login-type' has to be 'context-specific')",
"Key pair generation",
"Key generation",
"Specify the type and length (bytes if symmetric) of the key to create, for example rsa:1024, EC:prime256v1, EC:ed25519, EC:curve25519, GOSTR3410-2012-256:B, AES:16 or GENERIC:64",
"Specify 'sign' key usage flag (sets SIGN in privkey, sets VERIFY in pubkey)",
"Specify 'decrypt' key usage flag (sets DECRYPT in privkey and ENCRYPT in pubkey for RSA, sets both DECRYPT and ENCRYPT for secret keys)",
"Specify 'derive' key usage flag (EC only)",
"Specify 'wrap' key usage flag",
"Write an object (key, cert, data) to the card",
"Get object's CKA_VALUE attribute (use with --type)",
"Delete an object (use with --type cert/data/privkey/pubkey/secrkey)",
"Specify the application label of the data object (use with --type data)",
"Specify the application ID of the data object (use with --type data)",
"Specify the issuer in hexadecimal format (use with --type cert)",
"Specify the subject in hexadecimal format (use with --type cert/privkey/pubkey)",
"Specify the type of object (e.g. cert, privkey, pubkey, secrkey, data)",
"Specify the ID of the object",
"Specify the label of the object",
"Specify the ID of the slot to use",
"Specify the description of the slot to use",
"Specify the index of the slot to use",
"Specify the index of the object to use",
"Specify the token label of the slot to use",
"Set the CKA_ID of an object, <args>= the (new) CKA_ID",
"Use <arg> to create some attributes when writing an object",
"Specify the input file",
"Specify the file with signature for verification",
"Specify the output file",
"Format for ECDSA signature <arg>: 'rs' (default), 'sequence', 'openssl'",
"Specify the comma-separated list of allowed mechanisms when creating an object.",
"Test (best used with the --login or --pin option)",
"Test hotplug capabilities (C_GetSlotList + C_WaitForSlotEvent)",
"Test Mozilla-like key pair gen and cert req, <arg>=certfile",
"Verbose operation. (Set OPENSC_DEBUG to enable OpenSC specific debugging)",
"Set the CKA_PRIVATE attribute (object is only viewable after a login)",
"Set the CKA_SENSITIVE attribute (object cannot be revealed in plaintext)",
"Set the CKA_EXTRACTABLE attribute (object can be extracted)",
"Set the CKA_DESTROYABLE attribute to false (object cannot be destroyed)",
"Set the CKA_ALWAYS_AUTHENTICATE attribute to a key object (require PIN verification for each use)",
"Test EC (best used with the --login or --pin option)",
#ifndef _WIN32
"Test forking and calling C_Initialize() in the child",
#endif
"Call C_initialize() with CKF_OS_LOCKING_OK.",
#if defined(_WIN32) || defined(HAVE_PTHREAD)
"Test threads. Multiple times to start additional threads, arg is string or 2 byte commands",
#endif
"Generate given amount of random data",
"Allow using software mechanisms (without CKF_HW)",
"Initialization vector",
};
static const char * app_name = "pkcs11-tool"; /* for utils.c */
static int verbose = 0;
static const char * opt_input = NULL;
static const char * opt_output = NULL;
static const char * opt_signature_file = NULL;
static const char * opt_module = DEFAULT_PKCS11_PROVIDER;
static int opt_slot_set = 0;
static CK_SLOT_ID opt_slot = 0;
static const char * opt_slot_description = NULL;
static const char * opt_token_label = NULL;
static CK_ULONG opt_slot_index = 0;
static int opt_slot_index_set = 0;
static CK_ULONG opt_object_index = 0;
static int opt_object_index_set = 0;
static CK_MECHANISM_TYPE opt_mechanism = 0;
static int opt_mechanism_used = 0;
static const char * opt_file_to_write = NULL;
static const char * opt_object_class_str = NULL;
static CK_OBJECT_CLASS opt_object_class = -1;
static CK_BYTE opt_object_id[100], new_object_id[100];
static const char * opt_attr_from_file = NULL;
static size_t opt_object_id_len = 0, new_object_id_len = 0;
static char * opt_object_label = NULL;
static const char * opt_pin = NULL;
static const char * opt_so_pin = NULL;
static const char * opt_puk = NULL;
static const char * opt_new_pin = NULL;
static char * opt_application_label = NULL;
static char * opt_application_id = NULL;
static char * opt_issuer = NULL;
static char * opt_subject = NULL;
static char * opt_key_type = NULL;
static char * opt_sig_format = NULL;
#define MAX_ALLOWED_MECHANISMS 20
static CK_MECHANISM_TYPE opt_allowed_mechanisms[MAX_ALLOWED_MECHANISMS];
static size_t opt_allowed_mechanisms_len = 0;
static int opt_is_private = 0;
static int opt_is_sensitive = 0;
static int opt_is_extractable = 0;
static int opt_is_destroyable = 1;
static int opt_test_hotplug = 0;
static int opt_login_type = -1;
static int opt_key_usage_sign = 0;
static int opt_key_usage_decrypt = 0;
static int opt_key_usage_derive = 0;
static int opt_key_usage_wrap = 0;
static int opt_key_usage_default = 1; /* uses defaults if no opt_key_usage options */
static int opt_derive_pass_der = 0;
static unsigned long opt_random_bytes = 0;
static CK_MECHANISM_TYPE opt_hash_alg = 0;
static unsigned long opt_mgf = 0;
static long opt_salt_len = 0;
static int opt_salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */
static int opt_always_auth = 0;
static CK_FLAGS opt_allow_sw = CKF_HW;
static const char * opt_iv = NULL;
static void *module = NULL;
static CK_FUNCTION_LIST_3_0_PTR p11 = NULL;
static CK_SLOT_ID_PTR p11_slots = NULL;
static CK_ULONG p11_num_slots = 0;
static int suppress_warn = 0;
static CK_C_INITIALIZE_ARGS_PTR c_initialize_args_ptr = NULL;
#if defined(_WIN32) || defined(HAVE_PTHREAD)
static CK_C_INITIALIZE_ARGS c_initialize_args_OS = {NULL, NULL, NULL, NULL, CKF_OS_LOCKING_OK, NULL};
#ifdef _WIN32
static HANDLE test_threads_handles[MAX_TEST_THREADS];
#else
static pthread_t test_threads_handles[MAX_TEST_THREADS];
#endif
struct test_threads_data {
int tnum;
char * tests;
volatile int state;
volatile CK_RV rv;
};
static struct test_threads_data test_threads_datas[MAX_TEST_THREADS];
static int test_threads_num = 0;
#endif /* defined(_WIN32) || defined(HAVE_PTHREAD) */
struct flag_info {
CK_FLAGS value;
const char * name;
};
/*
* Flags for mech_info. These flags can provide meta-data for
* pkcs11 mechanisms and are tracked per mechanism. Thus for figuring
* out if sign is valid for this mechanism, one can query the mechanism
* table over having to build conditional statements.
*
* Note that the tool takes in raw 0x prefixed mechanisms that may not exist in
* the table, so we just assume MF_UNKOWN for flags.
*
* TODO these flags are only the tip of the iceberg, but can be filled out as time progresses.
*/
#define MF_UNKNOWN 0 /* Used to indicate additional information is not available */
#define MF_SIGN (1 << 0) /* C_Sign interface supported */
#define MF_VERIFY (1 << 1) /* C_verify interface supported */
#define MF_HMAC (1 << 2) /* Is an Hashed Message Authentication Code (HMAC) */
#define MF_MGF (1 << 3) /* Is an Mask Generation Function (MGF) */
#define MF_CKO_SECRET_KEY (1 << 4) /* Uses a CKO_SECRET_KEY class object */
/* Handy initializers */
#define MF_GENERIC_HMAC_FLAGS (MF_SIGN | MF_VERIFY | MF_HMAC | MF_CKO_SECRET_KEY)
struct mech_info {
CK_MECHANISM_TYPE mech;
const char * name;
const char * short_name;
uint16_t mf_flags;
};
struct x509cert_info {
unsigned char subject[512];
int subject_len;
unsigned char issuer[512];
int issuer_len;
unsigned char serialnum[128];
int serialnum_len;
};
struct rsakey_info {
unsigned char *modulus;
int modulus_len;
unsigned char *public_exponent;
int public_exponent_len;
unsigned char *private_exponent;
int private_exponent_len;
unsigned char *prime_1;
int prime_1_len;
unsigned char *prime_2;
int prime_2_len;
unsigned char *exponent_1;
int exponent_1_len;
unsigned char *exponent_2;
int exponent_2_len;
unsigned char *coefficient;
int coefficient_len;
};
struct gostkey_info {
struct sc_lv_data param_oid;
struct sc_lv_data public;
struct sc_lv_data private;
};
static void show_cryptoki_info(void);
static void list_slots(int, int, int);
static void show_token(CK_SLOT_ID);
static void list_mechs(CK_SLOT_ID);
static void list_objects(CK_SESSION_HANDLE, CK_OBJECT_CLASS);
static void list_interfaces(void);
static int login(CK_SESSION_HANDLE, int);
static void init_token(CK_SLOT_ID);
static void init_pin(CK_SLOT_ID, CK_SESSION_HANDLE);
static int change_pin(CK_SLOT_ID, CK_SESSION_HANDLE);
static int unlock_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess, int login_type);
static void show_object(CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static void show_key(CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static void show_cert(CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj);
static void show_profile(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj);
static void sign_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static void verify_signature(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static void decrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static void encrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static void hash_data(CK_SLOT_ID, CK_SESSION_HANDLE);
static void derive_key(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE,
CK_OBJECT_HANDLE *, CK_OBJECT_HANDLE *, const char *);
static int gen_key(CK_SLOT_ID slot, CK_SESSION_HANDLE, CK_OBJECT_HANDLE *, const char *, char *);
static int unwrap_key(CK_SESSION_HANDLE session);
static int wrap_key(CK_SESSION_HANDLE session);
static int write_object(CK_SESSION_HANDLE session);
static int read_object(CK_SESSION_HANDLE session);
static int delete_object(CK_SESSION_HANDLE session);
static void set_id_attr(CK_SESSION_HANDLE session);
static int find_object_id_or_label(CK_SESSION_HANDLE sess, CK_OBJECT_CLASS cls,
CK_OBJECT_HANDLE_PTR ret,
const unsigned char *, size_t id_len,
const char *,
int obj_index);
static int find_object(CK_SESSION_HANDLE, CK_OBJECT_CLASS,
CK_OBJECT_HANDLE_PTR,
const unsigned char *, size_t id_len, int obj_index);
static int find_object_flags(CK_SESSION_HANDLE, uint16_t flags,
CK_OBJECT_HANDLE_PTR,
const unsigned char *, size_t id_len, int obj_index);
static int find_mechanism(CK_SLOT_ID, CK_FLAGS, CK_MECHANISM_TYPE_PTR, size_t, CK_MECHANISM_TYPE_PTR);
static int find_slot_by_description(const char *, CK_SLOT_ID_PTR);
static int find_slot_by_token_label(const char *, CK_SLOT_ID_PTR);
static void get_token_info(CK_SLOT_ID, CK_TOKEN_INFO_PTR);
static CK_ULONG get_mechanisms(CK_SLOT_ID,
CK_MECHANISM_TYPE_PTR *, CK_FLAGS);
static void p11_fatal(const char *, CK_RV);
static void p11_warn(const char *, CK_RV);
static const char * p11_slot_info_flags(CK_FLAGS);
static const char * p11_token_info_flags(CK_FLAGS);
static const char * p11_utf8_to_local(CK_UTF8CHAR *, size_t);
static const char * p11_flag_names(struct flag_info *, CK_FLAGS);
static const char * p11_mechanism_to_name(CK_MECHANISM_TYPE);
static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *);
static uint16_t p11_mechanism_to_flags(CK_MECHANISM_TYPE mech);
static const char * p11_mgf_to_name(CK_RSA_PKCS_MGF_TYPE);
static CK_MECHANISM_TYPE p11_name_to_mgf(const char *);
static const char * p11_profile_to_name(CK_ULONG);
static void p11_perror(const char *, CK_RV);
static const char * CKR2Str(CK_ULONG res);
static int p11_test(CK_SESSION_HANDLE session);
static int test_card_detection(int);
static CK_BYTE_PTR get_iv(const char * iv_input, size_t *iv_size);
static void pseudo_randomize(unsigned char *data, size_t dataLen);
static CK_SESSION_HANDLE test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
#ifndef _WIN32
static void test_fork(void);
#endif
#if defined(_WIN32) || defined(HAVE_PTHREAD)
static void test_threads();
static int test_threads_start(int tnum);
static int test_threads_cleanup();
#ifdef _WIN32
static DWORD WINAPI test_threads_run(_In_ LPVOID pttd);
#else
static void * test_threads_run(void * pttd);
#endif
#endif /* defined(_WIN32) || defined(HAVE_PTHREAD) */
static void generate_random(CK_SESSION_HANDLE session);
static CK_RV find_object_with_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *out,
CK_ATTRIBUTE *attrs, CK_ULONG attrsLen, CK_ULONG obj_index);
static CK_ULONG get_private_key_length(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE prkey);
/* win32 needs this in open(2) */
#ifndef O_BINARY
# define O_BINARY 0
#endif
#define ATTR_METHOD(ATTR, TYPE) \
static TYPE \
get##ATTR(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) \
{ \
TYPE type = 0; \
CK_ATTRIBUTE attr = { CKA_##ATTR, &type, sizeof(type) }; \
CK_RV rv; \
\
rv = p11->C_GetAttributeValue(sess, obj, &attr, 1); \
if (rv != CKR_OK) \
p11_warn("C_GetAttributeValue(" #ATTR ")", rv); \
return type; \
}
#define VARATTR_METHOD(ATTR, TYPE) \
static TYPE * \
get##ATTR(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, CK_ULONG_PTR pulCount) \
{ \
CK_ATTRIBUTE attr = { CKA_##ATTR, NULL, 0 }; \
CK_RV rv; \
if (pulCount) \
*pulCount = 0; \
rv = p11->C_GetAttributeValue(sess, obj, &attr, 1); \
if (rv == CKR_OK) { \
if (attr.ulValueLen == (CK_ULONG)(-1)) \
return NULL; \
if (!(attr.pValue = calloc(1, attr.ulValueLen + 1))) \
util_fatal("out of memory in get" #ATTR ": %m"); \
rv = p11->C_GetAttributeValue(sess, obj, &attr, 1); \
if (attr.ulValueLen == (CK_ULONG)(-1)) { \
free(attr.pValue); \
return NULL; \
} \
if (pulCount) \
*pulCount = attr.ulValueLen / sizeof(TYPE); \
} else if (rv != CKR_ATTRIBUTE_TYPE_INVALID) { \
p11_warn("C_GetAttributeValue(" #ATTR ")", rv); \
} \
return (TYPE *) attr.pValue; \
}
/*
* Define attribute accessors
*/
ATTR_METHOD(CLASS, CK_OBJECT_CLASS); /* getCLASS */
ATTR_METHOD(ALWAYS_AUTHENTICATE, CK_BBOOL); /* getALWAYS_AUTHENTICATE */
ATTR_METHOD(PRIVATE, CK_BBOOL); /* getPRIVATE */
ATTR_METHOD(MODIFIABLE, CK_BBOOL); /* getMODIFIABLE */
ATTR_METHOD(ENCRYPT, CK_BBOOL); /* getENCRYPT */
ATTR_METHOD(DECRYPT, CK_BBOOL); /* getDECRYPT */
ATTR_METHOD(SIGN, CK_BBOOL); /* getSIGN */
ATTR_METHOD(VERIFY, CK_BBOOL); /* getVERIFY */
ATTR_METHOD(WRAP, CK_BBOOL); /* getWRAP */
ATTR_METHOD(UNWRAP, CK_BBOOL); /* getUNWRAP */
ATTR_METHOD(DERIVE, CK_BBOOL); /* getDERIVE */
ATTR_METHOD(SENSITIVE, CK_BBOOL); /* getSENSITIVE */
ATTR_METHOD(ALWAYS_SENSITIVE, CK_BBOOL); /* getALWAYS_SENSITIVE */
ATTR_METHOD(EXTRACTABLE, CK_BBOOL); /* getEXTRACTABLE */
ATTR_METHOD(NEVER_EXTRACTABLE, CK_BBOOL); /* getNEVER_EXTRACTABLE */
ATTR_METHOD(LOCAL, CK_BBOOL); /* getLOCAL */
ATTR_METHOD(OPENSC_NON_REPUDIATION, CK_BBOOL); /* getOPENSC_NON_REPUDIATION */
ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE); /* getKEY_TYPE */
ATTR_METHOD(CERTIFICATE_TYPE, CK_CERTIFICATE_TYPE); /* getCERTIFICATE_TYPE */
ATTR_METHOD(MODULUS_BITS, CK_ULONG); /* getMODULUS_BITS */
ATTR_METHOD(VALUE_LEN, CK_ULONG); /* getVALUE_LEN */
ATTR_METHOD(PROFILE_ID, CK_ULONG); /* getPROFILE_ID */
VARATTR_METHOD(LABEL, char); /* getLABEL */
VARATTR_METHOD(UNIQUE_ID, char); /* getUNIQUE_ID */
VARATTR_METHOD(APPLICATION, char); /* getAPPLICATION */
VARATTR_METHOD(ID, unsigned char); /* getID */
VARATTR_METHOD(OBJECT_ID, unsigned char); /* getOBJECT_ID */
VARATTR_METHOD(MODULUS, CK_BYTE); /* getMODULUS */
#ifdef ENABLE_OPENSSL
VARATTR_METHOD(SUBJECT, unsigned char); /* getSUBJECT */
VARATTR_METHOD(SERIAL_NUMBER, unsigned char); /* getSERIAL_NUMBER */
VARATTR_METHOD(PUBLIC_EXPONENT, CK_BYTE); /* getPUBLIC_EXPONENT */
#endif
VARATTR_METHOD(VALUE, unsigned char); /* getVALUE */
VARATTR_METHOD(GOSTR3410_PARAMS, unsigned char); /* getGOSTR3410_PARAMS */
VARATTR_METHOD(GOSTR3411_PARAMS, unsigned char); /* getGOSTR3411_PARAMS */
VARATTR_METHOD(EC_POINT, unsigned char); /* getEC_POINT */
VARATTR_METHOD(EC_PARAMS, unsigned char); /* getEC_PARAMS */
VARATTR_METHOD(ALLOWED_MECHANISMS, CK_MECHANISM_TYPE); /* getALLOWED_MECHANISMS */
int main(int argc, char * argv[])
{
CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE object = CK_INVALID_HANDLE;
int err = 0, c, long_optind = 0;
int do_show_info = 0;
int do_list_slots = 0;
int list_token_slots = 0;
int do_list_mechs = 0;
int do_list_objects = 0;
int do_list_interfaces = 0;
int do_sign = 0;
int do_verify = 0;
int do_decrypt = 0;
int do_encrypt = 0;
int do_unwrap = 0;
int do_wrap = 0;
int do_hash = 0;
int do_derive = 0;
int do_gen_keypair = 0;
int do_gen_key = 0;
int do_write_object = 0;
int do_read_object = 0;
int do_delete_object = 0;
int do_set_id = 0;
int do_test = 0;
int do_test_kpgen_certwrite = 0;
int do_test_ec = 0;
#ifndef _WIN32
int do_test_fork = 0;
#endif
#if defined(_WIN32) || defined(HAVE_PTHREAD)
int do_test_threads = 0;
#endif
int need_session = 0;
int opt_login = 0;
int do_init_token = 0;
int do_init_pin = 0;
int do_change_pin = 0;
int do_unlock_pin = 0;
int action_count = 0;
int do_generate_random = 0;
char *s = NULL;
CK_RV rv;
#ifdef _WIN32
char expanded_val[PATH_MAX];
DWORD expanded_len;
if(_setmode(_fileno(stdout), _O_BINARY ) == -1)
util_fatal("Cannot set FMODE to O_BINARY");
if(_setmode(_fileno(stdin), _O_BINARY ) == -1)
util_fatal("Cannot set FMODE to O_BINARY");
#endif
while (1) {
c = getopt_long(argc, argv, "ILMOTa:bd:e:hi:klm:o:p:scvf:ty:w:z:r",
options, &long_optind);
if (c == -1)
break;
switch (c) {
case 'I':
do_show_info = 1;
action_count++;
break;
case 'L':
do_list_slots = 1;
action_count++;
break;
case 'T':
do_list_slots = 1;
list_token_slots = 1;
action_count++;
break;
case 'M':
do_list_mechs = 1;
action_count++;
break;
case 'O':
need_session |= NEED_SESSION_RO;
do_list_objects = 1;
action_count++;
break;
case 'h':
need_session |= NEED_SESSION_RO;
do_hash = 1;
action_count++;
break;
case 'k':
need_session |= NEED_SESSION_RW;
do_gen_keypair = 1;
action_count++;
break;
case OPT_GENERATE_KEY:
need_session |= NEED_SESSION_RW;
do_gen_key = 1;
action_count++;
break;
case 'w':
need_session |= NEED_SESSION_RW;
do_write_object = 1;
opt_file_to_write = optarg;
action_count++;
break;
case 'r':
need_session |= NEED_SESSION_RO;
do_read_object = 1;
action_count++;
break;
case 'b':
need_session |= NEED_SESSION_RW;
do_delete_object = 1;
action_count++;
break;
case 'e':
need_session |= NEED_SESSION_RW;
do_set_id = 1;
new_object_id_len = sizeof(new_object_id);
if (sc_hex_to_bin(optarg, new_object_id, &new_object_id_len)) {
fprintf(stderr, "Invalid ID \"%s\"\n", optarg);
util_print_usage_and_die(app_name, options, option_help, NULL);
}
action_count++;
break;
case OPT_ATTR_FROM:
opt_attr_from_file = optarg;
break;
case 'y':
opt_object_class_str = optarg;
if (strcmp(optarg, "cert") == 0)
opt_object_class = CKO_CERTIFICATE;
else if (strcmp(optarg, "privkey") == 0)
opt_object_class = CKO_PRIVATE_KEY;
else if (strcmp(optarg, "secrkey") == 0)
opt_object_class = CKO_SECRET_KEY;
else if (strcmp(optarg, "pubkey") == 0)
opt_object_class = CKO_PUBLIC_KEY;
else if (strcmp(optarg, "data") == 0)
opt_object_class = CKO_DATA;
else {
fprintf(stderr, "Unsupported object type \"%s\"\n", optarg);
util_print_usage_and_die(app_name, options, option_help, NULL);
}
break;
case 'd':
opt_object_id_len = sizeof(opt_object_id);
if (sc_hex_to_bin(optarg, opt_object_id, &opt_object_id_len)) {
fprintf(stderr, "Invalid ID \"%s\"\n", optarg);
util_print_usage_and_die(app_name, options, option_help, NULL);
}
break;
case 'a':
opt_object_label = optarg;
break;
case 'i':
opt_input = optarg;
break;
case OPT_SIGNATURE_FILE:
opt_signature_file = optarg;
break;
case OPT_SESSION_RW:
need_session |= NEED_SESSION_RW;
break;
case 'l':
need_session |= NEED_SESSION_RO;
opt_login = 1;
break;
case 'm':
opt_mechanism_used = 1;
opt_mechanism = p11_name_to_mechanism(optarg);
break;
case OPT_HASH_ALGORITHM:
opt_hash_alg = p11_name_to_mechanism(optarg);
break;
case OPT_MGF:
opt_mgf = p11_name_to_mgf(optarg);
break;
case OPT_SALT:
opt_salt_len = (CK_ULONG) strtoul(optarg, NULL, 0);
opt_salt_len_given = 1;
break;
case 'o':
opt_output = optarg;
break;
case 'p':
need_session |= NEED_SESSION_RO;
opt_login = 1;
util_get_pin(optarg, &opt_pin);
break;
case 'c':
do_change_pin = 1;
need_session |= NEED_SESSION_RW;
action_count++;
break;
case OPT_UNLOCK_PIN:
do_unlock_pin = 1;
need_session |= NEED_SESSION_RW;
action_count++;
break;
case 's':
need_session |= NEED_SESSION_RO;
do_sign = 1;
action_count++;
break;
case OPT_VERIFY:
need_session |= NEED_SESSION_RO;
do_verify = 1;
action_count++;
break;
case OPT_DECRYPT:
need_session |= NEED_SESSION_RO;
do_decrypt = 1;
action_count++;
break;
case OPT_ENCRYPT:
need_session |= NEED_SESSION_RO;
do_encrypt = 1;
action_count++;
break;
case OPT_UNWRAP:
need_session |= NEED_SESSION_RW;
do_unwrap = 1;
action_count++;
break;
case OPT_WRAP:
need_session |= NEED_SESSION_RO;
do_wrap = 1;
action_count++;
break;
case 'f':
opt_sig_format = optarg;
break;
case 't':
need_session |= NEED_SESSION_RW;
do_test = 1;
action_count++;
break;
case 'z':
do_test_kpgen_certwrite = 1;
opt_file_to_write = optarg;
action_count++;
break;
case 'v':
verbose++;
break;
case OPT_SLOT:
opt_slot = (CK_SLOT_ID) strtoul(optarg, NULL, 0);
opt_slot_set = 1;
if (verbose)
fprintf(stderr, "Using slot with ID 0x%lx\n", opt_slot);
break;
case OPT_SLOT_DESCRIPTION:
if (opt_slot_set) {
fprintf(stderr, "Error: Only one of --slot, --slot-description, --slot-index or --token-label can be used\n");
util_print_usage_and_die(app_name, options, option_help, NULL);
}
opt_slot_description = optarg;
break;
case OPT_SLOT_INDEX:
if (opt_slot_set || opt_slot_description) {
fprintf(stderr, "Error: Only one of --slot, --slot-description, --slot-index or --token-label can be used\n");
util_print_usage_and_die(app_name, options, option_help, NULL);
}
opt_slot_index = (CK_ULONG) strtoul(optarg, NULL, 0);
opt_slot_index_set = 1;
break;
case OPT_OBJECT_INDEX:
opt_object_index = (CK_ULONG) strtoul(optarg, NULL, 0);
opt_object_index_set = 1;
break;
case OPT_TOKEN_LABEL:
if (opt_slot_set || opt_slot_description || opt_slot_index_set) {
fprintf(stderr, "Error: Only one of --slot, --slot-description, --slot-index or --token-label can be used\n");
util_print_usage_and_die(app_name, options, option_help, NULL);
}
opt_token_label = optarg;
break;
case OPT_MODULE:
opt_module = optarg;
break;
case OPT_APPLICATION_LABEL:
opt_application_label = optarg;
break;
case OPT_APPLICATION_ID:
opt_application_id = optarg;
break;
case OPT_ISSUER:
opt_issuer = optarg;
break;
case OPT_SUBJECT:
opt_subject = optarg;
break;
case OPT_NEW_PIN:
util_get_pin(optarg, &opt_new_pin);
break;
case OPT_PUK:
util_get_pin(optarg, &opt_puk);
break;
case OPT_LOGIN_TYPE:
if (!strcmp(optarg, "so"))
opt_login_type = CKU_SO;
else if (!strcmp(optarg, "user"))
opt_login_type = CKU_USER;
else if (!strcmp(optarg, "context-specific"))
opt_login_type = CKU_CONTEXT_SPECIFIC;
else {
fprintf(stderr, "Unsupported login type \"%s\"\n", optarg);
util_print_usage_and_die(app_name, options, option_help, NULL);
}
break;
case OPT_SO_PIN:
util_get_pin(optarg, &opt_so_pin);
break;
case OPT_INIT_TOKEN:
do_init_token = 1;
action_count++;
break ;
case OPT_INIT_PIN:
need_session |= NEED_SESSION_RW;
do_init_pin = 1;
action_count++;
break ;
case OPT_KEY_TYPE:
opt_key_type = optarg;
break;
case OPT_KEY_USAGE_SIGN:
opt_key_usage_sign = 1;
opt_key_usage_default = 0;
break;
case OPT_KEY_USAGE_DECRYPT:
opt_key_usage_decrypt = 1;
opt_key_usage_default = 0;
break;
case OPT_KEY_USAGE_DERIVE:
opt_key_usage_derive = 1;
opt_key_usage_default = 0;
break;
case OPT_KEY_USAGE_WRAP:
opt_key_usage_wrap = 1;
opt_key_usage_default = 0;
break;
case OPT_PRIVATE:
opt_is_private = 1;
break;
case OPT_SENSITIVE:
opt_is_sensitive = 1;
break;
case OPT_EXTRACTABLE:
opt_is_extractable = 1;
break;
case OPT_UNDESTROYABLE:
opt_is_destroyable = 0;
break;
case OPT_TEST_HOTPLUG:
opt_test_hotplug = 1;
action_count++;
break;
case OPT_TEST_EC:
do_test_ec = 1;
action_count++;
break;
case OPT_DERIVE_PASS_DER:
opt_derive_pass_der = 1;
/* fall through */
case OPT_DERIVE:
need_session |= NEED_SESSION_RW;
do_derive = 1;
action_count++;
break;
#ifndef _WIN32
case OPT_TEST_FORK:
do_test_fork = 1;
action_count++;
break;
#endif
#if defined(_WIN32) || defined(HAVE_PTHREAD)
case OPT_USE_LOCKING:
c_initialize_args_ptr = &c_initialize_args_OS;
break;
case OPT_TEST_THREADS:
do_test_threads = 1;
if (test_threads_num < MAX_TEST_THREADS) {
test_threads_datas[test_threads_num].tnum = test_threads_num;
test_threads_datas[test_threads_num].tests = optarg;
test_threads_num++;
} else {
fprintf(stderr,"Too many --test_threads options limit is %d\n", MAX_TEST_THREADS);
util_print_usage_and_die(app_name, options, option_help, NULL);
}
action_count++;
break;
#endif
case OPT_GENERATE_RANDOM:
need_session |= NEED_SESSION_RO;
opt_random_bytes = strtoul(optarg, NULL, 0);
do_generate_random = 1;
action_count++;
break;
case OPT_ALWAYS_AUTH:
opt_always_auth = 1;
break;
case OPT_ALLOW_SW:
opt_allow_sw = 0;
break;
case OPT_ALLOWED_MECHANISMS:
/* Parse the mechanism list and fail early */
s = strtok(optarg, ",");
while (s != NULL) {
if (opt_allowed_mechanisms_len > MAX_ALLOWED_MECHANISMS) {
fprintf(stderr, "Too many mechanisms provided"
" (max %d). Skipping the rest.", MAX_ALLOWED_MECHANISMS);
break;
}
opt_allowed_mechanisms[opt_allowed_mechanisms_len] =
p11_name_to_mechanism(s);
opt_allowed_mechanisms_len++;
s = strtok(NULL, ",");
}
break;
case OPT_LIST_INTERFACES:
do_list_interfaces = 1;
action_count++;
break;
case OPT_IV:
opt_iv = optarg;
break;
default:
util_print_usage_and_die(app_name, options, option_help, NULL);
}
}
if (optind < argc) {
util_fatal("invalid option(s) given");
}
if (action_count == 0)
util_print_usage_and_die(app_name, options, option_help, NULL);
#ifdef _WIN32
expanded_len = PATH_MAX;
expanded_len = ExpandEnvironmentStringsA(opt_module, expanded_val, expanded_len);
if (0 < expanded_len && expanded_len < sizeof expanded_val)
opt_module = expanded_val;
#endif
#ifndef ENABLE_SHARED
if (strcmp(opt_module, DEFAULT_PKCS11_PROVIDER) == 0)
p11 = &pkcs11_function_list_3_0;
else
#endif
{
CK_FUNCTION_LIST_PTR p11_v2 = NULL;
module = C_LoadModule(opt_module, &p11_v2);
if (module == NULL)
util_fatal("Failed to load pkcs11 module");
p11 = (CK_FUNCTION_LIST_3_0_PTR) p11_v2;
}
/* This can be done even before initialization */
if (do_list_interfaces)
list_interfaces();
#if defined(_WIN32) || defined(HAVE_PTHREAD)
if (do_test_threads)
test_threads();
#endif
rv = p11->C_Initialize(c_initialize_args_ptr);
#if defined(_WIN32) || defined(HAVE_PTHREAD)
if (do_test_threads || rv != CKR_OK)
fprintf(stderr,"Main C_Initialize(%s) rv:%s\n",
(c_initialize_args_ptr) ? "CKF_OS_LOCKING_OK" : "NULL", CKR2Str(rv));
#else
if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
fprintf(stderr, "\n*** Cryptoki library has already been initialized ***\n");
#endif /* defined(_WIN32) || defined(HAVE_PTHREAD) */
if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)
p11_fatal("C_Initialize", rv);
#ifndef _WIN32
if (do_test_fork)
test_fork();
#endif
if (do_show_info)
show_cryptoki_info();
list_slots(list_token_slots, 1, do_list_slots);
if (opt_test_hotplug) {
test_card_detection(0);
test_card_detection(1);
}
if (p11_num_slots == 0) {
fprintf(stderr, "No slots.\n");
err = 1;
goto end;
}
if (!opt_slot_set && (action_count > do_list_slots)) {
if (opt_slot_description) {
if (!find_slot_by_description(opt_slot_description, &opt_slot)) {
fprintf(stderr, "No slot named \"%s\" found\n", opt_slot_description);
err = 1;
goto end;
}
if (verbose)
fprintf(stderr, "Using slot with label \"%s\" (0x%lx)\n", opt_slot_description, opt_slot);
} else if (opt_token_label) {
if (!find_slot_by_token_label(opt_token_label, &opt_slot)) {
fprintf(stderr, "No slot with token named \"%s\" found\n", opt_token_label);
err = 1;
goto end;
}
if (verbose)
fprintf(stderr, "Using slot with label \"%s\" (0x%lx)\n", opt_slot_description, opt_slot);
} else if (opt_slot_index_set) {
if (opt_slot_index < p11_num_slots) {
opt_slot = p11_slots[opt_slot_index];
fprintf(stderr, "Using slot with index %lu (0x%lx)\n", opt_slot_index, opt_slot);
} else {
fprintf(stderr, "Slot with index %lu (counting from 0) is not available.\n", opt_slot_index);
fprintf(stderr, "You must specify a valid slot with either --slot, --slot-description, --slot-index or --token-label.\n");
err = 1;
goto end;
}
} else {
/* use first slot with token present (or default slot on error) */
unsigned int i, found = 0;
for (i = 0; i < p11_num_slots; i++) {
CK_SLOT_INFO info;
rv = p11->C_GetSlotInfo(p11_slots[i], &info);
if (rv != CKR_OK)
p11_fatal("C_GetSlotInfo", rv);
if (info.flags & CKF_TOKEN_PRESENT) {
opt_slot = p11_slots[i];
fprintf(stderr, "Using slot %u with a present token (0x%lx)\n", i, opt_slot);
found = 1;
break;
}
}
if (!found) {
fprintf(stderr, "No slot with a token was found.\n");
err = 1;
goto end;
}
}
}
if (do_list_mechs)
list_mechs(opt_slot);
if (do_sign || do_decrypt || do_encrypt || do_unwrap || do_wrap) {
CK_TOKEN_INFO info;
get_token_info(opt_slot, &info);
if (!(info.flags & CKF_TOKEN_INITIALIZED))
util_fatal("Token not initialized");
if (info.flags & CKF_LOGIN_REQUIRED)
opt_login++;
}
if (do_init_token)
init_token(opt_slot);
if (need_session) {
int flags = CKF_SERIAL_SESSION;
if (need_session & NEED_SESSION_RW)
flags |= CKF_RW_SESSION;
rv = p11->C_OpenSession(opt_slot, flags,
NULL, NULL, &session);
if (rv != CKR_OK)
p11_fatal("C_OpenSession", rv);
}
if (opt_login) {
int r;
if (opt_login_type == -1)
opt_login_type = do_init_pin ? CKU_SO : CKU_USER;
r = login(session, opt_login_type);
if (r != 0)
return r;
}
if (do_change_pin)
/* To be sure we won't mix things up with the -l or -p options,
* we safely stop here. */
return change_pin(opt_slot, session);
if (do_unlock_pin) {
if (opt_login_type != -1
&& opt_login_type != CKU_CONTEXT_SPECIFIC) {
fprintf(stderr, "Invalid login type for 'Unlock User PIN' operation\n");
util_print_usage_and_die(app_name, options, option_help, NULL);
}
return unlock_pin(opt_slot, session, opt_login_type);
}
if (do_init_pin) {
init_pin(opt_slot, session);
/* We logged in as a CKU_SO user just to initialize
* the User PIN, we now have to exit. */
goto end;
}
uint16_t mf_flags = MF_UNKNOWN;
if (opt_mechanism_used) {
mf_flags = p11_mechanism_to_flags(opt_mechanism);
}
if (do_sign || do_derive) {
/*
* Newer mechanisms have their details in the mechanism table, however
* if it's not known fall back to the old code always assuming it was a
* CKO_PRIVATE_KEY.
*/
if (mf_flags != MF_UNKNOWN) {
/* this function dies on error via util_fatal */
find_object_flags(session, mf_flags, &object,
opt_object_id_len ? opt_object_id : NULL,
opt_object_id_len, 0);
} else if (!find_object(session, CKO_PRIVATE_KEY, &object,
opt_object_id_len ? opt_object_id : NULL,
opt_object_id_len, 0))
util_fatal("Private key not found");
}
if (do_decrypt) {
/*
* Newer mechanisms have their details in the mechanism table, however
* if it's not known fall back to the old code always assuming it was a
* CKO_PUBLIC_KEY then a CKO_CERTIFICATE.
*/
if (mf_flags != MF_UNKNOWN) {
/* this function dies on error via util_fatal */
find_object_flags(session, mf_flags, &object,
opt_object_id_len ? opt_object_id : NULL,
opt_object_id_len, 0);
} else if (!find_object(session, CKO_PRIVATE_KEY, &object,
opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
if (!find_object(session, CKO_SECRET_KEY, &object,
opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
util_fatal("Private/secret key not found");
}
if (do_encrypt) {
/*
* Newer mechanisms have their details in the mechanism table, however
* if it's not known fall back to the old code always assuming it was a
* CKO_PUBLIC_KEY then a CKO_CERTIFICATE.
*/
if (mf_flags != MF_UNKNOWN) {
/* this function dies on error via util_fatal */
find_object_flags(session, mf_flags, &object,
opt_object_id_len ? opt_object_id : NULL,
opt_object_id_len, 0);
} else if (!find_object(session, CKO_SECRET_KEY, &object,
opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
util_fatal("Secret key not found");
}
if (do_verify) {
/*
* Newer mechanisms have their details in the mechanism table, however
* if it's not known fall back to the old code always assuming it was a
* CKO_PUBLIC_KEY then a CKO_CERTIFICATE.
*/
if (mf_flags != MF_UNKNOWN) {
/* this function dies on error via util_fatal */
find_object_flags(session, mf_flags, &object,
opt_object_id_len ? opt_object_id : NULL,
opt_object_id_len, 0);
} else if (!find_object(session, CKO_PUBLIC_KEY, &object,
opt_object_id_len ? opt_object_id : NULL,
opt_object_id_len, 0) &&
!find_object(session, CKO_CERTIFICATE, &object,
opt_object_id_len ? opt_object_id : NULL,
opt_object_id_len, 0))
util_fatal("Public key nor certificate not found");
}
if (do_unwrap)
unwrap_key(session);
if (do_wrap)
wrap_key(session);
/* before list objects, so we can see a derived key */
if (do_derive)
derive_key(opt_slot, session, object);
if (do_list_objects)
list_objects(session, opt_object_class);
if (do_sign)
sign_data(opt_slot, session, object);
if (do_verify)
verify_signature(opt_slot, session, object);
if (do_decrypt)
decrypt_data(opt_slot, session, object);
if (do_encrypt)
encrypt_data(opt_slot, session, object);
if (do_hash)
hash_data(opt_slot, session);
if (do_gen_keypair) {
CK_OBJECT_HANDLE hPublicKey, hPrivateKey;
gen_keypair(opt_slot, session, &hPublicKey, &hPrivateKey, opt_key_type);
}
if (do_gen_key) {
CK_OBJECT_HANDLE hSecretKey;
gen_key(opt_slot, session, &hSecretKey, opt_key_type, NULL);
}
if (do_write_object) {
if (opt_object_class_str == NULL)
util_fatal("You should specify the object type with the -y option");
write_object(session);
}
if (do_read_object) {
if (opt_object_class_str == NULL)
util_fatal("You should specify type of the object to read");
if (opt_object_id_len == 0 && opt_object_label == NULL &&
opt_application_label == NULL && opt_application_id == NULL &&
opt_issuer == NULL && opt_subject == NULL)
util_fatal("You should specify at least one of the "
"object ID, object label, application label or application ID");
read_object(session);
}
if (do_delete_object) {
if (opt_object_class_str == NULL)
util_fatal("You should specify type of the object to delete");
if (opt_object_id_len == 0 && opt_object_label == NULL &&
opt_application_label == NULL && opt_application_id == NULL &&
opt_object_index_set == 0)
util_fatal("You should specify at least one of the "
"object ID, object label, application label, application ID or object index");
delete_object(session);
}
if (do_set_id) {
if (opt_object_class_str == NULL)
util_fatal("You should specify the object type with the -y option");
if (opt_object_id_len == 0 && opt_object_label == NULL)
util_fatal("You should specify the current object with the -d or -a option");
set_id_attr(session);
}
if (do_test)
p11_test(session);
if (do_test_kpgen_certwrite) {
if (!opt_login)
fprintf(stderr, "ERR: login required\n");
else
session = test_kpgen_certwrite(opt_slot, session);
}
if (do_test_ec) {
if (!opt_login)
fprintf(stderr, "ERR: login required\n");
else
test_ec(opt_slot, session);
}
if (do_generate_random) {
generate_random(session);
}
end:
if (session != CK_INVALID_HANDLE) {
rv = p11->C_CloseSession(session);
if (rv != CKR_OK)
p11_fatal("C_CloseSession", rv);
}
#if defined(_WIN32) || defined(HAVE_PTHREAD)
if (do_test_threads)
test_threads_cleanup();
#endif /* defined(_WIN32) || defined(HAVE_PTHREAD) */
if (p11)
p11->C_Finalize(NULL_PTR);
if (module)
C_UnloadModule(module);
return err;
}
static void show_cryptoki_info(void)
{
CK_INFO info;
CK_RV rv;
rv = p11->C_GetInfo(&info);
if (rv != CKR_OK)
p11_fatal("C_GetInfo", rv);
printf("Cryptoki version %u.%u\n",
info.cryptokiVersion.major,
info.cryptokiVersion.minor);
printf("Manufacturer %s\n",
p11_utf8_to_local(info.manufacturerID,
sizeof(info.manufacturerID)));
printf("Library %s (ver %u.%u)\n",
p11_utf8_to_local(info.libraryDescription,
sizeof(info.libraryDescription)),
info.libraryVersion.major,
info.libraryVersion.minor);
}
static void list_interfaces(void)
{
CK_ULONG count = 0, i;
CK_INTERFACE_PTR interfaces = NULL;
CK_RV rv;
if (p11->version.major < 3) {
fprintf(stderr, "Interfaces are supported only in PKCS #11 3.0 and newer\n");
exit(1);
}
rv = p11->C_GetInterfaceList(NULL, &count);
if (rv != CKR_OK) {
p11_fatal("C_GetInterfaceList(size inquire)", rv);
}
interfaces = malloc(count * sizeof(CK_INTERFACE));
if (interfaces == NULL) {
perror("malloc failed");
exit(1);
}
rv = p11->C_GetInterfaceList(interfaces, &count);
if (rv != CKR_OK) {
p11_fatal("C_GetInterfaceList", rv);
}
for (i = 0; i < count; i++) {
printf("Interface '%s'\n version: %d.%d\n funcs=%p\n flags=0x%lu\n",
interfaces[i].pInterfaceName,
((CK_VERSION *)interfaces[i].pFunctionList)->major,
((CK_VERSION *)interfaces[i].pFunctionList)->minor,
interfaces[i].pFunctionList,
interfaces[i].flags);
}
}
static void list_slots(int tokens, int refresh, int print)
{
CK_SLOT_INFO info;
CK_ULONG n;
CK_RV rv;
/* Get the list of slots */
if (refresh) {
rv = p11->C_GetSlotList(tokens, NULL, &p11_num_slots);
if (rv != CKR_OK)
p11_fatal("C_GetSlotList(NULL)", rv);
free(p11_slots);
p11_slots = NULL;
if (p11_num_slots > 0) {
p11_slots = calloc(p11_num_slots, sizeof(CK_SLOT_ID));
if (p11_slots == NULL) {
perror("calloc failed");
exit(1);
}
rv = p11->C_GetSlotList(tokens, p11_slots, &p11_num_slots);
if (rv != CKR_OK)
p11_fatal("C_GetSlotList()", rv);
}
}
if (!print)
return;
printf("Available slots:\n");
for (n = 0; n < p11_num_slots; n++) {
printf("Slot %lu (0x%lx): ", n, p11_slots[n]);
rv = p11->C_GetSlotInfo(p11_slots[n], &info);
if (rv != CKR_OK) {
printf("(GetSlotInfo failed, %s)\n", CKR2Str(rv));
continue;
}
printf("%s\n", p11_utf8_to_local(info.slotDescription,
sizeof(info.slotDescription)));
if ((!verbose) && !(info.flags & CKF_TOKEN_PRESENT)) {
printf(" (empty)\n");
continue;
}
if (verbose) {
printf(" manufacturer: %s\n", p11_utf8_to_local(info.manufacturerID,
sizeof(info.manufacturerID)));
printf(" hardware ver: %u.%u\n",
info.hardwareVersion.major,
info.hardwareVersion.minor);
printf(" firmware ver: %u.%u\n",
info.firmwareVersion.major,
info.firmwareVersion.minor);
printf(" flags: %s\n", p11_slot_info_flags(info.flags));
}
if (info.flags & CKF_TOKEN_PRESENT)
show_token(p11_slots[n]);
}
}
static void show_token(CK_SLOT_ID slot)
{
CK_TOKEN_INFO info;
CK_RV rv;
rv = p11->C_GetTokenInfo(slot, &info);
if (rv == CKR_TOKEN_NOT_RECOGNIZED) {
printf(" (token not recognized)\n");
return;
} else if (rv != CKR_OK) {
printf("C_GetTokenInfo() failed: rv = %s\n", CKR2Str(rv));
return;
}
if (!(info.flags & CKF_TOKEN_INITIALIZED) && (!verbose)) {
printf(" token state: uninitialized\n");
return;
}
printf(" token label : %s\n",
p11_utf8_to_local(info.label,
sizeof(info.label)));
printf(" token manufacturer : %s\n",
p11_utf8_to_local(info.manufacturerID,
sizeof(info.manufacturerID)));
printf(" token model : %s\n",
p11_utf8_to_local(info.model,
sizeof(info.model)));
printf(" token flags : %s\n",
p11_token_info_flags(info.flags));
printf(" hardware version : %d.%d\n", info.hardwareVersion.major, info.hardwareVersion.minor);
printf(" firmware version : %d.%d\n", info.firmwareVersion.major, info.firmwareVersion.minor);
printf(" serial num : %s\n", p11_utf8_to_local(info.serialNumber,
sizeof(info.serialNumber)));
printf(" pin min/max : %lu/%lu\n", info.ulMinPinLen, info.ulMaxPinLen);
}
static void list_mechs(CK_SLOT_ID slot)
{
CK_MECHANISM_TYPE *mechs = NULL;
CK_ULONG n, num_mechs = 0;
CK_RV rv;
num_mechs = get_mechanisms(slot, &mechs, -1);
printf("Supported mechanisms:\n");
for (n = 0; n < num_mechs; n++) {
CK_MECHANISM_INFO info;
printf(" %s", p11_mechanism_to_name(mechs[n]));
rv = p11->C_GetMechanismInfo(slot, mechs[n], &info);
if (rv == CKR_OK) {
if (info.ulMinKeySize || info.ulMaxKeySize) {
printf(", keySize={");
if (info.ulMinKeySize)
printf("%li", info.ulMinKeySize);
printf(",");
if (info.ulMaxKeySize)
printf("%li", info.ulMaxKeySize);
printf("}");
}
if (info.flags & CKF_HW) {
printf(", hw");
info.flags &= ~CKF_HW;
}
if (info.flags & CKF_ENCRYPT) {
printf(", encrypt");
info.flags &= ~CKF_ENCRYPT;
}
if (info.flags & CKF_DECRYPT) {
printf(", decrypt");
info.flags &= ~CKF_DECRYPT;
}
if (info.flags & CKF_DIGEST) {
printf(", digest");
info.flags &= ~CKF_DIGEST;
}
if (info.flags & CKF_SIGN) {
printf(", sign");
info.flags &= ~CKF_SIGN;
}
if (info.flags & CKF_SIGN_RECOVER) {
printf(", sign_recover");
info.flags &= ~CKF_SIGN_RECOVER;
}
if (info.flags & CKF_VERIFY) {
printf(", verify");
info.flags &= ~CKF_VERIFY;
}
if (info.flags & CKF_VERIFY_RECOVER) {
printf(", verify_recover");
info.flags &= ~CKF_VERIFY_RECOVER;
}
if (info.flags & CKF_GENERATE) {
printf(", generate");
info.flags &= ~CKF_GENERATE;
}
if (info.flags & CKF_GENERATE_KEY_PAIR) {
printf(", generate_key_pair");
info.flags &= ~CKF_GENERATE_KEY_PAIR;
}
if (info.flags & CKF_WRAP) {
printf(", wrap");
info.flags &= ~CKF_WRAP;
}
if (info.flags & CKF_UNWRAP) {
printf(", unwrap");
info.flags &= ~CKF_UNWRAP;
}
if (info.flags & CKF_DERIVE) {
printf(", derive");
info.flags &= ~CKF_DERIVE;
}
if (info.flags & CKF_EC_F_P) {
printf(", EC F_P");
info.flags &= ~CKF_EC_F_P;
}
if (info.flags & CKF_EC_F_2M) {
printf(", EC F_2M");
info.flags &= ~CKF_EC_F_2M;
}
if (info.flags & CKF_EC_ECPARAMETERS) {
printf(", EC parameters");
info.flags &= ~CKF_EC_ECPARAMETERS;
}
if (info.flags & CKF_EC_OID) {
printf(", EC OID");
info.flags &= ~CKF_EC_OID;
}
if (info.flags & CKF_EC_UNCOMPRESS) {
printf(", EC uncompressed");
info.flags &= ~CKF_EC_UNCOMPRESS;
}
if (info.flags & CKF_EC_COMPRESS) {
printf(", EC compressed");
info.flags &= ~CKF_EC_COMPRESS;
}
if (info.flags & CKF_EC_CURVENAME) {
printf(", EC curve name");
info.flags &= ~CKF_EC_CURVENAME;
}
if (info.flags)
printf(", other flags=0x%x", (unsigned int) info.flags);
}
printf("\n");
}
if (mechs)
free(mechs);
}
static int login(CK_SESSION_HANDLE session, int login_type)
{
char *pin = NULL;
size_t len = 0;
int pin_allocated = 0, r;
CK_TOKEN_INFO info;
CK_RV rv;
CK_FLAGS pin_flags;
get_token_info(opt_slot, &info);
/* Identify which pin to enter */
if (login_type == CKU_SO)
pin = (char *) opt_so_pin;
else if (login_type == CKU_USER)
pin = (char *) opt_pin;
else if (login_type == CKU_CONTEXT_SPECIFIC)
pin = opt_pin ? (char *) opt_pin : (char *) opt_puk;
if (!pin && !(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) {
printf("Logging in to \"%s\".\n", p11_utf8_to_local(info.label, sizeof(info.label)));
if (login_type == CKU_SO) {
pin_flags=info.flags & (
CKF_SO_PIN_COUNT_LOW |
CKF_SO_PIN_FINAL_TRY |
CKF_SO_PIN_LOCKED |
CKF_SO_PIN_TO_BE_CHANGED);
if(pin_flags)
printf("WARNING: %s\n",p11_token_info_flags(pin_flags));
printf("Please enter SO PIN: ");
}
else if (login_type == CKU_USER) {
pin_flags=info.flags & (
CKF_USER_PIN_COUNT_LOW |
CKF_USER_PIN_FINAL_TRY |
CKF_USER_PIN_LOCKED |
CKF_USER_PIN_TO_BE_CHANGED);
if(pin_flags)
printf("WARNING: %s\n",p11_token_info_flags(pin_flags));
printf("Please enter User PIN: ");
}
else if (login_type == CKU_CONTEXT_SPECIFIC) {
printf("Please enter context specific PIN: ");
}
r = util_getpass(&pin, &len, stdin);
if (r < 0)
util_fatal("util_getpass error");
pin_allocated = 1;
}
if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
&& (!pin || !*pin)
&& login_type != CKU_CONTEXT_SPECIFIC)
return 1;
rv = p11->C_Login(session, login_type,
(CK_UTF8CHAR *) pin, pin == NULL ? 0 : strlen(pin));
if (rv != CKR_OK)
p11_fatal("C_Login", rv);
if (pin_allocated)
free(pin);
return 0;
}
static void init_token(CK_SLOT_ID slot)
{
unsigned char token_label[33];
char new_buf[21], *new_pin = NULL;
size_t len = 0;
int pin_allocated = 0, r;
CK_TOKEN_INFO info;
CK_RV rv;
if (!opt_object_label)
util_fatal("The token label must be specified using --label");
snprintf((char *) token_label, sizeof (token_label), "%-32.32s",
opt_object_label);
get_token_info(slot, &info);
if (opt_so_pin != NULL) {
new_pin = (char *) opt_so_pin;
} else {
if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) {
printf("Please enter the new SO PIN: ");
r = util_getpass(&new_pin, &len, stdin);
if (r < 0)
util_fatal("No PIN entered");
if (!new_pin || !*new_pin || strlen(new_pin) > 20)
util_fatal("Invalid SO PIN");
strlcpy(new_buf, new_pin, sizeof new_buf);
free(new_pin); new_pin = NULL;
printf("Please enter the new SO PIN (again): ");
r = util_getpass(&new_pin, &len, stdin);
if (r < 0)
util_fatal("No PIN entered");
if (!new_pin || !*new_pin ||
strcmp(new_buf, new_pin) != 0)
util_fatal("Different new SO PINs");
pin_allocated = 1;
}
}
rv = p11->C_InitToken(slot, (CK_UTF8CHAR *) new_pin,
new_pin == NULL ? 0 : strlen(new_pin), token_label);
if (rv != CKR_OK)
p11_fatal("C_InitToken", rv);
printf("Token successfully initialized\n");
if (pin_allocated)
free(new_pin);
}
static void init_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess)
{
char *pin;
char *new_pin1 = NULL, *new_pin2 = NULL;
size_t len1 = 0, len2 = 0;
int r;
CK_TOKEN_INFO info;
CK_RV rv;
get_token_info(slot, &info);
if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) {
if (! opt_pin && !opt_new_pin) {
printf("Please enter the new PIN: ");
r = util_getpass(&new_pin1,&len1,stdin);
if (r < 0)
util_fatal("No PIN entered");
if (!new_pin1 || !*new_pin1 || strlen(new_pin1) > 20)
util_fatal("Invalid User PIN");
printf("Please enter the new PIN again: ");
r = util_getpass(&new_pin2, &len2, stdin);
if (r < 0)
util_fatal("No PIN entered");
if (!new_pin2 || !*new_pin2 ||
strcmp(new_pin1, new_pin2) != 0)
util_fatal("Different new User PINs");
}
}
pin = (char *) opt_pin;
if (!pin) pin = (char *) opt_new_pin;
if (!pin) pin = new_pin1;
rv = p11->C_InitPIN(sess, (CK_UTF8CHAR *) pin, pin == NULL ? 0 : strlen(pin));
if (new_pin1) {
memset(new_pin1, 0, len1);
free(new_pin1);
}
if (new_pin2) {
memset(new_pin2,0, len2);
free(new_pin2);
}
if (rv != CKR_OK)
p11_fatal("C_InitPIN", rv);
printf("User PIN successfully initialized\n");
}
static int change_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess)
{
char old_buf[21], *old_pin = opt_so_pin ? (char*)opt_so_pin : (char*)opt_pin;
char new_buf[21], *new_pin = (char *)opt_new_pin;
CK_TOKEN_INFO info;
CK_RV rv;
int r;
size_t len = 0;
get_token_info(slot, &info);
const CK_FLAGS hasReaderPinPad = info.flags & CKF_PROTECTED_AUTHENTICATION_PATH;
if (!hasReaderPinPad && !old_pin) {
printf("Please enter the current PIN: ");
r = util_getpass(&old_pin, &len, stdin);
if (r < 0)
return 1;
if (!old_pin || !*old_pin || strlen(old_pin) > 20)
return 1;
strcpy(old_buf, old_pin);
old_pin = old_buf;
}
if (!hasReaderPinPad && !new_pin) {
printf("Please enter the new PIN: ");
r = util_getpass(&new_pin, &len, stdin);
if (r < 0)
return 1;
if (!new_pin || !*new_pin || strlen(new_pin) > 20)
return 1;
strcpy(new_buf, new_pin);
printf("Please enter the new PIN again: ");
r = util_getpass(&new_pin, &len, stdin);
if (r < 0)
return 1;
if (!new_pin || !*new_pin || strcmp(new_buf, new_pin) != 0) {
free(new_pin);
return 1;
}
}
rv = p11->C_SetPIN(sess,
(CK_UTF8CHAR *) old_pin, old_pin == NULL ? 0 : strlen(old_pin),
(CK_UTF8CHAR *) new_pin, new_pin == NULL ? 0 : strlen(new_pin));
if (rv != CKR_OK)
p11_fatal("C_SetPIN", rv);
printf("PIN successfully changed\n");
return 0;
}
static int unlock_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess, int login_type)
{
char unlock_buf[21], *unlock_code = NULL;
char new_buf[21], *new_pin = NULL;
CK_TOKEN_INFO info;
CK_RV rv;
int r;
size_t len = 0;
get_token_info(slot, &info);
if (login_type == CKU_CONTEXT_SPECIFIC)
unlock_code = opt_pin ? (char *) opt_pin : (char *) opt_puk;
else if (login_type == -1)
unlock_code = (char *) opt_puk;
else
return 1;
if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) && !unlock_code) {
if (login_type == CKU_CONTEXT_SPECIFIC)
printf("Please enter the 'Change PIN' context secret code: ");
else if (login_type == -1)
printf("Please enter unblock code for User PIN: ");
r = util_getpass(&unlock_code, &len, stdin);
if (r < 0)
return 1;
if (!unlock_code || !*unlock_code || strlen(unlock_code) > 20)
return 1;
strcpy(unlock_buf, unlock_code);
unlock_code = unlock_buf;
}
new_pin = (char *) opt_new_pin;
if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) && !new_pin) {
printf("Please enter the new PIN: ");
r = util_getpass(&new_pin, &len, stdin);
if (r < 0)
return 1;
strlcpy(new_buf, new_pin, sizeof new_buf);
printf("Please enter the new PIN again: ");
r = util_getpass(&new_pin, &len, stdin);
if (r < 0)
return 1;
if (!new_pin || !*new_pin || strcmp(new_buf, new_pin) != 0) {
if (new_pin != opt_new_pin)
free(new_pin);
printf(" different new PINs, exiting\n");
return -1;
}
if (!new_pin || !*new_pin || strlen(new_pin) > 20) {
if (new_pin != opt_new_pin)
free(new_pin);
return 1;
}
}
rv = p11->C_SetPIN(sess,
(CK_UTF8CHAR *) unlock_code, unlock_code == NULL ? 0 : strlen(unlock_code),
(CK_UTF8CHAR *) new_pin, new_pin == NULL ? 0 : strlen(new_pin));
if (rv != CKR_OK)
p11_fatal("C_SetPIN", rv);
printf("PIN successfully changed\n");
return 0;
}
/* return digest length in bytes */
static unsigned long hash_length(const int hash) {
unsigned long sLen = 0;
switch (hash) {
case CKM_SHA_1:
sLen = 20;
break;
case CKM_SHA224:
case CKM_SHA3_224:
sLen = 28;
break;
case CKM_SHA256:
case CKM_SHA3_256:
sLen = 32;
break;
case CKM_SHA384:
case CKM_SHA3_384:
sLen = 48;
break;
case CKM_SHA512:
case CKM_SHA3_512:
sLen = 64;
break;
default:
util_fatal("Unknown hash algorithm '%s' for RSA-PSS signatures",
p11_mechanism_to_name(hash));
break;
}
return sLen;
}
static unsigned long
parse_pss_params(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key,
CK_MECHANISM *mech, CK_RSA_PKCS_PSS_PARAMS *pss_params)
{
unsigned long hashlen = 0;
if (pss_params == NULL)
return 0;
pss_params->hashAlg = 0;
if (opt_hash_alg != 0 && opt_mechanism != CKM_RSA_PKCS_PSS)
util_fatal("The hash-algorithm is applicable only to "
"RSA-PKCS-PSS mechanism");
/* set "default" MGF and hash algorithms. We can overwrite MGF later */
switch (opt_mechanism) {
case CKM_RSA_PKCS_PSS:
pss_params->hashAlg = opt_hash_alg;
switch (opt_hash_alg) {
case CKM_SHA224:
pss_params->mgf = CKG_MGF1_SHA224;
break;
case CKM_SHA256:
pss_params->mgf = CKG_MGF1_SHA256;
break;
case CKM_SHA384:
pss_params->mgf = CKG_MGF1_SHA384;
break;
case CKM_SHA512:
pss_params->mgf = CKG_MGF1_SHA512;
break;
case CKM_SHA3_224:
pss_params->mgf = CKG_MGF1_SHA3_224;
break;
case CKM_SHA3_256:
pss_params->mgf = CKG_MGF1_SHA3_256;
break;
case CKM_SHA3_384:
pss_params->mgf = CKG_MGF1_SHA3_384;
break;
case CKM_SHA3_512:
pss_params->mgf = CKG_MGF1_SHA3_512;
break;
default:
/* the PSS should use SHA-1 if not specified */
pss_params->hashAlg = CKM_SHA_1;
/* fallthrough */
case CKM_SHA_1:
pss_params->mgf = CKG_MGF1_SHA1;
}
break;
case CKM_SHA1_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA_1;
pss_params->mgf = CKG_MGF1_SHA1;
break;
case CKM_SHA224_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA224;
pss_params->mgf = CKG_MGF1_SHA224;
break;
case CKM_SHA256_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA256;
pss_params->mgf = CKG_MGF1_SHA256;
break;
case CKM_SHA384_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA384;
pss_params->mgf = CKG_MGF1_SHA384;
break;
case CKM_SHA512_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA512;
pss_params->mgf = CKG_MGF1_SHA512;
break;
case CKM_SHA3_224_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA3_224;
pss_params->mgf = CKG_MGF1_SHA3_224;
break;
case CKM_SHA3_256_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA3_256;
pss_params->mgf = CKG_MGF1_SHA3_256;
break;
case CKM_SHA3_384_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA3_384;
pss_params->mgf = CKG_MGF1_SHA3_384;
break;
case CKM_SHA3_512_RSA_PKCS_PSS:
pss_params->hashAlg = CKM_SHA3_512;
pss_params->mgf = CKG_MGF1_SHA3_512;
break;
default: /* The non-RSA-PSS algorithms do not need any parameters */
return 0;
}
/* One of RSA-PSS mechanisms above: They need parameters */
if (pss_params->hashAlg) {
if (opt_mgf != 0)
pss_params->mgf = opt_mgf;
hashlen = hash_length(pss_params->hashAlg);
if (opt_salt_len_given == 1) { /* salt size explicitly given */
unsigned long modlen = 0;
modlen = (get_private_key_length(session, key) + 7) / 8;
switch (opt_salt_len) {
case -1: /* salt size equals to digest size */
pss_params->sLen = hashlen;
break;
case -2: /* maximum permissible salt len */
case -3:
pss_params->sLen = modlen - hashlen - 2;
break;
default: /* use given size but its value must be >= 0 */
if (opt_salt_len < 0)
util_fatal("Salt length must be greater or equal "
"to zero, or equal to -1 (meaning: use digest size) "
"or to -2 or -3 (meaning: use maximum permissible size");
pss_params->sLen = opt_salt_len;
break;
} /* end switch (opt_salt_len_given) */
} else { /* use default: salt len of digest size */
pss_params->sLen = hashlen;
}
mech->pParameter = pss_params;
mech->ulParameterLen = sizeof(*pss_params);
fprintf(stderr, "PSS parameters: hashAlg=%s, mgf=%s, salt_len=%lu B\n",
p11_mechanism_to_name(pss_params->hashAlg),
p11_mgf_to_name(pss_params->mgf),
pss_params->sLen);
}
return hashlen;
}
static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE key)
{
unsigned char in_buffer[1025], sig_buffer[512];
CK_MECHANISM mech;
CK_RSA_PKCS_PSS_PARAMS pss_params;
CK_RV rv;
CK_ULONG sig_len;
int fd, r;
unsigned long hashlen;
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_SIGN|opt_allow_sw, NULL, 0, &opt_mechanism))
util_fatal("Sign mechanism not supported");
fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;
hashlen = parse_pss_params(session, key, &mech, &pss_params);
if (opt_input == NULL)
fd = 0;
else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0)
util_fatal("Cannot open %s: %m", opt_input);
r = read(fd, in_buffer, sizeof(in_buffer));
if (r < 0)
util_fatal("Cannot read from %s: %m", opt_input);
if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) {
util_fatal("For %s mechanism, message size (got %d bytes) "
"must be equal to specified digest length (%lu)\n",
p11_mechanism_to_name(opt_mechanism), r, hashlen);
}
rv = CKR_CANCEL;
if (r < (int) sizeof(in_buffer)) {
rv = p11->C_SignInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_SignInit", rv);
if (getALWAYS_AUTHENTICATE(session, key))
login(session,CKU_CONTEXT_SPECIFIC);
sig_len = sizeof(sig_buffer);
rv = p11->C_Sign(session, in_buffer, r, sig_buffer, &sig_len);
}
if (rv != CKR_OK) {
rv = p11->C_SignInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_SignInit", rv);
if (getALWAYS_AUTHENTICATE(session, key))
login(session,CKU_CONTEXT_SPECIFIC);
do {
rv = p11->C_SignUpdate(session, in_buffer, r);
if (rv != CKR_OK)
p11_fatal("C_SignUpdate", rv);
r = read(fd, in_buffer, sizeof(in_buffer));
} while (r > 0);
sig_len = sizeof(sig_buffer);
rv = p11->C_SignFinal(session, sig_buffer, &sig_len);
if (rv != CKR_OK)
p11_fatal("C_SignFinal", rv);
}
if (fd != 0)
close(fd);
if (opt_output == NULL)
fd = 1;
else if ((fd = open(opt_output, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
util_fatal("failed to open %s: %m", opt_output);
}
if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 ||
opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 ||
opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224 ||
opt_mechanism == CKM_ECDSA_SHA3_224 || opt_mechanism == CKM_ECDSA_SHA3_256 ||
opt_mechanism == CKM_ECDSA_SHA3_384 || opt_mechanism == CKM_ECDSA_SHA3_512) {
if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") ||
!strcmp(opt_sig_format, "sequence"))) {
unsigned char *seq;
size_t seqlen;
if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer,
sig_len, &seq, &seqlen)) {
util_fatal("Failed to convert signature to ASN.1 sequence format");
}
memcpy(sig_buffer, seq, seqlen);
sig_len = seqlen;
free(seq);
}
}
r = write(fd, sig_buffer, sig_len);
if (r < 0)
util_fatal("Failed to write to %s: %m", opt_output);
if (fd != 1)
close(fd);
}
static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE key)
{
unsigned char in_buffer[1025], sig_buffer[512];
CK_MECHANISM mech;
CK_RSA_PKCS_PSS_PARAMS pss_params;
CK_RV rv;
CK_ULONG sig_len;
int fd, fd2, r, r2;
unsigned long hashlen;
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_VERIFY|opt_allow_sw, NULL, 0, &opt_mechanism))
util_fatal("Mechanism not supported for signature verification");
fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;
hashlen = parse_pss_params(session, key, &mech, &pss_params);
if (hashlen && opt_salt_len_given) {
if (opt_salt_len == -2) {
/* openssl allow us to set sLen to -2 for autodetecting salt length
* here maximal CK_ULONG value is used to pass this special code
* to openssl. For non OpenSC PKCS#11 module this is minimal limitation
* because there is no need to use extra long salt length.
*/
pss_params.sLen = ((CK_ULONG) 1 ) << (sizeof(CK_ULONG) * CHAR_BIT -1);
fprintf(stderr, "Warning, requesting salt length recovery from signature (supported only in in opensc pkcs11 module).\n");
}
}
/* Open a signature file */
if (opt_signature_file == NULL)
util_fatal("No file with signature provided. Use --signature-file");
else if ((fd2 = open(opt_signature_file, O_RDONLY|O_BINARY)) < 0)
util_fatal("Cannot open %s: %m", opt_signature_file);
r2 = read(fd2, sig_buffer, sizeof(sig_buffer));
if (r2 < 0)
util_fatal("Cannot read from %s: %m", opt_signature_file);
close(fd2);
if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 ||
opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 ||
opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224 ||
opt_mechanism == CKM_ECDSA_SHA3_224 || opt_mechanism == CKM_ECDSA_SHA3_256 ||
opt_mechanism == CKM_ECDSA_SHA3_384 || opt_mechanism == CKM_ECDSA_SHA3_512) {
if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") ||
!strcmp(opt_sig_format, "sequence"))) {
CK_BYTE* bytes;
CK_ULONG len;
size_t rs_len = 0;
unsigned char rs_buffer[512];
bytes = getEC_POINT(session, key, &len);
free(bytes);
/*
* (We only support uncompressed for now)
* Uncompressed EC_POINT is DER OCTET STRING of "04||x||y"
* So a "256" bit key has x and y of 32 bytes each
* something like: "04 41 04||x||y"
* Do simple size calculation based on DER encoding
*/
if ((len - 2) <= 127)
rs_len = len - 3;
else if ((len - 3) <= 255)
rs_len = len - 4;
else
util_fatal("Key not supported");
if (sc_asn1_sig_value_sequence_to_rs(NULL, sig_buffer, r2,
rs_buffer, rs_len)) {
util_fatal("Failed to convert ASN.1 signature");
}
memcpy(sig_buffer, rs_buffer, rs_len);
r2 = rs_len;
}
}
/* Open the data file */
if (opt_input == NULL)
fd = 0;
else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0)
util_fatal("Cannot open %s: %m", opt_input);
r = read(fd, in_buffer, sizeof(in_buffer));
if (r < 0)
util_fatal("Cannot read from %s: %m", opt_input);
if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) {
util_fatal("For %s mechanism, message size (got %d bytes)"
" must be equal to specified digest length (%lu)\n",
p11_mechanism_to_name(opt_mechanism), r, hashlen);
}
rv = CKR_CANCEL;
if (r < (int) sizeof(in_buffer)) {
rv = p11->C_VerifyInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_VerifyInit", rv);
sig_len = r2;
rv = p11->C_Verify(session, in_buffer, r, sig_buffer, sig_len);
}
if (rv != CKR_OK && rv != CKR_SIGNATURE_INVALID) {
rv = p11->C_VerifyInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_VerifyInit", rv);
do {
rv = p11->C_VerifyUpdate(session, in_buffer, r);
if (rv != CKR_OK)
p11_fatal("C_VerifyUpdate", rv);
r = read(fd, in_buffer, sizeof(in_buffer));
} while (r > 0);
sig_len = r2;
rv = p11->C_VerifyFinal(session, sig_buffer, sig_len);
if (rv != CKR_OK && rv != CKR_SIGNATURE_INVALID)
p11_fatal("C_VerifyFinal", rv);
}
if (fd != 0)
close(fd);
if (rv == CKR_OK)
printf("Signature is valid\n");
else if (rv == CKR_SIGNATURE_INVALID)
printf("Invalid signature\n");
else
printf("Cryptoki returned error: %s\n", CKR2Str(rv));
}
static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE key)
{
unsigned char in_buffer[1024], out_buffer[1024];
CK_MECHANISM mech;
CK_RV rv;
CK_RSA_PKCS_OAEP_PARAMS oaep_params;
CK_ULONG in_len, out_len;
int fd_in, fd_out;
int r;
CK_BYTE_PTR iv = NULL;
size_t iv_size = 0;
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_DECRYPT|opt_allow_sw, NULL, 0, &opt_mechanism))
util_fatal("Decrypt mechanism not supported");
fprintf(stderr, "Using decrypt algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;
oaep_params.hashAlg = 0;
if (opt_hash_alg != 0 && opt_mechanism != CKM_RSA_PKCS_OAEP)
util_fatal("The hash-algorithm is applicable only to "
"RSA-PKCS-OAEP mechanism");
/* set "default" MGF and hash algorithms. We can overwrite MGF later */
switch (opt_mechanism) {
case CKM_RSA_PKCS_OAEP:
oaep_params.hashAlg = opt_hash_alg;
switch (opt_hash_alg) {
case CKM_SHA_1:
oaep_params.mgf = CKG_MGF1_SHA1;
break;
case CKM_SHA224:
oaep_params.mgf = CKG_MGF1_SHA224;
break;
case CKM_SHA3_224:
oaep_params.mgf = CKG_MGF1_SHA3_224;
break;
case CKM_SHA3_256:
oaep_params.mgf = CKG_MGF1_SHA3_256;
break;
case CKM_SHA3_384:
oaep_params.mgf = CKG_MGF1_SHA3_384;
break;
case CKM_SHA3_512:
oaep_params.mgf = CKG_MGF1_SHA3_512;
break;
default:
oaep_params.hashAlg = CKM_SHA256;
/* fall through */
case CKM_SHA256:
oaep_params.mgf = CKG_MGF1_SHA256;
break;
case CKM_SHA384:
oaep_params.mgf = CKG_MGF1_SHA384;
break;
case CKM_SHA512:
oaep_params.mgf = CKG_MGF1_SHA512;
break;
}
break;
case CKM_RSA_X_509:
case CKM_RSA_PKCS:
case CKM_AES_ECB:
mech.pParameter = NULL;
mech.ulParameterLen = 0;
break;
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
iv_size = 16;
iv = get_iv(opt_iv, &iv_size);
mech.pParameter = iv;
mech.ulParameterLen = iv_size;
break;
default:
util_fatal("Mechanism %s illegal or not supported\n", p11_mechanism_to_name(opt_mechanism));
}
/* If an RSA-OAEP mechanism, it needs parameters */
if (oaep_params.hashAlg) {
if (opt_mgf != 0)
oaep_params.mgf = opt_mgf;
/* These settings are compatible with OpenSSL 1.0.2L and 1.1.0+ */
oaep_params.source = 0UL; /* empty encoding parameter (label) */
oaep_params.pSourceData = NULL; /* PKCS#11 standard: this must be NULLPTR */
oaep_params.ulSourceDataLen = 0; /* PKCS#11 standard: this must be 0 */
mech.pParameter = &oaep_params;
mech.ulParameterLen = sizeof(oaep_params);
fprintf(stderr, "OAEP parameters: hashAlg=%s, mgf=%s, source_type=%lu, source_ptr=%p, source_len=%lu\n",
p11_mechanism_to_name(oaep_params.hashAlg),
p11_mgf_to_name(oaep_params.mgf),
oaep_params.source,
oaep_params.pSourceData,
oaep_params.ulSourceDataLen);
}
if (opt_input == NULL)
fd_in = 0;
else if ((fd_in = open(opt_input, O_RDONLY | O_BINARY)) < 0)
util_fatal("Cannot open %s: %m", opt_input);
if (opt_output == NULL) {
fd_out = 1;
} else {
fd_out = open(opt_output, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
if (fd_out < 0)
util_fatal("failed to open %s: %m", opt_output);
}
r = read(fd_in, in_buffer, sizeof(in_buffer));
in_len = r;
if (r < 0)
util_fatal("Cannot read from %s: %m", opt_input);
rv = CKR_CANCEL;
if (r < (int) sizeof(in_buffer)) {
out_len = sizeof(out_buffer);
rv = p11->C_DecryptInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_DecryptInit", rv);
if (getALWAYS_AUTHENTICATE(session, key))
login(session, CKU_CONTEXT_SPECIFIC);
rv = p11->C_Decrypt(session, in_buffer, in_len, out_buffer, &out_len);
}
if (rv != CKR_OK) {
rv = p11->C_DecryptInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_DecryptInit", rv);
if (getALWAYS_AUTHENTICATE(session, key))
login(session, CKU_CONTEXT_SPECIFIC);
do {
out_len = sizeof(out_buffer);
rv = p11->C_DecryptUpdate(session, in_buffer, in_len, out_buffer, &out_len);
if (rv != CKR_OK)
p11_fatal("C_DecryptUpdate", rv);
r = write(fd_out, out_buffer, out_len);
if (r != (int) out_len)
util_fatal("Cannot write to %s: %m", opt_output);
r = read(fd_in, in_buffer, sizeof(in_buffer));
in_len = r;
} while (r > 0);
out_len = sizeof(out_buffer);
rv = p11->C_DecryptFinal(session, out_buffer, &out_len);
if (rv != CKR_OK)
p11_fatal("C_DecryptFinal", rv);
}
if (out_len) {
r = write(fd_out, out_buffer, out_len);
if (r != (int) out_len)
util_fatal("Cannot write to %s: %m", opt_output);
}
if (fd_in != 0)
close(fd_in);
if (fd_out != 1)
close(fd_out);
free(iv);
}
static void encrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE key)
{
unsigned char in_buffer[1024], out_buffer[1024];
CK_MECHANISM mech;
CK_RV rv;
CK_ULONG in_len, out_len;
int fd_in, fd_out;
int r;
CK_BYTE_PTR iv = NULL;
size_t iv_size = 0;
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_ENCRYPT | opt_allow_sw, NULL, 0, &opt_mechanism))
util_fatal("Encrypt mechanism not supported");
fprintf(stderr, "Using encrypt algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;
switch (opt_mechanism) {
case CKM_AES_ECB:
mech.pParameter = NULL;
mech.ulParameterLen = 0;
break;
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
iv_size = 16;
iv = get_iv(opt_iv, &iv_size);
mech.pParameter = iv;
mech.ulParameterLen = iv_size;
break;
default:
util_fatal("Mechanism %s illegal or not supported\n", p11_mechanism_to_name(opt_mechanism));
}
if (opt_input == NULL)
fd_in = 0;
else if ((fd_in = open(opt_input, O_RDONLY | O_BINARY)) < 0)
util_fatal("Cannot open %s: %m", opt_input);
if (opt_output == NULL) {
fd_out = 1;
} else {
fd_out = open(opt_output, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
if (fd_out < 0)
util_fatal("failed to open %s: %m", opt_output);
}
r = read(fd_in, in_buffer, sizeof(in_buffer));
in_len = r;
if (r < 0)
util_fatal("Cannot read from %s: %m", opt_input);
rv = CKR_CANCEL;
if (r < (int) sizeof(in_buffer)) {
out_len = sizeof(out_buffer);
rv = p11->C_EncryptInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_EncryptInit", rv);
if (getALWAYS_AUTHENTICATE(session, key))
login(session, CKU_CONTEXT_SPECIFIC);
out_len = sizeof(out_buffer);
rv = p11->C_Encrypt(session, in_buffer, in_len, out_buffer, &out_len);
}
if (rv != CKR_OK) {
rv = p11->C_EncryptInit(session, &mech, key);
if (rv != CKR_OK)
p11_fatal("C_EncryptInit", rv);
if (getALWAYS_AUTHENTICATE(session, key))
login(session, CKU_CONTEXT_SPECIFIC);
do {
out_len = sizeof(out_buffer);
rv = p11->C_EncryptUpdate(session, in_buffer, in_len, out_buffer, &out_len);
if (rv != CKR_OK)
p11_fatal("C_EncryptUpdate", rv);
r = write(fd_out, out_buffer, out_len);
if (r != (int) out_len)
util_fatal("Cannot write to %s: %m", opt_output);
r = read(fd_in, in_buffer, sizeof(in_buffer));
in_len = r;
} while (r > 0);
out_len = sizeof(out_buffer);
rv = p11->C_EncryptFinal(session, out_buffer, &out_len);
if (rv != CKR_OK)
p11_fatal("C_EncryptFinal", rv);
}
if (out_len) {
r = write(fd_out, out_buffer, out_len);
if (r != (int) out_len)
util_fatal("Cannot write to %s: %m", opt_output);
}
if (fd_in != 0)
close(fd_in);
if (fd_out != 1)
close(fd_out);
free(iv);
}
static void hash_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
{
unsigned char buffer[64];
CK_MECHANISM mech;
CK_RV rv;
CK_ULONG hash_len;
int fd, r;
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_DIGEST, NULL, 0, &opt_mechanism))
util_fatal("Digest mechanism is not supported");
fprintf(stderr, "Using digest algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;
rv = p11->C_DigestInit(session, &mech);
if (rv != CKR_OK)
p11_fatal("C_DigestInit", rv);
if (opt_input == NULL)
fd = 0;
else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0)
util_fatal("Cannot open %s: %m", opt_input);
while ((r = read(fd, buffer, sizeof(buffer))) > 0) {
rv = p11->C_DigestUpdate(session, buffer, r);
if (rv != CKR_OK)
p11_fatal("C_DigestUpdate", rv);
}
if (fd != 0)
close(fd);
hash_len = sizeof(buffer);
rv = p11->C_DigestFinal(session, buffer, &hash_len);
if (rv != CKR_OK)
p11_fatal("C_DigestFinal", rv);
if (opt_output == NULL)
fd = 1;
else if ((fd = open(opt_output, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR)) < 0)
util_fatal("failed to open %s: %m", opt_output);
r = write(fd, buffer, hash_len);
if (r < 0)
util_fatal("Failed to write to %s: %m", opt_output);
if (fd != 1)
close(fd);
}
#define FILL_ATTR(attr, typ, val, len) {(attr).type=(typ); (attr).pValue=(val); (attr).ulValueLen=len;}
/* Generate asymmetric key pair */
static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE *hPublicKey, CK_OBJECT_HANDLE *hPrivateKey, const char *type)
{
CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
CK_ULONG modulusBits = 1024;
CK_BYTE publicExponent[] = { 0x01, 0x00, 0x01 }; /* 65537 in bytes */
CK_BBOOL _true = TRUE;
CK_BBOOL _false = FALSE;
CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
CK_OBJECT_CLASS privkey_class = CKO_PRIVATE_KEY;
CK_ATTRIBUTE publicKeyTemplate[20] = {
{CKA_CLASS, &pubkey_class, sizeof(pubkey_class)},
{CKA_TOKEN, &_true, sizeof(_true)},
};
int n_pubkey_attr = 2;
CK_ATTRIBUTE privateKeyTemplate[20] = {
{CKA_CLASS, &privkey_class, sizeof(privkey_class)},
{CKA_TOKEN, &_true, sizeof(_true)},
{CKA_PRIVATE, &_true, sizeof(_true)},
{CKA_SENSITIVE, &_true, sizeof(_true)},
};
unsigned long int gost_key_type = -1;
int n_privkey_attr = 4;
unsigned char *ecparams = NULL;
size_t ecparams_size;
CK_ULONG key_type = CKK_RSA;
CK_RV rv;
if (type != NULL) {
if (strncmp(type, "RSA:", strlen("RSA:")) == 0 || strncmp(type, "rsa:", strlen("rsa:")) == 0) {
CK_MECHANISM_TYPE mtypes[] = {CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_X9_31_KEY_PAIR_GEN};
size_t mtypes_num = sizeof(mtypes)/sizeof(mtypes[0]);
CK_ULONG key_length;
const char *size = type + strlen("RSA:");
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_GENERATE_KEY_PAIR, mtypes, mtypes_num, &opt_mechanism))
util_fatal("Generate RSA mechanism not supported");
if (size == NULL)
util_fatal("Unknown key pair type %s, expecting RSA:<nbytes>", type);
key_length = (unsigned long)atol(size);
if (key_length != 0)
modulusBits = key_length;
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits));
n_pubkey_attr++;
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent));
n_pubkey_attr++;
if (opt_key_usage_default || opt_key_usage_sign) {
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_VERIFY, &_true, sizeof(_true));
n_pubkey_attr++;
FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_SIGN, &_true, sizeof(_true));
n_privkey_attr++;
}
if (opt_key_usage_default || opt_key_usage_decrypt) {
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_ENCRYPT, &_true, sizeof(_true));
n_pubkey_attr++;
FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_DECRYPT, &_true, sizeof(_true));
n_privkey_attr++;
}
if (opt_key_usage_wrap) {
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_WRAP, &_true, sizeof(_true));
n_pubkey_attr++;
FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_UNWRAP, &_true, sizeof(_true));
n_privkey_attr++;
}
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
n_pubkey_attr++;
FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
n_privkey_attr++;
}
else if (strncmp(type, "EC:", strlen("EC:")) == 0 || strncmp(type, "ec:", strlen("ec:")) == 0) {
CK_MECHANISM_TYPE mtypes[] = {CKM_EC_KEY_PAIR_GEN};
size_t mtypes_num = sizeof(mtypes)/sizeof(mtypes[0]);
int ii;
key_type = CKK_EC;
for (ii=0; ec_curve_infos[ii].name; ii++) {
if (!strcmp(ec_curve_infos[ii].name, type + 3))
break;
if (!strcmp(ec_curve_infos[ii].oid, type + 3))
break;
}
if (!ec_curve_infos[ii].name)
util_fatal("Unknown EC key params '%s'", type + 3);