common.c revision 3089:8ddeb2ace8aa
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/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * This file contains the functions that are shared among
30 * the various services this tool will ultimately provide.
31 * The functions in this file return PKCS#11 CK_RV errors.
32 * Only one session and one login per token is supported
33 * at this time.
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <ctype.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <fcntl.h>
43#include <tzfile.h>
44#include <cryptoutil.h>
45#include <security/cryptoki.h>
46#include <kmfapi.h>
47
48#include "common.h"
49
50/* Local status variables. */
51static boolean_t	initialized = B_FALSE;
52static boolean_t	session_opened = B_FALSE;
53static boolean_t	logged_in = B_FALSE;
54
55/* Supporting structures and global variables for getopt_av(). */
56typedef struct	av_opts_s {
57	int		shortnm;	/* short name character */
58	char		*longnm;	/* long name string, NOT terminated */
59	int		longnm_len;	/* length of long name string */
60	boolean_t	has_arg;	/* takes optional argument */
61} av_opts;
62static av_opts		*opts_av = NULL;
63static const char	*_save_optstr = NULL;
64static int		_save_numopts = 0;
65
66int			optind_av = 1;
67char			*optarg_av = NULL;
68
69static void close_sess(CK_SESSION_HANDLE);
70static void logout_token(CK_SESSION_HANDLE);
71
72/*
73 * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
74 * along with setting/resetting state variables.
75 */
76CK_RV
77init_pk11(void)
78{
79	CK_RV		rv = CKR_OK;
80
81	/* If C_Initialize() already called, nothing to do here. */
82	if (initialized == B_TRUE)
83		return (CKR_OK);
84
85	/* Reset state variables because C_Initialize() not yet done. */
86	session_opened = B_FALSE;
87	logged_in = B_FALSE;
88
89	/* Initialize PKCS#11 library. */
90	if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
91	    rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
92		return (rv);
93	}
94
95	initialized = B_TRUE;
96	return (CKR_OK);
97}
98
99/*
100 * Finalize PKCS#11 library and reset state variables.  Open sessions,
101 * if any, are closed, and thereby any logins are logged out also.
102 */
103void
104final_pk11(CK_SESSION_HANDLE sess)
105{
106
107	/* If the library wasn't initialized, nothing to do here. */
108	if (!initialized)
109		return;
110
111	/* Make sure the sesion is closed first. */
112	close_sess(sess);
113
114	(void) C_Finalize(NULL);
115	initialized = B_FALSE;
116}
117
118/*
119 * Close PKCS#11 session and reset state variables.  Any logins are
120 * logged out.
121 */
122static void
123close_sess(CK_SESSION_HANDLE sess)
124{
125
126	if (sess == NULL) {
127		return;
128	}
129
130	/* If session is already closed, nothing to do here. */
131	if (!session_opened)
132		return;
133
134	/* Make sure user is logged out of token. */
135	logout_token(sess);
136
137	(void) C_CloseSession(sess);
138	session_opened = B_FALSE;
139}
140
141/*
142 * Log user out of token and reset status variable.
143 */
144static void
145logout_token(CK_SESSION_HANDLE sess)
146{
147
148	if (sess == NULL) {
149		return;
150	}
151
152	/* If already logged out, nothing to do here. */
153	if (!logged_in)
154		return;
155
156	(void) C_Logout(sess);
157	logged_in = B_FALSE;
158}
159
160/*
161 * Gets PIN from user.  Caller needs to free the returned PIN when done.
162 * If two prompts are given, the PIN is confirmed with second prompt.
163 * Note that getphassphrase() may return data in static memory area.
164 */
165CK_RV
166get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
167{
168	char		*save_phrase, *phrase1, *phrase2;
169
170
171#ifdef DEBUG
172	if (getenv("TOKENPIN") != NULL) {
173		*pin = (CK_UTF8CHAR_PTR)strdup(getenv("TOKENPIN"));
174		*pinlen = strlen((char *)(*pin));
175		return (CKR_OK);
176	}
177#endif /* DEBUG */
178
179	/* Prompt user for a PIN. */
180	if (prompt1 == NULL) {
181		return (CKR_ARGUMENTS_BAD);
182	}
183	if ((phrase1 = getpassphrase(prompt1)) == NULL) {
184		return (CKR_FUNCTION_FAILED);
185	}
186
187	/* Duplicate 1st PIN in separate chunk of memory. */
188	if ((save_phrase = strdup(phrase1)) == NULL)
189		return (CKR_HOST_MEMORY);
190
191	/* If second prompt given, PIN confirmation is requested. */
192	if (prompt2 != NULL) {
193		if ((phrase2 = getpassphrase(prompt2)) == NULL) {
194			free(save_phrase);
195			return (CKR_FUNCTION_FAILED);
196		}
197		if (strcmp(save_phrase, phrase2) != 0) {
198			free(save_phrase);
199			return (CKR_PIN_INCORRECT);
200		}
201	}
202
203	*pin = (CK_UTF8CHAR_PTR)save_phrase;
204	*pinlen = strlen(save_phrase);
205	return (CKR_OK);
206}
207
208/*
209 * Gets yes/no response from user.  If either no prompt is supplied, a
210 * default prompt is used.  If not message for invalid input is supplied,
211 * a default will not be provided.  If the user provides no response,
212 * the input default B_TRUE == yes, B_FALSE == no is returned.
213 * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
214 */
215boolean_t
216yesno(char *prompt, char *invalid, boolean_t dflt)
217{
218	char		*response, buf[1024];
219	char		*yes = gettext("yes");
220	char		*no = gettext("no");
221
222
223#ifdef DEBUG
224	/* If debugging or testing, return TRUE and avoid prompting */
225	if (getenv("TOKENPIN") != NULL) {
226		return (B_TRUE);
227	}
228#endif /* DEBUG */
229
230	if (prompt == NULL)
231		prompt = gettext("Enter (y)es or (n)o? ");
232
233	for (;;) {
234		/* Prompt user. */
235		(void) printf("%s", prompt);
236		(void) fflush(stdout);
237
238		/* Get the response. */
239		if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
240			break;		/* go to default response */
241
242		/* Skip any leading white space. */
243		while (isspace(*response))
244			response++;
245		if (*response == '\0')
246			break;		/* go to default response */
247
248		/* Is it valid input?  Return appropriately. */
249		if (strncasecmp(response, yes, 1) == 0)
250			return (B_TRUE);
251		if (strncasecmp(response, no, 1) == 0)
252			return (B_FALSE);
253
254		/* Indicate invalid input, and try again. */
255		if (invalid != NULL)
256		    (void) printf("%s", invalid);
257	}
258	return (dflt);
259}
260
261/*
262 * Gets the list of slots which have tokens in them.  Keeps adjusting
263 * the size of the slot list buffer until the call is successful or an
264 * irrecoverable error occurs.
265 */
266CK_RV
267get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
268{
269	CK_ULONG	tmp_count = 0;
270	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
271	int		rv = CKR_OK;
272
273	if (!initialized)
274		if ((rv = init_pk11()) != CKR_OK)
275			return (rv);
276
277	/*
278	 * Get the slot count first because we don't know how many
279	 * slots there are and how many of those slots even have tokens.
280	 * Don't specify an arbitrary buffer size for the slot list;
281	 * it may be too small (see section 11.5 of PKCS#11 spec).
282	 * Also select only those slots that have tokens in them,
283	 * because this tool has no need to know about empty slots.
284	 */
285	if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
286		return (rv);
287
288	if (tmp_count == 0) {
289		*slot_list = NULL_PTR;
290		*slot_count = 0;
291		return (CKR_OK);
292	}
293
294	/* Allocate initial space for the slot list. */
295	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
296	    sizeof (CK_SLOT_ID))) == NULL)
297		return (CKR_HOST_MEMORY);
298
299	/* Then get the slot list itself. */
300	for (;;) {
301		if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
302			*slot_list = tmp_list;
303			*slot_count = tmp_count;
304			break;
305		}
306
307		if (rv != CKR_BUFFER_TOO_SMALL) {
308			free(tmp_list);
309			break;
310		}
311
312		/* If the number of slots grew, try again. */
313		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
314		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
315			free(tmp_list);
316			rv = CKR_HOST_MEMORY;
317			break;
318		}
319		tmp_list = tmp2_list;
320	}
321
322	return (rv);
323}
324
325/*
326 * Breaks out the getopt-style option string into a structure that can be
327 * traversed later for calls to getopt_av().  Option string is NOT altered,
328 * but the struct fields point to locations within option string.
329 */
330static int
331populate_opts(char *optstring)
332{
333	int		i;
334	av_opts		*temp;
335	char		*marker;
336
337	if (optstring == NULL || *optstring == '\0')
338		return (0);
339
340	/*
341	 * This tries to imitate getopt(3c) Each option must conform to:
342	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
343	 * If long name is missing, the short name is used for long name.
344	 */
345	for (i = 0; *optstring != '\0'; i++) {
346		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
347		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
348			if (opts_av != NULL)
349				free(opts_av);
350			opts_av = NULL;
351			return (0);
352		} else {
353			opts_av = (av_opts *)temp;
354		}
355
356		(void) memset(&opts_av[i], 0, sizeof (av_opts));
357		marker = optstring;		/* may need optstring later */
358
359		opts_av[i].shortnm = *marker++;	/* set short name */
360
361		if (*marker == ':') {		/* check for opt arg */
362			marker++;
363			opts_av[i].has_arg = B_TRUE;
364		}
365
366		if (*marker == '(') {		/* check and set long name */
367			marker++;
368			opts_av[i].longnm = marker;
369			opts_av[i].longnm_len = strcspn(marker, ")");
370			optstring = marker + opts_av[i].longnm_len + 1;
371		} else {
372			/* use short name option character */
373			opts_av[i].longnm = optstring;
374			opts_av[i].longnm_len = 1;
375			optstring = marker;
376		}
377	}
378
379	return (i);
380}
381
382/*
383 * getopt_av() is very similar to getopt(3c) in that the takes an option
384 * string, compares command line arguments for matches, and returns a single
385 * letter option when a match is found.  However, getopt_av() differs from
386 * getopt(3c) by requiring that only longname options and values be found
387 * on the command line and all leading dashes are omitted.  In other words,
388 * it tries to enforce only longname "option=value" arguments on the command
389 * line.  Boolean options are not allowed either.
390 */
391int
392getopt_av(int argc, char * const *argv, const char *optstring)
393{
394	int	i;
395	int	len;
396	char   *cur_option;
397
398	if (optind_av >= argc)
399		return (EOF);
400
401	/* First time or when optstring changes from previous one */
402	if (_save_optstr != optstring) {
403		if (opts_av != NULL)
404		    free(opts_av);
405		opts_av = NULL;
406		_save_optstr = optstring;
407		_save_numopts = populate_opts((char *)optstring);
408	}
409
410	for (i = 0; i < _save_numopts; i++) {
411		cur_option = argv[optind_av];
412
413		if (strcmp(cur_option, "--") == 0) {
414			optind_av++;
415			break;
416		}
417
418		if (cur_option[0] == '-' && strlen(cur_option) == 2) {
419			len = 1;
420			cur_option++; /* remove "-" */
421		} else {
422			len = strcspn(cur_option, "=");
423		}
424
425		if (len == opts_av[i].longnm_len && strncmp(cur_option,
426		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
427			/* matched */
428			if (!opts_av[i].has_arg) {
429				optind_av++;
430				return (opts_av[i].shortnm);
431			}
432
433			/* needs optarg */
434			if (cur_option[len] == '=') {
435				optarg_av = &(cur_option[len+1]);
436				optind_av++;
437				return (opts_av[i].shortnm);
438			}
439
440			optarg_av = NULL;
441			optind_av++;
442			return ((int)'?');
443		}
444	}
445
446	return (EOF);
447}
448
449KMF_KEYSTORE_TYPE
450KS2Int(char *keystore_str)
451{
452	if (keystore_str == NULL)
453		return (0);
454	if (!strcasecmp(keystore_str, "pkcs11"))
455		return (KMF_KEYSTORE_PK11TOKEN);
456	else if (!strcasecmp(keystore_str, "nss"))
457		return (KMF_KEYSTORE_NSS);
458	else if (!strcasecmp(keystore_str, "file"))
459		return (KMF_KEYSTORE_OPENSSL);
460	else
461		return (0);
462}
463
464
465int
466Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg)
467{
468	if (algm == NULL) {
469		*sigAlg = KMF_ALGID_MD5WithRSA;
470		*ktype = KMF_RSA;
471	} else if (strcasecmp(algm, "DSA") == 0) {
472		*sigAlg = KMF_ALGID_SHA1WithDSA;
473		*ktype = KMF_DSA;
474	} else if (strcasecmp(algm, "RSA") == 0) {
475		*sigAlg = KMF_ALGID_MD5WithRSA;
476		*ktype = KMF_RSA;
477	} else {
478		return (-1);
479	}
480	return (0);
481}
482
483int
484Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
485{
486	if (algm == NULL)
487		*ktype = KMF_AES;
488	else if (strcasecmp(algm, "aes") == 0)
489		*ktype = KMF_AES;
490	else if (strcasecmp(algm, "arcfour") == 0)
491		*ktype = KMF_RC4;
492	else if (strcasecmp(algm, "des") == 0)
493		*ktype = KMF_DES;
494	else if (strcasecmp(algm, "3des") == 0)
495		*ktype = KMF_DES3;
496	else
497		return (-1);
498
499	return (0);
500}
501
502int
503Str2Lifetime(char *ltimestr, uint32_t *ltime)
504{
505	int num;
506	char timetok[6];
507
508	if (ltimestr == NULL || !strlen(ltimestr)) {
509		/* default to 1 year lifetime */
510		*ltime = SECSPERDAY * DAYSPERNYEAR;
511		return (0);
512	}
513
514	(void) memset(timetok, 0, sizeof (timetok));
515	if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
516		return (-1);
517
518	if (!strcasecmp(timetok, "day") ||
519	    !strcasecmp(timetok, "days")) {
520		*ltime = num * SECSPERDAY;
521	} else if (!strcasecmp(timetok, "hour") ||
522		!strcasecmp(timetok, "hours")) {
523		*ltime = num * SECSPERHOUR;
524	} else if (!strcasecmp(timetok, "year") ||
525		!strcasecmp(timetok, "years")) {
526		*ltime = num * SECSPERDAY * DAYSPERNYEAR;
527	} else {
528		*ltime = 0;
529		return (-1);
530	}
531
532	return (0);
533}
534
535int
536OT2Int(char *objclass)
537{
538	char *c = NULL;
539	int retval = 0;
540
541	if (objclass == NULL)
542		return (-1);
543
544	c = strchr(objclass, ':');
545	if (c != NULL) {
546		if (!strcasecmp(c, ":private"))
547			retval = PK_PRIVATE_OBJ;
548		else if (!strcasecmp(c, ":public"))
549			retval = PK_PUBLIC_OBJ;
550		else if (!strcasecmp(c, ":both"))
551			retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
552		else /* unrecognized option */
553			return (-1);
554
555		*c = '\0';
556	}
557
558	if (!strcasecmp(objclass, "public")) {
559		if (retval)
560			return (-1);
561		return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ |
562			PK_PUBKEY_OBJ);
563	} else if (!strcasecmp(objclass, "private")) {
564		if (retval)
565			return (-1);
566		return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
567	} else if (!strcasecmp(objclass, "both")) {
568		if (retval)
569			return (-1);
570		return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
571	} else if (!strcasecmp(objclass, "cert")) {
572		return (retval | PK_CERT_OBJ);
573	} else if (!strcasecmp(objclass, "key")) {
574		if (retval == 0) /* return all keys */
575			return (retval | PK_KEY_OBJ);
576		else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
577			/* return all keys */
578			return (retval | PK_KEY_OBJ);
579		else if (retval & PK_PUBLIC_OBJ)
580			/* Only return public keys */
581			return (retval | PK_PUBKEY_OBJ);
582		else if (retval & PK_PRIVATE_OBJ)
583			/* Only return private keys */
584			return (retval | PK_PRIKEY_OBJ);
585	} else if (!strcasecmp(objclass, "crl")) {
586		if (retval)
587			return (-1);
588		return (retval | PK_CRL_OBJ);
589	}
590
591	if (retval == 0) /* No matches found */
592		retval = -1;
593	return (retval);
594}
595
596KMF_ENCODE_FORMAT
597Str2Format(char *formstr)
598{
599	if (formstr == NULL || !strcasecmp(formstr, "der"))
600		return (KMF_FORMAT_ASN1);
601	if (!strcasecmp(formstr, "pem"))
602		return (KMF_FORMAT_PEM);
603	if (!strcasecmp(formstr, "pkcs12"))
604		return (KMF_FORMAT_PKCS12);
605
606	return (KMF_FORMAT_UNDEF);
607}
608
609
610KMF_RETURN
611select_token(void *kmfhandle, char *token,
612	int readonly)
613{
614	KMF_RETURN rv = KMF_OK;
615	KMF_CONFIG_PARAMS  config;
616
617	if (token == NULL)
618		return (KMF_ERR_BAD_PARAMETER);
619
620	(void) memset(&config, 0, sizeof (config));
621	config.kstype = KMF_KEYSTORE_PK11TOKEN;
622	config.pkcs11config.label = token;
623	config.pkcs11config.readonly = readonly;
624
625	rv = KMF_ConfigureKeystore(kmfhandle, &config);
626	if (rv == KMF_ERR_TOKEN_SELECTED)
627		rv = KMF_OK;
628	return (rv);
629}
630
631
632KMF_RETURN
633configure_nss(void *kmfhandle, char *dir, char *prefix)
634{
635	KMF_RETURN rv = KMF_OK;
636	KMF_CONFIG_PARAMS  config;
637
638	(void) memset(&config, 0, sizeof (config));
639	config.kstype = KMF_KEYSTORE_NSS;
640	config.nssconfig.configdir = dir;
641	config.nssconfig.certPrefix = prefix;
642	config.nssconfig.keyPrefix = prefix;
643	config.nssconfig.secModName = NULL;
644
645	rv = KMF_ConfigureKeystore(kmfhandle, &config);
646	if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
647		rv = KMF_OK;
648
649	return (rv);
650}
651
652
653KMF_RETURN
654get_pk12_password(KMF_CREDENTIAL *cred)
655{
656	KMF_RETURN rv = KMF_OK;
657	char prompt[1024];
658
659	/*
660	 * Get the password to use for the PK12 encryption.
661	 */
662	(void) strlcpy(prompt,
663		gettext("Enter password to use for "
664			"accessing the PKCS12 file: "),
665		sizeof (prompt));
666
667	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
668		(ulong_t *)&cred->credlen) != CKR_OK) {
669		cred->cred = NULL;
670		cred->credlen = 0;
671	}
672
673	return (rv);
674}
675
676
677#define	COUNTRY_PROMPT	"Country Name (2 letter code) [US]:"
678#define	STATE_PROMPT	"State or Province Name (full name) [Some-State]:"
679#define	LOCALITY_PROMPT	"Locality Name (eg, city) []:"
680#define	ORG_PROMPT	"Organization Name (eg, company) []:"
681#define	UNIT_PROMPT	"Organizational Unit Name (eg, section) []:"
682#define	NAME_PROMPT	"Common Name (eg, YOUR name) []:"
683#define	EMAIL_PROMPT	"Email Address []:"
684
685#define	COUNTRY_DEFAULT "US"
686#define	STATE_DEFAULT	"Some-State"
687#define	INVALID_INPUT 	"Invalid input; please re-enter ..."
688
689#define	SUBNAMESIZ	1024
690#define	RDN_MIN		1
691#define	RDN_MAX		64
692#define	COUNTRYNAME_MIN	2
693#define	COUNTRYNAME_MAX	2
694
695static char *
696get_input_string(char *prompt, char *default_str, int min_len, int max_len)
697{
698	char buf[1024];
699	char *response = NULL;
700	char *ret = NULL;
701	int len;
702
703	for (;;) {
704		(void) printf("\t%s", prompt);
705		(void) fflush(stdout);
706
707		response = fgets(buf, sizeof (buf), stdin);
708		if (response == NULL) {
709			if (default_str != NULL) {
710				ret = strdup(default_str);
711			}
712			break;
713		}
714
715		/* Skip any leading white space. */
716		while (isspace(*response))
717			response++;
718		if (*response == '\0') {
719			if (default_str != NULL) {
720				ret = strdup(default_str);
721			}
722			break;
723		}
724
725		len = strlen(response);
726		response[len-1] = '\0'; /* get rid of "LF" */
727		len--;
728		if (len >= min_len && len <= max_len) {
729			ret = strdup(response);
730			break;
731		}
732
733		(void) printf("%s\n", INVALID_INPUT);
734
735	}
736
737	return (ret);
738}
739
740int
741get_subname(char **result)
742{
743	char *country = NULL;
744	char *state = NULL;
745	char *locality = NULL;
746	char *org = NULL;
747	char *unit = NULL;
748	char *name = NULL;
749	char *email = NULL;
750	char *subname = NULL;
751
752	(void) printf("Entering following fields for subject (a DN) ...\n");
753	country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
754	    COUNTRYNAME_MIN, COUNTRYNAME_MAX);
755	if (country == NULL)
756		return (-1);
757
758	state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
759	    RDN_MIN, RDN_MAX);
760	if (state == NULL) {
761		goto out;
762	}
763
764	locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
765	org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
766	unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
767	name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
768	email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
769
770	/* Now create a subject name from the input strings */
771	if ((subname = malloc(SUBNAMESIZ)) == NULL)
772		goto out;
773
774	(void) memset(subname, 0, SUBNAMESIZ);
775	(void) strlcpy(subname, "C=", SUBNAMESIZ);
776	(void) strlcat(subname, country, SUBNAMESIZ);
777	(void) strlcat(subname, ", ", SUBNAMESIZ);
778	(void) strlcat(subname, "ST=", SUBNAMESIZ);
779	(void) strlcat(subname, state, SUBNAMESIZ);
780
781	if (locality) {
782		(void) strlcat(subname, ", ", SUBNAMESIZ);
783		(void) strlcat(subname, "L=", SUBNAMESIZ);
784		(void) strlcat(subname, locality, SUBNAMESIZ);
785	}
786
787	if (org) {
788		(void) strlcat(subname, ", ", SUBNAMESIZ);
789		(void) strlcat(subname, "O=", SUBNAMESIZ);
790		(void) strlcat(subname, org, SUBNAMESIZ);
791	}
792
793	if (unit) {
794		(void) strlcat(subname, ", ", SUBNAMESIZ);
795		(void) strlcat(subname, "OU=", SUBNAMESIZ);
796		(void) strlcat(subname, unit, SUBNAMESIZ);
797	}
798
799	if (name) {
800		(void) strlcat(subname, ", ", SUBNAMESIZ);
801		(void) strlcat(subname, "CN=", SUBNAMESIZ);
802		(void) strlcat(subname, name, SUBNAMESIZ);
803	}
804
805	if (email) {
806		(void) strlcat(subname, ", ", SUBNAMESIZ);
807		(void) strlcat(subname, "E=", SUBNAMESIZ);
808		(void) strlcat(subname, email, SUBNAMESIZ);
809	}
810
811out:
812	if (country)
813		free(country);
814	if (state)
815		free(state);
816	if (locality)
817		free(locality);
818	if (org)
819		free(org);
820	if (unit)
821		free(unit);
822	if (name)
823		free(name);
824	if (email)
825		free(email);
826
827	if (subname == NULL)
828		return (-1);
829	else {
830		*result = subname;
831		return (0);
832	}
833}
834
835/*
836 * Parse a string of KeyUsage values and convert
837 * them to the correct KU Bits.
838 * The field may be marked "critical" by prepending
839 * "critical:" to the list.
840 * EX:  critical:digitialSignature,keyEncipherment
841 */
842KMF_RETURN
843verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
844{
845	KMF_RETURN ret = KMF_OK;
846	uint16_t kuval;
847	char *k;
848
849	*kubits = 0;
850	if (kustr == NULL || !strlen(kustr))
851		return (KMF_ERR_BAD_PARAMETER);
852
853	/* Check to see if this is critical */
854	if (!strncasecmp(kustr, "critical:", strlen("critical:"))) {
855		*critical = TRUE;
856		kustr += strlen("critical:");
857	} else {
858		*critical = FALSE;
859	}
860
861	k = strtok(kustr, ",");
862	while (k != NULL) {
863		kuval = KMF_StringToKeyUsage(k);
864		if (kuval == 0) {
865			*kubits = 0;
866			return (KMF_ERR_BAD_PARAMETER);
867		}
868		*kubits |= kuval;
869		k = strtok(NULL, ",");
870	}
871
872	return (ret);
873}
874
875/*
876 * Verify the alternate subject label is real or invalid.
877 *
878 * The field may be marked "critical" by prepending
879 * "critical:" to the list.
880 * EX:  "critical:IP=1.2.3.4"
881 */
882KMF_RETURN
883verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
884{
885	char *p;
886	KMF_RETURN rv = KMF_OK;
887
888	/* Check to see if this is critical */
889	if (!strncasecmp(arg, "critical:", strlen("critical:"))) {
890		*critical = TRUE;
891		arg += strlen("critical:");
892	} else {
893		*critical = FALSE;
894	}
895
896	/* Make sure there is an "=" sign */
897	p = strchr(arg, '=');
898	if (p == NULL)
899		return (KMF_ERR_BAD_PARAMETER);
900
901	p[0] = '\0';
902
903	if (strcmp(arg, "IP") == 0)
904		*type = GENNAME_IPADDRESS;
905	else if (strcmp(arg, "DNS") == 0)
906		*type = GENNAME_DNSNAME;
907	else if (strcmp(arg, "EMAIL") == 0)
908		*type = GENNAME_RFC822NAME;
909	else if (strcmp(arg, "URI") == 0)
910		*type = GENNAME_URI;
911	else if (strcmp(arg, "DN") == 0)
912		*type = GENNAME_DIRECTORYNAME;
913	else if (strcmp(arg, "RID") == 0)
914		*type = GENNAME_REGISTEREDID;
915	else
916		rv = KMF_ERR_BAD_PARAMETER;
917
918	p[0] = '=';
919
920	return (rv);
921}
922
923int
924get_token_password(KMF_KEYSTORE_TYPE kstype,
925	char *token_spec, KMF_CREDENTIAL *cred)
926{
927	char	prompt[1024];
928	char	*p = NULL;
929
930	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
931		p = strchr(token_spec, ':');
932		if (p != NULL)
933		*p = 0;
934	}
935	/*
936	 * Login to the token first.
937	 */
938	(void) snprintf(prompt, sizeof (prompt),
939		gettext(DEFAULT_TOKEN_PROMPT),
940		token_spec);
941
942	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
943		(ulong_t *)&cred->credlen) != CKR_OK) {
944		cred->cred = NULL;
945		cred->credlen = 0;
946	}
947
948	if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
949		*p = ':';
950	return (KMF_OK);
951}
952
953KMF_RETURN
954verify_file(char *filename)
955{
956	KMF_RETURN ret = KMF_OK;
957	int fd;
958
959	/*
960	 * Attempt to open with  the EXCL flag so that if
961	 * it already exists, the open will fail.  It will
962	 * also fail if the file cannot be created due to
963	 * permissions on the parent directory, or if the
964	 * parent directory itself does not exist.
965	 */
966	fd = open(filename, O_CREAT | O_EXCL, 0600);
967	if (fd == -1)
968		return (KMF_ERR_OPEN_FILE);
969
970	/* If we were able to create it, delete it. */
971	(void) close(fd);
972	(void) unlink(filename);
973
974	return (ret);
975}
976
977void
978display_error(void *handle, KMF_RETURN errcode, char *prefix)
979{
980	KMF_RETURN rv1, rv2;
981	char *plugin_errmsg = NULL;
982	char *kmf_errmsg = NULL;
983
984	rv1 = KMF_GetPluginErrorString(handle, &plugin_errmsg);
985	rv2 = KMF_GetKMFErrorString(errcode, &kmf_errmsg);
986
987	cryptoerror(LOG_STDERR, "%s:", prefix);
988	if (rv1 == KMF_OK && plugin_errmsg) {
989		cryptoerror(LOG_STDERR,
990			gettext("keystore error: %s"),
991			plugin_errmsg);
992		KMF_FreeString(plugin_errmsg);
993	}
994
995	if (rv2 == KMF_OK && kmf_errmsg) {
996		cryptoerror(LOG_STDERR,
997			gettext("libkmf error: %s"),
998			kmf_errmsg);
999		KMF_FreeString(kmf_errmsg);
1000	}
1001
1002	if (rv1 != KMF_OK && rv2 != KMF_OK)
1003		cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
1004
1005}
1006