1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
22 */
23
24/*
25 * This file contains the functions that are shared among
26 * the various services this tool will ultimately provide.
27 * The functions in this file return PKCS#11 CK_RV errors.
28 * Only one session and one login per token is supported
29 * at this time.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <ctype.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <tzfile.h>
40#include <cryptoutil.h>
41#include <security/cryptoki.h>
42#include <kmfapi.h>
43
44#include "common.h"
45
46/* Local status variables. */
47static boolean_t	initialized = B_FALSE;
48static boolean_t	session_opened = B_FALSE;
49static boolean_t	logged_in = B_FALSE;
50
51/* Supporting structures and global variables for getopt_av(). */
52typedef struct	av_opts_s {
53	int		shortnm;	/* short name character */
54	char		*longnm;	/* long name string, NOT terminated */
55	int		longnm_len;	/* length of long name string */
56	boolean_t	has_arg;	/* takes optional argument */
57} av_opts;
58static av_opts		*opts_av = NULL;
59static const char	*_save_optstr = NULL;
60static int		_save_numopts = 0;
61
62int			optind_av = 1;
63char			*optarg_av = NULL;
64
65static void close_sess(CK_SESSION_HANDLE);
66static void logout_token(CK_SESSION_HANDLE);
67
68struct oid_table_entry {
69	const KMF_OID *oid;
70	char *name;
71};
72
73struct oid_table_entry oid_table[] = {
74	{ &KMFOID_ECC_secp112r1, "secp112r1"},
75	{ &KMFOID_ECC_secp112r2, "secp112r2"},
76	{ &KMFOID_ECC_secp128r1, "secp128r1"},
77	{ &KMFOID_ECC_secp128r2, "secp128r2"},
78	{ &KMFOID_ECC_secp160k1, "secp160k1"},
79	{ &KMFOID_ECC_secp160r1, "secp160r1"},
80	{ &KMFOID_ECC_secp160r2, "secp160r2"},
81	{ &KMFOID_ECC_secp192k1, "secp192k1"},
82	{ &KMFOID_ECC_secp192r1, "secp192r1"},
83	{ &KMFOID_ECC_secp224k1, "secp224k1"},
84	{ &KMFOID_ECC_secp224r1, "secp224r1"},
85	{ &KMFOID_ECC_secp256k1, "secp256k1"},
86	{ &KMFOID_ECC_secp256r1, "secp256r1"},
87	{ &KMFOID_ECC_secp384r1, "secp384r1"},
88	{ &KMFOID_ECC_secp521r1, "secp521r1"},
89	{ &KMFOID_ECC_sect113r1, "sect113r1"},
90	{ &KMFOID_ECC_sect113r2, "sect113r2"},
91	{ &KMFOID_ECC_sect131r1, "sect131r1"},
92	{ &KMFOID_ECC_sect131r2, "sect131r2"},
93	{ &KMFOID_ECC_sect163k1, "sect163k1"},
94	{ &KMFOID_ECC_sect163r1, "sect163r1"},
95	{ &KMFOID_ECC_sect163r2, "sect163r2"},
96	{ &KMFOID_ECC_sect193r1, "sect193r1"},
97	{ &KMFOID_ECC_sect193r2, "sect193r2"},
98	{ &KMFOID_ECC_sect233k1, "sect233k1"},
99	{ &KMFOID_ECC_sect233r1, "sect233r1"},
100	{ &KMFOID_ECC_sect239k1, "sect239k1"},
101	{ &KMFOID_ECC_sect283k1, "sect283k1"},
102	{ &KMFOID_ECC_sect283r1, "sect283r1"},
103	{ &KMFOID_ECC_sect409k1, "sect409k1"},
104	{ &KMFOID_ECC_sect409r1, "sect409r1"},
105	{ &KMFOID_ECC_sect571k1, "sect571k1"},
106	{ &KMFOID_ECC_sect571r1, "sect571r1"},
107	{ &KMFOID_ECC_c2pnb163v1, "c2pnb163v1"},
108	{ &KMFOID_ECC_c2pnb163v2, "c2pnb163v2"},
109	{ &KMFOID_ECC_c2pnb163v3, "c2pnb163v3"},
110	{ &KMFOID_ECC_c2pnb176v1, "c2pnb176v1"},
111	{ &KMFOID_ECC_c2tnb191v1, "c2tnb191v1"},
112	{ &KMFOID_ECC_c2tnb191v2, "c2tnb191v2"},
113	{ &KMFOID_ECC_c2tnb191v3, "c2tnb191v3"},
114	{ &KMFOID_ECC_c2pnb208w1, "c2pnb208w1"},
115	{ &KMFOID_ECC_c2tnb239v1, "c2tnb239v1"},
116	{ &KMFOID_ECC_c2tnb239v2, "c2tnb239v2"},
117	{ &KMFOID_ECC_c2tnb239v3, "c2tnb239v3"},
118	{ &KMFOID_ECC_c2pnb272w1, "c2pnb272w1"},
119	{ &KMFOID_ECC_c2pnb304w1, "c2pnb304w1"},
120	{ &KMFOID_ECC_c2tnb359v1, "c2tnb359v1"},
121	{ &KMFOID_ECC_c2pnb368w1, "c2pnb368w1"},
122	{ &KMFOID_ECC_c2tnb431r1, "c2tnb431r1"},
123	{ &KMFOID_ECC_prime192v2, "prime192v2"},
124	{ &KMFOID_ECC_prime192v3, "prime192v3"},
125	{ &KMFOID_MD5, "md5"},
126	{ &KMFOID_SHA1, "sha1"},
127	{ &KMFOID_SHA256, "sha256"},
128	{ &KMFOID_SHA384, "sha384"},
129	{ &KMFOID_SHA512, "sha512"}
130};
131int number_of_oids = sizeof (oid_table) / sizeof (struct oid_table_entry);
132#define	number_of_curves (number_of_oids - 5)
133
134/*
135 * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
136 * along with setting/resetting state variables.
137 */
138static CK_RV
139init_pkcs11(void)
140{
141	CK_RV		rv = CKR_OK;
142
143	/* If C_Initialize() already called, nothing to do here. */
144	if (initialized == B_TRUE)
145		return (CKR_OK);
146
147	/* Reset state variables because C_Initialize() not yet done. */
148	session_opened = B_FALSE;
149	logged_in = B_FALSE;
150
151	/* Initialize PKCS#11 library. */
152	if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
153	    rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
154		return (rv);
155	}
156
157	initialized = B_TRUE;
158	return (CKR_OK);
159}
160
161/*
162 * Finalize PKCS#11 library and reset state variables.  Open sessions,
163 * if any, are closed, and thereby any logins are logged out also.
164 */
165void
166final_pk11(CK_SESSION_HANDLE sess)
167{
168
169	/* If the library wasn't initialized, nothing to do here. */
170	if (!initialized)
171		return;
172
173	/* Make sure the sesion is closed first. */
174	close_sess(sess);
175
176	(void) C_Finalize(NULL);
177	initialized = B_FALSE;
178}
179
180/*
181 * Close PKCS#11 session and reset state variables.  Any logins are
182 * logged out.
183 */
184static void
185close_sess(CK_SESSION_HANDLE sess)
186{
187
188	if (sess == 0) {
189		return;
190	}
191
192	/* If session is already closed, nothing to do here. */
193	if (!session_opened)
194		return;
195
196	/* Make sure user is logged out of token. */
197	logout_token(sess);
198
199	(void) C_CloseSession(sess);
200	session_opened = B_FALSE;
201}
202
203/*
204 * Log user out of token and reset status variable.
205 */
206static void
207logout_token(CK_SESSION_HANDLE sess)
208{
209
210	if (sess == 0) {
211		return;
212	}
213
214	/* If already logged out, nothing to do here. */
215	if (!logged_in)
216		return;
217
218	(void) C_Logout(sess);
219	logged_in = B_FALSE;
220}
221
222/*
223 * Gets PIN from user.  Caller needs to free the returned PIN when done.
224 * If two prompts are given, the PIN is confirmed with second prompt.
225 * Note that getphassphrase() may return data in static memory area.
226 */
227CK_RV
228get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
229{
230	char *save_phrase, *phrase1, *phrase2;
231
232	/* Prompt user for a PIN. */
233	if (prompt1 == NULL) {
234		return (CKR_ARGUMENTS_BAD);
235	}
236	if ((phrase1 = getpassphrase(prompt1)) == NULL) {
237		return (CKR_FUNCTION_FAILED);
238	}
239
240	/* Duplicate 1st PIN in separate chunk of memory. */
241	if ((save_phrase = strdup(phrase1)) == NULL)
242		return (CKR_HOST_MEMORY);
243
244	/* If second prompt given, PIN confirmation is requested. */
245	if (prompt2 != NULL) {
246		if ((phrase2 = getpassphrase(prompt2)) == NULL) {
247			free(save_phrase);
248			return (CKR_FUNCTION_FAILED);
249		}
250		if (strcmp(save_phrase, phrase2) != 0) {
251			free(save_phrase);
252			return (CKR_PIN_INCORRECT);
253		}
254	}
255
256	*pin = (CK_UTF8CHAR_PTR)save_phrase;
257	*pinlen = strlen(save_phrase);
258	return (CKR_OK);
259}
260
261int
262yn_to_int(char *ynstr)
263{
264	char *y = gettext("yes");
265	char *n = gettext("no");
266	if (ynstr == NULL)
267		return (-1);
268
269	if (strncasecmp(ynstr, y, 1) == 0)
270		return (1);
271	else if (strncasecmp(ynstr, n, 1) == 0)
272		return (0);
273	else
274		return (-1);
275}
276
277/*
278 * Gets yes/no response from user.  If either no prompt is supplied, a
279 * default prompt is used.  If not message for invalid input is supplied,
280 * a default will not be provided.  If the user provides no response,
281 * the input default B_TRUE == yes, B_FALSE == no is returned.
282 * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
283 */
284boolean_t
285yesno(char *prompt, char *invalid, boolean_t dflt)
286{
287	char	*response, buf[1024];
288	int	ans;
289
290	if (prompt == NULL)
291		prompt = gettext("Enter (y)es or (n)o? ");
292
293	for (;;) {
294		/* Prompt user. */
295		(void) printf("%s", prompt);
296		(void) fflush(stdout);
297
298		/* Get the response. */
299		if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
300			break;		/* go to default response */
301
302		/* Skip any leading white space. */
303		while (isspace(*response))
304			response++;
305		if (*response == '\0')
306			break;		/* go to default response */
307
308		ans = yn_to_int(response);
309		if (ans == 1)
310			return (B_TRUE);
311		else if (ans == 0)
312			return (B_FALSE);
313
314		/* Indicate invalid input, and try again. */
315		if (invalid != NULL)
316			(void) printf("%s", invalid);
317	}
318	return (dflt);
319}
320
321/*
322 * Gets the list of slots which have tokens in them.  Keeps adjusting
323 * the size of the slot list buffer until the call is successful or an
324 * irrecoverable error occurs.
325 */
326CK_RV
327get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
328{
329	CK_ULONG	tmp_count = 0;
330	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
331	int		rv = CKR_OK;
332
333	if (!initialized)
334		if ((rv = init_pkcs11()) != CKR_OK)
335			return (rv);
336
337	/*
338	 * Get the slot count first because we don't know how many
339	 * slots there are and how many of those slots even have tokens.
340	 * Don't specify an arbitrary buffer size for the slot list;
341	 * it may be too small (see section 11.5 of PKCS#11 spec).
342	 * Also select only those slots that have tokens in them,
343	 * because this tool has no need to know about empty slots.
344	 */
345	if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
346		return (rv);
347
348	if (tmp_count == 0) {
349		*slot_list = NULL_PTR;
350		*slot_count = 0;
351		return (CKR_OK);
352	}
353
354	/* Allocate initial space for the slot list. */
355	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
356	    sizeof (CK_SLOT_ID))) == NULL)
357		return (CKR_HOST_MEMORY);
358
359	/* Then get the slot list itself. */
360	for (;;) {
361		if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
362			*slot_list = tmp_list;
363			*slot_count = tmp_count;
364			break;
365		}
366
367		if (rv != CKR_BUFFER_TOO_SMALL) {
368			free(tmp_list);
369			break;
370		}
371
372		/* If the number of slots grew, try again. */
373		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
374		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
375			free(tmp_list);
376			rv = CKR_HOST_MEMORY;
377			break;
378		}
379		tmp_list = tmp2_list;
380	}
381
382	return (rv);
383}
384
385/*
386 * Breaks out the getopt-style option string into a structure that can be
387 * traversed later for calls to getopt_av().  Option string is NOT altered,
388 * but the struct fields point to locations within option string.
389 */
390static int
391populate_opts(char *optstring)
392{
393	int		i;
394	av_opts		*temp;
395	char		*marker;
396
397	if (optstring == NULL || *optstring == '\0')
398		return (0);
399
400	/*
401	 * This tries to imitate getopt(3c) Each option must conform to:
402	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
403	 * If long name is missing, the short name is used for long name.
404	 */
405	for (i = 0; *optstring != '\0'; i++) {
406		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
407		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
408			if (opts_av != NULL)
409				free(opts_av);
410			opts_av = NULL;
411			return (0);
412		} else {
413			opts_av = (av_opts *)temp;
414		}
415
416		(void) memset(&opts_av[i], 0, sizeof (av_opts));
417		marker = optstring;		/* may need optstring later */
418
419		opts_av[i].shortnm = *marker++;	/* set short name */
420
421		if (*marker == ':') {		/* check for opt arg */
422			marker++;
423			opts_av[i].has_arg = B_TRUE;
424		}
425
426		if (*marker == '(') {		/* check and set long name */
427			marker++;
428			opts_av[i].longnm = marker;
429			opts_av[i].longnm_len = strcspn(marker, ")");
430			optstring = marker + opts_av[i].longnm_len + 1;
431		} else {
432			/* use short name option character */
433			opts_av[i].longnm = optstring;
434			opts_av[i].longnm_len = 1;
435			optstring = marker;
436		}
437	}
438
439	return (i);
440}
441
442/*
443 * getopt_av() is very similar to getopt(3c) in that the takes an option
444 * string, compares command line arguments for matches, and returns a single
445 * letter option when a match is found.  However, getopt_av() differs from
446 * getopt(3c) by requiring that only longname options and values be found
447 * on the command line and all leading dashes are omitted.  In other words,
448 * it tries to enforce only longname "option=value" arguments on the command
449 * line.  Boolean options are not allowed either.
450 */
451int
452getopt_av(int argc, char * const *argv, const char *optstring)
453{
454	int	i;
455	int	len;
456	char   *cur_option;
457
458	if (optind_av >= argc)
459		return (EOF);
460
461	/* First time or when optstring changes from previous one */
462	if (_save_optstr != optstring) {
463		if (opts_av != NULL)
464			free(opts_av);
465		opts_av = NULL;
466		_save_optstr = optstring;
467		_save_numopts = populate_opts((char *)optstring);
468	}
469
470	for (i = 0; i < _save_numopts; i++) {
471		cur_option = argv[optind_av];
472
473		if (strcmp(cur_option, "--") == 0) {
474			optind_av++;
475			break;
476		}
477
478		if (cur_option[0] == '-' && strlen(cur_option) == 2) {
479			len = 1;
480			cur_option++; /* remove "-" */
481		} else {
482			len = strcspn(cur_option, "=");
483		}
484
485		if (len == opts_av[i].longnm_len && strncmp(cur_option,
486		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
487			/* matched */
488			if (!opts_av[i].has_arg) {
489				optind_av++;
490				return (opts_av[i].shortnm);
491			}
492
493			/* needs optarg */
494			if (cur_option[len] == '=') {
495				optarg_av = &(cur_option[len+1]);
496				optind_av++;
497				return (opts_av[i].shortnm);
498			}
499
500			optarg_av = NULL;
501			optind_av++;
502			return ((int)'?');
503		}
504	}
505
506	return (EOF);
507}
508
509KMF_KEYSTORE_TYPE
510KS2Int(char *keystore_str)
511{
512	if (keystore_str == NULL)
513		return (0);
514	if (strcasecmp(keystore_str, "pkcs11") == 0)
515		return (KMF_KEYSTORE_PK11TOKEN);
516	else if (strcasecmp(keystore_str, "nss") == 0)
517		return (KMF_KEYSTORE_NSS);
518	else if (strcasecmp(keystore_str, "file") == 0)
519		return (KMF_KEYSTORE_OPENSSL);
520	else
521		return (0);
522}
523
524/*
525 * compare_oids
526 * return 1 if equal
527 */
528boolean_t
529compare_oids(KMF_OID *oid1, const KMF_OID *oid2)
530{
531	return ((oid1->Length == oid2->Length) &&
532	    !memcmp(oid1->Data, oid2->Data, oid1->Length));
533}
534
535int
536Str2KeyType(char *algm, KMF_OID *hashoid, KMF_KEY_ALG *ktype,
537    KMF_ALGORITHM_INDEX *sigAlg)
538{
539	if (algm == NULL) {
540		/* Default to SHA1+RSA */
541		*sigAlg = KMF_ALGID_SHA1WithRSA;
542		*ktype = KMF_RSA;
543	} else if (strcasecmp(algm, "DSA") == 0) {
544		if (hashoid == NULL ||
545		    compare_oids(hashoid, &KMFOID_SHA1))
546			*sigAlg = KMF_ALGID_SHA1WithDSA;
547		else if (compare_oids(hashoid, &KMFOID_SHA256))
548			*sigAlg = KMF_ALGID_SHA256WithDSA;
549		else
550			return (-1); /* unsupported hash/key combo */
551		*ktype = KMF_DSA;
552	} else if (strcasecmp(algm, "RSA") == 0) {
553		if (hashoid == NULL ||
554		    compare_oids(hashoid, &KMFOID_SHA1))
555			*sigAlg = KMF_ALGID_SHA1WithRSA;
556		else if (compare_oids(hashoid, &KMFOID_SHA256))
557			*sigAlg = KMF_ALGID_SHA256WithRSA;
558		else if (compare_oids(hashoid, &KMFOID_SHA384))
559			*sigAlg = KMF_ALGID_SHA384WithRSA;
560		else if (compare_oids(hashoid, &KMFOID_SHA512))
561			*sigAlg = KMF_ALGID_SHA512WithRSA;
562		else if (compare_oids(hashoid, &KMFOID_MD5))
563			*sigAlg = KMF_ALGID_MD5WithRSA;
564		else
565			return (-1); /* unsupported hash/key combo */
566		*ktype = KMF_RSA;
567	} else if (strcasecmp(algm, "EC") == 0) {
568		/* EC keys may be used with some SHA2 hashes */
569		if (hashoid == NULL ||
570		    compare_oids(hashoid, &KMFOID_SHA1))
571			*sigAlg = KMF_ALGID_SHA1WithECDSA;
572		else if (compare_oids(hashoid, &KMFOID_SHA256))
573			*sigAlg = KMF_ALGID_SHA256WithECDSA;
574		else if (compare_oids(hashoid, &KMFOID_SHA384))
575			*sigAlg = KMF_ALGID_SHA384WithECDSA;
576		else if (compare_oids(hashoid, &KMFOID_SHA512))
577			*sigAlg = KMF_ALGID_SHA512WithECDSA;
578		else
579			return (-1); /* unsupported hash/key combo */
580
581		*ktype = KMF_ECDSA;
582	} else {
583		return (-1);
584	}
585	return (0);
586}
587
588int
589Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
590{
591	if (algm == NULL)
592		*ktype = KMF_AES;
593	else if (strcasecmp(algm, "aes") == 0)
594		*ktype = KMF_AES;
595	else if (strcasecmp(algm, "arcfour") == 0)
596		*ktype = KMF_RC4;
597	else if (strcasecmp(algm, "des") == 0)
598		*ktype = KMF_DES;
599	else if (strcasecmp(algm, "3des") == 0)
600		*ktype = KMF_DES3;
601	else if (strcasecmp(algm, "generic") == 0)
602		*ktype = KMF_GENERIC_SECRET;
603	else
604		return (-1);
605
606	return (0);
607}
608
609int
610Str2Lifetime(char *ltimestr, uint32_t *ltime)
611{
612	int num;
613	char timetok[6];
614
615	if (ltimestr == NULL || strlen(ltimestr) == 0) {
616		/* default to 1 year lifetime */
617		*ltime = SECSPERDAY * DAYSPERNYEAR;
618		return (0);
619	}
620
621	(void) memset(timetok, 0, sizeof (timetok));
622	if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
623		return (-1);
624
625	if (strcasecmp(timetok, "day") == 0||
626	    strcasecmp(timetok, "days") == 0) {
627		*ltime = num * SECSPERDAY;
628	} else if (strcasecmp(timetok, "hour") == 0||
629	    strcasecmp(timetok, "hours") == 0) {
630		*ltime = num * SECSPERHOUR;
631	} else if (strcasecmp(timetok, "year") == 0 ||
632	    strcasecmp(timetok, "years") == 0) {
633		*ltime = num * SECSPERDAY * DAYSPERNYEAR;
634	} else {
635		*ltime = 0;
636		return (-1);
637	}
638
639	return (0);
640}
641
642int
643OT2Int(char *objclass)
644{
645	char *c = NULL;
646	int retval = 0;
647
648	if (objclass == NULL)
649		return (-1);
650
651	c = strchr(objclass, ':');
652	if (c != NULL) {
653		if (strcasecmp(c, ":private") == 0)
654			retval = PK_PRIVATE_OBJ;
655		else if (strcasecmp(c, ":public") == 0)
656			retval = PK_PUBLIC_OBJ;
657		else if (strcasecmp(c, ":both") == 0)
658			retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
659		else /* unrecognized option */
660			return (-1);
661
662		*c = '\0';
663	}
664
665	if (strcasecmp(objclass, "public") == 0) {
666		if (retval)
667			return (-1);
668		return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ);
669	} else if (strcasecmp(objclass, "private") == 0) {
670		if (retval)
671			return (-1);
672		return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
673	} else if (strcasecmp(objclass, "both") == 0) {
674		if (retval)
675			return (-1);
676		return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
677	} else if (strcasecmp(objclass, "cert") == 0) {
678		return (retval | PK_CERT_OBJ);
679	} else if (strcasecmp(objclass, "key") == 0) {
680		if (retval == 0) /* return all keys */
681			return (retval | PK_KEY_OBJ);
682		else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
683			/* return all keys */
684			return (retval | PK_KEY_OBJ);
685		else if (retval & PK_PUBLIC_OBJ)
686			/* Only return public keys */
687			return (retval | PK_PUBKEY_OBJ);
688		else if (retval & PK_PRIVATE_OBJ)
689			/* Only return private keys */
690			return (retval | PK_PRIKEY_OBJ);
691	} else if (strcasecmp(objclass, "crl") == 0) {
692		if (retval)
693			return (-1);
694		return (retval | PK_CRL_OBJ);
695	}
696
697	if (retval == 0) /* No matches found */
698		retval = -1;
699	return (retval);
700}
701
702KMF_ENCODE_FORMAT
703Str2Format(char *formstr)
704{
705	if (formstr == NULL || strcasecmp(formstr, "der") == 0)
706		return (KMF_FORMAT_ASN1);
707	if (strcasecmp(formstr, "pem") == 0)
708		return (KMF_FORMAT_PEM);
709	if (strcasecmp(formstr, "pkcs12") == 0)
710		return (KMF_FORMAT_PKCS12);
711	if (strcasecmp(formstr, "raw") == 0)
712		return (KMF_FORMAT_RAWKEY);
713
714	return (KMF_FORMAT_UNDEF);
715}
716
717KMF_RETURN
718select_token(void *kmfhandle, char *token, int readonly)
719{
720	KMF_ATTRIBUTE attlist[10];
721	int i = 0;
722	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
723	KMF_RETURN rv = KMF_OK;
724
725	if (token == NULL)
726		return (KMF_ERR_BAD_PARAMETER);
727
728	kmf_set_attr_at_index(attlist, i,
729	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
730	    sizeof (kstype));
731	i++;
732
733	if (token) {
734		kmf_set_attr_at_index(attlist, i,
735		    KMF_TOKEN_LABEL_ATTR, token,
736		    strlen(token));
737		i++;
738	}
739
740	kmf_set_attr_at_index(attlist, i,
741	    KMF_READONLY_ATTR, &readonly,
742	    sizeof (readonly));
743	i++;
744
745	rv = kmf_configure_keystore(kmfhandle, i, attlist);
746	if (rv == KMF_ERR_TOKEN_SELECTED)
747		rv = KMF_OK;
748	return (rv);
749}
750
751KMF_RETURN
752configure_nss(void *kmfhandle, char *dir, char *prefix)
753{
754	KMF_ATTRIBUTE attlist[10];
755	int i = 0;
756	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
757	KMF_RETURN rv = KMF_OK;
758
759	kmf_set_attr_at_index(attlist, i,
760	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
761	    sizeof (kstype));
762	i++;
763
764	if (dir) {
765		kmf_set_attr_at_index(attlist, i,
766		    KMF_DIRPATH_ATTR, dir,
767		    strlen(dir));
768		i++;
769	}
770
771	if (prefix) {
772		kmf_set_attr_at_index(attlist, i,
773		    KMF_CERTPREFIX_ATTR, prefix,
774		    strlen(prefix));
775		i++;
776
777		kmf_set_attr_at_index(attlist, i,
778		    KMF_KEYPREFIX_ATTR, prefix,
779		    strlen(prefix));
780		i++;
781	}
782
783	rv = kmf_configure_keystore(kmfhandle, i, attlist);
784	if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
785		rv = KMF_OK;
786
787	return (rv);
788}
789
790KMF_RETURN
791get_pk12_password(KMF_CREDENTIAL *cred)
792{
793	KMF_RETURN rv = KMF_OK;
794	char prompt[1024];
795
796	/*
797	 * Get the password to use for the PK12 encryption.
798	 */
799	(void) strlcpy(prompt,
800	    gettext("Enter password to use for "
801	    "accessing the PKCS12 file: "), sizeof (prompt));
802
803	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
804	    (ulong_t *)&cred->credlen) != CKR_OK) {
805		cred->cred = NULL;
806		cred->credlen = 0;
807	}
808
809	return (rv);
810}
811
812#define	FILENAME_PROMPT gettext("Filename:")
813#define	FILENAME_MINLEN	1
814#define	FILENAME_MAXLEN MAXPATHLEN
815
816#define	COUNTRY_PROMPT	gettext("Country Name (2 letter code) [US]:")
817#define	STATE_PROMPT	gettext("State or Province Name (full name) " \
818	"[Some-State]:")
819#define	LOCALITY_PROMPT	gettext("Locality Name (eg, city) []:")
820#define	ORG_PROMPT	gettext("Organization Name (eg, company) []:")
821#define	UNIT_PROMPT	gettext("Organizational Unit Name (eg, section) []:")
822#define	NAME_PROMPT	gettext("Common Name (eg, YOUR name) []:")
823#define	EMAIL_PROMPT	gettext("Email Address []:")
824
825#define	SERNO_PROMPT	gettext("Serial Number (hex value, example: " \
826	"0x01020304):")
827#define	SERNO_MINLEN	3
828#define	SERNO_MAXLEN	42
829
830#define	LABEL_PROMPT	gettext("Enter a label for the certificate:")
831#define	LABEL_MINLEN	1
832#define	LABEL_MAXLEN	1024
833
834#define	COUNTRY_DEFAULT "US"
835#define	STATE_DEFAULT	NULL
836#define	INVALID_INPUT	gettext("Invalid input; please re-enter ...")
837
838#define	SUBNAMESIZ	1024
839#define	RDN_MIN		1
840#define	RDN_MAX		64
841#define	COUNTRYNAME_MIN	2
842#define	COUNTRYNAME_MAX	2
843
844static char *
845get_input_string(char *prompt, char *default_str, int min_len, int max_len)
846{
847	char buf[1024];
848	char *response = NULL;
849	char *ret = NULL;
850	int len;
851
852	for (;;) {
853		(void) printf("\t%s", prompt);
854		(void) fflush(stdout);
855
856		response = fgets(buf, sizeof (buf), stdin);
857		if (response == NULL) {
858			if (default_str != NULL) {
859				ret = strdup(default_str);
860			}
861			break;
862		}
863
864		/* Skip any leading white space. */
865		while (isspace(*response))
866			response++;
867		if (*response == '\0') {
868			if (default_str != NULL) {
869				ret = strdup(default_str);
870			}
871			break;
872		}
873
874		len = strlen(response);
875		response[len-1] = '\0'; /* get rid of "LF" */
876		len--;
877		if (len >= min_len && len <= max_len) {
878			ret = strdup(response);
879			break;
880		}
881
882		(void) printf("%s\n", INVALID_INPUT);
883
884	}
885
886	return (ret);
887}
888
889int
890get_filename(char *txt, char **result)
891{
892	char prompt[1024];
893	char *fname = NULL;
894
895	(void) snprintf(prompt, sizeof (prompt),
896	    gettext("Enter filename for the %s: "),
897	    txt);
898	fname = get_input_string(prompt, NULL,
899	    FILENAME_MINLEN, FILENAME_MAXLEN);
900	*result = fname;
901	return (0);
902}
903
904int
905get_certlabel(char **result)
906{
907	char *label = NULL;
908
909	label = get_input_string(LABEL_PROMPT, NULL,
910	    LABEL_MINLEN, LABEL_MAXLEN);
911	*result = label;
912	return (0);
913}
914
915int
916get_serial(char **result)
917{
918	char *serial = NULL;
919
920	serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN,
921	    SERNO_MAXLEN);
922
923	*result = serial;
924	return (0);
925}
926
927int
928get_subname(char **result)
929{
930	char *country = NULL;
931	char *state = NULL;
932	char *locality = NULL;
933	char *org = NULL;
934	char *unit = NULL;
935	char *name = NULL;
936	char *email = NULL;
937	char *subname = NULL;
938
939	(void) printf("Entering following fields for subject (a DN) ...\n");
940	country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
941	    COUNTRYNAME_MIN, COUNTRYNAME_MAX);
942	if (country == NULL)
943		return (-1);
944
945	state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
946	    RDN_MIN, RDN_MAX);
947
948	locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
949	org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
950	unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
951	name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
952	email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
953
954	/* Now create a subject name from the input strings */
955	if ((subname = malloc(SUBNAMESIZ)) == NULL)
956		goto out;
957
958	(void) memset(subname, 0, SUBNAMESIZ);
959	(void) strlcpy(subname, "C=", SUBNAMESIZ);
960	(void) strlcat(subname, country, SUBNAMESIZ);
961	if (state != NULL) {
962		(void) strlcat(subname, ", ST=", SUBNAMESIZ);
963		(void) strlcat(subname, state, SUBNAMESIZ);
964	}
965
966	if (locality != NULL) {
967		(void) strlcat(subname, ", L=", SUBNAMESIZ);
968		(void) strlcat(subname, locality, SUBNAMESIZ);
969	}
970
971	if (org != NULL) {
972		(void) strlcat(subname, ", O=", SUBNAMESIZ);
973		(void) strlcat(subname, org, SUBNAMESIZ);
974	}
975
976	if (unit != NULL) {
977		(void) strlcat(subname, ", OU=", SUBNAMESIZ);
978		(void) strlcat(subname, unit, SUBNAMESIZ);
979	}
980
981	if (name != NULL) {
982		(void) strlcat(subname, ", CN=", SUBNAMESIZ);
983		(void) strlcat(subname, name, SUBNAMESIZ);
984	}
985
986	if (email != NULL) {
987		(void) strlcat(subname, ", E=", SUBNAMESIZ);
988		(void) strlcat(subname, email, SUBNAMESIZ);
989	}
990
991out:
992	if (country)
993		free(country);
994	if (state)
995		free(state);
996	if (locality)
997		free(locality);
998	if (org)
999		free(org);
1000	if (unit)
1001		free(unit);
1002	if (name)
1003		free(name);
1004	if (email)
1005		free(email);
1006
1007	if (subname == NULL)
1008		return (-1);
1009	else {
1010		*result = subname;
1011		return (0);
1012	}
1013}
1014
1015/*
1016 * Parse a string of KeyUsage values and convert
1017 * them to the correct KU Bits.
1018 * The field may be marked "critical" by prepending
1019 * "critical:" to the list.
1020 * EX:  critical:digitialSignature,keyEncipherment
1021 */
1022KMF_RETURN
1023verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
1024{
1025	KMF_RETURN ret = KMF_OK;
1026	uint16_t kuval;
1027	char *k;
1028
1029	*kubits = 0;
1030	if (kustr == NULL || strlen(kustr) == 0)
1031		return (KMF_ERR_BAD_PARAMETER);
1032
1033	/* Check to see if this is critical */
1034	if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) {
1035		*critical = TRUE;
1036		kustr += strlen("critical:");
1037	} else {
1038		*critical = FALSE;
1039	}
1040
1041	k = strtok(kustr, ",");
1042	while (k != NULL) {
1043		kuval = kmf_string_to_ku(k);
1044		if (kuval == 0) {
1045			*kubits = 0;
1046			return (KMF_ERR_BAD_PARAMETER);
1047		}
1048		*kubits |= kuval;
1049		k = strtok(NULL, ",");
1050	}
1051
1052	return (ret);
1053}
1054
1055/*
1056 * Verify the alternate subject label is real or invalid.
1057 *
1058 * The field may be marked "critical" by prepending
1059 * "critical:" to the list.
1060 * EX:  "critical:IP=1.2.3.4"
1061 */
1062KMF_RETURN
1063verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
1064{
1065	char *p;
1066	KMF_RETURN rv = KMF_OK;
1067
1068	/* Check to see if this is critical */
1069	if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) {
1070		*critical = TRUE;
1071		arg += strlen("critical:");
1072	} else {
1073		*critical = FALSE;
1074	}
1075
1076	/* Make sure there is an "=" sign */
1077	p = strchr(arg, '=');
1078	if (p == NULL)
1079		return (KMF_ERR_BAD_PARAMETER);
1080
1081	p[0] = '\0';
1082
1083	if (strcmp(arg, "IP") == 0)
1084		*type = GENNAME_IPADDRESS;
1085	else if (strcmp(arg, "DNS") == 0)
1086		*type = GENNAME_DNSNAME;
1087	else if (strcmp(arg, "EMAIL") == 0)
1088		*type = GENNAME_RFC822NAME;
1089	else if (strcmp(arg, "URI") == 0)
1090		*type = GENNAME_URI;
1091	else if (strcmp(arg, "DN") == 0)
1092		*type = GENNAME_DIRECTORYNAME;
1093	else if (strcmp(arg, "RID") == 0)
1094		*type = GENNAME_REGISTEREDID;
1095	else if (strcmp(arg, "KRB") == 0)
1096		*type = GENNAME_KRB5PRINC;
1097	else if (strcmp(arg, "UPN") == 0)
1098		*type = GENNAME_SCLOGON_UPN;
1099	else
1100		rv = KMF_ERR_BAD_PARAMETER;
1101
1102	p[0] = '=';
1103
1104	return (rv);
1105}
1106
1107int
1108get_token_password(KMF_KEYSTORE_TYPE kstype,
1109	char *token_spec, KMF_CREDENTIAL *cred)
1110{
1111	char	prompt[1024];
1112	char	temptoken[32];
1113	char	*p = NULL;
1114	char	*t = NULL;
1115	int	len;
1116
1117	(void) memset(temptoken, 0, sizeof (temptoken));
1118	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
1119		p = strchr(token_spec, ':');
1120		if (p != NULL)
1121			*p = 0;
1122	}
1123	len = strlen(token_spec);
1124	if (len > sizeof (temptoken))
1125		len = sizeof (temptoken);
1126
1127	(void) strncpy(temptoken, token_spec, len);
1128
1129	/*
1130	 * Strip trailing whitespace
1131	 */
1132	t = temptoken + (len - 1);
1133	while (isspace(*t) && t >= temptoken) {
1134		*t = 0x00;
1135		t--;
1136	}
1137
1138	/*
1139	 * Login to the token first.
1140	 */
1141	(void) snprintf(prompt, sizeof (prompt),
1142	    gettext(DEFAULT_TOKEN_PROMPT), temptoken);
1143
1144	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
1145	    (ulong_t *)&cred->credlen) != CKR_OK) {
1146		cred->cred = NULL;
1147		cred->credlen = 0;
1148	}
1149
1150	if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
1151		*p = ':';
1152	return (KMF_OK);
1153}
1154
1155KMF_RETURN
1156verify_file(char *filename)
1157{
1158	KMF_RETURN ret = KMF_OK;
1159	int fd;
1160
1161	/*
1162	 * Attempt to open with  the EXCL flag so that if
1163	 * it already exists, the open will fail.  It will
1164	 * also fail if the file cannot be created due to
1165	 * permissions on the parent directory, or if the
1166	 * parent directory itself does not exist.
1167	 */
1168	fd = open(filename, O_CREAT | O_EXCL, 0600);
1169	if (fd == -1) {
1170		if (errno == EEXIST)
1171			return (KMF_ERR_OPEN_FILE);
1172		else
1173			return (KMF_ERR_WRITE_FILE);
1174	}
1175
1176	/* If we were able to create it, delete it. */
1177	(void) close(fd);
1178	(void) unlink(filename);
1179
1180	return (ret);
1181}
1182
1183void
1184display_error(void *handle, KMF_RETURN errcode, char *prefix)
1185{
1186	KMF_RETURN rv1, rv2;
1187	char *plugin_errmsg = NULL;
1188	char *kmf_errmsg = NULL;
1189
1190	rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg);
1191	rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg);
1192
1193	cryptoerror(LOG_STDERR, "%s:", prefix);
1194	if (rv1 == KMF_OK && plugin_errmsg) {
1195		cryptoerror(LOG_STDERR, gettext("keystore error: %s"),
1196		    plugin_errmsg);
1197		kmf_free_str(plugin_errmsg);
1198	}
1199
1200	if (rv2 == KMF_OK && kmf_errmsg) {
1201		cryptoerror(LOG_STDERR, gettext("libkmf error: %s"),
1202		    kmf_errmsg);
1203		kmf_free_str(kmf_errmsg);
1204	}
1205
1206	if (rv1 != KMF_OK && rv2 != KMF_OK)
1207		cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
1208
1209}
1210
1211static KMF_RETURN
1212addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid)
1213{
1214	if (newoid != NULL && ekus != NULL) {
1215		ekus->eku_count++;
1216
1217		ekus->critlist = realloc(ekus->critlist,
1218		    ekus->eku_count * sizeof (int));
1219		if (ekus->critlist != NULL)
1220			ekus->critlist[ekus->eku_count-1] = critical;
1221		else
1222			return (KMF_ERR_MEMORY);
1223
1224		ekus->ekulist = realloc(
1225		    ekus->ekulist, ekus->eku_count * sizeof (KMF_OID));
1226		if (ekus->ekulist != NULL)
1227			ekus->ekulist[ekus->eku_count-1] = *newoid;
1228		else
1229			return (KMF_ERR_MEMORY);
1230	}
1231	return (KMF_OK);
1232}
1233
1234void
1235free_eku_list(EKU_LIST *ekus)
1236{
1237	if (ekus != NULL && ekus->eku_count > 0) {
1238		int i;
1239		for (i = 0; i < ekus->eku_count; i++) {
1240			kmf_free_data(&ekus->ekulist[i]);
1241		}
1242		free(ekus->ekulist);
1243		free(ekus->critlist);
1244		free(ekus);
1245	}
1246}
1247
1248static KMF_RETURN
1249parse_ekus(char *ekustr, EKU_LIST *ekus)
1250{
1251	KMF_RETURN rv = KMF_OK;
1252	KMF_OID *newoid;
1253	int critical;
1254
1255	if (strncasecmp(ekustr, "critical:",
1256	    strlen("critical:")) == 0) {
1257		critical = TRUE;
1258		ekustr += strlen("critical:");
1259	} else {
1260		critical = FALSE;
1261	}
1262	newoid = kmf_ekuname_to_oid(ekustr);
1263	if (newoid != NULL) {
1264		rv = addToEKUList(ekus, critical, newoid);
1265		free(newoid);
1266	} else {
1267		rv = PK_ERR_USAGE;
1268	}
1269
1270	return (rv);
1271}
1272
1273KMF_RETURN
1274verify_ekunames(char *ekuliststr, EKU_LIST **ekulist)
1275{
1276	KMF_RETURN rv = KMF_OK;
1277	char *p;
1278	EKU_LIST *ekus = NULL;
1279
1280	if (ekuliststr == NULL || strlen(ekuliststr) == 0)
1281		return (0);
1282
1283	ekus = calloc(sizeof (EKU_LIST), 1);
1284	if (ekus == NULL)
1285		return (KMF_ERR_MEMORY);
1286
1287	/*
1288	 * The list should be comma separated list of EKU Names.
1289	 */
1290	p = strtok(ekuliststr, ",");
1291
1292	/* If no tokens found, then maybe it's just a single EKU value */
1293	if (p == NULL) {
1294		rv = parse_ekus(ekuliststr, ekus);
1295	}
1296
1297	while (p != NULL) {
1298		rv = parse_ekus(p, ekus);
1299
1300		if (rv != KMF_OK)
1301			break;
1302		p = strtok(NULL, ",");
1303	}
1304
1305	if (rv != KMF_OK)
1306		free_eku_list(ekus);
1307	else
1308		*ekulist = ekus;
1309
1310	return (rv);
1311}
1312
1313KMF_RETURN
1314token_auth_needed(KMF_HANDLE_T handle, char *tokenlabel, int *auth)
1315{
1316	CK_TOKEN_INFO info;
1317	CK_SLOT_ID slot;
1318	CK_RV ckrv;
1319	KMF_RETURN rv;
1320
1321	*auth = 0;
1322	rv = kmf_pk11_token_lookup(handle, tokenlabel, &slot);
1323	if (rv != KMF_OK)
1324		return (rv);
1325
1326	ckrv = C_GetTokenInfo(slot, &info);
1327	if (ckrv != KMF_OK)
1328		return (KMF_ERR_INTERNAL);
1329
1330	*auth = (info.flags & CKF_LOGIN_REQUIRED);
1331
1332	return (KMF_OK);
1333}
1334
1335void
1336show_ecc_curves()
1337{
1338	int i;
1339
1340	(void) printf(gettext("Supported ECC curve names:\n"));
1341	for (i = 0; i < number_of_curves; i++) {
1342		(void) printf("%s", oid_table[i].name);
1343		if (i > 0 && ((i+1) % 5) == 0)
1344			(void) printf("\n");
1345		else if (i+1 < number_of_curves)
1346			(void) printf(", ");
1347	}
1348	(void) printf("\n");
1349}
1350
1351KMF_OID *
1352ecc_name_to_oid(char *name)
1353{
1354	int i;
1355	for (i = 0; i < number_of_oids; i++) {
1356		if (strcasecmp(name, oid_table[i].name) == 0)
1357			return ((KMF_OID *)oid_table[i].oid);
1358	}
1359	return (NULL);
1360}
1361