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.
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.
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]
21 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
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
36 #include <sys/types.h>
40 #include <cryptoutil.h>
41 #include <security/cryptoki.h>
46 /* Local status variables. */
47 static boolean_t initialized
= B_FALSE
;
48 static boolean_t session_opened
= B_FALSE
;
49 static boolean_t logged_in
= B_FALSE
;
51 /* Supporting structures and global variables for getopt_av(). */
52 typedef 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 */
58 static av_opts
*opts_av
= NULL
;
59 static const char *_save_optstr
= NULL
;
60 static int _save_numopts
= 0;
63 char *optarg_av
= NULL
;
65 static void close_sess(CK_SESSION_HANDLE
);
66 static void logout_token(CK_SESSION_HANDLE
);
68 struct oid_table_entry
{
73 struct 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"}
131 int number_of_oids
= sizeof (oid_table
) / sizeof (struct oid_table_entry
);
132 #define number_of_curves (number_of_oids - 5)
135 * Perform PKCS#11 setup here. Currently only C_Initialize is required,
136 * along with setting/resetting state variables.
143 /* If C_Initialize() already called, nothing to do here. */
144 if (initialized
== B_TRUE
)
147 /* Reset state variables because C_Initialize() not yet done. */
148 session_opened
= B_FALSE
;
151 /* Initialize PKCS#11 library. */
152 if ((rv
= C_Initialize(NULL_PTR
)) != CKR_OK
&&
153 rv
!= CKR_CRYPTOKI_ALREADY_INITIALIZED
) {
157 initialized
= B_TRUE
;
162 * Finalize PKCS#11 library and reset state variables. Open sessions,
163 * if any, are closed, and thereby any logins are logged out also.
166 final_pk11(CK_SESSION_HANDLE sess
)
169 /* If the library wasn't initialized, nothing to do here. */
173 /* Make sure the sesion is closed first. */
176 (void) C_Finalize(NULL
);
177 initialized
= B_FALSE
;
181 * Close PKCS#11 session and reset state variables. Any logins are
185 close_sess(CK_SESSION_HANDLE sess
)
192 /* If session is already closed, nothing to do here. */
196 /* Make sure user is logged out of token. */
199 (void) C_CloseSession(sess
);
200 session_opened
= B_FALSE
;
204 * Log user out of token and reset status variable.
207 logout_token(CK_SESSION_HANDLE sess
)
214 /* If already logged out, nothing to do here. */
218 (void) C_Logout(sess
);
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.
228 get_pin(char *prompt1
, char *prompt2
, CK_UTF8CHAR_PTR
*pin
, CK_ULONG
*pinlen
)
230 char *save_phrase
, *phrase1
, *phrase2
;
232 /* Prompt user for a PIN. */
233 if (prompt1
== NULL
) {
234 return (CKR_ARGUMENTS_BAD
);
236 if ((phrase1
= getpassphrase(prompt1
)) == NULL
) {
237 return (CKR_FUNCTION_FAILED
);
240 /* Duplicate 1st PIN in separate chunk of memory. */
241 if ((save_phrase
= strdup(phrase1
)) == NULL
)
242 return (CKR_HOST_MEMORY
);
244 /* If second prompt given, PIN confirmation is requested. */
245 if (prompt2
!= NULL
) {
246 if ((phrase2
= getpassphrase(prompt2
)) == NULL
) {
248 return (CKR_FUNCTION_FAILED
);
250 if (strcmp(save_phrase
, phrase2
) != 0) {
252 return (CKR_PIN_INCORRECT
);
256 *pin
= (CK_UTF8CHAR_PTR
)save_phrase
;
257 *pinlen
= strlen(save_phrase
);
262 yn_to_int(char *ynstr
)
264 char *y
= gettext("yes");
265 char *n
= gettext("no");
269 if (strncasecmp(ynstr
, y
, 1) == 0)
271 else if (strncasecmp(ynstr
, n
, 1) == 0)
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.
285 yesno(char *prompt
, char *invalid
, boolean_t dflt
)
287 char *response
, buf
[1024];
291 prompt
= gettext("Enter (y)es or (n)o? ");
295 (void) printf("%s", prompt
);
296 (void) fflush(stdout
);
298 /* Get the response. */
299 if ((response
= fgets(buf
, sizeof (buf
), stdin
)) == NULL
)
300 break; /* go to default response */
302 /* Skip any leading white space. */
303 while (isspace(*response
))
305 if (*response
== '\0')
306 break; /* go to default response */
308 ans
= yn_to_int(response
);
314 /* Indicate invalid input, and try again. */
316 (void) printf("%s", invalid
);
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.
327 get_token_slots(CK_SLOT_ID_PTR
*slot_list
, CK_ULONG
*slot_count
)
329 CK_ULONG tmp_count
= 0;
330 CK_SLOT_ID_PTR tmp_list
= NULL_PTR
, tmp2_list
= NULL_PTR
;
334 if ((rv
= init_pkcs11()) != CKR_OK
)
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.
345 if ((rv
= C_GetSlotList(1, NULL_PTR
, &tmp_count
)) != CKR_OK
)
348 if (tmp_count
== 0) {
349 *slot_list
= NULL_PTR
;
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
);
359 /* Then get the slot list itself. */
361 if ((rv
= C_GetSlotList(1, tmp_list
, &tmp_count
)) == CKR_OK
) {
362 *slot_list
= tmp_list
;
363 *slot_count
= tmp_count
;
367 if (rv
!= CKR_BUFFER_TOO_SMALL
) {
372 /* If the number of slots grew, try again. */
373 if ((tmp2_list
= reallocarray(tmp_list
, tmp_count
,
374 sizeof (CK_SLOT_ID
))) == NULL
) {
376 rv
= CKR_HOST_MEMORY
;
379 tmp_list
= tmp2_list
;
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.
391 populate_opts(char *optstring
)
397 if (optstring
== NULL
|| *optstring
== '\0')
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.
405 for (i
= 0; *optstring
!= '\0'; i
++) {
406 if ((temp
= (av_opts
*)((i
== 0) ? malloc(sizeof (av_opts
)) :
407 reallocarray(opts_av
, i
+ 1, sizeof (av_opts
)))) == NULL
) {
412 opts_av
= (av_opts
*)temp
;
415 (void) memset(&opts_av
[i
], 0, sizeof (av_opts
));
416 marker
= optstring
; /* may need optstring later */
418 opts_av
[i
].shortnm
= *marker
++; /* set short name */
420 if (*marker
== ':') { /* check for opt arg */
422 opts_av
[i
].has_arg
= B_TRUE
;
425 if (*marker
== '(') { /* check and set long name */
427 opts_av
[i
].longnm
= marker
;
428 opts_av
[i
].longnm_len
= strcspn(marker
, ")");
429 optstring
= marker
+ opts_av
[i
].longnm_len
+ 1;
431 /* use short name option character */
432 opts_av
[i
].longnm
= optstring
;
433 opts_av
[i
].longnm_len
= 1;
442 * getopt_av() is very similar to getopt(3c) in that the takes an option
443 * string, compares command line arguments for matches, and returns a single
444 * letter option when a match is found. However, getopt_av() differs from
445 * getopt(3c) by requiring that only longname options and values be found
446 * on the command line and all leading dashes are omitted. In other words,
447 * it tries to enforce only longname "option=value" arguments on the command
448 * line. Boolean options are not allowed either.
451 getopt_av(int argc
, char * const *argv
, const char *optstring
)
457 if (optind_av
>= argc
)
460 /* First time or when optstring changes from previous one */
461 if (_save_optstr
!= optstring
) {
464 _save_optstr
= optstring
;
465 _save_numopts
= populate_opts((char *)optstring
);
468 for (i
= 0; i
< _save_numopts
; i
++) {
469 cur_option
= argv
[optind_av
];
471 if (strcmp(cur_option
, "--") == 0) {
476 if (cur_option
[0] == '-' && strlen(cur_option
) == 2) {
478 cur_option
++; /* remove "-" */
480 len
= strcspn(cur_option
, "=");
483 if (len
== opts_av
[i
].longnm_len
&& strncmp(cur_option
,
484 opts_av
[i
].longnm
, opts_av
[i
].longnm_len
) == 0) {
486 if (!opts_av
[i
].has_arg
) {
488 return (opts_av
[i
].shortnm
);
492 if (cur_option
[len
] == '=') {
493 optarg_av
= &(cur_option
[len
+1]);
495 return (opts_av
[i
].shortnm
);
508 KS2Int(char *keystore_str
)
510 if (keystore_str
== NULL
)
512 if (strcasecmp(keystore_str
, "pkcs11") == 0)
513 return (KMF_KEYSTORE_PK11TOKEN
);
514 else if (strcasecmp(keystore_str
, "nss") == 0)
515 return (KMF_KEYSTORE_NSS
);
516 else if (strcasecmp(keystore_str
, "file") == 0)
517 return (KMF_KEYSTORE_OPENSSL
);
527 compare_oids(KMF_OID
*oid1
, const KMF_OID
*oid2
)
529 return ((oid1
->Length
== oid2
->Length
) &&
530 !memcmp(oid1
->Data
, oid2
->Data
, oid1
->Length
));
534 Str2KeyType(char *algm
, KMF_OID
*hashoid
, KMF_KEY_ALG
*ktype
,
535 KMF_ALGORITHM_INDEX
*sigAlg
)
538 /* Default to SHA1+RSA */
539 *sigAlg
= KMF_ALGID_SHA1WithRSA
;
541 } else if (strcasecmp(algm
, "DSA") == 0) {
542 if (hashoid
== NULL
||
543 compare_oids(hashoid
, &KMFOID_SHA1
))
544 *sigAlg
= KMF_ALGID_SHA1WithDSA
;
545 else if (compare_oids(hashoid
, &KMFOID_SHA256
))
546 *sigAlg
= KMF_ALGID_SHA256WithDSA
;
548 return (-1); /* unsupported hash/key combo */
550 } else if (strcasecmp(algm
, "RSA") == 0) {
551 if (hashoid
== NULL
||
552 compare_oids(hashoid
, &KMFOID_SHA1
))
553 *sigAlg
= KMF_ALGID_SHA1WithRSA
;
554 else if (compare_oids(hashoid
, &KMFOID_SHA256
))
555 *sigAlg
= KMF_ALGID_SHA256WithRSA
;
556 else if (compare_oids(hashoid
, &KMFOID_SHA384
))
557 *sigAlg
= KMF_ALGID_SHA384WithRSA
;
558 else if (compare_oids(hashoid
, &KMFOID_SHA512
))
559 *sigAlg
= KMF_ALGID_SHA512WithRSA
;
560 else if (compare_oids(hashoid
, &KMFOID_MD5
))
561 *sigAlg
= KMF_ALGID_MD5WithRSA
;
563 return (-1); /* unsupported hash/key combo */
565 } else if (strcasecmp(algm
, "EC") == 0) {
566 /* EC keys may be used with some SHA2 hashes */
567 if (hashoid
== NULL
||
568 compare_oids(hashoid
, &KMFOID_SHA1
))
569 *sigAlg
= KMF_ALGID_SHA1WithECDSA
;
570 else if (compare_oids(hashoid
, &KMFOID_SHA256
))
571 *sigAlg
= KMF_ALGID_SHA256WithECDSA
;
572 else if (compare_oids(hashoid
, &KMFOID_SHA384
))
573 *sigAlg
= KMF_ALGID_SHA384WithECDSA
;
574 else if (compare_oids(hashoid
, &KMFOID_SHA512
))
575 *sigAlg
= KMF_ALGID_SHA512WithECDSA
;
577 return (-1); /* unsupported hash/key combo */
587 Str2SymKeyType(char *algm
, KMF_KEY_ALG
*ktype
)
591 else if (strcasecmp(algm
, "aes") == 0)
593 else if (strcasecmp(algm
, "arcfour") == 0)
595 else if (strcasecmp(algm
, "des") == 0)
597 else if (strcasecmp(algm
, "3des") == 0)
599 else if (strcasecmp(algm
, "generic") == 0)
600 *ktype
= KMF_GENERIC_SECRET
;
608 Str2Lifetime(char *ltimestr
, uint32_t *ltime
)
613 if (ltimestr
== NULL
|| strlen(ltimestr
) == 0) {
614 /* default to 1 year lifetime */
615 *ltime
= SECSPERDAY
* DAYSPERNYEAR
;
619 (void) memset(timetok
, 0, sizeof (timetok
));
620 if (sscanf(ltimestr
, "%d-%06s", &num
, timetok
) != 2)
623 if (strcasecmp(timetok
, "day") == 0||
624 strcasecmp(timetok
, "days") == 0) {
625 *ltime
= num
* SECSPERDAY
;
626 } else if (strcasecmp(timetok
, "hour") == 0||
627 strcasecmp(timetok
, "hours") == 0) {
628 *ltime
= num
* SECSPERHOUR
;
629 } else if (strcasecmp(timetok
, "year") == 0 ||
630 strcasecmp(timetok
, "years") == 0) {
631 *ltime
= num
* SECSPERDAY
* DAYSPERNYEAR
;
641 OT2Int(char *objclass
)
646 if (objclass
== NULL
)
649 c
= strchr(objclass
, ':');
651 if (strcasecmp(c
, ":private") == 0)
652 retval
= PK_PRIVATE_OBJ
;
653 else if (strcasecmp(c
, ":public") == 0)
654 retval
= PK_PUBLIC_OBJ
;
655 else if (strcasecmp(c
, ":both") == 0)
656 retval
= PK_PRIVATE_OBJ
| PK_PUBLIC_OBJ
;
657 else /* unrecognized option */
663 if (strcasecmp(objclass
, "public") == 0) {
666 return (retval
| PK_PUBLIC_OBJ
| PK_CERT_OBJ
| PK_PUBKEY_OBJ
);
667 } else if (strcasecmp(objclass
, "private") == 0) {
670 return (retval
| PK_PRIKEY_OBJ
| PK_PRIVATE_OBJ
);
671 } else if (strcasecmp(objclass
, "both") == 0) {
674 return (PK_KEY_OBJ
| PK_PUBLIC_OBJ
| PK_PRIVATE_OBJ
);
675 } else if (strcasecmp(objclass
, "cert") == 0) {
676 return (retval
| PK_CERT_OBJ
);
677 } else if (strcasecmp(objclass
, "key") == 0) {
678 if (retval
== 0) /* return all keys */
679 return (retval
| PK_KEY_OBJ
);
680 else if (retval
== (PK_PRIVATE_OBJ
| PK_PUBLIC_OBJ
))
681 /* return all keys */
682 return (retval
| PK_KEY_OBJ
);
683 else if (retval
& PK_PUBLIC_OBJ
)
684 /* Only return public keys */
685 return (retval
| PK_PUBKEY_OBJ
);
686 else if (retval
& PK_PRIVATE_OBJ
)
687 /* Only return private keys */
688 return (retval
| PK_PRIKEY_OBJ
);
689 } else if (strcasecmp(objclass
, "crl") == 0) {
692 return (retval
| PK_CRL_OBJ
);
695 if (retval
== 0) /* No matches found */
701 Str2Format(char *formstr
)
703 if (formstr
== NULL
|| strcasecmp(formstr
, "der") == 0)
704 return (KMF_FORMAT_ASN1
);
705 if (strcasecmp(formstr
, "pem") == 0)
706 return (KMF_FORMAT_PEM
);
707 if (strcasecmp(formstr
, "pkcs12") == 0)
708 return (KMF_FORMAT_PKCS12
);
709 if (strcasecmp(formstr
, "raw") == 0)
710 return (KMF_FORMAT_RAWKEY
);
712 return (KMF_FORMAT_UNDEF
);
716 select_token(void *kmfhandle
, char *token
, int readonly
)
718 KMF_ATTRIBUTE attlist
[10];
720 KMF_KEYSTORE_TYPE kstype
= KMF_KEYSTORE_PK11TOKEN
;
721 KMF_RETURN rv
= KMF_OK
;
724 return (KMF_ERR_BAD_PARAMETER
);
726 kmf_set_attr_at_index(attlist
, i
,
727 KMF_KEYSTORE_TYPE_ATTR
, &kstype
,
732 kmf_set_attr_at_index(attlist
, i
,
733 KMF_TOKEN_LABEL_ATTR
, token
,
738 kmf_set_attr_at_index(attlist
, i
,
739 KMF_READONLY_ATTR
, &readonly
,
743 rv
= kmf_configure_keystore(kmfhandle
, i
, attlist
);
744 if (rv
== KMF_ERR_TOKEN_SELECTED
)
750 configure_nss(void *kmfhandle
, char *dir
, char *prefix
)
752 KMF_ATTRIBUTE attlist
[10];
754 KMF_KEYSTORE_TYPE kstype
= KMF_KEYSTORE_NSS
;
755 KMF_RETURN rv
= KMF_OK
;
757 kmf_set_attr_at_index(attlist
, i
,
758 KMF_KEYSTORE_TYPE_ATTR
, &kstype
,
763 kmf_set_attr_at_index(attlist
, i
,
764 KMF_DIRPATH_ATTR
, dir
,
770 kmf_set_attr_at_index(attlist
, i
,
771 KMF_CERTPREFIX_ATTR
, prefix
,
775 kmf_set_attr_at_index(attlist
, i
,
776 KMF_KEYPREFIX_ATTR
, prefix
,
781 rv
= kmf_configure_keystore(kmfhandle
, i
, attlist
);
782 if (rv
== KMF_KEYSTORE_ALREADY_INITIALIZED
)
789 get_pk12_password(KMF_CREDENTIAL
*cred
)
791 KMF_RETURN rv
= KMF_OK
;
795 * Get the password to use for the PK12 encryption.
797 (void) strlcpy(prompt
,
798 gettext("Enter password to use for "
799 "accessing the PKCS12 file: "), sizeof (prompt
));
801 if (get_pin(prompt
, NULL
, (uchar_t
**)&cred
->cred
,
802 (ulong_t
*)&cred
->credlen
) != CKR_OK
) {
810 #define FILENAME_PROMPT gettext("Filename:")
811 #define FILENAME_MINLEN 1
812 #define FILENAME_MAXLEN MAXPATHLEN
814 #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:")
815 #define STATE_PROMPT gettext("State or Province Name (full name) " \
817 #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:")
818 #define ORG_PROMPT gettext("Organization Name (eg, company) []:")
819 #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:")
820 #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:")
821 #define EMAIL_PROMPT gettext("Email Address []:")
823 #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \
825 #define SERNO_MINLEN 3
826 #define SERNO_MAXLEN 42
828 #define LABEL_PROMPT gettext("Enter a label for the certificate:")
829 #define LABEL_MINLEN 1
830 #define LABEL_MAXLEN 1024
832 #define COUNTRY_DEFAULT "US"
833 #define STATE_DEFAULT NULL
834 #define INVALID_INPUT gettext("Invalid input; please re-enter ...")
836 #define SUBNAMESIZ 1024
839 #define COUNTRYNAME_MIN 2
840 #define COUNTRYNAME_MAX 2
843 get_input_string(char *prompt
, char *default_str
, int min_len
, int max_len
)
846 char *response
= NULL
;
851 (void) printf("\t%s", prompt
);
852 (void) fflush(stdout
);
854 response
= fgets(buf
, sizeof (buf
), stdin
);
855 if (response
== NULL
) {
856 if (default_str
!= NULL
) {
857 ret
= strdup(default_str
);
862 /* Skip any leading white space. */
863 while (isspace(*response
))
865 if (*response
== '\0') {
866 if (default_str
!= NULL
) {
867 ret
= strdup(default_str
);
872 len
= strlen(response
);
873 response
[len
-1] = '\0'; /* get rid of "LF" */
875 if (len
>= min_len
&& len
<= max_len
) {
876 ret
= strdup(response
);
880 (void) printf("%s\n", INVALID_INPUT
);
888 get_filename(char *txt
, char **result
)
893 (void) snprintf(prompt
, sizeof (prompt
),
894 gettext("Enter filename for the %s: "),
896 fname
= get_input_string(prompt
, NULL
,
897 FILENAME_MINLEN
, FILENAME_MAXLEN
);
903 get_certlabel(char **result
)
907 label
= get_input_string(LABEL_PROMPT
, NULL
,
908 LABEL_MINLEN
, LABEL_MAXLEN
);
914 get_serial(char **result
)
918 serial
= get_input_string(SERNO_PROMPT
, NULL
, SERNO_MINLEN
,
926 get_subname(char **result
)
928 char *country
= NULL
;
930 char *locality
= NULL
;
935 char *subname
= NULL
;
937 (void) printf("Entering following fields for subject (a DN) ...\n");
938 country
= get_input_string(COUNTRY_PROMPT
, COUNTRY_DEFAULT
,
939 COUNTRYNAME_MIN
, COUNTRYNAME_MAX
);
943 state
= get_input_string(STATE_PROMPT
, STATE_DEFAULT
,
946 locality
= get_input_string(LOCALITY_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
947 org
= get_input_string(ORG_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
948 unit
= get_input_string(UNIT_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
949 name
= get_input_string(NAME_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
950 email
= get_input_string(EMAIL_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
952 /* Now create a subject name from the input strings */
953 if ((subname
= malloc(SUBNAMESIZ
)) == NULL
)
956 (void) memset(subname
, 0, SUBNAMESIZ
);
957 (void) strlcpy(subname
, "C=", SUBNAMESIZ
);
958 (void) strlcat(subname
, country
, SUBNAMESIZ
);
960 (void) strlcat(subname
, ", ST=", SUBNAMESIZ
);
961 (void) strlcat(subname
, state
, SUBNAMESIZ
);
964 if (locality
!= NULL
) {
965 (void) strlcat(subname
, ", L=", SUBNAMESIZ
);
966 (void) strlcat(subname
, locality
, SUBNAMESIZ
);
970 (void) strlcat(subname
, ", O=", SUBNAMESIZ
);
971 (void) strlcat(subname
, org
, SUBNAMESIZ
);
975 (void) strlcat(subname
, ", OU=", SUBNAMESIZ
);
976 (void) strlcat(subname
, unit
, SUBNAMESIZ
);
980 (void) strlcat(subname
, ", CN=", SUBNAMESIZ
);
981 (void) strlcat(subname
, name
, SUBNAMESIZ
);
985 (void) strlcat(subname
, ", E=", SUBNAMESIZ
);
986 (void) strlcat(subname
, email
, SUBNAMESIZ
);
1007 * Parse a string of KeyUsage values and convert
1008 * them to the correct KU Bits.
1009 * The field may be marked "critical" by prepending
1010 * "critical:" to the list.
1011 * EX: critical:digitialSignature,keyEncipherment
1014 verify_keyusage(char *kustr
, uint16_t *kubits
, int *critical
)
1016 KMF_RETURN ret
= KMF_OK
;
1021 if (kustr
== NULL
|| strlen(kustr
) == 0)
1022 return (KMF_ERR_BAD_PARAMETER
);
1024 /* Check to see if this is critical */
1025 if (strncasecmp(kustr
, "critical:", strlen("critical:")) == 0) {
1027 kustr
+= strlen("critical:");
1032 k
= strtok(kustr
, ",");
1034 kuval
= kmf_string_to_ku(k
);
1037 return (KMF_ERR_BAD_PARAMETER
);
1040 k
= strtok(NULL
, ",");
1047 * Verify the alternate subject label is real or invalid.
1049 * The field may be marked "critical" by prepending
1050 * "critical:" to the list.
1051 * EX: "critical:IP=1.2.3.4"
1054 verify_altname(char *arg
, KMF_GENERALNAMECHOICES
*type
, int *critical
)
1057 KMF_RETURN rv
= KMF_OK
;
1059 /* Check to see if this is critical */
1060 if (strncasecmp(arg
, "critical:", strlen("critical:")) == 0) {
1062 arg
+= strlen("critical:");
1067 /* Make sure there is an "=" sign */
1068 p
= strchr(arg
, '=');
1070 return (KMF_ERR_BAD_PARAMETER
);
1074 if (strcmp(arg
, "IP") == 0)
1075 *type
= GENNAME_IPADDRESS
;
1076 else if (strcmp(arg
, "DNS") == 0)
1077 *type
= GENNAME_DNSNAME
;
1078 else if (strcmp(arg
, "EMAIL") == 0)
1079 *type
= GENNAME_RFC822NAME
;
1080 else if (strcmp(arg
, "URI") == 0)
1081 *type
= GENNAME_URI
;
1082 else if (strcmp(arg
, "DN") == 0)
1083 *type
= GENNAME_DIRECTORYNAME
;
1084 else if (strcmp(arg
, "RID") == 0)
1085 *type
= GENNAME_REGISTEREDID
;
1086 else if (strcmp(arg
, "KRB") == 0)
1087 *type
= GENNAME_KRB5PRINC
;
1088 else if (strcmp(arg
, "UPN") == 0)
1089 *type
= GENNAME_SCLOGON_UPN
;
1091 rv
= KMF_ERR_BAD_PARAMETER
;
1099 get_token_password(KMF_KEYSTORE_TYPE kstype
,
1100 char *token_spec
, KMF_CREDENTIAL
*cred
)
1108 (void) memset(temptoken
, 0, sizeof (temptoken
));
1109 if (kstype
== KMF_KEYSTORE_PK11TOKEN
) {
1110 p
= strchr(token_spec
, ':');
1114 len
= strlen(token_spec
);
1115 if (len
> sizeof (temptoken
))
1116 len
= sizeof (temptoken
);
1118 (void) strncpy(temptoken
, token_spec
, len
);
1121 * Strip trailing whitespace
1123 t
= temptoken
+ (len
- 1);
1124 while (isspace(*t
) && t
>= temptoken
) {
1130 * Login to the token first.
1132 (void) snprintf(prompt
, sizeof (prompt
),
1133 gettext(DEFAULT_TOKEN_PROMPT
), temptoken
);
1135 if (get_pin(prompt
, NULL
, (uchar_t
**)&cred
->cred
,
1136 (ulong_t
*)&cred
->credlen
) != CKR_OK
) {
1141 if (kstype
== KMF_KEYSTORE_PK11TOKEN
&& p
!= NULL
)
1147 verify_file(char *filename
)
1149 KMF_RETURN ret
= KMF_OK
;
1153 * Attempt to open with the EXCL flag so that if
1154 * it already exists, the open will fail. It will
1155 * also fail if the file cannot be created due to
1156 * permissions on the parent directory, or if the
1157 * parent directory itself does not exist.
1159 fd
= open(filename
, O_CREAT
| O_EXCL
, 0600);
1161 if (errno
== EEXIST
)
1162 return (KMF_ERR_OPEN_FILE
);
1164 return (KMF_ERR_WRITE_FILE
);
1167 /* If we were able to create it, delete it. */
1169 (void) unlink(filename
);
1175 display_error(void *handle
, KMF_RETURN errcode
, char *prefix
)
1177 KMF_RETURN rv1
, rv2
;
1178 char *plugin_errmsg
= NULL
;
1179 char *kmf_errmsg
= NULL
;
1181 rv1
= kmf_get_plugin_error_str(handle
, &plugin_errmsg
);
1182 rv2
= kmf_get_kmf_error_str(errcode
, &kmf_errmsg
);
1184 cryptoerror(LOG_STDERR
, "%s:", prefix
);
1185 if (rv1
== KMF_OK
&& plugin_errmsg
) {
1186 cryptoerror(LOG_STDERR
, gettext("keystore error: %s"),
1188 kmf_free_str(plugin_errmsg
);
1191 if (rv2
== KMF_OK
&& kmf_errmsg
) {
1192 cryptoerror(LOG_STDERR
, gettext("libkmf error: %s"),
1194 kmf_free_str(kmf_errmsg
);
1197 if (rv1
!= KMF_OK
&& rv2
!= KMF_OK
)
1198 cryptoerror(LOG_STDERR
, gettext("<unknown error>\n"));
1203 addToEKUList(EKU_LIST
*ekus
, int critical
, KMF_OID
*newoid
)
1205 if (newoid
!= NULL
&& ekus
!= NULL
) {
1208 ekus
->critlist
= reallocarray(ekus
->critlist
,
1209 ekus
->eku_count
, sizeof (int));
1210 if (ekus
->critlist
!= NULL
)
1211 ekus
->critlist
[ekus
->eku_count
-1] = critical
;
1213 return (KMF_ERR_MEMORY
);
1215 ekus
->ekulist
= reallocarray(ekus
->ekulist
, ekus
->eku_count
,
1217 if (ekus
->ekulist
!= NULL
)
1218 ekus
->ekulist
[ekus
->eku_count
-1] = *newoid
;
1220 return (KMF_ERR_MEMORY
);
1226 free_eku_list(EKU_LIST
*ekus
)
1228 if (ekus
!= NULL
&& ekus
->eku_count
> 0) {
1230 for (i
= 0; i
< ekus
->eku_count
; i
++) {
1231 kmf_free_data(&ekus
->ekulist
[i
]);
1233 free(ekus
->ekulist
);
1234 free(ekus
->critlist
);
1240 parse_ekus(char *ekustr
, EKU_LIST
*ekus
)
1242 KMF_RETURN rv
= KMF_OK
;
1246 if (strncasecmp(ekustr
, "critical:",
1247 strlen("critical:")) == 0) {
1249 ekustr
+= strlen("critical:");
1253 newoid
= kmf_ekuname_to_oid(ekustr
);
1254 if (newoid
!= NULL
) {
1255 rv
= addToEKUList(ekus
, critical
, newoid
);
1265 verify_ekunames(char *ekuliststr
, EKU_LIST
**ekulist
)
1267 KMF_RETURN rv
= KMF_OK
;
1269 EKU_LIST
*ekus
= NULL
;
1271 if (ekuliststr
== NULL
|| strlen(ekuliststr
) == 0)
1274 ekus
= calloc(sizeof (EKU_LIST
), 1);
1276 return (KMF_ERR_MEMORY
);
1279 * The list should be comma separated list of EKU Names.
1281 p
= strtok(ekuliststr
, ",");
1283 /* If no tokens found, then maybe it's just a single EKU value */
1285 rv
= parse_ekus(ekuliststr
, ekus
);
1289 rv
= parse_ekus(p
, ekus
);
1293 p
= strtok(NULL
, ",");
1297 free_eku_list(ekus
);
1305 token_auth_needed(KMF_HANDLE_T handle
, char *tokenlabel
, int *auth
)
1313 rv
= kmf_pk11_token_lookup(handle
, tokenlabel
, &slot
);
1317 ckrv
= C_GetTokenInfo(slot
, &info
);
1319 return (KMF_ERR_INTERNAL
);
1321 *auth
= (info
.flags
& CKF_LOGIN_REQUIRED
);
1331 (void) printf(gettext("Supported ECC curve names:\n"));
1332 for (i
= 0; i
< number_of_curves
; i
++) {
1333 (void) printf("%s", oid_table
[i
].name
);
1334 if (i
> 0 && ((i
+1) % 5) == 0)
1335 (void) printf("\n");
1336 else if (i
+1 < number_of_curves
)
1337 (void) printf(", ");
1339 (void) printf("\n");
1343 ecc_name_to_oid(char *name
)
1346 for (i
= 0; i
< number_of_oids
; i
++) {
1347 if (strcasecmp(name
, oid_table
[i
].name
) == 0)
1348 return ((KMF_OID
*)oid_table
[i
].oid
);