common.c revision 5051:cbbb7c8b40a9
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 2007 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 if (strcasecmp(algm, "generic") == 0)
497		*ktype = KMF_GENERIC_SECRET;
498	else
499		return (-1);
500
501	return (0);
502}
503
504int
505Str2Lifetime(char *ltimestr, uint32_t *ltime)
506{
507	int num;
508	char timetok[6];
509
510	if (ltimestr == NULL || !strlen(ltimestr)) {
511		/* default to 1 year lifetime */
512		*ltime = SECSPERDAY * DAYSPERNYEAR;
513		return (0);
514	}
515
516	(void) memset(timetok, 0, sizeof (timetok));
517	if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
518		return (-1);
519
520	if (!strcasecmp(timetok, "day") ||
521	    !strcasecmp(timetok, "days")) {
522		*ltime = num * SECSPERDAY;
523	} else if (!strcasecmp(timetok, "hour") ||
524	    !strcasecmp(timetok, "hours")) {
525		*ltime = num * SECSPERHOUR;
526	} else if (!strcasecmp(timetok, "year") ||
527	    !strcasecmp(timetok, "years")) {
528		*ltime = num * SECSPERDAY * DAYSPERNYEAR;
529	} else {
530		*ltime = 0;
531		return (-1);
532	}
533
534	return (0);
535}
536
537int
538OT2Int(char *objclass)
539{
540	char *c = NULL;
541	int retval = 0;
542
543	if (objclass == NULL)
544		return (-1);
545
546	c = strchr(objclass, ':');
547	if (c != NULL) {
548		if (!strcasecmp(c, ":private"))
549			retval = PK_PRIVATE_OBJ;
550		else if (!strcasecmp(c, ":public"))
551			retval = PK_PUBLIC_OBJ;
552		else if (!strcasecmp(c, ":both"))
553			retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
554		else /* unrecognized option */
555			return (-1);
556
557		*c = '\0';
558	}
559
560	if (!strcasecmp(objclass, "public")) {
561		if (retval)
562			return (-1);
563		return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ);
564	} else if (!strcasecmp(objclass, "private")) {
565		if (retval)
566			return (-1);
567		return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
568	} else if (!strcasecmp(objclass, "both")) {
569		if (retval)
570			return (-1);
571		return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
572	} else if (!strcasecmp(objclass, "cert")) {
573		return (retval | PK_CERT_OBJ);
574	} else if (!strcasecmp(objclass, "key")) {
575		if (retval == 0) /* return all keys */
576			return (retval | PK_KEY_OBJ);
577		else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
578			/* return all keys */
579			return (retval | PK_KEY_OBJ);
580		else if (retval & PK_PUBLIC_OBJ)
581			/* Only return public keys */
582			return (retval | PK_PUBKEY_OBJ);
583		else if (retval & PK_PRIVATE_OBJ)
584			/* Only return private keys */
585			return (retval | PK_PRIKEY_OBJ);
586	} else if (!strcasecmp(objclass, "crl")) {
587		if (retval)
588			return (-1);
589		return (retval | PK_CRL_OBJ);
590	}
591
592	if (retval == 0) /* No matches found */
593		retval = -1;
594	return (retval);
595}
596
597KMF_ENCODE_FORMAT
598Str2Format(char *formstr)
599{
600	if (formstr == NULL || !strcasecmp(formstr, "der"))
601		return (KMF_FORMAT_ASN1);
602	if (!strcasecmp(formstr, "pem"))
603		return (KMF_FORMAT_PEM);
604	if (!strcasecmp(formstr, "pkcs12"))
605		return (KMF_FORMAT_PKCS12);
606	if (!strcasecmp(formstr, "raw"))
607		return (KMF_FORMAT_RAWKEY);
608
609	return (KMF_FORMAT_UNDEF);
610}
611
612
613KMF_RETURN
614select_token(void *kmfhandle, char *token,
615	int readonly)
616{
617	KMF_ATTRIBUTE attlist[10];
618	int i = 0;
619	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
620	KMF_RETURN rv = KMF_OK;
621
622	if (token == NULL)
623		return (KMF_ERR_BAD_PARAMETER);
624
625	kmf_set_attr_at_index(attlist, i,
626	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
627	    sizeof (kstype));
628	i++;
629
630	if (token) {
631		kmf_set_attr_at_index(attlist, i,
632		    KMF_TOKEN_LABEL_ATTR, token,
633		    strlen(token));
634		i++;
635	}
636
637	kmf_set_attr_at_index(attlist, i,
638	    KMF_READONLY_ATTR, &readonly,
639	    sizeof (readonly));
640	i++;
641
642	rv = kmf_configure_keystore(kmfhandle, i, attlist);
643	if (rv == KMF_ERR_TOKEN_SELECTED)
644		rv = KMF_OK;
645	return (rv);
646}
647
648
649KMF_RETURN
650configure_nss(void *kmfhandle, char *dir, char *prefix)
651{
652
653	KMF_ATTRIBUTE attlist[10];
654	int i = 0;
655	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
656	KMF_RETURN rv = KMF_OK;
657
658	kmf_set_attr_at_index(attlist, i,
659	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
660	    sizeof (kstype));
661	i++;
662
663	if (dir) {
664		kmf_set_attr_at_index(attlist, i,
665		    KMF_DIRPATH_ATTR, dir,
666		    strlen(dir));
667		i++;
668	}
669
670	if (prefix) {
671		kmf_set_attr_at_index(attlist, i,
672		    KMF_CERTPREFIX_ATTR, prefix,
673		    strlen(prefix));
674		i++;
675
676		kmf_set_attr_at_index(attlist, i,
677		    KMF_KEYPREFIX_ATTR, prefix,
678		    strlen(prefix));
679		i++;
680	}
681
682	rv = kmf_configure_keystore(kmfhandle, i, attlist);
683	if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
684		rv = KMF_OK;
685
686	return (rv);
687}
688
689
690KMF_RETURN
691get_pk12_password(KMF_CREDENTIAL *cred)
692{
693	KMF_RETURN rv = KMF_OK;
694	char prompt[1024];
695
696	/*
697	 * Get the password to use for the PK12 encryption.
698	 */
699	(void) strlcpy(prompt,
700	    gettext("Enter password to use for "
701	    "accessing the PKCS12 file: "), sizeof (prompt));
702
703	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
704	    (ulong_t *)&cred->credlen) != CKR_OK) {
705		cred->cred = NULL;
706		cred->credlen = 0;
707	}
708
709	return (rv);
710}
711
712
713#define	COUNTRY_PROMPT	"Country Name (2 letter code) [US]:"
714#define	STATE_PROMPT	"State or Province Name (full name) [Some-State]:"
715#define	LOCALITY_PROMPT	"Locality Name (eg, city) []:"
716#define	ORG_PROMPT	"Organization Name (eg, company) []:"
717#define	UNIT_PROMPT	"Organizational Unit Name (eg, section) []:"
718#define	NAME_PROMPT	"Common Name (eg, YOUR name) []:"
719#define	EMAIL_PROMPT	"Email Address []:"
720
721#define	COUNTRY_DEFAULT "US"
722#define	STATE_DEFAULT	"Some-State"
723#define	INVALID_INPUT 	"Invalid input; please re-enter ..."
724
725#define	SUBNAMESIZ	1024
726#define	RDN_MIN		1
727#define	RDN_MAX		64
728#define	COUNTRYNAME_MIN	2
729#define	COUNTRYNAME_MAX	2
730
731static char *
732get_input_string(char *prompt, char *default_str, int min_len, int max_len)
733{
734	char buf[1024];
735	char *response = NULL;
736	char *ret = NULL;
737	int len;
738
739	for (;;) {
740		(void) printf("\t%s", prompt);
741		(void) fflush(stdout);
742
743		response = fgets(buf, sizeof (buf), stdin);
744		if (response == NULL) {
745			if (default_str != NULL) {
746				ret = strdup(default_str);
747			}
748			break;
749		}
750
751		/* Skip any leading white space. */
752		while (isspace(*response))
753			response++;
754		if (*response == '\0') {
755			if (default_str != NULL) {
756				ret = strdup(default_str);
757			}
758			break;
759		}
760
761		len = strlen(response);
762		response[len-1] = '\0'; /* get rid of "LF" */
763		len--;
764		if (len >= min_len && len <= max_len) {
765			ret = strdup(response);
766			break;
767		}
768
769		(void) printf("%s\n", INVALID_INPUT);
770
771	}
772
773	return (ret);
774}
775
776int
777get_subname(char **result)
778{
779	char *country = NULL;
780	char *state = NULL;
781	char *locality = NULL;
782	char *org = NULL;
783	char *unit = NULL;
784	char *name = NULL;
785	char *email = NULL;
786	char *subname = NULL;
787
788	(void) printf("Entering following fields for subject (a DN) ...\n");
789	country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
790	    COUNTRYNAME_MIN, COUNTRYNAME_MAX);
791	if (country == NULL)
792		return (-1);
793
794	state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
795	    RDN_MIN, RDN_MAX);
796	if (state == NULL) {
797		goto out;
798	}
799
800	locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
801	org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
802	unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
803	name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
804	email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
805
806	/* Now create a subject name from the input strings */
807	if ((subname = malloc(SUBNAMESIZ)) == NULL)
808		goto out;
809
810	(void) memset(subname, 0, SUBNAMESIZ);
811	(void) strlcpy(subname, "C=", SUBNAMESIZ);
812	(void) strlcat(subname, country, SUBNAMESIZ);
813	(void) strlcat(subname, ", ", SUBNAMESIZ);
814	(void) strlcat(subname, "ST=", SUBNAMESIZ);
815	(void) strlcat(subname, state, SUBNAMESIZ);
816
817	if (locality) {
818		(void) strlcat(subname, ", ", SUBNAMESIZ);
819		(void) strlcat(subname, "L=", SUBNAMESIZ);
820		(void) strlcat(subname, locality, SUBNAMESIZ);
821	}
822
823	if (org) {
824		(void) strlcat(subname, ", ", SUBNAMESIZ);
825		(void) strlcat(subname, "O=", SUBNAMESIZ);
826		(void) strlcat(subname, org, SUBNAMESIZ);
827	}
828
829	if (unit) {
830		(void) strlcat(subname, ", ", SUBNAMESIZ);
831		(void) strlcat(subname, "OU=", SUBNAMESIZ);
832		(void) strlcat(subname, unit, SUBNAMESIZ);
833	}
834
835	if (name) {
836		(void) strlcat(subname, ", ", SUBNAMESIZ);
837		(void) strlcat(subname, "CN=", SUBNAMESIZ);
838		(void) strlcat(subname, name, SUBNAMESIZ);
839	}
840
841	if (email) {
842		(void) strlcat(subname, ", ", SUBNAMESIZ);
843		(void) strlcat(subname, "E=", SUBNAMESIZ);
844		(void) strlcat(subname, email, SUBNAMESIZ);
845	}
846
847out:
848	if (country)
849		free(country);
850	if (state)
851		free(state);
852	if (locality)
853		free(locality);
854	if (org)
855		free(org);
856	if (unit)
857		free(unit);
858	if (name)
859		free(name);
860	if (email)
861		free(email);
862
863	if (subname == NULL)
864		return (-1);
865	else {
866		*result = subname;
867		return (0);
868	}
869}
870
871/*
872 * Parse a string of KeyUsage values and convert
873 * them to the correct KU Bits.
874 * The field may be marked "critical" by prepending
875 * "critical:" to the list.
876 * EX:  critical:digitialSignature,keyEncipherment
877 */
878KMF_RETURN
879verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
880{
881	KMF_RETURN ret = KMF_OK;
882	uint16_t kuval;
883	char *k;
884
885	*kubits = 0;
886	if (kustr == NULL || !strlen(kustr))
887		return (KMF_ERR_BAD_PARAMETER);
888
889	/* Check to see if this is critical */
890	if (!strncasecmp(kustr, "critical:", strlen("critical:"))) {
891		*critical = TRUE;
892		kustr += strlen("critical:");
893	} else {
894		*critical = FALSE;
895	}
896
897	k = strtok(kustr, ",");
898	while (k != NULL) {
899		kuval = kmf_string_to_ku(k);
900		if (kuval == 0) {
901			*kubits = 0;
902			return (KMF_ERR_BAD_PARAMETER);
903		}
904		*kubits |= kuval;
905		k = strtok(NULL, ",");
906	}
907
908	return (ret);
909}
910
911/*
912 * Verify the alternate subject label is real or invalid.
913 *
914 * The field may be marked "critical" by prepending
915 * "critical:" to the list.
916 * EX:  "critical:IP=1.2.3.4"
917 */
918KMF_RETURN
919verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
920{
921	char *p;
922	KMF_RETURN rv = KMF_OK;
923
924	/* Check to see if this is critical */
925	if (!strncasecmp(arg, "critical:", strlen("critical:"))) {
926		*critical = TRUE;
927		arg += strlen("critical:");
928	} else {
929		*critical = FALSE;
930	}
931
932	/* Make sure there is an "=" sign */
933	p = strchr(arg, '=');
934	if (p == NULL)
935		return (KMF_ERR_BAD_PARAMETER);
936
937	p[0] = '\0';
938
939	if (strcmp(arg, "IP") == 0)
940		*type = GENNAME_IPADDRESS;
941	else if (strcmp(arg, "DNS") == 0)
942		*type = GENNAME_DNSNAME;
943	else if (strcmp(arg, "EMAIL") == 0)
944		*type = GENNAME_RFC822NAME;
945	else if (strcmp(arg, "URI") == 0)
946		*type = GENNAME_URI;
947	else if (strcmp(arg, "DN") == 0)
948		*type = GENNAME_DIRECTORYNAME;
949	else if (strcmp(arg, "RID") == 0)
950		*type = GENNAME_REGISTEREDID;
951	else
952		rv = KMF_ERR_BAD_PARAMETER;
953
954	p[0] = '=';
955
956	return (rv);
957}
958
959int
960get_token_password(KMF_KEYSTORE_TYPE kstype,
961	char *token_spec, KMF_CREDENTIAL *cred)
962{
963	char	prompt[1024];
964	char	*p = NULL;
965
966	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
967		p = strchr(token_spec, ':');
968		if (p != NULL)
969		*p = 0;
970	}
971	/*
972	 * Login to the token first.
973	 */
974	(void) snprintf(prompt, sizeof (prompt),
975	    gettext(DEFAULT_TOKEN_PROMPT), token_spec);
976
977	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
978	    (ulong_t *)&cred->credlen) != CKR_OK) {
979		cred->cred = NULL;
980		cred->credlen = 0;
981	}
982
983	if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
984		*p = ':';
985	return (KMF_OK);
986}
987
988KMF_RETURN
989verify_file(char *filename)
990{
991	KMF_RETURN ret = KMF_OK;
992	int fd;
993
994	/*
995	 * Attempt to open with  the EXCL flag so that if
996	 * it already exists, the open will fail.  It will
997	 * also fail if the file cannot be created due to
998	 * permissions on the parent directory, or if the
999	 * parent directory itself does not exist.
1000	 */
1001	fd = open(filename, O_CREAT | O_EXCL, 0600);
1002	if (fd == -1)
1003		return (KMF_ERR_OPEN_FILE);
1004
1005	/* If we were able to create it, delete it. */
1006	(void) close(fd);
1007	(void) unlink(filename);
1008
1009	return (ret);
1010}
1011
1012void
1013display_error(void *handle, KMF_RETURN errcode, char *prefix)
1014{
1015	KMF_RETURN rv1, rv2;
1016	char *plugin_errmsg = NULL;
1017	char *kmf_errmsg = NULL;
1018
1019	rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg);
1020	rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg);
1021
1022	cryptoerror(LOG_STDERR, "%s:", prefix);
1023	if (rv1 == KMF_OK && plugin_errmsg) {
1024		cryptoerror(LOG_STDERR, gettext("keystore error: %s"),
1025		    plugin_errmsg);
1026		kmf_free_str(plugin_errmsg);
1027	}
1028
1029	if (rv2 == KMF_OK && kmf_errmsg) {
1030		cryptoerror(LOG_STDERR, gettext("libkmf error: %s"),
1031		    kmf_errmsg);
1032		kmf_free_str(kmf_errmsg);
1033	}
1034
1035	if (rv1 != KMF_OK && rv2 != KMF_OK)
1036		cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
1037
1038}
1039