comparison usr/src/cmd/cmd-crypto/pktool/common.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
comparison
equal deleted inserted replaced
-1:000000000000 0:c9caec207d52
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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "@(#)common.c 1.10 08/02/15 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. */
51 static boolean_t initialized = B_FALSE;
52 static boolean_t session_opened = B_FALSE;
53 static boolean_t logged_in = B_FALSE;
54
55 /* Supporting structures and global variables for getopt_av(). */
56 typedef 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;
62 static av_opts *opts_av = NULL;
63 static const char *_save_optstr = NULL;
64 static int _save_numopts = 0;
65
66 int optind_av = 1;
67 char *optarg_av = NULL;
68
69 static void close_sess(CK_SESSION_HANDLE);
70 static 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 */
76 CK_RV
77 init_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 */
103 void
104 final_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 */
122 static void
123 close_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 */
144 static void
145 logout_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 */
165 CK_RV
166 get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
167 {
168 char *save_phrase, *phrase1, *phrase2;
169
170 /* Prompt user for a PIN. */
171 if (prompt1 == NULL) {
172 return (CKR_ARGUMENTS_BAD);
173 }
174 if ((phrase1 = getpassphrase(prompt1)) == NULL) {
175 return (CKR_FUNCTION_FAILED);
176 }
177
178 /* Duplicate 1st PIN in separate chunk of memory. */
179 if ((save_phrase = strdup(phrase1)) == NULL)
180 return (CKR_HOST_MEMORY);
181
182 /* If second prompt given, PIN confirmation is requested. */
183 if (prompt2 != NULL) {
184 if ((phrase2 = getpassphrase(prompt2)) == NULL) {
185 free(save_phrase);
186 return (CKR_FUNCTION_FAILED);
187 }
188 if (strcmp(save_phrase, phrase2) != 0) {
189 free(save_phrase);
190 return (CKR_PIN_INCORRECT);
191 }
192 }
193
194 *pin = (CK_UTF8CHAR_PTR)save_phrase;
195 *pinlen = strlen(save_phrase);
196 return (CKR_OK);
197 }
198
199 int
200 yn_to_int(char *ynstr)
201 {
202 char *y = gettext("yes");
203 char *n = gettext("no");
204 if (ynstr == NULL)
205 return (-1);
206
207 if (strncasecmp(ynstr, y, 1) == 0)
208 return (1);
209 else if (strncasecmp(ynstr, n, 1) == 0)
210 return (0);
211 else
212 return (-1);
213 }
214
215 /*
216 * Gets yes/no response from user. If either no prompt is supplied, a
217 * default prompt is used. If not message for invalid input is supplied,
218 * a default will not be provided. If the user provides no response,
219 * the input default B_TRUE == yes, B_FALSE == no is returned.
220 * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
221 */
222 boolean_t
223 yesno(char *prompt, char *invalid, boolean_t dflt)
224 {
225 char *response, buf[1024];
226 int ans;
227
228 if (prompt == NULL)
229 prompt = gettext("Enter (y)es or (n)o? ");
230
231 for (;;) {
232 /* Prompt user. */
233 (void) printf("%s", prompt);
234 (void) fflush(stdout);
235
236 /* Get the response. */
237 if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
238 break; /* go to default response */
239
240 /* Skip any leading white space. */
241 while (isspace(*response))
242 response++;
243 if (*response == '\0')
244 break; /* go to default response */
245
246 ans = yn_to_int(response);
247 if (ans == 1)
248 return (B_TRUE);
249 else if (ans == 0)
250 return (B_FALSE);
251
252 /* Indicate invalid input, and try again. */
253 if (invalid != NULL)
254 (void) printf("%s", invalid);
255 }
256 return (dflt);
257 }
258
259 /*
260 * Gets the list of slots which have tokens in them. Keeps adjusting
261 * the size of the slot list buffer until the call is successful or an
262 * irrecoverable error occurs.
263 */
264 CK_RV
265 get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
266 {
267 CK_ULONG tmp_count = 0;
268 CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
269 int rv = CKR_OK;
270
271 if (!initialized)
272 if ((rv = init_pk11()) != CKR_OK)
273 return (rv);
274
275 /*
276 * Get the slot count first because we don't know how many
277 * slots there are and how many of those slots even have tokens.
278 * Don't specify an arbitrary buffer size for the slot list;
279 * it may be too small (see section 11.5 of PKCS#11 spec).
280 * Also select only those slots that have tokens in them,
281 * because this tool has no need to know about empty slots.
282 */
283 if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
284 return (rv);
285
286 if (tmp_count == 0) {
287 *slot_list = NULL_PTR;
288 *slot_count = 0;
289 return (CKR_OK);
290 }
291
292 /* Allocate initial space for the slot list. */
293 if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
294 sizeof (CK_SLOT_ID))) == NULL)
295 return (CKR_HOST_MEMORY);
296
297 /* Then get the slot list itself. */
298 for (;;) {
299 if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
300 *slot_list = tmp_list;
301 *slot_count = tmp_count;
302 break;
303 }
304
305 if (rv != CKR_BUFFER_TOO_SMALL) {
306 free(tmp_list);
307 break;
308 }
309
310 /* If the number of slots grew, try again. */
311 if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
312 tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
313 free(tmp_list);
314 rv = CKR_HOST_MEMORY;
315 break;
316 }
317 tmp_list = tmp2_list;
318 }
319
320 return (rv);
321 }
322
323 /*
324 * Breaks out the getopt-style option string into a structure that can be
325 * traversed later for calls to getopt_av(). Option string is NOT altered,
326 * but the struct fields point to locations within option string.
327 */
328 static int
329 populate_opts(char *optstring)
330 {
331 int i;
332 av_opts *temp;
333 char *marker;
334
335 if (optstring == NULL || *optstring == '\0')
336 return (0);
337
338 /*
339 * This tries to imitate getopt(3c) Each option must conform to:
340 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
341 * If long name is missing, the short name is used for long name.
342 */
343 for (i = 0; *optstring != '\0'; i++) {
344 if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
345 realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
346 if (opts_av != NULL)
347 free(opts_av);
348 opts_av = NULL;
349 return (0);
350 } else {
351 opts_av = (av_opts *)temp;
352 }
353
354 (void) memset(&opts_av[i], 0, sizeof (av_opts));
355 marker = optstring; /* may need optstring later */
356
357 opts_av[i].shortnm = *marker++; /* set short name */
358
359 if (*marker == ':') { /* check for opt arg */
360 marker++;
361 opts_av[i].has_arg = B_TRUE;
362 }
363
364 if (*marker == '(') { /* check and set long name */
365 marker++;
366 opts_av[i].longnm = marker;
367 opts_av[i].longnm_len = strcspn(marker, ")");
368 optstring = marker + opts_av[i].longnm_len + 1;
369 } else {
370 /* use short name option character */
371 opts_av[i].longnm = optstring;
372 opts_av[i].longnm_len = 1;
373 optstring = marker;
374 }
375 }
376
377 return (i);
378 }
379
380 /*
381 * getopt_av() is very similar to getopt(3c) in that the takes an option
382 * string, compares command line arguments for matches, and returns a single
383 * letter option when a match is found. However, getopt_av() differs from
384 * getopt(3c) by requiring that only longname options and values be found
385 * on the command line and all leading dashes are omitted. In other words,
386 * it tries to enforce only longname "option=value" arguments on the command
387 * line. Boolean options are not allowed either.
388 */
389 int
390 getopt_av(int argc, char * const *argv, const char *optstring)
391 {
392 int i;
393 int len;
394 char *cur_option;
395
396 if (optind_av >= argc)
397 return (EOF);
398
399 /* First time or when optstring changes from previous one */
400 if (_save_optstr != optstring) {
401 if (opts_av != NULL)
402 free(opts_av);
403 opts_av = NULL;
404 _save_optstr = optstring;
405 _save_numopts = populate_opts((char *)optstring);
406 }
407
408 for (i = 0; i < _save_numopts; i++) {
409 cur_option = argv[optind_av];
410
411 if (strcmp(cur_option, "--") == 0) {
412 optind_av++;
413 break;
414 }
415
416 if (cur_option[0] == '-' && strlen(cur_option) == 2) {
417 len = 1;
418 cur_option++; /* remove "-" */
419 } else {
420 len = strcspn(cur_option, "=");
421 }
422
423 if (len == opts_av[i].longnm_len && strncmp(cur_option,
424 opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
425 /* matched */
426 if (!opts_av[i].has_arg) {
427 optind_av++;
428 return (opts_av[i].shortnm);
429 }
430
431 /* needs optarg */
432 if (cur_option[len] == '=') {
433 optarg_av = &(cur_option[len+1]);
434 optind_av++;
435 return (opts_av[i].shortnm);
436 }
437
438 optarg_av = NULL;
439 optind_av++;
440 return ((int)'?');
441 }
442 }
443
444 return (EOF);
445 }
446
447 KMF_KEYSTORE_TYPE
448 KS2Int(char *keystore_str)
449 {
450 if (keystore_str == NULL)
451 return (0);
452 if (strcasecmp(keystore_str, "pkcs11") == 0)
453 return (KMF_KEYSTORE_PK11TOKEN);
454 else if (strcasecmp(keystore_str, "nss") == 0)
455 return (KMF_KEYSTORE_NSS);
456 else if (strcasecmp(keystore_str, "file") == 0)
457 return (KMF_KEYSTORE_OPENSSL);
458 else
459 return (0);
460 }
461
462
463 int
464 Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg)
465 {
466 if (algm == NULL) {
467 *sigAlg = KMF_ALGID_MD5WithRSA;
468 *ktype = KMF_RSA;
469 } else if (strcasecmp(algm, "DSA") == 0) {
470 *sigAlg = KMF_ALGID_SHA1WithDSA;
471 *ktype = KMF_DSA;
472 } else if (strcasecmp(algm, "RSA") == 0) {
473 *sigAlg = KMF_ALGID_MD5WithRSA;
474 *ktype = KMF_RSA;
475 } else {
476 return (-1);
477 }
478 return (0);
479 }
480
481 int
482 Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
483 {
484 if (algm == NULL)
485 *ktype = KMF_AES;
486 else if (strcasecmp(algm, "aes") == 0)
487 *ktype = KMF_AES;
488 else if (strcasecmp(algm, "arcfour") == 0)
489 *ktype = KMF_RC4;
490 else if (strcasecmp(algm, "des") == 0)
491 *ktype = KMF_DES;
492 else if (strcasecmp(algm, "3des") == 0)
493 *ktype = KMF_DES3;
494 else if (strcasecmp(algm, "generic") == 0)
495 *ktype = KMF_GENERIC_SECRET;
496 else
497 return (-1);
498
499 return (0);
500 }
501
502 int
503 Str2Lifetime(char *ltimestr, uint32_t *ltime)
504 {
505 int num;
506 char timetok[6];
507
508 if (ltimestr == NULL || strlen(ltimestr) == 0) {
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") == 0||
519 strcasecmp(timetok, "days") == 0) {
520 *ltime = num * SECSPERDAY;
521 } else if (strcasecmp(timetok, "hour") == 0||
522 strcasecmp(timetok, "hours") == 0) {
523 *ltime = num * SECSPERHOUR;
524 } else if (strcasecmp(timetok, "year") == 0 ||
525 strcasecmp(timetok, "years") == 0) {
526 *ltime = num * SECSPERDAY * DAYSPERNYEAR;
527 } else {
528 *ltime = 0;
529 return (-1);
530 }
531
532 return (0);
533 }
534
535 int
536 OT2Int(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") == 0)
547 retval = PK_PRIVATE_OBJ;
548 else if (strcasecmp(c, ":public") == 0)
549 retval = PK_PUBLIC_OBJ;
550 else if (strcasecmp(c, ":both") == 0)
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") == 0) {
559 if (retval)
560 return (-1);
561 return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ);
562 } else if (strcasecmp(objclass, "private") == 0) {
563 if (retval)
564 return (-1);
565 return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
566 } else if (strcasecmp(objclass, "both") == 0) {
567 if (retval)
568 return (-1);
569 return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
570 } else if (strcasecmp(objclass, "cert") == 0) {
571 return (retval | PK_CERT_OBJ);
572 } else if (strcasecmp(objclass, "key") == 0) {
573 if (retval == 0) /* return all keys */
574 return (retval | PK_KEY_OBJ);
575 else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
576 /* return all keys */
577 return (retval | PK_KEY_OBJ);
578 else if (retval & PK_PUBLIC_OBJ)
579 /* Only return public keys */
580 return (retval | PK_PUBKEY_OBJ);
581 else if (retval & PK_PRIVATE_OBJ)
582 /* Only return private keys */
583 return (retval | PK_PRIKEY_OBJ);
584 } else if (strcasecmp(objclass, "crl") == 0) {
585 if (retval)
586 return (-1);
587 return (retval | PK_CRL_OBJ);
588 }
589
590 if (retval == 0) /* No matches found */
591 retval = -1;
592 return (retval);
593 }
594
595 KMF_ENCODE_FORMAT
596 Str2Format(char *formstr)
597 {
598 if (formstr == NULL || strcasecmp(formstr, "der") == 0)
599 return (KMF_FORMAT_ASN1);
600 if (strcasecmp(formstr, "pem") == 0)
601 return (KMF_FORMAT_PEM);
602 if (strcasecmp(formstr, "pkcs12") == 0)
603 return (KMF_FORMAT_PKCS12);
604 if (strcasecmp(formstr, "raw") == 0)
605 return (KMF_FORMAT_RAWKEY);
606
607 return (KMF_FORMAT_UNDEF);
608 }
609
610 KMF_RETURN
611 select_token(void *kmfhandle, char *token, int readonly)
612 {
613 KMF_ATTRIBUTE attlist[10];
614 int i = 0;
615 KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
616 KMF_RETURN rv = KMF_OK;
617
618 if (token == NULL)
619 return (KMF_ERR_BAD_PARAMETER);
620
621 kmf_set_attr_at_index(attlist, i,
622 KMF_KEYSTORE_TYPE_ATTR, &kstype,
623 sizeof (kstype));
624 i++;
625
626 if (token) {
627 kmf_set_attr_at_index(attlist, i,
628 KMF_TOKEN_LABEL_ATTR, token,
629 strlen(token));
630 i++;
631 }
632
633 kmf_set_attr_at_index(attlist, i,
634 KMF_READONLY_ATTR, &readonly,
635 sizeof (readonly));
636 i++;
637
638 rv = kmf_configure_keystore(kmfhandle, i, attlist);
639 if (rv == KMF_ERR_TOKEN_SELECTED)
640 rv = KMF_OK;
641 return (rv);
642 }
643
644 KMF_RETURN
645 configure_nss(void *kmfhandle, char *dir, char *prefix)
646 {
647 KMF_ATTRIBUTE attlist[10];
648 int i = 0;
649 KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
650 KMF_RETURN rv = KMF_OK;
651
652 kmf_set_attr_at_index(attlist, i,
653 KMF_KEYSTORE_TYPE_ATTR, &kstype,
654 sizeof (kstype));
655 i++;
656
657 if (dir) {
658 kmf_set_attr_at_index(attlist, i,
659 KMF_DIRPATH_ATTR, dir,
660 strlen(dir));
661 i++;
662 }
663
664 if (prefix) {
665 kmf_set_attr_at_index(attlist, i,
666 KMF_CERTPREFIX_ATTR, prefix,
667 strlen(prefix));
668 i++;
669
670 kmf_set_attr_at_index(attlist, i,
671 KMF_KEYPREFIX_ATTR, prefix,
672 strlen(prefix));
673 i++;
674 }
675
676 rv = kmf_configure_keystore(kmfhandle, i, attlist);
677 if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
678 rv = KMF_OK;
679
680 return (rv);
681 }
682
683 KMF_RETURN
684 get_pk12_password(KMF_CREDENTIAL *cred)
685 {
686 KMF_RETURN rv = KMF_OK;
687 char prompt[1024];
688
689 /*
690 * Get the password to use for the PK12 encryption.
691 */
692 (void) strlcpy(prompt,
693 gettext("Enter password to use for "
694 "accessing the PKCS12 file: "), sizeof (prompt));
695
696 if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
697 (ulong_t *)&cred->credlen) != CKR_OK) {
698 cred->cred = NULL;
699 cred->credlen = 0;
700 }
701
702 return (rv);
703 }
704
705 #define FILENAME_PROMPT gettext("Filename:")
706 #define FILENAME_MINLEN 1
707 #define FILENAME_MAXLEN MAXPATHLEN
708
709 #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:")
710 #define STATE_PROMPT gettext("State or Province Name (full name) " \
711 "[Some-State]:")
712 #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:")
713 #define ORG_PROMPT gettext("Organization Name (eg, company) []:")
714 #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:")
715 #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:")
716 #define EMAIL_PROMPT gettext("Email Address []:")
717
718 #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \
719 "0x01020304):")
720 #define SERNO_MINLEN 3
721 #define SERNO_MAXLEN 42
722
723 #define LABEL_PROMPT gettext("Enter a label for the certificate:")
724 #define LABEL_MINLEN 1
725 #define LABEL_MAXLEN 1024
726
727 #define COUNTRY_DEFAULT "US"
728 #define STATE_DEFAULT NULL
729 #define INVALID_INPUT gettext("Invalid input; please re-enter ...")
730
731 #define SUBNAMESIZ 1024
732 #define RDN_MIN 1
733 #define RDN_MAX 64
734 #define COUNTRYNAME_MIN 2
735 #define COUNTRYNAME_MAX 2
736
737 static char *
738 get_input_string(char *prompt, char *default_str, int min_len, int max_len)
739 {
740 char buf[1024];
741 char *response = NULL;
742 char *ret = NULL;
743 int len;
744
745 for (;;) {
746 (void) printf("\t%s", prompt);
747 (void) fflush(stdout);
748
749 response = fgets(buf, sizeof (buf), stdin);
750 if (response == NULL) {
751 if (default_str != NULL) {
752 ret = strdup(default_str);
753 }
754 break;
755 }
756
757 /* Skip any leading white space. */
758 while (isspace(*response))
759 response++;
760 if (*response == '\0') {
761 if (default_str != NULL) {
762 ret = strdup(default_str);
763 }
764 break;
765 }
766
767 len = strlen(response);
768 response[len-1] = '\0'; /* get rid of "LF" */
769 len--;
770 if (len >= min_len && len <= max_len) {
771 ret = strdup(response);
772 break;
773 }
774
775 (void) printf("%s\n", INVALID_INPUT);
776
777 }
778
779 return (ret);
780 }
781
782 int
783 get_filename(char *txt, char **result)
784 {
785 char prompt[1024];
786 char *fname = NULL;
787
788 (void) snprintf(prompt, sizeof (prompt),
789 gettext("Enter filename for the %s: "),
790 txt);
791 fname = get_input_string(prompt, NULL,
792 FILENAME_MINLEN, FILENAME_MAXLEN);
793 *result = fname;
794 return (0);
795 }
796
797 int
798 get_certlabel(char **result)
799 {
800 char *label = NULL;
801
802 label = get_input_string(LABEL_PROMPT, NULL,
803 LABEL_MINLEN, LABEL_MAXLEN);
804 *result = label;
805 return (0);
806 }
807
808 int
809 get_serial(char **result)
810 {
811 char *serial = NULL;
812
813 serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN,
814 SERNO_MAXLEN);
815
816 *result = serial;
817 return (0);
818 }
819
820 int
821 get_subname(char **result)
822 {
823 char *country = NULL;
824 char *state = NULL;
825 char *locality = NULL;
826 char *org = NULL;
827 char *unit = NULL;
828 char *name = NULL;
829 char *email = NULL;
830 char *subname = NULL;
831
832 (void) printf("Entering following fields for subject (a DN) ...\n");
833 country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
834 COUNTRYNAME_MIN, COUNTRYNAME_MAX);
835 if (country == NULL)
836 return (-1);
837
838 state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
839 RDN_MIN, RDN_MAX);
840
841 locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
842 org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
843 unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
844 name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
845 email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
846
847 /* Now create a subject name from the input strings */
848 if ((subname = malloc(SUBNAMESIZ)) == NULL)
849 goto out;
850
851 (void) memset(subname, 0, SUBNAMESIZ);
852 (void) strlcpy(subname, "C=", SUBNAMESIZ);
853 (void) strlcat(subname, country, SUBNAMESIZ);
854 if (state != NULL) {
855 (void) strlcat(subname, ", ST=", SUBNAMESIZ);
856 (void) strlcat(subname, state, SUBNAMESIZ);
857 }
858
859 if (locality != NULL) {
860 (void) strlcat(subname, ", L=", SUBNAMESIZ);
861 (void) strlcat(subname, locality, SUBNAMESIZ);
862 }
863
864 if (org != NULL) {
865 (void) strlcat(subname, ", O=", SUBNAMESIZ);
866 (void) strlcat(subname, org, SUBNAMESIZ);
867 }
868
869 if (unit != NULL) {
870 (void) strlcat(subname, ", OU=", SUBNAMESIZ);
871 (void) strlcat(subname, unit, SUBNAMESIZ);
872 }
873
874 if (name != NULL) {
875 (void) strlcat(subname, ", CN=", SUBNAMESIZ);
876 (void) strlcat(subname, name, SUBNAMESIZ);
877 }
878
879 if (email != NULL) {
880 (void) strlcat(subname, ", E=", SUBNAMESIZ);
881 (void) strlcat(subname, email, SUBNAMESIZ);
882 }
883
884 out:
885 if (country)
886 free(country);
887 if (state)
888 free(state);
889 if (locality)
890 free(locality);
891 if (org)
892 free(org);
893 if (unit)
894 free(unit);
895 if (name)
896 free(name);
897 if (email)
898 free(email);
899
900 if (subname == NULL)
901 return (-1);
902 else {
903 *result = subname;
904 return (0);
905 }
906 }
907
908 /*
909 * Parse a string of KeyUsage values and convert
910 * them to the correct KU Bits.
911 * The field may be marked "critical" by prepending
912 * "critical:" to the list.
913 * EX: critical:digitialSignature,keyEncipherment
914 */
915 KMF_RETURN
916 verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
917 {
918 KMF_RETURN ret = KMF_OK;
919 uint16_t kuval;
920 char *k;
921
922 *kubits = 0;
923 if (kustr == NULL || strlen(kustr) == 0)
924 return (KMF_ERR_BAD_PARAMETER);
925
926 /* Check to see if this is critical */
927 if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) {
928 *critical = TRUE;
929 kustr += strlen("critical:");
930 } else {
931 *critical = FALSE;
932 }
933
934 k = strtok(kustr, ",");
935 while (k != NULL) {
936 kuval = kmf_string_to_ku(k);
937 if (kuval == 0) {
938 *kubits = 0;
939 return (KMF_ERR_BAD_PARAMETER);
940 }
941 *kubits |= kuval;
942 k = strtok(NULL, ",");
943 }
944
945 return (ret);
946 }
947
948 /*
949 * Verify the alternate subject label is real or invalid.
950 *
951 * The field may be marked "critical" by prepending
952 * "critical:" to the list.
953 * EX: "critical:IP=1.2.3.4"
954 */
955 KMF_RETURN
956 verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
957 {
958 char *p;
959 KMF_RETURN rv = KMF_OK;
960
961 /* Check to see if this is critical */
962 if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) {
963 *critical = TRUE;
964 arg += strlen("critical:");
965 } else {
966 *critical = FALSE;
967 }
968
969 /* Make sure there is an "=" sign */
970 p = strchr(arg, '=');
971 if (p == NULL)
972 return (KMF_ERR_BAD_PARAMETER);
973
974 p[0] = '\0';
975
976 if (strcmp(arg, "IP") == 0)
977 *type = GENNAME_IPADDRESS;
978 else if (strcmp(arg, "DNS") == 0)
979 *type = GENNAME_DNSNAME;
980 else if (strcmp(arg, "EMAIL") == 0)
981 *type = GENNAME_RFC822NAME;
982 else if (strcmp(arg, "URI") == 0)
983 *type = GENNAME_URI;
984 else if (strcmp(arg, "DN") == 0)
985 *type = GENNAME_DIRECTORYNAME;
986 else if (strcmp(arg, "RID") == 0)
987 *type = GENNAME_REGISTEREDID;
988 else if (strcmp(arg, "KRB") == 0)
989 *type = GENNAME_KRB5PRINC;
990 else if (strcmp(arg, "UPN") == 0)
991 *type = GENNAME_SCLOGON_UPN;
992 else
993 rv = KMF_ERR_BAD_PARAMETER;
994
995 p[0] = '=';
996
997 return (rv);
998 }
999
1000 int
1001 get_token_password(KMF_KEYSTORE_TYPE kstype,
1002 char *token_spec, KMF_CREDENTIAL *cred)
1003 {
1004 char prompt[1024];
1005 char *p = NULL;
1006
1007 if (kstype == KMF_KEYSTORE_PK11TOKEN) {
1008 p = strchr(token_spec, ':');
1009 if (p != NULL)
1010 *p = 0;
1011 }
1012 /*
1013 * Login to the token first.
1014 */
1015 (void) snprintf(prompt, sizeof (prompt),
1016 gettext(DEFAULT_TOKEN_PROMPT), token_spec);
1017
1018 if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
1019 (ulong_t *)&cred->credlen) != CKR_OK) {
1020 cred->cred = NULL;
1021 cred->credlen = 0;
1022 }
1023
1024 if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
1025 *p = ':';
1026 return (KMF_OK);
1027 }
1028
1029 KMF_RETURN
1030 verify_file(char *filename)
1031 {
1032 KMF_RETURN ret = KMF_OK;
1033 int fd;
1034
1035 /*
1036 * Attempt to open with the EXCL flag so that if
1037 * it already exists, the open will fail. It will
1038 * also fail if the file cannot be created due to
1039 * permissions on the parent directory, or if the
1040 * parent directory itself does not exist.
1041 */
1042 fd = open(filename, O_CREAT | O_EXCL, 0600);
1043 if (fd == -1)
1044 return (KMF_ERR_OPEN_FILE);
1045
1046 /* If we were able to create it, delete it. */
1047 (void) close(fd);
1048 (void) unlink(filename);
1049
1050 return (ret);
1051 }
1052
1053 void
1054 display_error(void *handle, KMF_RETURN errcode, char *prefix)
1055 {
1056 KMF_RETURN rv1, rv2;
1057 char *plugin_errmsg = NULL;
1058 char *kmf_errmsg = NULL;
1059
1060 rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg);
1061 rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg);
1062
1063 cryptoerror(LOG_STDERR, "%s:", prefix);
1064 if (rv1 == KMF_OK && plugin_errmsg) {
1065 cryptoerror(LOG_STDERR, gettext("keystore error: %s"),
1066 plugin_errmsg);
1067 kmf_free_str(plugin_errmsg);
1068 }
1069
1070 if (rv2 == KMF_OK && kmf_errmsg) {
1071 cryptoerror(LOG_STDERR, gettext("libkmf error: %s"),
1072 kmf_errmsg);
1073 kmf_free_str(kmf_errmsg);
1074 }
1075
1076 if (rv1 != KMF_OK && rv2 != KMF_OK)
1077 cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
1078
1079 }
1080
1081 static KMF_RETURN
1082 addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid)
1083 {
1084 if (newoid != NULL && ekus != NULL) {
1085 ekus->eku_count++;
1086
1087 ekus->critlist = realloc(ekus->critlist,
1088 ekus->eku_count * sizeof (int));
1089 if (ekus->critlist != NULL)
1090 ekus->critlist[ekus->eku_count-1] = critical;
1091 else
1092 return (KMF_ERR_MEMORY);
1093
1094 ekus->ekulist = realloc(
1095 ekus->ekulist, ekus->eku_count * sizeof (KMF_OID));
1096 if (ekus->ekulist != NULL)
1097 ekus->ekulist[ekus->eku_count-1] = *newoid;
1098 else
1099 return (KMF_ERR_MEMORY);
1100 }
1101 return (KMF_OK);
1102 }
1103
1104 void
1105 free_eku_list(EKU_LIST *ekus)
1106 {
1107 if (ekus != NULL && ekus->eku_count > 0) {
1108 int i;
1109 for (i = 0; i < ekus->eku_count; i++) {
1110 kmf_free_data(&ekus->ekulist[i]);
1111 }
1112 free(ekus->ekulist);
1113 free(ekus->critlist);
1114 }
1115 }
1116
1117 static KMF_RETURN
1118 parse_ekus(char *ekustr, EKU_LIST *ekus)
1119 {
1120 KMF_RETURN rv = KMF_OK;
1121 KMF_OID *newoid;
1122 int critical;
1123
1124 if (strncasecmp(ekustr, "critical:",
1125 strlen("critical:")) == 0) {
1126 critical = TRUE;
1127 ekustr += strlen("critical:");
1128 } else {
1129 critical = FALSE;
1130 }
1131 newoid = kmf_ekuname_to_oid(ekustr);
1132 if (newoid != NULL) {
1133 rv = addToEKUList(ekus, critical, newoid);
1134 free(newoid);
1135 } else {
1136 rv = PK_ERR_USAGE;
1137 }
1138
1139 return (rv);
1140 }
1141
1142 KMF_RETURN
1143 verify_ekunames(char *ekuliststr, EKU_LIST **ekulist)
1144 {
1145 KMF_RETURN rv = KMF_OK;
1146 char *p;
1147 EKU_LIST *ekus = NULL;
1148
1149 if (ekuliststr == NULL || strlen(ekuliststr) == 0)
1150 return (0);
1151
1152 /*
1153 * The list should be comma separated list of EKU Names.
1154 */
1155 p = strtok(ekuliststr, ",");
1156
1157 /* If no tokens found, then maybe it's just a single EKU value */
1158 if (p == NULL) {
1159 rv = parse_ekus(ekuliststr, ekus);
1160 }
1161
1162 while (p != NULL) {
1163 rv = parse_ekus(p, ekus);
1164
1165 if (rv != KMF_OK)
1166 break;
1167 p = strtok(NULL, ",");
1168 }
1169
1170 if (rv != KMF_OK)
1171 free_eku_list(ekus);
1172 else
1173 *ekulist = ekus;
1174
1175 return (rv);
1176 }