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
20*12234Swyllys.ingersoll@sun.com *
21*12234Swyllys.ingersoll@sun.com * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
220Sstevel@tonic-gate */
230Sstevel@tonic-gate
240Sstevel@tonic-gate /*
250Sstevel@tonic-gate * This file contains the functions that are shared among
260Sstevel@tonic-gate * the various services this tool will ultimately provide.
2717Sdinak * The functions in this file return PKCS#11 CK_RV errors.
2817Sdinak * Only one session and one login per token is supported
2917Sdinak * at this time.
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <ctype.h>
363089Swyllys #include <sys/types.h>
373089Swyllys #include <sys/stat.h>
383089Swyllys #include <fcntl.h>
393089Swyllys #include <tzfile.h>
400Sstevel@tonic-gate #include <cryptoutil.h>
410Sstevel@tonic-gate #include <security/cryptoki.h>
423089Swyllys #include <kmfapi.h>
430Sstevel@tonic-gate
443089Swyllys #include "common.h"
4517Sdinak
4617Sdinak /* Local status variables. */
4717Sdinak static boolean_t initialized = B_FALSE;
4817Sdinak static boolean_t session_opened = B_FALSE;
4917Sdinak static boolean_t logged_in = B_FALSE;
5017Sdinak
51864Sdinak /* Supporting structures and global variables for getopt_av(). */
52864Sdinak typedef struct av_opts_s {
53864Sdinak int shortnm; /* short name character */
54864Sdinak char *longnm; /* long name string, NOT terminated */
55864Sdinak int longnm_len; /* length of long name string */
56864Sdinak boolean_t has_arg; /* takes optional argument */
57864Sdinak } av_opts;
58864Sdinak static av_opts *opts_av = NULL;
59864Sdinak static const char *_save_optstr = NULL;
60864Sdinak static int _save_numopts = 0;
61864Sdinak
62864Sdinak int optind_av = 1;
63864Sdinak char *optarg_av = NULL;
64864Sdinak
653089Swyllys static void close_sess(CK_SESSION_HANDLE);
663089Swyllys static void logout_token(CK_SESSION_HANDLE);
673089Swyllys
6811973Swyllys.ingersoll@sun.com struct oid_table_entry {
6911973Swyllys.ingersoll@sun.com const KMF_OID *oid;
7011973Swyllys.ingersoll@sun.com char *name;
7111973Swyllys.ingersoll@sun.com };
7211973Swyllys.ingersoll@sun.com
7311973Swyllys.ingersoll@sun.com struct oid_table_entry oid_table[] = {
7411973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp112r1, "secp112r1"},
7511973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp112r2, "secp112r2"},
7611973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp128r1, "secp128r1"},
7711973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp128r2, "secp128r2"},
7811973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp160k1, "secp160k1"},
7911973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp160r1, "secp160r1"},
8011973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp160r2, "secp160r2"},
8111973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp192k1, "secp192k1"},
8211973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp192r1, "secp192r1"},
8311973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp224k1, "secp224k1"},
8411973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp224r1, "secp224r1"},
8511973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp256k1, "secp256k1"},
8611973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp256r1, "secp256r1"},
8711973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp384r1, "secp384r1"},
8811973Swyllys.ingersoll@sun.com { &KMFOID_ECC_secp521r1, "secp521r1"},
8911973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect113r1, "sect113r1"},
9011973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect113r2, "sect113r2"},
9111973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect131r1, "sect131r1"},
9211973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect131r2, "sect131r2"},
9311973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect163k1, "sect163k1"},
9411973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect163r1, "sect163r1"},
9511973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect163r2, "sect163r2"},
9611973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect193r1, "sect193r1"},
9711973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect193r2, "sect193r2"},
9811973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect233k1, "sect233k1"},
9911973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect233r1, "sect233r1"},
10011973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect239k1, "sect239k1"},
10111973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect283k1, "sect283k1"},
10211973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect283r1, "sect283r1"},
10311973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect409k1, "sect409k1"},
10411973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect409r1, "sect409r1"},
10511973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect571k1, "sect571k1"},
10611973Swyllys.ingersoll@sun.com { &KMFOID_ECC_sect571r1, "sect571r1"},
10711973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb163v1, "c2pnb163v1"},
10811973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb163v2, "c2pnb163v2"},
10911973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb163v3, "c2pnb163v3"},
11011973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb176v1, "c2pnb176v1"},
11111973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb191v1, "c2tnb191v1"},
11211973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb191v2, "c2tnb191v2"},
11311973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb191v3, "c2tnb191v3"},
11411973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb208w1, "c2pnb208w1"},
11511973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb239v1, "c2tnb239v1"},
11611973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb239v2, "c2tnb239v2"},
11711973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb239v3, "c2tnb239v3"},
11811973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb272w1, "c2pnb272w1"},
11911973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb304w1, "c2pnb304w1"},
12011973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb359v1, "c2tnb359v1"},
12111973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2pnb368w1, "c2pnb368w1"},
12211973Swyllys.ingersoll@sun.com { &KMFOID_ECC_c2tnb431r1, "c2tnb431r1"},
12311973Swyllys.ingersoll@sun.com { &KMFOID_ECC_prime192v2, "prime192v2"},
12411973Swyllys.ingersoll@sun.com { &KMFOID_ECC_prime192v3, "prime192v3"},
12511973Swyllys.ingersoll@sun.com { &KMFOID_MD5, "md5"},
12611973Swyllys.ingersoll@sun.com { &KMFOID_SHA1, "sha1"},
12711973Swyllys.ingersoll@sun.com { &KMFOID_SHA256, "sha256"},
12811973Swyllys.ingersoll@sun.com { &KMFOID_SHA384, "sha384"},
12911973Swyllys.ingersoll@sun.com { &KMFOID_SHA512, "sha512"}
13011973Swyllys.ingersoll@sun.com };
13111973Swyllys.ingersoll@sun.com int number_of_oids = sizeof (oid_table) / sizeof (struct oid_table_entry);
13211973Swyllys.ingersoll@sun.com #define number_of_curves (number_of_oids - 5)
13311973Swyllys.ingersoll@sun.com
13417Sdinak /*
13517Sdinak * Perform PKCS#11 setup here. Currently only C_Initialize is required,
13617Sdinak * along with setting/resetting state variables.
13717Sdinak */
1386669Swyllys static CK_RV
init_pkcs11(void)1396669Swyllys init_pkcs11(void)
14017Sdinak {
14117Sdinak CK_RV rv = CKR_OK;
14217Sdinak
14317Sdinak /* If C_Initialize() already called, nothing to do here. */
14417Sdinak if (initialized == B_TRUE)
14517Sdinak return (CKR_OK);
14617Sdinak
14717Sdinak /* Reset state variables because C_Initialize() not yet done. */
14817Sdinak session_opened = B_FALSE;
14917Sdinak logged_in = B_FALSE;
15017Sdinak
15117Sdinak /* Initialize PKCS#11 library. */
15217Sdinak if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
15317Sdinak rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
15417Sdinak return (rv);
15517Sdinak }
15617Sdinak
15717Sdinak initialized = B_TRUE;
15817Sdinak return (CKR_OK);
15917Sdinak }
16017Sdinak
16117Sdinak /*
16217Sdinak * Finalize PKCS#11 library and reset state variables. Open sessions,
16317Sdinak * if any, are closed, and thereby any logins are logged out also.
16417Sdinak */
16517Sdinak void
final_pk11(CK_SESSION_HANDLE sess)16617Sdinak final_pk11(CK_SESSION_HANDLE sess)
16717Sdinak {
16817Sdinak
16917Sdinak /* If the library wasn't initialized, nothing to do here. */
17017Sdinak if (!initialized)
17117Sdinak return;
17217Sdinak
17317Sdinak /* Make sure the sesion is closed first. */
17417Sdinak close_sess(sess);
17517Sdinak
17617Sdinak (void) C_Finalize(NULL);
17717Sdinak initialized = B_FALSE;
17817Sdinak }
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate /*
18117Sdinak * Close PKCS#11 session and reset state variables. Any logins are
18217Sdinak * logged out.
18317Sdinak */
1843089Swyllys static void
close_sess(CK_SESSION_HANDLE sess)18517Sdinak close_sess(CK_SESSION_HANDLE sess)
18617Sdinak {
18717Sdinak
18817Sdinak if (sess == NULL) {
18917Sdinak return;
19017Sdinak }
19117Sdinak
19217Sdinak /* If session is already closed, nothing to do here. */
19317Sdinak if (!session_opened)
19417Sdinak return;
1950Sstevel@tonic-gate
19617Sdinak /* Make sure user is logged out of token. */
19717Sdinak logout_token(sess);
19817Sdinak
19917Sdinak (void) C_CloseSession(sess);
20017Sdinak session_opened = B_FALSE;
20117Sdinak }
20217Sdinak
20317Sdinak /*
20417Sdinak * Log user out of token and reset status variable.
20517Sdinak */
2063089Swyllys static void
logout_token(CK_SESSION_HANDLE sess)20717Sdinak logout_token(CK_SESSION_HANDLE sess)
20817Sdinak {
20917Sdinak
21017Sdinak if (sess == NULL) {
21117Sdinak return;
21217Sdinak }
21317Sdinak
21417Sdinak /* If already logged out, nothing to do here. */
21517Sdinak if (!logged_in)
21617Sdinak return;
21717Sdinak
21817Sdinak (void) C_Logout(sess);
21917Sdinak logged_in = B_FALSE;
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate /*
22317Sdinak * Gets PIN from user. Caller needs to free the returned PIN when done.
22417Sdinak * If two prompts are given, the PIN is confirmed with second prompt.
22517Sdinak * Note that getphassphrase() may return data in static memory area.
22617Sdinak */
22717Sdinak CK_RV
get_pin(char * prompt1,char * prompt2,CK_UTF8CHAR_PTR * pin,CK_ULONG * pinlen)22817Sdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
22917Sdinak {
2306051Swyllys char *save_phrase, *phrase1, *phrase2;
2310Sstevel@tonic-gate
23217Sdinak /* Prompt user for a PIN. */
23317Sdinak if (prompt1 == NULL) {
23417Sdinak return (CKR_ARGUMENTS_BAD);
23517Sdinak }
23617Sdinak if ((phrase1 = getpassphrase(prompt1)) == NULL) {
23717Sdinak return (CKR_FUNCTION_FAILED);
23817Sdinak }
23917Sdinak
24017Sdinak /* Duplicate 1st PIN in separate chunk of memory. */
24117Sdinak if ((save_phrase = strdup(phrase1)) == NULL)
24217Sdinak return (CKR_HOST_MEMORY);
24317Sdinak
24417Sdinak /* If second prompt given, PIN confirmation is requested. */
24517Sdinak if (prompt2 != NULL) {
24617Sdinak if ((phrase2 = getpassphrase(prompt2)) == NULL) {
24717Sdinak free(save_phrase);
24817Sdinak return (CKR_FUNCTION_FAILED);
24917Sdinak }
25017Sdinak if (strcmp(save_phrase, phrase2) != 0) {
25117Sdinak free(save_phrase);
25217Sdinak return (CKR_PIN_INCORRECT);
25317Sdinak }
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate
25617Sdinak *pin = (CK_UTF8CHAR_PTR)save_phrase;
25717Sdinak *pinlen = strlen(save_phrase);
25817Sdinak return (CKR_OK);
25917Sdinak }
26017Sdinak
2616051Swyllys int
yn_to_int(char * ynstr)2626051Swyllys yn_to_int(char *ynstr)
2636051Swyllys {
2646051Swyllys char *y = gettext("yes");
2656051Swyllys char *n = gettext("no");
2666051Swyllys if (ynstr == NULL)
2676051Swyllys return (-1);
2686051Swyllys
2696051Swyllys if (strncasecmp(ynstr, y, 1) == 0)
2706051Swyllys return (1);
2716051Swyllys else if (strncasecmp(ynstr, n, 1) == 0)
2726051Swyllys return (0);
2736051Swyllys else
2746051Swyllys return (-1);
2756051Swyllys }
2766051Swyllys
27717Sdinak /*
27817Sdinak * Gets yes/no response from user. If either no prompt is supplied, a
27917Sdinak * default prompt is used. If not message for invalid input is supplied,
28017Sdinak * a default will not be provided. If the user provides no response,
28117Sdinak * the input default B_TRUE == yes, B_FALSE == no is returned.
28217Sdinak * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
28317Sdinak */
28417Sdinak boolean_t
yesno(char * prompt,char * invalid,boolean_t dflt)28517Sdinak yesno(char *prompt, char *invalid, boolean_t dflt)
28617Sdinak {
2876051Swyllys char *response, buf[1024];
2886051Swyllys int ans;
28917Sdinak
29017Sdinak if (prompt == NULL)
29117Sdinak prompt = gettext("Enter (y)es or (n)o? ");
29217Sdinak
29317Sdinak for (;;) {
29417Sdinak /* Prompt user. */
29517Sdinak (void) printf("%s", prompt);
29617Sdinak (void) fflush(stdout);
29717Sdinak
29817Sdinak /* Get the response. */
29917Sdinak if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
30017Sdinak break; /* go to default response */
30117Sdinak
30217Sdinak /* Skip any leading white space. */
30317Sdinak while (isspace(*response))
30417Sdinak response++;
30517Sdinak if (*response == '\0')
30617Sdinak break; /* go to default response */
30717Sdinak
3086051Swyllys ans = yn_to_int(response);
3096051Swyllys if (ans == 1)
31017Sdinak return (B_TRUE);
3116051Swyllys else if (ans == 0)
31217Sdinak return (B_FALSE);
31317Sdinak
31417Sdinak /* Indicate invalid input, and try again. */
31517Sdinak if (invalid != NULL)
3165051Swyllys (void) printf("%s", invalid);
31717Sdinak }
31817Sdinak return (dflt);
31917Sdinak }
32017Sdinak
32117Sdinak /*
32217Sdinak * Gets the list of slots which have tokens in them. Keeps adjusting
32317Sdinak * the size of the slot list buffer until the call is successful or an
32417Sdinak * irrecoverable error occurs.
32517Sdinak */
32617Sdinak CK_RV
get_token_slots(CK_SLOT_ID_PTR * slot_list,CK_ULONG * slot_count)32717Sdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
32817Sdinak {
32917Sdinak CK_ULONG tmp_count = 0;
33017Sdinak CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
33117Sdinak int rv = CKR_OK;
33217Sdinak
33317Sdinak if (!initialized)
3346669Swyllys if ((rv = init_pkcs11()) != CKR_OK)
33517Sdinak return (rv);
33617Sdinak
33717Sdinak /*
33817Sdinak * Get the slot count first because we don't know how many
33917Sdinak * slots there are and how many of those slots even have tokens.
34017Sdinak * Don't specify an arbitrary buffer size for the slot list;
34117Sdinak * it may be too small (see section 11.5 of PKCS#11 spec).
34217Sdinak * Also select only those slots that have tokens in them,
34317Sdinak * because this tool has no need to know about empty slots.
34417Sdinak */
34517Sdinak if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
34617Sdinak return (rv);
34717Sdinak
34817Sdinak if (tmp_count == 0) {
34917Sdinak *slot_list = NULL_PTR;
35017Sdinak *slot_count = 0;
35117Sdinak return (CKR_OK);
35217Sdinak }
35317Sdinak
35417Sdinak /* Allocate initial space for the slot list. */
35517Sdinak if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
35617Sdinak sizeof (CK_SLOT_ID))) == NULL)
35717Sdinak return (CKR_HOST_MEMORY);
35817Sdinak
35917Sdinak /* Then get the slot list itself. */
36017Sdinak for (;;) {
36117Sdinak if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
36217Sdinak *slot_list = tmp_list;
36317Sdinak *slot_count = tmp_count;
36417Sdinak break;
36517Sdinak }
36617Sdinak
36717Sdinak if (rv != CKR_BUFFER_TOO_SMALL) {
36817Sdinak free(tmp_list);
36917Sdinak break;
37017Sdinak }
37117Sdinak
37217Sdinak /* If the number of slots grew, try again. */
37317Sdinak if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
37417Sdinak tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
37517Sdinak free(tmp_list);
37617Sdinak rv = CKR_HOST_MEMORY;
37717Sdinak break;
37817Sdinak }
37917Sdinak tmp_list = tmp2_list;
38017Sdinak }
38117Sdinak
38217Sdinak return (rv);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /*
386864Sdinak * Breaks out the getopt-style option string into a structure that can be
387864Sdinak * traversed later for calls to getopt_av(). Option string is NOT altered,
388864Sdinak * but the struct fields point to locations within option string.
389864Sdinak */
390864Sdinak static int
populate_opts(char * optstring)391864Sdinak populate_opts(char *optstring)
392864Sdinak {
393864Sdinak int i;
394864Sdinak av_opts *temp;
395864Sdinak char *marker;
396864Sdinak
397864Sdinak if (optstring == NULL || *optstring == '\0')
398864Sdinak return (0);
399864Sdinak
400864Sdinak /*
401864Sdinak * This tries to imitate getopt(3c) Each option must conform to:
402864Sdinak * <short name char> [ ':' ] [ '(' <long name string> ')' ]
403864Sdinak * If long name is missing, the short name is used for long name.
404864Sdinak */
405864Sdinak for (i = 0; *optstring != '\0'; i++) {
406864Sdinak if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
407864Sdinak realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
4083089Swyllys if (opts_av != NULL)
4093089Swyllys free(opts_av);
410864Sdinak opts_av = NULL;
411864Sdinak return (0);
4123089Swyllys } else {
413864Sdinak opts_av = (av_opts *)temp;
4143089Swyllys }
415864Sdinak
4163089Swyllys (void) memset(&opts_av[i], 0, sizeof (av_opts));
417864Sdinak marker = optstring; /* may need optstring later */
418864Sdinak
419864Sdinak opts_av[i].shortnm = *marker++; /* set short name */
420864Sdinak
421864Sdinak if (*marker == ':') { /* check for opt arg */
422864Sdinak marker++;
423864Sdinak opts_av[i].has_arg = B_TRUE;
424864Sdinak }
425864Sdinak
426864Sdinak if (*marker == '(') { /* check and set long name */
427864Sdinak marker++;
428864Sdinak opts_av[i].longnm = marker;
429864Sdinak opts_av[i].longnm_len = strcspn(marker, ")");
430864Sdinak optstring = marker + opts_av[i].longnm_len + 1;
431864Sdinak } else {
432864Sdinak /* use short name option character */
433864Sdinak opts_av[i].longnm = optstring;
434864Sdinak opts_av[i].longnm_len = 1;
435864Sdinak optstring = marker;
436864Sdinak }
437864Sdinak }
438864Sdinak
439864Sdinak return (i);
440864Sdinak }
441864Sdinak
442864Sdinak /*
443864Sdinak * getopt_av() is very similar to getopt(3c) in that the takes an option
444864Sdinak * string, compares command line arguments for matches, and returns a single
445864Sdinak * letter option when a match is found. However, getopt_av() differs from
446864Sdinak * getopt(3c) by requiring that only longname options and values be found
447864Sdinak * on the command line and all leading dashes are omitted. In other words,
448864Sdinak * it tries to enforce only longname "option=value" arguments on the command
449864Sdinak * line. Boolean options are not allowed either.
450864Sdinak */
451864Sdinak int
getopt_av(int argc,char * const * argv,const char * optstring)452864Sdinak getopt_av(int argc, char * const *argv, const char *optstring)
453864Sdinak {
454864Sdinak int i;
455864Sdinak int len;
4563089Swyllys char *cur_option;
457864Sdinak
458864Sdinak if (optind_av >= argc)
459864Sdinak return (EOF);
460864Sdinak
461864Sdinak /* First time or when optstring changes from previous one */
462864Sdinak if (_save_optstr != optstring) {
463864Sdinak if (opts_av != NULL)
4645051Swyllys free(opts_av);
465864Sdinak opts_av = NULL;
466864Sdinak _save_optstr = optstring;
467864Sdinak _save_numopts = populate_opts((char *)optstring);
468864Sdinak }
469864Sdinak
470864Sdinak for (i = 0; i < _save_numopts; i++) {
4713089Swyllys cur_option = argv[optind_av];
4723089Swyllys
4733089Swyllys if (strcmp(cur_option, "--") == 0) {
474864Sdinak optind_av++;
475864Sdinak break;
476864Sdinak }
477864Sdinak
4783089Swyllys if (cur_option[0] == '-' && strlen(cur_option) == 2) {
4793089Swyllys len = 1;
4803089Swyllys cur_option++; /* remove "-" */
4813089Swyllys } else {
4823089Swyllys len = strcspn(cur_option, "=");
4833089Swyllys }
484864Sdinak
4853089Swyllys if (len == opts_av[i].longnm_len && strncmp(cur_option,
486864Sdinak opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
487864Sdinak /* matched */
488864Sdinak if (!opts_av[i].has_arg) {
489864Sdinak optind_av++;
490864Sdinak return (opts_av[i].shortnm);
491864Sdinak }
492864Sdinak
493864Sdinak /* needs optarg */
4943089Swyllys if (cur_option[len] == '=') {
4953089Swyllys optarg_av = &(cur_option[len+1]);
496864Sdinak optind_av++;
497864Sdinak return (opts_av[i].shortnm);
498864Sdinak }
499864Sdinak
500864Sdinak optarg_av = NULL;
501864Sdinak optind_av++;
502864Sdinak return ((int)'?');
503864Sdinak }
504864Sdinak }
505864Sdinak
506864Sdinak return (EOF);
507864Sdinak }
5083089Swyllys
5093089Swyllys KMF_KEYSTORE_TYPE
KS2Int(char * keystore_str)5103089Swyllys KS2Int(char *keystore_str)
5113089Swyllys {
5123089Swyllys if (keystore_str == NULL)
5133089Swyllys return (0);
5146051Swyllys if (strcasecmp(keystore_str, "pkcs11") == 0)
5153089Swyllys return (KMF_KEYSTORE_PK11TOKEN);
5166051Swyllys else if (strcasecmp(keystore_str, "nss") == 0)
5173089Swyllys return (KMF_KEYSTORE_NSS);
5186051Swyllys else if (strcasecmp(keystore_str, "file") == 0)
5193089Swyllys return (KMF_KEYSTORE_OPENSSL);
5203089Swyllys else
5213089Swyllys return (0);
5223089Swyllys }
5233089Swyllys
52411973Swyllys.ingersoll@sun.com /*
52511973Swyllys.ingersoll@sun.com * compare_oids
52611973Swyllys.ingersoll@sun.com * return 1 if equal
52711973Swyllys.ingersoll@sun.com */
52811973Swyllys.ingersoll@sun.com boolean_t
compare_oids(KMF_OID * oid1,const KMF_OID * oid2)52911973Swyllys.ingersoll@sun.com compare_oids(KMF_OID *oid1, const KMF_OID *oid2)
53011973Swyllys.ingersoll@sun.com {
53111973Swyllys.ingersoll@sun.com return ((oid1->Length == oid2->Length) &&
53211973Swyllys.ingersoll@sun.com !memcmp(oid1->Data, oid2->Data, oid1->Length));
53311973Swyllys.ingersoll@sun.com }
5343089Swyllys
5353089Swyllys int
Str2KeyType(char * algm,KMF_OID * hashoid,KMF_KEY_ALG * ktype,KMF_ALGORITHM_INDEX * sigAlg)53611973Swyllys.ingersoll@sun.com Str2KeyType(char *algm, KMF_OID *hashoid, KMF_KEY_ALG *ktype,
53711973Swyllys.ingersoll@sun.com KMF_ALGORITHM_INDEX *sigAlg)
5383089Swyllys {
5393089Swyllys if (algm == NULL) {
54011973Swyllys.ingersoll@sun.com /* Default to SHA1+RSA */
54110744Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithRSA;
5423089Swyllys *ktype = KMF_RSA;
5433089Swyllys } else if (strcasecmp(algm, "DSA") == 0) {
54411973Swyllys.ingersoll@sun.com if (hashoid == NULL ||
54511973Swyllys.ingersoll@sun.com compare_oids(hashoid, &KMFOID_SHA1))
54611973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithDSA;
54711973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA256))
54811973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA256WithDSA;
54911973Swyllys.ingersoll@sun.com else
55011973Swyllys.ingersoll@sun.com return (-1); /* unsupported hash/key combo */
5513089Swyllys *ktype = KMF_DSA;
5523089Swyllys } else if (strcasecmp(algm, "RSA") == 0) {
55311973Swyllys.ingersoll@sun.com if (hashoid == NULL ||
55411973Swyllys.ingersoll@sun.com compare_oids(hashoid, &KMFOID_SHA1))
55511973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithRSA;
55611973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA256))
55711973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA256WithRSA;
55811973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA384))
55911973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA384WithRSA;
56011973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA512))
56111973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA512WithRSA;
56211973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_MD5))
56311973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_MD5WithRSA;
56411973Swyllys.ingersoll@sun.com else
56511973Swyllys.ingersoll@sun.com return (-1); /* unsupported hash/key combo */
5663089Swyllys *ktype = KMF_RSA;
56711973Swyllys.ingersoll@sun.com } else if (strcasecmp(algm, "EC") == 0) {
56811973Swyllys.ingersoll@sun.com /* EC keys may be used with some SHA2 hashes */
56911973Swyllys.ingersoll@sun.com if (hashoid == NULL ||
57011973Swyllys.ingersoll@sun.com compare_oids(hashoid, &KMFOID_SHA1))
57111973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA1WithECDSA;
57211973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA256))
57311973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA256WithECDSA;
57411973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA384))
57511973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA384WithECDSA;
57611973Swyllys.ingersoll@sun.com else if (compare_oids(hashoid, &KMFOID_SHA512))
57711973Swyllys.ingersoll@sun.com *sigAlg = KMF_ALGID_SHA512WithECDSA;
57811973Swyllys.ingersoll@sun.com else
57911973Swyllys.ingersoll@sun.com return (-1); /* unsupported hash/key combo */
58011973Swyllys.ingersoll@sun.com
58111973Swyllys.ingersoll@sun.com *ktype = KMF_ECDSA;
5823089Swyllys } else {
5833089Swyllys return (-1);
5843089Swyllys }
5853089Swyllys return (0);
5863089Swyllys }
5873089Swyllys
5883089Swyllys int
Str2SymKeyType(char * algm,KMF_KEY_ALG * ktype)5893089Swyllys Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
5903089Swyllys {
5913089Swyllys if (algm == NULL)
5923089Swyllys *ktype = KMF_AES;
5933089Swyllys else if (strcasecmp(algm, "aes") == 0)
5943089Swyllys *ktype = KMF_AES;
5953089Swyllys else if (strcasecmp(algm, "arcfour") == 0)
5963089Swyllys *ktype = KMF_RC4;
5973089Swyllys else if (strcasecmp(algm, "des") == 0)
5983089Swyllys *ktype = KMF_DES;
5993089Swyllys else if (strcasecmp(algm, "3des") == 0)
6003089Swyllys *ktype = KMF_DES3;
6013812Shylee else if (strcasecmp(algm, "generic") == 0)
6023812Shylee *ktype = KMF_GENERIC_SECRET;
6033089Swyllys else
6043089Swyllys return (-1);
6053089Swyllys
6063089Swyllys return (0);
6073089Swyllys }
6083089Swyllys
6093089Swyllys int
Str2Lifetime(char * ltimestr,uint32_t * ltime)6103089Swyllys Str2Lifetime(char *ltimestr, uint32_t *ltime)
6113089Swyllys {
6123089Swyllys int num;
6133089Swyllys char timetok[6];
6143089Swyllys
6156051Swyllys if (ltimestr == NULL || strlen(ltimestr) == 0) {
6163089Swyllys /* default to 1 year lifetime */
6173089Swyllys *ltime = SECSPERDAY * DAYSPERNYEAR;
6183089Swyllys return (0);
6193089Swyllys }
6203089Swyllys
6213089Swyllys (void) memset(timetok, 0, sizeof (timetok));
6223089Swyllys if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
6233089Swyllys return (-1);
6243089Swyllys
6256051Swyllys if (strcasecmp(timetok, "day") == 0||
6266051Swyllys strcasecmp(timetok, "days") == 0) {
6273089Swyllys *ltime = num * SECSPERDAY;
6286051Swyllys } else if (strcasecmp(timetok, "hour") == 0||
6296051Swyllys strcasecmp(timetok, "hours") == 0) {
6303089Swyllys *ltime = num * SECSPERHOUR;
6316051Swyllys } else if (strcasecmp(timetok, "year") == 0 ||
6326051Swyllys strcasecmp(timetok, "years") == 0) {
6333089Swyllys *ltime = num * SECSPERDAY * DAYSPERNYEAR;
6343089Swyllys } else {
6353089Swyllys *ltime = 0;
6363089Swyllys return (-1);
6373089Swyllys }
6383089Swyllys
6393089Swyllys return (0);
6403089Swyllys }
6413089Swyllys
6423089Swyllys int
OT2Int(char * objclass)6433089Swyllys OT2Int(char *objclass)
6443089Swyllys {
6453089Swyllys char *c = NULL;
6463089Swyllys int retval = 0;
6473089Swyllys
6483089Swyllys if (objclass == NULL)
6493089Swyllys return (-1);
6503089Swyllys
6513089Swyllys c = strchr(objclass, ':');
6523089Swyllys if (c != NULL) {
6536051Swyllys if (strcasecmp(c, ":private") == 0)
6543089Swyllys retval = PK_PRIVATE_OBJ;
6556051Swyllys else if (strcasecmp(c, ":public") == 0)
6563089Swyllys retval = PK_PUBLIC_OBJ;
6576051Swyllys else if (strcasecmp(c, ":both") == 0)
6583089Swyllys retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
6593089Swyllys else /* unrecognized option */
6603089Swyllys return (-1);
6613089Swyllys
6623089Swyllys *c = '\0';
6633089Swyllys }
6643089Swyllys
6656051Swyllys if (strcasecmp(objclass, "public") == 0) {
6663089Swyllys if (retval)
6673089Swyllys return (-1);
6685051Swyllys return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ);
6696051Swyllys } else if (strcasecmp(objclass, "private") == 0) {
6703089Swyllys if (retval)
6713089Swyllys return (-1);
6723089Swyllys return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
6736051Swyllys } else if (strcasecmp(objclass, "both") == 0) {
6743089Swyllys if (retval)
6753089Swyllys return (-1);
6763089Swyllys return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
6776051Swyllys } else if (strcasecmp(objclass, "cert") == 0) {
6783089Swyllys return (retval | PK_CERT_OBJ);
6796051Swyllys } else if (strcasecmp(objclass, "key") == 0) {
6803089Swyllys if (retval == 0) /* return all keys */
6813089Swyllys return (retval | PK_KEY_OBJ);
6823089Swyllys else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
6833089Swyllys /* return all keys */
6843089Swyllys return (retval | PK_KEY_OBJ);
6853089Swyllys else if (retval & PK_PUBLIC_OBJ)
6863089Swyllys /* Only return public keys */
6873089Swyllys return (retval | PK_PUBKEY_OBJ);
6883089Swyllys else if (retval & PK_PRIVATE_OBJ)
6893089Swyllys /* Only return private keys */
6903089Swyllys return (retval | PK_PRIKEY_OBJ);
6916051Swyllys } else if (strcasecmp(objclass, "crl") == 0) {
6923089Swyllys if (retval)
6933089Swyllys return (-1);
6943089Swyllys return (retval | PK_CRL_OBJ);
6953089Swyllys }
6963089Swyllys
6973089Swyllys if (retval == 0) /* No matches found */
6983089Swyllys retval = -1;
6993089Swyllys return (retval);
7003089Swyllys }
7013089Swyllys
7023089Swyllys KMF_ENCODE_FORMAT
Str2Format(char * formstr)7033089Swyllys Str2Format(char *formstr)
7043089Swyllys {
7056051Swyllys if (formstr == NULL || strcasecmp(formstr, "der") == 0)
7063089Swyllys return (KMF_FORMAT_ASN1);
7076051Swyllys if (strcasecmp(formstr, "pem") == 0)
7083089Swyllys return (KMF_FORMAT_PEM);
7096051Swyllys if (strcasecmp(formstr, "pkcs12") == 0)
7103089Swyllys return (KMF_FORMAT_PKCS12);
7116051Swyllys if (strcasecmp(formstr, "raw") == 0)
7125051Swyllys return (KMF_FORMAT_RAWKEY);
7133089Swyllys
7143089Swyllys return (KMF_FORMAT_UNDEF);
7153089Swyllys }
7163089Swyllys
7173089Swyllys KMF_RETURN
select_token(void * kmfhandle,char * token,int readonly)7186051Swyllys select_token(void *kmfhandle, char *token, int readonly)
7193089Swyllys {
7205051Swyllys KMF_ATTRIBUTE attlist[10];
7215051Swyllys int i = 0;
7225051Swyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
7233089Swyllys KMF_RETURN rv = KMF_OK;
7243089Swyllys
7253089Swyllys if (token == NULL)
7263089Swyllys return (KMF_ERR_BAD_PARAMETER);
7273089Swyllys
7285051Swyllys kmf_set_attr_at_index(attlist, i,
7295051Swyllys KMF_KEYSTORE_TYPE_ATTR, &kstype,
7305051Swyllys sizeof (kstype));
7315051Swyllys i++;
7323089Swyllys
7335051Swyllys if (token) {
7345051Swyllys kmf_set_attr_at_index(attlist, i,
7355051Swyllys KMF_TOKEN_LABEL_ATTR, token,
7365051Swyllys strlen(token));
7375051Swyllys i++;
7385051Swyllys }
7395051Swyllys
7405051Swyllys kmf_set_attr_at_index(attlist, i,
7415051Swyllys KMF_READONLY_ATTR, &readonly,
7425051Swyllys sizeof (readonly));
7435051Swyllys i++;
7445051Swyllys
7455051Swyllys rv = kmf_configure_keystore(kmfhandle, i, attlist);
7463089Swyllys if (rv == KMF_ERR_TOKEN_SELECTED)
7473089Swyllys rv = KMF_OK;
7483089Swyllys return (rv);
7493089Swyllys }
7503089Swyllys
7513089Swyllys KMF_RETURN
configure_nss(void * kmfhandle,char * dir,char * prefix)7523089Swyllys configure_nss(void *kmfhandle, char *dir, char *prefix)
7533089Swyllys {
7545051Swyllys KMF_ATTRIBUTE attlist[10];
7555051Swyllys int i = 0;
7565051Swyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
7573089Swyllys KMF_RETURN rv = KMF_OK;
7585051Swyllys
7595051Swyllys kmf_set_attr_at_index(attlist, i,
7605051Swyllys KMF_KEYSTORE_TYPE_ATTR, &kstype,
7615051Swyllys sizeof (kstype));
7625051Swyllys i++;
7633089Swyllys
7645051Swyllys if (dir) {
7655051Swyllys kmf_set_attr_at_index(attlist, i,
7665051Swyllys KMF_DIRPATH_ATTR, dir,
7675051Swyllys strlen(dir));
7685051Swyllys i++;
7695051Swyllys }
7703089Swyllys
7715051Swyllys if (prefix) {
7725051Swyllys kmf_set_attr_at_index(attlist, i,
7735051Swyllys KMF_CERTPREFIX_ATTR, prefix,
7745051Swyllys strlen(prefix));
7755051Swyllys i++;
7765051Swyllys
7775051Swyllys kmf_set_attr_at_index(attlist, i,
7785051Swyllys KMF_KEYPREFIX_ATTR, prefix,
7795051Swyllys strlen(prefix));
7805051Swyllys i++;
7815051Swyllys }
7825051Swyllys
7835051Swyllys rv = kmf_configure_keystore(kmfhandle, i, attlist);
7843089Swyllys if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
7853089Swyllys rv = KMF_OK;
7863089Swyllys
7873089Swyllys return (rv);
7883089Swyllys }
7893089Swyllys
7903089Swyllys KMF_RETURN
get_pk12_password(KMF_CREDENTIAL * cred)7913089Swyllys get_pk12_password(KMF_CREDENTIAL *cred)
7923089Swyllys {
7933089Swyllys KMF_RETURN rv = KMF_OK;
7943089Swyllys char prompt[1024];
7953089Swyllys
7963089Swyllys /*
7973089Swyllys * Get the password to use for the PK12 encryption.
7983089Swyllys */
7993089Swyllys (void) strlcpy(prompt,
8005051Swyllys gettext("Enter password to use for "
8015051Swyllys "accessing the PKCS12 file: "), sizeof (prompt));
8023089Swyllys
8033089Swyllys if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
8045051Swyllys (ulong_t *)&cred->credlen) != CKR_OK) {
8053089Swyllys cred->cred = NULL;
8063089Swyllys cred->credlen = 0;
8073089Swyllys }
8083089Swyllys
8093089Swyllys return (rv);
8103089Swyllys }
8113089Swyllys
8125221Swyllys #define FILENAME_PROMPT gettext("Filename:")
8135221Swyllys #define FILENAME_MINLEN 1
8145221Swyllys #define FILENAME_MAXLEN MAXPATHLEN
8153089Swyllys
8165221Swyllys #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:")
8175221Swyllys #define STATE_PROMPT gettext("State or Province Name (full name) " \
8185221Swyllys "[Some-State]:")
8195221Swyllys #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:")
8205221Swyllys #define ORG_PROMPT gettext("Organization Name (eg, company) []:")
8215221Swyllys #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:")
8225221Swyllys #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:")
8235221Swyllys #define EMAIL_PROMPT gettext("Email Address []:")
8245221Swyllys
8255221Swyllys #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \
8265221Swyllys "0x01020304):")
8275221Swyllys #define SERNO_MINLEN 3
8285221Swyllys #define SERNO_MAXLEN 42
8295221Swyllys
8305221Swyllys #define LABEL_PROMPT gettext("Enter a label for the certificate:")
8315221Swyllys #define LABEL_MINLEN 1
8325221Swyllys #define LABEL_MAXLEN 1024
8333089Swyllys
8343089Swyllys #define COUNTRY_DEFAULT "US"
8355221Swyllys #define STATE_DEFAULT NULL
8365221Swyllys #define INVALID_INPUT gettext("Invalid input; please re-enter ...")
8373089Swyllys
8383089Swyllys #define SUBNAMESIZ 1024
8393089Swyllys #define RDN_MIN 1
8403089Swyllys #define RDN_MAX 64
8413089Swyllys #define COUNTRYNAME_MIN 2
8423089Swyllys #define COUNTRYNAME_MAX 2
8433089Swyllys
8443089Swyllys static char *
get_input_string(char * prompt,char * default_str,int min_len,int max_len)8453089Swyllys get_input_string(char *prompt, char *default_str, int min_len, int max_len)
8463089Swyllys {
8473089Swyllys char buf[1024];
8483089Swyllys char *response = NULL;
8493089Swyllys char *ret = NULL;
8503089Swyllys int len;
8513089Swyllys
8523089Swyllys for (;;) {
8533089Swyllys (void) printf("\t%s", prompt);
8543089Swyllys (void) fflush(stdout);
8553089Swyllys
8563089Swyllys response = fgets(buf, sizeof (buf), stdin);
8573089Swyllys if (response == NULL) {
8583089Swyllys if (default_str != NULL) {
8593089Swyllys ret = strdup(default_str);
8603089Swyllys }
8613089Swyllys break;
8623089Swyllys }
8633089Swyllys
8643089Swyllys /* Skip any leading white space. */
8653089Swyllys while (isspace(*response))
8663089Swyllys response++;
8673089Swyllys if (*response == '\0') {
8683089Swyllys if (default_str != NULL) {
8693089Swyllys ret = strdup(default_str);
8703089Swyllys }
8713089Swyllys break;
8723089Swyllys }
8733089Swyllys
8743089Swyllys len = strlen(response);
8753089Swyllys response[len-1] = '\0'; /* get rid of "LF" */
8763089Swyllys len--;
8773089Swyllys if (len >= min_len && len <= max_len) {
8783089Swyllys ret = strdup(response);
8793089Swyllys break;
8803089Swyllys }
8813089Swyllys
8823089Swyllys (void) printf("%s\n", INVALID_INPUT);
8833089Swyllys
8843089Swyllys }
8853089Swyllys
8863089Swyllys return (ret);
8873089Swyllys }
8883089Swyllys
8893089Swyllys int
get_filename(char * txt,char ** result)8905221Swyllys get_filename(char *txt, char **result)
8915221Swyllys {
8925221Swyllys char prompt[1024];
8935221Swyllys char *fname = NULL;
8945221Swyllys
8955221Swyllys (void) snprintf(prompt, sizeof (prompt),
8965221Swyllys gettext("Enter filename for the %s: "),
8975221Swyllys txt);
8985221Swyllys fname = get_input_string(prompt, NULL,
8995221Swyllys FILENAME_MINLEN, FILENAME_MAXLEN);
9005221Swyllys *result = fname;
9015221Swyllys return (0);
9025221Swyllys }
9035221Swyllys
9045221Swyllys int
get_certlabel(char ** result)9055221Swyllys get_certlabel(char **result)
9065221Swyllys {
9075221Swyllys char *label = NULL;
9085221Swyllys
9095221Swyllys label = get_input_string(LABEL_PROMPT, NULL,
9105221Swyllys LABEL_MINLEN, LABEL_MAXLEN);
9115221Swyllys *result = label;
9125221Swyllys return (0);
9135221Swyllys }
9145221Swyllys
9155221Swyllys int
get_serial(char ** result)9165221Swyllys get_serial(char **result)
9175221Swyllys {
9185221Swyllys char *serial = NULL;
9195221Swyllys
9205221Swyllys serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN,
9215221Swyllys SERNO_MAXLEN);
9225221Swyllys
9235221Swyllys *result = serial;
9245221Swyllys return (0);
9255221Swyllys }
9265221Swyllys
9275221Swyllys int
get_subname(char ** result)9283089Swyllys get_subname(char **result)
9293089Swyllys {
9303089Swyllys char *country = NULL;
9313089Swyllys char *state = NULL;
9323089Swyllys char *locality = NULL;
9333089Swyllys char *org = NULL;
9343089Swyllys char *unit = NULL;
9353089Swyllys char *name = NULL;
9363089Swyllys char *email = NULL;
9373089Swyllys char *subname = NULL;
9383089Swyllys
9393089Swyllys (void) printf("Entering following fields for subject (a DN) ...\n");
9403089Swyllys country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
9413089Swyllys COUNTRYNAME_MIN, COUNTRYNAME_MAX);
9423089Swyllys if (country == NULL)
9433089Swyllys return (-1);
9443089Swyllys
9453089Swyllys state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
9463089Swyllys RDN_MIN, RDN_MAX);
9473089Swyllys
9483089Swyllys locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
9493089Swyllys org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
9503089Swyllys unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
9513089Swyllys name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
9523089Swyllys email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
9533089Swyllys
9543089Swyllys /* Now create a subject name from the input strings */
9553089Swyllys if ((subname = malloc(SUBNAMESIZ)) == NULL)
9563089Swyllys goto out;
9573089Swyllys
9583089Swyllys (void) memset(subname, 0, SUBNAMESIZ);
9593089Swyllys (void) strlcpy(subname, "C=", SUBNAMESIZ);
9603089Swyllys (void) strlcat(subname, country, SUBNAMESIZ);
9615221Swyllys if (state != NULL) {
9625221Swyllys (void) strlcat(subname, ", ST=", SUBNAMESIZ);
9635221Swyllys (void) strlcat(subname, state, SUBNAMESIZ);
9645221Swyllys }
9653089Swyllys
9665221Swyllys if (locality != NULL) {
9675221Swyllys (void) strlcat(subname, ", L=", SUBNAMESIZ);
9683089Swyllys (void) strlcat(subname, locality, SUBNAMESIZ);
9693089Swyllys }
9703089Swyllys
9715221Swyllys if (org != NULL) {
9725221Swyllys (void) strlcat(subname, ", O=", SUBNAMESIZ);
9733089Swyllys (void) strlcat(subname, org, SUBNAMESIZ);
9743089Swyllys }
9753089Swyllys
9765221Swyllys if (unit != NULL) {
9775221Swyllys (void) strlcat(subname, ", OU=", SUBNAMESIZ);
9783089Swyllys (void) strlcat(subname, unit, SUBNAMESIZ);
9793089Swyllys }
9803089Swyllys
9815221Swyllys if (name != NULL) {
9825221Swyllys (void) strlcat(subname, ", CN=", SUBNAMESIZ);
9833089Swyllys (void) strlcat(subname, name, SUBNAMESIZ);
9843089Swyllys }
9853089Swyllys
9865221Swyllys if (email != NULL) {
9875221Swyllys (void) strlcat(subname, ", E=", SUBNAMESIZ);
9883089Swyllys (void) strlcat(subname, email, SUBNAMESIZ);
9893089Swyllys }
9903089Swyllys
9913089Swyllys out:
9923089Swyllys if (country)
9933089Swyllys free(country);
9943089Swyllys if (state)
9953089Swyllys free(state);
9963089Swyllys if (locality)
9973089Swyllys free(locality);
9983089Swyllys if (org)
9993089Swyllys free(org);
10003089Swyllys if (unit)
10013089Swyllys free(unit);
10023089Swyllys if (name)
10033089Swyllys free(name);
10043089Swyllys if (email)
10053089Swyllys free(email);
10063089Swyllys
10073089Swyllys if (subname == NULL)
10083089Swyllys return (-1);
10093089Swyllys else {
10103089Swyllys *result = subname;
10113089Swyllys return (0);
10123089Swyllys }
10133089Swyllys }
10143089Swyllys
10153089Swyllys /*
10163089Swyllys * Parse a string of KeyUsage values and convert
10173089Swyllys * them to the correct KU Bits.
10183089Swyllys * The field may be marked "critical" by prepending
10193089Swyllys * "critical:" to the list.
10203089Swyllys * EX: critical:digitialSignature,keyEncipherment
10213089Swyllys */
10223089Swyllys KMF_RETURN
verify_keyusage(char * kustr,uint16_t * kubits,int * critical)10233089Swyllys verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
10243089Swyllys {
10253089Swyllys KMF_RETURN ret = KMF_OK;
10263089Swyllys uint16_t kuval;
10273089Swyllys char *k;
10283089Swyllys
10293089Swyllys *kubits = 0;
10306051Swyllys if (kustr == NULL || strlen(kustr) == 0)
10313089Swyllys return (KMF_ERR_BAD_PARAMETER);
10323089Swyllys
10333089Swyllys /* Check to see if this is critical */
10346051Swyllys if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) {
10353089Swyllys *critical = TRUE;
10363089Swyllys kustr += strlen("critical:");
10373089Swyllys } else {
10383089Swyllys *critical = FALSE;
10393089Swyllys }
10403089Swyllys
10413089Swyllys k = strtok(kustr, ",");
10423089Swyllys while (k != NULL) {
10435051Swyllys kuval = kmf_string_to_ku(k);
10443089Swyllys if (kuval == 0) {
10453089Swyllys *kubits = 0;
10463089Swyllys return (KMF_ERR_BAD_PARAMETER);
10473089Swyllys }
10483089Swyllys *kubits |= kuval;
10493089Swyllys k = strtok(NULL, ",");
10503089Swyllys }
10513089Swyllys
10523089Swyllys return (ret);
10533089Swyllys }
10543089Swyllys
10553089Swyllys /*
10563089Swyllys * Verify the alternate subject label is real or invalid.
10573089Swyllys *
10583089Swyllys * The field may be marked "critical" by prepending
10593089Swyllys * "critical:" to the list.
10603089Swyllys * EX: "critical:IP=1.2.3.4"
10613089Swyllys */
10623089Swyllys KMF_RETURN
verify_altname(char * arg,KMF_GENERALNAMECHOICES * type,int * critical)10633089Swyllys verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
10643089Swyllys {
10653089Swyllys char *p;
10663089Swyllys KMF_RETURN rv = KMF_OK;
10673089Swyllys
10683089Swyllys /* Check to see if this is critical */
10696051Swyllys if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) {
10703089Swyllys *critical = TRUE;
10713089Swyllys arg += strlen("critical:");
10723089Swyllys } else {
10733089Swyllys *critical = FALSE;
10743089Swyllys }
10753089Swyllys
10763089Swyllys /* Make sure there is an "=" sign */
10773089Swyllys p = strchr(arg, '=');
10783089Swyllys if (p == NULL)
10793089Swyllys return (KMF_ERR_BAD_PARAMETER);
10803089Swyllys
10813089Swyllys p[0] = '\0';
10823089Swyllys
10833089Swyllys if (strcmp(arg, "IP") == 0)
10843089Swyllys *type = GENNAME_IPADDRESS;
10853089Swyllys else if (strcmp(arg, "DNS") == 0)
10863089Swyllys *type = GENNAME_DNSNAME;
10873089Swyllys else if (strcmp(arg, "EMAIL") == 0)
10883089Swyllys *type = GENNAME_RFC822NAME;
10893089Swyllys else if (strcmp(arg, "URI") == 0)
10903089Swyllys *type = GENNAME_URI;
10913089Swyllys else if (strcmp(arg, "DN") == 0)
10923089Swyllys *type = GENNAME_DIRECTORYNAME;
10933089Swyllys else if (strcmp(arg, "RID") == 0)
10943089Swyllys *type = GENNAME_REGISTEREDID;
10956051Swyllys else if (strcmp(arg, "KRB") == 0)
10966051Swyllys *type = GENNAME_KRB5PRINC;
10976051Swyllys else if (strcmp(arg, "UPN") == 0)
10986051Swyllys *type = GENNAME_SCLOGON_UPN;
10993089Swyllys else
11003089Swyllys rv = KMF_ERR_BAD_PARAMETER;
11013089Swyllys
11023089Swyllys p[0] = '=';
11033089Swyllys
11043089Swyllys return (rv);
11053089Swyllys }
11063089Swyllys
11073089Swyllys int
get_token_password(KMF_KEYSTORE_TYPE kstype,char * token_spec,KMF_CREDENTIAL * cred)11083089Swyllys get_token_password(KMF_KEYSTORE_TYPE kstype,
11093089Swyllys char *token_spec, KMF_CREDENTIAL *cred)
11103089Swyllys {
11113089Swyllys char prompt[1024];
11128132SWyllys.Ingersoll@Sun.COM char temptoken[32];
11133089Swyllys char *p = NULL;
11148132SWyllys.Ingersoll@Sun.COM char *t = NULL;
11159126SWyllys.Ingersoll@Sun.COM int len;
11163089Swyllys
11179126SWyllys.Ingersoll@Sun.COM (void) memset(temptoken, 0, sizeof (temptoken));
11183089Swyllys if (kstype == KMF_KEYSTORE_PK11TOKEN) {
11193089Swyllys p = strchr(token_spec, ':');
11203089Swyllys if (p != NULL)
11218132SWyllys.Ingersoll@Sun.COM *p = 0;
11223089Swyllys }
11239126SWyllys.Ingersoll@Sun.COM len = strlen(token_spec);
11249126SWyllys.Ingersoll@Sun.COM if (len > sizeof (temptoken))
11259126SWyllys.Ingersoll@Sun.COM len = sizeof (temptoken);
11269126SWyllys.Ingersoll@Sun.COM
11279126SWyllys.Ingersoll@Sun.COM (void) strncpy(temptoken, token_spec, len);
11288132SWyllys.Ingersoll@Sun.COM
11298132SWyllys.Ingersoll@Sun.COM /*
11308132SWyllys.Ingersoll@Sun.COM * Strip trailing whitespace
11318132SWyllys.Ingersoll@Sun.COM */
11329126SWyllys.Ingersoll@Sun.COM t = temptoken + (len - 1);
11338132SWyllys.Ingersoll@Sun.COM while (isspace(*t) && t >= temptoken) {
11348132SWyllys.Ingersoll@Sun.COM *t = 0x00;
11358132SWyllys.Ingersoll@Sun.COM t--;
11368132SWyllys.Ingersoll@Sun.COM }
11378132SWyllys.Ingersoll@Sun.COM
11383089Swyllys /*
11393089Swyllys * Login to the token first.
11403089Swyllys */
11413089Swyllys (void) snprintf(prompt, sizeof (prompt),
11428132SWyllys.Ingersoll@Sun.COM gettext(DEFAULT_TOKEN_PROMPT), temptoken);
11433089Swyllys
11443089Swyllys if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
11455051Swyllys (ulong_t *)&cred->credlen) != CKR_OK) {
11463089Swyllys cred->cred = NULL;
11473089Swyllys cred->credlen = 0;
11483089Swyllys }
11493089Swyllys
11503089Swyllys if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
11513089Swyllys *p = ':';
11523089Swyllys return (KMF_OK);
11533089Swyllys }
11543089Swyllys
11553089Swyllys KMF_RETURN
verify_file(char * filename)11563089Swyllys verify_file(char *filename)
11573089Swyllys {
11583089Swyllys KMF_RETURN ret = KMF_OK;
11593089Swyllys int fd;
11603089Swyllys
11613089Swyllys /*
11623089Swyllys * Attempt to open with the EXCL flag so that if
11633089Swyllys * it already exists, the open will fail. It will
11643089Swyllys * also fail if the file cannot be created due to
11653089Swyllys * permissions on the parent directory, or if the
11663089Swyllys * parent directory itself does not exist.
11673089Swyllys */
11683089Swyllys fd = open(filename, O_CREAT | O_EXCL, 0600);
1169*12234Swyllys.ingersoll@sun.com if (fd == -1) {
1170*12234Swyllys.ingersoll@sun.com if (errno == EEXIST)
1171*12234Swyllys.ingersoll@sun.com return (KMF_ERR_OPEN_FILE);
1172*12234Swyllys.ingersoll@sun.com else
1173*12234Swyllys.ingersoll@sun.com return (KMF_ERR_WRITE_FILE);
1174*12234Swyllys.ingersoll@sun.com }
11753089Swyllys
11763089Swyllys /* If we were able to create it, delete it. */
11773089Swyllys (void) close(fd);
11783089Swyllys (void) unlink(filename);
11793089Swyllys
11803089Swyllys return (ret);
11813089Swyllys }
11823089Swyllys
11833089Swyllys void
display_error(void * handle,KMF_RETURN errcode,char * prefix)11843089Swyllys display_error(void *handle, KMF_RETURN errcode, char *prefix)
11853089Swyllys {
11863089Swyllys KMF_RETURN rv1, rv2;
11873089Swyllys char *plugin_errmsg = NULL;
11883089Swyllys char *kmf_errmsg = NULL;
11893089Swyllys
11905051Swyllys rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg);
11915051Swyllys rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg);
11923089Swyllys
11933089Swyllys cryptoerror(LOG_STDERR, "%s:", prefix);
11943089Swyllys if (rv1 == KMF_OK && plugin_errmsg) {
11955051Swyllys cryptoerror(LOG_STDERR, gettext("keystore error: %s"),
11965051Swyllys plugin_errmsg);
11975051Swyllys kmf_free_str(plugin_errmsg);
11983089Swyllys }
11993089Swyllys
12003089Swyllys if (rv2 == KMF_OK && kmf_errmsg) {
12015051Swyllys cryptoerror(LOG_STDERR, gettext("libkmf error: %s"),
12025051Swyllys kmf_errmsg);
12035051Swyllys kmf_free_str(kmf_errmsg);
12043089Swyllys }
12053089Swyllys
12063089Swyllys if (rv1 != KMF_OK && rv2 != KMF_OK)
12073089Swyllys cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
12083089Swyllys
12093089Swyllys }
12106051Swyllys
12116051Swyllys static KMF_RETURN
addToEKUList(EKU_LIST * ekus,int critical,KMF_OID * newoid)12126051Swyllys addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid)
12136051Swyllys {
12146051Swyllys if (newoid != NULL && ekus != NULL) {
12156051Swyllys ekus->eku_count++;
12166051Swyllys
12176051Swyllys ekus->critlist = realloc(ekus->critlist,
12186051Swyllys ekus->eku_count * sizeof (int));
12196051Swyllys if (ekus->critlist != NULL)
12206051Swyllys ekus->critlist[ekus->eku_count-1] = critical;
12216051Swyllys else
12226051Swyllys return (KMF_ERR_MEMORY);
12236051Swyllys
12246051Swyllys ekus->ekulist = realloc(
12256051Swyllys ekus->ekulist, ekus->eku_count * sizeof (KMF_OID));
12266051Swyllys if (ekus->ekulist != NULL)
12276051Swyllys ekus->ekulist[ekus->eku_count-1] = *newoid;
12286051Swyllys else
12296051Swyllys return (KMF_ERR_MEMORY);
12306051Swyllys }
12316051Swyllys return (KMF_OK);
12326051Swyllys }
12336051Swyllys
12346051Swyllys void
free_eku_list(EKU_LIST * ekus)12356051Swyllys free_eku_list(EKU_LIST *ekus)
12366051Swyllys {
12376051Swyllys if (ekus != NULL && ekus->eku_count > 0) {
12386051Swyllys int i;
12396051Swyllys for (i = 0; i < ekus->eku_count; i++) {
12406051Swyllys kmf_free_data(&ekus->ekulist[i]);
12416051Swyllys }
12426051Swyllys free(ekus->ekulist);
12436051Swyllys free(ekus->critlist);
124410818Swyllys.ingersoll@sun.com free(ekus);
12456051Swyllys }
12466051Swyllys }
12476051Swyllys
12486051Swyllys static KMF_RETURN
parse_ekus(char * ekustr,EKU_LIST * ekus)12496051Swyllys parse_ekus(char *ekustr, EKU_LIST *ekus)
12506051Swyllys {
12516051Swyllys KMF_RETURN rv = KMF_OK;
12526051Swyllys KMF_OID *newoid;
12536051Swyllys int critical;
12546051Swyllys
12556051Swyllys if (strncasecmp(ekustr, "critical:",
12566051Swyllys strlen("critical:")) == 0) {
12576051Swyllys critical = TRUE;
12586051Swyllys ekustr += strlen("critical:");
12596051Swyllys } else {
12606051Swyllys critical = FALSE;
12616051Swyllys }
12626051Swyllys newoid = kmf_ekuname_to_oid(ekustr);
12636051Swyllys if (newoid != NULL) {
12646051Swyllys rv = addToEKUList(ekus, critical, newoid);
12656051Swyllys free(newoid);
12666051Swyllys } else {
12676051Swyllys rv = PK_ERR_USAGE;
12686051Swyllys }
12696051Swyllys
12706051Swyllys return (rv);
12716051Swyllys }
12726051Swyllys
12736051Swyllys KMF_RETURN
verify_ekunames(char * ekuliststr,EKU_LIST ** ekulist)12746051Swyllys verify_ekunames(char *ekuliststr, EKU_LIST **ekulist)
12756051Swyllys {
12766051Swyllys KMF_RETURN rv = KMF_OK;
12776051Swyllys char *p;
12786051Swyllys EKU_LIST *ekus = NULL;
12796051Swyllys
12806051Swyllys if (ekuliststr == NULL || strlen(ekuliststr) == 0)
12816051Swyllys return (0);
12826051Swyllys
128310818Swyllys.ingersoll@sun.com ekus = calloc(sizeof (EKU_LIST), 1);
128410818Swyllys.ingersoll@sun.com if (ekus == NULL)
128510818Swyllys.ingersoll@sun.com return (KMF_ERR_MEMORY);
128610818Swyllys.ingersoll@sun.com
12876051Swyllys /*
12886051Swyllys * The list should be comma separated list of EKU Names.
12896051Swyllys */
12906051Swyllys p = strtok(ekuliststr, ",");
12916051Swyllys
12926051Swyllys /* If no tokens found, then maybe it's just a single EKU value */
12936051Swyllys if (p == NULL) {
12946051Swyllys rv = parse_ekus(ekuliststr, ekus);
12956051Swyllys }
12966051Swyllys
12976051Swyllys while (p != NULL) {
12986051Swyllys rv = parse_ekus(p, ekus);
12996051Swyllys
13006051Swyllys if (rv != KMF_OK)
13016051Swyllys break;
13026051Swyllys p = strtok(NULL, ",");
13036051Swyllys }
13046051Swyllys
13056051Swyllys if (rv != KMF_OK)
13066051Swyllys free_eku_list(ekus);
13076051Swyllys else
13086051Swyllys *ekulist = ekus;
13096051Swyllys
13106051Swyllys return (rv);
13116051Swyllys }
13126354Swyllys
13136354Swyllys KMF_RETURN
token_auth_needed(KMF_HANDLE_T handle,char * tokenlabel,int * auth)13146354Swyllys token_auth_needed(KMF_HANDLE_T handle, char *tokenlabel, int *auth)
13156354Swyllys {
13166354Swyllys CK_TOKEN_INFO info;
13176354Swyllys CK_SLOT_ID slot;
13186354Swyllys CK_RV ckrv;
13196354Swyllys KMF_RETURN rv;
13206354Swyllys
13216354Swyllys *auth = 0;
13226354Swyllys rv = kmf_pk11_token_lookup(handle, tokenlabel, &slot);
13236354Swyllys if (rv != KMF_OK)
13246354Swyllys return (rv);
13256354Swyllys
13266354Swyllys ckrv = C_GetTokenInfo(slot, &info);
13276354Swyllys if (ckrv != KMF_OK)
13286354Swyllys return (KMF_ERR_INTERNAL);
13296354Swyllys
13306354Swyllys *auth = (info.flags & CKF_LOGIN_REQUIRED);
13316354Swyllys
13326354Swyllys return (KMF_OK);
13336354Swyllys }
133411973Swyllys.ingersoll@sun.com
133511973Swyllys.ingersoll@sun.com void
show_ecc_curves()133611973Swyllys.ingersoll@sun.com show_ecc_curves()
133711973Swyllys.ingersoll@sun.com {
133811973Swyllys.ingersoll@sun.com int i;
133911973Swyllys.ingersoll@sun.com
134011973Swyllys.ingersoll@sun.com (void) printf(gettext("Supported ECC curve names:\n"));
134111973Swyllys.ingersoll@sun.com for (i = 0; i < number_of_curves; i++) {
134211973Swyllys.ingersoll@sun.com (void) printf("%s", oid_table[i].name);
134311973Swyllys.ingersoll@sun.com if (i > 0 && ((i+1) % 5) == 0)
134411973Swyllys.ingersoll@sun.com (void) printf("\n");
134511973Swyllys.ingersoll@sun.com else if (i+1 < number_of_curves)
134611973Swyllys.ingersoll@sun.com (void) printf(", ");
134711973Swyllys.ingersoll@sun.com }
134811973Swyllys.ingersoll@sun.com (void) printf("\n");
134911973Swyllys.ingersoll@sun.com }
135011973Swyllys.ingersoll@sun.com
135111973Swyllys.ingersoll@sun.com KMF_OID *
ecc_name_to_oid(char * name)135211973Swyllys.ingersoll@sun.com ecc_name_to_oid(char *name)
135311973Swyllys.ingersoll@sun.com {
135411973Swyllys.ingersoll@sun.com int i;
135511973Swyllys.ingersoll@sun.com for (i = 0; i < number_of_oids; i++) {
135611973Swyllys.ingersoll@sun.com if (strcasecmp(name, oid_table[i].name) == 0)
135711973Swyllys.ingersoll@sun.com return ((KMF_OID *)oid_table[i].oid);
135811973Swyllys.ingersoll@sun.com }
135911973Swyllys.ingersoll@sun.com return (NULL);
136011973Swyllys.ingersoll@sun.com }
1361