common.c revision 7711facfe58561dd91d6ece0f5f41150c3956c83
/*
* 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
* 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 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>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"
#include "biginteger.h"
/* True and false for attribute templates. */
/* Local status variables. */
/*
* Perform PKCS#11 setup here. Currently only C_Initialize is required,
*/
init_pk11(void)
{
cryptodebug("inside init_pk11");
/* If C_Initialize() already called, nothing to do here. */
if (initialized == B_TRUE)
return (CKR_OK);
/* Reset state variables because C_Initialize() not yet done. */
/* Initialize PKCS#11 library. */
cryptodebug("calling C_Initialize()");
return (rv);
}
return (CKR_OK);
}
/*
* Finalize PKCS#11 library and reset state variables. Open sessions,
* if any, are closed, and thereby any logins are logged out also.
*/
void
{
cryptodebug("inside final_pk11");
/* If the library wasn't initialized, nothing to do here. */
if (!initialized)
return;
/* Make sure the sesion is closed first. */
cryptodebug("calling C_Finalize()");
(void) C_Finalize(NULL);
}
/*
* 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.
*/
{
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
*/
close_sess(*sess);
else
return (CKR_OK);
}
/* Make sure the PKCS#11 is already initialized. */
if (!initialized)
return (rv);
/* Create a session for subsequent operations. */
cryptodebug("calling C_OpenSession()");
return (rv);
return (CKR_OK);
}
/*
* Close PKCS#11 session and reset state variables. Any logins are
* logged out.
*/
void
{
cryptodebug("inside close_sess");
cryptodebug("session handle is null");
return;
}
/* If session is already closed, nothing to do here. */
if (!session_opened)
return;
/* Make sure user is logged out of token. */
cryptodebug("calling C_CloseSession()");
(void) C_CloseSession(sess);
}
/*
* 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.
*/
{
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)
return (rv);
/* Log the user into the token. */
cryptodebug("calling C_Login()");
return (rv);
}
return (CKR_OK);
}
/*
* Log user out of token and reset status variable.
*/
void
{
cryptodebug("inside logout_token");
cryptodebug("session handle is null");
return;
}
/* If already logged out, nothing to do here. */
if (!logged_in)
return;
cryptodebug("calling C_Logout()");
}
/*
* 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.
*/
{
cryptodebug("inside quick_start");
/* Call open_sess() explicitly if R/W session is needed. */
if (sess_flags & CKF_RW_SESSION)
return (rv);
return (rv);
return (CKR_OK);
}
/*
* Shortcut function to go from any state to uninitialized PKCS#11 library.
*/
void
{
cryptodebug("inside quick_finish");
/* All the needed calls are done implicitly. */
}
/*
* 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.
*/
{
cryptodebug("inside get_pin");
/* Prompt user for a PIN. */
cryptodebug("no passphrase prompt given");
return (CKR_ARGUMENTS_BAD);
}
cryptodebug("getpassphrase() failed");
return (CKR_FUNCTION_FAILED);
}
/* Duplicate 1st PIN in separate chunk of memory. */
return (CKR_HOST_MEMORY);
/* If second prompt given, PIN confirmation is requested. */
cryptodebug("getpassphrase() confirmation failed");
return (CKR_FUNCTION_FAILED);
}
cryptodebug("passphrases do not match");
return (CKR_PIN_INCORRECT);
}
}
return (CKR_OK);
}
/*
* 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.
*/
{
cryptodebug("inside yesno");
for (;;) {
/* Prompt user. */
/* Get the response. */
break; /* go to default response */
/* Skip any leading white space. */
response++;
if (*response == '\0')
break; /* go to default response */
/* Is it valid input? Return appropriately. */
return (B_TRUE);
return (B_FALSE);
/* Indicate invalid input, and try again. */
}
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.
*/
{
cryptodebug("inside get_token_slots");
if (!initialized)
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");
return (rv);
if (tmp_count == 0) {
cryptodebug("no slots with tokens found");
*slot_count = 0;
return (CKR_OK);
}
/* Allocate initial space for the slot list. */
sizeof (CK_SLOT_ID))) == NULL)
return (CKR_HOST_MEMORY);
/* Then get the slot list itself. */
for (;;) {
cryptodebug("calling C_GetSlotList()");
*slot_count = tmp_count;
break;
}
if (rv != CKR_BUFFER_TOO_SMALL) {
break;
}
/* If the number of slots grew, try again. */
cryptodebug("number of tokens present increased");
break;
}
}
return (rv);
}
/*
* memcmp_pad_max() is a specialized version of memcmp() which
* compares two pieces of data up to a maximum length. If the
* the two data match up the maximum length, they are considered
* matching. Trailing blanks do not cause the match to fail if
* one of the data is shorted.
*
* Examples of matches:
* "one" |
* "one " |
* ^maximum length
*
* "Number One | X" (X is beyond maximum length)
* "Number One " |
* ^maximum length
*
* Examples of mismatches:
* " one"
* "one"
*
* "Number One X|"
* "Number One |"
* ^maximum length
*/
static int
{
char *marker;
/* No point in comparing anything beyond max_sz */
/* Find shorter of the two data. */
} else { /* d1_len > d2_len */
}
/* Have a match in the shortest length of data? */
/* CONSTCOND */
return (!0);
/* If the rest of longer data is nulls or blanks, call it a match. */
/* CONSTCOND */
return (!0);
return (0);
}
/*
* 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.
*/
{
CK_ULONG slot_count = 0;
int i;
cryptodebug("inside find_token_slot");
if (token_name == NULL)
return (CKR_ARGUMENTS_BAD);
/* Get a list of all slots with tokens present. */
return (rv);
/* If there are no such slots, the desired token won't be found. */
if (slot_count == 0)
return (CKR_TOKEN_NOT_PRESENT);
/* Search the slot list for the token. */
for (i = 0; i < slot_count; i++) {
cryptodebug("calling C_GetTokenInfo()");
CKR_OK) {
cryptodebug("token in slot %d returns %s", i,
continue;
}
/* See if the token label matches. */
max_sz) == 0)
/*
* If manufacturer id was given, see if it actually matches.
* If no manufacturer id was given, assume match is true.
*/
if (manuf_id) {
} else
/*
* If serial number was given, see if it actually matches.
* If no serial number was given, assume match is true.
*/
if (serial_no) {
} else
cryptodebug("slot %d:", i);
cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s",
"true" : "false");
cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s",
"true" : "false");
break; /* found it! */
}
/* Scanned the whole list without finding the token. */
if (i == slot_count) {
cryptodebug("token not found");
return (CKR_TOKEN_NOT_PRESENT);
}
/* Return slot id where token was found and its PIN state. */
cryptodebug("token found at slot %d", i);
return (CKR_OK);
}
/*
* 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
*
* 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)
*/
void
{
int n_written = 0;
int space_left = FULL_NAME_LEN;
if (!token_name)
return;
space_left -= n_written;
space_left -= n_written;
space_left -= n_written;
/* space_left should always be >= 1 */
}
/*
* Find how many token objects with the given label.
*/
{
{ 0, NULL, 0 },
{ 0, NULL, 0 },
{ 0, NULL, 0 }
};
cryptodebug("inside find_obj_count");
cryptodebug("session handle is null");
return (CKR_SESSION_HANDLE_INVALID);
}
if (label) {
cryptodebug("object label was specified");
cur_attr++;
}
cryptodebug("only searching for private objects");
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) {
cryptodebug("only searching for certificates");
} else if (obj_type & PK_PRIKEY_OBJ) {
cryptodebug("only searching for private keys");
} else if (obj_type & PK_PUBKEY_OBJ) {
cryptodebug("only searching for public keys");
} else if (obj_type & PK_SECKEY_OBJ) {
cryptodebug("only searching for secret keys");
}
cur_attr++;
}
/*
* This can't happen now. When finding objects is enhanced in the
* future. this could lead to buffer overruns.
*/
cryptodebug("internal error: attr template overrun");
cryptodebug("calling C_FindObjectsInit");
return (rv);
/* Look for the object, checking if there are more than one. */
cryptodebug("calling C_FindObjects");
break;
/* No more found. */
if (obj_count == 0)
break;
}
cryptodebug("calling C_FindObjectsFinal");
(void) C_FindObjectsFinal(sess);
return (rv);
}
/*
* Find the token object with the given label.
*/
{
{ 0, NULL, 0 },
{ 0, NULL, 0 },
{ 0, NULL, 0 }
};
int i;
cryptodebug("inside find_obj");
return (rv);
if (*count == 0)
return (CKR_OK);
sizeof (CK_OBJECT_HANDLE))) == NULL) {
cryptodebug("no memory for found object");
return (CKR_HOST_MEMORY);
}
if (label) {
cryptodebug("object label was specified");
cur_attr++;
}
cryptodebug("only searching for private objects");
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) {
cryptodebug("only searching for certificates");
} else if (obj_type & PK_PRIKEY_OBJ) {
cryptodebug("only searching for private keys");
} else if (obj_type & PK_PUBKEY_OBJ) {
cryptodebug("only searching for public keys");
} else if (obj_type & PK_SECKEY_OBJ) {
cryptodebug("only searching for secret keys");
}
cur_attr++;
}
/*
* This can't happen now. When finding objects is enhanced in the
* future. this could lead to buffer overruns.
*/
cryptodebug("internal error: attr template overrun");
cryptodebug("calling C_FindObjectsInit");
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++) {
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)
else
cryptodebug("number of objects changed since last count");
}
} 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) {
*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 *
{
switch (class) {
default: return (gettext("unknown object"));
}
}
char *
{
switch (keytype) {
default: return (gettext("typeless"));
}
}
char *
{
switch (attrtype) {
default: return (gettext("unknown capability"));
}
}
/*
* 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
char *blank)
{
char *marker;
int nc;
int newline;
int indent_len;
cryptodebug("inside octetify");
"continuing to full length of buffer");
"using only hex octets");
/* If string is empty, write as much of the blank string and leave. */
if (str_sz == 0) {
return;
}
/* If only limit or indent is set, pick default for the other. */
indent = "\n";
limit = 60;
if (!first) {
newline) {
newline++;
continue;
}
} else {
}
}
*marker = '\0';
}
/*
* Copies a biginteger_t to a template attribute.
* Should be a macro instead of a function.
*/
void
{
}
/*
* Copies a string and its length to a template attribute.
* Should be a macro instead of a function.
*/
void
{
}
/*
* Copies a template attribute to a biginteger_t.
* Should be a macro instead of a function.
*/
void
{
}
/*
* Copies a template attribute to a string and its length.
* Should be a macro instead of a function.
*/
void
{
}
/*
* Copies a template attribute to a date and its length.
* Should be a macro instead of a function.
*/
void
{
}