10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 2317Sdinak * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * This file contains the functions that are shared among 310Sstevel@tonic-gate * the various services this tool will ultimately provide. 3217Sdinak * The functions in this file return PKCS#11 CK_RV errors. 3317Sdinak * Only one session and one login per token is supported 3417Sdinak * at this time. 350Sstevel@tonic-gate */ 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <stdio.h> 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <string.h> 400Sstevel@tonic-gate #include <ctype.h> 410Sstevel@tonic-gate #include <cryptoutil.h> 420Sstevel@tonic-gate #include <security/cryptoki.h> 430Sstevel@tonic-gate #include "common.h" 4417Sdinak #include "biginteger.h" 450Sstevel@tonic-gate 4617Sdinak /* True and false for attribute templates. */ 4717Sdinak CK_BBOOL pk_true = B_TRUE; 4817Sdinak CK_BBOOL pk_false = B_FALSE; 4917Sdinak 5017Sdinak /* Local status variables. */ 5117Sdinak static boolean_t initialized = B_FALSE; 5217Sdinak static boolean_t session_opened = B_FALSE; 5317Sdinak static boolean_t session_writable = B_FALSE; 5417Sdinak static boolean_t logged_in = B_FALSE; 5517Sdinak 56*864Sdinak /* Supporting structures and global variables for getopt_av(). */ 57*864Sdinak typedef struct av_opts_s { 58*864Sdinak int shortnm; /* short name character */ 59*864Sdinak char *longnm; /* long name string, NOT terminated */ 60*864Sdinak int longnm_len; /* length of long name string */ 61*864Sdinak boolean_t has_arg; /* takes optional argument */ 62*864Sdinak } av_opts; 63*864Sdinak static av_opts *opts_av = NULL; 64*864Sdinak static const char *_save_optstr = NULL; 65*864Sdinak static int _save_numopts = 0; 66*864Sdinak 67*864Sdinak int optind_av = 1; 68*864Sdinak char *optarg_av = NULL; 69*864Sdinak 7017Sdinak /* 7117Sdinak * Perform PKCS#11 setup here. Currently only C_Initialize is required, 7217Sdinak * along with setting/resetting state variables. 7317Sdinak */ 7417Sdinak CK_RV 7517Sdinak init_pk11(void) 7617Sdinak { 7717Sdinak CK_RV rv = CKR_OK; 7817Sdinak 7917Sdinak cryptodebug("inside init_pk11"); 8017Sdinak 8117Sdinak /* If C_Initialize() already called, nothing to do here. */ 8217Sdinak if (initialized == B_TRUE) 8317Sdinak return (CKR_OK); 8417Sdinak 8517Sdinak /* Reset state variables because C_Initialize() not yet done. */ 8617Sdinak session_opened = B_FALSE; 8717Sdinak session_writable = B_FALSE; 8817Sdinak logged_in = B_FALSE; 8917Sdinak 9017Sdinak /* Initialize PKCS#11 library. */ 9117Sdinak cryptodebug("calling C_Initialize()"); 9217Sdinak if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && 9317Sdinak rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 9417Sdinak return (rv); 9517Sdinak } 9617Sdinak 9717Sdinak initialized = B_TRUE; 9817Sdinak return (CKR_OK); 9917Sdinak } 10017Sdinak 10117Sdinak /* 10217Sdinak * Finalize PKCS#11 library and reset state variables. Open sessions, 10317Sdinak * if any, are closed, and thereby any logins are logged out also. 10417Sdinak */ 10517Sdinak void 10617Sdinak final_pk11(CK_SESSION_HANDLE sess) 10717Sdinak { 10817Sdinak cryptodebug("inside final_pk11"); 10917Sdinak 11017Sdinak /* If the library wasn't initialized, nothing to do here. */ 11117Sdinak if (!initialized) 11217Sdinak return; 11317Sdinak 11417Sdinak /* Make sure the sesion is closed first. */ 11517Sdinak close_sess(sess); 11617Sdinak 11717Sdinak cryptodebug("calling C_Finalize()"); 11817Sdinak (void) C_Finalize(NULL); 11917Sdinak initialized = B_FALSE; 12017Sdinak } 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate /* 12317Sdinak * Create a PKCS#11 session on the given slot, and set state information. 12417Sdinak * If session is already open, check that the read-only/read-write state 12517Sdinak * requested matches that of the session. If it doesn't, make it so. 1260Sstevel@tonic-gate */ 12717Sdinak CK_RV 12817Sdinak open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_SESSION_HANDLE_PTR sess) 1290Sstevel@tonic-gate { 13017Sdinak CK_RV rv = CKR_OK; 13117Sdinak 13217Sdinak cryptodebug("inside open_sess"); 13317Sdinak 13417Sdinak /* If the session is already open, check the session flags. */ 13517Sdinak if (session_opened) { 13617Sdinak /* 13717Sdinak * If requesting R/W session and it is currently R/O, 13817Sdinak * need to close the session and reopen it R/W. The 13917Sdinak * other cases are considered acceptable: 14017Sdinak * sess_flags current state 14117Sdinak * ---------- ------------- 14217Sdinak * ~CKF_RW_SESSION !session_writable 14317Sdinak * ~CKF_RW_SESSION session_writable 14417Sdinak * CKF_RW_SESSION session_writable 14517Sdinak */ 14617Sdinak if ((sess_flags & CKF_RW_SESSION) && !session_writable) 14717Sdinak close_sess(*sess); 14817Sdinak else 14917Sdinak return (CKR_OK); 15017Sdinak } 15117Sdinak 15217Sdinak /* Make sure the PKCS#11 is already initialized. */ 15317Sdinak if (!initialized) 15417Sdinak if ((rv = init_pk11()) != CKR_OK) 15517Sdinak return (rv); 15617Sdinak 15717Sdinak /* Create a session for subsequent operations. */ 15817Sdinak cryptodebug("calling C_OpenSession()"); 15917Sdinak if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|sess_flags, 16017Sdinak NULL, NULL, sess)) != CKR_OK) 16117Sdinak return (rv); 16217Sdinak session_opened = B_TRUE; 16317Sdinak session_writable = (sess_flags & CKF_RW_SESSION) ? B_TRUE : B_FALSE; 16417Sdinak return (CKR_OK); 16517Sdinak } 16617Sdinak 16717Sdinak /* 16817Sdinak * Close PKCS#11 session and reset state variables. Any logins are 16917Sdinak * logged out. 17017Sdinak */ 17117Sdinak void 17217Sdinak close_sess(CK_SESSION_HANDLE sess) 17317Sdinak { 17417Sdinak cryptodebug("inside close_sess"); 17517Sdinak 17617Sdinak if (sess == NULL) { 17717Sdinak cryptodebug("session handle is null"); 17817Sdinak return; 17917Sdinak } 18017Sdinak 18117Sdinak /* If session is already closed, nothing to do here. */ 18217Sdinak session_writable = B_FALSE; 18317Sdinak if (!session_opened) 18417Sdinak return; 1850Sstevel@tonic-gate 18617Sdinak /* Make sure user is logged out of token. */ 18717Sdinak logout_token(sess); 18817Sdinak 18917Sdinak cryptodebug("calling C_CloseSession()"); 19017Sdinak (void) C_CloseSession(sess); 19117Sdinak session_opened = B_FALSE; 19217Sdinak } 19317Sdinak 19417Sdinak /* 19517Sdinak * Log user into token in given slot. If this first login ever for this 19617Sdinak * token, the initial PIN is "changeme", C_Login() will succeed, but all 19717Sdinak * PKCS#11 calls following the C_Login() will fail with CKR_PIN_EXPIRED. 19817Sdinak */ 19917Sdinak CK_RV 20017Sdinak login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, 20117Sdinak CK_SESSION_HANDLE_PTR sess) 20217Sdinak { 20317Sdinak CK_RV rv = CKR_OK; 20417Sdinak 20517Sdinak cryptodebug("inside login_token"); 20617Sdinak 20717Sdinak /* If already logged in, nothing to do here. */ 20817Sdinak if (logged_in) 20917Sdinak return (CKR_OK); 21017Sdinak 21117Sdinak /* Make sure we have a session first, assume R/O is enough. */ 21217Sdinak if (!session_opened) 21317Sdinak if ((rv = open_sess(slot_id, CKF_SERIAL_SESSION, sess)) != 21417Sdinak CKR_OK) 21517Sdinak return (rv); 2160Sstevel@tonic-gate 21717Sdinak /* Log the user into the token. */ 21817Sdinak cryptodebug("calling C_Login()"); 21917Sdinak if ((rv = C_Login(*sess, CKU_USER, pin, pinlen)) != CKR_OK) { 22017Sdinak cryptodebug("C_Login returns %s", pkcs11_strerror(rv)); 22117Sdinak return (rv); 22217Sdinak } 22317Sdinak 22417Sdinak logged_in = B_TRUE; 22517Sdinak return (CKR_OK); 22617Sdinak } 2270Sstevel@tonic-gate 22817Sdinak /* 22917Sdinak * Log user out of token and reset status variable. 23017Sdinak */ 23117Sdinak void 23217Sdinak logout_token(CK_SESSION_HANDLE sess) 23317Sdinak { 23417Sdinak cryptodebug("inside logout_token"); 23517Sdinak 23617Sdinak if (sess == NULL) { 23717Sdinak cryptodebug("session handle is null"); 23817Sdinak return; 23917Sdinak } 24017Sdinak 24117Sdinak /* If already logged out, nothing to do here. */ 24217Sdinak if (!logged_in) 24317Sdinak return; 24417Sdinak 24517Sdinak cryptodebug("calling C_Logout()"); 24617Sdinak (void) C_Logout(sess); 24717Sdinak logged_in = B_FALSE; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate /* 25117Sdinak * Shortcut function to get from an uninitialized state to user logged in. 25217Sdinak * If the library is already initialized, the session is already opened, 25317Sdinak * or the user is already logged in, those steps are skipped and the next 25417Sdinak * step is checked. 2550Sstevel@tonic-gate */ 25617Sdinak CK_RV 25717Sdinak quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin, 25817Sdinak CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess) 25917Sdinak { 26017Sdinak CK_RV rv = CKR_OK; 26117Sdinak 26217Sdinak cryptodebug("inside quick_start"); 26317Sdinak 26417Sdinak /* Call open_sess() explicitly if R/W session is needed. */ 26517Sdinak if (sess_flags & CKF_RW_SESSION) 26617Sdinak if ((rv = open_sess(slot_id, sess_flags, sess)) != CKR_OK) 26717Sdinak return (rv); 26817Sdinak 26917Sdinak if ((rv = login_token(slot_id, pin, pinlen, sess)) != CKR_OK) 27017Sdinak return (rv); 27117Sdinak 27217Sdinak return (CKR_OK); 27317Sdinak } 27417Sdinak 27517Sdinak /* 27617Sdinak * Shortcut function to go from any state to uninitialized PKCS#11 library. 27717Sdinak */ 27817Sdinak void 27917Sdinak quick_finish(CK_SESSION_HANDLE sess) 2800Sstevel@tonic-gate { 28117Sdinak cryptodebug("inside quick_finish"); 28217Sdinak 28317Sdinak /* All the needed calls are done implicitly. */ 28417Sdinak final_pk11(sess); 28517Sdinak } 2860Sstevel@tonic-gate 28717Sdinak /* 28817Sdinak * Gets PIN from user. Caller needs to free the returned PIN when done. 28917Sdinak * If two prompts are given, the PIN is confirmed with second prompt. 29017Sdinak * Note that getphassphrase() may return data in static memory area. 29117Sdinak */ 29217Sdinak CK_RV 29317Sdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) 29417Sdinak { 29517Sdinak char *save_phrase, *phrase1, *phrase2; 29617Sdinak 29717Sdinak cryptodebug("inside get_pin"); 2980Sstevel@tonic-gate 29917Sdinak /* Prompt user for a PIN. */ 30017Sdinak if (prompt1 == NULL) { 30117Sdinak cryptodebug("no passphrase prompt given"); 30217Sdinak return (CKR_ARGUMENTS_BAD); 30317Sdinak } 30417Sdinak if ((phrase1 = getpassphrase(prompt1)) == NULL) { 30517Sdinak cryptodebug("getpassphrase() failed"); 30617Sdinak return (CKR_FUNCTION_FAILED); 30717Sdinak } 30817Sdinak 30917Sdinak /* Duplicate 1st PIN in separate chunk of memory. */ 31017Sdinak if ((save_phrase = strdup(phrase1)) == NULL) 31117Sdinak return (CKR_HOST_MEMORY); 31217Sdinak 31317Sdinak /* If second prompt given, PIN confirmation is requested. */ 31417Sdinak if (prompt2 != NULL) { 31517Sdinak if ((phrase2 = getpassphrase(prompt2)) == NULL) { 31617Sdinak cryptodebug("getpassphrase() confirmation failed"); 31717Sdinak free(save_phrase); 31817Sdinak return (CKR_FUNCTION_FAILED); 31917Sdinak } 32017Sdinak if (strcmp(save_phrase, phrase2) != 0) { 32117Sdinak cryptodebug("passphrases do not match"); 32217Sdinak free(save_phrase); 32317Sdinak return (CKR_PIN_INCORRECT); 32417Sdinak } 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 32717Sdinak *pin = (CK_UTF8CHAR_PTR)save_phrase; 32817Sdinak *pinlen = strlen(save_phrase); 32917Sdinak return (CKR_OK); 33017Sdinak } 33117Sdinak 33217Sdinak /* 33317Sdinak * Gets yes/no response from user. If either no prompt is supplied, a 33417Sdinak * default prompt is used. If not message for invalid input is supplied, 33517Sdinak * a default will not be provided. If the user provides no response, 33617Sdinak * the input default B_TRUE == yes, B_FALSE == no is returned. 33717Sdinak * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. 33817Sdinak */ 33917Sdinak boolean_t 34017Sdinak yesno(char *prompt, char *invalid, boolean_t dflt) 34117Sdinak { 34217Sdinak char *response, buf[1024]; 34317Sdinak char *yes = gettext("yes"); 34417Sdinak char *no = gettext("no"); 34517Sdinak 34617Sdinak cryptodebug("inside yesno"); 34717Sdinak 34817Sdinak if (prompt == NULL) 34917Sdinak prompt = gettext("Enter (y)es or (n)o? "); 35017Sdinak 35117Sdinak for (;;) { 35217Sdinak /* Prompt user. */ 35317Sdinak (void) printf("%s", prompt); 35417Sdinak (void) fflush(stdout); 35517Sdinak 35617Sdinak /* Get the response. */ 35717Sdinak if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) 35817Sdinak break; /* go to default response */ 35917Sdinak 36017Sdinak /* Skip any leading white space. */ 36117Sdinak while (isspace(*response)) 36217Sdinak response++; 36317Sdinak if (*response == '\0') 36417Sdinak break; /* go to default response */ 36517Sdinak 36617Sdinak /* Is it valid input? Return appropriately. */ 36717Sdinak if (strncasecmp(response, yes, 1) == 0) 36817Sdinak return (B_TRUE); 36917Sdinak if (strncasecmp(response, no, 1) == 0) 37017Sdinak return (B_FALSE); 37117Sdinak 37217Sdinak /* Indicate invalid input, and try again. */ 37317Sdinak if (invalid != NULL) 37417Sdinak (void) printf("%s", invalid); 37517Sdinak } 37617Sdinak return (dflt); 37717Sdinak } 37817Sdinak 37917Sdinak /* 38017Sdinak * Gets the list of slots which have tokens in them. Keeps adjusting 38117Sdinak * the size of the slot list buffer until the call is successful or an 38217Sdinak * irrecoverable error occurs. 38317Sdinak */ 38417Sdinak CK_RV 38517Sdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) 38617Sdinak { 38717Sdinak CK_ULONG tmp_count = 0; 38817Sdinak CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; 38917Sdinak int rv = CKR_OK; 39017Sdinak 39117Sdinak cryptodebug("inside get_token_slots"); 39217Sdinak 39317Sdinak if (!initialized) 39417Sdinak if ((rv = init_pk11()) != CKR_OK) 39517Sdinak return (rv); 39617Sdinak 39717Sdinak /* 39817Sdinak * Get the slot count first because we don't know how many 39917Sdinak * slots there are and how many of those slots even have tokens. 40017Sdinak * Don't specify an arbitrary buffer size for the slot list; 40117Sdinak * it may be too small (see section 11.5 of PKCS#11 spec). 40217Sdinak * Also select only those slots that have tokens in them, 40317Sdinak * because this tool has no need to know about empty slots. 40417Sdinak */ 40517Sdinak cryptodebug("calling C_GetSlotList() for slot count"); 40617Sdinak if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) 40717Sdinak return (rv); 40817Sdinak 40917Sdinak if (tmp_count == 0) { 41017Sdinak cryptodebug("no slots with tokens found"); 41117Sdinak *slot_list = NULL_PTR; 41217Sdinak *slot_count = 0; 41317Sdinak return (CKR_OK); 41417Sdinak } 41517Sdinak 41617Sdinak /* Allocate initial space for the slot list. */ 41717Sdinak if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * 41817Sdinak sizeof (CK_SLOT_ID))) == NULL) 41917Sdinak return (CKR_HOST_MEMORY); 42017Sdinak 42117Sdinak /* Then get the slot list itself. */ 42217Sdinak for (;;) { 42317Sdinak cryptodebug("calling C_GetSlotList()"); 42417Sdinak if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { 42517Sdinak *slot_list = tmp_list; 42617Sdinak *slot_count = tmp_count; 42717Sdinak break; 42817Sdinak } 42917Sdinak 43017Sdinak if (rv != CKR_BUFFER_TOO_SMALL) { 43117Sdinak free(tmp_list); 43217Sdinak break; 43317Sdinak } 43417Sdinak 43517Sdinak /* If the number of slots grew, try again. */ 43617Sdinak cryptodebug("number of tokens present increased"); 43717Sdinak if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, 43817Sdinak tmp_count * sizeof (CK_SLOT_ID))) == NULL) { 43917Sdinak free(tmp_list); 44017Sdinak rv = CKR_HOST_MEMORY; 44117Sdinak break; 44217Sdinak } 44317Sdinak tmp_list = tmp2_list; 44417Sdinak } 44517Sdinak 44617Sdinak return (rv); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * memcmp_pad_max() is a specialized version of memcmp() which 4510Sstevel@tonic-gate * compares two pieces of data up to a maximum length. If the 4520Sstevel@tonic-gate * the two data match up the maximum length, they are considered 4530Sstevel@tonic-gate * matching. Trailing blanks do not cause the match to fail if 4540Sstevel@tonic-gate * one of the data is shorted. 4550Sstevel@tonic-gate * 4560Sstevel@tonic-gate * Examples of matches: 4570Sstevel@tonic-gate * "one" | 4580Sstevel@tonic-gate * "one " | 4590Sstevel@tonic-gate * ^maximum length 4600Sstevel@tonic-gate * 4610Sstevel@tonic-gate * "Number One | X" (X is beyond maximum length) 4620Sstevel@tonic-gate * "Number One " | 4630Sstevel@tonic-gate * ^maximum length 4640Sstevel@tonic-gate * 4650Sstevel@tonic-gate * Examples of mismatches: 4660Sstevel@tonic-gate * " one" 4670Sstevel@tonic-gate * "one" 4680Sstevel@tonic-gate * 4690Sstevel@tonic-gate * "Number One X|" 4700Sstevel@tonic-gate * "Number One |" 4710Sstevel@tonic-gate * ^maximum length 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate static int 4740Sstevel@tonic-gate memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz) 4750Sstevel@tonic-gate { 4760Sstevel@tonic-gate uint_t len, extra_len; 4770Sstevel@tonic-gate char *marker; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate /* No point in comparing anything beyond max_sz */ 4800Sstevel@tonic-gate if (d1_len > max_sz) 4810Sstevel@tonic-gate d1_len = max_sz; 4820Sstevel@tonic-gate if (d2_len > max_sz) 4830Sstevel@tonic-gate d2_len = max_sz; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* Find shorter of the two data. */ 4860Sstevel@tonic-gate if (d1_len <= d2_len) { 4870Sstevel@tonic-gate len = d1_len; 4880Sstevel@tonic-gate extra_len = d2_len; 4890Sstevel@tonic-gate marker = d2; 4900Sstevel@tonic-gate } else { /* d1_len > d2_len */ 4910Sstevel@tonic-gate len = d2_len; 4920Sstevel@tonic-gate extra_len = d1_len; 4930Sstevel@tonic-gate marker = d1; 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* Have a match in the shortest length of data? */ 4970Sstevel@tonic-gate if (memcmp(d1, d2, len) != 0) 4980Sstevel@tonic-gate /* CONSTCOND */ 4990Sstevel@tonic-gate return (!0); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* If the rest of longer data is nulls or blanks, call it a match. */ 5020Sstevel@tonic-gate while (len < extra_len) 5030Sstevel@tonic-gate if (!isspace(marker[len++])) 5040Sstevel@tonic-gate /* CONSTCOND */ 5050Sstevel@tonic-gate return (!0); 5060Sstevel@tonic-gate return (0); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* 51017Sdinak * Locate a token slot whose token matches the label, manufacturer ID, and 51117Sdinak * serial number given. Token label must be specified, manufacturer ID and 51217Sdinak * serial number are optional. When the token is located, the PIN state 51317Sdinak * is also returned to determine if it still has the default PIN. 5140Sstevel@tonic-gate */ 51517Sdinak CK_RV 5160Sstevel@tonic-gate find_token_slot(char *token_name, char *manuf_id, char *serial_no, 5170Sstevel@tonic-gate CK_SLOT_ID *slot_id, CK_FLAGS *pin_state) 5180Sstevel@tonic-gate { 5190Sstevel@tonic-gate CK_SLOT_ID_PTR slot_list; 5200Sstevel@tonic-gate CK_TOKEN_INFO token_info; 5210Sstevel@tonic-gate CK_ULONG slot_count = 0; 52217Sdinak int rv = CKR_OK; 5230Sstevel@tonic-gate int i; 5240Sstevel@tonic-gate uint_t len, max_sz; 5250Sstevel@tonic-gate boolean_t tok_match = B_FALSE, 5260Sstevel@tonic-gate man_match = B_FALSE, 5270Sstevel@tonic-gate ser_match = B_FALSE; 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate cryptodebug("inside find_token_slot"); 5300Sstevel@tonic-gate 53117Sdinak if (token_name == NULL) 53217Sdinak return (CKR_ARGUMENTS_BAD); 5330Sstevel@tonic-gate 53417Sdinak /* Get a list of all slots with tokens present. */ 53517Sdinak if ((rv = get_token_slots(&slot_list, &slot_count)) != CKR_OK) 53617Sdinak return (rv); 5370Sstevel@tonic-gate 53817Sdinak /* If there are no such slots, the desired token won't be found. */ 53917Sdinak if (slot_count == 0) 54017Sdinak return (CKR_TOKEN_NOT_PRESENT); 5410Sstevel@tonic-gate 54217Sdinak /* Search the slot list for the token. */ 5430Sstevel@tonic-gate for (i = 0; i < slot_count; i++) { 54417Sdinak cryptodebug("calling C_GetTokenInfo()"); 54517Sdinak if ((rv = C_GetTokenInfo(slot_list[i], &token_info)) != 54617Sdinak CKR_OK) { 54717Sdinak cryptodebug("token in slot %d returns %s", i, 54817Sdinak pkcs11_strerror(rv)); 5490Sstevel@tonic-gate continue; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 55217Sdinak /* See if the token label matches. */ 5530Sstevel@tonic-gate len = strlen(token_name); 5540Sstevel@tonic-gate max_sz = sizeof (token_info.label); 5550Sstevel@tonic-gate if (memcmp_pad_max(&(token_info.label), max_sz, token_name, len, 5560Sstevel@tonic-gate max_sz) == 0) 5570Sstevel@tonic-gate tok_match = B_TRUE; 5580Sstevel@tonic-gate 55917Sdinak /* 56017Sdinak * If manufacturer id was given, see if it actually matches. 56117Sdinak * If no manufacturer id was given, assume match is true. 56217Sdinak */ 56317Sdinak if (manuf_id) { 56417Sdinak len = strlen(manuf_id); 56517Sdinak max_sz = sizeof ((char *)(token_info.manufacturerID)); 56617Sdinak if (memcmp_pad_max(&(token_info.manufacturerID), max_sz, 56717Sdinak manuf_id, len, max_sz) == 0) 56817Sdinak man_match = B_TRUE; 56917Sdinak } else 57017Sdinak man_match = B_TRUE; 57117Sdinak 57217Sdinak /* 57317Sdinak * If serial number was given, see if it actually matches. 57417Sdinak * If no serial number was given, assume match is true. 57517Sdinak */ 57617Sdinak if (serial_no) { 57717Sdinak len = strlen(serial_no); 57817Sdinak max_sz = sizeof ((char *)(token_info.serialNumber)); 57917Sdinak if (memcmp_pad_max(&(token_info.serialNumber), max_sz, 58017Sdinak serial_no, len, max_sz) == 0) 58117Sdinak ser_match = B_TRUE; 58217Sdinak } else 58317Sdinak ser_match = B_TRUE; 58417Sdinak 5850Sstevel@tonic-gate cryptodebug("slot %d:", i); 58617Sdinak cryptodebug("\tlabel = \"%.32s\"%s", token_info.label, 58717Sdinak tok_match ? " match" : ""); 58817Sdinak cryptodebug("\tmanuf = \"%.32s\"%s", token_info.manufacturerID, 58917Sdinak man_match ? " match" : ""); 59017Sdinak cryptodebug("\tserno = \"%.16s\"%s", token_info.serialNumber, 59117Sdinak ser_match ? " match" : ""); 5920Sstevel@tonic-gate cryptodebug("\tmodel = \"%.16s\"", token_info.model); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s", 5950Sstevel@tonic-gate (token_info.flags & CKF_USER_PIN_INITIALIZED) ? 5960Sstevel@tonic-gate "true" : "false"); 5970Sstevel@tonic-gate cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s", 5980Sstevel@tonic-gate (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? 5990Sstevel@tonic-gate "true" : "false"); 6000Sstevel@tonic-gate 60117Sdinak if (tok_match && man_match && ser_match) 60217Sdinak break; /* found it! */ 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 60517Sdinak /* Scanned the whole list without finding the token. */ 6060Sstevel@tonic-gate if (i == slot_count) { 60717Sdinak cryptodebug("token not found"); 6080Sstevel@tonic-gate free(slot_list); 60917Sdinak return (CKR_TOKEN_NOT_PRESENT); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 61217Sdinak /* Return slot id where token was found and its PIN state. */ 61317Sdinak cryptodebug("token found at slot %d", i); 6140Sstevel@tonic-gate *slot_id = slot_list[i]; 6150Sstevel@tonic-gate *pin_state = (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED); 6160Sstevel@tonic-gate free(slot_list); 61717Sdinak return (CKR_OK); 61817Sdinak } 61917Sdinak 62017Sdinak /* 621*864Sdinak * Returns pointer to either null-terminator or next unescaped colon. The 622*864Sdinak * string to be extracted starts at the beginning and goes until one character 623*864Sdinak * before this pointer. If NULL is returned, the string itself is NULL. 624*864Sdinak */ 625*864Sdinak static char * 626*864Sdinak find_unescaped_colon(char *str) 627*864Sdinak { 628*864Sdinak char *end; 629*864Sdinak 630*864Sdinak if (str == NULL) 631*864Sdinak return (NULL); 632*864Sdinak 633*864Sdinak while ((end = strchr(str, ':')) != NULL) { 634*864Sdinak if (end != str && *(end-1) != '\\') 635*864Sdinak return (end); 636*864Sdinak str = end + 1; /* could point to null-terminator */ 637*864Sdinak } 638*864Sdinak if (end == NULL) 639*864Sdinak end = strchr(str, '\0'); 640*864Sdinak return (end); 641*864Sdinak } 642*864Sdinak 643*864Sdinak /* 644*864Sdinak * Compresses away any characters escaped with backslash from given string. 645*864Sdinak * The string is altered in-place. Example, "ab\:\\e" becomes "ab:\e". 646*864Sdinak */ 647*864Sdinak static void 648*864Sdinak unescape_str(char *str) 649*864Sdinak { 650*864Sdinak boolean_t escaped = B_FALSE; 651*864Sdinak char *mark; 652*864Sdinak 653*864Sdinak if (str == NULL) 654*864Sdinak return; 655*864Sdinak 656*864Sdinak for (mark = str; *str != '\0'; str++) { 657*864Sdinak if (*str != '\\' || escaped == B_TRUE) { 658*864Sdinak *mark++ = *str; 659*864Sdinak escaped = B_FALSE; 660*864Sdinak } else { 661*864Sdinak escaped = B_TRUE; 662*864Sdinak } 663*864Sdinak } 664*864Sdinak *mark = '\0'; 665*864Sdinak } 666*864Sdinak 667*864Sdinak /* 668*864Sdinak * Given a colon-separated token specifier, this functions splits it into 669*864Sdinak * its label, manufacturer ID (if any), and serial number (if any). Literal 670*864Sdinak * colons within the label/manuf/serial can be escaped with a backslash. 671*864Sdinak * Fields can left blank and trailing colons can be omitted, however leading 672*864Sdinak * colons are required as placeholders. For example, these are equivalent: 673*864Sdinak * (a) "lbl", "lbl:", "lbl::" (b) "lbl:man", "lbl:man:" 674*864Sdinak * but these are not: 675*864Sdinak * (c) "man", ":man" (d) "ser", "::ser" 676*864Sdinak * Furthermore, the token label is required always. 677*864Sdinak * 678*864Sdinak * The buffer containing the token specifier is altered by replacing the 679*864Sdinak * colons to null-terminators, and pointers returned are pointers into this 680*864Sdinak * string. No new memory is allocated. 681*864Sdinak */ 682*864Sdinak int 683*864Sdinak parse_token_spec(char *token_spec, char **token_name, char **manuf_id, 684*864Sdinak char **serial_no) 685*864Sdinak { 686*864Sdinak char *mark; 687*864Sdinak 688*864Sdinak if (token_spec == NULL || *token_spec == '\0') { 689*864Sdinak cryptodebug("token specifier is empty"); 690*864Sdinak return (-1); 691*864Sdinak } 692*864Sdinak 693*864Sdinak *token_name = NULL; 694*864Sdinak *manuf_id = NULL; 695*864Sdinak *serial_no = NULL; 696*864Sdinak 697*864Sdinak /* Token label (required) */ 698*864Sdinak mark = find_unescaped_colon(token_spec); 699*864Sdinak *token_name = token_spec; 700*864Sdinak if (*mark != '\0') 701*864Sdinak *mark++ = '\0'; /* mark points to next field, if any */ 702*864Sdinak unescape_str(*token_name); 703*864Sdinak 704*864Sdinak if (*(*token_name) == '\0') { /* token label is required */ 705*864Sdinak cryptodebug("no token label found"); 706*864Sdinak return (-1); 707*864Sdinak } 708*864Sdinak 709*864Sdinak if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */ 710*864Sdinak return (0); 711*864Sdinak token_spec = mark; 712*864Sdinak 713*864Sdinak /* Manufacturer identifier (optional) */ 714*864Sdinak mark = find_unescaped_colon(token_spec); 715*864Sdinak *manuf_id = token_spec; 716*864Sdinak if (*mark != '\0') 717*864Sdinak *mark++ = '\0'; /* mark points to next field, if any */ 718*864Sdinak unescape_str(*manuf_id); 719*864Sdinak 720*864Sdinak if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */ 721*864Sdinak return (0); 722*864Sdinak token_spec = mark; 723*864Sdinak 724*864Sdinak /* Serial number (optional) */ 725*864Sdinak mark = find_unescaped_colon(token_spec); 726*864Sdinak *serial_no = token_spec; 727*864Sdinak if (*mark != '\0') 728*864Sdinak *mark++ = '\0'; /* null-terminate, just in case */ 729*864Sdinak unescape_str(*serial_no); 730*864Sdinak 731*864Sdinak return (0); 732*864Sdinak } 733*864Sdinak 734*864Sdinak /* 73517Sdinak * Constructs a fully qualified token name from its label, manufacturer ID 73617Sdinak * (if any), and its serial number (if any). Note that the given buf must 73717Sdinak * be big enough. Do NOT i18n/l10n. 73817Sdinak * 73917Sdinak * FULL_NAME_LEN is defined in common.h to be 91 because a fully qualified 74017Sdinak * token name adds up this way: 74117Sdinak * =32(label) + 32(manuf) + 16(serial) + 4("", ) + 4("", ) + 3("" and nul) 74217Sdinak */ 74317Sdinak void 74417Sdinak full_token_name(char *token_name, char *manuf_id, char *serial_no, char *buf) 74517Sdinak { 74617Sdinak char *marker = buf; 74717Sdinak int n_written = 0; 74817Sdinak int space_left = FULL_NAME_LEN; 74917Sdinak 75017Sdinak if (!token_name) 75117Sdinak return; 75217Sdinak 75317Sdinak n_written = sprintf(buf, "\"%.32s\"", token_name); 75417Sdinak marker += n_written; 75517Sdinak space_left -= n_written; 75617Sdinak 75717Sdinak n_written = sprintf(marker, ", \"%.32s\"", manuf_id ? manuf_id : ""); 75817Sdinak marker += n_written; 75917Sdinak space_left -= n_written; 76017Sdinak 76117Sdinak n_written = sprintf(marker, ", \"%.16s\"", serial_no ? serial_no : ""); 76217Sdinak marker += n_written; 76317Sdinak space_left -= n_written; 76417Sdinak 76517Sdinak /* space_left should always be >= 1 */ 76617Sdinak } 76717Sdinak 76817Sdinak /* 76917Sdinak * Find how many token objects with the given label. 77017Sdinak */ 77117Sdinak CK_RV 77217Sdinak find_obj_count(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, 77317Sdinak CK_ULONG *count) 77417Sdinak { 77517Sdinak CK_RV rv = CKR_OK; 77617Sdinak CK_ATTRIBUTE attrs[4] = { 77717Sdinak { CKA_TOKEN, &pk_true, sizeof (pk_true) }, 77817Sdinak { 0, NULL, 0 }, 77917Sdinak { 0, NULL, 0 }, 78017Sdinak { 0, NULL, 0 } 78117Sdinak }; 78217Sdinak CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); 78317Sdinak CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ 78417Sdinak CK_OBJECT_CLASS obj_class; 78517Sdinak CK_OBJECT_HANDLE tmp_obj; 78617Sdinak CK_ULONG obj_count = 0; 78717Sdinak 78817Sdinak cryptodebug("inside find_obj_count"); 78917Sdinak 79017Sdinak if (!session_opened || sess == NULL) { 79117Sdinak cryptodebug("session handle is null"); 79217Sdinak return (CKR_SESSION_HANDLE_INVALID); 79317Sdinak } 79417Sdinak 79517Sdinak if (label) { 79617Sdinak cryptodebug("object label was specified"); 79717Sdinak attrs[cur_attr].type = CKA_LABEL; 79817Sdinak attrs[cur_attr].pValue = label; 79917Sdinak attrs[cur_attr].ulValueLen = strlen((char *)label); 80017Sdinak cur_attr++; 80117Sdinak } 80217Sdinak 80317Sdinak if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { 80417Sdinak cryptodebug("only searching for private objects"); 80517Sdinak attrs[cur_attr].type = CKA_PRIVATE; 80617Sdinak attrs[cur_attr].pValue = &pk_true; 80717Sdinak attrs[cur_attr].ulValueLen = sizeof (pk_true); 80817Sdinak cur_attr++; 80917Sdinak } 81017Sdinak 81117Sdinak /* 81217Sdinak * If "certs and all keys" is not specified, but at least either 81317Sdinak * "certs" or some "keys" is specified, then go into this block. 81417Sdinak * If all certs and keys were specified, there's no point in 81517Sdinak * putting that fact in the attribute template -- leave that open, 81617Sdinak * and all certs and keys will be matched automatically. 81717Sdinak * In other words, only if at least one of 0x10,0x20,0x40,0x80 81817Sdinak * bits is off, go into this code block. 81917Sdinak * 82017Sdinak * NOTE: For now, only one of cert or key types is allowed. 82117Sdinak * This needs to change in the future. 82217Sdinak */ 82317Sdinak if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && 82417Sdinak ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { 82517Sdinak if (obj_type & PK_CERT_OBJ) { 82617Sdinak cryptodebug("only searching for certificates"); 82717Sdinak obj_class = CKO_CERTIFICATE; 82817Sdinak } else if (obj_type & PK_PRIKEY_OBJ) { 82917Sdinak cryptodebug("only searching for private keys"); 83017Sdinak obj_class = CKO_PRIVATE_KEY; 83117Sdinak } else if (obj_type & PK_PUBKEY_OBJ) { 83217Sdinak cryptodebug("only searching for public keys"); 83317Sdinak obj_class = CKO_PUBLIC_KEY; 83417Sdinak } else if (obj_type & PK_SECKEY_OBJ) { 83517Sdinak cryptodebug("only searching for secret keys"); 83617Sdinak obj_class = CKO_SECRET_KEY; 83717Sdinak } 83817Sdinak 83917Sdinak attrs[cur_attr].type = CKA_CLASS; 84017Sdinak attrs[cur_attr].pValue = &obj_class; 84117Sdinak attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); 84217Sdinak cur_attr++; 84317Sdinak } 84417Sdinak 84517Sdinak /* 84617Sdinak * This can't happen now. When finding objects is enhanced in the 84717Sdinak * future. this could lead to buffer overruns. 84817Sdinak */ 84917Sdinak if (cur_attr > num_attrs) 85017Sdinak cryptodebug("internal error: attr template overrun"); 85117Sdinak 85217Sdinak cryptodebug("calling C_FindObjectsInit"); 85317Sdinak if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) 85417Sdinak return (rv); 85517Sdinak 85617Sdinak /* Look for the object, checking if there are more than one. */ 85717Sdinak cryptodebug("calling C_FindObjects"); 85817Sdinak for (*count = 0; /* empty */; (*count)++) { 85917Sdinak if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != 86017Sdinak CKR_OK) 86117Sdinak break; 86217Sdinak 86317Sdinak /* No more found. */ 86417Sdinak if (obj_count == 0) 86517Sdinak break; 86617Sdinak } 86717Sdinak 86817Sdinak cryptodebug("%d matching objects found", *count); 86917Sdinak 87017Sdinak cryptodebug("calling C_FindObjectsFinal"); 87117Sdinak (void) C_FindObjectsFinal(sess); 87217Sdinak return (rv); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* 87617Sdinak * Find the token object with the given label. 8770Sstevel@tonic-gate */ 87817Sdinak CK_RV 87917Sdinak find_objs(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, 88017Sdinak CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count) 8810Sstevel@tonic-gate { 88217Sdinak CK_RV rv = CKR_OK; 88317Sdinak CK_ATTRIBUTE attrs[4] = { 88417Sdinak { CKA_TOKEN, &pk_true, sizeof (pk_true) }, 88517Sdinak { 0, NULL, 0 }, 88617Sdinak { 0, NULL, 0 }, 88717Sdinak { 0, NULL, 0 } 88817Sdinak }; 88917Sdinak CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); 89017Sdinak CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ 89117Sdinak CK_OBJECT_CLASS obj_class; 89217Sdinak CK_OBJECT_HANDLE tmp_obj; 89317Sdinak CK_ULONG obj_count = 0; 89417Sdinak int i; 89517Sdinak 89617Sdinak cryptodebug("inside find_obj"); 89717Sdinak 89817Sdinak if ((rv = find_obj_count(sess, obj_type, label, count)) != CKR_OK) 89917Sdinak return (rv); 90017Sdinak 90117Sdinak if (*count == 0) 90217Sdinak return (CKR_OK); 90317Sdinak 90417Sdinak if ((*obj = (CK_OBJECT_HANDLE_PTR) malloc((*count) * 90517Sdinak sizeof (CK_OBJECT_HANDLE))) == NULL) { 90617Sdinak cryptodebug("no memory for found object"); 90717Sdinak return (CKR_HOST_MEMORY); 90817Sdinak } 90917Sdinak 91017Sdinak if (label) { 91117Sdinak cryptodebug("object label was specified"); 91217Sdinak attrs[cur_attr].type = CKA_LABEL; 91317Sdinak attrs[cur_attr].pValue = label; 91417Sdinak attrs[cur_attr].ulValueLen = strlen((char *)label); 91517Sdinak cur_attr++; 91617Sdinak } 9170Sstevel@tonic-gate 91817Sdinak if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { 91917Sdinak cryptodebug("only searching for private objects"); 92017Sdinak attrs[cur_attr].type = CKA_PRIVATE; 92117Sdinak attrs[cur_attr].pValue = &pk_true; 92217Sdinak attrs[cur_attr].ulValueLen = sizeof (pk_true); 92317Sdinak cur_attr++; 92417Sdinak } 9250Sstevel@tonic-gate 92617Sdinak /* 92717Sdinak * If "certs and all keys" is not specified, but at least either 92817Sdinak * "certs" or some "keys" is specified, then go into this block. 92917Sdinak * If all certs and keys were specified, there's no point in 93017Sdinak * putting that fact in the attribute template -- leave that open, 93117Sdinak * and all certs and keys will be matched automatically. 93217Sdinak * In other words, only if at least one of 0x10,0x20,0x40,0x80 93317Sdinak * bits is off, go into this code block. 93417Sdinak * 93517Sdinak * NOTE: For now, only one of cert or key types is allowed. 93617Sdinak * This needs to change in the future. 93717Sdinak */ 93817Sdinak if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && 93917Sdinak ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { 94017Sdinak if (obj_type & PK_CERT_OBJ) { 94117Sdinak cryptodebug("only searching for certificates"); 94217Sdinak obj_class = CKO_CERTIFICATE; 94317Sdinak } else if (obj_type & PK_PRIKEY_OBJ) { 94417Sdinak cryptodebug("only searching for private keys"); 94517Sdinak obj_class = CKO_PRIVATE_KEY; 94617Sdinak } else if (obj_type & PK_PUBKEY_OBJ) { 94717Sdinak cryptodebug("only searching for public keys"); 94817Sdinak obj_class = CKO_PUBLIC_KEY; 94917Sdinak } else if (obj_type & PK_SECKEY_OBJ) { 95017Sdinak cryptodebug("only searching for secret keys"); 95117Sdinak obj_class = CKO_SECRET_KEY; 95217Sdinak } 95317Sdinak 95417Sdinak attrs[cur_attr].type = CKA_CLASS; 95517Sdinak attrs[cur_attr].pValue = &obj_class; 95617Sdinak attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); 95717Sdinak cur_attr++; 95817Sdinak } 95917Sdinak 96017Sdinak /* 96117Sdinak * This can't happen now. When finding objects is enhanced in the 96217Sdinak * future. this could lead to buffer overruns. 96317Sdinak */ 96417Sdinak if (cur_attr > num_attrs) 96517Sdinak cryptodebug("internal error: attr template overrun"); 96617Sdinak 96717Sdinak cryptodebug("calling C_FindObjectsInit"); 96817Sdinak if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) { 96917Sdinak free(*obj); 97017Sdinak return (rv); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate /* 97417Sdinak * Find all the matching objects. The loop goes 1 more beyond 97517Sdinak * the number of objects found to determine if any new objects 97617Sdinak * were created since the time the object count was done. 9770Sstevel@tonic-gate */ 97817Sdinak cryptodebug("calling C_FindObjects"); 97917Sdinak for (i = 0; i < (*count) + 1; i++) { 98017Sdinak if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != 98117Sdinak CKR_OK) 98217Sdinak break; 98317Sdinak 98417Sdinak /* No more found. */ 98517Sdinak if (obj_count == 0) 98617Sdinak break; 98717Sdinak 98817Sdinak /* 98917Sdinak * Save the object in the list being created, as long as 99017Sdinak * we don't overrun the size of the list. 99117Sdinak */ 99217Sdinak if (i < *count) 99317Sdinak (*obj)[i] = tmp_obj; 99417Sdinak else 99517Sdinak cryptodebug("number of objects changed since last count"); 99617Sdinak } 99717Sdinak 99817Sdinak if (rv != CKR_OK) { 99917Sdinak free(*obj); 100017Sdinak } else { 100117Sdinak /* 100217Sdinak * There are three cases to handle: (1) fewer objects were 100317Sdinak * found than originally counted => change *count to the 100417Sdinak * smaller number; (2) the number of objects found matches 100517Sdinak * the number originally counted => do nothing; (3) more 100617Sdinak * objects found than originally counted => list passed 100717Sdinak * in is too small to contain the extra object(s), flag 100817Sdinak * that in the debug output but don't change number of 100917Sdinak * objects returned. The caller can double-check by 101017Sdinak * calling find_obj_count() after this function to make 101117Sdinak * sure the numbers match, if desired. 101217Sdinak */ 101317Sdinak /* Case 1: Fewer objects. */ 101417Sdinak if (i < *count) { 101517Sdinak cryptodebug("%d objects found, expected %d", i, *count); 101617Sdinak *count = i; 101717Sdinak /* Case 3: More objects. */ 101817Sdinak } else if (i > *count) { 101917Sdinak cryptodebug("at least %d objects found, expected %d", 102017Sdinak i, *count); 102117Sdinak } 102217Sdinak /* 102317Sdinak * Case 2: Same number of objects. 102417Sdinak * 102517Sdinak * else if (i == *count) 102617Sdinak * ; 102717Sdinak */ 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate 103017Sdinak cryptodebug("calling C_FindObjectsFinal"); 103117Sdinak (void) C_FindObjectsFinal(sess); 103217Sdinak return (rv); 103317Sdinak } 103417Sdinak 103517Sdinak char * 103617Sdinak class_str(CK_OBJECT_CLASS class) 103717Sdinak { 103817Sdinak switch (class) { 103917Sdinak case CKO_DATA: return (gettext("data")); 104017Sdinak case CKO_CERTIFICATE: return (gettext("certificate")); 104117Sdinak case CKO_PUBLIC_KEY: return (gettext("public key")); 104217Sdinak case CKO_PRIVATE_KEY: return (gettext("private key")); 104317Sdinak case CKO_SECRET_KEY: return (gettext("secret key")); 104417Sdinak case CKO_DOMAIN_PARAMETERS: return (gettext("domain parameter")); 104517Sdinak default: return (gettext("unknown object")); 104617Sdinak } 104717Sdinak } 104817Sdinak 104917Sdinak char * 105017Sdinak keytype_str(CK_KEY_TYPE keytype) 105117Sdinak { 105217Sdinak switch (keytype) { 105317Sdinak case CKK_RSA: return (gettext("RSA")); 105417Sdinak case CKK_DSA: return (gettext("DSA")); 105517Sdinak case CKK_DH: return (gettext("Diffie-Hellman")); 105617Sdinak case CKK_X9_42_DH: return (gettext("X9.42 Diffie-Hellman")); 105717Sdinak case CKK_GENERIC_SECRET: return (gettext("generic")); 105817Sdinak case CKK_RC2: return (gettext("RC2")); 105917Sdinak case CKK_RC4: return (gettext("RC4")); 106017Sdinak case CKK_DES: return (gettext("DES")); 106117Sdinak case CKK_DES2: return (gettext("Double-DES")); 106217Sdinak case CKK_DES3: return (gettext("Triple-DES")); 106317Sdinak case CKK_RC5: return (gettext("RC5")); 106417Sdinak case CKK_AES: return (gettext("AES")); 106517Sdinak default: return (gettext("typeless")); 106617Sdinak } 106717Sdinak } 106817Sdinak 106917Sdinak char * 107017Sdinak attr_str(CK_ATTRIBUTE_TYPE attrtype) 107117Sdinak { 107217Sdinak switch (attrtype) { 107317Sdinak case CKA_PRIVATE: return (gettext("private")); 107417Sdinak case CKA_LOCAL: return (gettext("local")); 107517Sdinak case CKA_SENSITIVE: return (gettext("sensitive")); 107617Sdinak case CKA_EXTRACTABLE: return (gettext("extractable")); 107717Sdinak case CKA_ENCRYPT: return (gettext("encrypt")); 107817Sdinak case CKA_DECRYPT: return (gettext("decrypt")); 107917Sdinak case CKA_WRAP: return (gettext("wrap")); 108017Sdinak case CKA_UNWRAP: return (gettext("unwrap")); 108117Sdinak case CKA_SIGN: return (gettext("sign")); 108217Sdinak case CKA_SIGN_RECOVER: return (gettext("sign-recover")); 108317Sdinak case CKA_VERIFY: return (gettext("verify")); 108417Sdinak case CKA_VERIFY_RECOVER: return (gettext("verify-recover")); 108517Sdinak case CKA_DERIVE: return (gettext("derive")); 108617Sdinak case CKA_ALWAYS_SENSITIVE: return (gettext("always sensitive")); 108717Sdinak case CKA_NEVER_EXTRACTABLE: return (gettext("never extractable")); 108817Sdinak default: return (gettext("unknown capability")); 108917Sdinak } 10900Sstevel@tonic-gate } 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate /* 109317Sdinak * Convert a byte string into a string of octets formatted like this: 109417Sdinak * oo oo oo oo oo ... oo 109517Sdinak * where each "oo" is an octet is space separated and in the form: 109617Sdinak * [0-f][0-f] if the octet is a non-printable character 109717Sdinak * <space><char> if the octet is a printable character 109817Sdinak * 109917Sdinak * Note: octets_sz must be 3 * str_sz + 1, or at least as long as "blank" 11000Sstevel@tonic-gate */ 11010Sstevel@tonic-gate void 110217Sdinak octetify(CK_BYTE *str, CK_ULONG str_sz, char *octets, int octets_sz, 110317Sdinak boolean_t stop_on_nul, boolean_t do_ascii, int limit, char *indent, 110417Sdinak char *blank) 11050Sstevel@tonic-gate { 110617Sdinak char *marker; 110717Sdinak int nc; 110817Sdinak int newline; 110917Sdinak int indent_len; 111017Sdinak boolean_t first = B_TRUE; 111117Sdinak 111217Sdinak cryptodebug("inside octetify"); 111317Sdinak 111417Sdinak cryptodebug(stop_on_nul ? "stopping on first nul found" : 111517Sdinak "continuing to full length of buffer"); 111617Sdinak cryptodebug(do_ascii ? "using ascii chars where printable" : 111717Sdinak "using only hex octets"); 111817Sdinak cryptodebug("every %d characters indent with \"%s\"\n ", limit, indent); 111917Sdinak cryptodebug("return \"%s\" if buffer is null or empty", blank); 112017Sdinak 112117Sdinak /* If string is empty, write as much of the blank string and leave. */ 112217Sdinak if (str_sz == 0) { 112317Sdinak (void) snprintf(octets, octets_sz, "%s", blank); 112417Sdinak return; 112517Sdinak } 112617Sdinak 112717Sdinak /* If only limit or indent is set, pick default for the other. */ 112817Sdinak if (limit > 0 && indent == NULL) 112917Sdinak indent = "\n"; 113017Sdinak if (indent != NULL && limit == 0) 113117Sdinak limit = 60; 113217Sdinak indent_len = strlen(indent); 11330Sstevel@tonic-gate 113417Sdinak for (marker = octets, newline = 0, first = B_TRUE; 113517Sdinak (stop_on_nul && *str != '\0') || 113617Sdinak (!stop_on_nul && str_sz > 0 && octets_sz > 0); 113717Sdinak str++, str_sz--, marker += nc, octets_sz -= nc) { 113817Sdinak if (!first) { 113917Sdinak if (limit > 0 && ((marker - octets) / limit) > 114017Sdinak newline) { 114117Sdinak nc = snprintf(marker, indent_len, "%s", indent); 114217Sdinak newline++; 114317Sdinak continue; 114417Sdinak } 114517Sdinak nc = sprintf(marker, 114617Sdinak ((do_ascii && isprint(*str) && !isspace(*str)) ? 114717Sdinak "%s%c" : "%s%02x"), (do_ascii ? " " : ":"), *str); 114817Sdinak } else { 114917Sdinak nc = sprintf(marker, 115017Sdinak ((do_ascii && isprint(*str) && !isspace(*str)) ? 115117Sdinak "%c" : "%02x"), *str); 115217Sdinak first = B_FALSE; 115317Sdinak } 11540Sstevel@tonic-gate } 115517Sdinak *marker = '\0'; 115617Sdinak } 115717Sdinak 115817Sdinak /* 115917Sdinak * Copies a biginteger_t to a template attribute. 116017Sdinak * Should be a macro instead of a function. 116117Sdinak */ 116217Sdinak void 116317Sdinak copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr) 116417Sdinak { 116517Sdinak attr->pValue = big.big_value; 116617Sdinak attr->ulValueLen = big.big_value_len; 116717Sdinak } 116817Sdinak 116917Sdinak /* 117017Sdinak * Copies a string and its length to a template attribute. 117117Sdinak * Should be a macro instead of a function. 117217Sdinak */ 117317Sdinak void 117417Sdinak copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, CK_ATTRIBUTE_PTR attr) 117517Sdinak { 117617Sdinak attr->pValue = buf; 117717Sdinak attr->ulValueLen = buflen; 11780Sstevel@tonic-gate } 117917Sdinak 118017Sdinak /* 118117Sdinak * Copies a template attribute to a biginteger_t. 118217Sdinak * Should be a macro instead of a function. 118317Sdinak */ 118417Sdinak void 118517Sdinak copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big) 118617Sdinak { 118717Sdinak big->big_value = attr->pValue; 118817Sdinak big->big_value_len = attr->ulValueLen; 118917Sdinak } 119017Sdinak 119117Sdinak /* 119217Sdinak * Copies a template attribute to a string and its length. 119317Sdinak * Should be a macro instead of a function. 119417Sdinak */ 119517Sdinak void 119617Sdinak copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, CK_ULONG *buflen) 119717Sdinak { 119817Sdinak *buf = attr->pValue; 119917Sdinak *buflen = attr->ulValueLen; 120017Sdinak } 120117Sdinak 120217Sdinak /* 120317Sdinak * Copies a template attribute to a date and its length. 120417Sdinak * Should be a macro instead of a function. 120517Sdinak */ 120617Sdinak void 120717Sdinak copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, CK_ULONG *buflen) 120817Sdinak { 120917Sdinak *buf = (CK_DATE *)attr->pValue; 121017Sdinak *buflen = attr->ulValueLen; 121117Sdinak } 1212*864Sdinak 1213*864Sdinak /* 1214*864Sdinak * Breaks out the getopt-style option string into a structure that can be 1215*864Sdinak * traversed later for calls to getopt_av(). Option string is NOT altered, 1216*864Sdinak * but the struct fields point to locations within option string. 1217*864Sdinak */ 1218*864Sdinak static int 1219*864Sdinak populate_opts(char *optstring) 1220*864Sdinak { 1221*864Sdinak int i; 1222*864Sdinak av_opts *temp; 1223*864Sdinak char *marker; 1224*864Sdinak 1225*864Sdinak if (optstring == NULL || *optstring == '\0') 1226*864Sdinak return (0); 1227*864Sdinak 1228*864Sdinak /* 1229*864Sdinak * This tries to imitate getopt(3c) Each option must conform to: 1230*864Sdinak * <short name char> [ ':' ] [ '(' <long name string> ')' ] 1231*864Sdinak * If long name is missing, the short name is used for long name. 1232*864Sdinak */ 1233*864Sdinak for (i = 0; *optstring != '\0'; i++) { 1234*864Sdinak if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : 1235*864Sdinak realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { 1236*864Sdinak free(opts_av); 1237*864Sdinak opts_av = NULL; 1238*864Sdinak return (0); 1239*864Sdinak } else 1240*864Sdinak opts_av = (av_opts *)temp; 1241*864Sdinak 1242*864Sdinak marker = optstring; /* may need optstring later */ 1243*864Sdinak 1244*864Sdinak opts_av[i].shortnm = *marker++; /* set short name */ 1245*864Sdinak 1246*864Sdinak if (*marker == ':') { /* check for opt arg */ 1247*864Sdinak marker++; 1248*864Sdinak opts_av[i].has_arg = B_TRUE; 1249*864Sdinak } 1250*864Sdinak 1251*864Sdinak if (*marker == '(') { /* check and set long name */ 1252*864Sdinak marker++; 1253*864Sdinak opts_av[i].longnm = marker; 1254*864Sdinak opts_av[i].longnm_len = strcspn(marker, ")"); 1255*864Sdinak optstring = marker + opts_av[i].longnm_len + 1; 1256*864Sdinak } else { 1257*864Sdinak /* use short name option character */ 1258*864Sdinak opts_av[i].longnm = optstring; 1259*864Sdinak opts_av[i].longnm_len = 1; 1260*864Sdinak optstring = marker; 1261*864Sdinak } 1262*864Sdinak } 1263*864Sdinak 1264*864Sdinak return (i); 1265*864Sdinak } 1266*864Sdinak 1267*864Sdinak /* 1268*864Sdinak * getopt_av() is very similar to getopt(3c) in that the takes an option 1269*864Sdinak * string, compares command line arguments for matches, and returns a single 1270*864Sdinak * letter option when a match is found. However, getopt_av() differs from 1271*864Sdinak * getopt(3c) by requiring that only longname options and values be found 1272*864Sdinak * on the command line and all leading dashes are omitted. In other words, 1273*864Sdinak * it tries to enforce only longname "option=value" arguments on the command 1274*864Sdinak * line. Boolean options are not allowed either. 1275*864Sdinak */ 1276*864Sdinak int 1277*864Sdinak getopt_av(int argc, char * const *argv, const char *optstring) 1278*864Sdinak { 1279*864Sdinak int i; 1280*864Sdinak int len; 1281*864Sdinak 1282*864Sdinak if (optind_av >= argc) 1283*864Sdinak return (EOF); 1284*864Sdinak 1285*864Sdinak /* First time or when optstring changes from previous one */ 1286*864Sdinak if (_save_optstr != optstring) { 1287*864Sdinak if (opts_av != NULL) 1288*864Sdinak free(opts_av); 1289*864Sdinak opts_av = NULL; 1290*864Sdinak _save_optstr = optstring; 1291*864Sdinak _save_numopts = populate_opts((char *)optstring); 1292*864Sdinak } 1293*864Sdinak 1294*864Sdinak for (i = 0; i < _save_numopts; i++) { 1295*864Sdinak if (strcmp(argv[optind_av], "--") == 0) { 1296*864Sdinak optind_av++; 1297*864Sdinak break; 1298*864Sdinak } 1299*864Sdinak 1300*864Sdinak len = strcspn(argv[optind_av], "="); 1301*864Sdinak 1302*864Sdinak if (len == opts_av[i].longnm_len && strncmp(argv[optind_av], 1303*864Sdinak opts_av[i].longnm, opts_av[i].longnm_len) == 0) { 1304*864Sdinak /* matched */ 1305*864Sdinak if (!opts_av[i].has_arg) { 1306*864Sdinak optind_av++; 1307*864Sdinak return (opts_av[i].shortnm); 1308*864Sdinak } 1309*864Sdinak 1310*864Sdinak /* needs optarg */ 1311*864Sdinak if (argv[optind_av][len] == '=') { 1312*864Sdinak optarg_av = &(argv[optind_av][len+1]); 1313*864Sdinak optind_av++; 1314*864Sdinak return (opts_av[i].shortnm); 1315*864Sdinak } 1316*864Sdinak 1317*864Sdinak optarg_av = NULL; 1318*864Sdinak optind_av++; 1319*864Sdinak return ((int)'?'); 1320*864Sdinak } 1321*864Sdinak } 1322*864Sdinak 1323*864Sdinak return (EOF); 1324*864Sdinak } 1325