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 /* 23*17Sdinak * 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. 32*17Sdinak * The functions in this file return PKCS#11 CK_RV errors. 33*17Sdinak * Only one session and one login per token is supported 34*17Sdinak * 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" 44*17Sdinak #include "biginteger.h" 450Sstevel@tonic-gate 46*17Sdinak /* True and false for attribute templates. */ 47*17Sdinak CK_BBOOL pk_true = B_TRUE; 48*17Sdinak CK_BBOOL pk_false = B_FALSE; 49*17Sdinak 50*17Sdinak /* Local status variables. */ 51*17Sdinak static boolean_t initialized = B_FALSE; 52*17Sdinak static boolean_t session_opened = B_FALSE; 53*17Sdinak static boolean_t session_writable = B_FALSE; 54*17Sdinak static boolean_t logged_in = B_FALSE; 55*17Sdinak 56*17Sdinak /* 57*17Sdinak * Perform PKCS#11 setup here. Currently only C_Initialize is required, 58*17Sdinak * along with setting/resetting state variables. 59*17Sdinak */ 60*17Sdinak CK_RV 61*17Sdinak init_pk11(void) 62*17Sdinak { 63*17Sdinak CK_RV rv = CKR_OK; 64*17Sdinak 65*17Sdinak cryptodebug("inside init_pk11"); 66*17Sdinak 67*17Sdinak /* If C_Initialize() already called, nothing to do here. */ 68*17Sdinak if (initialized == B_TRUE) 69*17Sdinak return (CKR_OK); 70*17Sdinak 71*17Sdinak /* Reset state variables because C_Initialize() not yet done. */ 72*17Sdinak session_opened = B_FALSE; 73*17Sdinak session_writable = B_FALSE; 74*17Sdinak logged_in = B_FALSE; 75*17Sdinak 76*17Sdinak /* Initialize PKCS#11 library. */ 77*17Sdinak cryptodebug("calling C_Initialize()"); 78*17Sdinak if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && 79*17Sdinak rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 80*17Sdinak return (rv); 81*17Sdinak } 82*17Sdinak 83*17Sdinak initialized = B_TRUE; 84*17Sdinak return (CKR_OK); 85*17Sdinak } 86*17Sdinak 87*17Sdinak /* 88*17Sdinak * Finalize PKCS#11 library and reset state variables. Open sessions, 89*17Sdinak * if any, are closed, and thereby any logins are logged out also. 90*17Sdinak */ 91*17Sdinak void 92*17Sdinak final_pk11(CK_SESSION_HANDLE sess) 93*17Sdinak { 94*17Sdinak cryptodebug("inside final_pk11"); 95*17Sdinak 96*17Sdinak /* If the library wasn't initialized, nothing to do here. */ 97*17Sdinak if (!initialized) 98*17Sdinak return; 99*17Sdinak 100*17Sdinak /* Make sure the sesion is closed first. */ 101*17Sdinak close_sess(sess); 102*17Sdinak 103*17Sdinak cryptodebug("calling C_Finalize()"); 104*17Sdinak (void) C_Finalize(NULL); 105*17Sdinak initialized = B_FALSE; 106*17Sdinak } 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate /* 109*17Sdinak * Create a PKCS#11 session on the given slot, and set state information. 110*17Sdinak * If session is already open, check that the read-only/read-write state 111*17Sdinak * requested matches that of the session. If it doesn't, make it so. 1120Sstevel@tonic-gate */ 113*17Sdinak CK_RV 114*17Sdinak open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_SESSION_HANDLE_PTR sess) 1150Sstevel@tonic-gate { 116*17Sdinak CK_RV rv = CKR_OK; 117*17Sdinak 118*17Sdinak cryptodebug("inside open_sess"); 119*17Sdinak 120*17Sdinak /* If the session is already open, check the session flags. */ 121*17Sdinak if (session_opened) { 122*17Sdinak /* 123*17Sdinak * If requesting R/W session and it is currently R/O, 124*17Sdinak * need to close the session and reopen it R/W. The 125*17Sdinak * other cases are considered acceptable: 126*17Sdinak * sess_flags current state 127*17Sdinak * ---------- ------------- 128*17Sdinak * ~CKF_RW_SESSION !session_writable 129*17Sdinak * ~CKF_RW_SESSION session_writable 130*17Sdinak * CKF_RW_SESSION session_writable 131*17Sdinak */ 132*17Sdinak if ((sess_flags & CKF_RW_SESSION) && !session_writable) 133*17Sdinak close_sess(*sess); 134*17Sdinak else 135*17Sdinak return (CKR_OK); 136*17Sdinak } 137*17Sdinak 138*17Sdinak /* Make sure the PKCS#11 is already initialized. */ 139*17Sdinak if (!initialized) 140*17Sdinak if ((rv = init_pk11()) != CKR_OK) 141*17Sdinak return (rv); 142*17Sdinak 143*17Sdinak /* Create a session for subsequent operations. */ 144*17Sdinak cryptodebug("calling C_OpenSession()"); 145*17Sdinak if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|sess_flags, 146*17Sdinak NULL, NULL, sess)) != CKR_OK) 147*17Sdinak return (rv); 148*17Sdinak session_opened = B_TRUE; 149*17Sdinak session_writable = (sess_flags & CKF_RW_SESSION) ? B_TRUE : B_FALSE; 150*17Sdinak return (CKR_OK); 151*17Sdinak } 152*17Sdinak 153*17Sdinak /* 154*17Sdinak * Close PKCS#11 session and reset state variables. Any logins are 155*17Sdinak * logged out. 156*17Sdinak */ 157*17Sdinak void 158*17Sdinak close_sess(CK_SESSION_HANDLE sess) 159*17Sdinak { 160*17Sdinak cryptodebug("inside close_sess"); 161*17Sdinak 162*17Sdinak if (sess == NULL) { 163*17Sdinak cryptodebug("session handle is null"); 164*17Sdinak return; 165*17Sdinak } 166*17Sdinak 167*17Sdinak /* If session is already closed, nothing to do here. */ 168*17Sdinak session_writable = B_FALSE; 169*17Sdinak if (!session_opened) 170*17Sdinak return; 1710Sstevel@tonic-gate 172*17Sdinak /* Make sure user is logged out of token. */ 173*17Sdinak logout_token(sess); 174*17Sdinak 175*17Sdinak cryptodebug("calling C_CloseSession()"); 176*17Sdinak (void) C_CloseSession(sess); 177*17Sdinak session_opened = B_FALSE; 178*17Sdinak } 179*17Sdinak 180*17Sdinak /* 181*17Sdinak * Log user into token in given slot. If this first login ever for this 182*17Sdinak * token, the initial PIN is "changeme", C_Login() will succeed, but all 183*17Sdinak * PKCS#11 calls following the C_Login() will fail with CKR_PIN_EXPIRED. 184*17Sdinak */ 185*17Sdinak CK_RV 186*17Sdinak login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, 187*17Sdinak CK_SESSION_HANDLE_PTR sess) 188*17Sdinak { 189*17Sdinak CK_RV rv = CKR_OK; 190*17Sdinak 191*17Sdinak cryptodebug("inside login_token"); 192*17Sdinak 193*17Sdinak /* If already logged in, nothing to do here. */ 194*17Sdinak if (logged_in) 195*17Sdinak return (CKR_OK); 196*17Sdinak 197*17Sdinak /* Make sure we have a session first, assume R/O is enough. */ 198*17Sdinak if (!session_opened) 199*17Sdinak if ((rv = open_sess(slot_id, CKF_SERIAL_SESSION, sess)) != 200*17Sdinak CKR_OK) 201*17Sdinak return (rv); 2020Sstevel@tonic-gate 203*17Sdinak /* Log the user into the token. */ 204*17Sdinak cryptodebug("calling C_Login()"); 205*17Sdinak if ((rv = C_Login(*sess, CKU_USER, pin, pinlen)) != CKR_OK) { 206*17Sdinak cryptodebug("C_Login returns %s", pkcs11_strerror(rv)); 207*17Sdinak return (rv); 208*17Sdinak } 209*17Sdinak 210*17Sdinak logged_in = B_TRUE; 211*17Sdinak return (CKR_OK); 212*17Sdinak } 2130Sstevel@tonic-gate 214*17Sdinak /* 215*17Sdinak * Log user out of token and reset status variable. 216*17Sdinak */ 217*17Sdinak void 218*17Sdinak logout_token(CK_SESSION_HANDLE sess) 219*17Sdinak { 220*17Sdinak cryptodebug("inside logout_token"); 221*17Sdinak 222*17Sdinak if (sess == NULL) { 223*17Sdinak cryptodebug("session handle is null"); 224*17Sdinak return; 225*17Sdinak } 226*17Sdinak 227*17Sdinak /* If already logged out, nothing to do here. */ 228*17Sdinak if (!logged_in) 229*17Sdinak return; 230*17Sdinak 231*17Sdinak cryptodebug("calling C_Logout()"); 232*17Sdinak (void) C_Logout(sess); 233*17Sdinak logged_in = B_FALSE; 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /* 237*17Sdinak * Shortcut function to get from an uninitialized state to user logged in. 238*17Sdinak * If the library is already initialized, the session is already opened, 239*17Sdinak * or the user is already logged in, those steps are skipped and the next 240*17Sdinak * step is checked. 2410Sstevel@tonic-gate */ 242*17Sdinak CK_RV 243*17Sdinak quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin, 244*17Sdinak CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess) 245*17Sdinak { 246*17Sdinak CK_RV rv = CKR_OK; 247*17Sdinak 248*17Sdinak cryptodebug("inside quick_start"); 249*17Sdinak 250*17Sdinak /* Call open_sess() explicitly if R/W session is needed. */ 251*17Sdinak if (sess_flags & CKF_RW_SESSION) 252*17Sdinak if ((rv = open_sess(slot_id, sess_flags, sess)) != CKR_OK) 253*17Sdinak return (rv); 254*17Sdinak 255*17Sdinak if ((rv = login_token(slot_id, pin, pinlen, sess)) != CKR_OK) 256*17Sdinak return (rv); 257*17Sdinak 258*17Sdinak return (CKR_OK); 259*17Sdinak } 260*17Sdinak 261*17Sdinak /* 262*17Sdinak * Shortcut function to go from any state to uninitialized PKCS#11 library. 263*17Sdinak */ 264*17Sdinak void 265*17Sdinak quick_finish(CK_SESSION_HANDLE sess) 2660Sstevel@tonic-gate { 267*17Sdinak cryptodebug("inside quick_finish"); 268*17Sdinak 269*17Sdinak /* All the needed calls are done implicitly. */ 270*17Sdinak final_pk11(sess); 271*17Sdinak } 2720Sstevel@tonic-gate 273*17Sdinak /* 274*17Sdinak * Gets PIN from user. Caller needs to free the returned PIN when done. 275*17Sdinak * If two prompts are given, the PIN is confirmed with second prompt. 276*17Sdinak * Note that getphassphrase() may return data in static memory area. 277*17Sdinak */ 278*17Sdinak CK_RV 279*17Sdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) 280*17Sdinak { 281*17Sdinak char *save_phrase, *phrase1, *phrase2; 282*17Sdinak 283*17Sdinak cryptodebug("inside get_pin"); 2840Sstevel@tonic-gate 285*17Sdinak /* Prompt user for a PIN. */ 286*17Sdinak if (prompt1 == NULL) { 287*17Sdinak cryptodebug("no passphrase prompt given"); 288*17Sdinak return (CKR_ARGUMENTS_BAD); 289*17Sdinak } 290*17Sdinak if ((phrase1 = getpassphrase(prompt1)) == NULL) { 291*17Sdinak cryptodebug("getpassphrase() failed"); 292*17Sdinak return (CKR_FUNCTION_FAILED); 293*17Sdinak } 294*17Sdinak 295*17Sdinak /* Duplicate 1st PIN in separate chunk of memory. */ 296*17Sdinak if ((save_phrase = strdup(phrase1)) == NULL) 297*17Sdinak return (CKR_HOST_MEMORY); 298*17Sdinak 299*17Sdinak /* If second prompt given, PIN confirmation is requested. */ 300*17Sdinak if (prompt2 != NULL) { 301*17Sdinak if ((phrase2 = getpassphrase(prompt2)) == NULL) { 302*17Sdinak cryptodebug("getpassphrase() confirmation failed"); 303*17Sdinak free(save_phrase); 304*17Sdinak return (CKR_FUNCTION_FAILED); 305*17Sdinak } 306*17Sdinak if (strcmp(save_phrase, phrase2) != 0) { 307*17Sdinak cryptodebug("passphrases do not match"); 308*17Sdinak free(save_phrase); 309*17Sdinak return (CKR_PIN_INCORRECT); 310*17Sdinak } 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 313*17Sdinak *pin = (CK_UTF8CHAR_PTR)save_phrase; 314*17Sdinak *pinlen = strlen(save_phrase); 315*17Sdinak return (CKR_OK); 316*17Sdinak } 317*17Sdinak 318*17Sdinak /* 319*17Sdinak * Gets yes/no response from user. If either no prompt is supplied, a 320*17Sdinak * default prompt is used. If not message for invalid input is supplied, 321*17Sdinak * a default will not be provided. If the user provides no response, 322*17Sdinak * the input default B_TRUE == yes, B_FALSE == no is returned. 323*17Sdinak * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. 324*17Sdinak */ 325*17Sdinak boolean_t 326*17Sdinak yesno(char *prompt, char *invalid, boolean_t dflt) 327*17Sdinak { 328*17Sdinak char *response, buf[1024]; 329*17Sdinak char *yes = gettext("yes"); 330*17Sdinak char *no = gettext("no"); 331*17Sdinak 332*17Sdinak cryptodebug("inside yesno"); 333*17Sdinak 334*17Sdinak if (prompt == NULL) 335*17Sdinak prompt = gettext("Enter (y)es or (n)o? "); 336*17Sdinak 337*17Sdinak for (;;) { 338*17Sdinak /* Prompt user. */ 339*17Sdinak (void) printf("%s", prompt); 340*17Sdinak (void) fflush(stdout); 341*17Sdinak 342*17Sdinak /* Get the response. */ 343*17Sdinak if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) 344*17Sdinak break; /* go to default response */ 345*17Sdinak 346*17Sdinak /* Skip any leading white space. */ 347*17Sdinak while (isspace(*response)) 348*17Sdinak response++; 349*17Sdinak if (*response == '\0') 350*17Sdinak break; /* go to default response */ 351*17Sdinak 352*17Sdinak /* Is it valid input? Return appropriately. */ 353*17Sdinak if (strncasecmp(response, yes, 1) == 0) 354*17Sdinak return (B_TRUE); 355*17Sdinak if (strncasecmp(response, no, 1) == 0) 356*17Sdinak return (B_FALSE); 357*17Sdinak 358*17Sdinak /* Indicate invalid input, and try again. */ 359*17Sdinak if (invalid != NULL) 360*17Sdinak (void) printf("%s", invalid); 361*17Sdinak } 362*17Sdinak return (dflt); 363*17Sdinak } 364*17Sdinak 365*17Sdinak /* 366*17Sdinak * Gets the list of slots which have tokens in them. Keeps adjusting 367*17Sdinak * the size of the slot list buffer until the call is successful or an 368*17Sdinak * irrecoverable error occurs. 369*17Sdinak */ 370*17Sdinak CK_RV 371*17Sdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) 372*17Sdinak { 373*17Sdinak CK_ULONG tmp_count = 0; 374*17Sdinak CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; 375*17Sdinak int rv = CKR_OK; 376*17Sdinak 377*17Sdinak cryptodebug("inside get_token_slots"); 378*17Sdinak 379*17Sdinak if (!initialized) 380*17Sdinak if ((rv = init_pk11()) != CKR_OK) 381*17Sdinak return (rv); 382*17Sdinak 383*17Sdinak /* 384*17Sdinak * Get the slot count first because we don't know how many 385*17Sdinak * slots there are and how many of those slots even have tokens. 386*17Sdinak * Don't specify an arbitrary buffer size for the slot list; 387*17Sdinak * it may be too small (see section 11.5 of PKCS#11 spec). 388*17Sdinak * Also select only those slots that have tokens in them, 389*17Sdinak * because this tool has no need to know about empty slots. 390*17Sdinak */ 391*17Sdinak cryptodebug("calling C_GetSlotList() for slot count"); 392*17Sdinak if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) 393*17Sdinak return (rv); 394*17Sdinak 395*17Sdinak if (tmp_count == 0) { 396*17Sdinak cryptodebug("no slots with tokens found"); 397*17Sdinak *slot_list = NULL_PTR; 398*17Sdinak *slot_count = 0; 399*17Sdinak return (CKR_OK); 400*17Sdinak } 401*17Sdinak 402*17Sdinak /* Allocate initial space for the slot list. */ 403*17Sdinak if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * 404*17Sdinak sizeof (CK_SLOT_ID))) == NULL) 405*17Sdinak return (CKR_HOST_MEMORY); 406*17Sdinak 407*17Sdinak /* Then get the slot list itself. */ 408*17Sdinak for (;;) { 409*17Sdinak cryptodebug("calling C_GetSlotList()"); 410*17Sdinak if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { 411*17Sdinak *slot_list = tmp_list; 412*17Sdinak *slot_count = tmp_count; 413*17Sdinak break; 414*17Sdinak } 415*17Sdinak 416*17Sdinak if (rv != CKR_BUFFER_TOO_SMALL) { 417*17Sdinak free(tmp_list); 418*17Sdinak break; 419*17Sdinak } 420*17Sdinak 421*17Sdinak /* If the number of slots grew, try again. */ 422*17Sdinak cryptodebug("number of tokens present increased"); 423*17Sdinak if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, 424*17Sdinak tmp_count * sizeof (CK_SLOT_ID))) == NULL) { 425*17Sdinak free(tmp_list); 426*17Sdinak rv = CKR_HOST_MEMORY; 427*17Sdinak break; 428*17Sdinak } 429*17Sdinak tmp_list = tmp2_list; 430*17Sdinak } 431*17Sdinak 432*17Sdinak return (rv); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* 4360Sstevel@tonic-gate * memcmp_pad_max() is a specialized version of memcmp() which 4370Sstevel@tonic-gate * compares two pieces of data up to a maximum length. If the 4380Sstevel@tonic-gate * the two data match up the maximum length, they are considered 4390Sstevel@tonic-gate * matching. Trailing blanks do not cause the match to fail if 4400Sstevel@tonic-gate * one of the data is shorted. 4410Sstevel@tonic-gate * 4420Sstevel@tonic-gate * Examples of matches: 4430Sstevel@tonic-gate * "one" | 4440Sstevel@tonic-gate * "one " | 4450Sstevel@tonic-gate * ^maximum length 4460Sstevel@tonic-gate * 4470Sstevel@tonic-gate * "Number One | X" (X is beyond maximum length) 4480Sstevel@tonic-gate * "Number One " | 4490Sstevel@tonic-gate * ^maximum length 4500Sstevel@tonic-gate * 4510Sstevel@tonic-gate * Examples of mismatches: 4520Sstevel@tonic-gate * " one" 4530Sstevel@tonic-gate * "one" 4540Sstevel@tonic-gate * 4550Sstevel@tonic-gate * "Number One X|" 4560Sstevel@tonic-gate * "Number One |" 4570Sstevel@tonic-gate * ^maximum length 4580Sstevel@tonic-gate */ 4590Sstevel@tonic-gate static int 4600Sstevel@tonic-gate memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz) 4610Sstevel@tonic-gate { 4620Sstevel@tonic-gate uint_t len, extra_len; 4630Sstevel@tonic-gate char *marker; 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* No point in comparing anything beyond max_sz */ 4660Sstevel@tonic-gate if (d1_len > max_sz) 4670Sstevel@tonic-gate d1_len = max_sz; 4680Sstevel@tonic-gate if (d2_len > max_sz) 4690Sstevel@tonic-gate d2_len = max_sz; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* Find shorter of the two data. */ 4720Sstevel@tonic-gate if (d1_len <= d2_len) { 4730Sstevel@tonic-gate len = d1_len; 4740Sstevel@tonic-gate extra_len = d2_len; 4750Sstevel@tonic-gate marker = d2; 4760Sstevel@tonic-gate } else { /* d1_len > d2_len */ 4770Sstevel@tonic-gate len = d2_len; 4780Sstevel@tonic-gate extra_len = d1_len; 4790Sstevel@tonic-gate marker = d1; 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* Have a match in the shortest length of data? */ 4830Sstevel@tonic-gate if (memcmp(d1, d2, len) != 0) 4840Sstevel@tonic-gate /* CONSTCOND */ 4850Sstevel@tonic-gate return (!0); 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* If the rest of longer data is nulls or blanks, call it a match. */ 4880Sstevel@tonic-gate while (len < extra_len) 4890Sstevel@tonic-gate if (!isspace(marker[len++])) 4900Sstevel@tonic-gate /* CONSTCOND */ 4910Sstevel@tonic-gate return (!0); 4920Sstevel@tonic-gate return (0); 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate /* 496*17Sdinak * Locate a token slot whose token matches the label, manufacturer ID, and 497*17Sdinak * serial number given. Token label must be specified, manufacturer ID and 498*17Sdinak * serial number are optional. When the token is located, the PIN state 499*17Sdinak * is also returned to determine if it still has the default PIN. 5000Sstevel@tonic-gate */ 501*17Sdinak CK_RV 5020Sstevel@tonic-gate find_token_slot(char *token_name, char *manuf_id, char *serial_no, 5030Sstevel@tonic-gate CK_SLOT_ID *slot_id, CK_FLAGS *pin_state) 5040Sstevel@tonic-gate { 5050Sstevel@tonic-gate CK_SLOT_ID_PTR slot_list; 5060Sstevel@tonic-gate CK_TOKEN_INFO token_info; 5070Sstevel@tonic-gate CK_ULONG slot_count = 0; 508*17Sdinak int rv = CKR_OK; 5090Sstevel@tonic-gate int i; 5100Sstevel@tonic-gate uint_t len, max_sz; 5110Sstevel@tonic-gate boolean_t tok_match = B_FALSE, 5120Sstevel@tonic-gate man_match = B_FALSE, 5130Sstevel@tonic-gate ser_match = B_FALSE; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate cryptodebug("inside find_token_slot"); 5160Sstevel@tonic-gate 517*17Sdinak if (token_name == NULL) 518*17Sdinak return (CKR_ARGUMENTS_BAD); 5190Sstevel@tonic-gate 520*17Sdinak /* Get a list of all slots with tokens present. */ 521*17Sdinak if ((rv = get_token_slots(&slot_list, &slot_count)) != CKR_OK) 522*17Sdinak return (rv); 5230Sstevel@tonic-gate 524*17Sdinak /* If there are no such slots, the desired token won't be found. */ 525*17Sdinak if (slot_count == 0) 526*17Sdinak return (CKR_TOKEN_NOT_PRESENT); 5270Sstevel@tonic-gate 528*17Sdinak /* Search the slot list for the token. */ 5290Sstevel@tonic-gate for (i = 0; i < slot_count; i++) { 530*17Sdinak cryptodebug("calling C_GetTokenInfo()"); 531*17Sdinak if ((rv = C_GetTokenInfo(slot_list[i], &token_info)) != 532*17Sdinak CKR_OK) { 533*17Sdinak cryptodebug("token in slot %d returns %s", i, 534*17Sdinak pkcs11_strerror(rv)); 5350Sstevel@tonic-gate continue; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 538*17Sdinak /* See if the token label matches. */ 5390Sstevel@tonic-gate len = strlen(token_name); 5400Sstevel@tonic-gate max_sz = sizeof (token_info.label); 5410Sstevel@tonic-gate if (memcmp_pad_max(&(token_info.label), max_sz, token_name, len, 5420Sstevel@tonic-gate max_sz) == 0) 5430Sstevel@tonic-gate tok_match = B_TRUE; 5440Sstevel@tonic-gate 545*17Sdinak /* 546*17Sdinak * If manufacturer id was given, see if it actually matches. 547*17Sdinak * If no manufacturer id was given, assume match is true. 548*17Sdinak */ 549*17Sdinak if (manuf_id) { 550*17Sdinak len = strlen(manuf_id); 551*17Sdinak max_sz = sizeof ((char *)(token_info.manufacturerID)); 552*17Sdinak if (memcmp_pad_max(&(token_info.manufacturerID), max_sz, 553*17Sdinak manuf_id, len, max_sz) == 0) 554*17Sdinak man_match = B_TRUE; 555*17Sdinak } else 556*17Sdinak man_match = B_TRUE; 557*17Sdinak 558*17Sdinak /* 559*17Sdinak * If serial number was given, see if it actually matches. 560*17Sdinak * If no serial number was given, assume match is true. 561*17Sdinak */ 562*17Sdinak if (serial_no) { 563*17Sdinak len = strlen(serial_no); 564*17Sdinak max_sz = sizeof ((char *)(token_info.serialNumber)); 565*17Sdinak if (memcmp_pad_max(&(token_info.serialNumber), max_sz, 566*17Sdinak serial_no, len, max_sz) == 0) 567*17Sdinak ser_match = B_TRUE; 568*17Sdinak } else 569*17Sdinak ser_match = B_TRUE; 570*17Sdinak 5710Sstevel@tonic-gate cryptodebug("slot %d:", i); 572*17Sdinak cryptodebug("\tlabel = \"%.32s\"%s", token_info.label, 573*17Sdinak tok_match ? " match" : ""); 574*17Sdinak cryptodebug("\tmanuf = \"%.32s\"%s", token_info.manufacturerID, 575*17Sdinak man_match ? " match" : ""); 576*17Sdinak cryptodebug("\tserno = \"%.16s\"%s", token_info.serialNumber, 577*17Sdinak ser_match ? " match" : ""); 5780Sstevel@tonic-gate cryptodebug("\tmodel = \"%.16s\"", token_info.model); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s", 5810Sstevel@tonic-gate (token_info.flags & CKF_USER_PIN_INITIALIZED) ? 5820Sstevel@tonic-gate "true" : "false"); 5830Sstevel@tonic-gate cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s", 5840Sstevel@tonic-gate (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? 5850Sstevel@tonic-gate "true" : "false"); 5860Sstevel@tonic-gate 587*17Sdinak if (tok_match && man_match && ser_match) 588*17Sdinak break; /* found it! */ 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 591*17Sdinak /* Scanned the whole list without finding the token. */ 5920Sstevel@tonic-gate if (i == slot_count) { 593*17Sdinak cryptodebug("token not found"); 5940Sstevel@tonic-gate free(slot_list); 595*17Sdinak return (CKR_TOKEN_NOT_PRESENT); 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 598*17Sdinak /* Return slot id where token was found and its PIN state. */ 599*17Sdinak cryptodebug("token found at slot %d", i); 6000Sstevel@tonic-gate *slot_id = slot_list[i]; 6010Sstevel@tonic-gate *pin_state = (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED); 6020Sstevel@tonic-gate free(slot_list); 603*17Sdinak return (CKR_OK); 604*17Sdinak } 605*17Sdinak 606*17Sdinak /* 607*17Sdinak * Constructs a fully qualified token name from its label, manufacturer ID 608*17Sdinak * (if any), and its serial number (if any). Note that the given buf must 609*17Sdinak * be big enough. Do NOT i18n/l10n. 610*17Sdinak * 611*17Sdinak * FULL_NAME_LEN is defined in common.h to be 91 because a fully qualified 612*17Sdinak * token name adds up this way: 613*17Sdinak * =32(label) + 32(manuf) + 16(serial) + 4("", ) + 4("", ) + 3("" and nul) 614*17Sdinak */ 615*17Sdinak void 616*17Sdinak full_token_name(char *token_name, char *manuf_id, char *serial_no, char *buf) 617*17Sdinak { 618*17Sdinak char *marker = buf; 619*17Sdinak int n_written = 0; 620*17Sdinak int space_left = FULL_NAME_LEN; 621*17Sdinak 622*17Sdinak if (!token_name) 623*17Sdinak return; 624*17Sdinak 625*17Sdinak n_written = sprintf(buf, "\"%.32s\"", token_name); 626*17Sdinak marker += n_written; 627*17Sdinak space_left -= n_written; 628*17Sdinak 629*17Sdinak n_written = sprintf(marker, ", \"%.32s\"", manuf_id ? manuf_id : ""); 630*17Sdinak marker += n_written; 631*17Sdinak space_left -= n_written; 632*17Sdinak 633*17Sdinak n_written = sprintf(marker, ", \"%.16s\"", serial_no ? serial_no : ""); 634*17Sdinak marker += n_written; 635*17Sdinak space_left -= n_written; 636*17Sdinak 637*17Sdinak /* space_left should always be >= 1 */ 638*17Sdinak } 639*17Sdinak 640*17Sdinak /* 641*17Sdinak * Find how many token objects with the given label. 642*17Sdinak */ 643*17Sdinak CK_RV 644*17Sdinak find_obj_count(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, 645*17Sdinak CK_ULONG *count) 646*17Sdinak { 647*17Sdinak CK_RV rv = CKR_OK; 648*17Sdinak CK_ATTRIBUTE attrs[4] = { 649*17Sdinak { CKA_TOKEN, &pk_true, sizeof (pk_true) }, 650*17Sdinak { 0, NULL, 0 }, 651*17Sdinak { 0, NULL, 0 }, 652*17Sdinak { 0, NULL, 0 } 653*17Sdinak }; 654*17Sdinak CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); 655*17Sdinak CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ 656*17Sdinak CK_OBJECT_CLASS obj_class; 657*17Sdinak CK_OBJECT_HANDLE tmp_obj; 658*17Sdinak CK_ULONG obj_count = 0; 659*17Sdinak 660*17Sdinak cryptodebug("inside find_obj_count"); 661*17Sdinak 662*17Sdinak if (!session_opened || sess == NULL) { 663*17Sdinak cryptodebug("session handle is null"); 664*17Sdinak return (CKR_SESSION_HANDLE_INVALID); 665*17Sdinak } 666*17Sdinak 667*17Sdinak if (label) { 668*17Sdinak cryptodebug("object label was specified"); 669*17Sdinak attrs[cur_attr].type = CKA_LABEL; 670*17Sdinak attrs[cur_attr].pValue = label; 671*17Sdinak attrs[cur_attr].ulValueLen = strlen((char *)label); 672*17Sdinak cur_attr++; 673*17Sdinak } 674*17Sdinak 675*17Sdinak if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { 676*17Sdinak cryptodebug("only searching for private objects"); 677*17Sdinak attrs[cur_attr].type = CKA_PRIVATE; 678*17Sdinak attrs[cur_attr].pValue = &pk_true; 679*17Sdinak attrs[cur_attr].ulValueLen = sizeof (pk_true); 680*17Sdinak cur_attr++; 681*17Sdinak } 682*17Sdinak 683*17Sdinak /* 684*17Sdinak * If "certs and all keys" is not specified, but at least either 685*17Sdinak * "certs" or some "keys" is specified, then go into this block. 686*17Sdinak * If all certs and keys were specified, there's no point in 687*17Sdinak * putting that fact in the attribute template -- leave that open, 688*17Sdinak * and all certs and keys will be matched automatically. 689*17Sdinak * In other words, only if at least one of 0x10,0x20,0x40,0x80 690*17Sdinak * bits is off, go into this code block. 691*17Sdinak * 692*17Sdinak * NOTE: For now, only one of cert or key types is allowed. 693*17Sdinak * This needs to change in the future. 694*17Sdinak */ 695*17Sdinak if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && 696*17Sdinak ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { 697*17Sdinak if (obj_type & PK_CERT_OBJ) { 698*17Sdinak cryptodebug("only searching for certificates"); 699*17Sdinak obj_class = CKO_CERTIFICATE; 700*17Sdinak } else if (obj_type & PK_PRIKEY_OBJ) { 701*17Sdinak cryptodebug("only searching for private keys"); 702*17Sdinak obj_class = CKO_PRIVATE_KEY; 703*17Sdinak } else if (obj_type & PK_PUBKEY_OBJ) { 704*17Sdinak cryptodebug("only searching for public keys"); 705*17Sdinak obj_class = CKO_PUBLIC_KEY; 706*17Sdinak } else if (obj_type & PK_SECKEY_OBJ) { 707*17Sdinak cryptodebug("only searching for secret keys"); 708*17Sdinak obj_class = CKO_SECRET_KEY; 709*17Sdinak } 710*17Sdinak 711*17Sdinak attrs[cur_attr].type = CKA_CLASS; 712*17Sdinak attrs[cur_attr].pValue = &obj_class; 713*17Sdinak attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); 714*17Sdinak cur_attr++; 715*17Sdinak } 716*17Sdinak 717*17Sdinak /* 718*17Sdinak * This can't happen now. When finding objects is enhanced in the 719*17Sdinak * future. this could lead to buffer overruns. 720*17Sdinak */ 721*17Sdinak if (cur_attr > num_attrs) 722*17Sdinak cryptodebug("internal error: attr template overrun"); 723*17Sdinak 724*17Sdinak cryptodebug("calling C_FindObjectsInit"); 725*17Sdinak if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) 726*17Sdinak return (rv); 727*17Sdinak 728*17Sdinak /* Look for the object, checking if there are more than one. */ 729*17Sdinak cryptodebug("calling C_FindObjects"); 730*17Sdinak for (*count = 0; /* empty */; (*count)++) { 731*17Sdinak if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != 732*17Sdinak CKR_OK) 733*17Sdinak break; 734*17Sdinak 735*17Sdinak /* No more found. */ 736*17Sdinak if (obj_count == 0) 737*17Sdinak break; 738*17Sdinak } 739*17Sdinak 740*17Sdinak cryptodebug("%d matching objects found", *count); 741*17Sdinak 742*17Sdinak cryptodebug("calling C_FindObjectsFinal"); 743*17Sdinak (void) C_FindObjectsFinal(sess); 744*17Sdinak return (rv); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate /* 748*17Sdinak * Find the token object with the given label. 7490Sstevel@tonic-gate */ 750*17Sdinak CK_RV 751*17Sdinak find_objs(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, 752*17Sdinak CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count) 7530Sstevel@tonic-gate { 754*17Sdinak CK_RV rv = CKR_OK; 755*17Sdinak CK_ATTRIBUTE attrs[4] = { 756*17Sdinak { CKA_TOKEN, &pk_true, sizeof (pk_true) }, 757*17Sdinak { 0, NULL, 0 }, 758*17Sdinak { 0, NULL, 0 }, 759*17Sdinak { 0, NULL, 0 } 760*17Sdinak }; 761*17Sdinak CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); 762*17Sdinak CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ 763*17Sdinak CK_OBJECT_CLASS obj_class; 764*17Sdinak CK_OBJECT_HANDLE tmp_obj; 765*17Sdinak CK_ULONG obj_count = 0; 766*17Sdinak int i; 767*17Sdinak 768*17Sdinak cryptodebug("inside find_obj"); 769*17Sdinak 770*17Sdinak if ((rv = find_obj_count(sess, obj_type, label, count)) != CKR_OK) 771*17Sdinak return (rv); 772*17Sdinak 773*17Sdinak if (*count == 0) 774*17Sdinak return (CKR_OK); 775*17Sdinak 776*17Sdinak if ((*obj = (CK_OBJECT_HANDLE_PTR) malloc((*count) * 777*17Sdinak sizeof (CK_OBJECT_HANDLE))) == NULL) { 778*17Sdinak cryptodebug("no memory for found object"); 779*17Sdinak return (CKR_HOST_MEMORY); 780*17Sdinak } 781*17Sdinak 782*17Sdinak if (label) { 783*17Sdinak cryptodebug("object label was specified"); 784*17Sdinak attrs[cur_attr].type = CKA_LABEL; 785*17Sdinak attrs[cur_attr].pValue = label; 786*17Sdinak attrs[cur_attr].ulValueLen = strlen((char *)label); 787*17Sdinak cur_attr++; 788*17Sdinak } 7890Sstevel@tonic-gate 790*17Sdinak if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { 791*17Sdinak cryptodebug("only searching for private objects"); 792*17Sdinak attrs[cur_attr].type = CKA_PRIVATE; 793*17Sdinak attrs[cur_attr].pValue = &pk_true; 794*17Sdinak attrs[cur_attr].ulValueLen = sizeof (pk_true); 795*17Sdinak cur_attr++; 796*17Sdinak } 7970Sstevel@tonic-gate 798*17Sdinak /* 799*17Sdinak * If "certs and all keys" is not specified, but at least either 800*17Sdinak * "certs" or some "keys" is specified, then go into this block. 801*17Sdinak * If all certs and keys were specified, there's no point in 802*17Sdinak * putting that fact in the attribute template -- leave that open, 803*17Sdinak * and all certs and keys will be matched automatically. 804*17Sdinak * In other words, only if at least one of 0x10,0x20,0x40,0x80 805*17Sdinak * bits is off, go into this code block. 806*17Sdinak * 807*17Sdinak * NOTE: For now, only one of cert or key types is allowed. 808*17Sdinak * This needs to change in the future. 809*17Sdinak */ 810*17Sdinak if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && 811*17Sdinak ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { 812*17Sdinak if (obj_type & PK_CERT_OBJ) { 813*17Sdinak cryptodebug("only searching for certificates"); 814*17Sdinak obj_class = CKO_CERTIFICATE; 815*17Sdinak } else if (obj_type & PK_PRIKEY_OBJ) { 816*17Sdinak cryptodebug("only searching for private keys"); 817*17Sdinak obj_class = CKO_PRIVATE_KEY; 818*17Sdinak } else if (obj_type & PK_PUBKEY_OBJ) { 819*17Sdinak cryptodebug("only searching for public keys"); 820*17Sdinak obj_class = CKO_PUBLIC_KEY; 821*17Sdinak } else if (obj_type & PK_SECKEY_OBJ) { 822*17Sdinak cryptodebug("only searching for secret keys"); 823*17Sdinak obj_class = CKO_SECRET_KEY; 824*17Sdinak } 825*17Sdinak 826*17Sdinak attrs[cur_attr].type = CKA_CLASS; 827*17Sdinak attrs[cur_attr].pValue = &obj_class; 828*17Sdinak attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); 829*17Sdinak cur_attr++; 830*17Sdinak } 831*17Sdinak 832*17Sdinak /* 833*17Sdinak * This can't happen now. When finding objects is enhanced in the 834*17Sdinak * future. this could lead to buffer overruns. 835*17Sdinak */ 836*17Sdinak if (cur_attr > num_attrs) 837*17Sdinak cryptodebug("internal error: attr template overrun"); 838*17Sdinak 839*17Sdinak cryptodebug("calling C_FindObjectsInit"); 840*17Sdinak if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) { 841*17Sdinak free(*obj); 842*17Sdinak return (rv); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate /* 846*17Sdinak * Find all the matching objects. The loop goes 1 more beyond 847*17Sdinak * the number of objects found to determine if any new objects 848*17Sdinak * were created since the time the object count was done. 8490Sstevel@tonic-gate */ 850*17Sdinak cryptodebug("calling C_FindObjects"); 851*17Sdinak for (i = 0; i < (*count) + 1; i++) { 852*17Sdinak if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != 853*17Sdinak CKR_OK) 854*17Sdinak break; 855*17Sdinak 856*17Sdinak /* No more found. */ 857*17Sdinak if (obj_count == 0) 858*17Sdinak break; 859*17Sdinak 860*17Sdinak /* 861*17Sdinak * Save the object in the list being created, as long as 862*17Sdinak * we don't overrun the size of the list. 863*17Sdinak */ 864*17Sdinak if (i < *count) 865*17Sdinak (*obj)[i] = tmp_obj; 866*17Sdinak else 867*17Sdinak cryptodebug("number of objects changed since last count"); 868*17Sdinak } 869*17Sdinak 870*17Sdinak if (rv != CKR_OK) { 871*17Sdinak free(*obj); 872*17Sdinak } else { 873*17Sdinak /* 874*17Sdinak * There are three cases to handle: (1) fewer objects were 875*17Sdinak * found than originally counted => change *count to the 876*17Sdinak * smaller number; (2) the number of objects found matches 877*17Sdinak * the number originally counted => do nothing; (3) more 878*17Sdinak * objects found than originally counted => list passed 879*17Sdinak * in is too small to contain the extra object(s), flag 880*17Sdinak * that in the debug output but don't change number of 881*17Sdinak * objects returned. The caller can double-check by 882*17Sdinak * calling find_obj_count() after this function to make 883*17Sdinak * sure the numbers match, if desired. 884*17Sdinak */ 885*17Sdinak /* Case 1: Fewer objects. */ 886*17Sdinak if (i < *count) { 887*17Sdinak cryptodebug("%d objects found, expected %d", i, *count); 888*17Sdinak *count = i; 889*17Sdinak /* Case 3: More objects. */ 890*17Sdinak } else if (i > *count) { 891*17Sdinak cryptodebug("at least %d objects found, expected %d", 892*17Sdinak i, *count); 893*17Sdinak } 894*17Sdinak /* 895*17Sdinak * Case 2: Same number of objects. 896*17Sdinak * 897*17Sdinak * else if (i == *count) 898*17Sdinak * ; 899*17Sdinak */ 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate 902*17Sdinak cryptodebug("calling C_FindObjectsFinal"); 903*17Sdinak (void) C_FindObjectsFinal(sess); 904*17Sdinak return (rv); 905*17Sdinak } 906*17Sdinak 907*17Sdinak char * 908*17Sdinak class_str(CK_OBJECT_CLASS class) 909*17Sdinak { 910*17Sdinak switch (class) { 911*17Sdinak case CKO_DATA: return (gettext("data")); 912*17Sdinak case CKO_CERTIFICATE: return (gettext("certificate")); 913*17Sdinak case CKO_PUBLIC_KEY: return (gettext("public key")); 914*17Sdinak case CKO_PRIVATE_KEY: return (gettext("private key")); 915*17Sdinak case CKO_SECRET_KEY: return (gettext("secret key")); 916*17Sdinak case CKO_DOMAIN_PARAMETERS: return (gettext("domain parameter")); 917*17Sdinak default: return (gettext("unknown object")); 918*17Sdinak } 919*17Sdinak } 920*17Sdinak 921*17Sdinak char * 922*17Sdinak keytype_str(CK_KEY_TYPE keytype) 923*17Sdinak { 924*17Sdinak switch (keytype) { 925*17Sdinak case CKK_RSA: return (gettext("RSA")); 926*17Sdinak case CKK_DSA: return (gettext("DSA")); 927*17Sdinak case CKK_DH: return (gettext("Diffie-Hellman")); 928*17Sdinak case CKK_X9_42_DH: return (gettext("X9.42 Diffie-Hellman")); 929*17Sdinak case CKK_GENERIC_SECRET: return (gettext("generic")); 930*17Sdinak case CKK_RC2: return (gettext("RC2")); 931*17Sdinak case CKK_RC4: return (gettext("RC4")); 932*17Sdinak case CKK_DES: return (gettext("DES")); 933*17Sdinak case CKK_DES2: return (gettext("Double-DES")); 934*17Sdinak case CKK_DES3: return (gettext("Triple-DES")); 935*17Sdinak case CKK_RC5: return (gettext("RC5")); 936*17Sdinak case CKK_AES: return (gettext("AES")); 937*17Sdinak default: return (gettext("typeless")); 938*17Sdinak } 939*17Sdinak } 940*17Sdinak 941*17Sdinak char * 942*17Sdinak attr_str(CK_ATTRIBUTE_TYPE attrtype) 943*17Sdinak { 944*17Sdinak switch (attrtype) { 945*17Sdinak case CKA_PRIVATE: return (gettext("private")); 946*17Sdinak case CKA_LOCAL: return (gettext("local")); 947*17Sdinak case CKA_SENSITIVE: return (gettext("sensitive")); 948*17Sdinak case CKA_EXTRACTABLE: return (gettext("extractable")); 949*17Sdinak case CKA_ENCRYPT: return (gettext("encrypt")); 950*17Sdinak case CKA_DECRYPT: return (gettext("decrypt")); 951*17Sdinak case CKA_WRAP: return (gettext("wrap")); 952*17Sdinak case CKA_UNWRAP: return (gettext("unwrap")); 953*17Sdinak case CKA_SIGN: return (gettext("sign")); 954*17Sdinak case CKA_SIGN_RECOVER: return (gettext("sign-recover")); 955*17Sdinak case CKA_VERIFY: return (gettext("verify")); 956*17Sdinak case CKA_VERIFY_RECOVER: return (gettext("verify-recover")); 957*17Sdinak case CKA_DERIVE: return (gettext("derive")); 958*17Sdinak case CKA_ALWAYS_SENSITIVE: return (gettext("always sensitive")); 959*17Sdinak case CKA_NEVER_EXTRACTABLE: return (gettext("never extractable")); 960*17Sdinak default: return (gettext("unknown capability")); 961*17Sdinak } 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate /* 965*17Sdinak * Convert a byte string into a string of octets formatted like this: 966*17Sdinak * oo oo oo oo oo ... oo 967*17Sdinak * where each "oo" is an octet is space separated and in the form: 968*17Sdinak * [0-f][0-f] if the octet is a non-printable character 969*17Sdinak * <space><char> if the octet is a printable character 970*17Sdinak * 971*17Sdinak * Note: octets_sz must be 3 * str_sz + 1, or at least as long as "blank" 9720Sstevel@tonic-gate */ 9730Sstevel@tonic-gate void 974*17Sdinak octetify(CK_BYTE *str, CK_ULONG str_sz, char *octets, int octets_sz, 975*17Sdinak boolean_t stop_on_nul, boolean_t do_ascii, int limit, char *indent, 976*17Sdinak char *blank) 9770Sstevel@tonic-gate { 978*17Sdinak char *marker; 979*17Sdinak int nc; 980*17Sdinak int newline; 981*17Sdinak int indent_len; 982*17Sdinak boolean_t first = B_TRUE; 983*17Sdinak 984*17Sdinak cryptodebug("inside octetify"); 985*17Sdinak 986*17Sdinak cryptodebug(stop_on_nul ? "stopping on first nul found" : 987*17Sdinak "continuing to full length of buffer"); 988*17Sdinak cryptodebug(do_ascii ? "using ascii chars where printable" : 989*17Sdinak "using only hex octets"); 990*17Sdinak cryptodebug("every %d characters indent with \"%s\"\n ", limit, indent); 991*17Sdinak cryptodebug("return \"%s\" if buffer is null or empty", blank); 992*17Sdinak 993*17Sdinak /* If string is empty, write as much of the blank string and leave. */ 994*17Sdinak if (str_sz == 0) { 995*17Sdinak (void) snprintf(octets, octets_sz, "%s", blank); 996*17Sdinak return; 997*17Sdinak } 998*17Sdinak 999*17Sdinak /* If only limit or indent is set, pick default for the other. */ 1000*17Sdinak if (limit > 0 && indent == NULL) 1001*17Sdinak indent = "\n"; 1002*17Sdinak if (indent != NULL && limit == 0) 1003*17Sdinak limit = 60; 1004*17Sdinak indent_len = strlen(indent); 10050Sstevel@tonic-gate 1006*17Sdinak for (marker = octets, newline = 0, first = B_TRUE; 1007*17Sdinak (stop_on_nul && *str != '\0') || 1008*17Sdinak (!stop_on_nul && str_sz > 0 && octets_sz > 0); 1009*17Sdinak str++, str_sz--, marker += nc, octets_sz -= nc) { 1010*17Sdinak if (!first) { 1011*17Sdinak if (limit > 0 && ((marker - octets) / limit) > 1012*17Sdinak newline) { 1013*17Sdinak nc = snprintf(marker, indent_len, "%s", indent); 1014*17Sdinak newline++; 1015*17Sdinak continue; 1016*17Sdinak } 1017*17Sdinak nc = sprintf(marker, 1018*17Sdinak ((do_ascii && isprint(*str) && !isspace(*str)) ? 1019*17Sdinak "%s%c" : "%s%02x"), (do_ascii ? " " : ":"), *str); 1020*17Sdinak } else { 1021*17Sdinak nc = sprintf(marker, 1022*17Sdinak ((do_ascii && isprint(*str) && !isspace(*str)) ? 1023*17Sdinak "%c" : "%02x"), *str); 1024*17Sdinak first = B_FALSE; 1025*17Sdinak } 10260Sstevel@tonic-gate } 1027*17Sdinak *marker = '\0'; 1028*17Sdinak } 1029*17Sdinak 1030*17Sdinak /* 1031*17Sdinak * Copies a biginteger_t to a template attribute. 1032*17Sdinak * Should be a macro instead of a function. 1033*17Sdinak */ 1034*17Sdinak void 1035*17Sdinak copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr) 1036*17Sdinak { 1037*17Sdinak attr->pValue = big.big_value; 1038*17Sdinak attr->ulValueLen = big.big_value_len; 1039*17Sdinak } 1040*17Sdinak 1041*17Sdinak /* 1042*17Sdinak * Copies a string and its length to a template attribute. 1043*17Sdinak * Should be a macro instead of a function. 1044*17Sdinak */ 1045*17Sdinak void 1046*17Sdinak copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, CK_ATTRIBUTE_PTR attr) 1047*17Sdinak { 1048*17Sdinak attr->pValue = buf; 1049*17Sdinak attr->ulValueLen = buflen; 10500Sstevel@tonic-gate } 1051*17Sdinak 1052*17Sdinak /* 1053*17Sdinak * Copies a template attribute to a biginteger_t. 1054*17Sdinak * Should be a macro instead of a function. 1055*17Sdinak */ 1056*17Sdinak void 1057*17Sdinak copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big) 1058*17Sdinak { 1059*17Sdinak big->big_value = attr->pValue; 1060*17Sdinak big->big_value_len = attr->ulValueLen; 1061*17Sdinak } 1062*17Sdinak 1063*17Sdinak /* 1064*17Sdinak * Copies a template attribute to a string and its length. 1065*17Sdinak * Should be a macro instead of a function. 1066*17Sdinak */ 1067*17Sdinak void 1068*17Sdinak copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, CK_ULONG *buflen) 1069*17Sdinak { 1070*17Sdinak *buf = attr->pValue; 1071*17Sdinak *buflen = attr->ulValueLen; 1072*17Sdinak } 1073*17Sdinak 1074*17Sdinak /* 1075*17Sdinak * Copies a template attribute to a date and its length. 1076*17Sdinak * Should be a macro instead of a function. 1077*17Sdinak */ 1078*17Sdinak void 1079*17Sdinak copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, CK_ULONG *buflen) 1080*17Sdinak { 1081*17Sdinak *buf = (CK_DATE *)attr->pValue; 1082*17Sdinak *buflen = attr->ulValueLen; 1083*17Sdinak } 1084