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 5*3089Swyllys * Common Development and Distribution License (the "License"). 6*3089Swyllys * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3089Swyllys * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * This file contains the functions that are shared among 300Sstevel@tonic-gate * the various services this tool will ultimately provide. 3117Sdinak * The functions in this file return PKCS#11 CK_RV errors. 3217Sdinak * Only one session and one login per token is supported 3317Sdinak * at this time. 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <stdio.h> 370Sstevel@tonic-gate #include <stdlib.h> 380Sstevel@tonic-gate #include <string.h> 390Sstevel@tonic-gate #include <ctype.h> 40*3089Swyllys #include <sys/types.h> 41*3089Swyllys #include <sys/stat.h> 42*3089Swyllys #include <fcntl.h> 43*3089Swyllys #include <tzfile.h> 440Sstevel@tonic-gate #include <cryptoutil.h> 450Sstevel@tonic-gate #include <security/cryptoki.h> 46*3089Swyllys #include <kmfapi.h> 470Sstevel@tonic-gate 48*3089Swyllys #include "common.h" 4917Sdinak 5017Sdinak /* Local status variables. */ 5117Sdinak static boolean_t initialized = B_FALSE; 5217Sdinak static boolean_t session_opened = B_FALSE; 5317Sdinak static boolean_t logged_in = B_FALSE; 5417Sdinak 55864Sdinak /* Supporting structures and global variables for getopt_av(). */ 56864Sdinak typedef struct av_opts_s { 57864Sdinak int shortnm; /* short name character */ 58864Sdinak char *longnm; /* long name string, NOT terminated */ 59864Sdinak int longnm_len; /* length of long name string */ 60864Sdinak boolean_t has_arg; /* takes optional argument */ 61864Sdinak } av_opts; 62864Sdinak static av_opts *opts_av = NULL; 63864Sdinak static const char *_save_optstr = NULL; 64864Sdinak static int _save_numopts = 0; 65864Sdinak 66864Sdinak int optind_av = 1; 67864Sdinak char *optarg_av = NULL; 68864Sdinak 69*3089Swyllys static void close_sess(CK_SESSION_HANDLE); 70*3089Swyllys static void logout_token(CK_SESSION_HANDLE); 71*3089Swyllys 7217Sdinak /* 7317Sdinak * Perform PKCS#11 setup here. Currently only C_Initialize is required, 7417Sdinak * along with setting/resetting state variables. 7517Sdinak */ 7617Sdinak CK_RV 7717Sdinak init_pk11(void) 7817Sdinak { 7917Sdinak CK_RV rv = CKR_OK; 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 logged_in = B_FALSE; 8817Sdinak 8917Sdinak /* Initialize PKCS#11 library. */ 9017Sdinak if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && 9117Sdinak rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 9217Sdinak return (rv); 9317Sdinak } 9417Sdinak 9517Sdinak initialized = B_TRUE; 9617Sdinak return (CKR_OK); 9717Sdinak } 9817Sdinak 9917Sdinak /* 10017Sdinak * Finalize PKCS#11 library and reset state variables. Open sessions, 10117Sdinak * if any, are closed, and thereby any logins are logged out also. 10217Sdinak */ 10317Sdinak void 10417Sdinak final_pk11(CK_SESSION_HANDLE sess) 10517Sdinak { 10617Sdinak 10717Sdinak /* If the library wasn't initialized, nothing to do here. */ 10817Sdinak if (!initialized) 10917Sdinak return; 11017Sdinak 11117Sdinak /* Make sure the sesion is closed first. */ 11217Sdinak close_sess(sess); 11317Sdinak 11417Sdinak (void) C_Finalize(NULL); 11517Sdinak initialized = B_FALSE; 11617Sdinak } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate /* 11917Sdinak * Close PKCS#11 session and reset state variables. Any logins are 12017Sdinak * logged out. 12117Sdinak */ 122*3089Swyllys static void 12317Sdinak close_sess(CK_SESSION_HANDLE sess) 12417Sdinak { 12517Sdinak 12617Sdinak if (sess == NULL) { 12717Sdinak return; 12817Sdinak } 12917Sdinak 13017Sdinak /* If session is already closed, nothing to do here. */ 13117Sdinak if (!session_opened) 13217Sdinak return; 1330Sstevel@tonic-gate 13417Sdinak /* Make sure user is logged out of token. */ 13517Sdinak logout_token(sess); 13617Sdinak 13717Sdinak (void) C_CloseSession(sess); 13817Sdinak session_opened = B_FALSE; 13917Sdinak } 14017Sdinak 14117Sdinak /* 14217Sdinak * Log user out of token and reset status variable. 14317Sdinak */ 144*3089Swyllys static void 14517Sdinak logout_token(CK_SESSION_HANDLE sess) 14617Sdinak { 14717Sdinak 14817Sdinak if (sess == NULL) { 14917Sdinak return; 15017Sdinak } 15117Sdinak 15217Sdinak /* If already logged out, nothing to do here. */ 15317Sdinak if (!logged_in) 15417Sdinak return; 15517Sdinak 15617Sdinak (void) C_Logout(sess); 15717Sdinak logged_in = B_FALSE; 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 16117Sdinak * Gets PIN from user. Caller needs to free the returned PIN when done. 16217Sdinak * If two prompts are given, the PIN is confirmed with second prompt. 16317Sdinak * Note that getphassphrase() may return data in static memory area. 16417Sdinak */ 16517Sdinak CK_RV 16617Sdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) 16717Sdinak { 16817Sdinak char *save_phrase, *phrase1, *phrase2; 16917Sdinak 170*3089Swyllys 171*3089Swyllys #ifdef DEBUG 172*3089Swyllys if (getenv("TOKENPIN") != NULL) { 173*3089Swyllys *pin = (CK_UTF8CHAR_PTR)strdup(getenv("TOKENPIN")); 174*3089Swyllys *pinlen = strlen((char *)(*pin)); 175*3089Swyllys return (CKR_OK); 176*3089Swyllys } 177*3089Swyllys #endif /* DEBUG */ 1780Sstevel@tonic-gate 17917Sdinak /* Prompt user for a PIN. */ 18017Sdinak if (prompt1 == NULL) { 18117Sdinak return (CKR_ARGUMENTS_BAD); 18217Sdinak } 18317Sdinak if ((phrase1 = getpassphrase(prompt1)) == NULL) { 18417Sdinak return (CKR_FUNCTION_FAILED); 18517Sdinak } 18617Sdinak 18717Sdinak /* Duplicate 1st PIN in separate chunk of memory. */ 18817Sdinak if ((save_phrase = strdup(phrase1)) == NULL) 18917Sdinak return (CKR_HOST_MEMORY); 19017Sdinak 19117Sdinak /* If second prompt given, PIN confirmation is requested. */ 19217Sdinak if (prompt2 != NULL) { 19317Sdinak if ((phrase2 = getpassphrase(prompt2)) == NULL) { 19417Sdinak free(save_phrase); 19517Sdinak return (CKR_FUNCTION_FAILED); 19617Sdinak } 19717Sdinak if (strcmp(save_phrase, phrase2) != 0) { 19817Sdinak free(save_phrase); 19917Sdinak return (CKR_PIN_INCORRECT); 20017Sdinak } 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 20317Sdinak *pin = (CK_UTF8CHAR_PTR)save_phrase; 20417Sdinak *pinlen = strlen(save_phrase); 20517Sdinak return (CKR_OK); 20617Sdinak } 20717Sdinak 20817Sdinak /* 20917Sdinak * Gets yes/no response from user. If either no prompt is supplied, a 21017Sdinak * default prompt is used. If not message for invalid input is supplied, 21117Sdinak * a default will not be provided. If the user provides no response, 21217Sdinak * the input default B_TRUE == yes, B_FALSE == no is returned. 21317Sdinak * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. 21417Sdinak */ 21517Sdinak boolean_t 21617Sdinak yesno(char *prompt, char *invalid, boolean_t dflt) 21717Sdinak { 21817Sdinak char *response, buf[1024]; 21917Sdinak char *yes = gettext("yes"); 22017Sdinak char *no = gettext("no"); 22117Sdinak 222*3089Swyllys 223*3089Swyllys #ifdef DEBUG 224*3089Swyllys /* If debugging or testing, return TRUE and avoid prompting */ 225*3089Swyllys if (getenv("TOKENPIN") != NULL) { 226*3089Swyllys return (B_TRUE); 227*3089Swyllys } 228*3089Swyllys #endif /* DEBUG */ 22917Sdinak 23017Sdinak if (prompt == NULL) 23117Sdinak prompt = gettext("Enter (y)es or (n)o? "); 23217Sdinak 23317Sdinak for (;;) { 23417Sdinak /* Prompt user. */ 23517Sdinak (void) printf("%s", prompt); 23617Sdinak (void) fflush(stdout); 23717Sdinak 23817Sdinak /* Get the response. */ 23917Sdinak if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) 24017Sdinak break; /* go to default response */ 24117Sdinak 24217Sdinak /* Skip any leading white space. */ 24317Sdinak while (isspace(*response)) 24417Sdinak response++; 24517Sdinak if (*response == '\0') 24617Sdinak break; /* go to default response */ 24717Sdinak 24817Sdinak /* Is it valid input? Return appropriately. */ 24917Sdinak if (strncasecmp(response, yes, 1) == 0) 25017Sdinak return (B_TRUE); 25117Sdinak if (strncasecmp(response, no, 1) == 0) 25217Sdinak return (B_FALSE); 25317Sdinak 25417Sdinak /* Indicate invalid input, and try again. */ 25517Sdinak if (invalid != NULL) 25617Sdinak (void) printf("%s", invalid); 25717Sdinak } 25817Sdinak return (dflt); 25917Sdinak } 26017Sdinak 26117Sdinak /* 26217Sdinak * Gets the list of slots which have tokens in them. Keeps adjusting 26317Sdinak * the size of the slot list buffer until the call is successful or an 26417Sdinak * irrecoverable error occurs. 26517Sdinak */ 26617Sdinak CK_RV 26717Sdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) 26817Sdinak { 26917Sdinak CK_ULONG tmp_count = 0; 27017Sdinak CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; 27117Sdinak int rv = CKR_OK; 27217Sdinak 27317Sdinak if (!initialized) 27417Sdinak if ((rv = init_pk11()) != CKR_OK) 27517Sdinak return (rv); 27617Sdinak 27717Sdinak /* 27817Sdinak * Get the slot count first because we don't know how many 27917Sdinak * slots there are and how many of those slots even have tokens. 28017Sdinak * Don't specify an arbitrary buffer size for the slot list; 28117Sdinak * it may be too small (see section 11.5 of PKCS#11 spec). 28217Sdinak * Also select only those slots that have tokens in them, 28317Sdinak * because this tool has no need to know about empty slots. 28417Sdinak */ 28517Sdinak if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) 28617Sdinak return (rv); 28717Sdinak 28817Sdinak if (tmp_count == 0) { 28917Sdinak *slot_list = NULL_PTR; 29017Sdinak *slot_count = 0; 29117Sdinak return (CKR_OK); 29217Sdinak } 29317Sdinak 29417Sdinak /* Allocate initial space for the slot list. */ 29517Sdinak if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * 29617Sdinak sizeof (CK_SLOT_ID))) == NULL) 29717Sdinak return (CKR_HOST_MEMORY); 29817Sdinak 29917Sdinak /* Then get the slot list itself. */ 30017Sdinak for (;;) { 30117Sdinak if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { 30217Sdinak *slot_list = tmp_list; 30317Sdinak *slot_count = tmp_count; 30417Sdinak break; 30517Sdinak } 30617Sdinak 30717Sdinak if (rv != CKR_BUFFER_TOO_SMALL) { 30817Sdinak free(tmp_list); 30917Sdinak break; 31017Sdinak } 31117Sdinak 31217Sdinak /* If the number of slots grew, try again. */ 31317Sdinak if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, 31417Sdinak tmp_count * sizeof (CK_SLOT_ID))) == NULL) { 31517Sdinak free(tmp_list); 31617Sdinak rv = CKR_HOST_MEMORY; 31717Sdinak break; 31817Sdinak } 31917Sdinak tmp_list = tmp2_list; 32017Sdinak } 32117Sdinak 32217Sdinak return (rv); 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate /* 326864Sdinak * Breaks out the getopt-style option string into a structure that can be 327864Sdinak * traversed later for calls to getopt_av(). Option string is NOT altered, 328864Sdinak * but the struct fields point to locations within option string. 329864Sdinak */ 330864Sdinak static int 331864Sdinak populate_opts(char *optstring) 332864Sdinak { 333864Sdinak int i; 334864Sdinak av_opts *temp; 335864Sdinak char *marker; 336864Sdinak 337864Sdinak if (optstring == NULL || *optstring == '\0') 338864Sdinak return (0); 339864Sdinak 340864Sdinak /* 341864Sdinak * This tries to imitate getopt(3c) Each option must conform to: 342864Sdinak * <short name char> [ ':' ] [ '(' <long name string> ')' ] 343864Sdinak * If long name is missing, the short name is used for long name. 344864Sdinak */ 345864Sdinak for (i = 0; *optstring != '\0'; i++) { 346864Sdinak if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : 347864Sdinak realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { 348*3089Swyllys if (opts_av != NULL) 349*3089Swyllys free(opts_av); 350864Sdinak opts_av = NULL; 351864Sdinak return (0); 352*3089Swyllys } else { 353864Sdinak opts_av = (av_opts *)temp; 354*3089Swyllys } 355864Sdinak 356*3089Swyllys (void) memset(&opts_av[i], 0, sizeof (av_opts)); 357864Sdinak marker = optstring; /* may need optstring later */ 358864Sdinak 359864Sdinak opts_av[i].shortnm = *marker++; /* set short name */ 360864Sdinak 361864Sdinak if (*marker == ':') { /* check for opt arg */ 362864Sdinak marker++; 363864Sdinak opts_av[i].has_arg = B_TRUE; 364864Sdinak } 365864Sdinak 366864Sdinak if (*marker == '(') { /* check and set long name */ 367864Sdinak marker++; 368864Sdinak opts_av[i].longnm = marker; 369864Sdinak opts_av[i].longnm_len = strcspn(marker, ")"); 370864Sdinak optstring = marker + opts_av[i].longnm_len + 1; 371864Sdinak } else { 372864Sdinak /* use short name option character */ 373864Sdinak opts_av[i].longnm = optstring; 374864Sdinak opts_av[i].longnm_len = 1; 375864Sdinak optstring = marker; 376864Sdinak } 377864Sdinak } 378864Sdinak 379864Sdinak return (i); 380864Sdinak } 381864Sdinak 382864Sdinak /* 383864Sdinak * getopt_av() is very similar to getopt(3c) in that the takes an option 384864Sdinak * string, compares command line arguments for matches, and returns a single 385864Sdinak * letter option when a match is found. However, getopt_av() differs from 386864Sdinak * getopt(3c) by requiring that only longname options and values be found 387864Sdinak * on the command line and all leading dashes are omitted. In other words, 388864Sdinak * it tries to enforce only longname "option=value" arguments on the command 389864Sdinak * line. Boolean options are not allowed either. 390864Sdinak */ 391864Sdinak int 392864Sdinak getopt_av(int argc, char * const *argv, const char *optstring) 393864Sdinak { 394864Sdinak int i; 395864Sdinak int len; 396*3089Swyllys char *cur_option; 397864Sdinak 398864Sdinak if (optind_av >= argc) 399864Sdinak return (EOF); 400864Sdinak 401864Sdinak /* First time or when optstring changes from previous one */ 402864Sdinak if (_save_optstr != optstring) { 403864Sdinak if (opts_av != NULL) 404864Sdinak free(opts_av); 405864Sdinak opts_av = NULL; 406864Sdinak _save_optstr = optstring; 407864Sdinak _save_numopts = populate_opts((char *)optstring); 408864Sdinak } 409864Sdinak 410864Sdinak for (i = 0; i < _save_numopts; i++) { 411*3089Swyllys cur_option = argv[optind_av]; 412*3089Swyllys 413*3089Swyllys if (strcmp(cur_option, "--") == 0) { 414864Sdinak optind_av++; 415864Sdinak break; 416864Sdinak } 417864Sdinak 418*3089Swyllys if (cur_option[0] == '-' && strlen(cur_option) == 2) { 419*3089Swyllys len = 1; 420*3089Swyllys cur_option++; /* remove "-" */ 421*3089Swyllys } else { 422*3089Swyllys len = strcspn(cur_option, "="); 423*3089Swyllys } 424864Sdinak 425*3089Swyllys if (len == opts_av[i].longnm_len && strncmp(cur_option, 426864Sdinak opts_av[i].longnm, opts_av[i].longnm_len) == 0) { 427864Sdinak /* matched */ 428864Sdinak if (!opts_av[i].has_arg) { 429864Sdinak optind_av++; 430864Sdinak return (opts_av[i].shortnm); 431864Sdinak } 432864Sdinak 433864Sdinak /* needs optarg */ 434*3089Swyllys if (cur_option[len] == '=') { 435*3089Swyllys optarg_av = &(cur_option[len+1]); 436864Sdinak optind_av++; 437864Sdinak return (opts_av[i].shortnm); 438864Sdinak } 439864Sdinak 440864Sdinak optarg_av = NULL; 441864Sdinak optind_av++; 442864Sdinak return ((int)'?'); 443864Sdinak } 444864Sdinak } 445864Sdinak 446864Sdinak return (EOF); 447864Sdinak } 448*3089Swyllys 449*3089Swyllys KMF_KEYSTORE_TYPE 450*3089Swyllys KS2Int(char *keystore_str) 451*3089Swyllys { 452*3089Swyllys if (keystore_str == NULL) 453*3089Swyllys return (0); 454*3089Swyllys if (!strcasecmp(keystore_str, "pkcs11")) 455*3089Swyllys return (KMF_KEYSTORE_PK11TOKEN); 456*3089Swyllys else if (!strcasecmp(keystore_str, "nss")) 457*3089Swyllys return (KMF_KEYSTORE_NSS); 458*3089Swyllys else if (!strcasecmp(keystore_str, "file")) 459*3089Swyllys return (KMF_KEYSTORE_OPENSSL); 460*3089Swyllys else 461*3089Swyllys return (0); 462*3089Swyllys } 463*3089Swyllys 464*3089Swyllys 465*3089Swyllys int 466*3089Swyllys Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg) 467*3089Swyllys { 468*3089Swyllys if (algm == NULL) { 469*3089Swyllys *sigAlg = KMF_ALGID_MD5WithRSA; 470*3089Swyllys *ktype = KMF_RSA; 471*3089Swyllys } else if (strcasecmp(algm, "DSA") == 0) { 472*3089Swyllys *sigAlg = KMF_ALGID_SHA1WithDSA; 473*3089Swyllys *ktype = KMF_DSA; 474*3089Swyllys } else if (strcasecmp(algm, "RSA") == 0) { 475*3089Swyllys *sigAlg = KMF_ALGID_MD5WithRSA; 476*3089Swyllys *ktype = KMF_RSA; 477*3089Swyllys } else { 478*3089Swyllys return (-1); 479*3089Swyllys } 480*3089Swyllys return (0); 481*3089Swyllys } 482*3089Swyllys 483*3089Swyllys int 484*3089Swyllys Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype) 485*3089Swyllys { 486*3089Swyllys if (algm == NULL) 487*3089Swyllys *ktype = KMF_AES; 488*3089Swyllys else if (strcasecmp(algm, "aes") == 0) 489*3089Swyllys *ktype = KMF_AES; 490*3089Swyllys else if (strcasecmp(algm, "arcfour") == 0) 491*3089Swyllys *ktype = KMF_RC4; 492*3089Swyllys else if (strcasecmp(algm, "des") == 0) 493*3089Swyllys *ktype = KMF_DES; 494*3089Swyllys else if (strcasecmp(algm, "3des") == 0) 495*3089Swyllys *ktype = KMF_DES3; 496*3089Swyllys else 497*3089Swyllys return (-1); 498*3089Swyllys 499*3089Swyllys return (0); 500*3089Swyllys } 501*3089Swyllys 502*3089Swyllys int 503*3089Swyllys Str2Lifetime(char *ltimestr, uint32_t *ltime) 504*3089Swyllys { 505*3089Swyllys int num; 506*3089Swyllys char timetok[6]; 507*3089Swyllys 508*3089Swyllys if (ltimestr == NULL || !strlen(ltimestr)) { 509*3089Swyllys /* default to 1 year lifetime */ 510*3089Swyllys *ltime = SECSPERDAY * DAYSPERNYEAR; 511*3089Swyllys return (0); 512*3089Swyllys } 513*3089Swyllys 514*3089Swyllys (void) memset(timetok, 0, sizeof (timetok)); 515*3089Swyllys if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2) 516*3089Swyllys return (-1); 517*3089Swyllys 518*3089Swyllys if (!strcasecmp(timetok, "day") || 519*3089Swyllys !strcasecmp(timetok, "days")) { 520*3089Swyllys *ltime = num * SECSPERDAY; 521*3089Swyllys } else if (!strcasecmp(timetok, "hour") || 522*3089Swyllys !strcasecmp(timetok, "hours")) { 523*3089Swyllys *ltime = num * SECSPERHOUR; 524*3089Swyllys } else if (!strcasecmp(timetok, "year") || 525*3089Swyllys !strcasecmp(timetok, "years")) { 526*3089Swyllys *ltime = num * SECSPERDAY * DAYSPERNYEAR; 527*3089Swyllys } else { 528*3089Swyllys *ltime = 0; 529*3089Swyllys return (-1); 530*3089Swyllys } 531*3089Swyllys 532*3089Swyllys return (0); 533*3089Swyllys } 534*3089Swyllys 535*3089Swyllys int 536*3089Swyllys OT2Int(char *objclass) 537*3089Swyllys { 538*3089Swyllys char *c = NULL; 539*3089Swyllys int retval = 0; 540*3089Swyllys 541*3089Swyllys if (objclass == NULL) 542*3089Swyllys return (-1); 543*3089Swyllys 544*3089Swyllys c = strchr(objclass, ':'); 545*3089Swyllys if (c != NULL) { 546*3089Swyllys if (!strcasecmp(c, ":private")) 547*3089Swyllys retval = PK_PRIVATE_OBJ; 548*3089Swyllys else if (!strcasecmp(c, ":public")) 549*3089Swyllys retval = PK_PUBLIC_OBJ; 550*3089Swyllys else if (!strcasecmp(c, ":both")) 551*3089Swyllys retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ; 552*3089Swyllys else /* unrecognized option */ 553*3089Swyllys return (-1); 554*3089Swyllys 555*3089Swyllys *c = '\0'; 556*3089Swyllys } 557*3089Swyllys 558*3089Swyllys if (!strcasecmp(objclass, "public")) { 559*3089Swyllys if (retval) 560*3089Swyllys return (-1); 561*3089Swyllys return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | 562*3089Swyllys PK_PUBKEY_OBJ); 563*3089Swyllys } else if (!strcasecmp(objclass, "private")) { 564*3089Swyllys if (retval) 565*3089Swyllys return (-1); 566*3089Swyllys return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); 567*3089Swyllys } else if (!strcasecmp(objclass, "both")) { 568*3089Swyllys if (retval) 569*3089Swyllys return (-1); 570*3089Swyllys return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); 571*3089Swyllys } else if (!strcasecmp(objclass, "cert")) { 572*3089Swyllys return (retval | PK_CERT_OBJ); 573*3089Swyllys } else if (!strcasecmp(objclass, "key")) { 574*3089Swyllys if (retval == 0) /* return all keys */ 575*3089Swyllys return (retval | PK_KEY_OBJ); 576*3089Swyllys else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) 577*3089Swyllys /* return all keys */ 578*3089Swyllys return (retval | PK_KEY_OBJ); 579*3089Swyllys else if (retval & PK_PUBLIC_OBJ) 580*3089Swyllys /* Only return public keys */ 581*3089Swyllys return (retval | PK_PUBKEY_OBJ); 582*3089Swyllys else if (retval & PK_PRIVATE_OBJ) 583*3089Swyllys /* Only return private keys */ 584*3089Swyllys return (retval | PK_PRIKEY_OBJ); 585*3089Swyllys } else if (!strcasecmp(objclass, "crl")) { 586*3089Swyllys if (retval) 587*3089Swyllys return (-1); 588*3089Swyllys return (retval | PK_CRL_OBJ); 589*3089Swyllys } 590*3089Swyllys 591*3089Swyllys if (retval == 0) /* No matches found */ 592*3089Swyllys retval = -1; 593*3089Swyllys return (retval); 594*3089Swyllys } 595*3089Swyllys 596*3089Swyllys KMF_ENCODE_FORMAT 597*3089Swyllys Str2Format(char *formstr) 598*3089Swyllys { 599*3089Swyllys if (formstr == NULL || !strcasecmp(formstr, "der")) 600*3089Swyllys return (KMF_FORMAT_ASN1); 601*3089Swyllys if (!strcasecmp(formstr, "pem")) 602*3089Swyllys return (KMF_FORMAT_PEM); 603*3089Swyllys if (!strcasecmp(formstr, "pkcs12")) 604*3089Swyllys return (KMF_FORMAT_PKCS12); 605*3089Swyllys 606*3089Swyllys return (KMF_FORMAT_UNDEF); 607*3089Swyllys } 608*3089Swyllys 609*3089Swyllys 610*3089Swyllys KMF_RETURN 611*3089Swyllys select_token(void *kmfhandle, char *token, 612*3089Swyllys int readonly) 613*3089Swyllys { 614*3089Swyllys KMF_RETURN rv = KMF_OK; 615*3089Swyllys KMF_CONFIG_PARAMS config; 616*3089Swyllys 617*3089Swyllys if (token == NULL) 618*3089Swyllys return (KMF_ERR_BAD_PARAMETER); 619*3089Swyllys 620*3089Swyllys (void) memset(&config, 0, sizeof (config)); 621*3089Swyllys config.kstype = KMF_KEYSTORE_PK11TOKEN; 622*3089Swyllys config.pkcs11config.label = token; 623*3089Swyllys config.pkcs11config.readonly = readonly; 624*3089Swyllys 625*3089Swyllys rv = KMF_ConfigureKeystore(kmfhandle, &config); 626*3089Swyllys if (rv == KMF_ERR_TOKEN_SELECTED) 627*3089Swyllys rv = KMF_OK; 628*3089Swyllys return (rv); 629*3089Swyllys } 630*3089Swyllys 631*3089Swyllys 632*3089Swyllys KMF_RETURN 633*3089Swyllys configure_nss(void *kmfhandle, char *dir, char *prefix) 634*3089Swyllys { 635*3089Swyllys KMF_RETURN rv = KMF_OK; 636*3089Swyllys KMF_CONFIG_PARAMS config; 637*3089Swyllys 638*3089Swyllys (void) memset(&config, 0, sizeof (config)); 639*3089Swyllys config.kstype = KMF_KEYSTORE_NSS; 640*3089Swyllys config.nssconfig.configdir = dir; 641*3089Swyllys config.nssconfig.certPrefix = prefix; 642*3089Swyllys config.nssconfig.keyPrefix = prefix; 643*3089Swyllys config.nssconfig.secModName = NULL; 644*3089Swyllys 645*3089Swyllys rv = KMF_ConfigureKeystore(kmfhandle, &config); 646*3089Swyllys if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) 647*3089Swyllys rv = KMF_OK; 648*3089Swyllys 649*3089Swyllys return (rv); 650*3089Swyllys } 651*3089Swyllys 652*3089Swyllys 653*3089Swyllys KMF_RETURN 654*3089Swyllys get_pk12_password(KMF_CREDENTIAL *cred) 655*3089Swyllys { 656*3089Swyllys KMF_RETURN rv = KMF_OK; 657*3089Swyllys char prompt[1024]; 658*3089Swyllys 659*3089Swyllys /* 660*3089Swyllys * Get the password to use for the PK12 encryption. 661*3089Swyllys */ 662*3089Swyllys (void) strlcpy(prompt, 663*3089Swyllys gettext("Enter password to use for " 664*3089Swyllys "accessing the PKCS12 file: "), 665*3089Swyllys sizeof (prompt)); 666*3089Swyllys 667*3089Swyllys if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 668*3089Swyllys (ulong_t *)&cred->credlen) != CKR_OK) { 669*3089Swyllys cred->cred = NULL; 670*3089Swyllys cred->credlen = 0; 671*3089Swyllys } 672*3089Swyllys 673*3089Swyllys return (rv); 674*3089Swyllys } 675*3089Swyllys 676*3089Swyllys 677*3089Swyllys #define COUNTRY_PROMPT "Country Name (2 letter code) [US]:" 678*3089Swyllys #define STATE_PROMPT "State or Province Name (full name) [Some-State]:" 679*3089Swyllys #define LOCALITY_PROMPT "Locality Name (eg, city) []:" 680*3089Swyllys #define ORG_PROMPT "Organization Name (eg, company) []:" 681*3089Swyllys #define UNIT_PROMPT "Organizational Unit Name (eg, section) []:" 682*3089Swyllys #define NAME_PROMPT "Common Name (eg, YOUR name) []:" 683*3089Swyllys #define EMAIL_PROMPT "Email Address []:" 684*3089Swyllys 685*3089Swyllys #define COUNTRY_DEFAULT "US" 686*3089Swyllys #define STATE_DEFAULT "Some-State" 687*3089Swyllys #define INVALID_INPUT "Invalid input; please re-enter ..." 688*3089Swyllys 689*3089Swyllys #define SUBNAMESIZ 1024 690*3089Swyllys #define RDN_MIN 1 691*3089Swyllys #define RDN_MAX 64 692*3089Swyllys #define COUNTRYNAME_MIN 2 693*3089Swyllys #define COUNTRYNAME_MAX 2 694*3089Swyllys 695*3089Swyllys static char * 696*3089Swyllys get_input_string(char *prompt, char *default_str, int min_len, int max_len) 697*3089Swyllys { 698*3089Swyllys char buf[1024]; 699*3089Swyllys char *response = NULL; 700*3089Swyllys char *ret = NULL; 701*3089Swyllys int len; 702*3089Swyllys 703*3089Swyllys for (;;) { 704*3089Swyllys (void) printf("\t%s", prompt); 705*3089Swyllys (void) fflush(stdout); 706*3089Swyllys 707*3089Swyllys response = fgets(buf, sizeof (buf), stdin); 708*3089Swyllys if (response == NULL) { 709*3089Swyllys if (default_str != NULL) { 710*3089Swyllys ret = strdup(default_str); 711*3089Swyllys } 712*3089Swyllys break; 713*3089Swyllys } 714*3089Swyllys 715*3089Swyllys /* Skip any leading white space. */ 716*3089Swyllys while (isspace(*response)) 717*3089Swyllys response++; 718*3089Swyllys if (*response == '\0') { 719*3089Swyllys if (default_str != NULL) { 720*3089Swyllys ret = strdup(default_str); 721*3089Swyllys } 722*3089Swyllys break; 723*3089Swyllys } 724*3089Swyllys 725*3089Swyllys len = strlen(response); 726*3089Swyllys response[len-1] = '\0'; /* get rid of "LF" */ 727*3089Swyllys len--; 728*3089Swyllys if (len >= min_len && len <= max_len) { 729*3089Swyllys ret = strdup(response); 730*3089Swyllys break; 731*3089Swyllys } 732*3089Swyllys 733*3089Swyllys (void) printf("%s\n", INVALID_INPUT); 734*3089Swyllys 735*3089Swyllys } 736*3089Swyllys 737*3089Swyllys return (ret); 738*3089Swyllys } 739*3089Swyllys 740*3089Swyllys int 741*3089Swyllys get_subname(char **result) 742*3089Swyllys { 743*3089Swyllys char *country = NULL; 744*3089Swyllys char *state = NULL; 745*3089Swyllys char *locality = NULL; 746*3089Swyllys char *org = NULL; 747*3089Swyllys char *unit = NULL; 748*3089Swyllys char *name = NULL; 749*3089Swyllys char *email = NULL; 750*3089Swyllys char *subname = NULL; 751*3089Swyllys 752*3089Swyllys (void) printf("Entering following fields for subject (a DN) ...\n"); 753*3089Swyllys country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, 754*3089Swyllys COUNTRYNAME_MIN, COUNTRYNAME_MAX); 755*3089Swyllys if (country == NULL) 756*3089Swyllys return (-1); 757*3089Swyllys 758*3089Swyllys state = get_input_string(STATE_PROMPT, STATE_DEFAULT, 759*3089Swyllys RDN_MIN, RDN_MAX); 760*3089Swyllys if (state == NULL) { 761*3089Swyllys goto out; 762*3089Swyllys } 763*3089Swyllys 764*3089Swyllys locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); 765*3089Swyllys org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); 766*3089Swyllys unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); 767*3089Swyllys name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); 768*3089Swyllys email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); 769*3089Swyllys 770*3089Swyllys /* Now create a subject name from the input strings */ 771*3089Swyllys if ((subname = malloc(SUBNAMESIZ)) == NULL) 772*3089Swyllys goto out; 773*3089Swyllys 774*3089Swyllys (void) memset(subname, 0, SUBNAMESIZ); 775*3089Swyllys (void) strlcpy(subname, "C=", SUBNAMESIZ); 776*3089Swyllys (void) strlcat(subname, country, SUBNAMESIZ); 777*3089Swyllys (void) strlcat(subname, ", ", SUBNAMESIZ); 778*3089Swyllys (void) strlcat(subname, "ST=", SUBNAMESIZ); 779*3089Swyllys (void) strlcat(subname, state, SUBNAMESIZ); 780*3089Swyllys 781*3089Swyllys if (locality) { 782*3089Swyllys (void) strlcat(subname, ", ", SUBNAMESIZ); 783*3089Swyllys (void) strlcat(subname, "L=", SUBNAMESIZ); 784*3089Swyllys (void) strlcat(subname, locality, SUBNAMESIZ); 785*3089Swyllys } 786*3089Swyllys 787*3089Swyllys if (org) { 788*3089Swyllys (void) strlcat(subname, ", ", SUBNAMESIZ); 789*3089Swyllys (void) strlcat(subname, "O=", SUBNAMESIZ); 790*3089Swyllys (void) strlcat(subname, org, SUBNAMESIZ); 791*3089Swyllys } 792*3089Swyllys 793*3089Swyllys if (unit) { 794*3089Swyllys (void) strlcat(subname, ", ", SUBNAMESIZ); 795*3089Swyllys (void) strlcat(subname, "OU=", SUBNAMESIZ); 796*3089Swyllys (void) strlcat(subname, unit, SUBNAMESIZ); 797*3089Swyllys } 798*3089Swyllys 799*3089Swyllys if (name) { 800*3089Swyllys (void) strlcat(subname, ", ", SUBNAMESIZ); 801*3089Swyllys (void) strlcat(subname, "CN=", SUBNAMESIZ); 802*3089Swyllys (void) strlcat(subname, name, SUBNAMESIZ); 803*3089Swyllys } 804*3089Swyllys 805*3089Swyllys if (email) { 806*3089Swyllys (void) strlcat(subname, ", ", SUBNAMESIZ); 807*3089Swyllys (void) strlcat(subname, "E=", SUBNAMESIZ); 808*3089Swyllys (void) strlcat(subname, email, SUBNAMESIZ); 809*3089Swyllys } 810*3089Swyllys 811*3089Swyllys out: 812*3089Swyllys if (country) 813*3089Swyllys free(country); 814*3089Swyllys if (state) 815*3089Swyllys free(state); 816*3089Swyllys if (locality) 817*3089Swyllys free(locality); 818*3089Swyllys if (org) 819*3089Swyllys free(org); 820*3089Swyllys if (unit) 821*3089Swyllys free(unit); 822*3089Swyllys if (name) 823*3089Swyllys free(name); 824*3089Swyllys if (email) 825*3089Swyllys free(email); 826*3089Swyllys 827*3089Swyllys if (subname == NULL) 828*3089Swyllys return (-1); 829*3089Swyllys else { 830*3089Swyllys *result = subname; 831*3089Swyllys return (0); 832*3089Swyllys } 833*3089Swyllys } 834*3089Swyllys 835*3089Swyllys /* 836*3089Swyllys * Parse a string of KeyUsage values and convert 837*3089Swyllys * them to the correct KU Bits. 838*3089Swyllys * The field may be marked "critical" by prepending 839*3089Swyllys * "critical:" to the list. 840*3089Swyllys * EX: critical:digitialSignature,keyEncipherment 841*3089Swyllys */ 842*3089Swyllys KMF_RETURN 843*3089Swyllys verify_keyusage(char *kustr, uint16_t *kubits, int *critical) 844*3089Swyllys { 845*3089Swyllys KMF_RETURN ret = KMF_OK; 846*3089Swyllys uint16_t kuval; 847*3089Swyllys char *k; 848*3089Swyllys 849*3089Swyllys *kubits = 0; 850*3089Swyllys if (kustr == NULL || !strlen(kustr)) 851*3089Swyllys return (KMF_ERR_BAD_PARAMETER); 852*3089Swyllys 853*3089Swyllys /* Check to see if this is critical */ 854*3089Swyllys if (!strncasecmp(kustr, "critical:", strlen("critical:"))) { 855*3089Swyllys *critical = TRUE; 856*3089Swyllys kustr += strlen("critical:"); 857*3089Swyllys } else { 858*3089Swyllys *critical = FALSE; 859*3089Swyllys } 860*3089Swyllys 861*3089Swyllys k = strtok(kustr, ","); 862*3089Swyllys while (k != NULL) { 863*3089Swyllys kuval = KMF_StringToKeyUsage(k); 864*3089Swyllys if (kuval == 0) { 865*3089Swyllys *kubits = 0; 866*3089Swyllys return (KMF_ERR_BAD_PARAMETER); 867*3089Swyllys } 868*3089Swyllys *kubits |= kuval; 869*3089Swyllys k = strtok(NULL, ","); 870*3089Swyllys } 871*3089Swyllys 872*3089Swyllys return (ret); 873*3089Swyllys } 874*3089Swyllys 875*3089Swyllys /* 876*3089Swyllys * Verify the alternate subject label is real or invalid. 877*3089Swyllys * 878*3089Swyllys * The field may be marked "critical" by prepending 879*3089Swyllys * "critical:" to the list. 880*3089Swyllys * EX: "critical:IP=1.2.3.4" 881*3089Swyllys */ 882*3089Swyllys KMF_RETURN 883*3089Swyllys verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) 884*3089Swyllys { 885*3089Swyllys char *p; 886*3089Swyllys KMF_RETURN rv = KMF_OK; 887*3089Swyllys 888*3089Swyllys /* Check to see if this is critical */ 889*3089Swyllys if (!strncasecmp(arg, "critical:", strlen("critical:"))) { 890*3089Swyllys *critical = TRUE; 891*3089Swyllys arg += strlen("critical:"); 892*3089Swyllys } else { 893*3089Swyllys *critical = FALSE; 894*3089Swyllys } 895*3089Swyllys 896*3089Swyllys /* Make sure there is an "=" sign */ 897*3089Swyllys p = strchr(arg, '='); 898*3089Swyllys if (p == NULL) 899*3089Swyllys return (KMF_ERR_BAD_PARAMETER); 900*3089Swyllys 901*3089Swyllys p[0] = '\0'; 902*3089Swyllys 903*3089Swyllys if (strcmp(arg, "IP") == 0) 904*3089Swyllys *type = GENNAME_IPADDRESS; 905*3089Swyllys else if (strcmp(arg, "DNS") == 0) 906*3089Swyllys *type = GENNAME_DNSNAME; 907*3089Swyllys else if (strcmp(arg, "EMAIL") == 0) 908*3089Swyllys *type = GENNAME_RFC822NAME; 909*3089Swyllys else if (strcmp(arg, "URI") == 0) 910*3089Swyllys *type = GENNAME_URI; 911*3089Swyllys else if (strcmp(arg, "DN") == 0) 912*3089Swyllys *type = GENNAME_DIRECTORYNAME; 913*3089Swyllys else if (strcmp(arg, "RID") == 0) 914*3089Swyllys *type = GENNAME_REGISTEREDID; 915*3089Swyllys else 916*3089Swyllys rv = KMF_ERR_BAD_PARAMETER; 917*3089Swyllys 918*3089Swyllys p[0] = '='; 919*3089Swyllys 920*3089Swyllys return (rv); 921*3089Swyllys } 922*3089Swyllys 923*3089Swyllys int 924*3089Swyllys get_token_password(KMF_KEYSTORE_TYPE kstype, 925*3089Swyllys char *token_spec, KMF_CREDENTIAL *cred) 926*3089Swyllys { 927*3089Swyllys char prompt[1024]; 928*3089Swyllys char *p = NULL; 929*3089Swyllys 930*3089Swyllys if (kstype == KMF_KEYSTORE_PK11TOKEN) { 931*3089Swyllys p = strchr(token_spec, ':'); 932*3089Swyllys if (p != NULL) 933*3089Swyllys *p = 0; 934*3089Swyllys } 935*3089Swyllys /* 936*3089Swyllys * Login to the token first. 937*3089Swyllys */ 938*3089Swyllys (void) snprintf(prompt, sizeof (prompt), 939*3089Swyllys gettext(DEFAULT_TOKEN_PROMPT), 940*3089Swyllys token_spec); 941*3089Swyllys 942*3089Swyllys if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 943*3089Swyllys (ulong_t *)&cred->credlen) != CKR_OK) { 944*3089Swyllys cred->cred = NULL; 945*3089Swyllys cred->credlen = 0; 946*3089Swyllys } 947*3089Swyllys 948*3089Swyllys if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) 949*3089Swyllys *p = ':'; 950*3089Swyllys return (KMF_OK); 951*3089Swyllys } 952*3089Swyllys 953*3089Swyllys KMF_RETURN 954*3089Swyllys verify_file(char *filename) 955*3089Swyllys { 956*3089Swyllys KMF_RETURN ret = KMF_OK; 957*3089Swyllys int fd; 958*3089Swyllys 959*3089Swyllys /* 960*3089Swyllys * Attempt to open with the EXCL flag so that if 961*3089Swyllys * it already exists, the open will fail. It will 962*3089Swyllys * also fail if the file cannot be created due to 963*3089Swyllys * permissions on the parent directory, or if the 964*3089Swyllys * parent directory itself does not exist. 965*3089Swyllys */ 966*3089Swyllys fd = open(filename, O_CREAT | O_EXCL, 0600); 967*3089Swyllys if (fd == -1) 968*3089Swyllys return (KMF_ERR_OPEN_FILE); 969*3089Swyllys 970*3089Swyllys /* If we were able to create it, delete it. */ 971*3089Swyllys (void) close(fd); 972*3089Swyllys (void) unlink(filename); 973*3089Swyllys 974*3089Swyllys return (ret); 975*3089Swyllys } 976*3089Swyllys 977*3089Swyllys void 978*3089Swyllys display_error(void *handle, KMF_RETURN errcode, char *prefix) 979*3089Swyllys { 980*3089Swyllys KMF_RETURN rv1, rv2; 981*3089Swyllys char *plugin_errmsg = NULL; 982*3089Swyllys char *kmf_errmsg = NULL; 983*3089Swyllys 984*3089Swyllys rv1 = KMF_GetPluginErrorString(handle, &plugin_errmsg); 985*3089Swyllys rv2 = KMF_GetKMFErrorString(errcode, &kmf_errmsg); 986*3089Swyllys 987*3089Swyllys cryptoerror(LOG_STDERR, "%s:", prefix); 988*3089Swyllys if (rv1 == KMF_OK && plugin_errmsg) { 989*3089Swyllys cryptoerror(LOG_STDERR, 990*3089Swyllys gettext("keystore error: %s"), 991*3089Swyllys plugin_errmsg); 992*3089Swyllys KMF_FreeString(plugin_errmsg); 993*3089Swyllys } 994*3089Swyllys 995*3089Swyllys if (rv2 == KMF_OK && kmf_errmsg) { 996*3089Swyllys cryptoerror(LOG_STDERR, 997*3089Swyllys gettext("libkmf error: %s"), 998*3089Swyllys kmf_errmsg); 999*3089Swyllys KMF_FreeString(kmf_errmsg); 1000*3089Swyllys } 1001*3089Swyllys 1002*3089Swyllys if (rv1 != KMF_OK && rv2 != KMF_OK) 1003*3089Swyllys cryptoerror(LOG_STDERR, gettext("<unknown error>\n")); 1004*3089Swyllys 1005*3089Swyllys } 1006