summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authordinak <none@none>2005-06-15 19:38:38 -0700
committerdinak <none@none>2005-06-15 19:38:38 -0700
commit7711facfe58561dd91d6ece0f5f41150c3956c83 (patch)
treedd68055110e4f9562ff4b14f6d3ac9d2f76176b9 /usr/src/cmd
parentac0f75d71d71ee22b0e3a392d3b2fa2885e11634 (diff)
downloadillumos-joyent-7711facfe58561dd91d6ece0f5f41150c3956c83.tar.gz
PSARC 2004/124 pktool enhancements to support object migration and softtoken interoperability
PSARC 2005/019 pktool(1) list/delete updates 4931202 Provide import utility from PKCS12 file to softtoken's keystore 5059459 provide utility to export-to-PKCS#12-file from softttoken 5059461 pktool(1) needs subcommands to list and delete objects in softtoken 6216772 update pktool(1) list/delete subcommands 6278459 add "tokens" subcommand to pktool(1) 6285539 E_NAME_USED_NOT_DEF2 lint error for ENGINE_load_builtin_engines
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/Makefile22
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/biginteger.h58
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/common.c1005
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/common.h98
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/delete.c227
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/derparse.c371
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/derparse.h55
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/export.c1404
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/import.c945
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/list.c1016
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/osslcommon.c224
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/osslcommon.h50
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/p12common.c103
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/p12common.h46
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/pktool.c167
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/setpin.c198
-rw-r--r--usr/src/cmd/cmd-crypto/pktool/tokens.c104
17 files changed, 5781 insertions, 312 deletions
diff --git a/usr/src/cmd/cmd-crypto/pktool/Makefile b/usr/src/cmd/cmd-crypto/pktool/Makefile
index 5cadc0ce1c..0ad8e96905 100644
--- a/usr/src/cmd/cmd-crypto/pktool/Makefile
+++ b/usr/src/cmd/cmd-crypto/pktool/Makefile
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -30,24 +30,38 @@ PROG = pktool
OBJS = pktool.o \
common.o \
- setpin.o
+ derparse.o \
+ osslcommon.o \
+ p12common.o \
+ setpin.o \
+ list.o \
+ delete.o \
+ import.o \
+ export.o \
+ tokens.o
include ../../Makefile.cmd
+include $(SRC)/lib/openssl/Makefile.openssl
SRCS = $(OBJS:%.o=%.c)
POFILES = $(OBJS:%.o=%.po)
POFILE = $(PROG)_msg.po
+CPPFLAGS += -I. $(OPENSSL_CPPFLAGS)
CFLAGS += $(CCVERBOSE)
-LDLIBS += -lpkcs11 -lcryptoutil
+DYNFLAGS += $(OPENSSL_DYNFLAGS)
+LDFLAGS += $(OPENSSL_LDFLAGS)
+LDLIBS += -lpkcs11 -lcryptoutil -lcrypto -lldap
+
+LINTFLAGS += $(OPENSSL_LDFLAGS)
.KEEP_STATE:
all : $(PROG)
$(PROG) : $(OBJS)
- $(LINK.c) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS)
+ $(LINK.c) -o $@ $(OBJS) $(DYNFLAGS) $(LDLIBS)
$(POST_PROCESS)
$(POFILE) : $(POFILES)
diff --git a/usr/src/cmd/cmd-crypto/pktool/biginteger.h b/usr/src/cmd/cmd-crypto/pktool/biginteger.h
new file mode 100644
index 0000000000..3764e47aaa
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/biginteger.h
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PKTOOL_BIGINTEGER_H
+#define _PKTOOL_BIGINTEGER_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <security/pkcs11t.h>
+
+/*
+ * NOTE:
+ *
+ * This is same "biginteger_t" found in both these places:
+ * usr/src/lib/pkcs11/pkcs11_softtoken/common/softObject.h
+ * usr/src/lib/pkcs11/pkcs11_kernel/common/kernelObject.h
+ * The BIGNUM implementation in usr/src/common/bignum does not
+ * meet the need. It is recommended that the biginteger_t be
+ * factored out of pkcs11_softtoken/pkcs11_kernel/pktool and
+ * the pkcs11 libraries and moved into cryptoutil.h
+ */
+typedef struct biginteger {
+ CK_BYTE *big_value;
+ CK_ULONG big_value_len;
+} biginteger_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKTOOL_BIGINTEGER_H */
diff --git a/usr/src/cmd/cmd-crypto/pktool/common.c b/usr/src/cmd/cmd-crypto/pktool/common.c
index 29d4605942..76685ba171 100644
--- a/usr/src/cmd/cmd-crypto/pktool/common.c
+++ b/usr/src/cmd/cmd-crypto/pktool/common.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,6 +29,9 @@
/*
* This file contains the functions that are shared among
* the various services this tool will ultimately provide.
+ * The functions in this file return PKCS#11 CK_RV errors.
+ * Only one session and one login per token is supported
+ * at this time.
*/
#include <stdio.h>
@@ -38,50 +41,395 @@
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"
+#include "biginteger.h"
-/* Global PKCS#11 error value. */
-int pk11_errno = 0;
+/* True and false for attribute templates. */
+CK_BBOOL pk_true = B_TRUE;
+CK_BBOOL pk_false = B_FALSE;
+
+/* Local status variables. */
+static boolean_t initialized = B_FALSE;
+static boolean_t session_opened = B_FALSE;
+static boolean_t session_writable = B_FALSE;
+static boolean_t logged_in = B_FALSE;
/*
- * Gets passphrase from user, caller needs to free when done.
+ * Perform PKCS#11 setup here. Currently only C_Initialize is required,
+ * along with setting/resetting state variables.
*/
-int
-get_password(char *prompt, char **password)
+CK_RV
+init_pk11(void)
{
- char *phrase;
+ CK_RV rv = CKR_OK;
+
+ cryptodebug("inside init_pk11");
+
+ /* If C_Initialize() already called, nothing to do here. */
+ if (initialized == B_TRUE)
+ return (CKR_OK);
- /* Prompt user for password. */
- if ((phrase = getpassphrase(prompt)) == NULL)
- return (-1);
+ /* Reset state variables because C_Initialize() not yet done. */
+ session_opened = B_FALSE;
+ session_writable = B_FALSE;
+ logged_in = B_FALSE;
- /* Duplicate passphrase in separate chunk of memory */
- if ((*password = strdup(phrase)) == NULL)
- return (-1);
+ /* Initialize PKCS#11 library. */
+ cryptodebug("calling C_Initialize()");
+ if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
+ rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+ return (rv);
+ }
- return (strlen(phrase));
+ initialized = B_TRUE;
+ return (CKR_OK);
}
/*
- * Perform any PKCS#11 setup here. Right now, this tool only
- * requires C_Initialize(). Additional features planned for
- * this tool will require more initialization and state info
- * added here.
+ * Finalize PKCS#11 library and reset state variables. Open sessions,
+ * if any, are closed, and thereby any logins are logged out also.
*/
-int
-init_pk11(void)
+void
+final_pk11(CK_SESSION_HANDLE sess)
{
- int rv;
+ cryptodebug("inside final_pk11");
- cryptodebug("inside init_pk11");
+ /* If the library wasn't initialized, nothing to do here. */
+ if (!initialized)
+ return;
- /* Initialize PKCS#11 library. */
- if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
- rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
- pk11_errno = rv;
- return (PK_ERR_PK11INIT);
+ /* Make sure the sesion is closed first. */
+ close_sess(sess);
+
+ cryptodebug("calling C_Finalize()");
+ (void) C_Finalize(NULL);
+ initialized = B_FALSE;
+}
+
+/*
+ * Create a PKCS#11 session on the given slot, and set state information.
+ * If session is already open, check that the read-only/read-write state
+ * requested matches that of the session. If it doesn't, make it so.
+ */
+CK_RV
+open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_SESSION_HANDLE_PTR sess)
+{
+ CK_RV rv = CKR_OK;
+
+ cryptodebug("inside open_sess");
+
+ /* If the session is already open, check the session flags. */
+ if (session_opened) {
+ /*
+ * If requesting R/W session and it is currently R/O,
+ * need to close the session and reopen it R/W. The
+ * other cases are considered acceptable:
+ * sess_flags current state
+ * ---------- -------------
+ * ~CKF_RW_SESSION !session_writable
+ * ~CKF_RW_SESSION session_writable
+ * CKF_RW_SESSION session_writable
+ */
+ if ((sess_flags & CKF_RW_SESSION) && !session_writable)
+ close_sess(*sess);
+ else
+ return (CKR_OK);
+ }
+
+ /* Make sure the PKCS#11 is already initialized. */
+ if (!initialized)
+ if ((rv = init_pk11()) != CKR_OK)
+ return (rv);
+
+ /* Create a session for subsequent operations. */
+ cryptodebug("calling C_OpenSession()");
+ if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|sess_flags,
+ NULL, NULL, sess)) != CKR_OK)
+ return (rv);
+ session_opened = B_TRUE;
+ session_writable = (sess_flags & CKF_RW_SESSION) ? B_TRUE : B_FALSE;
+ return (CKR_OK);
+}
+
+/*
+ * Close PKCS#11 session and reset state variables. Any logins are
+ * logged out.
+ */
+void
+close_sess(CK_SESSION_HANDLE sess)
+{
+ cryptodebug("inside close_sess");
+
+ if (sess == NULL) {
+ cryptodebug("session handle is null");
+ return;
+ }
+
+ /* If session is already closed, nothing to do here. */
+ session_writable = B_FALSE;
+ if (!session_opened)
+ return;
+
+ /* Make sure user is logged out of token. */
+ logout_token(sess);
+
+ cryptodebug("calling C_CloseSession()");
+ (void) C_CloseSession(sess);
+ session_opened = B_FALSE;
+}
+
+/*
+ * Log user into token in given slot. If this first login ever for this
+ * token, the initial PIN is "changeme", C_Login() will succeed, but all
+ * PKCS#11 calls following the C_Login() will fail with CKR_PIN_EXPIRED.
+ */
+CK_RV
+login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen,
+ CK_SESSION_HANDLE_PTR sess)
+{
+ CK_RV rv = CKR_OK;
+
+ cryptodebug("inside login_token");
+
+ /* If already logged in, nothing to do here. */
+ if (logged_in)
+ return (CKR_OK);
+
+ /* Make sure we have a session first, assume R/O is enough. */
+ if (!session_opened)
+ if ((rv = open_sess(slot_id, CKF_SERIAL_SESSION, sess)) !=
+ CKR_OK)
+ return (rv);
+
+ /* Log the user into the token. */
+ cryptodebug("calling C_Login()");
+ if ((rv = C_Login(*sess, CKU_USER, pin, pinlen)) != CKR_OK) {
+ cryptodebug("C_Login returns %s", pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ logged_in = B_TRUE;
+ return (CKR_OK);
+}
+
+/*
+ * Log user out of token and reset status variable.
+ */
+void
+logout_token(CK_SESSION_HANDLE sess)
+{
+ cryptodebug("inside logout_token");
+
+ if (sess == NULL) {
+ cryptodebug("session handle is null");
+ return;
}
- return (PK_ERR_NONE);
+ /* If already logged out, nothing to do here. */
+ if (!logged_in)
+ return;
+
+ cryptodebug("calling C_Logout()");
+ (void) C_Logout(sess);
+ logged_in = B_FALSE;
+}
+
+/*
+ * Shortcut function to get from an uninitialized state to user logged in.
+ * If the library is already initialized, the session is already opened,
+ * or the user is already logged in, those steps are skipped and the next
+ * step is checked.
+ */
+CK_RV
+quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin,
+ CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess)
+{
+ CK_RV rv = CKR_OK;
+
+ cryptodebug("inside quick_start");
+
+ /* Call open_sess() explicitly if R/W session is needed. */
+ if (sess_flags & CKF_RW_SESSION)
+ if ((rv = open_sess(slot_id, sess_flags, sess)) != CKR_OK)
+ return (rv);
+
+ if ((rv = login_token(slot_id, pin, pinlen, sess)) != CKR_OK)
+ return (rv);
+
+ return (CKR_OK);
+}
+
+/*
+ * Shortcut function to go from any state to uninitialized PKCS#11 library.
+ */
+void
+quick_finish(CK_SESSION_HANDLE sess)
+{
+ cryptodebug("inside quick_finish");
+
+ /* All the needed calls are done implicitly. */
+ final_pk11(sess);
+}
+
+/*
+ * Gets PIN from user. Caller needs to free the returned PIN when done.
+ * If two prompts are given, the PIN is confirmed with second prompt.
+ * Note that getphassphrase() may return data in static memory area.
+ */
+CK_RV
+get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
+{
+ char *save_phrase, *phrase1, *phrase2;
+
+ cryptodebug("inside get_pin");
+
+ /* Prompt user for a PIN. */
+ if (prompt1 == NULL) {
+ cryptodebug("no passphrase prompt given");
+ return (CKR_ARGUMENTS_BAD);
+ }
+ if ((phrase1 = getpassphrase(prompt1)) == NULL) {
+ cryptodebug("getpassphrase() failed");
+ return (CKR_FUNCTION_FAILED);
+ }
+
+ /* Duplicate 1st PIN in separate chunk of memory. */
+ if ((save_phrase = strdup(phrase1)) == NULL)
+ return (CKR_HOST_MEMORY);
+
+ /* If second prompt given, PIN confirmation is requested. */
+ if (prompt2 != NULL) {
+ if ((phrase2 = getpassphrase(prompt2)) == NULL) {
+ cryptodebug("getpassphrase() confirmation failed");
+ free(save_phrase);
+ return (CKR_FUNCTION_FAILED);
+ }
+ if (strcmp(save_phrase, phrase2) != 0) {
+ cryptodebug("passphrases do not match");
+ free(save_phrase);
+ return (CKR_PIN_INCORRECT);
+ }
+ }
+
+ *pin = (CK_UTF8CHAR_PTR)save_phrase;
+ *pinlen = strlen(save_phrase);
+ return (CKR_OK);
+}
+
+/*
+ * Gets yes/no response from user. If either no prompt is supplied, a
+ * default prompt is used. If not message for invalid input is supplied,
+ * a default will not be provided. If the user provides no response,
+ * the input default B_TRUE == yes, B_FALSE == no is returned.
+ * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
+ */
+boolean_t
+yesno(char *prompt, char *invalid, boolean_t dflt)
+{
+ char *response, buf[1024];
+ char *yes = gettext("yes");
+ char *no = gettext("no");
+
+ cryptodebug("inside yesno");
+
+ if (prompt == NULL)
+ prompt = gettext("Enter (y)es or (n)o? ");
+
+ for (;;) {
+ /* Prompt user. */
+ (void) printf("%s", prompt);
+ (void) fflush(stdout);
+
+ /* Get the response. */
+ if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
+ break; /* go to default response */
+
+ /* Skip any leading white space. */
+ while (isspace(*response))
+ response++;
+ if (*response == '\0')
+ break; /* go to default response */
+
+ /* Is it valid input? Return appropriately. */
+ if (strncasecmp(response, yes, 1) == 0)
+ return (B_TRUE);
+ if (strncasecmp(response, no, 1) == 0)
+ return (B_FALSE);
+
+ /* Indicate invalid input, and try again. */
+ if (invalid != NULL)
+ (void) printf("%s", invalid);
+ }
+ return (dflt);
+}
+
+/*
+ * Gets the list of slots which have tokens in them. Keeps adjusting
+ * the size of the slot list buffer until the call is successful or an
+ * irrecoverable error occurs.
+ */
+CK_RV
+get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
+{
+ CK_ULONG tmp_count = 0;
+ CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
+ int rv = CKR_OK;
+
+ cryptodebug("inside get_token_slots");
+
+ if (!initialized)
+ if ((rv = init_pk11()) != CKR_OK)
+ return (rv);
+
+ /*
+ * Get the slot count first because we don't know how many
+ * slots there are and how many of those slots even have tokens.
+ * Don't specify an arbitrary buffer size for the slot list;
+ * it may be too small (see section 11.5 of PKCS#11 spec).
+ * Also select only those slots that have tokens in them,
+ * because this tool has no need to know about empty slots.
+ */
+ cryptodebug("calling C_GetSlotList() for slot count");
+ if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
+ return (rv);
+
+ if (tmp_count == 0) {
+ cryptodebug("no slots with tokens found");
+ *slot_list = NULL_PTR;
+ *slot_count = 0;
+ return (CKR_OK);
+ }
+
+ /* Allocate initial space for the slot list. */
+ if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
+ sizeof (CK_SLOT_ID))) == NULL)
+ return (CKR_HOST_MEMORY);
+
+ /* Then get the slot list itself. */
+ for (;;) {
+ cryptodebug("calling C_GetSlotList()");
+ if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
+ *slot_list = tmp_list;
+ *slot_count = tmp_count;
+ break;
+ }
+
+ if (rv != CKR_BUFFER_TOO_SMALL) {
+ free(tmp_list);
+ break;
+ }
+
+ /* If the number of slots grew, try again. */
+ cryptodebug("number of tokens present increased");
+ if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
+ tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
+ free(tmp_list);
+ rv = CKR_HOST_MEMORY;
+ break;
+ }
+ tmp_list = tmp2_list;
+ }
+
+ return (rv);
}
/*
@@ -111,7 +459,6 @@ init_pk11(void)
static int
memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
{
-
uint_t len, extra_len;
char *marker;
@@ -146,18 +493,19 @@ memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
}
/*
- * Locate a token slot whose token matches the label, manufacturer
- * ID, and serial number given. Token label must be specified,
- * manufacturer ID and serial number are optional.
+ * Locate a token slot whose token matches the label, manufacturer ID, and
+ * serial number given. Token label must be specified, manufacturer ID and
+ * serial number are optional. When the token is located, the PIN state
+ * is also returned to determine if it still has the default PIN.
*/
-int
+CK_RV
find_token_slot(char *token_name, char *manuf_id, char *serial_no,
CK_SLOT_ID *slot_id, CK_FLAGS *pin_state)
{
CK_SLOT_ID_PTR slot_list;
CK_TOKEN_INFO token_info;
CK_ULONG slot_count = 0;
- int rv;
+ int rv = CKR_OK;
int i;
uint_t len, max_sz;
boolean_t tok_match = B_FALSE,
@@ -166,141 +514,570 @@ find_token_slot(char *token_name, char *manuf_id, char *serial_no,
cryptodebug("inside find_token_slot");
- /*
- * Get the slot count first because we don't know how many
- * slots there are and how many of those slots even have tokens.
- * Don't specify an arbitrary buffer size for the slot list;
- * it may be too small (see section 11.5 of PKCS#11 spec).
- * Also select only those slots that have tokens in them,
- * because this tool has no need to know about empty slots.
- */
- if ((rv = C_GetSlotList(1, NULL_PTR, &slot_count)) != CKR_OK) {
- pk11_errno = rv;
- return (PK_ERR_PK11SLOTS);
- }
+ if (token_name == NULL)
+ return (CKR_ARGUMENTS_BAD);
- if (slot_count == 0)
- return (PK_ERR_NOSLOTS); /* with tokens in them */
+ /* Get a list of all slots with tokens present. */
+ if ((rv = get_token_slots(&slot_list, &slot_count)) != CKR_OK)
+ return (rv);
- /* Allocate space for the slot list and get it. */
- if ((slot_list =
- (CK_SLOT_ID_PTR) malloc(slot_count * sizeof (CK_SLOT_ID))) == NULL)
- return (PK_ERR_NOMEMORY);
-
- if ((rv = C_GetSlotList(1, slot_list, &slot_count)) != CKR_OK) {
- /* NOTE: can slot_count change from previous call??? */
- pk11_errno = rv;
- free(slot_list);
- return (PK_ERR_PK11SLOTS);
- }
+ /* If there are no such slots, the desired token won't be found. */
+ if (slot_count == 0)
+ return (CKR_TOKEN_NOT_PRESENT);
- /* Search for the token. */
+ /* Search the slot list for the token. */
for (i = 0; i < slot_count; i++) {
- if ((rv =
- C_GetTokenInfo(slot_list[i], &token_info)) != CKR_OK) {
- cryptodebug("slot %d has no token", i);
+ cryptodebug("calling C_GetTokenInfo()");
+ if ((rv = C_GetTokenInfo(slot_list[i], &token_info)) !=
+ CKR_OK) {
+ cryptodebug("token in slot %d returns %s", i,
+ pkcs11_strerror(rv));
continue;
}
+ /* See if the token label matches. */
len = strlen(token_name);
max_sz = sizeof (token_info.label);
if (memcmp_pad_max(&(token_info.label), max_sz, token_name, len,
max_sz) == 0)
tok_match = B_TRUE;
- cryptodebug("slot %d:", i);
- cryptodebug("\tlabel = \"%.32s\"", token_info.label);
- cryptodebug("\tmanuf = \"%.32s\"", token_info.manufacturerID);
- cryptodebug("\tserno = \"%.16s\"", token_info.serialNumber);
- cryptodebug("\tmodel = \"%.16s\"", token_info.model);
-
- cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s",
- (token_info.flags & CKF_USER_PIN_INITIALIZED) ?
- "true" : "false");
- cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s",
- (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ?
- "true" : "false");
-
+ /*
+ * If manufacturer id was given, see if it actually matches.
+ * If no manufacturer id was given, assume match is true.
+ */
if (manuf_id) {
len = strlen(manuf_id);
max_sz = sizeof ((char *)(token_info.manufacturerID));
if (memcmp_pad_max(&(token_info.manufacturerID), max_sz,
manuf_id, len, max_sz) == 0)
man_match = B_TRUE;
- }
+ } else
+ man_match = B_TRUE;
+ /*
+ * If serial number was given, see if it actually matches.
+ * If no serial number was given, assume match is true.
+ */
if (serial_no) {
len = strlen(serial_no);
max_sz = sizeof ((char *)(token_info.serialNumber));
if (memcmp_pad_max(&(token_info.serialNumber), max_sz,
serial_no, len, max_sz) == 0)
ser_match = B_TRUE;
- }
+ } else
+ ser_match = B_TRUE;
+
+ cryptodebug("slot %d:", i);
+ cryptodebug("\tlabel = \"%.32s\"%s", token_info.label,
+ tok_match ? " match" : "");
+ cryptodebug("\tmanuf = \"%.32s\"%s", token_info.manufacturerID,
+ man_match ? " match" : "");
+ cryptodebug("\tserno = \"%.16s\"%s", token_info.serialNumber,
+ ser_match ? " match" : "");
+ cryptodebug("\tmodel = \"%.16s\"", token_info.model);
- if (tok_match &&
- (manuf_id ? B_TRUE : B_FALSE) == man_match &&
- (serial_no ? B_TRUE : B_FALSE) == ser_match)
- break; /* found it! */
+ cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s",
+ (token_info.flags & CKF_USER_PIN_INITIALIZED) ?
+ "true" : "false");
+ cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s",
+ (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ?
+ "true" : "false");
+
+ if (tok_match && man_match && ser_match)
+ break; /* found it! */
}
+ /* Scanned the whole list without finding the token. */
if (i == slot_count) {
+ cryptodebug("token not found");
free(slot_list);
- return (PK_ERR_NOTFOUND);
+ return (CKR_TOKEN_NOT_PRESENT);
}
- cryptodebug("matched token at slot %d", i);
+ /* Return slot id where token was found and its PIN state. */
+ cryptodebug("token found at slot %d", i);
*slot_id = slot_list[i];
*pin_state = (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED);
free(slot_list);
- return (PK_ERR_NONE);
+ return (CKR_OK);
}
/*
- * Log into the token in given slot and create a session for it.
+ * Constructs a fully qualified token name from its label, manufacturer ID
+ * (if any), and its serial number (if any). Note that the given buf must
+ * be big enough. Do NOT i18n/l10n.
+ *
+ * FULL_NAME_LEN is defined in common.h to be 91 because a fully qualified
+ * token name adds up this way:
+ * =32(label) + 32(manuf) + 16(serial) + 4("", ) + 4("", ) + 3("" and nul)
*/
-int
-login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen,
- CK_SESSION_HANDLE_PTR hdl)
+void
+full_token_name(char *token_name, char *manuf_id, char *serial_no, char *buf)
{
- int rv;
+ char *marker = buf;
+ int n_written = 0;
+ int space_left = FULL_NAME_LEN;
- cryptodebug("inside login_token");
+ if (!token_name)
+ return;
+
+ n_written = sprintf(buf, "\"%.32s\"", token_name);
+ marker += n_written;
+ space_left -= n_written;
+
+ n_written = sprintf(marker, ", \"%.32s\"", manuf_id ? manuf_id : "");
+ marker += n_written;
+ space_left -= n_written;
- /* Create a read-write session so we can change the PIN. */
- if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|CKF_RW_SESSION,
- NULL, NULL, hdl)) != CKR_OK) {
- pk11_errno = rv;
- return (PK_ERR_PK11SESSION);
+ n_written = sprintf(marker, ", \"%.16s\"", serial_no ? serial_no : "");
+ marker += n_written;
+ space_left -= n_written;
+
+ /* space_left should always be >= 1 */
+}
+
+/*
+ * Find how many token objects with the given label.
+ */
+CK_RV
+find_obj_count(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label,
+ CK_ULONG *count)
+{
+ CK_RV rv = CKR_OK;
+ CK_ATTRIBUTE attrs[4] = {
+ { CKA_TOKEN, &pk_true, sizeof (pk_true) },
+ { 0, NULL, 0 },
+ { 0, NULL, 0 },
+ { 0, NULL, 0 }
+ };
+ CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
+ CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */
+ CK_OBJECT_CLASS obj_class;
+ CK_OBJECT_HANDLE tmp_obj;
+ CK_ULONG obj_count = 0;
+
+ cryptodebug("inside find_obj_count");
+
+ if (!session_opened || sess == NULL) {
+ cryptodebug("session handle is null");
+ return (CKR_SESSION_HANDLE_INVALID);
+ }
+
+ if (label) {
+ cryptodebug("object label was specified");
+ attrs[cur_attr].type = CKA_LABEL;
+ attrs[cur_attr].pValue = label;
+ attrs[cur_attr].ulValueLen = strlen((char *)label);
+ cur_attr++;
+ }
+
+ if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) {
+ cryptodebug("only searching for private objects");
+ attrs[cur_attr].type = CKA_PRIVATE;
+ attrs[cur_attr].pValue = &pk_true;
+ attrs[cur_attr].ulValueLen = sizeof (pk_true);
+ cur_attr++;
}
/*
- * If the token is newly created, there initial PIN will be "changme",
- * and all subsequent PKCS#11 calls will fail with CKR_PIN_EXPIRED,
- * but C_Login() will succeed.
+ * If "certs and all keys" is not specified, but at least either
+ * "certs" or some "keys" is specified, then go into this block.
+ * If all certs and keys were specified, there's no point in
+ * putting that fact in the attribute template -- leave that open,
+ * and all certs and keys will be matched automatically.
+ * In other words, only if at least one of 0x10,0x20,0x40,0x80
+ * bits is off, go into this code block.
+ *
+ * NOTE: For now, only one of cert or key types is allowed.
+ * This needs to change in the future.
*/
- if ((rv = C_Login(*hdl, CKU_USER, pin, pinlen)) != CKR_OK) {
- pk11_errno = rv;
- (void) C_CloseSession(*hdl);
- cryptodebug("C_Login returns %s", pkcs11_strerror(rv));
- if (rv == CKR_USER_PIN_NOT_INITIALIZED)
- return (PK_ERR_CHANGEPIN);
- return (PK_ERR_PK11LOGIN);
+ if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) &&
+ ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) {
+ if (obj_type & PK_CERT_OBJ) {
+ cryptodebug("only searching for certificates");
+ obj_class = CKO_CERTIFICATE;
+ } else if (obj_type & PK_PRIKEY_OBJ) {
+ cryptodebug("only searching for private keys");
+ obj_class = CKO_PRIVATE_KEY;
+ } else if (obj_type & PK_PUBKEY_OBJ) {
+ cryptodebug("only searching for public keys");
+ obj_class = CKO_PUBLIC_KEY;
+ } else if (obj_type & PK_SECKEY_OBJ) {
+ cryptodebug("only searching for secret keys");
+ obj_class = CKO_SECRET_KEY;
+ }
+
+ attrs[cur_attr].type = CKA_CLASS;
+ attrs[cur_attr].pValue = &obj_class;
+ attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS);
+ cur_attr++;
+ }
+
+ /*
+ * This can't happen now. When finding objects is enhanced in the
+ * future. this could lead to buffer overruns.
+ */
+ if (cur_attr > num_attrs)
+ cryptodebug("internal error: attr template overrun");
+
+ cryptodebug("calling C_FindObjectsInit");
+ if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK)
+ return (rv);
+
+ /* Look for the object, checking if there are more than one. */
+ cryptodebug("calling C_FindObjects");
+ for (*count = 0; /* empty */; (*count)++) {
+ if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) !=
+ CKR_OK)
+ break;
+
+ /* No more found. */
+ if (obj_count == 0)
+ break;
+ }
+
+ cryptodebug("%d matching objects found", *count);
+
+ cryptodebug("calling C_FindObjectsFinal");
+ (void) C_FindObjectsFinal(sess);
+ return (rv);
+}
+
+/*
+ * Find the token object with the given label.
+ */
+CK_RV
+find_objs(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label,
+ CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count)
+{
+ CK_RV rv = CKR_OK;
+ CK_ATTRIBUTE attrs[4] = {
+ { CKA_TOKEN, &pk_true, sizeof (pk_true) },
+ { 0, NULL, 0 },
+ { 0, NULL, 0 },
+ { 0, NULL, 0 }
+ };
+ CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
+ CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */
+ CK_OBJECT_CLASS obj_class;
+ CK_OBJECT_HANDLE tmp_obj;
+ CK_ULONG obj_count = 0;
+ int i;
+
+ cryptodebug("inside find_obj");
+
+ if ((rv = find_obj_count(sess, obj_type, label, count)) != CKR_OK)
+ return (rv);
+
+ if (*count == 0)
+ return (CKR_OK);
+
+ if ((*obj = (CK_OBJECT_HANDLE_PTR) malloc((*count) *
+ sizeof (CK_OBJECT_HANDLE))) == NULL) {
+ cryptodebug("no memory for found object");
+ return (CKR_HOST_MEMORY);
+ }
+
+ if (label) {
+ cryptodebug("object label was specified");
+ attrs[cur_attr].type = CKA_LABEL;
+ attrs[cur_attr].pValue = label;
+ attrs[cur_attr].ulValueLen = strlen((char *)label);
+ cur_attr++;
+ }
+
+ if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) {
+ cryptodebug("only searching for private objects");
+ attrs[cur_attr].type = CKA_PRIVATE;
+ attrs[cur_attr].pValue = &pk_true;
+ attrs[cur_attr].ulValueLen = sizeof (pk_true);
+ cur_attr++;
+ }
+
+ /*
+ * If "certs and all keys" is not specified, but at least either
+ * "certs" or some "keys" is specified, then go into this block.
+ * If all certs and keys were specified, there's no point in
+ * putting that fact in the attribute template -- leave that open,
+ * and all certs and keys will be matched automatically.
+ * In other words, only if at least one of 0x10,0x20,0x40,0x80
+ * bits is off, go into this code block.
+ *
+ * NOTE: For now, only one of cert or key types is allowed.
+ * This needs to change in the future.
+ */
+ if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) &&
+ ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) {
+ if (obj_type & PK_CERT_OBJ) {
+ cryptodebug("only searching for certificates");
+ obj_class = CKO_CERTIFICATE;
+ } else if (obj_type & PK_PRIKEY_OBJ) {
+ cryptodebug("only searching for private keys");
+ obj_class = CKO_PRIVATE_KEY;
+ } else if (obj_type & PK_PUBKEY_OBJ) {
+ cryptodebug("only searching for public keys");
+ obj_class = CKO_PUBLIC_KEY;
+ } else if (obj_type & PK_SECKEY_OBJ) {
+ cryptodebug("only searching for secret keys");
+ obj_class = CKO_SECRET_KEY;
+ }
+
+ attrs[cur_attr].type = CKA_CLASS;
+ attrs[cur_attr].pValue = &obj_class;
+ attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS);
+ cur_attr++;
+ }
+
+ /*
+ * This can't happen now. When finding objects is enhanced in the
+ * future. this could lead to buffer overruns.
+ */
+ if (cur_attr > num_attrs)
+ cryptodebug("internal error: attr template overrun");
+
+ cryptodebug("calling C_FindObjectsInit");
+ if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) {
+ free(*obj);
+ return (rv);
+ }
+
+ /*
+ * Find all the matching objects. The loop goes 1 more beyond
+ * the number of objects found to determine if any new objects
+ * were created since the time the object count was done.
+ */
+ cryptodebug("calling C_FindObjects");
+ for (i = 0; i < (*count) + 1; i++) {
+ if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) !=
+ CKR_OK)
+ break;
+
+ /* No more found. */
+ if (obj_count == 0)
+ break;
+
+ /*
+ * Save the object in the list being created, as long as
+ * we don't overrun the size of the list.
+ */
+ if (i < *count)
+ (*obj)[i] = tmp_obj;
+ else
+ cryptodebug("number of objects changed since last count");
+ }
+
+ if (rv != CKR_OK) {
+ free(*obj);
+ } else {
+ /*
+ * There are three cases to handle: (1) fewer objects were
+ * found than originally counted => change *count to the
+ * smaller number; (2) the number of objects found matches
+ * the number originally counted => do nothing; (3) more
+ * objects found than originally counted => list passed
+ * in is too small to contain the extra object(s), flag
+ * that in the debug output but don't change number of
+ * objects returned. The caller can double-check by
+ * calling find_obj_count() after this function to make
+ * sure the numbers match, if desired.
+ */
+ /* Case 1: Fewer objects. */
+ if (i < *count) {
+ cryptodebug("%d objects found, expected %d", i, *count);
+ *count = i;
+ /* Case 3: More objects. */
+ } else if (i > *count) {
+ cryptodebug("at least %d objects found, expected %d",
+ i, *count);
+ }
+ /*
+ * Case 2: Same number of objects.
+ *
+ * else if (i == *count)
+ * ;
+ */
+ }
+
+ cryptodebug("calling C_FindObjectsFinal");
+ (void) C_FindObjectsFinal(sess);
+ return (rv);
+}
+
+char *
+class_str(CK_OBJECT_CLASS class)
+{
+ switch (class) {
+ case CKO_DATA: return (gettext("data"));
+ case CKO_CERTIFICATE: return (gettext("certificate"));
+ case CKO_PUBLIC_KEY: return (gettext("public key"));
+ case CKO_PRIVATE_KEY: return (gettext("private key"));
+ case CKO_SECRET_KEY: return (gettext("secret key"));
+ case CKO_DOMAIN_PARAMETERS: return (gettext("domain parameter"));
+ default: return (gettext("unknown object"));
+ }
+}
+
+char *
+keytype_str(CK_KEY_TYPE keytype)
+{
+ switch (keytype) {
+ case CKK_RSA: return (gettext("RSA"));
+ case CKK_DSA: return (gettext("DSA"));
+ case CKK_DH: return (gettext("Diffie-Hellman"));
+ case CKK_X9_42_DH: return (gettext("X9.42 Diffie-Hellman"));
+ case CKK_GENERIC_SECRET: return (gettext("generic"));
+ case CKK_RC2: return (gettext("RC2"));
+ case CKK_RC4: return (gettext("RC4"));
+ case CKK_DES: return (gettext("DES"));
+ case CKK_DES2: return (gettext("Double-DES"));
+ case CKK_DES3: return (gettext("Triple-DES"));
+ case CKK_RC5: return (gettext("RC5"));
+ case CKK_AES: return (gettext("AES"));
+ default: return (gettext("typeless"));
}
+}
- return (PK_ERR_NONE);
+char *
+attr_str(CK_ATTRIBUTE_TYPE attrtype)
+{
+ switch (attrtype) {
+ case CKA_PRIVATE: return (gettext("private"));
+ case CKA_LOCAL: return (gettext("local"));
+ case CKA_SENSITIVE: return (gettext("sensitive"));
+ case CKA_EXTRACTABLE: return (gettext("extractable"));
+ case CKA_ENCRYPT: return (gettext("encrypt"));
+ case CKA_DECRYPT: return (gettext("decrypt"));
+ case CKA_WRAP: return (gettext("wrap"));
+ case CKA_UNWRAP: return (gettext("unwrap"));
+ case CKA_SIGN: return (gettext("sign"));
+ case CKA_SIGN_RECOVER: return (gettext("sign-recover"));
+ case CKA_VERIFY: return (gettext("verify"));
+ case CKA_VERIFY_RECOVER: return (gettext("verify-recover"));
+ case CKA_DERIVE: return (gettext("derive"));
+ case CKA_ALWAYS_SENSITIVE: return (gettext("always sensitive"));
+ case CKA_NEVER_EXTRACTABLE: return (gettext("never extractable"));
+ default: return (gettext("unknown capability"));
+ }
}
/*
- * Log out of the token and close the session.
+ * Convert a byte string into a string of octets formatted like this:
+ * oo oo oo oo oo ... oo
+ * where each "oo" is an octet is space separated and in the form:
+ * [0-f][0-f] if the octet is a non-printable character
+ * <space><char> if the octet is a printable character
+ *
+ * Note: octets_sz must be 3 * str_sz + 1, or at least as long as "blank"
*/
void
-logout_token(CK_SESSION_HANDLE hdl)
+octetify(CK_BYTE *str, CK_ULONG str_sz, char *octets, int octets_sz,
+ boolean_t stop_on_nul, boolean_t do_ascii, int limit, char *indent,
+ char *blank)
{
- cryptodebug("inside logout_token");
+ char *marker;
+ int nc;
+ int newline;
+ int indent_len;
+ boolean_t first = B_TRUE;
+
+ cryptodebug("inside octetify");
+
+ cryptodebug(stop_on_nul ? "stopping on first nul found" :
+ "continuing to full length of buffer");
+ cryptodebug(do_ascii ? "using ascii chars where printable" :
+ "using only hex octets");
+ cryptodebug("every %d characters indent with \"%s\"\n ", limit, indent);
+ cryptodebug("return \"%s\" if buffer is null or empty", blank);
- if (hdl) {
- (void) C_Logout(hdl);
- (void) C_CloseSession(hdl);
+ /* If string is empty, write as much of the blank string and leave. */
+ if (str_sz == 0) {
+ (void) snprintf(octets, octets_sz, "%s", blank);
+ return;
}
- (void) C_Finalize(NULL);
+
+ /* If only limit or indent is set, pick default for the other. */
+ if (limit > 0 && indent == NULL)
+ indent = "\n";
+ if (indent != NULL && limit == 0)
+ limit = 60;
+ indent_len = strlen(indent);
+
+ for (marker = octets, newline = 0, first = B_TRUE;
+ (stop_on_nul && *str != '\0') ||
+ (!stop_on_nul && str_sz > 0 && octets_sz > 0);
+ str++, str_sz--, marker += nc, octets_sz -= nc) {
+ if (!first) {
+ if (limit > 0 && ((marker - octets) / limit) >
+ newline) {
+ nc = snprintf(marker, indent_len, "%s", indent);
+ newline++;
+ continue;
+ }
+ nc = sprintf(marker,
+ ((do_ascii && isprint(*str) && !isspace(*str)) ?
+ "%s%c" : "%s%02x"), (do_ascii ? " " : ":"), *str);
+ } else {
+ nc = sprintf(marker,
+ ((do_ascii && isprint(*str) && !isspace(*str)) ?
+ "%c" : "%02x"), *str);
+ first = B_FALSE;
+ }
+ }
+ *marker = '\0';
+}
+
+/*
+ * Copies a biginteger_t to a template attribute.
+ * Should be a macro instead of a function.
+ */
+void
+copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr)
+{
+ attr->pValue = big.big_value;
+ attr->ulValueLen = big.big_value_len;
+}
+
+/*
+ * Copies a string and its length to a template attribute.
+ * Should be a macro instead of a function.
+ */
+void
+copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, CK_ATTRIBUTE_PTR attr)
+{
+ attr->pValue = buf;
+ attr->ulValueLen = buflen;
+}
+
+/*
+ * Copies a template attribute to a biginteger_t.
+ * Should be a macro instead of a function.
+ */
+void
+copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big)
+{
+ big->big_value = attr->pValue;
+ big->big_value_len = attr->ulValueLen;
+}
+
+/*
+ * Copies a template attribute to a string and its length.
+ * Should be a macro instead of a function.
+ */
+void
+copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, CK_ULONG *buflen)
+{
+ *buf = attr->pValue;
+ *buflen = attr->ulValueLen;
+}
+
+/*
+ * Copies a template attribute to a date and its length.
+ * Should be a macro instead of a function.
+ */
+void
+copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, CK_ULONG *buflen)
+{
+ *buf = (CK_DATE *)attr->pValue;
+ *buflen = attr->ulValueLen;
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/common.h b/usr/src/cmd/cmd-crypto/pktool/common.h
index 68abed5dd6..e725bcb83d 100644
--- a/usr/src/cmd/cmd-crypto/pktool/common.h
+++ b/usr/src/cmd/cmd-crypto/pktool/common.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,38 +39,90 @@ extern "C" {
#endif
#include <cryptoutil.h>
+#include <biginteger.h>
/* I18N helpers. */
#include <libintl.h>
#include <locale.h>
+/* Defines used throughout */
+#define FULL_NAME_LEN 91 /* See full_token_name() for this number. */
+
/* Error codes */
#define PK_ERR_NONE 0
#define PK_ERR_USAGE 1
#define PK_ERR_QUIT 2
-#define PK_ERR_PK11INIT 3
-#define PK_ERR_PK11SLOTS 4
-#define PK_ERR_PK11SESSION 5
-#define PK_ERR_PK11LOGIN 6
-#define PK_ERR_PK11SETPIN 7
-#define PK_ERR_NOSLOTS 8
-#define PK_ERR_NOMEMORY 9
-#define PK_ERR_NOTFOUND 10
-#define PK_ERR_PASSPHRASE 11
-#define PK_ERR_NEWPIN 12
-#define PK_ERR_PINCONFIRM 13
-#define PK_ERR_PINMATCH 14
-#define PK_ERR_CHANGEPIN 15
-
-extern int pk11_errno;
-
-extern int get_password(char *prompt, char **password);
-extern int init_pk11(void);
-extern int find_token_slot(char *token_name, char *manuf_id,
+#define PK_ERR_PK11 3
+#define PK_ERR_SYSTEM 4
+#define PK_ERR_OPENSSL 5
+
+/* Types of objects for searches. */
+#define PK_PRIVATE_OBJ 0x0001
+#define PK_PUBLIC_OBJ 0x0002
+#define PK_CERT_OBJ 0x0010
+#define PK_PRIKEY_OBJ 0x0020
+#define PK_PUBKEY_OBJ 0x0040
+#define PK_SECKEY_OBJ 0x0080
+
+#define PK_KEY_OBJ (PK_PRIKEY_OBJ|PK_PUBKEY_OBJ|PK_SECKEY_OBJ)
+#define PK_ALL_OBJ (PK_PRIVATE_OBJ|PK_PUBLIC_OBJ|\
+ PK_CERT_OBJ|PK_KEY_OBJ)
+
+/* Constants for attribute templates. */
+extern CK_BBOOL pk_false;
+extern CK_BBOOL pk_true;
+
+
+/* Common functions. */
+extern CK_RV init_pk11(void);
+extern void final_pk11(CK_SESSION_HANDLE sess);
+
+extern CK_RV open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags,
+ CK_SESSION_HANDLE_PTR sess);
+extern void close_sess(CK_SESSION_HANDLE sess);
+
+extern CK_RV login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin,
+ CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess);
+extern void logout_token(CK_SESSION_HANDLE sess);
+
+extern CK_RV quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags,
+ CK_UTF8CHAR_PTR pin, CK_ULONG pinlen,
+ CK_SESSION_HANDLE_PTR sess);
+extern void quick_finish(CK_SESSION_HANDLE sess);
+
+extern CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin,
+ CK_ULONG *pinlen);
+extern boolean_t yesno(char *prompt, char *invalid, boolean_t dflt);
+
+extern CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list,
+ CK_ULONG *slot_count);
+extern CK_RV find_token_slot(char *token_name, char *manuf_id,
char *serial_no, CK_SLOT_ID *slot_id, CK_FLAGS *pin_state);
-extern int login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin,
- CK_ULONG pinlen, CK_SESSION_HANDLE_PTR hdl);
-extern void logout_token(CK_SESSION_HANDLE hdl);
+
+extern CK_RV find_obj_count(CK_SESSION_HANDLE sess, int obj_type,
+ CK_BYTE *label, CK_ULONG *count);
+extern CK_RV find_objs(CK_SESSION_HANDLE sess, int obj_type,
+ CK_BYTE *label, CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count);
+
+extern void full_token_name(char *token, char *manuf, char *serial,
+ char *buf);
+
+extern char *class_str(CK_OBJECT_CLASS class);
+extern char *keytype_str(CK_KEY_TYPE keytype);
+extern char *attr_str(CK_ATTRIBUTE_TYPE attrtype);
+
+extern void octetify(CK_BYTE *str, CK_ULONG str_sz, char *oct, int oct_sz,
+ boolean_t stop_on_nul, boolean_t do_ascii, int limit,
+ char *indent, char *blank);
+
+extern void copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr);
+extern void copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen,
+ CK_ATTRIBUTE_PTR attr);
+extern void copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big);
+extern void copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf,
+ CK_ULONG *buflen);
+extern void copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf,
+ CK_ULONG *buflen);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/delete.c b/usr/src/cmd/cmd-crypto/pktool/delete.c
new file mode 100644
index 0000000000..ca8bbf3c50
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/delete.c
@@ -0,0 +1,227 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements the token object delete operation for this tool.
+ * It loads the PKCS#11 modules, finds the object to delete, deletes it,
+ * and cleans up. User must be R/W logged into the token.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+
+/*
+ * Delete token objects.
+ */
+int
+pk_delete(int argc, char *argv[])
+{
+ int opt;
+ extern int optind;
+ extern char *optarg;
+ char *token_name = NULL;
+ char *manuf_id = NULL;
+ char *serial_no = NULL;
+ char full_name[FULL_NAME_LEN];
+ boolean_t public_objs = B_FALSE;
+ boolean_t private_objs = B_FALSE;
+ CK_BYTE *object_label = NULL;
+ int obj_type = 0x00;
+ CK_SLOT_ID slot_id;
+ CK_FLAGS pin_state;
+ CK_UTF8CHAR_PTR pin = NULL;
+ CK_ULONG pinlen = 0;
+ CK_SESSION_HANDLE sess;
+ CK_OBJECT_HANDLE *objs;
+ CK_ULONG num_objs;
+ CK_ATTRIBUTE label = { CKA_LABEL, NULL, 0 };
+ CK_RV rv = CKR_OK;
+ int i;
+
+ cryptodebug("inside pk_delete");
+
+ /* Parse command line options. Do NOT i18n/l10n. */
+ while ((opt = getopt(argc, argv, "p(private)P(public)l:(label)")) !=
+ EOF) {
+ switch (opt) {
+ case 'p': /* private objects */
+ private_objs = B_TRUE;
+ obj_type |= PK_PRIVATE_OBJ;
+ break;
+ case 'P': /* public objects */
+ public_objs = B_TRUE;
+ obj_type |= PK_PUBLIC_OBJ;
+ break;
+ case 'l': /* objects with specific label */
+ if (object_label)
+ return (PK_ERR_USAGE);
+ object_label = (CK_BYTE *)optarg;
+ break;
+ default:
+ return (PK_ERR_USAGE);
+ break;
+ }
+ }
+
+ /* At least one of public, private, or object label is required. */
+ if (!private_objs && !public_objs && object_label == NULL)
+ return (PK_ERR_USAGE);
+
+ /*
+ * If object label is given but neither public/private is specified,
+ * delete all objects with that label.
+ */
+ if (!private_objs && !public_objs && object_label != NULL)
+ obj_type = PK_ALL_OBJ;
+
+ /* No additional args allowed. */
+ argc -= optind;
+ argv += optind;
+ if (argc)
+ return (PK_ERR_USAGE);
+ /* Done parsing command line options. */
+
+ /* Delete operation only supported on softtoken. */
+ if (token_name == NULL)
+ token_name = SOFT_TOKEN_LABEL;
+ if (manuf_id == NULL)
+ manuf_id = SOFT_MANUFACTURER_ID;
+ if (serial_no == NULL)
+ serial_no = SOFT_TOKEN_SERIAL;
+ full_token_name(token_name, manuf_id, serial_no, full_name);
+
+ /* Find the slot with token. */
+ if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
+ &pin_state)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to find token %s (%s)."), full_name,
+ pkcs11_strerror(rv));
+ return (PK_ERR_PK11);
+ }
+
+ /* Always get the user's PIN for delete operations. */
+ if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
+ &pinlen)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get token passphrase (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(NULL);
+ return (PK_ERR_PK11);
+ }
+
+ /* Log the user R/W into the token. */
+ if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to log into token (%s)."), pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ /* Find the object(s) with the given label and/or type. */
+ if ((rv = find_objs(sess, obj_type, object_label, &objs, &num_objs)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to find token objects (%s)."), pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ if (num_objs == 0) {
+ (void) fprintf(stdout, gettext("No matching objects found.\n"));
+ quick_finish(sess);
+ return (0);
+ }
+
+ if (num_objs != 1) {
+ (void) fprintf(stdout, gettext(
+ "Warning: %d matching objects found, deleting all.\n"),
+ num_objs);
+ if (yesno(gettext("Continue with delete? "),
+ gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
+ quick_finish(sess);
+ return (0);
+ }
+ }
+
+ /* Destroy the objects if found. */
+ for (i = 0; i < num_objs; i++) {
+ /*
+ * To give nice feedback to the user, get the object's
+ * label before deleting it.
+ */
+ cryptodebug("calling C_GetAttributeValue for label");
+ label.pValue = NULL;
+ label.ulValueLen = 0;
+ if (C_GetAttributeValue(sess, objs[i], &label, 1) == CKR_OK) {
+ if (label.ulValueLen != (CK_ULONG)-1 &&
+ label.ulValueLen != 0 &&
+ (label.pValue = malloc(label.ulValueLen)) != NULL) {
+ if (C_GetAttributeValue(sess, objs[i], &label,
+ 1) != CKR_OK) {
+ free(label.pValue);
+ label.pValue = NULL;
+ label.ulValueLen = 0;
+ }
+ } else {
+ label.ulValueLen = 0;
+ }
+ }
+
+ cryptodebug("calling C_DestroyObject");
+ if ((rv = C_DestroyObject(sess, objs[i])) != CKR_OK) {
+ if (label.pValue != NULL)
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to delete object #%d \"%.*s\" "
+ "(%s)."), i+1, label.ulValueLen,
+ label.pValue, pkcs11_strerror(rv));
+ else
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to delete object #%d (%s)."),
+ i+1, pkcs11_strerror(rv));
+ } else {
+ if (label.pValue != NULL)
+ (void) fprintf(stdout, gettext("Object #%d "
+ "\"%.*s\" successfully deleted.\n"),
+ i+1, label.ulValueLen, label.pValue);
+ else
+ (void) fprintf(stdout, gettext(
+ "Object #%d successfully deleted.\n"), i+1);
+ }
+
+ if (label.pValue != NULL)
+ free(label.pValue);
+ }
+
+ /* Clean up. */
+ quick_finish(sess);
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/derparse.c b/usr/src/cmd/cmd-crypto/pktool/derparse.c
new file mode 100644
index 0000000000..cec607220a
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/derparse.c
@@ -0,0 +1,371 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * derparse.c - Functions for parsing DER-encoded data
+ *
+ * NOTE: This code was originally written by Cryptographic Products
+ * Group at Sun Microsystems for the SCA 1000 "realmparse" program.
+ * It is mostly intact except for necessary adaptaions to allow it to
+ * compile in this environment.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <lber.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <cryptoutil.h>
+#include "derparse.h"
+
+/* I18N helpers. */
+#include <libintl.h>
+#include <locale.h>
+
+/*
+ * Some types that we need below.
+ */
+typedef struct oidinfo {
+ uint8_t *value; /* OID value in bytes */
+ size_t length; /* Length of OID */
+ char *strval; /* String rep. for OID in RDN */
+} oidinfo_t;
+
+/*
+ * X.509 Issuer OIDs as recommended by RFC 3280
+ * We might see these in certificates in their subject an issuer names.
+ */
+static uint8_t common_name_oid[] = {0x55, 0x04, 0x03};
+static uint8_t surname_oid[] = {0x55, 0x04, 0x04};
+static uint8_t serial_number_oid[] = {0x55, 0x04, 0x05};
+static uint8_t country_name_oid[] = {0x55, 0x04, 0x06};
+static uint8_t locality_name_oid[] = {0x55, 0x04, 0x07};
+static uint8_t state_name_oid[] = {0x55, 0x04, 0x08};
+static uint8_t org_name_oid[] = {0x55, 0x04, 0x0a};
+static uint8_t org_unit_name_oid[] = {0x55, 0x04, 0x0b};
+static uint8_t title_oid[] = {0x55, 0x04, 0x0c};
+static uint8_t name_oid[] = {0x55, 0x04, 0x29};
+static uint8_t given_name_oid[] = {0x55, 0x04, 0x2a};
+static uint8_t initials_oid[] = {0x55, 0x04, 0x2b};
+static uint8_t gen_qual_oid[] = {0x55, 0x04, 0x2c};
+static uint8_t dn_qual_oid[] = {0x55, 0x04, 0x2e};
+static uint8_t pseudonym_oid[] = {0x55, 0x04, 0x31};
+static uint8_t uid_oid[] =
+ {0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x01};
+static uint8_t domain_comp_oid[] =
+ {0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19};
+static uint8_t email_addr_oid[] =
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01};
+
+/* Define this structure so we can match on a given oid */
+static oidinfo_t oids[] = {
+ {common_name_oid, sizeof (common_name_oid), "CN"},
+ {surname_oid, sizeof (surname_oid), "SN"},
+ {serial_number_oid, sizeof (serial_number_oid), "SerialNum"},
+ {country_name_oid, sizeof (country_name_oid), "C"},
+ {locality_name_oid, sizeof (locality_name_oid), "L"},
+ {state_name_oid, sizeof (state_name_oid), "ST"},
+ {org_name_oid, sizeof (org_name_oid), "O"},
+ {org_unit_name_oid, sizeof (org_unit_name_oid), "OU"},
+ {title_oid, sizeof (title_oid), "Title"},
+ {name_oid, sizeof (name_oid), "Name"},
+ {given_name_oid, sizeof (given_name_oid), "GN"},
+ {initials_oid, sizeof (initials_oid), "Initials"},
+ {gen_qual_oid, sizeof (gen_qual_oid), "GenQual"},
+ {dn_qual_oid, sizeof (dn_qual_oid), "DNQual"},
+ {pseudonym_oid, sizeof (pseudonym_oid), "Pseudonym"},
+ {uid_oid, sizeof (uid_oid), "UID"},
+ {domain_comp_oid, sizeof (domain_comp_oid), "DC"},
+ {email_addr_oid, sizeof (email_addr_oid), "E"}
+};
+static int oidblocklen = sizeof (oids) / sizeof (oidinfo_t);
+
+/* Local functions */
+static int oid_to_str(uint8_t *, size_t, char *, size_t);
+static int get_oid_type(char *);
+
+/*
+ * An RDNSequence is what is handed to us when we get attributes like
+ * CKA_ISSUER and CKA_SUBJECT_NAME. This function will take in a buffer
+ * with the DER encoded bytes of an RDNSequence and print out the components.
+ *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue
+ * }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+void
+rdnseq_to_str(uchar_t *derdata, size_t dersz, char *out, size_t outsz)
+{
+#define PKTOOL_LINEMAX 1024
+ char oidout[PKTOOL_LINEMAX];
+ BerElement *ber = NULL;
+ BerValue ber_rdns;
+ int tag;
+ ber_len_t size;
+ char *atv_type = NULL; /* Attribute Type */
+ ber_len_t atv_type_size;
+ char *atv_value = NULL; /* Attribute Value */
+ ber_len_t atv_value_size;
+ char *cookie = NULL;
+ int idx;
+ char *prndata = NULL;
+ int prnsz;
+ int offset = 0;
+ boolean_t first = B_TRUE;
+
+ cryptodebug("inside rdnseq_to_str");
+
+ if (derdata == NULL || dersz == 0) {
+ cryptodebug("nothing to parse");
+ return;
+ }
+
+ /* Take the raw bytes and stuff them into a BerValue structure */
+ ber_rdns.bv_val = (char *)derdata;
+ ber_rdns.bv_len = dersz;
+
+ /* Allocate the BerElement */
+ if ((ber = ber_init(&ber_rdns)) == NULLBER) {
+ cryptodebug("ber_init failed to return ber element");
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to begin parsing RDNSequence."));
+ return;
+ }
+
+ /* Begin by parsing out the outer sequence */
+ tag = ber_next_element(ber, &size, cookie);
+ if (tag != LBER_SEQUENCE) {
+ cryptodebug("ber_next_element tag is not SEQUENCE");
+ cryptoerror(LOG_STDERR, gettext(
+ "Expected RDNSequence SEQUENCE object, got tag [%02x]."),
+ tag);
+ return;
+ }
+ tag = ber_scanf(ber, "{");
+
+ /* Parse the sequence of RelativeDistinguishedName objects */
+ while ((tag = ber_next_element(ber, &size, cookie)) != -1) {
+ if (tag != LBER_SET) {
+ cryptodebug("ber_next_element tag is not SET");
+ cryptoerror(LOG_STDERR, gettext(
+ "Expected RelativeDistinguishedName SET object, "
+ "got tag [%02x]."), tag);
+ return;
+ }
+ tag = ber_scanf(ber, "[");
+
+ /* AttributeTypeAndValue */
+ tag = ber_next_element(ber, &size, cookie);
+ if (tag != LBER_SEQUENCE) {
+ cryptodebug("ber_next_element tag is not SEQUENCE");
+ cryptoerror(LOG_STDERR, gettext(
+ "Expected AttributeTypeAndValue SEQUENCE object, "
+ "got tag [%02x]."), tag);
+ return;
+ }
+ tag = ber_scanf(ber, "{");
+
+ /* AttributeType OID */
+ tag = ber_next_element(ber, &atv_type_size, cookie);
+ atv_type_size++; /* Add room for null terminator */
+ if (tag != LBER_OID) {
+ cryptodebug("ber_next_element tag is not OID");
+ cryptoerror(LOG_STDERR, gettext(
+ "Expected an OID, got tag [%02x]."), tag);
+ return;
+ }
+ /* Note: ber_scanf() allocates memory here for "a". */
+ tag = ber_scanf(ber, "a", &atv_type, &atv_type_size);
+
+ /* AttributeValue */
+ tag = ber_next_element(ber, &atv_value_size, cookie);
+ atv_value_size++;
+ if ((tag != LBER_PRINTABLE_STRING) && (tag != LBER_IA5STRING)) {
+ cryptodebug("ber_next_element tag is not "
+ "PRINTABLE_STRING/IA5STRING");
+ cryptoerror(LOG_STDERR, gettext("Expected a STRING, "
+ "got tag [%02x]."), tag);
+ free(atv_type);
+ return;
+ }
+ /* Note: ber_scanf() allocates memory here for "a". */
+ tag = ber_scanf(ber, "a", &atv_value, &atv_value_size);
+
+ /*
+ * Now go and turn the attribute type and value into
+ * some kind of meaningful output.
+ */
+ if ((idx = get_oid_type(atv_type)) == -1) {
+ if (oid_to_str((uint8_t *)atv_type, strlen(atv_type),
+ oidout, sizeof (oidout)) < 0) {
+ cryptodebug("oid_to_str failed");
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert OID to string."));
+ free(atv_type);
+ free(atv_value);
+ return;
+ }
+ prndata = oidout;
+ } else {
+ prndata = oids[idx].strval;
+ }
+
+ if (!first)
+ prnsz = snprintf(out + offset, outsz - offset,
+ ", %s = %s", prndata, atv_value);
+ else {
+ prnsz = snprintf(out + offset, outsz - offset,
+ "%s = %s", prndata, atv_value);
+ first = B_FALSE;
+ }
+
+ free(atv_type);
+ free(atv_value);
+ atv_type = NULL;
+ atv_value = NULL;
+
+ offset += prnsz;
+ if (offset >= outsz)
+ break;
+ }
+}
+
+/*
+ * Convert OID to dotted notation string.
+ */
+static int
+oid_to_str(uint8_t *oid, size_t oidlen, char *oidout, size_t oidout_len)
+{
+ int count = 0;
+ int offset = 0;
+ int prnsz;
+ uint_t firstnum;
+ uint_t secondnum;
+ uint64_t nextnum = 0;
+
+ cryptodebug("inside oid_to_str");
+
+ if (oidlen == 0)
+ return (-1);
+
+ /*
+ * The first octet has a value of (40 x oidnum1) + oidnum2. We
+ * will deconstruct it here and sanity check the result. According
+ * to X.690, oidnum1 should never be more than 2 and oidnum2
+ * shouldn't be greater than 39 when oidnum1 = 0 or 1.
+ */
+ firstnum = oid[count] / 40;
+ if (firstnum > 2) /* force remainder to be > 39 */
+ firstnum = 2;
+ secondnum = oid[count] - (firstnum * 40);
+
+ (void) memset(oidout, 0, oidout_len);
+
+ prnsz = snprintf(oidout, oidout_len, "%d.%d", firstnum, secondnum);
+ offset += prnsz;
+ if (offset >= oidout_len)
+ return (0);
+
+ /* Start at the second byte and move our way forward */
+ for (count = 1; count < oidlen; count++) {
+ /* ORIGINAL COMMENT */
+ /*
+ * Each oid byte is taken as a 7-bit number. If bit 8 is
+ * set, it means the next octet and this one are to be
+ * chained together as a single bit string, and so forth.
+ * We need to mask of bit 8, then shift over 7 bits in the
+ * resulting integer, and then stuff the new 7 bits in
+ * the low order byte, all the while making sure we don't
+ * stomp bit 1 from the previous octet.
+ * See X.690 or the layman's guide to ASN.1 for more.
+ */
+
+ /*
+ * String together as many of the next octets if each of
+ * their high order bits is set to 1. For example,
+ * 1 1010111, 1 0010100, 1 0010110, 0 1101111, ...
+ * (3 8-bit octets)
+ * becomes
+ * 1010111 0010100 0010110, 1101111, ...
+ * (one 21 bit integer)
+ * The high order bit functions as a "link" between octets.
+ * Note that if there are more than 9 octets with their
+ * high order bits set, it will overflow a 64-bit integer.
+ */
+ for (nextnum = 0; (oid[count] & 0x80) && (count < oidlen);
+ count++) {
+ nextnum <<= 7;
+ nextnum |= (oid[count] & 0x7f);
+ }
+ if (count == oidlen) /* last number not terminated? */
+ return (-1);
+
+ /* We're done with this oid number, write it and move on */
+ prnsz = snprintf(oidout + offset, oidout_len - offset,
+ ".%lld", nextnum);
+ offset += prnsz;
+ if (offset >= oidout_len)
+ return (0);
+ }
+
+ return (0);
+}
+
+/*
+ * Returns the index in the oids[] array that matches the input type,
+ * or -1 if it could not find a match.
+ */
+static int
+get_oid_type(char *type)
+{
+ int count;
+
+ cryptodebug("inside get_oid_type");
+
+ for (count = 0; count < oidblocklen; count++) {
+ if (memcmp(oids[count].value, type, oids[count].length) == 0) {
+ return (count);
+ }
+ }
+
+ /* If we get here, we haven't found a match, so return -1 */
+ return (-1);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/derparse.h b/usr/src/cmd/cmd-crypto/pktool/derparse.h
new file mode 100644
index 0000000000..2ff36d2163
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/derparse.h
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PKTOOL_DERPARSE_H
+#define _PKTOOL_DERPARSE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef LBER_OID
+#define LBER_OID 0x06
+#endif
+
+#ifndef LBER_PRINTABLE_STRING
+#define LBER_PRINTABLE_STRING 0x13
+#endif
+
+#ifndef LBER_IA5STRING
+#define LBER_IA5STRING 0x16
+#endif
+
+extern void rdnseq_to_str(uchar_t *from, size_t from_sz, char *to,
+ size_t to_sz);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKTOOL_DERPARSE_H */
diff --git a/usr/src/cmd/cmd-crypto/pktool/export.c b/usr/src/cmd/cmd-crypto/pktool/export.c
new file mode 100644
index 0000000000..00a4b379fd
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/export.c
@@ -0,0 +1,1404 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements the export operation for this tool.
+ * The basic flow of the process is to find the soft token,
+ * log into it, find the PKCS#11 objects in the soft token
+ * to be exported matching keys with their certificates, export
+ * them to the PKCS#12 file encrypting them with a file password
+ * if desired, and log out.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+#include "biginteger.h"
+#include "osslcommon.h"
+#include "p12common.h"
+#include <openssl/pkcs12.h>
+
+/*
+ * Writes OpenSSL objects to PKCS#12 file. The PKCS#11 objects from
+ * the soft token need to be converted to OpenSSL structures prior
+ * to this call, since the PKCS#12 routines depend on that format.
+ * This code is patterned from OpenSSL apps that write PKCS#12 files.
+ *
+ * Note: it's not clear from the usage of all the functions here by
+ * OpenSSL apps whether these functions have return values or error
+ * conditions that can be checked. This function may benefit from
+ * a closer review at a later time.
+ */
+static int
+write_objs_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
+ CK_BYTE_PTR id, CK_ULONG id_len, EVP_PKEY *priv_key, X509 *cert,
+ STACK_OF(X509) *ca_certs, int *successes, int *failures)
+/* ARGSUSED */
+{
+ STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL;
+ PKCS12_SAFEBAG *bag = NULL;
+ X509 *ca = NULL;
+ PKCS7 *cert_authsafe = NULL;
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
+ PKCS7 *key_authsafe = NULL;
+ STACK_OF(PKCS7) *authsafe_stack = NULL;
+ PKCS12 *p12_elem = NULL;
+ unsigned char *lab = NULL;
+ int lab_len = 0;
+ int i;
+ int n_writes = 0;
+
+ cryptodebug("inside write_objs_pkcs12");
+
+ /* Do not reset *successes or *failures -- keep running totals. */
+
+ /* If there is nothing to write to the PKCS#12 file, leave. */
+ if (cert == NULL && ca_certs == NULL && priv_key == NULL) {
+ cryptodebug("nothing to write to export file");
+ return (0);
+ }
+
+ /*
+ * Section 1:
+ *
+ * The first PKCS#12 container (safebag) will hold the certificates
+ * associated with this key. The result of this section is a
+ * PIN-encrypted PKCS#7 container (authsafe). If there are no
+ * certificates, there is no point in creating the "safebag" or the
+ * "authsafe" so we go to the next section.
+ */
+ if (cert != NULL || ca_certs != NULL) {
+ /* Start a PKCS#12 safebag container for the certificates. */
+ cryptodebug("creating certificate PKCS#12 safebag");
+ bag_stack = sk_PKCS12_SAFEBAG_new_null();
+ if (bag_stack == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create PKCS#12 certificate bag."));
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Add the cert corresponding to private key to bag_stack. */
+ if (cert) {
+ /* Convert cert from X509 struct to PKCS#12 bag */
+ cryptodebug("adding certificate to PKCS#12 safebag");
+ bag = PKCS12_x5092certbag(cert);
+ if (bag == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert certificate to "
+ "PKCS#12 bag."));
+ /* Cleanup the safebag. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack,
+ PKCS12_SAFEBAG_free);
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Add the key id to the certificate bag. */
+ cryptodebug("add key id to PKCS#12 safebag");
+ if (!PKCS12_add_localkeyid(bag, id, id_len))
+ cryptodebug("error not caught");
+
+ /* Add the friendly name to the certificate bag. */
+ if ((lab = X509_alias_get0(cert, &lab_len)) != NULL) {
+ cryptodebug(
+ "label PKCS#12 safebag with friendly name");
+ if (!PKCS12_add_friendlyname(bag, (char *)lab,
+ lab_len))
+ cryptodebug("error not caught");
+ }
+
+ /* Pile it on the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag))
+ cryptodebug("error not caught");
+
+ n_writes++;
+ }
+
+ /* Add all the CA chain certs to the bag_stack. */
+ if (ca_certs) {
+ cryptodebug("adding CA certificate chain to PKCS#12 "
+ "safebag");
+ /*
+ * Go through the stack of CA certs, converting each
+ * one to a PKCS#12 bag and piling them onto the
+ * bag_stack.
+ */
+ for (i = 0; i < sk_X509_num(ca_certs); i++) {
+ /*
+ * sk_X509_value() is macro that embeds a
+ * cast to (X509 *). Here it translates
+ * into ((X509 *)sk_value((ca_certs), (i))).
+ * Lint is complaining about the embedded
+ * casting, and to fix it, you need to fix
+ * openssl header files.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ ca = sk_X509_value(ca_certs, i);
+
+ /* Convert CA cert to PKCS#12 bag. */
+ cryptodebug("adding CA certificate #%d "
+ "to PKCS#12 safebag", i+1);
+ bag = PKCS12_x5092certbag(ca);
+ if (bag == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert CA certificate "
+ "#%d to PKCS#12 bag."), i+1);
+ /* Cleanup the safebag. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack,
+ PKCS12_SAFEBAG_free);
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Note CA certs do not have friendly name. */
+
+ /* Pile it onto the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag))
+ cryptodebug("error not caught");
+
+ n_writes++;
+ }
+ }
+
+ /* Turn bag_stack of certs into encrypted authsafe. */
+ cryptodebug("encrypt certificate PKCS#12 bag into "
+ "PKCS#7 authsafe");
+ cert_authsafe = PKCS12_pack_p7encdata(
+ NID_pbe_WithSHA1And40BitRC2_CBC, (char *)pin, -1, NULL,
+ 0, PKCS12_DEFAULT_ITER, bag_stack);
+
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ bag_stack = NULL;
+
+ if (cert_authsafe == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to PKCS#7-encrypt certificate bag."));
+ (*failures)++;
+ return (-1);
+ }
+ }
+
+ /*
+ * Section 2:
+ *
+ * The second PKCS#12 container (safebag) will hold the private key
+ * that goes with the certificates above. The results of this section
+ * is an unencrypted PKCS#7 container (authsafe). If there is no
+ * private key, there is no point in creating the "safebag" or the
+ * "authsafe" so we go to the next section.
+ */
+ if (priv_key != NULL) {
+ /* Make a PKCS#8 shrouded key bag. */
+ cryptodebug("create PKCS#8 shrouded key out of private key");
+ p8 = EVP_PKEY2PKCS8(priv_key);
+ if (p8 == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create PKCS#8 shrouded key for "
+ "private key."));
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Put the shrouded key into a PKCS#12 bag. */
+ cryptodebug("convert shrouded key to PKCS#12 bag");
+ bag = PKCS12_MAKE_SHKEYBAG(
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC, (char *)pin,
+ -1, NULL, 0, PKCS12_DEFAULT_ITER, p8);
+
+ /* Clean up the PKCS#8 shrouded key, don't need it now. */
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ p8 = NULL;
+
+ if (bag == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert private key to PKCS#12 bag."));
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Add the key id to the certificate bag. */
+ cryptodebug("add key id to PKCS#12 safebag");
+ if (!PKCS12_add_localkeyid(bag, id, id_len))
+ cryptodebug("error not caught");
+
+ /* Add the cert friendly name to the private key bag. */
+ if (lab != NULL) {
+ cryptodebug("label PKCS#12 safebag with friendly name");
+ if (!PKCS12_add_friendlyname(bag, (char *)lab, lab_len))
+ cryptodebug("error not caught");
+ }
+
+ /* Start a PKCS#12 safebag container for the private key. */
+ cryptodebug("creating private key PKCS#12 safebag");
+ bag_stack = sk_PKCS12_SAFEBAG_new_null();
+ if (bag_stack == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create PKCS#12 private key bag."));
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Pile on the private key on the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag))
+ cryptodebug("error not caught");
+
+ /* Turn bag_stack with private key into unencrypted authsafe. */
+ cryptodebug("put private PKCS#12 bag into PKCS#7 authsafe");
+ key_authsafe = PKCS12_pack_p7data(bag_stack);
+
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ bag_stack = NULL;
+
+ if (key_authsafe == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to PKCS#7-convert private key bag."));
+ (*failures)++;
+ return (-1);
+ }
+
+ n_writes++;
+ }
+
+ /*
+ * Section 3:
+ *
+ * This is where the two PKCS#7 containers, one for the certificates
+ * and one for the private key, are put together into a PKCS#12
+ * element. This final PKCS#12 element is written to the export file.
+ */
+ /* Start a PKCS#7 stack. */
+ cryptodebug("create PKCS#7 authsafe for private key and certificates");
+ authsafe_stack = sk_PKCS7_new_null();
+ if (authsafe_stack == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create PKCS#7 container for private key "
+ "and certificates."));
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Put certificates and private key into PKCS#7 stack. */
+ if (key_authsafe != NULL) {
+ cryptodebug("put private key authsafe into PKCS#7 container");
+ if (!sk_PKCS7_push(authsafe_stack, key_authsafe))
+ cryptodebug("error not caught");
+ }
+ if (cert_authsafe != NULL) {
+ cryptodebug("put certificate authsafe into PKCS#7 container");
+ if (!sk_PKCS7_push(authsafe_stack, cert_authsafe))
+ cryptodebug("error not caught");
+ }
+
+ /* Create PKCS#12 element out of PKCS#7 stack. */
+ cryptodebug("create PKCS#12 element for export file");
+ p12_elem = PKCS12_init(NID_pkcs7_data);
+ if (p12_elem == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create PKCS#12 element for export file."));
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ (*failures)++;
+ return (-1);
+ }
+
+ /* Put the PKCS#7 stack into the PKCS#12 element. */
+ if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack))
+ cryptodebug("error not caught");
+
+ /* Clear away the PKCS#7 stack, we're done with it. */
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ authsafe_stack = NULL;
+
+ /* Set the integrity MAC on the PKCS#12 element. */
+ cryptodebug("setting MAC for PKCS#12 element");
+ if (!PKCS12_set_mac(p12_elem, (char *)pin, -1, NULL, 0,
+ PKCS12_DEFAULT_ITER, NULL))
+ cryptodebug("error not caught");
+
+ /* Write the PKCS#12 element to the export file. */
+ cryptodebug("writing PKCS#12 element to export file");
+ if (!i2d_PKCS12_bio(fbio, p12_elem))
+ cryptodebug("error not caught");
+
+ (*successes) += n_writes;
+
+ /* Clear away the PKCS#12 element. */
+ PKCS12_free(p12_elem);
+ return (0);
+}
+
+/*
+ * Get token objects: private key, its cert, and its cert chain.
+ */
+static CK_RV
+get_token_objs(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj,
+ CK_OBJECT_HANDLE *mate, CK_OBJECT_HANDLE_PTR *chain,
+ CK_ULONG *chain_len, CK_BYTE_PTR *id, CK_ULONG *id_len)
+{
+ CK_RV rv = CKR_OK;
+ CK_ATTRIBUTE keyid_attr[1] = {
+ { CKA_ID, NULL, 0 }
+ };
+ static CK_OBJECT_CLASS class = CKO_CERTIFICATE;
+ static CK_CERTIFICATE_TYPE certtype = CKC_X_509;
+ CK_ATTRIBUTE cert_attr[4] = {
+ { CKA_CLASS, &class, sizeof (CK_OBJECT_CLASS) },
+ { CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) },
+ { CKA_TOKEN, &pk_true, sizeof (pk_true) },
+ { CKA_ID, NULL, 0 }
+ };
+ CK_ULONG num_attr = sizeof (cert_attr) / sizeof (CK_ATTRIBUTE);
+ CK_OBJECT_HANDLE cert = ~0UL;
+ CK_ULONG num = 0;
+
+ cryptodebug("inside get_token_objs");
+
+ /* Get the size of the object's CKA_ID field first. */
+ cryptodebug("getting CKA_ID size for object 0x%x", obj);
+ if ((rv = C_GetAttributeValue(sess, obj, keyid_attr, 1)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext("Unable to get size of object"
+ " key id (%s)."), pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate the space needed for the key id. */
+ if ((keyid_attr[0].pValue = malloc(keyid_attr[0].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Get the CKA_ID field to match obj with its cert. */
+ cryptodebug("getting CKA_ID attribute for object 0x%x", obj);
+ if ((rv = C_GetAttributeValue(sess, obj, keyid_attr, 1)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext("Unable to get object "
+ "key id (%s)."), pkcs11_strerror(rv));
+ free(keyid_attr[0].pValue);
+ return (rv);
+ }
+
+ /* Now try to find any certs that have the same id. */
+ cryptodebug("searching for certificates with same CKA_ID");
+ cert_attr[3].pValue = keyid_attr[0].pValue;
+ cert_attr[3].ulValueLen = keyid_attr[0].ulValueLen;
+ if ((rv = C_FindObjectsInit(sess, cert_attr, num_attr)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext("Unable to initialize "
+ "certificate search (%s)."), pkcs11_strerror(rv));
+ free(keyid_attr[0].pValue);
+ return (rv);
+ }
+
+ /* Find the first cert that matches the key id. */
+ if ((rv = C_FindObjects(sess, &cert, 1, &num)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext("Certificate search failed "
+ "(%s)."), pkcs11_strerror(rv));
+ free(keyid_attr[0].pValue);
+ return (rv);
+ }
+
+ (void) C_FindObjectsFinal(sess);
+
+ *id = keyid_attr[0].pValue;
+ *id_len = keyid_attr[0].ulValueLen;
+
+ *mate = (num == 1) ? cert : ~0UL;
+
+ /* We currently do not find all the certs in the chain. */
+ *chain_len = 0;
+ *chain = NULL;
+
+ return (CKR_OK);
+}
+
+/*
+ * Converts PKCS#11 biginteger_t format to OpenSSL BIGNUM.
+ * "to" should be the address of a ptr init'ed to NULL to
+ * receive the BIGNUM, e.g.,
+ * biginteger_t from;
+ * BIGNUM *foo = NULL;
+ * cvt_bigint2bn(&from, &foo);
+ */
+static int
+cvt_bigint2bn(biginteger_t *from, BIGNUM **to)
+{
+ BIGNUM *temp = NULL;
+
+ cryptodebug("inside cvt_bigint2bn");
+
+ if (from == NULL || to == NULL)
+ return (-1);
+
+ cryptodebug("calling BN_bin2bn");
+ if ((temp = BN_bin2bn(from->big_value, from->big_value_len, *to)) ==
+ NULL)
+ return (-1);
+
+ *to = temp;
+ return (0);
+}
+
+/*
+ * Convert PKCS#11 RSA private key to OpenSSL EVP_PKEY structure.
+ */
+static CK_RV
+cvt_rsa2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+{
+ CK_RV rv = CKR_OK;
+ EVP_PKEY *key = NULL; /* OpenSSL representation */
+ RSA *rsa = NULL; /* OpenSSL representation */
+ biginteger_t mod = { NULL, 0 }; /* required */
+ biginteger_t pubexp = { NULL, 0 }; /* required */
+ biginteger_t priexp = { NULL, 0 }; /* optional */
+ biginteger_t prime1 = { NULL, 0 }; /* optional */
+ biginteger_t prime2 = { NULL, 0 }; /* optional */
+ biginteger_t exp1 = { NULL, 0 }; /* optional */
+ biginteger_t exp2 = { NULL, 0 }; /* optional */
+ biginteger_t coef = { NULL, 0 }; /* optional */
+ CK_ATTRIBUTE rsa_pri_attrs[8] = {
+ { CKA_MODULUS, NULL, 0 },
+ { CKA_PUBLIC_EXPONENT, NULL, 0 },
+ { CKA_PRIVATE_EXPONENT, NULL, 0 }, /* optional */
+ { CKA_PRIME_1, NULL, 0 }, /* | */
+ { CKA_PRIME_2, NULL, 0 }, /* | */
+ { CKA_EXPONENT_1, NULL, 0 }, /* | */
+ { CKA_EXPONENT_2, NULL, 0 }, /* | */
+ { CKA_COEFFICIENT, NULL, 0 } /* V */
+ };
+ CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+
+ cryptodebug("inside cvt_rsa2evp_pkey");
+
+ cryptodebug("calling RSA_new");
+ if ((rsa = RSA_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to allocate internal RSA structure."));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, rsa_pri_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get RSA private key attribute sizes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ rsa_pri_attrs[i].ulValueLen == 0) {
+ cryptodebug("cvt_rsa2evp_pkey: *** should not happen");
+ rsa_pri_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((rsa_pri_attrs[i].pValue =
+ malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ return (CKR_HOST_MEMORY);
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, rsa_pri_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get RSA private key attributes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /*
+ * Fill in all the temp variables. Modulus and public exponent
+ * are required. The rest are optional.
+ */
+ i = 0;
+ copy_attr_to_bigint(&(rsa_pri_attrs[i++]), &mod);
+ copy_attr_to_bigint(&(rsa_pri_attrs[i++]), &pubexp);
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ copy_attr_to_bigint(&(rsa_pri_attrs[i]), &priexp);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ copy_attr_to_bigint(&(rsa_pri_attrs[i]), &prime1);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ copy_attr_to_bigint(&(rsa_pri_attrs[i]), &prime2);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ copy_attr_to_bigint(&(rsa_pri_attrs[i]), &exp1);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ copy_attr_to_bigint(&(rsa_pri_attrs[i]), &exp2);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ copy_attr_to_bigint(&(rsa_pri_attrs[i]), &coef);
+ i++;
+
+ /* Start the conversion to internal OpenSSL RSA structure. */
+
+ /* Modulus n */
+ if (cvt_bigint2bn(&mod, &(rsa->n)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key modulus."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Public exponent e */
+ if (cvt_bigint2bn(&pubexp, &(rsa->e)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key public exponent."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Private exponent e */
+ if (priexp.big_value != NULL) {
+ if (cvt_bigint2bn(&priexp, &(rsa->d)) < 0) {
+ cryptoerror(LOG_STDERR, gettext("Unable to convert "
+ "RSA private key private exponent."));
+ return (CKR_GENERAL_ERROR);
+ }
+ } else
+ cryptodebug("no RSA private key private exponent");
+
+ /* Prime p */
+ if (prime1.big_value != NULL) {
+ if (cvt_bigint2bn(&prime1, &(rsa->p)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key prime 1."));
+ return (CKR_GENERAL_ERROR);
+ }
+ } else
+ cryptodebug("no RSA private key prime 1");
+
+ /* Prime q */
+ if (prime2.big_value != NULL) {
+ if (cvt_bigint2bn(&prime2, &(rsa->q)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key prime 2."));
+ return (CKR_GENERAL_ERROR);
+ }
+ } else
+ cryptodebug("no RSA private key prime 2");
+
+ /* Private exponent d modulo p-1 */
+ if (exp1.big_value != NULL) {
+ if (cvt_bigint2bn(&exp1, &(rsa->dmp1)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key exponent 1."));
+ return (CKR_GENERAL_ERROR);
+ }
+ } else
+ cryptodebug("no RSA private key exponent 1");
+
+ /* Private exponent d modulo q-1 */
+ if (exp2.big_value != NULL) {
+ if (cvt_bigint2bn(&exp2, &(rsa->dmq1)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key exponent 2."));
+ return (CKR_GENERAL_ERROR);
+ }
+ } else
+ cryptodebug("no RSA private key exponent 2");
+
+ /* CRT coefficient q-inverse mod p */
+ if (coef.big_value != NULL) {
+ if (cvt_bigint2bn(&coef, &(rsa->iqmp)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key coefficient."));
+ return (CKR_GENERAL_ERROR);
+ }
+ } else
+ cryptodebug("no RSA private key coefficient");
+
+ /* Create OpenSSL EVP_PKEY struct in which to stuff RSA struct. */
+ cryptodebug("calling EVP_PKEY_new");
+ if ((key = EVP_PKEY_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to allocate internal EVP_PKEY structure."));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Put the RSA struct into the EVP_PKEY struct and return it. */
+ cryptodebug("calling EVP_PKEY_set1_RSA");
+ (void) EVP_PKEY_set1_RSA(key, rsa);
+
+ *pk = key;
+ return (CKR_OK);
+}
+
+/*
+ * Convert PKCS#11 DSA private key to OpenSSL EVP_PKEY structure.
+ */
+static CK_RV
+cvt_dsa2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+{
+ CK_RV rv = CKR_OK;
+ EVP_PKEY *key = NULL; /* OpenSSL representation */
+ DSA *dsa = NULL; /* OpenSSL representation */
+ biginteger_t prime = { NULL, 0 }; /* required */
+ biginteger_t subprime = { NULL, 0 }; /* required */
+ biginteger_t base = { NULL, 0 }; /* required */
+ biginteger_t value = { NULL, 0 }; /* required */
+ CK_ATTRIBUTE dsa_pri_attrs[4] = {
+ { CKA_PRIME, NULL, 0 },
+ { CKA_SUBPRIME, NULL, 0 },
+ { CKA_BASE, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+
+ cryptodebug("inside cvt_dsa2evp_pkey");
+
+ cryptodebug("calling DSA_new");
+ if ((dsa = DSA_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to allocate internal DSA structure."));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, dsa_pri_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get DSA private key object attributes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (dsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ dsa_pri_attrs[i].ulValueLen == 0) {
+ cryptodebug("cvt_dsa2evp_pkey: *** should not happen");
+ dsa_pri_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((dsa_pri_attrs[i].pValue =
+ malloc(dsa_pri_attrs[i].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ return (CKR_HOST_MEMORY);
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, dsa_pri_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get DSA private key attributes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Fill in all the temp variables. They are all required. */
+ i = 0;
+ copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &prime);
+ copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &subprime);
+ copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &base);
+ copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &value);
+
+ /* Start the conversion to internal OpenSSL DSA structure. */
+
+ /* Prime p */
+ if (cvt_bigint2bn(&prime, &(dsa->p)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key prime."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Subprime q */
+ if (cvt_bigint2bn(&subprime, &(dsa->q)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key subprime."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Base g */
+ if (cvt_bigint2bn(&base, &(dsa->g)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key base."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Private key x */
+ if (cvt_bigint2bn(&value, &(dsa->priv_key)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key value."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Create OpenSSL EVP PKEY struct in which to stuff DSA struct. */
+ cryptodebug("calling EVP_PKEY_new");
+ if ((key = EVP_PKEY_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to allocate internal EVP_PKEY structure."));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Put the DSA struct into the EVP_PKEY struct and return it. */
+ cryptodebug("calling EVP_PKEY_set1_DSA");
+ (void) EVP_PKEY_set1_DSA(key, dsa);
+
+ *pk = key;
+ return (CKR_OK);
+}
+
+/*
+ * Convert PKCS#11 DH private key to OpenSSL EVP_PKEY structure.
+ */
+static CK_RV
+cvt_dh2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+{
+ CK_RV rv = CKR_OK;
+ EVP_PKEY *key = NULL; /* OpenSSL representation */
+ DH *dh = NULL; /* OpenSSL representation */
+ biginteger_t prime = { NULL, 0 }; /* required */
+ biginteger_t base = { NULL, 0 }; /* required */
+ biginteger_t value = { NULL, 0 }; /* required */
+ CK_ATTRIBUTE dh_pri_attrs[3] = {
+ { CKA_PRIME, NULL, 0 },
+ { CKA_BASE, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ULONG count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+
+ cryptodebug("inside cvt_dh2evp_pkey");
+
+ cryptodebug("calling DH_new");
+ if ((dh = DH_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to allocate internal DH structure."));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, dh_pri_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get DH private key object attributes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (dh_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ dh_pri_attrs[i].ulValueLen == 0) {
+ cryptodebug("cvt_dh2evp_pkey: ***should not happen");
+ dh_pri_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((dh_pri_attrs[i].pValue =
+ malloc(dh_pri_attrs[i].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ return (CKR_HOST_MEMORY);
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, dh_pri_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get DH private key attributes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Fill in all the temp variables. They are all required. */
+ i = 0;
+ copy_attr_to_bigint(&(dh_pri_attrs[i++]), &prime);
+ copy_attr_to_bigint(&(dh_pri_attrs[i++]), &base);
+ copy_attr_to_bigint(&(dh_pri_attrs[i++]), &value);
+
+ /* Start the conversion to internal OpenSSL DH structure. */
+
+ /* Prime p */
+ if (cvt_bigint2bn(&prime, &(dh->p)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DH private key prime."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Base g */
+ if (cvt_bigint2bn(&base, &(dh->g)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DH private key base."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Private value x */
+ if (cvt_bigint2bn(&value, &(dh->priv_key)) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DH private key value."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Create OpenSSL EVP PKEY struct in which to stuff DH struct. */
+ cryptodebug("calling EVP_PKEY_new");
+ if ((key = EVP_PKEY_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to allocate internal EVP_PKEY structure."));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Put the DH struct into the EVP_PKEY struct and return it. */
+ cryptodebug("calling EVP_PKEY_set1_DH");
+ (void) EVP_PKEY_set1_DH(key, dh);
+
+ *pk = key;
+ return (CKR_OK);
+}
+
+/*
+ * Convert PKCS#11 private key object to OpenSSL EVP_PKEY structure.
+ */
+static CK_RV
+cvt_obj2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk)
+{
+ CK_RV rv = CKR_OK;
+ static CK_KEY_TYPE keytype = 0;
+ CK_ATTRIBUTE keytype_attr[1] = {
+ { CKA_KEY_TYPE, &keytype, sizeof (keytype) }
+ };
+
+ cryptodebug("inside cvt_obj2evp_pkey");
+
+ /* Find out the key type to do the right conversion. */
+ cryptodebug("calling C_GetAttributeValue");
+ if ((rv = C_GetAttributeValue(sess, obj, keytype_attr, 1)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get token object key type (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ switch (keytype) {
+ case CKK_RSA:
+ cryptodebug("converting RSA key");
+ return (cvt_rsa2evp_pkey(sess, obj, pk));
+ case CKK_DSA:
+ cryptodebug("converting DSA key");
+ return (cvt_dsa2evp_pkey(sess, obj, pk));
+ case CKK_DH:
+ cryptodebug("converting DH key");
+ return (cvt_dh2evp_pkey(sess, obj, pk));
+ default:
+ cryptoerror(LOG_STDERR, gettext(
+ "Private key type 0x%02x conversion not supported."),
+ keytype);
+ return (CKR_GENERAL_ERROR);
+ }
+}
+
+/*
+ * Convert PKCS#11 certificate object to OpenSSL X509 structure.
+ */
+static CK_RV
+cvt_cert2x509(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, X509 **c)
+{
+ CK_RV rv = CKR_OK;
+ X509 *cert = NULL; /* OpenSSL representation */
+ X509 *temp_cert = NULL;
+ CK_BYTE *subject = NULL;
+ CK_ULONG subject_len = 0;
+ CK_BYTE *value = NULL;
+ CK_ULONG value_len = 0;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_BYTE *issuer = NULL;
+ CK_ULONG issuer_len = 0;
+ CK_BYTE *serial = NULL;
+ CK_ULONG serial_len = 0;
+ CK_ATTRIBUTE cert_attrs[6] = {
+ { CKA_SUBJECT, NULL, 0 }, /* required */
+ { CKA_VALUE, NULL, 0 }, /* required */
+ { CKA_LABEL, NULL, 0 }, /* optional */
+ { CKA_ID, NULL, 0 }, /* optional */
+ { CKA_ISSUER, NULL, 0 }, /* optional */
+ { CKA_SERIAL_NUMBER, NULL, 0 } /* optional */
+ };
+ CK_ULONG count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE);
+ int i = 0;
+ X509_NAME *ssl_subject = NULL;
+ X509_NAME *ssl_issuer = NULL;
+ ASN1_INTEGER *ssl_serial = NULL;
+
+ cryptodebug("inside cvt_cert2x509");
+
+ cryptodebug("calling X509_new");
+ if ((cert = X509_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to allocate internal X509 structure."));
+ return (CKR_HOST_MEMORY);
+ }
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, cert_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get certificate attribute sizes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (cert_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ cert_attrs[i].ulValueLen == 0) {
+ cryptodebug("cvt_cert2x509: *** should not happen");
+ cert_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((cert_attrs[i].pValue = malloc(cert_attrs[i].ulValueLen))
+ == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ return (CKR_HOST_MEMORY);
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, cert_attrs, count)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get certificate attributes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /*
+ * Fill in all the temp variables. Subject and value are required.
+ * The rest are optional.
+ */
+ i = 0;
+ copy_attr_to_string(&(cert_attrs[i++]), &subject, &subject_len);
+ copy_attr_to_string(&(cert_attrs[i++]), &value, &value_len);
+
+ if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ cert_attrs[i].ulValueLen != 0)
+ copy_attr_to_string(&(cert_attrs[i]), &label, &label_len);
+ i++;
+
+ if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ cert_attrs[i].ulValueLen != 0)
+ copy_attr_to_string(&(cert_attrs[i]), &id, &id_len);
+ i++;
+
+ if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ cert_attrs[i].ulValueLen != 0)
+ copy_attr_to_string(&(cert_attrs[i]), &issuer, &issuer_len);
+ i++;
+
+ if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ cert_attrs[i].ulValueLen != 0)
+ copy_attr_to_string(&(cert_attrs[i]), &serial, &serial_len);
+ i++;
+
+ /* Start the conversion to internal OpenSSL X509 structure. */
+
+ /* Subject name (required) */
+ cryptodebug("calling d2i_X509_NAME for subject name");
+ if ((ssl_subject = d2i_X509_NAME(NULL, &subject, subject_len)) ==
+ NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert certificate subject name."));
+ return (CKR_GENERAL_ERROR);
+ }
+ cryptodebug("calling X509_set_subject_name");
+ if (!X509_set_subject_name(cert, ssl_subject)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to pack certificate subject name entries."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Label (optional) */
+ cryptodebug("calling X509_alias_set1");
+ if (!X509_alias_set1(cert, label, label_len))
+ cryptodebug("error not caught");
+
+ /* Id (optional) */
+ cryptodebug("calling X509_keyid_set1");
+ if (!X509_keyid_set1(cert, id, id_len))
+ cryptodebug("error not caught");
+
+ /* Issuer name (optional) */
+ cryptodebug("calling d2i_X509_NAME for issuer name");
+ if ((ssl_issuer = d2i_X509_NAME(NULL, &issuer, issuer_len)) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert certificate issuer name."));
+ return (CKR_GENERAL_ERROR);
+ }
+ cryptodebug("calling X509_set_issuer_name");
+ if (!X509_set_issuer_name(cert, ssl_issuer)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to pack certificate issuer name entries."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Serial number (optional) */
+ cryptodebug("calling c2i_ASN1_INTEGER for serial number");
+ if ((ssl_serial = c2i_ASN1_INTEGER(NULL, &serial, serial_len)) ==
+ NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert certificate serial number."));
+ return (CKR_GENERAL_ERROR);
+ }
+ cryptodebug("calling X509_set_serialNumber");
+ if (!X509_set_serialNumber(cert, ssl_serial))
+ cryptodebug("error not caught");
+
+ /*
+ * Value (required)
+ *
+ * The rest of this code takes the CKA_VALUE attribute, converts
+ * it into a temp OpenSSL X509 structure and picks out the rest
+ * of the fields we need to convert it back into the current X509
+ * structure that will get exported. The reason we don't just
+ * start with CKA_VALUE is because while the object was in the
+ * softtoken, it is possible that some of its attributes changed.
+ * Those changes would not appear in CKA_VALUE and would be lost
+ * if we started with CKA_VALUE that was saved originally.
+ */
+ cryptodebug("calling d2i_X509 for cert value");
+ if ((temp_cert = d2i_X509(NULL, &value, value_len)) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert main certificate values."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ /* Transfer these values from temp_cert to cert. */
+ cryptodebug("calling X509_set_version/X509_get_version");
+ if (!X509_set_version(cert, X509_get_version(temp_cert)))
+ cryptodebug("error not caught");
+
+ cryptodebug("calling X509_set_notBefore/X509_get_notBefore");
+ if (!X509_set_notBefore(cert, X509_get_notBefore(temp_cert)))
+ cryptodebug("error not caught");
+
+ cryptodebug("calling X509_set_notAfter/X509_get_notAfter");
+ if (!X509_set_notAfter(cert, X509_get_notAfter(temp_cert)))
+ cryptodebug("error not caught");
+
+ cryptodebug("calling X509_set_pubkey/X509_get_pubkey");
+ if (!X509_set_pubkey(cert, X509_get_pubkey(temp_cert)))
+ cryptodebug("error not caught");
+
+ /*
+ * These don't get transfered from temp_cert to cert.
+ * It -appears- that they may get regenerated as needed.
+ *
+ * cert->cert_info->signature = dup(temp_cert->cert_info->signature);
+ * cert->sig_alg = dup(temp_cert->sig_alg);
+ * cert->signature = dup(temp_cert->signature);
+ * cert->skid = dup(temp_cert->skid);
+ * cert->akid = dup(temp_cert->akid);
+ */
+
+ *c = cert;
+ return (CKR_OK);
+}
+
+static CK_RV
+convert_token_objs(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj,
+ CK_OBJECT_HANDLE mate, CK_OBJECT_HANDLE *chain, CK_ULONG chain_len,
+ EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
+{
+ CK_RV rv = CKR_OK;
+ EVP_PKEY *pk = NULL;
+ X509 *c = NULL;
+ X509 *one_ca = NULL;
+ STACK_OF(X509) *ch = NULL;
+ int i;
+
+ cryptodebug("inside convert_token_objs");
+
+ if ((rv = cvt_obj2evp_pkey(sess, obj, &pk)) != CKR_OK)
+ return (rv);
+
+ if (mate != ~0UL) {
+ cryptodebug("converting cert corresponding to private key");
+ if ((rv = cvt_cert2x509(sess, mate, &c)) != CKR_OK)
+ return (rv);
+ }
+
+ if (chain_len != 0) {
+ cryptodebug("converting ca chain of %d certs corresponding "
+ "to private key", chain_len);
+ ch = sk_X509_new_null();
+ for (i = 0; i < chain_len; i++) {
+ if ((rv = cvt_cert2x509(sess, chain[i], &one_ca)) !=
+ CKR_OK) {
+ return (rv);
+ }
+ if (!sk_X509_push(ch, one_ca))
+ cryptodebug("error not caught");
+ }
+ }
+
+ *priv_key = pk;
+ *cert = (mate != ~0UL) ? c : NULL;
+ *ca = (chain_len != 0) ? ch : NULL;
+ return (CKR_OK);
+}
+
+/*
+ * Export objects from token to PKCS#12 file.
+ */
+int
+pk_export(int argc, char *argv[])
+{
+ char *token_name = NULL;
+ char *manuf_id = NULL;
+ char *serial_no = NULL;
+ char full_name[FULL_NAME_LEN];
+ char *filename = NULL;
+ CK_SLOT_ID slot_id;
+ CK_FLAGS pin_state;
+ CK_UTF8CHAR_PTR pin = NULL;
+ CK_ULONG pinlen = 0;
+ CK_UTF8CHAR_PTR pk12pin = NULL;
+ CK_ULONG pk12pinlen = 0;
+ CK_SESSION_HANDLE sess;
+ BIO *fbio = NULL;
+ EVP_PKEY *priv_key = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca = NULL;
+ CK_RV rv = CKR_OK;
+ CK_OBJECT_HANDLE *objs = NULL;
+ CK_ULONG num_objs = 0;
+ CK_OBJECT_HANDLE mate = ~0UL;
+ CK_OBJECT_HANDLE *chain = NULL;
+ CK_ULONG chain_len;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ int i = 0;
+ int good_ones = 0, bad_ones = 0; /* running totals */
+
+ cryptodebug("inside pk_export");
+
+ /* Get rid of subcommand work "export". */
+ argc--;
+ argv++;
+
+ /* One additional arg required: filename. */
+ if (argc != 1)
+ return (PK_ERR_USAGE);
+
+ filename = argv[0];
+ /* Done parsing command line options. */
+
+ /* Check if the file exists and might be overwritten. */
+ if (access(filename, F_OK) == 0) {
+ cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, "
+ "will be overwritten."), filename);
+ if (yesno(gettext("Continue with export? "),
+ gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
+ return (0);
+ }
+ }
+
+ /* Export operation only supported on softtoken. */
+ if (token_name == NULL)
+ token_name = SOFT_TOKEN_LABEL;
+ if (manuf_id == NULL)
+ manuf_id = SOFT_MANUFACTURER_ID;
+ if (serial_no == NULL)
+ serial_no = SOFT_TOKEN_SERIAL;
+ full_token_name(token_name, manuf_id, serial_no, full_name);
+
+ /* Find the slot with token. */
+ if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
+ &pin_state)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to find token %s (%s)."), full_name,
+ pkcs11_strerror(rv));
+ return (PK_ERR_PK11);
+ }
+
+ /* Get the user's PIN. */
+ if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
+ &pinlen)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get token passphrase (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(NULL);
+ return (PK_ERR_PK11);
+ }
+
+ /* Assume user must be logged in R/W to export objects from token. */
+ if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to log into token (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ /* Collect all private keys first. */
+ if ((rv = find_objs(sess, PK_PRIVATE_OBJ|PK_KEY_OBJ, NULL,
+ &objs, &num_objs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to retrieve private key token objects (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ /* Nothing to do? */
+ if (num_objs == 0) {
+ cryptoerror(LOG_STDERR, gettext("No objects found."));
+ quick_finish(sess);
+ return (0);
+ }
+
+ /* Setup OpenSSL context. */
+ PKTOOL_setup_openssl();
+
+ /* Create PKCS#12 file. */
+ if ((create_pkcs12(filename, &fbio)) < 0) {
+ cryptoerror(LOG_STDERR, gettext("No export file created."));
+ quick_finish(sess);
+ return (PK_ERR_SYSTEM);
+ }
+
+ /* Get the PIN for the PKCS#12 export file. */
+ if ((rv = get_pin(gettext("Create export file passphrase:"), gettext(
+ "Re-enter export file passphrase:"), &pk12pin, &pk12pinlen)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to get export file passphrase (%s)."),
+ pkcs11_strerror(rv));
+ close_pkcs12(fbio);
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ for (i = 0; i < num_objs; i++) {
+ /* Get a private key and its certificate and CA chain. */
+ if ((rv = get_token_objs(sess, objs[i], &mate, &chain,
+ &chain_len, &id, &id_len)) != CKR_OK) {
+ /*
+ * Note this "rv" is either CKR_OK or !CKR_OK. The
+ * real error codes/messages are handled inside
+ * read_token_objs().
+ */
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to get token objects."));
+ free(id);
+ close_pkcs12(fbio);
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ /* Convert to OpenSSL equivalents. */
+ if ((rv = convert_token_objs(sess, objs[i], mate, chain,
+ chain_len, &priv_key, &cert, &ca)) != CKR_OK) {
+ /*
+ * Note this "rv" is either CKR_OK or !CKR_OK. The
+ * real error codes/messages are handled inside
+ * read_token_objs().
+ */
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to convert token objects."));
+ free(id);
+ close_pkcs12(fbio);
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ /*
+ * When exporting of cert chains is implemented, these
+ * messages should be updated accordingly.
+ */
+ if (mate == ~0UL)
+ (void) fprintf(stdout, gettext(
+ "Writing object #%d...\n"), i+1);
+ else
+ (void) fprintf(stdout, gettext("Writing object #%d "
+ "and its certificate...\n"), i+1);
+
+ /* Write object and its certs to the PKCS#12 export file. */
+ if (write_objs_pkcs12(fbio, pk12pin, pk12pinlen, id, id_len,
+ priv_key, cert, ca, &good_ones, &bad_ones) < 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to write object #%d to export file."), i+1);
+ sk_X509_pop_free(ca, X509_free);
+ free(id);
+ close_pkcs12(fbio);
+ quick_finish(sess);
+ return (PK_ERR_OPENSSL);
+ }
+
+ /* Destroy key id and CA cert chain, done with them. */
+ free(id);
+ id = NULL;
+ sk_X509_pop_free(ca, X509_free);
+ ca = NULL;
+ }
+
+ (void) fprintf(stdout, gettext(
+ "%d token objects exported, %d errors occurred.\n"),
+ good_ones, bad_ones);
+
+ /* Close PKCS#12 file. */
+ close_pkcs12(fbio);
+
+ /* Clean up. */
+ quick_finish(sess);
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/import.c b/usr/src/cmd/cmd-crypto/pktool/import.c
new file mode 100644
index 0000000000..fee8ffc06a
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/import.c
@@ -0,0 +1,945 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements the import operation for this tool.
+ * The basic flow of the process is to decrypt the PKCS#12
+ * input file if it has a password, parse the elements in
+ * the file, find the soft token, log into it, import the
+ * PKCS#11 objects into the soft token, and log out.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+#include "biginteger.h"
+#include "osslcommon.h"
+#include "p12common.h"
+#include <openssl/pkcs12.h>
+#include <openssl/err.h>
+
+/*
+ * Helper function decrypt and parse PKCS#12 import file.
+ */
+static CK_RV
+extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
+ EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
+/* ARGSUSED */
+{
+ PKCS12 *pk12, *pk12_tmp;
+ EVP_PKEY *temp_pkey = NULL;
+ X509 *temp_cert = NULL;
+ STACK_OF(X509) *temp_ca = NULL;
+
+ cryptodebug("inside extract_pkcs12");
+
+ cryptodebug("calling PKCS12_new");
+ if ((pk12 = PKCS12_new()) == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create PKCS#12 context."));
+ return (CKR_GENERAL_ERROR);
+ }
+
+ cryptodebug("calling d2i_PKCS12_bio");
+ if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) {
+ /* This is ok; it seems to mean there is no more to read. */
+ if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 &&
+ ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG)
+ goto end_extract_pkcs12;
+
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to populate PKCS#12 context."));
+ PKCS12_free(pk12);
+ return (CKR_GENERAL_ERROR);
+ }
+ pk12 = pk12_tmp;
+
+ cryptodebug("calling PKCS12_parse");
+ if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert,
+ &temp_ca) <= 0) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to parse import file."));
+ PKCS12_free(pk12);
+ return (CKR_GENERAL_ERROR);
+ }
+
+end_extract_pkcs12:
+
+ *priv_key = temp_pkey;
+ *cert = temp_cert;
+ *ca = temp_ca;
+
+ PKCS12_free(pk12);
+ return (CKR_OK);
+}
+
+/*
+ * Converts OpenSSL BIGNUM into PKCS#11 biginteger_t format.
+ */
+static CK_RV
+cvt_bn2bigint(BIGNUM *from, biginteger_t *to)
+{
+ CK_BYTE *temp;
+ CK_ULONG temp_alloc_sz, temp_cvt_sz;
+
+ cryptodebug("inside cvt_bn2bigint");
+
+ if (from == NULL || to == NULL)
+ return (CKR_ARGUMENTS_BAD);
+
+ cryptodebug("calling BN_num_bytes");
+ temp_alloc_sz = BN_num_bytes(from);
+ if ((temp = malloc(temp_alloc_sz)) == NULL)
+ return (CKR_HOST_MEMORY);
+
+ cryptodebug("calling BN_bn2bin");
+ temp_cvt_sz = BN_bn2bin(from, (unsigned char *)temp);
+ if (temp_cvt_sz != temp_alloc_sz)
+ return (CKR_GENERAL_ERROR);
+
+ to->big_value = temp;
+ to->big_value_len = temp_cvt_sz;
+ return (CKR_OK);
+}
+
+/*
+ * Write RSA private key to token.
+ */
+static CK_RV
+write_rsa_private(CK_SESSION_HANDLE sess, RSA *rsa, X509 *cert)
+{
+ CK_RV rv = CKR_OK;
+ int i = 0;
+ static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
+ static CK_KEY_TYPE keytype = CKK_RSA;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_DATE startdate = { "", "", "" };
+ CK_DATE enddate = { "", "", "" };
+ char tmpdate[8];
+ biginteger_t mod = { NULL, 0 }; /* required */
+ biginteger_t pubexp = { NULL, 0 }; /* required */
+ biginteger_t priexp = { NULL, 0 }; /* optional */
+ biginteger_t prime1 = { NULL, 0 }; /* optional */
+ biginteger_t prime2 = { NULL, 0 }; /* optional */
+ biginteger_t exp1 = { NULL, 0 }; /* optional */
+ biginteger_t exp2 = { NULL, 0 }; /* optional */
+ biginteger_t coef = { NULL, 0 }; /* optional */
+ CK_ATTRIBUTE rsa_pri_attrs[16] = {
+ { CKA_CLASS, &objclass, sizeof (objclass) },
+ { CKA_KEY_TYPE, &keytype, sizeof (keytype) },
+ { CKA_PRIVATE, &pk_true, sizeof (pk_true) },
+ { CKA_TOKEN, &pk_true, sizeof (pk_true) },
+ { CKA_LABEL, NULL, 0 },
+ { CKA_ID, NULL, 0 },
+ { CKA_START_DATE, NULL, 0 },
+ { CKA_END_DATE, NULL, 0 },
+ { CKA_MODULUS, NULL, 0 },
+ { CKA_PUBLIC_EXPONENT, NULL, 0 },
+ { 0 /* CKA_PRIVATE_EXPONENT */, NULL, 0 }, /* optional */
+ { 0 /* CKA_PRIME_1 */, NULL, 0 }, /* | */
+ { 0 /* CKA_PRIME_2 */, NULL, 0 }, /* | */
+ { 0 /* CKA_EXPONENT_1 */, NULL, 0 }, /* | */
+ { 0 /* CKA_EXPONENT_2 */, NULL, 0 }, /* | */
+ { 0 /* CKA_COEFFICIENT */, NULL, 0 } /* V */
+ };
+ CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ CK_OBJECT_HANDLE obj;
+
+ cryptodebug("inside write_rsa_private");
+
+ /* Attributes start at array index 4. */
+ i = 4;
+
+ /* Recycle the certificate label for the private key label. */
+ cryptodebug("calling X509_alias_get0");
+ if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
+ label = (CK_BYTE *)gettext("no label");
+ label_len = strlen((char *)label);
+ }
+ copy_string_to_attr(label, label_len, &(rsa_pri_attrs[i++]));
+
+ /* Recycle the certificate id for the private key id. */
+ cryptodebug("calling PKTOOL_X509_keyid_get0");
+ if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
+ id = (CK_BYTE *)gettext("no id");
+ id_len = strlen((char *)id);
+ }
+ copy_string_to_attr(id, id_len, &(rsa_pri_attrs[i++]));
+
+ /* Recycle the certificate start and end dates for private key. */
+ cryptodebug("calling X509_get_notBefore");
+ if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
+ (void) memcpy(&startdate, tmpdate, sizeof (startdate));
+ copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
+ &(rsa_pri_attrs[i++]));
+ }
+
+ cryptodebug("calling X509_get_notAfter");
+ if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
+ (void) memcpy(&enddate, tmpdate, sizeof (enddate));
+ copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
+ &(rsa_pri_attrs[i++]));
+ }
+
+ /* Modulus n */
+ cryptodebug("converting RSA private key modulus");
+ if ((rv = cvt_bn2bigint(rsa->n, &mod)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key modulus."));
+ return (rv);
+ }
+ copy_bigint_to_attr(mod, &(rsa_pri_attrs[i++]));
+
+ /* Public exponent e */
+ cryptodebug("converting RSA private key public exponent");
+ if ((rv = cvt_bn2bigint(rsa->e, &pubexp)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key public exponent."));
+ return (rv);
+ }
+ copy_bigint_to_attr(pubexp, &(rsa_pri_attrs[i++]));
+
+ /* Private exponent d */
+ if (rsa->d != NULL) {
+ cryptodebug("converting RSA private key private exponent");
+ if ((rv = cvt_bn2bigint(rsa->d, &priexp)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext("Unable to convert "
+ "RSA private key private exponent."));
+ return (rv);
+ }
+ rsa_pri_attrs[i].type = CKA_PRIVATE_EXPONENT;
+ copy_bigint_to_attr(priexp, &(rsa_pri_attrs[i++]));
+ } else
+ cryptodebug("no RSA private key private exponent");
+
+ /* Prime p */
+ if (rsa->p != NULL) {
+ cryptodebug("converting RSA private key prime 1");
+ if ((rv = cvt_bn2bigint(rsa->p, &prime1)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key prime 1."));
+ return (rv);
+ }
+ rsa_pri_attrs[i].type = CKA_PRIME_1;
+ copy_bigint_to_attr(prime1, &(rsa_pri_attrs[i++]));
+ } else
+ cryptodebug("no RSA private key prime 1");
+
+ /* Prime q */
+ if (rsa->q != NULL) {
+ cryptodebug("converting RSA private key prime 2");
+ if ((rv = cvt_bn2bigint(rsa->q, &prime2)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key prime 2."));
+ return (rv);
+ }
+ rsa_pri_attrs[i].type = CKA_PRIME_2;
+ copy_bigint_to_attr(prime2, &(rsa_pri_attrs[i++]));
+ } else
+ cryptodebug("no RSA private key prime 2");
+
+ /* Private exponent d modulo p-1 */
+ if (rsa->dmp1 != NULL) {
+ cryptodebug("converting RSA private key exponent 1");
+ if ((rv = cvt_bn2bigint(rsa->dmp1, &exp1)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key exponent 1."));
+ return (rv);
+ }
+ rsa_pri_attrs[i].type = CKA_EXPONENT_1;
+ copy_bigint_to_attr(exp1, &(rsa_pri_attrs[i++]));
+ } else
+ cryptodebug("no RSA private key exponent 1");
+
+ /* Private exponent d modulo q-1 */
+ if (rsa->dmq1 != NULL) {
+ cryptodebug("converting RSA private key exponent 2");
+ if ((rv = cvt_bn2bigint(rsa->dmq1, &exp2)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key exponent 2."));
+ return (rv);
+ }
+ rsa_pri_attrs[i].type = CKA_EXPONENT_2;
+ copy_bigint_to_attr(exp2, &(rsa_pri_attrs[i++]));
+ } else
+ cryptodebug("no RSA private key exponent 2");
+
+ /* CRT coefficient q-inverse mod p */
+ if (rsa->iqmp != NULL) {
+ cryptodebug("converting RSA private key coefficient");
+ if ((rv = cvt_bn2bigint(rsa->iqmp, &coef)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert RSA private key coefficient."));
+ return (rv);
+ }
+ rsa_pri_attrs[i].type = CKA_COEFFICIENT;
+ copy_bigint_to_attr(coef, &(rsa_pri_attrs[i++]));
+ } else
+ cryptodebug("no RSA private key coefficient");
+
+ /* Indicates programming error: attributes overran the template */
+ if (i > count) {
+ cryptodebug("error: more attributes found than accounted for");
+ i = count;
+ }
+
+ cryptodebug("calling C_CreateObject");
+ if ((rv = C_CreateObject(sess, rsa_pri_attrs, i, &obj)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create RSA private key object."));
+ return (rv);
+ }
+
+ return (CKR_OK);
+}
+
+/*
+ * Write DSA private key to token.
+ */
+static CK_RV
+write_dsa_private(CK_SESSION_HANDLE sess, DSA *dsa, X509 *cert)
+{
+ CK_RV rv = CKR_OK;
+ int i = 0;
+ static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
+ static CK_KEY_TYPE keytype = CKK_DSA;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_DATE startdate = { "", "", "" };
+ CK_DATE enddate = { "", "", "" };
+ char tmpdate[8];
+ biginteger_t prime = { NULL, 0 }; /* required */
+ biginteger_t subprime = { NULL, 0 }; /* required */
+ biginteger_t base = { NULL, 0 }; /* required */
+ biginteger_t value = { NULL, 0 }; /* required */
+ CK_ATTRIBUTE dsa_pri_attrs[12] = {
+ { CKA_CLASS, &objclass, sizeof (objclass) },
+ { CKA_KEY_TYPE, &keytype, sizeof (keytype) },
+ { CKA_PRIVATE, &pk_true, sizeof (pk_true) },
+ { CKA_TOKEN, &pk_true, sizeof (pk_true) },
+ { CKA_LABEL, NULL, 0 },
+ { CKA_ID, NULL, 0 },
+ { CKA_START_DATE, NULL, 0 },
+ { CKA_END_DATE, NULL, 0 },
+ { CKA_PRIME, NULL, 0 },
+ { CKA_SUBPRIME, NULL, 0 },
+ { CKA_BASE, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ CK_OBJECT_HANDLE obj;
+
+ cryptodebug("inside write_dsa_private");
+
+ /* Attributes start at array index 4. */
+ i = 4;
+
+ /* Recycle the certificate label for the private key label. */
+ cryptodebug("calling X509_alias_get0");
+ if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
+ label = (CK_BYTE *)gettext("no label");
+ label_len = strlen((char *)label);
+ }
+ copy_string_to_attr(label, label_len, &(dsa_pri_attrs[i++]));
+
+ /* Recycle the certificate id for the private key id. */
+ cryptodebug("calling PKTOOL_X509_keyid_get0");
+ if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
+ id = (CK_BYTE *)gettext("no id");
+ id_len = strlen((char *)id);
+ }
+ copy_string_to_attr(id, id_len, &(dsa_pri_attrs[i++]));
+
+ /* Recycle the certificate start and end dates for private key. */
+ cryptodebug("calling X509_get_notBefore");
+ if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
+ (void) memcpy(&startdate, tmpdate, sizeof (startdate));
+ copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
+ &(dsa_pri_attrs[i++]));
+ }
+
+ cryptodebug("calling X509_get_notAfter");
+ if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
+ (void) memcpy(&enddate, tmpdate, sizeof (enddate));
+ copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
+ &(dsa_pri_attrs[i++]));
+ }
+
+ /* Prime p */
+ cryptodebug("converting DSA private key prime");
+ if ((rv = cvt_bn2bigint(dsa->p, &prime)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key prime."));
+ return (rv);
+ }
+ copy_bigint_to_attr(prime, &(dsa_pri_attrs[i++]));
+
+ /* Subprime q */
+ cryptodebug("converting DSA private key subprime");
+ if ((rv = cvt_bn2bigint(dsa->q, &subprime)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key subprime."));
+ return (rv);
+ }
+ copy_bigint_to_attr(subprime, &(dsa_pri_attrs[i++]));
+
+ /* Base g */
+ cryptodebug("converting DSA private key base");
+ if ((rv = cvt_bn2bigint(dsa->g, &base)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key base."));
+ return (rv);
+ }
+ copy_bigint_to_attr(base, &(dsa_pri_attrs[i++]));
+
+ /* Private key x */
+ cryptodebug("converting DSA private key value");
+ if ((rv = cvt_bn2bigint(dsa->priv_key, &value)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DSA private key value."));
+ return (rv);
+ }
+ copy_bigint_to_attr(value, &(dsa_pri_attrs[i++]));
+
+ /* Indicates programming error: attributes overran the template */
+ if (i > count) {
+ cryptodebug("error: more attributes found than accounted for");
+ i = count;
+ }
+
+ cryptodebug("calling C_CreateObject");
+ if ((rv = C_CreateObject(sess, dsa_pri_attrs, i, &obj)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create DSA private key object."));
+ return (rv);
+ }
+
+ return (CKR_OK);
+}
+
+/*
+ * Write DH private key to token.
+ */
+static CK_RV
+write_dh_private(CK_SESSION_HANDLE sess, DH *dh, X509 *cert)
+{
+ CK_RV rv = CKR_OK;
+ int i = 0;
+ static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
+ static CK_KEY_TYPE keytype = CKK_DH;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_DATE startdate = { "", "", "" };
+ CK_DATE enddate = { "", "", "" };
+ char tmpdate[8];
+ biginteger_t prime = { NULL, 0 }; /* required */
+ biginteger_t base = { NULL, 0 }; /* required */
+ biginteger_t value = { NULL, 0 }; /* required */
+ CK_ATTRIBUTE dh_pri_attrs[11] = {
+ { CKA_CLASS, &objclass, sizeof (objclass) },
+ { CKA_KEY_TYPE, &keytype, sizeof (keytype) },
+ { CKA_PRIVATE, &pk_true, sizeof (pk_true) },
+ { CKA_TOKEN, &pk_true, sizeof (pk_true) },
+ { CKA_LABEL, NULL, 0 },
+ { CKA_ID, NULL, 0 },
+ { CKA_START_DATE, NULL, 0 },
+ { CKA_END_DATE, NULL, 0 },
+ { CKA_PRIME, NULL, 0 },
+ { CKA_BASE, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ULONG count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ CK_OBJECT_HANDLE obj;
+
+ cryptodebug("inside write_dh_private");
+
+ /* Attributes start at array index 4. */
+ i = 4;
+
+ /* Recycle the certificate label for the private key label. */
+ cryptodebug("calling X509_alias_get0");
+ if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
+ label = (CK_BYTE *)gettext("no label");
+ label_len = strlen((char *)label);
+ }
+ copy_string_to_attr(label, label_len, &(dh_pri_attrs[i++]));
+
+ /* Recycle the certificate id for the private key id. */
+ cryptodebug("PKTOOL_X509_keyid_get0");
+ if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
+ id = (CK_BYTE *)gettext("no id");
+ id_len = strlen((char *)id);
+ }
+ copy_string_to_attr(id, id_len, &(dh_pri_attrs[i++]));
+
+ /* Recycle the certificate start and end dates for private key. */
+ cryptodebug("calling X509_get_notBefore");
+ if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
+ (void) memcpy(&startdate, tmpdate, sizeof (startdate));
+ copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
+ &(dh_pri_attrs[i++]));
+ }
+
+ cryptodebug("calling X509_get_notAfter");
+ if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
+ (void) memcpy(&enddate, tmpdate, sizeof (enddate));
+ copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
+ &(dh_pri_attrs[i++]));
+ }
+
+ /* Prime p */
+ cryptodebug("converting DH private key prime");
+ if ((rv = cvt_bn2bigint(dh->p, &prime)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DH private key prime."));
+ return (rv);
+ }
+ copy_bigint_to_attr(prime, &(dh_pri_attrs[i++]));
+
+ /* Base g */
+ cryptodebug("converting DH private key base");
+ if ((rv = cvt_bn2bigint(dh->g, &base)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DH private key base."));
+ return (rv);
+ }
+ copy_bigint_to_attr(base, &(dh_pri_attrs[i++]));
+
+ /* Private value x */
+ cryptodebug("converting DH private key value");
+ if ((rv = cvt_bn2bigint(dh->priv_key, &value)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to convert DH private key value."));
+ return (rv);
+ }
+ copy_bigint_to_attr(value, &(dh_pri_attrs[i++]));
+
+ /* Indicates programming error: attributes overran the template */
+ if (i > count) {
+ cryptodebug("error: more attributes found than accounted for");
+ i = count;
+ }
+
+ cryptodebug("calling C_CreateObject");
+ if ((rv = C_CreateObject(sess, dh_pri_attrs, i, &obj)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create DH private key object."));
+ return (rv);
+ }
+
+ return (CKR_OK);
+}
+
+/*
+ * Write certificate to token.
+ */
+static CK_RV
+write_cert(CK_SESSION_HANDLE sess, X509 *cert)
+{
+ CK_RV rv = CKR_OK;
+ int i = 0;
+ static CK_OBJECT_CLASS objclass = CKO_CERTIFICATE;
+ static CK_CERTIFICATE_TYPE certtype = CKC_X_509;
+ CK_BYTE *subject = NULL;
+ CK_ULONG subject_len = 0;
+ CK_BYTE *value = NULL;
+ CK_ULONG value_len = 0;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_BYTE *issuer = NULL;
+ CK_ULONG issuer_len = 0;
+ CK_BYTE *serial = NULL;
+ CK_ULONG serial_len = 0;
+ CK_ATTRIBUTE cert_attrs[9] = {
+ { CKA_CLASS, &objclass, sizeof (objclass) },
+ { CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) },
+ { CKA_TOKEN, &pk_true, sizeof (pk_true) },
+ { CKA_SUBJECT, NULL, 0 }, /* required */
+ { CKA_VALUE, NULL, 0 }, /* required */
+ { 0 /* CKA_LABEL */, NULL, 0 }, /* optional */
+ { 0 /* CKA_ID */, NULL, 0 }, /* optional */
+ { 0 /* CKA_ISSUER */, NULL, 0 }, /* optional */
+ { 0 /* CKA_SERIAL_NUMBER */, NULL, 0 } /* optional */
+ };
+ CK_ULONG count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE);
+ CK_OBJECT_HANDLE obj;
+
+ cryptodebug("inside write_cert");
+
+ /* Attributes start at array index 3. */
+ i = 3;
+
+ /*
+ * OpenSSL subject name and issuer (a little further below) are
+ * actually stack structures that contain individual ASN.1
+ * components. This stack of entries is packed into one DER string.
+ */
+ cryptodebug("calling PKTOOL_X509_subject_name");
+ if ((subject = PKTOOL_X509_subject_name(cert, (int *)&subject_len)) ==
+ NULL) {
+ subject = (CK_BYTE *)gettext("no subject name");
+ subject_len = strlen((char *)subject);
+ }
+ copy_string_to_attr(subject, subject_len, &(cert_attrs[i++]));
+
+ /* Get cert value, but it has to be reconstructed from cert. */
+ cryptodebug("calling PKTOOL_X509_cert_value");
+ if ((value = PKTOOL_X509_cert_value(cert, (int *)&value_len)) == NULL) {
+ value = (CK_BYTE *)gettext("no value");
+ value_len = strlen((char *)value);
+ }
+ copy_string_to_attr(value, value_len, &(cert_attrs[i++]));
+
+ /*
+ * Get certificate label which is "friendlyName" Netscape,
+ * "alias" in OpenSSL.
+ */
+ if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
+ cryptodebug("no certificate label");
+ } else {
+ cert_attrs[i].type = CKA_LABEL;
+ copy_string_to_attr(label, label_len, &(cert_attrs[i++]));
+ }
+
+ /* Get the keyid for the cert. */
+ if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
+ cryptodebug("no certificate id");
+ } else {
+ cert_attrs[i].type = CKA_ID;
+ copy_string_to_attr(id, id_len, &(cert_attrs[i++]));
+ }
+
+ /* Get the issuer name for the cert. */
+ if ((issuer = PKTOOL_X509_issuer_name(cert, (int *)&issuer_len)) ==
+ NULL) {
+ cryptodebug("no certificate issuer name");
+ } else {
+ cert_attrs[i].type = CKA_ISSUER;
+ copy_string_to_attr(issuer, issuer_len, &(cert_attrs[i++]));
+ }
+
+ /* Get the cert serial number. */
+ if ((serial = PKTOOL_X509_serial_number(cert, (int *)&serial_len)) ==
+ NULL) {
+ cryptodebug("no certificate serial number");
+ } else {
+ cert_attrs[i].type = CKA_SERIAL_NUMBER;
+ copy_string_to_attr(serial, serial_len, &(cert_attrs[i++]));
+ }
+
+ /* Indicates programming error: attributes overran the template */
+ if (i > count) {
+ cryptodebug("error: more attributes found than accounted for");
+ i = count;
+ }
+
+ cryptodebug("calling C_CreateObject");
+ if ((rv = C_CreateObject(sess, cert_attrs, i, &obj)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to create X.509 certificate object."));
+ return (rv);
+ }
+
+ return (CKR_OK);
+}
+
+/*
+ * Helper function to write PKCS#12 items to token. Returns CKR_OK
+ * or CKR_GENERAL_ERROR
+ */
+static CK_RV
+write_token_objs(CK_SESSION_HANDLE sess, EVP_PKEY *priv_key, X509 *cert,
+ STACK_OF(X509) *ca, int *successes, int *failures)
+{
+ int i;
+ X509 *c;
+ CK_RV rv = CKR_OK;
+
+ cryptodebug("inside write_token_objs");
+
+ /* Do not reset *successes or *failures -- keep running totals. */
+
+ /* Import user key. */
+ switch (priv_key->type) {
+ case EVP_PKEY_RSA:
+ (void) fprintf(stdout, gettext("Writing RSA private key...\n"));
+ if ((rv = write_rsa_private(sess,
+ EVP_PKEY_get1_RSA(priv_key), cert)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to write RSA private key (%s)."),
+ pkcs11_strerror(rv));
+ (*failures)++;
+ } else
+ (*successes)++;
+ break;
+ case EVP_PKEY_DSA:
+ (void) fprintf(stdout, gettext("Writing DSA private key...\n"));
+ if ((rv = write_dsa_private(sess,
+ EVP_PKEY_get1_DSA(priv_key), cert)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to write DSA private key (%s)."),
+ pkcs11_strerror(rv));
+ (*failures)++;
+ } else
+ (*successes)++;
+ break;
+ case EVP_PKEY_DH:
+ (void) fprintf(stdout, gettext("Writing DH private key...\n"));
+ if ((rv = write_dh_private(sess,
+ EVP_PKEY_get1_DH(priv_key), cert)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to write DH private key (%s)."),
+ pkcs11_strerror(rv));
+ (*failures)++;
+ } else
+ (*successes)++;
+ break;
+
+ default:
+ /*
+ * Note that EVP_PKEY_DH for X9.42 is not implemented
+ * in the OpenSSL library.
+ */
+ cryptoerror(LOG_STDERR, gettext(
+ "Private key type 0x%02x import not supported."),
+ priv_key->type);
+ (*failures)++;
+ break;
+ }
+
+ /* Import user certificate. */
+ (void) fprintf(stdout, gettext("Writing user certificate...\n"));
+ if ((rv = write_cert(sess, cert)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to write user certificate (%s)."),
+ pkcs11_strerror(rv));
+ (*failures)++;
+ } else
+ (*successes)++;
+
+ /* Import as many stacks of authority certificates as possible. */
+ for (i = 0; i != sk_X509_num(ca); i++) {
+ /*
+ * sk_X509_value() is macro that embeds a cast to (X509 *).
+ * Here it translates into ((X509 *)sk_value((ca), (i))).
+ * Lint is complaining about the embedded casting, and
+ * to fix it, you need to fix openssl header files.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ c = sk_X509_value(ca, i);
+ (void) fprintf(stdout, gettext(
+ "Writing authority certificate...\n"));
+ if ((rv = write_cert(sess, c)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to write authority certificate (%s)."),
+ pkcs11_strerror(rv));
+ (*failures)++;
+ } else
+ (*successes)++;
+ }
+
+ (void) fprintf(stdout, gettext("PKCS#12 element scan completed.\n"));
+ return (*failures != 0 ? CKR_GENERAL_ERROR : CKR_OK);
+}
+
+/*
+ * Import objects from PKCS#12 file into token.
+ */
+int
+pk_import(int argc, char *argv[])
+{
+ char *token_name = NULL;
+ char *manuf_id = NULL;
+ char *serial_no = NULL;
+ char full_name[FULL_NAME_LEN];
+ char *filename = NULL;
+ struct stat statbuf;
+ CK_SLOT_ID slot_id;
+ CK_FLAGS pin_state;
+ CK_UTF8CHAR_PTR pin = NULL;
+ CK_ULONG pinlen = 0;
+ CK_UTF8CHAR_PTR pk12pin = NULL;
+ CK_ULONG pk12pinlen = 0;
+ CK_SESSION_HANDLE sess;
+ BIO *fbio = NULL;
+ EVP_PKEY *priv_key = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca = NULL;
+ CK_RV rv = CKR_OK;
+ int i;
+ int good_count = 0, bad_count = 0; /* running totals */
+
+ cryptodebug("inside pk_import");
+
+ /* Get rid of subcommand word "import". */
+ argc--;
+ argv++;
+
+ /* One additional arg required: filename. */
+ if (argc != 1)
+ return (PK_ERR_USAGE);
+
+ filename = argv[0];
+ /* Done parsing command line options. */
+
+ /* Check that the file exists and is non-empty. */
+ if (access(filename, R_OK) < 0) {
+ cryptoerror(LOG_STDERR, gettext("File \"%s\" is unreadable "
+ "(%s)."), filename, strerror(errno));
+ return (CKR_OK);
+ }
+ if (stat(filename, &statbuf) < 0) {
+ cryptoerror(LOG_STDERR, gettext("Unable to get size of "
+ "file \"%s\" (%s)."), filename, strerror(errno));
+ return (CKR_OK);
+ }
+ if (statbuf.st_size == 0) {
+ cryptoerror(LOG_STDERR, gettext("File \"%s\" is empty."),
+ filename);
+ return (CKR_OK);
+ }
+
+ /* Import operation only supported on softtoken. */
+ if (token_name == NULL)
+ token_name = SOFT_TOKEN_LABEL;
+ if (manuf_id == NULL)
+ manuf_id = SOFT_MANUFACTURER_ID;
+ if (serial_no == NULL)
+ serial_no = SOFT_TOKEN_SERIAL;
+ full_token_name(token_name, manuf_id, serial_no, full_name);
+
+ /* Find the slot with token. */
+ if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
+ &pin_state)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to find token %s (%s)."), full_name,
+ pkcs11_strerror(rv));
+ return (PK_ERR_PK11);
+ }
+
+ /* Get the user's PIN. */
+ if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
+ &pinlen)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get token passphrase (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(NULL);
+ return (PK_ERR_PK11);
+ }
+
+ /* Assume user must be logged in R/W to import objects into token. */
+ if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to log into token (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ /* Setup OpenSSL context. */
+ PKTOOL_setup_openssl();
+
+ /* Open PKCS#12 file. */
+ if ((open_pkcs12(filename, &fbio)) < 0) {
+ cryptoerror(LOG_STDERR, gettext("Unable to open import file."));
+ quick_finish(sess);
+ return (PK_ERR_SYSTEM);
+ }
+
+ /* Get the PIN for the PKCS#12 import file. */
+ if ((rv = get_pin(gettext("Enter import file passphrase:"), NULL,
+ &pk12pin, &pk12pinlen)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get import file passphrase (%s)."),
+ pkcs11_strerror(rv));
+ close_pkcs12(fbio);
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ /* PKCS#12 import file may have multiple elements, loop until done. */
+ for (i = 0; /* */; i++) {
+ /* Extract the contents of the PKCS#12 import file. */
+ if ((rv = extract_pkcs12(fbio, pk12pin, pk12pinlen, &priv_key,
+ &cert, &ca)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to parse PKCS#12 element #%d "
+ "in import file (%s)."), i+1, pkcs11_strerror(rv));
+ close_pkcs12(fbio);
+ quick_finish(sess);
+ return (PK_ERR_OPENSSL);
+ }
+
+ /* Reached end of import file? */
+ if (rv == CKR_OK && priv_key == NULL && cert == NULL &&
+ ca == NULL)
+ break;
+
+ (void) fprintf(stdout, gettext(
+ "Scanning PKCS#12 element #%d for objects...\n"), i+1);
+
+ /* Write the objects to the token. */
+ if ((rv = write_token_objs(sess, priv_key, cert, ca,
+ &good_count, &bad_count)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to write PKCS#12 element #%d to token %s."),
+ i+1, full_name);
+ close_pkcs12(fbio);
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+ }
+
+ (void) fprintf(stdout, gettext("%d PKCS#12 elements scanned: "
+ "%d objects imported, %d errors occurred.\n"), i,
+ good_count, bad_count);
+
+ /* Close PKCS#12 file. */
+ close_pkcs12(fbio);
+
+ /* Clean up. */
+ quick_finish(sess);
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/list.c b/usr/src/cmd/cmd-crypto/pktool/list.c
new file mode 100644
index 0000000000..2e4bc811e5
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/list.c
@@ -0,0 +1,1016 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements the token object list operation for this tool.
+ * It loads the PKCS#11 modules, finds the object to list, lists it,
+ * and cleans up. User must be logged into the token to list private
+ * objects.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+#include "derparse.h"
+
+/*
+ * Get key size based on the key type.
+ */
+static CK_ULONG
+get_key_size(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, CK_KEY_TYPE key_type)
+{
+ CK_RV rv = CKR_OK;
+ CK_ULONG key_size;
+ CK_ATTRIBUTE modulus_sz =
+ { CKA_MODULUS, NULL, 0 }; /* RSA */
+ CK_ATTRIBUTE prime_sz =
+ { CKA_PRIME, NULL, 0 }; /* DSA, DH X9.42 */
+ CK_ATTRIBUTE value_sz =
+ { CKA_VALUE, NULL_PTR, 0 }; /* DH, DES/DES3, AES, GENERIC */
+
+ cryptodebug("inside get_key_size");
+
+ switch (key_type) {
+ case CKK_RSA:
+ if ((rv = C_GetAttributeValue(sess, obj, &modulus_sz, 1)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get modulus attribute size (%s)."),
+ pkcs11_strerror(rv));
+ } else
+ /* Convert key size to bits. */
+ key_size = modulus_sz.ulValueLen * 8;
+ break;
+ case CKK_DH:
+ if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get value attribute size (%s)."),
+ pkcs11_strerror(rv));
+ } else
+ /* Convert key size to bits. */
+ key_size = value_sz.ulValueLen * 8;
+ break;
+ case CKK_X9_42_DH:
+ case CKK_DSA:
+ if ((rv = C_GetAttributeValue(sess, obj, &prime_sz, 1)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get prime attribute size (%s)."),
+ pkcs11_strerror(rv));
+ } else
+ /* Convert key size to bits. */
+ key_size = prime_sz.ulValueLen * 8;
+ break;
+ case CKK_DES:
+ case CKK_DES3:
+ if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get value attribute size (%s)."),
+ pkcs11_strerror(rv));
+ } else
+ /* Convert key size to bits -- omitting parity bit. */
+ key_size = value_sz.ulValueLen * 7;
+ break;
+ case CKK_AES:
+ case CKK_GENERIC_SECRET:
+ if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get value attribute size (%s)."),
+ pkcs11_strerror(rv));
+ } else
+ /* Convert key size to bits. */
+ key_size = value_sz.ulValueLen * 8;
+ break;
+ default:
+ cryptoerror(LOG_STDERR, gettext(
+ "Unknown object key type (0x%02x)."), key_type);
+ break;
+ }
+
+ return (key_size);
+}
+
+/*
+ * Display private key.
+ */
+static CK_RV
+display_prikey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+{
+ CK_RV rv = CKR_OK;
+ static CK_BBOOL private;
+ static CK_BBOOL modifiable;
+ static CK_KEY_TYPE key_type;
+ CK_ULONG key_size;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_BYTE *subject = NULL;
+ CK_ULONG subject_len = 0;
+ CK_DATE *start_date = NULL;
+ CK_ULONG start_date_len = 0;
+ CK_DATE *end_date = NULL;
+ CK_ULONG end_date_len = 0;
+ CK_ATTRIBUTE attrs[18] = {
+ /* 0 to 2 */
+ { CKA_PRIVATE, &private, sizeof (private) },
+ { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
+ { CKA_KEY_TYPE, &key_type, sizeof (key_type) },
+ /* 3 to 12 */
+ { CKA_DERIVE, NULL, 0 },
+ { CKA_LOCAL, NULL, 0 },
+ { CKA_DECRYPT, NULL, 0 },
+ { CKA_SIGN, NULL, 0 },
+ { CKA_SIGN_RECOVER, NULL, 0 },
+ { CKA_UNWRAP, NULL, 0 },
+ { CKA_SENSITIVE, NULL, 0 },
+ { CKA_ALWAYS_SENSITIVE, NULL, 0 },
+ { CKA_EXTRACTABLE, NULL, 0 },
+ { CKA_NEVER_EXTRACTABLE, NULL, 0 },
+ /* 13 to 17 */
+ { CKA_LABEL, NULL, 0 }, /* optional */
+ { CKA_ID, NULL, 0 }, /* optional */
+ { CKA_SUBJECT, NULL, 0 }, /* optional */
+ { CKA_START_DATE, NULL, 0 }, /* optional */
+ { CKA_END_DATE, NULL, 0 } /* optional */
+ /* not displaying CKA_KEY_GEN_MECHANISM */
+ };
+ CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+ char *hex_id = NULL;
+ int hex_id_len = 0;
+ char *hex_subject = NULL;
+ int hex_subject_len = 0;
+
+ cryptodebug("inside display_prikey");
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get private key attribute sizes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each variable-length attribute. */
+ for (i = 3; i < n_attrs; i++) {
+ if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ attrs[i].ulValueLen == 0) {
+ cryptodebug("display_prikey: *** should not happen");
+ attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_prikey;
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get private key attributes (%s)."),
+ pkcs11_strerror(rv));
+ goto free_display_prikey;
+ }
+
+ /* Fill in all the optional temp variables. */
+ i = 13;
+ copy_attr_to_string(&(attrs[i++]), &label, &label_len);
+ copy_attr_to_string(&(attrs[i++]), &id, &id_len);
+ copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
+ copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
+ copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
+
+ /* Get the key size for the object. */
+ key_size = get_key_size(sess, obj, key_type);
+
+ /* Display the object ... */
+ /* ... the label and what it is (and key size in bits) ... */
+ (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"),
+ counter, label_len, label_len > 0 ? (char *)label :
+ gettext("<no label>"), key_size, keytype_str(key_type),
+ class_str(CKO_PRIVATE_KEY));
+
+ /* ... the id ... */
+ if (id_len == (CK_ULONG)-1 || id_len == 0)
+ (void) fprintf(stdout, gettext("\tId: --\n"));
+ else {
+ hex_id_len = 3 * id_len + 1;
+ if ((hex_id = malloc(hex_id_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_prikey;
+ }
+ octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
+ "\n\t\t", "");
+ (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
+ free(hex_id);
+ }
+
+ /* ... the subject name ... */
+ if (subject_len == (CK_ULONG)-1 || subject_len == 0)
+ (void) fprintf(stdout, gettext("\tSubject: --\n"));
+ else {
+ hex_subject_len = 2 * subject_len + 1; /* best guesstimate */
+ if ((hex_subject = malloc(hex_subject_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_prikey;
+ }
+ rdnseq_to_str(subject, subject_len, hex_subject,
+ hex_subject_len);
+ (void) fprintf(stdout, gettext("\tSubject: %.*s\n"),
+ hex_subject_len, hex_subject);
+ free(hex_subject);
+ }
+
+ /* ... the start date ... */
+ if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
+ (void) fprintf(stdout, gettext("\tStart Date: --\n"));
+ else
+ (void) fprintf(stdout, gettext(
+ "\tStart Date: %02.2s/%02.2s/%04.4s\n"),
+ start_date->month, start_date->day, start_date->year);
+
+ /* ... the end date ... */
+ if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
+ (void) fprintf(stdout, gettext("\tEnd Date: --\n"));
+ else
+ (void) fprintf(stdout, gettext(
+ "\tEnd Date: %02.2s/%02.2s/%04.4s\n"),
+ end_date->month, end_date->day, end_date->year);
+
+ /* ... and its capabilities */
+ (void) fprintf(stdout, "\t(%s, %s",
+ private != pk_false ? gettext("private") : gettext("public"),
+ modifiable == B_TRUE ? gettext("modifiable") :
+ gettext("not modifiable"));
+ for (i = 3; i <= 12; i++) {
+ if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ attrs[i].ulValueLen != 0 &&
+ *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
+ (void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
+ }
+ (void) fprintf(stdout, ")\n");
+
+free_display_prikey:
+ for (i = 3; i < n_attrs; i++)
+ if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ attrs[i].ulValueLen != 0)
+ free(attrs[i].pValue);
+ return (rv);
+}
+
+/*
+ * Display public key.
+ */
+static CK_RV
+display_pubkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+{
+ CK_RV rv = CKR_OK;
+ static CK_BBOOL private;
+ static CK_BBOOL modifiable;
+ static CK_BBOOL trusted;
+ static CK_KEY_TYPE key_type;
+ CK_ULONG key_size;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_BYTE *subject = NULL;
+ CK_ULONG subject_len = 0;
+ CK_DATE *start_date = NULL;
+ CK_ULONG start_date_len = 0;
+ CK_DATE *end_date = NULL;
+ CK_ULONG end_date_len = 0;
+ CK_ATTRIBUTE attrs[15] = {
+ /* 0 to 3 */
+ { CKA_PRIVATE, &private, sizeof (private) },
+ { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
+ { CKA_TRUSTED, &trusted, sizeof (trusted) },
+ { CKA_KEY_TYPE, &key_type, sizeof (key_type) },
+ /* 4 to 9 */
+ { CKA_DERIVE, NULL, 0 },
+ { CKA_LOCAL, NULL, 0 },
+ { CKA_ENCRYPT, NULL, 0 },
+ { CKA_VERIFY, NULL, 0 },
+ { CKA_VERIFY_RECOVER, NULL, 0 },
+ { CKA_WRAP, NULL, 0 },
+ /* 10 to 14 */
+ { CKA_LABEL, NULL, 0 }, /* optional */
+ { CKA_ID, NULL, 0 }, /* optional */
+ { CKA_SUBJECT, NULL, 0 }, /* optional */
+ { CKA_START_DATE, NULL, 0 }, /* optional */
+ { CKA_END_DATE, NULL, 0 } /* optional */
+ /* not displaying CKA_KEY_GEN_MECHANISM */
+ };
+ CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+ char *hex_id = NULL;
+ int hex_id_len = 0;
+ char *hex_subject = NULL;
+ int hex_subject_len = 0;
+
+ cryptodebug("inside display_pubkey");
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get public key attribute sizes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each variable-length attribute. */
+ for (i = 4; i < n_attrs; i++) {
+ if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ attrs[i].ulValueLen == 0) {
+ cryptodebug("display_pubkey: *** should not happen");
+ attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_pubkey;
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get public key attributes (%s)."),
+ pkcs11_strerror(rv));
+ goto free_display_pubkey;
+ }
+
+ /* Fill in all the optional temp variables. */
+ i = 10;
+ copy_attr_to_string(&(attrs[i++]), &label, &label_len);
+ copy_attr_to_string(&(attrs[i++]), &id, &id_len);
+ copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
+ copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
+ copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
+
+ /* Get the key size for the object. */
+ key_size = get_key_size(sess, obj, key_type);
+
+ /* Display the object ... */
+ /* ... the label and what it is (and key size in bits) ... */
+ (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"),
+ counter, label_len, label_len > 0 ? (char *)label :
+ gettext("<no label>"), key_size, keytype_str(key_type),
+ class_str(CKO_PUBLIC_KEY));
+
+ /* ... the id ... */
+ if (id_len == (CK_ULONG)-1 || id_len == 0)
+ (void) fprintf(stdout, gettext("\tId: --\n"));
+ else {
+ hex_id_len = 3 * id_len + 1;
+ if ((hex_id = malloc(hex_id_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_pubkey;
+ }
+ octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
+ "\n\t\t", "");
+ (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
+ free(hex_id);
+ }
+
+ /* ... the subject name ... */
+ if (subject_len == (CK_ULONG)-1 || subject_len == 0)
+ (void) fprintf(stdout, gettext("\tSubject: --\n"));
+ else {
+ hex_subject_len = 2 * subject_len + 1; /* best guesstimate */
+ if ((hex_subject = malloc(hex_subject_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_pubkey;
+ }
+ rdnseq_to_str(subject, subject_len, hex_subject,
+ hex_subject_len);
+ (void) fprintf(stdout, gettext("\tSubject: %.*s\n"),
+ hex_subject_len, hex_subject);
+ free(hex_subject);
+ }
+
+ /* ... the start date ... */
+ if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
+ (void) fprintf(stdout, gettext("\tStart Date: --\n"));
+ else
+ (void) fprintf(stdout, gettext(
+ "\tStart Date: %02.2s/%02.2s/%04.4s\n"),
+ start_date->month, start_date->day, start_date->year);
+
+ /* ... the end date ... */
+ if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
+ (void) fprintf(stdout, gettext("\tEnd Date: --\n"));
+ else
+ (void) fprintf(stdout, gettext(
+ "\tEnd Date: %02.2s/%02.2s/%04.4s\n"),
+ end_date->month, end_date->day, end_date->year);
+
+ /* ... and its capabilities */
+ (void) fprintf(stdout, "\t(%s, %s, %s",
+ private == B_TRUE ? gettext("private") : gettext("public"),
+ modifiable == B_TRUE ? gettext("modifiable") :
+ gettext("not modifiable"),
+ trusted == B_TRUE ? gettext("trusted") : gettext("untrusted"));
+ for (i = 4; i <= 9; i++) {
+ if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ attrs[i].ulValueLen != 0 &&
+ *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
+ (void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
+ }
+ (void) fprintf(stdout, ")\n");
+
+free_display_pubkey:
+ for (i = 4; i < n_attrs; i++)
+ if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ attrs[i].ulValueLen != 0)
+ free(attrs[i].pValue);
+ return (rv);
+}
+
+/*
+ * Display secret key.
+ */
+static CK_RV
+display_seckey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+{
+ CK_RV rv = CKR_OK;
+ static CK_BBOOL private;
+ static CK_BBOOL modifiable;
+ static CK_KEY_TYPE key_type;
+ static CK_ULONG key_size;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_DATE *start_date = NULL;
+ CK_ULONG start_date_len = 0;
+ CK_DATE *end_date = NULL;
+ CK_ULONG end_date_len = 0;
+ CK_ATTRIBUTE attrs[19] = {
+ /* 0 to 2 */
+ { CKA_PRIVATE, &private, sizeof (private) },
+ { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
+ { CKA_KEY_TYPE, &key_type, sizeof (key_type) },
+ /* 3 to 14 */
+ { CKA_DERIVE, NULL, 0 },
+ { CKA_LOCAL, NULL, 0 },
+ { CKA_ENCRYPT, NULL, 0 },
+ { CKA_DECRYPT, NULL, 0 },
+ { CKA_SIGN, NULL, 0 },
+ { CKA_VERIFY, NULL, 0 },
+ { CKA_WRAP, NULL, 0 },
+ { CKA_UNWRAP, NULL, 0 },
+ { CKA_SENSITIVE, NULL, 0 },
+ { CKA_ALWAYS_SENSITIVE, NULL, 0 },
+ { CKA_EXTRACTABLE, NULL, 0 },
+ { CKA_NEVER_EXTRACTABLE, 0 },
+ /* 15 to 18 */
+ { CKA_LABEL, NULL, 0 }, /* optional */
+ { CKA_ID, NULL, 0 }, /* optional */
+ { CKA_START_DATE, NULL, 0 }, /* optional */
+ { CKA_END_DATE, NULL, 0 } /* optional */
+ /* not displaying CKA_KEY_GEN_MECHANISM */
+ };
+ CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+ char *hex_id = NULL;
+ int hex_id_len = 0;
+
+ cryptodebug("inside display_seckey");
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get secret key attribute sizes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each variable-length attribute. */
+ for (i = 3; i < n_attrs; i++) {
+ if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ attrs[i].ulValueLen == 0) {
+ cryptodebug("display_seckey: *** should not happen");
+ attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_seckey;
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get secret key attributes (%s)."),
+ pkcs11_strerror(rv));
+ goto free_display_seckey;
+ }
+
+ /* Fill in all the optional temp variables. */
+ i = 15;
+ copy_attr_to_string(&(attrs[i++]), &label, &label_len);
+ copy_attr_to_string(&(attrs[i++]), &id, &id_len);
+ copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
+ copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
+
+ /* Get the key size for the object. */
+ key_size = get_key_size(sess, obj, key_type);
+
+ /* Display the object ... */
+ /* ... the label and what it is (and key size in bytes) ... */
+ (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"),
+ counter, label_len, label_len > 0 ? (char *)label :
+ gettext("<no label>"), key_size, keytype_str(key_type),
+ class_str(CKO_SECRET_KEY));
+
+ /* ... the id ... */
+ if (id_len == (CK_ULONG)-1 || id_len == 0)
+ (void) fprintf(stdout, gettext("\tId: --\n"));
+ else {
+ hex_id_len = 3 * id_len + 1;
+ if ((hex_id = malloc(hex_id_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_seckey;
+ }
+ octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
+ "\n\t\t", "");
+ (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
+ free(hex_id);
+ }
+
+ /* ... the start date ... */
+ if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
+ (void) fprintf(stdout, gettext("\tStart Date: --\n"));
+ else
+ (void) fprintf(stdout, gettext(
+ "\tStart Date: %02.2s/%02.2s/%04.4s\n"),
+ start_date->month, start_date->day, start_date->year);
+
+ /* ... the end date ... */
+ if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
+ (void) fprintf(stdout, gettext("\tEnd Date: --\n"));
+ else
+ (void) fprintf(stdout, gettext(
+ "\tEnd Date: %02.2s/%02.2s/%04.4s\n"),
+ end_date->month, end_date->day, end_date->year);
+
+ /* ... and its capabilities */
+ (void) fprintf(stdout, "\t(%s, %s",
+ private == B_TRUE ? gettext("private") : gettext("public"),
+ modifiable == B_TRUE ? gettext("modifiable") :
+ gettext("not modifiable"));
+ for (i = 3; i <= 14; i++) {
+ if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ attrs[i].ulValueLen != 0 &&
+ *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
+ (void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
+ }
+ (void) fprintf(stdout, ")\n");
+
+free_display_seckey:
+ for (i = 3; i < n_attrs; i++)
+ if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ attrs[i].ulValueLen != 0)
+ free(attrs[i].pValue);
+ return (rv);
+}
+
+/*
+ * Display certificate.
+ */
+static CK_RV
+display_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
+{
+ CK_RV rv = CKR_OK;
+ static CK_BBOOL private;
+ static CK_BBOOL modifiable;
+ static CK_BBOOL trusted;
+ CK_BYTE *subject = NULL;
+ CK_ULONG subject_len = 0;
+ CK_BYTE *value = NULL;
+ CK_ULONG value_len = 0;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_BYTE *id = NULL;
+ CK_ULONG id_len = 0;
+ CK_BYTE *issuer = NULL;
+ CK_ULONG issuer_len = 0;
+ CK_BYTE *serial = NULL;
+ CK_ULONG serial_len = 0;
+ CK_ATTRIBUTE attrs[9] = {
+ { CKA_PRIVATE, &private, sizeof (private) },
+ { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
+ { CKA_TRUSTED, &trusted, sizeof (trusted) },
+ { CKA_SUBJECT, NULL, 0 }, /* required */
+ { CKA_VALUE, NULL, 0 }, /* required */
+ { CKA_LABEL, NULL, 0 }, /* optional */
+ { CKA_ID, NULL, 0 }, /* optional */
+ { CKA_ISSUER, NULL, 0 }, /* optional */
+ { CKA_SERIAL_NUMBER, NULL, 0 } /* optional */
+ };
+ CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+ char *hex_id = NULL;
+ int hex_id_len = 0;
+ char *hex_subject = NULL;
+ int hex_subject_len = 0;
+ char *hex_issuer = NULL;
+ int hex_issuer_len = 0;
+ char *hex_serial = NULL;
+ int hex_serial_len = NULL;
+ uint32_t serial_value = 0;
+ char *hex_value = NULL;
+ int hex_value_len = 0;
+
+ cryptodebug("inside display_cert");
+
+ /* Get the sizes of the attributes we need. */
+ cryptodebug("calling C_GetAttributeValue for size info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get certificate attribute sizes (%s)."),
+ pkcs11_strerror(rv));
+ return (rv);
+ }
+
+ /* Allocate memory for each variable-length attribute. */
+ for (i = 3; i < n_attrs; i++) {
+ if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ attrs[i].ulValueLen == 0) {
+ cryptodebug("display_cert: *** should not happen");
+ attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_cert;
+ }
+ }
+
+ /* Now really get the attributes. */
+ cryptodebug("calling C_GetAttributeValue for attribute info");
+ if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get certificate attributes (%s)."),
+ pkcs11_strerror(rv));
+ goto free_display_cert;
+ }
+
+ /*
+ * Fill in all the temp variables. Subject and value are required.
+ * The rest are optional.
+ */
+ i = 3;
+ copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
+ copy_attr_to_string(&(attrs[i++]), &value, &value_len);
+ copy_attr_to_string(&(attrs[i++]), &label, &label_len);
+ copy_attr_to_string(&(attrs[i++]), &id, &id_len);
+ copy_attr_to_string(&(attrs[i++]), &issuer, &issuer_len);
+ copy_attr_to_string(&(attrs[i++]), &serial, &serial_len);
+
+ /* Display the object ... */
+ /* ... the label and what it is ... */
+ (void) fprintf(stdout, gettext("%d. \"%.*s\" (%s %s)\n"),
+ counter, label_len, label_len > 0 ? (char *)label :
+ gettext("<no label>"), "X.509", class_str(CKO_CERTIFICATE));
+
+ /* ... its capabilities ... */
+ (void) fprintf(stdout, gettext("\t(%s, %s, %s)\n"),
+ private == B_TRUE ? gettext("private") : gettext("public"),
+ modifiable == B_TRUE ? gettext("modifiable") :
+ gettext("not modifiable"),
+ trusted == B_TRUE ? gettext("trusted") : gettext("untrusted"));
+
+ /* ... the id ... */
+ if (id_len == (CK_ULONG)-1 || id_len == 0)
+ (void) fprintf(stdout, gettext("\tId: --\n"));
+ else {
+ hex_id_len = 3 * id_len + 1;
+ if ((hex_id = malloc(hex_id_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_cert;
+ }
+ octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
+ "\n\t\t", "");
+ (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id);
+ free(hex_id);
+ }
+
+ /* ... the subject name ... */
+ if (subject_len == (CK_ULONG)-1 || subject_len == 0)
+ (void) fprintf(stdout, gettext("\tSubject: --\n"));
+ else {
+ hex_subject_len = 2 * subject_len + 1; /* best guesstimate */
+ if ((hex_subject = malloc(hex_subject_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_cert;
+ }
+ rdnseq_to_str(subject, subject_len, hex_subject,
+ hex_subject_len);
+ (void) fprintf(stdout, gettext("\tSubject: %.*s\n"),
+ hex_subject_len, hex_subject);
+ free(hex_subject);
+ }
+
+ /* ... the issuer name ... */
+ if (issuer_len == (CK_ULONG)-1 || issuer_len == 0)
+ (void) fprintf(stdout, gettext("\tIssuer: --\n"));
+ else {
+ hex_issuer_len = 2 * issuer_len + 1; /* best guesstimate */
+ if ((hex_issuer = malloc(hex_issuer_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_cert;
+ }
+ rdnseq_to_str(issuer, issuer_len, hex_issuer, hex_issuer_len);
+ (void) fprintf(stdout, gettext("\tIssuer: %.*s\n"),
+ hex_issuer_len, hex_issuer);
+ free(hex_issuer);
+ }
+
+ /* ... the serial number ... */
+ if (serial_len == (CK_ULONG)-1 || serial_len == 0)
+ (void) fprintf(stdout, gettext("\tSerial: --\n"));
+ else {
+ hex_serial_len = 3 * serial_len + 1;
+ if ((hex_serial = malloc(hex_serial_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_cert;
+ }
+ octetify(serial, serial_len, hex_serial, hex_serial_len,
+ B_FALSE, B_FALSE, 60, "\n\t\t", "");
+ if (serial_len > 4)
+ (void) fprintf(stdout, gettext("\tSerial: %s\n"),
+ hex_serial);
+ else {
+ for (i = 0; i < serial_len; i++) {
+ serial_value <<= 8;
+ serial_value |= (serial[i] & 0xff);
+ }
+ (void) fprintf(stdout, gettext("\tSerial: %s (%d)\n"),
+ hex_serial, serial_value);
+ }
+ free(hex_serial);
+ }
+
+ /* ... and the value */
+ if (value_len == (CK_ULONG)-1 || value_len == 0)
+ (void) fprintf(stdout, gettext("\tValue: --\n"));
+ else {
+ hex_value_len = 3 * value_len + 1;
+ if ((hex_value = malloc(hex_value_len)) == NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ rv = CKR_HOST_MEMORY;
+ goto free_display_cert;
+ }
+ octetify(value, value_len, hex_value, hex_value_len,
+ B_FALSE, B_FALSE, 60, "\n\t\t", "");
+ (void) fprintf(stdout, gettext("\tValue: %s\n"), hex_value);
+ free(hex_value);
+ }
+
+free_display_cert:
+ for (i = 3; i < n_attrs; i++)
+ if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ attrs[i].ulValueLen != 0)
+ free(attrs[i].pValue);
+ return (rv);
+}
+
+/*
+ * List token object.
+ */
+int
+pk_list(int argc, char *argv[])
+{
+ int opt;
+ extern int optind;
+ extern char *optarg;
+ char *token_name = NULL;
+ char *manuf_id = NULL;
+ char *serial_no = NULL;
+ char full_name[FULL_NAME_LEN];
+ boolean_t public_objs = B_FALSE;
+ boolean_t private_objs = B_FALSE;
+ CK_BYTE *list_label = NULL;
+ int obj_type = 0x00;
+ CK_SLOT_ID slot_id;
+ CK_FLAGS pin_state;
+ CK_UTF8CHAR_PTR pin = NULL;
+ CK_ULONG pinlen = 0;
+ CK_SESSION_HANDLE sess;
+ CK_OBJECT_HANDLE *objs;
+ CK_ULONG num_objs;
+ CK_RV rv = CKR_OK;
+ int i;
+ static CK_OBJECT_CLASS objclass;
+ CK_ATTRIBUTE class_attr =
+ { CKA_CLASS, &objclass, sizeof (objclass) };
+
+ cryptodebug("inside pk_list");
+
+ /* Parse command line options. Do NOT i18n/l10n. */
+ while ((opt = getopt(argc, argv, "p(private)P(public)l:(label)")) !=
+ EOF) {
+ switch (opt) {
+ case 'p': /* private objects */
+ private_objs = B_TRUE;
+ obj_type |= PK_PRIVATE_OBJ;
+ break;
+ case 'P': /* public objects */
+ public_objs = B_TRUE;
+ obj_type |= PK_PUBLIC_OBJ;
+ break;
+ case 'l': /* object with specific label */
+ if (list_label)
+ return (PK_ERR_USAGE);
+ list_label = (CK_BYTE *)optarg;
+ break;
+ default:
+ return (PK_ERR_USAGE);
+ break;
+ }
+ }
+
+ /* If nothing specified, default is public objects. */
+ if (!public_objs && !private_objs) {
+ public_objs = B_TRUE;
+ obj_type |= PK_PUBLIC_OBJ;
+ }
+
+ /* No additional args allowed. */
+ argc -= optind;
+ argv += optind;
+ if (argc)
+ return (PK_ERR_USAGE);
+ /* Done parsing command line options. */
+
+ /* List operation only supported on softtoken. */
+ if (token_name == NULL)
+ token_name = SOFT_TOKEN_LABEL;
+ if (manuf_id == NULL)
+ manuf_id = SOFT_MANUFACTURER_ID;
+ if (serial_no == NULL)
+ serial_no = SOFT_TOKEN_SERIAL;
+ full_token_name(token_name, manuf_id, serial_no, full_name);
+
+ /* Find the slot with token. */
+ if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
+ &pin_state)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to find token %s (%s)."), full_name,
+ pkcs11_strerror(rv));
+ return (PK_ERR_PK11);
+ }
+
+ /* If private objects are to be listed, user must be logged in. */
+ if (private_objs) {
+ /* Get the user's PIN. */
+ if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
+ &pin, &pinlen)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to get token passphrase (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(NULL);
+ return (PK_ERR_PK11);
+ }
+
+ /* Logging in user R/O into the token is sufficient. */
+ cryptodebug("logging in with readonly session");
+ if ((rv = quick_start(slot_id, 0, pin, pinlen, &sess)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to log into token (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+ /* Otherwise, just create a session. */
+ } else {
+ cryptodebug("opening a readonly session");
+ if ((rv = open_sess(slot_id, 0, &sess)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to open token session (%s)."),
+ pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+ }
+
+ /* Find the object(s) with the given label and/or type. */
+ if ((rv = find_objs(sess, obj_type, list_label, &objs, &num_objs)) !=
+ CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to find token objects (%s)."), pkcs11_strerror(rv));
+ quick_finish(sess);
+ return (PK_ERR_PK11);
+ }
+
+ if (num_objs == 0) {
+ cryptoerror(LOG_STDERR, gettext("No objects found."));
+ quick_finish(sess);
+ return (0);
+ }
+
+ /* List the objects found. */
+ for (i = 0; i < num_objs; i++) {
+ /* Get object class first, then decide what is next. */
+ cryptodebug("calling C_GetAttributeValue for object class");
+ if ((rv = C_GetAttributeValue(sess, objs[i], &class_attr, 1))
+ != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get object #%d class attribute (%s)."),
+ i+1, pkcs11_strerror(rv));
+ continue;
+ }
+
+ /* Display based on the type of object. */
+ switch (objclass) {
+ case CKO_CERTIFICATE:
+ if ((rv = display_cert(sess, objs[i], i+1)) != CKR_OK)
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to display certificate."));
+ break;
+ case CKO_PUBLIC_KEY:
+ if ((rv = display_pubkey(sess, objs[i], i+1)) != CKR_OK)
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to display public key."));
+ break;
+ case CKO_PRIVATE_KEY:
+ if ((rv = display_prikey(sess, objs[i], i+1)) != CKR_OK)
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to display private key."));
+ break;
+ case CKO_SECRET_KEY:
+ if ((rv = display_seckey(sess, objs[i], i+1)) != CKR_OK)
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to display secret key."));
+ break;
+ case CKO_DATA:
+ cryptoerror(LOG_STDERR,
+ gettext("Data object display not implemented."));
+ break;
+ default:
+ cryptoerror(LOG_STDERR, gettext(
+ "Unknown token object class (0x%02x)."), objclass);
+ break;
+ }
+ }
+
+ /* Clean up. */
+ quick_finish(sess);
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/osslcommon.c b/usr/src/cmd/cmd-crypto/pktool/osslcommon.c
new file mode 100644
index 0000000000..84b4fdbdce
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/osslcommon.c
@@ -0,0 +1,224 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements some "missing" routines that should
+ * be part of the OpenSSL library but are not there yet.
+ */
+
+#include <cryptoutil.h>
+#include "osslcommon.h"
+#include <openssl/pkcs12.h>
+#include <openssl/engine.h>
+
+/*
+ * OpenSSL usage needs algorithms (ciphers and digests), strings,
+ * and engines loaded first to be useful.
+ */
+void
+PKTOOL_setup_openssl(void)
+{
+ cryptodebug("inside PKTOOL_setup_openssl");
+
+ /* Add all ciphers and digests. */
+ OpenSSL_add_all_algorithms();
+
+ /* Load up error message strings. */
+ ERR_load_crypto_strings();
+
+ /* Load up PKCS#11 engine. */
+ /* ENGINE_load_pk11(); */
+
+ /* Load up builtin crypto engines. */
+ /*
+ * This function is actually defined in OpenSSL libcrypto
+ * library. However it doesn't make its lint library correctly
+ * which is why this lint error occurs. OpenSSL needs fixing.
+ * Do not put a LINTED comment here because lint will complain
+ * that the directive is ununsed.
+ */
+ ENGINE_load_builtin_engines();
+
+ /* U/I methods are not necessary here. */
+ /* setup_ui_method(); */
+}
+
+/*
+ * This should be an OpenSSL function, but they haven't added it yet.
+ * See <openssl>/crypto/asn1/x_x509a.c:X509_alias_get0() for the model.
+ */
+unsigned char *
+PKTOOL_X509_keyid_get0(X509 *x, int *len)
+{
+ cryptodebug("inside PKTOOL_setup_openssl");
+
+ if (x->aux == NULL || x->aux->keyid == NULL) {
+ cryptodebug("certificate aux or aux->keyid is null");
+ return (NULL);
+ }
+ if (len)
+ *len = x->aux->keyid->length;
+ return (x->aux->keyid->data);
+}
+
+/*
+ * This should be an OpenSSL function, but couldn't find it yet.
+ * It gets the subject name safely without dereferencing null pointers.
+ * If it is ever found in OpenSSL, this should be removed and all
+ * calls to it need to be replaced with right OpenSSL function.
+ */
+unsigned char *
+PKTOOL_X509_subject_name(X509 *x, int *len)
+{
+ X509_NAME *temp;
+
+ cryptodebug("inside PKTOOL_X509_subject_name");
+
+ if ((temp = X509_get_subject_name(x)) == NULL) {
+ cryptodebug("certificate subject name stack is null");
+ return (NULL);
+ }
+ if (temp->bytes == NULL) {
+ cryptodebug("certificate subject name stack bytes is null");
+ return (NULL);
+ }
+ if (len)
+ *len = temp->bytes->length;
+ return ((unsigned char *)temp->bytes->data);
+}
+
+/*
+ * This should be an OpenSSL function, but couldn't find it yet.
+ * It gets the issuer name safely without dereferencing null pointers.
+ * If it is ever found in OpenSSL, this should be removed and all
+ * calls to it need to be replaced with right OpenSSL function.
+ */
+unsigned char *
+PKTOOL_X509_issuer_name(X509 *x, int *len)
+{
+ X509_NAME *temp;
+
+ cryptodebug("inside PKTOOL_X509_issuer_name");
+
+ if ((temp = X509_get_issuer_name(x)) == NULL) {
+ cryptodebug("certificate issuer name stack is null");
+ return (NULL);
+ }
+ if (temp->bytes == NULL) {
+ cryptodebug("certificate issuer name stack bytes is null");
+ return (NULL);
+ }
+ if (len)
+ *len = temp->bytes->length;
+ return ((unsigned char *)temp->bytes->data);
+}
+
+/*
+ * This should be an OpenSSL function, but couldn't find it yet.
+ * It gets the serial number safely without dereferencing null pointers.
+ * If it is ever found in OpenSSL, this should be removed and all
+ * calls to it need to be replaced with right OpenSSL function.
+ */
+unsigned char *
+PKTOOL_X509_serial_number(X509 *x, int *len)
+{
+ ASN1_INTEGER *temp;
+
+ cryptodebug("inside PKTOOL_X509_serial_number");
+
+ if ((temp = X509_get_serialNumber(x)) == NULL) {
+ cryptodebug("certificate serial number is null");
+ return (NULL);
+ }
+ if (len)
+ *len = temp->length;
+ return (temp->data);
+}
+
+/*
+ * This should be an OpenSSL function, but couldn't find it yet.
+ * It gets the cert value safely without dereferencing null pointers.
+ * If it is ever found in OpenSSL, this should be removed and all
+ * calls to it need to be replaced with right OpenSSL function.
+ */
+unsigned char *
+PKTOOL_X509_cert_value(X509 *x, int *len)
+{
+ PKCS12_SAFEBAG *bag;
+
+ cryptodebug("inside PKTOOL_X509_cert_value");
+
+ if ((bag = PKCS12_x5092certbag(x)) == NULL) {
+ cryptodebug("unable to convert cert to PKCS#12 bag");
+ return (NULL);
+ }
+ if (bag->value.bag == NULL || bag->value.bag->value.x509cert == NULL) {
+ cryptodebug("PKCS#12 bag value or cert inside it is null");
+ return (NULL);
+ }
+ if (len)
+ *len = bag->value.bag->value.x509cert->length;
+ return (bag->value.bag->value.x509cert->data);
+}
+
+/*
+ * Convert OpenSSL's ASN1_TIME format into a character buffer that
+ * can then be converted into PKCS#11 format. The buffer must be
+ * at least 8 bytes long. The length of the result will be 8 bytes.
+ * Return value of 0 indicates failure, 1 indicates success.
+ */
+int
+PKTOOL_cvt_ossltime(ASN1_TIME *t, char *buf)
+{
+ cryptodebug("inside PKTOOL_cvt_ossltime");
+
+ if (t == NULL) {
+ cryptodebug("time string is empty");
+ buf[0] = '\0';
+ return (0);
+ }
+
+ if (t->length == 15) { /* generalized time: YYYYMMDDmmhhssZ */
+ cryptodebug("time string is in generalized format");
+ (void) snprintf(buf, 8, "%08.8s", t->data);
+ return (1);
+ }
+
+ if (t->length == 13) { /* UTC time: YYMMDDmmhhssZ */
+ cryptodebug("time string is in UTC format");
+ /* Guess whether its a 197x to 199x date, or a 20xx date. */
+ (void) snprintf(buf, 8, "%s%06.6s",
+ ('7' <= t->data[0] && t->data[0] <= '9') ? "19" : "20",
+ t->data);
+ return (1);
+ }
+
+ cryptodebug("time string is in unknown format");
+ buf[0] = '\0';
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/osslcommon.h b/usr/src/cmd/cmd-crypto/pktool/osslcommon.h
new file mode 100644
index 0000000000..098d0e1f6a
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/osslcommon.h
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PKTOOL_OSSLCOMMON_H
+#define _PKTOOL_OSSLCOMMON_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <openssl/x509.h>
+
+extern void PKTOOL_setup_openssl(void);
+extern unsigned char *PKTOOL_X509_keyid_get0(X509 *x, int *len);
+extern unsigned char *PKTOOL_X509_subject_name(X509 *x, int *len);
+extern unsigned char *PKTOOL_X509_issuer_name(X509 *x, int *len);
+extern unsigned char *PKTOOL_X509_serial_number(X509 *x, int *len);
+extern unsigned char *PKTOOL_X509_cert_value(X509 *x, int *len);
+extern int PKTOOL_cvt_ossltime(ASN1_TIME *t, char *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKTOOL_OSSLCOMMON_H */
diff --git a/usr/src/cmd/cmd-crypto/pktool/p12common.c b/usr/src/cmd/cmd-crypto/pktool/p12common.c
new file mode 100644
index 0000000000..4e164ea911
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/p12common.c
@@ -0,0 +1,103 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements some of the common PKCS#12 routines.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <cryptoutil.h>
+#include "p12common.h"
+#include <openssl/pkcs12.h>
+
+/* I18N helpers. */
+#include <libintl.h>
+#include <locale.h>
+
+/*
+ * Common function to create/open PKCS#12 files.
+ */
+static int
+pkcs12_file(char *filename, boolean_t create, BIO **fbio)
+{
+ cryptodebug("inside pkcs12_file");
+
+ if (fbio == NULL) {
+ cryptoerror(LOG_STDERR, create ?
+ gettext("Error creating file \"%s\", invalid input.") :
+ gettext("Error opening file \"%s\", invalid input."),
+ filename);
+ return (-1);
+ }
+
+ cryptodebug(create ? "creating %s for binary writes" :
+ "opening %s for binary reads", filename);
+ if ((*fbio = BIO_new_file(filename, create ? "wb" : "rb")) == NULL) {
+ cryptoerror(LOG_STDERR, create ?
+ gettext("Error creating file \"%s\" (%s).") :
+ gettext("Error opening file \"%s\" (%s)."),
+ filename, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Create PKCS#12 export file.
+ */
+int
+create_pkcs12(char *filename, BIO **fbio)
+{
+ cryptodebug("inside create_pkcs12");
+
+ return (pkcs12_file(filename, B_TRUE, fbio));
+}
+
+/*
+ * Opens PKCS#12 import file.
+ */
+int
+open_pkcs12(char *filename, BIO **fbio)
+{
+ cryptodebug("inside open_pkcs12");
+
+ return (pkcs12_file(filename, B_FALSE, fbio));
+}
+
+/*
+ * Closes PKCS#12 export file.
+ */
+void
+close_pkcs12(BIO *fbio)
+{
+ cryptodebug("inside close_pkcs12");
+
+ BIO_free_all(fbio);
+}
diff --git a/usr/src/cmd/cmd-crypto/pktool/p12common.h b/usr/src/cmd/cmd-crypto/pktool/p12common.h
new file mode 100644
index 0000000000..03a2a6ae5e
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/p12common.h
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PKTOOL_P12COMMON_H
+#define _PKTOOL_P12COMMON_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <openssl/bio.h>
+
+extern int create_pkcs12(char *filename, BIO **fbio);
+extern int open_pkcs12(char *filename, BIO **fbio);
+extern void close_pkcs12(BIO *fbio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKTOOL_P12COMMON_H */
diff --git a/usr/src/cmd/cmd-crypto/pktool/pktool.c b/usr/src/cmd/cmd-crypto/pktool/pktool.c
index 1d7a185e61..0ed4d18efd 100644
--- a/usr/src/cmd/cmd-crypto/pktool/pktool.c
+++ b/usr/src/cmd/cmd-crypto/pktool/pktool.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,6 +28,9 @@
/*
* This file comprises the main driver for this tool.
+ * Upon parsing the command verbs from user input, it
+ * branches to the appropriate modules to perform the
+ * requested task.
*/
#include <stdio.h>
@@ -48,16 +51,33 @@
typedef struct verbcmd_s {
char *verb;
int (*action)(int, char *[]);
- int mode; /* reserved */
- char *synopsis; /* reserved */
+ int mode;
+ char *synopsis;
} verbcmd;
/* External declarations for supported verb actions. */
extern int pk_setpin(int argc, char *argv[]);
+extern int pk_list(int argc, char *argv[]);
+extern int pk_delete(int argc, char *argv[]);
+extern int pk_import(int argc, char *argv[]);
+extern int pk_export(int argc, char *argv[]);
+extern int pk_tokens(int argc, char *argv[]);
+
+/* Forward declarations for "built-in" verb actions. */
+static int pk_help(int argc, char *argv[]);
/* Command structure for verbs and their actions. Do NOT i18n/l10n. */
static verbcmd cmds[] = {
- { "setpin", pk_setpin, 0, "" },
+ { "tokens", pk_tokens, 0, "tokens" },
+ { "setpin", pk_setpin, 0, "setpin" },
+ { "list", pk_list, 0, "list [-p] [-P] [-l <label>]"
+ "\n\t\tor list [--public] [--private] [--label[=]<label>]" },
+ { "delete", pk_delete, 0,
+ "delete { [-p] [-P] [-l <label>] }"
+ "\n\t\tor delete { [--public] [--private] [--label[=]<label>] }" },
+ { "import", pk_import, 0, "import <file>" },
+ { "export", pk_export, 0, "export <file>" },
+ { "-?", pk_help, 0, "--help\t(help and usage)" },
};
static int num_cmds = sizeof (cmds) / sizeof (verbcmd);
@@ -71,8 +91,34 @@ static void usage(void);
static void
usage(void)
{
- (void) fprintf(stderr, gettext("Usage:\n"));
- (void) fprintf(stderr, gettext("\t%s setpin\n"), prog);
+ int i;
+
+ cryptodebug("inside usage");
+
+ /* Display this block only in command-line mode. */
+ (void) fprintf(stdout, gettext("Usage:\n"));
+ (void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog);
+ (void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog);
+ (void) fprintf(stdout, gettext("where subcommands may be:\n"));
+
+ /* Display only those verbs that match the current tool mode. */
+ for (i = 0; i < num_cmds; i++) {
+ /* Do NOT i18n/l10n. */
+ (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis);
+ }
+}
+
+/*
+ * Provide help, in the form of displaying the usage.
+ */
+static int
+pk_help(int argc, char *argv[])
+/* ARGSUSED */
+{
+ cryptodebug("inside pk_help");
+
+ usage();
+ return (0);
}
/*
@@ -86,6 +132,7 @@ main(int argc, char *argv[], char *envp[])
int rv;
int pk_argc = 0;
char **pk_argv = NULL;
+ int save_errno = 0;
/* Set up for i18n/l10n. */
(void) setlocale(LC_ALL, "");
@@ -101,122 +148,88 @@ main(int argc, char *argv[], char *envp[])
/* Set up for debug and error output. */
cryptodebug_init(prog);
- /* There must be one remaining arg at this point */
if (argc == 0) {
usage();
return (1);
}
- /*
- * By default, metaslot is enabled, and pkcs11_softtoken is
- * the keystore, so, pkcs11_softtoken is hidden.
- * Always turns off Metaslot so that we can see pkcs11_softtoken.
- */
+ /* Check for help options. For CLIP-compliance. */
+ if (argc == 1 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case '?':
+ return (pk_help(argc, argv));
+ default:
+ usage();
+ return (1);
+ }
+ }
+
+ /* Always turns off Metaslot so that we can see softtoken. */
+ cryptodebug("disabling Metaslot");
if (setenv("METASLOT_ENABLED", "false", 1) < 0) {
- pk11_errno = errno;
+ save_errno = errno;
cryptoerror(LOG_STDERR,
- gettext("Disabling metaslot failed: %s"),
- strerror(pk11_errno));
+ gettext("Disabling Metaslot failed (%s)."),
+ strerror(save_errno));
return (1);
}
/* Begin parsing command line. */
+ cryptodebug("begin parsing command line");
pk_argc = argc;
pk_argv = argv;
- /* Check for valid verb */
+ /* Check for valid verb (or an abbreviation of it). */
found = -1;
for (i = 0; i < num_cmds; i++) {
if (strcmp(cmds[i].verb, pk_argv[0]) == 0) {
if (found < 0) {
+ cryptodebug("found cmd %s", cmds[i].verb);
found = i;
break;
+ } else {
+ cryptodebug("also found cmd %s, skipping",
+ cmds[i].verb);
}
}
}
-
/* Stop here if no valid verb found. */
if (found < 0) {
- cryptoerror(LOG_STDERR,
- gettext("Invalid verb: %s"), pk_argv[0]);
+ cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"),
+ pk_argv[0]);
return (1);
}
/* Get to work! */
+ cryptodebug("begin executing cmd action");
rv = (*cmds[found].action)(pk_argc, pk_argv);
+ cryptodebug("end executing cmd action");
switch (rv) {
case PK_ERR_NONE:
+ cryptodebug("subcommand succeeded");
break; /* Command succeeded, do nothing. */
case PK_ERR_USAGE:
+ cryptodebug("usage error detected");
usage();
break;
case PK_ERR_QUIT:
+ cryptodebug("quit command received");
exit(0);
/* NOTREACHED */
- case PK_ERR_PK11INIT:
- cryptoerror(LOG_STDERR, "%s (%s)",
- gettext("Unable to initialize PKCS#11"),
- pkcs11_strerror(pk11_errno));
- cryptodebug("C_Initialize failed (%s)",
- pkcs11_strerror(pk11_errno));
- break;
- case PK_ERR_PK11SLOTS:
- cryptoerror(LOG_STDERR, "%s (%s)",
- gettext("Failed to find PKCS#11 slots"),
- pkcs11_strerror(pk11_errno));
- cryptodebug("C_GetSlotList failed (%s)",
- pkcs11_strerror(pk11_errno));
- break;
- case PK_ERR_PK11SESSION:
- cryptoerror(LOG_STDERR, "%s (%s)",
- gettext("Unable to open PKCS#11 session"),
- pkcs11_strerror(pk11_errno));
- cryptodebug("C_OpenSession failed (%s)",
- pkcs11_strerror(pk11_errno));
- break;
- case PK_ERR_PK11LOGIN:
- if (pk11_errno == CKR_PIN_INCORRECT)
- cryptoerror(LOG_STDERR, "%s", gettext("Incorrect PIN"));
- else {
- cryptoerror(LOG_STDERR, "%s (%s)",
- gettext("PKCS#11 authentication failed"),
- pkcs11_strerror(pk11_errno));
- cryptodebug("C_Login failed (%s)",
- pkcs11_strerror(pk11_errno));
- }
- break;
- case PK_ERR_PK11SETPIN:
- cryptoerror(LOG_STDERR, "%s (%s)",
- gettext("Set PIN failed"), pkcs11_strerror(pk11_errno));
- break;
- case PK_ERR_NOSLOTS:
- cryptoerror(LOG_STDERR, "%s", gettext("No slots were found"));
- break;
- case PK_ERR_NOMEMORY:
- cryptoerror(LOG_STDERR, "%s", gettext("Out of memory"));
- break;
- case PK_ERR_NOTFOUND:
- cryptoerror(LOG_STDERR, "%s", gettext("Token name not found"));
- break;
- case PK_ERR_PASSPHRASE:
+ case PK_ERR_PK11:
cryptoerror(LOG_STDERR, "%s",
- gettext("Unable to get token PIN"));
+ gettext("Command failed due to PKCS#11 error."));
break;
- case PK_ERR_NEWPIN:
- cryptoerror(LOG_STDERR, "%s", gettext("Failed to get new PIN"));
- break;
- case PK_ERR_PINCONFIRM:
+ case PK_ERR_SYSTEM:
cryptoerror(LOG_STDERR, "%s",
- gettext("Failed to confirm new PIN"));
- break;
- case PK_ERR_PINMATCH:
- cryptoerror(LOG_STDERR, "%s", gettext("PINs do not match"));
+ gettext("Command failed due to system error."));
break;
- case PK_ERR_CHANGEPIN:
- cryptoerror(LOG_STDERR, "%s", gettext("PIN must be changed"));
+ case PK_ERR_OPENSSL:
+ cryptoerror(LOG_STDERR, "%s",
+ gettext("Command failed due to OpenSSL error."));
break;
default:
- cryptoerror(LOG_STDERR, "%s (%d)",
+ cryptoerror(LOG_STDERR, "%s (%d).",
gettext("Unknown error value"), rv);
break;
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/setpin.c b/usr/src/cmd/cmd-crypto/pktool/setpin.c
index b9617e8048..947825eaff 100644
--- a/usr/src/cmd/cmd-crypto/pktool/setpin.c
+++ b/usr/src/cmd/cmd-crypto/pktool/setpin.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,60 +29,20 @@
/*
* This file implements the setpin operation for this tool.
* The basic flow of the process is to load the PKCS#11 module,
- * finds the soft token, log into it, prompt the user for the
- * new PIN, change the token's PIN, and log out.
+ * finds the soft token, prompt the user for the old PIN (if
+ * any) and the new PIN, change the token's PIN, and clean up.
*/
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include <string.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"
-static int
-set_token_pin(CK_SESSION_HANDLE hdl, CK_UTF8CHAR_PTR oldpin, CK_ULONG oldpinlen)
-{
- CK_UTF8CHAR_PTR pin1, pin2;
- int len1, len2;
- int rv;
-
- cryptodebug("inside set_token_pin");
-
- if ((len1 = get_password(gettext("Enter new PIN:"),
- (char **)&pin1)) < 0)
- return (PK_ERR_NEWPIN);
-
- if ((len2 = get_password(gettext("Re-enter new PIN:"),
- (char **)&pin2)) < 0) {
- free(pin1);
- return (PK_ERR_PINCONFIRM);
- }
-
- /* NOTE: Do not use strcmp on pin1 and pin2; they are UTF strings */
- if (len1 != len2 || memcmp(pin1, pin2, len1) != 0) {
- free(pin1);
- free(pin2);
- return (PK_ERR_PINMATCH);
- }
-
- if ((rv = C_SetPIN(hdl, oldpin, oldpinlen, pin1, (CK_ULONG)len1))
- != CKR_OK) {
- pk11_errno = rv;
- free(pin1);
- free(pin2);
- return (PK_ERR_PK11SETPIN);
- }
-
- free(pin1);
- free(pin2);
- return (PK_ERR_NONE);
-}
-
/*
- * This is the main entry point in this module. It controls the process
- * by which the token's PIN is changed. It relies on set_token_pin() to
- * handle the extra work of prompting and confirming the new PIN.
+ * Changes the token's PIN.
*/
int
pk_setpin(int argc, char *argv[])
@@ -93,69 +53,119 @@ pk_setpin(int argc, char *argv[])
char *serial_no = NULL;
CK_SLOT_ID slot_id;
CK_FLAGS pin_state;
- CK_SESSION_HANDLE hdl;
- CK_UTF8CHAR_PTR pin;
- int pinlen;
- int rv;
+ CK_SESSION_HANDLE sess;
+ CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL;
+ CK_ULONG old_pinlen = 0, new_pinlen = 0;
+ CK_RV rv = CKR_OK;
+ char full_name[FULL_NAME_LEN];
cryptodebug("inside pk_setpin");
- /*
- * Token_name, manuf_id, and serial_no are all optional.
- * If unspecified, token_name must have a default value
- * at least.
- */
- token_name = SOFT_TOKEN_LABEL;
- manuf_id = SOFT_MANUFACTURER_ID;
+ /* Get rid of subcommand word "setpin". */
+ argc--;
+ argv++;
/* No additional args allowed. */
- if (argc != 1)
+ if (argc != 0)
return (PK_ERR_USAGE);
/* Done parsing command line options. */
- /* Initialize PKCS11, find the slot with token. */
- if ((rv = init_pk11()) != PK_ERR_NONE)
- return (rv);
- if ((rv = find_token_slot(token_name, manuf_id, serial_no,
- &slot_id, &pin_state)) != PK_ERR_NONE)
- return (rv);
-
- /* Check if the token flags show the PIN has not be set yet. */
- if (pin_state == CKF_USER_PIN_TO_BE_CHANGED) {
- cryptodebug("pin_state: first time pin is being set");
- if ((pin = (CK_UTF8CHAR_PTR)strdup(SOFT_DEFAULT_PIN)) == NULL)
- return (PK_ERR_NOMEMORY);
- pinlen = strlen(SOFT_DEFAULT_PIN);
- } else {
- cryptodebug("pin_state: changing an existing pin ");
- /* Have user unlock token with correct password */
- if ((pinlen = get_password(gettext("Enter token PIN:"),
- (char **)&pin)) < 0)
- return (PK_ERR_PASSPHRASE);
+ /*
+ * Token_name, manuf_id, and serial_no are all optional.
+ * If unspecified, token_name must have a default value
+ * at least, so set it to the default softtoken value.
+ */
+ if (token_name == NULL)
+ token_name = SOFT_TOKEN_LABEL;
+ if (manuf_id == NULL)
+ manuf_id = SOFT_MANUFACTURER_ID;
+ if (serial_no == NULL)
+ serial_no = SOFT_TOKEN_SERIAL;
+ full_token_name(token_name, manuf_id, serial_no, full_name);
+
+ /* Find the slot with token. */
+ if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
+ &pin_state)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to find token %s (%s)."), full_name,
+ pkcs11_strerror(rv));
+ final_pk11(NULL);
+ return (PK_ERR_PK11);
}
/*
- * Log into the token. If login fails with an uninitialized PIN,
- * it means this is the first time the token has been used.
- * Or if the login is successful, but all subsequent calls to
- * any function return with an expired PIN, then this is the
- * first time the token is used. In either case, use the
- * passphrase "changeme" as the initial PIN.
+ * If the token is the softtoken, check if the token flags show the
+ * PIN has not been set yet. If not then set the old PIN to the
+ * default "changeme". Otherwise, let user type in the correct old
+ * PIN to unlock token.
*/
- if ((rv = login_token(slot_id, pin, (CK_ULONG)pinlen, &hdl))
- != PK_ERR_NONE) {
- free(pin);
- return (rv);
+ if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
+ strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
+ cryptodebug("pin_state: first time passphrase is being set");
+ if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
+ NULL) {
+ cryptoerror(LOG_STDERR, "%s.", strerror(errno));
+ final_pk11(NULL);
+ return (PK_ERR_PK11);
+ }
+ old_pinlen = strlen(SOFT_DEFAULT_PIN);
+ } else {
+ cryptodebug("pin_state: changing an existing pin ");
+ if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
+ &old_pin, &old_pinlen)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to get token passphrase (%s)."),
+ pkcs11_strerror(rv));
+ final_pk11(NULL);
+ return (PK_ERR_PK11);
+ }
+ }
+
+ /* Get the user's new PIN. */
+ if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
+ "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
+ if (rv == CKR_PIN_INCORRECT)
+ cryptoerror(LOG_STDERR, gettext(
+ "Passphrases do not match."));
+ else
+ cryptoerror(LOG_STDERR, gettext(
+ "Unable to get and confirm new passphrase (%s)."),
+ pkcs11_strerror(rv));
+ free(old_pin);
+ final_pk11(NULL);
+ return (PK_ERR_PK11);
+ }
+
+ /* Open a R/W session to the token to change the PIN. */
+ if ((rv = open_sess(slot_id, CKF_RW_SESSION, &sess)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to open token session (%s)."),
+ pkcs11_strerror(rv));
+ free(old_pin);
+ final_pk11(NULL);
+ return (PK_ERR_PK11);
}
- /* Set the pin for the PKCS11 token. */
- if ((rv = set_token_pin(hdl, pin, (CK_ULONG)pinlen)) != PK_ERR_NONE) {
- free(pin);
- logout_token(hdl);
- return (rv);
+ /* Change the PIN if possible. */
+ cryptodebug("calling C_SetPIN");
+ rv = C_SetPIN(sess, old_pin, old_pinlen, new_pin, new_pinlen);
+
+ /* Clean up. */
+ free(old_pin);
+ free(new_pin);
+ quick_finish(sess);
+
+ if (rv != CKR_OK) {
+ if (rv == CKR_PIN_INCORRECT)
+ cryptoerror(LOG_STDERR,
+ gettext("Incorrect passphrase."));
+ else
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to change passphrase (%s)."),
+ pkcs11_strerror(rv));
+ return (PK_ERR_PK11);
}
- free(pin);
- logout_token(hdl);
- return (PK_ERR_NONE);
+ (void) fprintf(stdout, gettext("Passphrase changed.\n"));
+ return (0);
}
diff --git a/usr/src/cmd/cmd-crypto/pktool/tokens.c b/usr/src/cmd/cmd-crypto/pktool/tokens.c
new file mode 100644
index 0000000000..e6345c77b8
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/pktool/tokens.c
@@ -0,0 +1,104 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements the token list operation for this tool.
+ * It loads the PKCS#11 modules, gets the list of slots with
+ * tokens in them, displays the list, and cleans up.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include "common.h"
+
+/*
+ * Lists all slots with tokens in them.
+ */
+int
+pk_tokens(int argc, char *argv[])
+{
+ CK_SLOT_ID_PTR slots = NULL;
+ CK_ULONG slot_count = 0;
+ CK_TOKEN_INFO token_info;
+ const char *fmt = NULL;
+ CK_RV rv = CKR_OK;
+ int i;
+
+ cryptodebug("inside pk_tokens");
+
+ /* Get rid of subcommand word "tokens". */
+ argc--;
+ argv++;
+
+ /* No additional args allowed. */
+ if (argc != 0)
+ return (PK_ERR_USAGE);
+ /* Done parsing command line options. */
+
+ /* Get the list of slots with tokens in them. */
+ if ((rv = get_token_slots(&slots, &slot_count)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to get token slot list (%s)."),
+ pkcs11_strerror(rv));
+ return (PK_ERR_PK11);
+ }
+
+ /* Make sure we have something to display. */
+ if (slot_count == 0) {
+ cryptoerror(LOG_STDERR, gettext("No slots with tokens found."));
+ return (0);
+ }
+
+ /* Display the list. */
+ fmt = "%-30.30s %-15.15s %-15.15s %-10.10s\n"; /* No I18N/L10N. */
+ (void) fprintf(stdout, fmt, gettext("Token Label"), gettext("Manuf ID"),
+ gettext("Serial No"), gettext("PIN State"));
+ for (i = 0; i < slot_count; i++) {
+ cryptodebug("calling C_GetTokenInfo");
+ if ((rv = C_GetTokenInfo(slots[i], &token_info)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("Unable to get slot %d token info (%s)."),
+ i, pkcs11_strerror(rv));
+ cryptodebug("token info error, slot %d (%s)", i,
+ pkcs11_strerror(rv));
+ continue;
+ }
+
+ (void) fprintf(stdout, fmt, token_info.label,
+ token_info.manufacturerID, token_info.serialNumber,
+ (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ?
+ gettext("default") : gettext("user set"));
+ }
+
+ /* Clean up. */
+ free(slots);
+ quick_finish(NULL);
+ return (0);
+}