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 53089Swyllys * Common Development and Distribution License (the "License"). 63089Swyllys * 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*11973Swyllys.ingersoll@sun.com * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * This file contains the functions that are shared among 280Sstevel@tonic-gate * the various services this tool will ultimately provide. 2917Sdinak * The functions in this file return PKCS#11 CK_RV errors. 3017Sdinak * Only one session and one login per token is supported 3117Sdinak * at this time. 320Sstevel@tonic-gate */ 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include <stdio.h> 350Sstevel@tonic-gate #include <stdlib.h> 360Sstevel@tonic-gate #include <string.h> 370Sstevel@tonic-gate #include <ctype.h> 383089Swyllys #include <sys/types.h> 393089Swyllys #include <sys/stat.h> 403089Swyllys #include <fcntl.h> 413089Swyllys #include <tzfile.h> 420Sstevel@tonic-gate #include <cryptoutil.h> 430Sstevel@tonic-gate #include <security/cryptoki.h> 443089Swyllys #include <kmfapi.h> 450Sstevel@tonic-gate 463089Swyllys #include "common.h" 4717Sdinak 4817Sdinak /* Local status variables. */ 4917Sdinak static boolean_t initialized = B_FALSE; 5017Sdinak static boolean_t session_opened = B_FALSE; 5117Sdinak static boolean_t logged_in = B_FALSE; 5217Sdinak 53864Sdinak /* Supporting structures and global variables for getopt_av(). */ 54864Sdinak typedef struct av_opts_s { 55864Sdinak int shortnm; /* short name character */ 56864Sdinak char *longnm; /* long name string, NOT terminated */ 57864Sdinak int longnm_len; /* length of long name string */ 58864Sdinak boolean_t has_arg; /* takes optional argument */ 59864Sdinak } av_opts; 60864Sdinak static av_opts *opts_av = NULL; 61864Sdinak static const char *_save_optstr = NULL; 62864Sdinak static int _save_numopts = 0; 63864Sdinak 64864Sdinak int optind_av = 1; 65864Sdinak char *optarg_av = NULL; 66864Sdinak 673089Swyllys static void close_sess(CK_SESSION_HANDLE); 683089Swyllys static void logout_token(CK_SESSION_HANDLE); 693089Swyllys 70*11973Swyllys.ingersoll@sun.com struct oid_table_entry { 71*11973Swyllys.ingersoll@sun.com const KMF_OID *oid; 72*11973Swyllys.ingersoll@sun.com char *name; 73*11973Swyllys.ingersoll@sun.com }; 74*11973Swyllys.ingersoll@sun.com 75*11973Swyllys.ingersoll@sun.com struct oid_table_entry oid_table[] = { 76*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp112r1, "secp112r1"}, 77*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp112r2, "secp112r2"}, 78*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp128r1, "secp128r1"}, 79*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp128r2, "secp128r2"}, 80*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp160k1, "secp160k1"}, 81*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp160r1, "secp160r1"}, 82*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp160r2, "secp160r2"}, 83*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp192k1, "secp192k1"}, 84*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp192r1, "secp192r1"}, 85*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp224k1, "secp224k1"}, 86*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp224r1, "secp224r1"}, 87*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp256k1, "secp256k1"}, 88*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp256r1, "secp256r1"}, 89*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp384r1, "secp384r1"}, 90*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp521r1, "secp521r1"}, 91*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect113r1, "sect113r1"}, 92*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect113r2, "sect113r2"}, 93*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect131r1, "sect131r1"}, 94*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect131r2, "sect131r2"}, 95*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect163k1, "sect163k1"}, 96*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect163r1, "sect163r1"}, 97*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect163r2, "sect163r2"}, 98*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect193r1, "sect193r1"}, 99*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect193r2, "sect193r2"}, 100*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect233k1, "sect233k1"}, 101*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect233r1, "sect233r1"}, 102*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect239k1, "sect239k1"}, 103*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect283k1, "sect283k1"}, 104*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect283r1, "sect283r1"}, 105*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect409k1, "sect409k1"}, 106*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect409r1, "sect409r1"}, 107*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect571k1, "sect571k1"}, 108*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect571r1, "sect571r1"}, 109*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb163v1, "c2pnb163v1"}, 110*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb163v2, "c2pnb163v2"}, 111*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb163v3, "c2pnb163v3"}, 112*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb176v1, "c2pnb176v1"}, 113*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb191v1, "c2tnb191v1"}, 114*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb191v2, "c2tnb191v2"}, 115*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb191v3, "c2tnb191v3"}, 116*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb208w1, "c2pnb208w1"}, 117*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb239v1, "c2tnb239v1"}, 118*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb239v2, "c2tnb239v2"}, 119*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb239v3, "c2tnb239v3"}, 120*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb272w1, "c2pnb272w1"}, 121*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb304w1, "c2pnb304w1"}, 122*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb359v1, "c2tnb359v1"}, 123*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb368w1, "c2pnb368w1"}, 124*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb431r1, "c2tnb431r1"}, 125*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_prime192v2, "prime192v2"}, 126*11973Swyllys.ingersoll@sun.com { &KMFOID_ECC_prime192v3, "prime192v3"}, 127*11973Swyllys.ingersoll@sun.com { &KMFOID_MD5, "md5"}, 128*11973Swyllys.ingersoll@sun.com { &KMFOID_SHA1, "sha1"}, 129*11973Swyllys.ingersoll@sun.com { &KMFOID_SHA256, "sha256"}, 130*11973Swyllys.ingersoll@sun.com { &KMFOID_SHA384, "sha384"}, 131*11973Swyllys.ingersoll@sun.com { &KMFOID_SHA512, "sha512"} 132*11973Swyllys.ingersoll@sun.com }; 133*11973Swyllys.ingersoll@sun.com int number_of_oids = sizeof (oid_table) / sizeof (struct oid_table_entry); 134*11973Swyllys.ingersoll@sun.com #define number_of_curves (number_of_oids - 5) 135*11973Swyllys.ingersoll@sun.com 13617Sdinak /* 13717Sdinak * Perform PKCS#11 setup here. Currently only C_Initialize is required, 13817Sdinak * along with setting/resetting state variables. 13917Sdinak */ 1406669Swyllys static CK_RV 1416669Swyllys init_pkcs11(void) 14217Sdinak { 14317Sdinak CK_RV rv = CKR_OK; 14417Sdinak 14517Sdinak /* If C_Initialize() already called, nothing to do here. */ 14617Sdinak if (initialized == B_TRUE) 14717Sdinak return (CKR_OK); 14817Sdinak 14917Sdinak /* Reset state variables because C_Initialize() not yet done. */ 15017Sdinak session_opened = B_FALSE; 15117Sdinak logged_in = B_FALSE; 15217Sdinak 15317Sdinak /* Initialize PKCS#11 library. */ 15417Sdinak if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && 15517Sdinak rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 15617Sdinak return (rv); 15717Sdinak } 15817Sdinak 15917Sdinak initialized = B_TRUE; 16017Sdinak return (CKR_OK); 16117Sdinak } 16217Sdinak 16317Sdinak /* 16417Sdinak * Finalize PKCS#11 library and reset state variables. Open sessions, 16517Sdinak * if any, are closed, and thereby any logins are logged out also. 16617Sdinak */ 16717Sdinak void 16817Sdinak final_pk11(CK_SESSION_HANDLE sess) 16917Sdinak { 17017Sdinak 17117Sdinak /* If the library wasn't initialized, nothing to do here. */ 17217Sdinak if (!initialized) 17317Sdinak return; 17417Sdinak 17517Sdinak /* Make sure the sesion is closed first. */ 17617Sdinak close_sess(sess); 17717Sdinak 17817Sdinak (void) C_Finalize(NULL); 17917Sdinak initialized = B_FALSE; 18017Sdinak } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 18317Sdinak * Close PKCS#11 session and reset state variables. Any logins are 18417Sdinak * logged out. 18517Sdinak */ 1863089Swyllys static void 18717Sdinak close_sess(CK_SESSION_HANDLE sess) 18817Sdinak { 18917Sdinak 19017Sdinak if (sess == NULL) { 19117Sdinak return; 19217Sdinak } 19317Sdinak 19417Sdinak /* If session is already closed, nothing to do here. */ 19517Sdinak if (!session_opened) 19617Sdinak return; 1970Sstevel@tonic-gate 19817Sdinak /* Make sure user is logged out of token. */ 19917Sdinak logout_token(sess); 20017Sdinak 20117Sdinak (void) C_CloseSession(sess); 20217Sdinak session_opened = B_FALSE; 20317Sdinak } 20417Sdinak 20517Sdinak /* 20617Sdinak * Log user out of token and reset status variable. 20717Sdinak */ 2083089Swyllys static void 20917Sdinak logout_token(CK_SESSION_HANDLE sess) 21017Sdinak { 21117Sdinak 21217Sdinak if (sess == NULL) { 21317Sdinak return; 21417Sdinak } 21517Sdinak 21617Sdinak /* If already logged out, nothing to do here. */ 21717Sdinak if (!logged_in) 21817Sdinak return; 21917Sdinak 22017Sdinak (void) C_Logout(sess); 22117Sdinak logged_in = B_FALSE; 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* 22517Sdinak * Gets PIN from user. Caller needs to free the returned PIN when done. 22617Sdinak * If two prompts are given, the PIN is confirmed with second prompt. 22717Sdinak * Note that getphassphrase() may return data in static memory area. 22817Sdinak */ 22917Sdinak CK_RV 23017Sdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) 23117Sdinak { 2326051Swyllys char *save_phrase, *phrase1, *phrase2; 2330Sstevel@tonic-gate 23417Sdinak /* Prompt user for a PIN. */ 23517Sdinak if (prompt1 == NULL) { 23617Sdinak return (CKR_ARGUMENTS_BAD); 23717Sdinak } 23817Sdinak if ((phrase1 = getpassphrase(prompt1)) == NULL) { 23917Sdinak return (CKR_FUNCTION_FAILED); 24017Sdinak } 24117Sdinak 24217Sdinak /* Duplicate 1st PIN in separate chunk of memory. */ 24317Sdinak if ((save_phrase = strdup(phrase1)) == NULL) 24417Sdinak return (CKR_HOST_MEMORY); 24517Sdinak 24617Sdinak /* If second prompt given, PIN confirmation is requested. */ 24717Sdinak if (prompt2 != NULL) { 24817Sdinak if ((phrase2 = getpassphrase(prompt2)) == NULL) { 24917Sdinak free(save_phrase); 25017Sdinak return (CKR_FUNCTION_FAILED); 25117Sdinak } 25217Sdinak if (strcmp(save_phrase, phrase2) != 0) { 25317Sdinak free(save_phrase); 25417Sdinak return (CKR_PIN_INCORRECT); 25517Sdinak } 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 25817Sdinak *pin = (CK_UTF8CHAR_PTR)save_phrase; 25917Sdinak *pinlen = strlen(save_phrase); 26017Sdinak return (CKR_OK); 26117Sdinak } 26217Sdinak 2636051Swyllys int 2646051Swyllys yn_to_int(char *ynstr) 2656051Swyllys { 2666051Swyllys char *y = gettext("yes"); 2676051Swyllys char *n = gettext("no"); 2686051Swyllys if (ynstr == NULL) 2696051Swyllys return (-1); 2706051Swyllys 2716051Swyllys if (strncasecmp(ynstr, y, 1) == 0) 2726051Swyllys return (1); 2736051Swyllys else if (strncasecmp(ynstr, n, 1) == 0) 2746051Swyllys return (0); 2756051Swyllys else 2766051Swyllys return (-1); 2776051Swyllys } 2786051Swyllys 27917Sdinak /* 28017Sdinak * Gets yes/no response from user. If either no prompt is supplied, a 28117Sdinak * default prompt is used. If not message for invalid input is supplied, 28217Sdinak * a default will not be provided. If the user provides no response, 28317Sdinak * the input default B_TRUE == yes, B_FALSE == no is returned. 28417Sdinak * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. 28517Sdinak */ 28617Sdinak boolean_t 28717Sdinak yesno(char *prompt, char *invalid, boolean_t dflt) 28817Sdinak { 2896051Swyllys char *response, buf[1024]; 2906051Swyllys int ans; 29117Sdinak 29217Sdinak if (prompt == NULL) 29317Sdinak prompt = gettext("Enter (y)es or (n)o? "); 29417Sdinak 29517Sdinak for (;;) { 29617Sdinak /* Prompt user. */ 29717Sdinak (void) printf("%s", prompt); 29817Sdinak (void) fflush(stdout); 29917Sdinak 30017Sdinak /* Get the response. */ 30117Sdinak if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) 30217Sdinak break; /* go to default response */ 30317Sdinak 30417Sdinak /* Skip any leading white space. */ 30517Sdinak while (isspace(*response)) 30617Sdinak response++; 30717Sdinak if (*response == '\0') 30817Sdinak break; /* go to default response */ 30917Sdinak 3106051Swyllys ans = yn_to_int(response); 3116051Swyllys if (ans == 1) 31217Sdinak return (B_TRUE); 3136051Swyllys else if (ans == 0) 31417Sdinak return (B_FALSE); 31517Sdinak 31617Sdinak /* Indicate invalid input, and try again. */ 31717Sdinak if (invalid != NULL) 3185051Swyllys (void) printf("%s", invalid); 31917Sdinak } 32017Sdinak return (dflt); 32117Sdinak } 32217Sdinak 32317Sdinak /* 32417Sdinak * Gets the list of slots which have tokens in them. Keeps adjusting 32517Sdinak * the size of the slot list buffer until the call is successful or an 32617Sdinak * irrecoverable error occurs. 32717Sdinak */ 32817Sdinak CK_RV 32917Sdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) 33017Sdinak { 33117Sdinak CK_ULONG tmp_count = 0; 33217Sdinak CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; 33317Sdinak int rv = CKR_OK; 33417Sdinak 33517Sdinak if (!initialized) 3366669Swyllys if ((rv = init_pkcs11()) != CKR_OK) 33717Sdinak return (rv); 33817Sdinak 33917Sdinak /* 34017Sdinak * Get the slot count first because we don't know how many 34117Sdinak * slots there are and how many of those slots even have tokens. 34217Sdinak * Don't specify an arbitrary buffer size for the slot list; 34317Sdinak * it may be too small (see section 11.5 of PKCS#11 spec). 34417Sdinak * Also select only those slots that have tokens in them, 34517Sdinak * because this tool has no need to know about empty slots. 34617Sdinak */ 34717Sdinak if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) 34817Sdinak return (rv); 34917Sdinak 35017Sdinak if (tmp_count == 0) { 35117Sdinak *slot_list = NULL_PTR; 35217Sdinak *slot_count = 0; 35317Sdinak return (CKR_OK); 35417Sdinak } 35517Sdinak 35617Sdinak /* Allocate initial space for the slot list. */ 35717Sdinak if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * 35817Sdinak sizeof (CK_SLOT_ID))) == NULL) 35917Sdinak return (CKR_HOST_MEMORY); 36017Sdinak 36117Sdinak /* Then get the slot list itself. */ 36217Sdinak for (;;) { 36317Sdinak if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { 36417Sdinak *slot_list = tmp_list; 36517Sdinak *slot_count = tmp_count; 36617Sdinak break; 36717Sdinak } 36817Sdinak 36917Sdinak if (rv != CKR_BUFFER_TOO_SMALL) { 37017Sdinak free(tmp_list); 37117Sdinak break; 37217Sdinak } 37317Sdinak 37417Sdinak /* If the number of slots grew, try again. */ 37517Sdinak if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, 37617Sdinak tmp_count * sizeof (CK_SLOT_ID))) == NULL) { 37717Sdinak free(tmp_list); 37817Sdinak rv = CKR_HOST_MEMORY; 37917Sdinak break; 38017Sdinak } 38117Sdinak tmp_list = tmp2_list; 38217Sdinak } 38317Sdinak 38417Sdinak return (rv); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate /* 388864Sdinak * Breaks out the getopt-style option string into a structure that can be 389864Sdinak * traversed later for calls to getopt_av(). Option string is NOT altered, 390864Sdinak * but the struct fields point to locations within option string. 391864Sdinak */ 392864Sdinak static int 393864Sdinak populate_opts(char *optstring) 394864Sdinak { 395864Sdinak int i; 396864Sdinak av_opts *temp; 397864Sdinak char *marker; 398864Sdinak 399864Sdinak if (optstring == NULL || *optstring == '\0') 400864Sdinak return (0); 401864Sdinak 402864Sdinak /* 403864Sdinak * This tries to imitate getopt(3c) Each option must conform to: 404864Sdinak * <short name char> [ ':' ] [ '(' <long name string> ')' ] 405864Sdinak * If long name is missing, the short name is used for long name. 406864Sdinak */ 407864Sdinak for (i = 0; *optstring != '\0'; i++) { 408864Sdinak if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : 409864Sdinak realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { 4103089Swyllys if (opts_av != NULL) 4113089Swyllys free(opts_av); 412864Sdinak opts_av = NULL; 413864Sdinak return (0); 4143089Swyllys } else { 415864Sdinak opts_av = (av_opts *)temp; 4163089Swyllys } 417864Sdinak 4183089Swyllys (void) memset(&opts_av[i], 0, sizeof (av_opts)); 419864Sdinak marker = optstring; /* may need optstring later */ 420864Sdinak 421864Sdinak opts_av[i].shortnm = *marker++; /* set short name */ 422864Sdinak 423864Sdinak if (*marker == ':') { /* check for opt arg */ 424864Sdinak marker++; 425864Sdinak opts_av[i].has_arg = B_TRUE; 426864Sdinak } 427864Sdinak 428864Sdinak if (*marker == '(') { /* check and set long name */ 429864Sdinak marker++; 430864Sdinak opts_av[i].longnm = marker; 431864Sdinak opts_av[i].longnm_len = strcspn(marker, ")"); 432864Sdinak optstring = marker + opts_av[i].longnm_len + 1; 433864Sdinak } else { 434864Sdinak /* use short name option character */ 435864Sdinak opts_av[i].longnm = optstring; 436864Sdinak opts_av[i].longnm_len = 1; 437864Sdinak optstring = marker; 438864Sdinak } 439864Sdinak } 440864Sdinak 441864Sdinak return (i); 442864Sdinak } 443864Sdinak 444864Sdinak /* 445864Sdinak * getopt_av() is very similar to getopt(3c) in that the takes an option 446864Sdinak * string, compares command line arguments for matches, and returns a single 447864Sdinak * letter option when a match is found. However, getopt_av() differs from 448864Sdinak * getopt(3c) by requiring that only longname options and values be found 449864Sdinak * on the command line and all leading dashes are omitted. In other words, 450864Sdinak * it tries to enforce only longname "option=value" arguments on the command 451864Sdinak * line. Boolean options are not allowed either. 452864Sdinak */ 453864Sdinak int 454864Sdinak getopt_av(int argc, char * const *argv, const char *optstring) 455864Sdinak { 456864Sdinak int i; 457864Sdinak int len; 4583089Swyllys char *cur_option; 459864Sdinak 460864Sdinak if (optind_av >= argc) 461864Sdinak return (EOF); 462864Sdinak 463864Sdinak /* First time or when optstring changes from previous one */ 464864Sdinak if (_save_optstr != optstring) { 465864Sdinak if (opts_av != NULL) 4665051Swyllys free(opts_av); 467864Sdinak opts_av = NULL; 468864Sdinak _save_optstr = optstring; 469864Sdinak _save_numopts = populate_opts((char *)optstring); 470864Sdinak } 471864Sdinak 472864Sdinak for (i = 0; i < _save_numopts; i++) { 4733089Swyllys cur_option = argv[optind_av]; 4743089Swyllys 4753089Swyllys if (strcmp(cur_option, "--") == 0) { 476864Sdinak optind_av++; 477864Sdinak break; 478864Sdinak } 479864Sdinak 4803089Swyllys if (cur_option[0] == '-' && strlen(cur_option) == 2) { 4813089Swyllys len = 1; 4823089Swyllys cur_option++; /* remove "-" */ 4833089Swyllys } else { 4843089Swyllys len = strcspn(cur_option, "="); 4853089Swyllys } 486864Sdinak 4873089Swyllys if (len == opts_av[i].longnm_len && strncmp(cur_option, 488864Sdinak opts_av[i].longnm, opts_av[i].longnm_len) == 0) { 489864Sdinak /* matched */ 490864Sdinak if (!opts_av[i].has_arg) { 491864Sdinak optind_av++; 492864Sdinak return (opts_av[i].shortnm); 493864Sdinak } 494864Sdinak 495864Sdinak /* needs optarg */ 4963089Swyllys if (cur_option[len] == '=') { 4973089Swyllys optarg_av = &(cur_option[len+1]); 498864Sdinak optind_av++; 499864Sdinak return (opts_av[i].shortnm); 500864Sdinak } 501864Sdinak 502864Sdinak optarg_av = NULL; 503864Sdinak optind_av++; 504864Sdinak return ((int)'?'); 505864Sdinak } 506864Sdinak } 507864Sdinak 508864Sdinak return (EOF); 509864Sdinak } 5103089Swyllys 5113089Swyllys KMF_KEYSTORE_TYPE 5123089Swyllys KS2Int(char *keystore_str) 5133089Swyllys { 5143089Swyllys if (keystore_str == NULL) 5153089Swyllys return (0); 5166051Swyllys if (strcasecmp(keystore_str, "pkcs11") == 0) 5173089Swyllys return (KMF_KEYSTORE_PK11TOKEN); 5186051Swyllys else if (strcasecmp(keystore_str, "nss") == 0) 5193089Swyllys return (KMF_KEYSTORE_NSS); 5206051Swyllys else if (strcasecmp(keystore_str, "file") == 0) 5213089Swyllys return (KMF_KEYSTORE_OPENSSL); 5223089Swyllys else 5233089Swyllys return (0); 5243089Swyllys } 5253089Swyllys 526*11973Swyllys.ingersoll@sun.com /* 527*11973Swyllys.ingersoll@sun.com * compare_oids 528*11973Swyllys.ingersoll@sun.com * return 1 if equal 529*11973Swyllys.ingersoll@sun.com */ 530*11973Swyllys.ingersoll@sun.com boolean_t 531*11973Swyllys.ingersoll@sun.com compare_oids(KMF_OID *oid1, const KMF_OID *oid2) 532*11973Swyllys.ingersoll@sun.com { 533*11973Swyllys.ingersoll@sun.com return ((oid1->Length == oid2->Length) && 534*11973Swyllys.ingersoll@sun.com !memcmp(oid1->Data, oid2->Data, oid1->Length)); 535*11973Swyllys.ingersoll@sun.com } 5363089Swyllys 5373089Swyllys int 538*11973Swyllys.ingersoll@sun.com Str2KeyType(char *algm, KMF_OID *hashoid, KMF_KEY_ALG *ktype, 539*11973Swyllys.ingersoll@sun.com KMF_ALGORITHM_INDEX *sigAlg) 5403089Swyllys { 5413089Swyllys if (algm == NULL) { 542*11973Swyllys.ingersoll@sun.com /* Default to SHA1+RSA */ 54310744Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithRSA; 5443089Swyllys *ktype = KMF_RSA; 5453089Swyllys } else if (strcasecmp(algm, "DSA") == 0) { 546*11973Swyllys.ingersoll@sun.com if (hashoid == NULL || 547*11973Swyllys.ingersoll@sun.com compare_oids(hashoid, &KMFOID_SHA1)) 548*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithDSA; 549*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA256)) 550*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA256WithDSA; 551*11973Swyllys.ingersoll@sun.com else 552*11973Swyllys.ingersoll@sun.com return (-1); /* unsupported hash/key combo */ 5533089Swyllys *ktype = KMF_DSA; 5543089Swyllys } else if (strcasecmp(algm, "RSA") == 0) { 555*11973Swyllys.ingersoll@sun.com if (hashoid == NULL || 556*11973Swyllys.ingersoll@sun.com compare_oids(hashoid, &KMFOID_SHA1)) 557*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithRSA; 558*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA256)) 559*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA256WithRSA; 560*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA384)) 561*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA384WithRSA; 562*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA512)) 563*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA512WithRSA; 564*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_MD5)) 565*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_MD5WithRSA; 566*11973Swyllys.ingersoll@sun.com else 567*11973Swyllys.ingersoll@sun.com return (-1); /* unsupported hash/key combo */ 5683089Swyllys *ktype = KMF_RSA; 569*11973Swyllys.ingersoll@sun.com } else if (strcasecmp(algm, "EC") == 0) { 570*11973Swyllys.ingersoll@sun.com /* EC keys may be used with some SHA2 hashes */ 571*11973Swyllys.ingersoll@sun.com if (hashoid == NULL || 572*11973Swyllys.ingersoll@sun.com compare_oids(hashoid, &KMFOID_SHA1)) 573*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithECDSA; 574*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA256)) 575*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA256WithECDSA; 576*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA384)) 577*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA384WithECDSA; 578*11973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA512)) 579*11973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA512WithECDSA; 580*11973Swyllys.ingersoll@sun.com else 581*11973Swyllys.ingersoll@sun.com return (-1); /* unsupported hash/key combo */ 582*11973Swyllys.ingersoll@sun.com 583*11973Swyllys.ingersoll@sun.com *ktype = KMF_ECDSA; 5843089Swyllys } else { 5853089Swyllys return (-1); 5863089Swyllys } 5873089Swyllys return (0); 5883089Swyllys } 5893089Swyllys 5903089Swyllys int 5913089Swyllys Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype) 5923089Swyllys { 5933089Swyllys if (algm == NULL) 5943089Swyllys *ktype = KMF_AES; 5953089Swyllys else if (strcasecmp(algm, "aes") == 0) 5963089Swyllys *ktype = KMF_AES; 5973089Swyllys else if (strcasecmp(algm, "arcfour") == 0) 5983089Swyllys *ktype = KMF_RC4; 5993089Swyllys else if (strcasecmp(algm, "des") == 0) 6003089Swyllys *ktype = KMF_DES; 6013089Swyllys else if (strcasecmp(algm, "3des") == 0) 6023089Swyllys *ktype = KMF_DES3; 6033812Shylee else if (strcasecmp(algm, "generic") == 0) 6043812Shylee *ktype = KMF_GENERIC_SECRET; 6053089Swyllys else 6063089Swyllys return (-1); 6073089Swyllys 6083089Swyllys return (0); 6093089Swyllys } 6103089Swyllys 6113089Swyllys int 6123089Swyllys Str2Lifetime(char *ltimestr, uint32_t *ltime) 6133089Swyllys { 6143089Swyllys int num; 6153089Swyllys char timetok[6]; 6163089Swyllys 6176051Swyllys if (ltimestr == NULL || strlen(ltimestr) == 0) { 6183089Swyllys /* default to 1 year lifetime */ 6193089Swyllys *ltime = SECSPERDAY * DAYSPERNYEAR; 6203089Swyllys return (0); 6213089Swyllys } 6223089Swyllys 6233089Swyllys (void) memset(timetok, 0, sizeof (timetok)); 6243089Swyllys if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2) 6253089Swyllys return (-1); 6263089Swyllys 6276051Swyllys if (strcasecmp(timetok, "day") == 0|| 6286051Swyllys strcasecmp(timetok, "days") == 0) { 6293089Swyllys *ltime = num * SECSPERDAY; 6306051Swyllys } else if (strcasecmp(timetok, "hour") == 0|| 6316051Swyllys strcasecmp(timetok, "hours") == 0) { 6323089Swyllys *ltime = num * SECSPERHOUR; 6336051Swyllys } else if (strcasecmp(timetok, "year") == 0 || 6346051Swyllys strcasecmp(timetok, "years") == 0) { 6353089Swyllys *ltime = num * SECSPERDAY * DAYSPERNYEAR; 6363089Swyllys } else { 6373089Swyllys *ltime = 0; 6383089Swyllys return (-1); 6393089Swyllys } 6403089Swyllys 6413089Swyllys return (0); 6423089Swyllys } 6433089Swyllys 6443089Swyllys int 6453089Swyllys OT2Int(char *objclass) 6463089Swyllys { 6473089Swyllys char *c = NULL; 6483089Swyllys int retval = 0; 6493089Swyllys 6503089Swyllys if (objclass == NULL) 6513089Swyllys return (-1); 6523089Swyllys 6533089Swyllys c = strchr(objclass, ':'); 6543089Swyllys if (c != NULL) { 6556051Swyllys if (strcasecmp(c, ":private") == 0) 6563089Swyllys retval = PK_PRIVATE_OBJ; 6576051Swyllys else if (strcasecmp(c, ":public") == 0) 6583089Swyllys retval = PK_PUBLIC_OBJ; 6596051Swyllys else if (strcasecmp(c, ":both") == 0) 6603089Swyllys retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ; 6613089Swyllys else /* unrecognized option */ 6623089Swyllys return (-1); 6633089Swyllys 6643089Swyllys *c = '\0'; 6653089Swyllys } 6663089Swyllys 6676051Swyllys if (strcasecmp(objclass, "public") == 0) { 6683089Swyllys if (retval) 6693089Swyllys return (-1); 6705051Swyllys return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ); 6716051Swyllys } else if (strcasecmp(objclass, "private") == 0) { 6723089Swyllys if (retval) 6733089Swyllys return (-1); 6743089Swyllys return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); 6756051Swyllys } else if (strcasecmp(objclass, "both") == 0) { 6763089Swyllys if (retval) 6773089Swyllys return (-1); 6783089Swyllys return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); 6796051Swyllys } else if (strcasecmp(objclass, "cert") == 0) { 6803089Swyllys return (retval | PK_CERT_OBJ); 6816051Swyllys } else if (strcasecmp(objclass, "key") == 0) { 6823089Swyllys if (retval == 0) /* return all keys */ 6833089Swyllys return (retval | PK_KEY_OBJ); 6843089Swyllys else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) 6853089Swyllys /* return all keys */ 6863089Swyllys return (retval | PK_KEY_OBJ); 6873089Swyllys else if (retval & PK_PUBLIC_OBJ) 6883089Swyllys /* Only return public keys */ 6893089Swyllys return (retval | PK_PUBKEY_OBJ); 6903089Swyllys else if (retval & PK_PRIVATE_OBJ) 6913089Swyllys /* Only return private keys */ 6923089Swyllys return (retval | PK_PRIKEY_OBJ); 6936051Swyllys } else if (strcasecmp(objclass, "crl") == 0) { 6943089Swyllys if (retval) 6953089Swyllys return (-1); 6963089Swyllys return (retval | PK_CRL_OBJ); 6973089Swyllys } 6983089Swyllys 6993089Swyllys if (retval == 0) /* No matches found */ 7003089Swyllys retval = -1; 7013089Swyllys return (retval); 7023089Swyllys } 7033089Swyllys 7043089Swyllys KMF_ENCODE_FORMAT 7053089Swyllys Str2Format(char *formstr) 7063089Swyllys { 7076051Swyllys if (formstr == NULL || strcasecmp(formstr, "der") == 0) 7083089Swyllys return (KMF_FORMAT_ASN1); 7096051Swyllys if (strcasecmp(formstr, "pem") == 0) 7103089Swyllys return (KMF_FORMAT_PEM); 7116051Swyllys if (strcasecmp(formstr, "pkcs12") == 0) 7123089Swyllys return (KMF_FORMAT_PKCS12); 7136051Swyllys if (strcasecmp(formstr, "raw") == 0) 7145051Swyllys return (KMF_FORMAT_RAWKEY); 7153089Swyllys 7163089Swyllys return (KMF_FORMAT_UNDEF); 7173089Swyllys } 7183089Swyllys 7193089Swyllys KMF_RETURN 7206051Swyllys select_token(void *kmfhandle, char *token, int readonly) 7213089Swyllys { 7225051Swyllys KMF_ATTRIBUTE attlist[10]; 7235051Swyllys int i = 0; 7245051Swyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; 7253089Swyllys KMF_RETURN rv = KMF_OK; 7263089Swyllys 7273089Swyllys if (token == NULL) 7283089Swyllys return (KMF_ERR_BAD_PARAMETER); 7293089Swyllys 7305051Swyllys kmf_set_attr_at_index(attlist, i, 7315051Swyllys KMF_KEYSTORE_TYPE_ATTR, &kstype, 7325051Swyllys sizeof (kstype)); 7335051Swyllys i++; 7343089Swyllys 7355051Swyllys if (token) { 7365051Swyllys kmf_set_attr_at_index(attlist, i, 7375051Swyllys KMF_TOKEN_LABEL_ATTR, token, 7385051Swyllys strlen(token)); 7395051Swyllys i++; 7405051Swyllys } 7415051Swyllys 7425051Swyllys kmf_set_attr_at_index(attlist, i, 7435051Swyllys KMF_READONLY_ATTR, &readonly, 7445051Swyllys sizeof (readonly)); 7455051Swyllys i++; 7465051Swyllys 7475051Swyllys rv = kmf_configure_keystore(kmfhandle, i, attlist); 7483089Swyllys if (rv == KMF_ERR_TOKEN_SELECTED) 7493089Swyllys rv = KMF_OK; 7503089Swyllys return (rv); 7513089Swyllys } 7523089Swyllys 7533089Swyllys KMF_RETURN 7543089Swyllys configure_nss(void *kmfhandle, char *dir, char *prefix) 7553089Swyllys { 7565051Swyllys KMF_ATTRIBUTE attlist[10]; 7575051Swyllys int i = 0; 7585051Swyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; 7593089Swyllys KMF_RETURN rv = KMF_OK; 7605051Swyllys 7615051Swyllys kmf_set_attr_at_index(attlist, i, 7625051Swyllys KMF_KEYSTORE_TYPE_ATTR, &kstype, 7635051Swyllys sizeof (kstype)); 7645051Swyllys i++; 7653089Swyllys 7665051Swyllys if (dir) { 7675051Swyllys kmf_set_attr_at_index(attlist, i, 7685051Swyllys KMF_DIRPATH_ATTR, dir, 7695051Swyllys strlen(dir)); 7705051Swyllys i++; 7715051Swyllys } 7723089Swyllys 7735051Swyllys if (prefix) { 7745051Swyllys kmf_set_attr_at_index(attlist, i, 7755051Swyllys KMF_CERTPREFIX_ATTR, prefix, 7765051Swyllys strlen(prefix)); 7775051Swyllys i++; 7785051Swyllys 7795051Swyllys kmf_set_attr_at_index(attlist, i, 7805051Swyllys KMF_KEYPREFIX_ATTR, prefix, 7815051Swyllys strlen(prefix)); 7825051Swyllys i++; 7835051Swyllys } 7845051Swyllys 7855051Swyllys rv = kmf_configure_keystore(kmfhandle, i, attlist); 7863089Swyllys if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) 7873089Swyllys rv = KMF_OK; 7883089Swyllys 7893089Swyllys return (rv); 7903089Swyllys } 7913089Swyllys 7923089Swyllys KMF_RETURN 7933089Swyllys get_pk12_password(KMF_CREDENTIAL *cred) 7943089Swyllys { 7953089Swyllys KMF_RETURN rv = KMF_OK; 7963089Swyllys char prompt[1024]; 7973089Swyllys 7983089Swyllys /* 7993089Swyllys * Get the password to use for the PK12 encryption. 8003089Swyllys */ 8013089Swyllys (void) strlcpy(prompt, 8025051Swyllys gettext("Enter password to use for " 8035051Swyllys "accessing the PKCS12 file: "), sizeof (prompt)); 8043089Swyllys 8053089Swyllys if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 8065051Swyllys (ulong_t *)&cred->credlen) != CKR_OK) { 8073089Swyllys cred->cred = NULL; 8083089Swyllys cred->credlen = 0; 8093089Swyllys } 8103089Swyllys 8113089Swyllys return (rv); 8123089Swyllys } 8133089Swyllys 8145221Swyllys #define FILENAME_PROMPT gettext("Filename:") 8155221Swyllys #define FILENAME_MINLEN 1 8165221Swyllys #define FILENAME_MAXLEN MAXPATHLEN 8173089Swyllys 8185221Swyllys #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:") 8195221Swyllys #define STATE_PROMPT gettext("State or Province Name (full name) " \ 8205221Swyllys "[Some-State]:") 8215221Swyllys #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:") 8225221Swyllys #define ORG_PROMPT gettext("Organization Name (eg, company) []:") 8235221Swyllys #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:") 8245221Swyllys #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:") 8255221Swyllys #define EMAIL_PROMPT gettext("Email Address []:") 8265221Swyllys 8275221Swyllys #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \ 8285221Swyllys "0x01020304):") 8295221Swyllys #define SERNO_MINLEN 3 8305221Swyllys #define SERNO_MAXLEN 42 8315221Swyllys 8325221Swyllys #define LABEL_PROMPT gettext("Enter a label for the certificate:") 8335221Swyllys #define LABEL_MINLEN 1 8345221Swyllys #define LABEL_MAXLEN 1024 8353089Swyllys 8363089Swyllys #define COUNTRY_DEFAULT "US" 8375221Swyllys #define STATE_DEFAULT NULL 8385221Swyllys #define INVALID_INPUT gettext("Invalid input; please re-enter ...") 8393089Swyllys 8403089Swyllys #define SUBNAMESIZ 1024 8413089Swyllys #define RDN_MIN 1 8423089Swyllys #define RDN_MAX 64 8433089Swyllys #define COUNTRYNAME_MIN 2 8443089Swyllys #define COUNTRYNAME_MAX 2 8453089Swyllys 8463089Swyllys static char * 8473089Swyllys get_input_string(char *prompt, char *default_str, int min_len, int max_len) 8483089Swyllys { 8493089Swyllys char buf[1024]; 8503089Swyllys char *response = NULL; 8513089Swyllys char *ret = NULL; 8523089Swyllys int len; 8533089Swyllys 8543089Swyllys for (;;) { 8553089Swyllys (void) printf("\t%s", prompt); 8563089Swyllys (void) fflush(stdout); 8573089Swyllys 8583089Swyllys response = fgets(buf, sizeof (buf), stdin); 8593089Swyllys if (response == NULL) { 8603089Swyllys if (default_str != NULL) { 8613089Swyllys ret = strdup(default_str); 8623089Swyllys } 8633089Swyllys break; 8643089Swyllys } 8653089Swyllys 8663089Swyllys /* Skip any leading white space. */ 8673089Swyllys while (isspace(*response)) 8683089Swyllys response++; 8693089Swyllys if (*response == '\0') { 8703089Swyllys if (default_str != NULL) { 8713089Swyllys ret = strdup(default_str); 8723089Swyllys } 8733089Swyllys break; 8743089Swyllys } 8753089Swyllys 8763089Swyllys len = strlen(response); 8773089Swyllys response[len-1] = '\0'; /* get rid of "LF" */ 8783089Swyllys len--; 8793089Swyllys if (len >= min_len && len <= max_len) { 8803089Swyllys ret = strdup(response); 8813089Swyllys break; 8823089Swyllys } 8833089Swyllys 8843089Swyllys (void) printf("%s\n", INVALID_INPUT); 8853089Swyllys 8863089Swyllys } 8873089Swyllys 8883089Swyllys return (ret); 8893089Swyllys } 8903089Swyllys 8913089Swyllys int 8925221Swyllys get_filename(char *txt, char **result) 8935221Swyllys { 8945221Swyllys char prompt[1024]; 8955221Swyllys char *fname = NULL; 8965221Swyllys 8975221Swyllys (void) snprintf(prompt, sizeof (prompt), 8985221Swyllys gettext("Enter filename for the %s: "), 8995221Swyllys txt); 9005221Swyllys fname = get_input_string(prompt, NULL, 9015221Swyllys FILENAME_MINLEN, FILENAME_MAXLEN); 9025221Swyllys *result = fname; 9035221Swyllys return (0); 9045221Swyllys } 9055221Swyllys 9065221Swyllys int 9075221Swyllys get_certlabel(char **result) 9085221Swyllys { 9095221Swyllys char *label = NULL; 9105221Swyllys 9115221Swyllys label = get_input_string(LABEL_PROMPT, NULL, 9125221Swyllys LABEL_MINLEN, LABEL_MAXLEN); 9135221Swyllys *result = label; 9145221Swyllys return (0); 9155221Swyllys } 9165221Swyllys 9175221Swyllys int 9185221Swyllys get_serial(char **result) 9195221Swyllys { 9205221Swyllys char *serial = NULL; 9215221Swyllys 9225221Swyllys serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN, 9235221Swyllys SERNO_MAXLEN); 9245221Swyllys 9255221Swyllys *result = serial; 9265221Swyllys return (0); 9275221Swyllys } 9285221Swyllys 9295221Swyllys int 9303089Swyllys get_subname(char **result) 9313089Swyllys { 9323089Swyllys char *country = NULL; 9333089Swyllys char *state = NULL; 9343089Swyllys char *locality = NULL; 9353089Swyllys char *org = NULL; 9363089Swyllys char *unit = NULL; 9373089Swyllys char *name = NULL; 9383089Swyllys char *email = NULL; 9393089Swyllys char *subname = NULL; 9403089Swyllys 9413089Swyllys (void) printf("Entering following fields for subject (a DN) ...\n"); 9423089Swyllys country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, 9433089Swyllys COUNTRYNAME_MIN, COUNTRYNAME_MAX); 9443089Swyllys if (country == NULL) 9453089Swyllys return (-1); 9463089Swyllys 9473089Swyllys state = get_input_string(STATE_PROMPT, STATE_DEFAULT, 9483089Swyllys RDN_MIN, RDN_MAX); 9493089Swyllys 9503089Swyllys locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); 9513089Swyllys org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); 9523089Swyllys unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); 9533089Swyllys name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); 9543089Swyllys email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); 9553089Swyllys 9563089Swyllys /* Now create a subject name from the input strings */ 9573089Swyllys if ((subname = malloc(SUBNAMESIZ)) == NULL) 9583089Swyllys goto out; 9593089Swyllys 9603089Swyllys (void) memset(subname, 0, SUBNAMESIZ); 9613089Swyllys (void) strlcpy(subname, "C=", SUBNAMESIZ); 9623089Swyllys (void) strlcat(subname, country, SUBNAMESIZ); 9635221Swyllys if (state != NULL) { 9645221Swyllys (void) strlcat(subname, ", ST=", SUBNAMESIZ); 9655221Swyllys (void) strlcat(subname, state, SUBNAMESIZ); 9665221Swyllys } 9673089Swyllys 9685221Swyllys if (locality != NULL) { 9695221Swyllys (void) strlcat(subname, ", L=", SUBNAMESIZ); 9703089Swyllys (void) strlcat(subname, locality, SUBNAMESIZ); 9713089Swyllys } 9723089Swyllys 9735221Swyllys if (org != NULL) { 9745221Swyllys (void) strlcat(subname, ", O=", SUBNAMESIZ); 9753089Swyllys (void) strlcat(subname, org, SUBNAMESIZ); 9763089Swyllys } 9773089Swyllys 9785221Swyllys if (unit != NULL) { 9795221Swyllys (void) strlcat(subname, ", OU=", SUBNAMESIZ); 9803089Swyllys (void) strlcat(subname, unit, SUBNAMESIZ); 9813089Swyllys } 9823089Swyllys 9835221Swyllys if (name != NULL) { 9845221Swyllys (void) strlcat(subname, ", CN=", SUBNAMESIZ); 9853089Swyllys (void) strlcat(subname, name, SUBNAMESIZ); 9863089Swyllys } 9873089Swyllys 9885221Swyllys if (email != NULL) { 9895221Swyllys (void) strlcat(subname, ", E=", SUBNAMESIZ); 9903089Swyllys (void) strlcat(subname, email, SUBNAMESIZ); 9913089Swyllys } 9923089Swyllys 9933089Swyllys out: 9943089Swyllys if (country) 9953089Swyllys free(country); 9963089Swyllys if (state) 9973089Swyllys free(state); 9983089Swyllys if (locality) 9993089Swyllys free(locality); 10003089Swyllys if (org) 10013089Swyllys free(org); 10023089Swyllys if (unit) 10033089Swyllys free(unit); 10043089Swyllys if (name) 10053089Swyllys free(name); 10063089Swyllys if (email) 10073089Swyllys free(email); 10083089Swyllys 10093089Swyllys if (subname == NULL) 10103089Swyllys return (-1); 10113089Swyllys else { 10123089Swyllys *result = subname; 10133089Swyllys return (0); 10143089Swyllys } 10153089Swyllys } 10163089Swyllys 10173089Swyllys /* 10183089Swyllys * Parse a string of KeyUsage values and convert 10193089Swyllys * them to the correct KU Bits. 10203089Swyllys * The field may be marked "critical" by prepending 10213089Swyllys * "critical:" to the list. 10223089Swyllys * EX: critical:digitialSignature,keyEncipherment 10233089Swyllys */ 10243089Swyllys KMF_RETURN 10253089Swyllys verify_keyusage(char *kustr, uint16_t *kubits, int *critical) 10263089Swyllys { 10273089Swyllys KMF_RETURN ret = KMF_OK; 10283089Swyllys uint16_t kuval; 10293089Swyllys char *k; 10303089Swyllys 10313089Swyllys *kubits = 0; 10326051Swyllys if (kustr == NULL || strlen(kustr) == 0) 10333089Swyllys return (KMF_ERR_BAD_PARAMETER); 10343089Swyllys 10353089Swyllys /* Check to see if this is critical */ 10366051Swyllys if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) { 10373089Swyllys *critical = TRUE; 10383089Swyllys kustr += strlen("critical:"); 10393089Swyllys } else { 10403089Swyllys *critical = FALSE; 10413089Swyllys } 10423089Swyllys 10433089Swyllys k = strtok(kustr, ","); 10443089Swyllys while (k != NULL) { 10455051Swyllys kuval = kmf_string_to_ku(k); 10463089Swyllys if (kuval == 0) { 10473089Swyllys *kubits = 0; 10483089Swyllys return (KMF_ERR_BAD_PARAMETER); 10493089Swyllys } 10503089Swyllys *kubits |= kuval; 10513089Swyllys k = strtok(NULL, ","); 10523089Swyllys } 10533089Swyllys 10543089Swyllys return (ret); 10553089Swyllys } 10563089Swyllys 10573089Swyllys /* 10583089Swyllys * Verify the alternate subject label is real or invalid. 10593089Swyllys * 10603089Swyllys * The field may be marked "critical" by prepending 10613089Swyllys * "critical:" to the list. 10623089Swyllys * EX: "critical:IP=1.2.3.4" 10633089Swyllys */ 10643089Swyllys KMF_RETURN 10653089Swyllys verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) 10663089Swyllys { 10673089Swyllys char *p; 10683089Swyllys KMF_RETURN rv = KMF_OK; 10693089Swyllys 10703089Swyllys /* Check to see if this is critical */ 10716051Swyllys if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) { 10723089Swyllys *critical = TRUE; 10733089Swyllys arg += strlen("critical:"); 10743089Swyllys } else { 10753089Swyllys *critical = FALSE; 10763089Swyllys } 10773089Swyllys 10783089Swyllys /* Make sure there is an "=" sign */ 10793089Swyllys p = strchr(arg, '='); 10803089Swyllys if (p == NULL) 10813089Swyllys return (KMF_ERR_BAD_PARAMETER); 10823089Swyllys 10833089Swyllys p[0] = '\0'; 10843089Swyllys 10853089Swyllys if (strcmp(arg, "IP") == 0) 10863089Swyllys *type = GENNAME_IPADDRESS; 10873089Swyllys else if (strcmp(arg, "DNS") == 0) 10883089Swyllys *type = GENNAME_DNSNAME; 10893089Swyllys else if (strcmp(arg, "EMAIL") == 0) 10903089Swyllys *type = GENNAME_RFC822NAME; 10913089Swyllys else if (strcmp(arg, "URI") == 0) 10923089Swyllys *type = GENNAME_URI; 10933089Swyllys else if (strcmp(arg, "DN") == 0) 10943089Swyllys *type = GENNAME_DIRECTORYNAME; 10953089Swyllys else if (strcmp(arg, "RID") == 0) 10963089Swyllys *type = GENNAME_REGISTEREDID; 10976051Swyllys else if (strcmp(arg, "KRB") == 0) 10986051Swyllys *type = GENNAME_KRB5PRINC; 10996051Swyllys else if (strcmp(arg, "UPN") == 0) 11006051Swyllys *type = GENNAME_SCLOGON_UPN; 11013089Swyllys else 11023089Swyllys rv = KMF_ERR_BAD_PARAMETER; 11033089Swyllys 11043089Swyllys p[0] = '='; 11053089Swyllys 11063089Swyllys return (rv); 11073089Swyllys } 11083089Swyllys 11093089Swyllys int 11103089Swyllys get_token_password(KMF_KEYSTORE_TYPE kstype, 11113089Swyllys char *token_spec, KMF_CREDENTIAL *cred) 11123089Swyllys { 11133089Swyllys char prompt[1024]; 11148132SWyllys.Ingersoll@Sun.COM char temptoken[32]; 11153089Swyllys char *p = NULL; 11168132SWyllys.Ingersoll@Sun.COM char *t = NULL; 11179126SWyllys.Ingersoll@Sun.COM int len; 11183089Swyllys 11199126SWyllys.Ingersoll@Sun.COM (void) memset(temptoken, 0, sizeof (temptoken)); 11203089Swyllys if (kstype == KMF_KEYSTORE_PK11TOKEN) { 11213089Swyllys p = strchr(token_spec, ':'); 11223089Swyllys if (p != NULL) 11238132SWyllys.Ingersoll@Sun.COM *p = 0; 11243089Swyllys } 11259126SWyllys.Ingersoll@Sun.COM len = strlen(token_spec); 11269126SWyllys.Ingersoll@Sun.COM if (len > sizeof (temptoken)) 11279126SWyllys.Ingersoll@Sun.COM len = sizeof (temptoken); 11289126SWyllys.Ingersoll@Sun.COM 11299126SWyllys.Ingersoll@Sun.COM (void) strncpy(temptoken, token_spec, len); 11308132SWyllys.Ingersoll@Sun.COM 11318132SWyllys.Ingersoll@Sun.COM /* 11328132SWyllys.Ingersoll@Sun.COM * Strip trailing whitespace 11338132SWyllys.Ingersoll@Sun.COM */ 11349126SWyllys.Ingersoll@Sun.COM t = temptoken + (len - 1); 11358132SWyllys.Ingersoll@Sun.COM while (isspace(*t) && t >= temptoken) { 11368132SWyllys.Ingersoll@Sun.COM *t = 0x00; 11378132SWyllys.Ingersoll@Sun.COM t--; 11388132SWyllys.Ingersoll@Sun.COM } 11398132SWyllys.Ingersoll@Sun.COM 11403089Swyllys /* 11413089Swyllys * Login to the token first. 11423089Swyllys */ 11433089Swyllys (void) snprintf(prompt, sizeof (prompt), 11448132SWyllys.Ingersoll@Sun.COM gettext(DEFAULT_TOKEN_PROMPT), temptoken); 11453089Swyllys 11463089Swyllys if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, 11475051Swyllys (ulong_t *)&cred->credlen) != CKR_OK) { 11483089Swyllys cred->cred = NULL; 11493089Swyllys cred->credlen = 0; 11503089Swyllys } 11513089Swyllys 11523089Swyllys if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) 11533089Swyllys *p = ':'; 11543089Swyllys return (KMF_OK); 11553089Swyllys } 11563089Swyllys 11573089Swyllys KMF_RETURN 11583089Swyllys verify_file(char *filename) 11593089Swyllys { 11603089Swyllys KMF_RETURN ret = KMF_OK; 11613089Swyllys int fd; 11623089Swyllys 11633089Swyllys /* 11643089Swyllys * Attempt to open with the EXCL flag so that if 11653089Swyllys * it already exists, the open will fail. It will 11663089Swyllys * also fail if the file cannot be created due to 11673089Swyllys * permissions on the parent directory, or if the 11683089Swyllys * parent directory itself does not exist. 11693089Swyllys */ 11703089Swyllys fd = open(filename, O_CREAT | O_EXCL, 0600); 11713089Swyllys if (fd == -1) 11723089Swyllys return (KMF_ERR_OPEN_FILE); 11733089Swyllys 11743089Swyllys /* If we were able to create it, delete it. */ 11753089Swyllys (void) close(fd); 11763089Swyllys (void) unlink(filename); 11773089Swyllys 11783089Swyllys return (ret); 11793089Swyllys } 11803089Swyllys 11813089Swyllys void 11823089Swyllys display_error(void *handle, KMF_RETURN errcode, char *prefix) 11833089Swyllys { 11843089Swyllys KMF_RETURN rv1, rv2; 11853089Swyllys char *plugin_errmsg = NULL; 11863089Swyllys char *kmf_errmsg = NULL; 11873089Swyllys 11885051Swyllys rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg); 11895051Swyllys rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg); 11903089Swyllys 11913089Swyllys cryptoerror(LOG_STDERR, "%s:", prefix); 11923089Swyllys if (rv1 == KMF_OK && plugin_errmsg) { 11935051Swyllys cryptoerror(LOG_STDERR, gettext("keystore error: %s"), 11945051Swyllys plugin_errmsg); 11955051Swyllys kmf_free_str(plugin_errmsg); 11963089Swyllys } 11973089Swyllys 11983089Swyllys if (rv2 == KMF_OK && kmf_errmsg) { 11995051Swyllys cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), 12005051Swyllys kmf_errmsg); 12015051Swyllys kmf_free_str(kmf_errmsg); 12023089Swyllys } 12033089Swyllys 12043089Swyllys if (rv1 != KMF_OK && rv2 != KMF_OK) 12053089Swyllys cryptoerror(LOG_STDERR, gettext("<unknown error>\n")); 12063089Swyllys 12073089Swyllys } 12086051Swyllys 12096051Swyllys static KMF_RETURN 12106051Swyllys addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid) 12116051Swyllys { 12126051Swyllys if (newoid != NULL && ekus != NULL) { 12136051Swyllys ekus->eku_count++; 12146051Swyllys 12156051Swyllys ekus->critlist = realloc(ekus->critlist, 12166051Swyllys ekus->eku_count * sizeof (int)); 12176051Swyllys if (ekus->critlist != NULL) 12186051Swyllys ekus->critlist[ekus->eku_count-1] = critical; 12196051Swyllys else 12206051Swyllys return (KMF_ERR_MEMORY); 12216051Swyllys 12226051Swyllys ekus->ekulist = realloc( 12236051Swyllys ekus->ekulist, ekus->eku_count * sizeof (KMF_OID)); 12246051Swyllys if (ekus->ekulist != NULL) 12256051Swyllys ekus->ekulist[ekus->eku_count-1] = *newoid; 12266051Swyllys else 12276051Swyllys return (KMF_ERR_MEMORY); 12286051Swyllys } 12296051Swyllys return (KMF_OK); 12306051Swyllys } 12316051Swyllys 12326051Swyllys void 12336051Swyllys free_eku_list(EKU_LIST *ekus) 12346051Swyllys { 12356051Swyllys if (ekus != NULL && ekus->eku_count > 0) { 12366051Swyllys int i; 12376051Swyllys for (i = 0; i < ekus->eku_count; i++) { 12386051Swyllys kmf_free_data(&ekus->ekulist[i]); 12396051Swyllys } 12406051Swyllys free(ekus->ekulist); 12416051Swyllys free(ekus->critlist); 124210818Swyllys.ingersoll@sun.com free(ekus); 12436051Swyllys } 12446051Swyllys } 12456051Swyllys 12466051Swyllys static KMF_RETURN 12476051Swyllys parse_ekus(char *ekustr, EKU_LIST *ekus) 12486051Swyllys { 12496051Swyllys KMF_RETURN rv = KMF_OK; 12506051Swyllys KMF_OID *newoid; 12516051Swyllys int critical; 12526051Swyllys 12536051Swyllys if (strncasecmp(ekustr, "critical:", 12546051Swyllys strlen("critical:")) == 0) { 12556051Swyllys critical = TRUE; 12566051Swyllys ekustr += strlen("critical:"); 12576051Swyllys } else { 12586051Swyllys critical = FALSE; 12596051Swyllys } 12606051Swyllys newoid = kmf_ekuname_to_oid(ekustr); 12616051Swyllys if (newoid != NULL) { 12626051Swyllys rv = addToEKUList(ekus, critical, newoid); 12636051Swyllys free(newoid); 12646051Swyllys } else { 12656051Swyllys rv = PK_ERR_USAGE; 12666051Swyllys } 12676051Swyllys 12686051Swyllys return (rv); 12696051Swyllys } 12706051Swyllys 12716051Swyllys KMF_RETURN 12726051Swyllys verify_ekunames(char *ekuliststr, EKU_LIST **ekulist) 12736051Swyllys { 12746051Swyllys KMF_RETURN rv = KMF_OK; 12756051Swyllys char *p; 12766051Swyllys EKU_LIST *ekus = NULL; 12776051Swyllys 12786051Swyllys if (ekuliststr == NULL || strlen(ekuliststr) == 0) 12796051Swyllys return (0); 12806051Swyllys 128110818Swyllys.ingersoll@sun.com ekus = calloc(sizeof (EKU_LIST), 1); 128210818Swyllys.ingersoll@sun.com if (ekus == NULL) 128310818Swyllys.ingersoll@sun.com return (KMF_ERR_MEMORY); 128410818Swyllys.ingersoll@sun.com 12856051Swyllys /* 12866051Swyllys * The list should be comma separated list of EKU Names. 12876051Swyllys */ 12886051Swyllys p = strtok(ekuliststr, ","); 12896051Swyllys 12906051Swyllys /* If no tokens found, then maybe it's just a single EKU value */ 12916051Swyllys if (p == NULL) { 12926051Swyllys rv = parse_ekus(ekuliststr, ekus); 12936051Swyllys } 12946051Swyllys 12956051Swyllys while (p != NULL) { 12966051Swyllys rv = parse_ekus(p, ekus); 12976051Swyllys 12986051Swyllys if (rv != KMF_OK) 12996051Swyllys break; 13006051Swyllys p = strtok(NULL, ","); 13016051Swyllys } 13026051Swyllys 13036051Swyllys if (rv != KMF_OK) 13046051Swyllys free_eku_list(ekus); 13056051Swyllys else 13066051Swyllys *ekulist = ekus; 13076051Swyllys 13086051Swyllys return (rv); 13096051Swyllys } 13106354Swyllys 13116354Swyllys KMF_RETURN 13126354Swyllys token_auth_needed(KMF_HANDLE_T handle, char *tokenlabel, int *auth) 13136354Swyllys { 13146354Swyllys CK_TOKEN_INFO info; 13156354Swyllys CK_SLOT_ID slot; 13166354Swyllys CK_RV ckrv; 13176354Swyllys KMF_RETURN rv; 13186354Swyllys 13196354Swyllys *auth = 0; 13206354Swyllys rv = kmf_pk11_token_lookup(handle, tokenlabel, &slot); 13216354Swyllys if (rv != KMF_OK) 13226354Swyllys return (rv); 13236354Swyllys 13246354Swyllys ckrv = C_GetTokenInfo(slot, &info); 13256354Swyllys if (ckrv != KMF_OK) 13266354Swyllys return (KMF_ERR_INTERNAL); 13276354Swyllys 13286354Swyllys *auth = (info.flags & CKF_LOGIN_REQUIRED); 13296354Swyllys 13306354Swyllys return (KMF_OK); 13316354Swyllys } 1332*11973Swyllys.ingersoll@sun.com 1333*11973Swyllys.ingersoll@sun.com void 1334*11973Swyllys.ingersoll@sun.com show_ecc_curves() 1335*11973Swyllys.ingersoll@sun.com { 1336*11973Swyllys.ingersoll@sun.com int i; 1337*11973Swyllys.ingersoll@sun.com 1338*11973Swyllys.ingersoll@sun.com (void) printf(gettext("Supported ECC curve names:\n")); 1339*11973Swyllys.ingersoll@sun.com for (i = 0; i < number_of_curves; i++) { 1340*11973Swyllys.ingersoll@sun.com (void) printf("%s", oid_table[i].name); 1341*11973Swyllys.ingersoll@sun.com if (i > 0 && ((i+1) % 5) == 0) 1342*11973Swyllys.ingersoll@sun.com (void) printf("\n"); 1343*11973Swyllys.ingersoll@sun.com else if (i+1 < number_of_curves) 1344*11973Swyllys.ingersoll@sun.com (void) printf(", "); 1345*11973Swyllys.ingersoll@sun.com } 1346*11973Swyllys.ingersoll@sun.com (void) printf("\n"); 1347*11973Swyllys.ingersoll@sun.com } 1348*11973Swyllys.ingersoll@sun.com 1349*11973Swyllys.ingersoll@sun.com KMF_OID * 1350*11973Swyllys.ingersoll@sun.com ecc_name_to_oid(char *name) 1351*11973Swyllys.ingersoll@sun.com { 1352*11973Swyllys.ingersoll@sun.com int i; 1353*11973Swyllys.ingersoll@sun.com for (i = 0; i < number_of_oids; i++) { 1354*11973Swyllys.ingersoll@sun.com if (strcasecmp(name, oid_table[i].name) == 0) 1355*11973Swyllys.ingersoll@sun.com return ((KMF_OID *)oid_table[i].oid); 1356*11973Swyllys.ingersoll@sun.com } 1357*11973Swyllys.ingersoll@sun.com return (NULL); 1358*11973Swyllys.ingersoll@sun.com } 1359