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
= (CK_SLOT_ID_PTR
) realloc(tmp_list
,
374 tmp_count
* 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 realloc(opts_av
, (i
+1) * sizeof (av_opts
)))) == NULL
) {
413 opts_av
= (av_opts
*)temp
;
416 (void) memset(&opts_av
[i
], 0, sizeof (av_opts
));
417 marker
= optstring
; /* may need optstring later */
419 opts_av
[i
].shortnm
= *marker
++; /* set short name */
421 if (*marker
== ':') { /* check for opt arg */
423 opts_av
[i
].has_arg
= B_TRUE
;
426 if (*marker
== '(') { /* check and set long name */
428 opts_av
[i
].longnm
= marker
;
429 opts_av
[i
].longnm_len
= strcspn(marker
, ")");
430 optstring
= marker
+ opts_av
[i
].longnm_len
+ 1;
432 /* use short name option character */
433 opts_av
[i
].longnm
= optstring
;
434 opts_av
[i
].longnm_len
= 1;
443 * getopt_av() is very similar to getopt(3c) in that the takes an option
444 * string, compares command line arguments for matches, and returns a single
445 * letter option when a match is found. However, getopt_av() differs from
446 * getopt(3c) by requiring that only longname options and values be found
447 * on the command line and all leading dashes are omitted. In other words,
448 * it tries to enforce only longname "option=value" arguments on the command
449 * line. Boolean options are not allowed either.
452 getopt_av(int argc
, char * const *argv
, const char *optstring
)
458 if (optind_av
>= argc
)
461 /* First time or when optstring changes from previous one */
462 if (_save_optstr
!= optstring
) {
466 _save_optstr
= optstring
;
467 _save_numopts
= populate_opts((char *)optstring
);
470 for (i
= 0; i
< _save_numopts
; i
++) {
471 cur_option
= argv
[optind_av
];
473 if (strcmp(cur_option
, "--") == 0) {
478 if (cur_option
[0] == '-' && strlen(cur_option
) == 2) {
480 cur_option
++; /* remove "-" */
482 len
= strcspn(cur_option
, "=");
485 if (len
== opts_av
[i
].longnm_len
&& strncmp(cur_option
,
486 opts_av
[i
].longnm
, opts_av
[i
].longnm_len
) == 0) {
488 if (!opts_av
[i
].has_arg
) {
490 return (opts_av
[i
].shortnm
);
494 if (cur_option
[len
] == '=') {
495 optarg_av
= &(cur_option
[len
+1]);
497 return (opts_av
[i
].shortnm
);
510 KS2Int(char *keystore_str
)
512 if (keystore_str
== NULL
)
514 if (strcasecmp(keystore_str
, "pkcs11") == 0)
515 return (KMF_KEYSTORE_PK11TOKEN
);
516 else if (strcasecmp(keystore_str
, "nss") == 0)
517 return (KMF_KEYSTORE_NSS
);
518 else if (strcasecmp(keystore_str
, "file") == 0)
519 return (KMF_KEYSTORE_OPENSSL
);
529 compare_oids(KMF_OID
*oid1
, const KMF_OID
*oid2
)
531 return ((oid1
->Length
== oid2
->Length
) &&
532 !memcmp(oid1
->Data
, oid2
->Data
, oid1
->Length
));
536 Str2KeyType(char *algm
, KMF_OID
*hashoid
, KMF_KEY_ALG
*ktype
,
537 KMF_ALGORITHM_INDEX
*sigAlg
)
540 /* Default to SHA1+RSA */
541 *sigAlg
= KMF_ALGID_SHA1WithRSA
;
543 } else if (strcasecmp(algm
, "DSA") == 0) {
544 if (hashoid
== NULL
||
545 compare_oids(hashoid
, &KMFOID_SHA1
))
546 *sigAlg
= KMF_ALGID_SHA1WithDSA
;
547 else if (compare_oids(hashoid
, &KMFOID_SHA256
))
548 *sigAlg
= KMF_ALGID_SHA256WithDSA
;
550 return (-1); /* unsupported hash/key combo */
552 } else if (strcasecmp(algm
, "RSA") == 0) {
553 if (hashoid
== NULL
||
554 compare_oids(hashoid
, &KMFOID_SHA1
))
555 *sigAlg
= KMF_ALGID_SHA1WithRSA
;
556 else if (compare_oids(hashoid
, &KMFOID_SHA256
))
557 *sigAlg
= KMF_ALGID_SHA256WithRSA
;
558 else if (compare_oids(hashoid
, &KMFOID_SHA384
))
559 *sigAlg
= KMF_ALGID_SHA384WithRSA
;
560 else if (compare_oids(hashoid
, &KMFOID_SHA512
))
561 *sigAlg
= KMF_ALGID_SHA512WithRSA
;
562 else if (compare_oids(hashoid
, &KMFOID_MD5
))
563 *sigAlg
= KMF_ALGID_MD5WithRSA
;
565 return (-1); /* unsupported hash/key combo */
567 } else if (strcasecmp(algm
, "EC") == 0) {
568 /* EC keys may be used with some SHA2 hashes */
569 if (hashoid
== NULL
||
570 compare_oids(hashoid
, &KMFOID_SHA1
))
571 *sigAlg
= KMF_ALGID_SHA1WithECDSA
;
572 else if (compare_oids(hashoid
, &KMFOID_SHA256
))
573 *sigAlg
= KMF_ALGID_SHA256WithECDSA
;
574 else if (compare_oids(hashoid
, &KMFOID_SHA384
))
575 *sigAlg
= KMF_ALGID_SHA384WithECDSA
;
576 else if (compare_oids(hashoid
, &KMFOID_SHA512
))
577 *sigAlg
= KMF_ALGID_SHA512WithECDSA
;
579 return (-1); /* unsupported hash/key combo */
589 Str2SymKeyType(char *algm
, KMF_KEY_ALG
*ktype
)
593 else if (strcasecmp(algm
, "aes") == 0)
595 else if (strcasecmp(algm
, "arcfour") == 0)
597 else if (strcasecmp(algm
, "des") == 0)
599 else if (strcasecmp(algm
, "3des") == 0)
601 else if (strcasecmp(algm
, "generic") == 0)
602 *ktype
= KMF_GENERIC_SECRET
;
610 Str2Lifetime(char *ltimestr
, uint32_t *ltime
)
615 if (ltimestr
== NULL
|| strlen(ltimestr
) == 0) {
616 /* default to 1 year lifetime */
617 *ltime
= SECSPERDAY
* DAYSPERNYEAR
;
621 (void) memset(timetok
, 0, sizeof (timetok
));
622 if (sscanf(ltimestr
, "%d-%06s", &num
, timetok
) != 2)
625 if (strcasecmp(timetok
, "day") == 0||
626 strcasecmp(timetok
, "days") == 0) {
627 *ltime
= num
* SECSPERDAY
;
628 } else if (strcasecmp(timetok
, "hour") == 0||
629 strcasecmp(timetok
, "hours") == 0) {
630 *ltime
= num
* SECSPERHOUR
;
631 } else if (strcasecmp(timetok
, "year") == 0 ||
632 strcasecmp(timetok
, "years") == 0) {
633 *ltime
= num
* SECSPERDAY
* DAYSPERNYEAR
;
643 OT2Int(char *objclass
)
648 if (objclass
== NULL
)
651 c
= strchr(objclass
, ':');
653 if (strcasecmp(c
, ":private") == 0)
654 retval
= PK_PRIVATE_OBJ
;
655 else if (strcasecmp(c
, ":public") == 0)
656 retval
= PK_PUBLIC_OBJ
;
657 else if (strcasecmp(c
, ":both") == 0)
658 retval
= PK_PRIVATE_OBJ
| PK_PUBLIC_OBJ
;
659 else /* unrecognized option */
665 if (strcasecmp(objclass
, "public") == 0) {
668 return (retval
| PK_PUBLIC_OBJ
| PK_CERT_OBJ
| PK_PUBKEY_OBJ
);
669 } else if (strcasecmp(objclass
, "private") == 0) {
672 return (retval
| PK_PRIKEY_OBJ
| PK_PRIVATE_OBJ
);
673 } else if (strcasecmp(objclass
, "both") == 0) {
676 return (PK_KEY_OBJ
| PK_PUBLIC_OBJ
| PK_PRIVATE_OBJ
);
677 } else if (strcasecmp(objclass
, "cert") == 0) {
678 return (retval
| PK_CERT_OBJ
);
679 } else if (strcasecmp(objclass
, "key") == 0) {
680 if (retval
== 0) /* return all keys */
681 return (retval
| PK_KEY_OBJ
);
682 else if (retval
== (PK_PRIVATE_OBJ
| PK_PUBLIC_OBJ
))
683 /* return all keys */
684 return (retval
| PK_KEY_OBJ
);
685 else if (retval
& PK_PUBLIC_OBJ
)
686 /* Only return public keys */
687 return (retval
| PK_PUBKEY_OBJ
);
688 else if (retval
& PK_PRIVATE_OBJ
)
689 /* Only return private keys */
690 return (retval
| PK_PRIKEY_OBJ
);
691 } else if (strcasecmp(objclass
, "crl") == 0) {
694 return (retval
| PK_CRL_OBJ
);
697 if (retval
== 0) /* No matches found */
703 Str2Format(char *formstr
)
705 if (formstr
== NULL
|| strcasecmp(formstr
, "der") == 0)
706 return (KMF_FORMAT_ASN1
);
707 if (strcasecmp(formstr
, "pem") == 0)
708 return (KMF_FORMAT_PEM
);
709 if (strcasecmp(formstr
, "pkcs12") == 0)
710 return (KMF_FORMAT_PKCS12
);
711 if (strcasecmp(formstr
, "raw") == 0)
712 return (KMF_FORMAT_RAWKEY
);
714 return (KMF_FORMAT_UNDEF
);
718 select_token(void *kmfhandle
, char *token
, int readonly
)
720 KMF_ATTRIBUTE attlist
[10];
722 KMF_KEYSTORE_TYPE kstype
= KMF_KEYSTORE_PK11TOKEN
;
723 KMF_RETURN rv
= KMF_OK
;
726 return (KMF_ERR_BAD_PARAMETER
);
728 kmf_set_attr_at_index(attlist
, i
,
729 KMF_KEYSTORE_TYPE_ATTR
, &kstype
,
734 kmf_set_attr_at_index(attlist
, i
,
735 KMF_TOKEN_LABEL_ATTR
, token
,
740 kmf_set_attr_at_index(attlist
, i
,
741 KMF_READONLY_ATTR
, &readonly
,
745 rv
= kmf_configure_keystore(kmfhandle
, i
, attlist
);
746 if (rv
== KMF_ERR_TOKEN_SELECTED
)
752 configure_nss(void *kmfhandle
, char *dir
, char *prefix
)
754 KMF_ATTRIBUTE attlist
[10];
756 KMF_KEYSTORE_TYPE kstype
= KMF_KEYSTORE_NSS
;
757 KMF_RETURN rv
= KMF_OK
;
759 kmf_set_attr_at_index(attlist
, i
,
760 KMF_KEYSTORE_TYPE_ATTR
, &kstype
,
765 kmf_set_attr_at_index(attlist
, i
,
766 KMF_DIRPATH_ATTR
, dir
,
772 kmf_set_attr_at_index(attlist
, i
,
773 KMF_CERTPREFIX_ATTR
, prefix
,
777 kmf_set_attr_at_index(attlist
, i
,
778 KMF_KEYPREFIX_ATTR
, prefix
,
783 rv
= kmf_configure_keystore(kmfhandle
, i
, attlist
);
784 if (rv
== KMF_KEYSTORE_ALREADY_INITIALIZED
)
791 get_pk12_password(KMF_CREDENTIAL
*cred
)
793 KMF_RETURN rv
= KMF_OK
;
797 * Get the password to use for the PK12 encryption.
799 (void) strlcpy(prompt
,
800 gettext("Enter password to use for "
801 "accessing the PKCS12 file: "), sizeof (prompt
));
803 if (get_pin(prompt
, NULL
, (uchar_t
**)&cred
->cred
,
804 (ulong_t
*)&cred
->credlen
) != CKR_OK
) {
812 #define FILENAME_PROMPT gettext("Filename:")
813 #define FILENAME_MINLEN 1
814 #define FILENAME_MAXLEN MAXPATHLEN
816 #define COUNTRY_PROMPT gettext("Country Name (2 letter code) [US]:")
817 #define STATE_PROMPT gettext("State or Province Name (full name) " \
819 #define LOCALITY_PROMPT gettext("Locality Name (eg, city) []:")
820 #define ORG_PROMPT gettext("Organization Name (eg, company) []:")
821 #define UNIT_PROMPT gettext("Organizational Unit Name (eg, section) []:")
822 #define NAME_PROMPT gettext("Common Name (eg, YOUR name) []:")
823 #define EMAIL_PROMPT gettext("Email Address []:")
825 #define SERNO_PROMPT gettext("Serial Number (hex value, example: " \
827 #define SERNO_MINLEN 3
828 #define SERNO_MAXLEN 42
830 #define LABEL_PROMPT gettext("Enter a label for the certificate:")
831 #define LABEL_MINLEN 1
832 #define LABEL_MAXLEN 1024
834 #define COUNTRY_DEFAULT "US"
835 #define STATE_DEFAULT NULL
836 #define INVALID_INPUT gettext("Invalid input; please re-enter ...")
838 #define SUBNAMESIZ 1024
841 #define COUNTRYNAME_MIN 2
842 #define COUNTRYNAME_MAX 2
845 get_input_string(char *prompt
, char *default_str
, int min_len
, int max_len
)
848 char *response
= NULL
;
853 (void) printf("\t%s", prompt
);
854 (void) fflush(stdout
);
856 response
= fgets(buf
, sizeof (buf
), stdin
);
857 if (response
== NULL
) {
858 if (default_str
!= NULL
) {
859 ret
= strdup(default_str
);
864 /* Skip any leading white space. */
865 while (isspace(*response
))
867 if (*response
== '\0') {
868 if (default_str
!= NULL
) {
869 ret
= strdup(default_str
);
874 len
= strlen(response
);
875 response
[len
-1] = '\0'; /* get rid of "LF" */
877 if (len
>= min_len
&& len
<= max_len
) {
878 ret
= strdup(response
);
882 (void) printf("%s\n", INVALID_INPUT
);
890 get_filename(char *txt
, char **result
)
895 (void) snprintf(prompt
, sizeof (prompt
),
896 gettext("Enter filename for the %s: "),
898 fname
= get_input_string(prompt
, NULL
,
899 FILENAME_MINLEN
, FILENAME_MAXLEN
);
905 get_certlabel(char **result
)
909 label
= get_input_string(LABEL_PROMPT
, NULL
,
910 LABEL_MINLEN
, LABEL_MAXLEN
);
916 get_serial(char **result
)
920 serial
= get_input_string(SERNO_PROMPT
, NULL
, SERNO_MINLEN
,
928 get_subname(char **result
)
930 char *country
= NULL
;
932 char *locality
= NULL
;
937 char *subname
= NULL
;
939 (void) printf("Entering following fields for subject (a DN) ...\n");
940 country
= get_input_string(COUNTRY_PROMPT
, COUNTRY_DEFAULT
,
941 COUNTRYNAME_MIN
, COUNTRYNAME_MAX
);
945 state
= get_input_string(STATE_PROMPT
, STATE_DEFAULT
,
948 locality
= get_input_string(LOCALITY_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
949 org
= get_input_string(ORG_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
950 unit
= get_input_string(UNIT_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
951 name
= get_input_string(NAME_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
952 email
= get_input_string(EMAIL_PROMPT
, NULL
, RDN_MIN
, RDN_MAX
);
954 /* Now create a subject name from the input strings */
955 if ((subname
= malloc(SUBNAMESIZ
)) == NULL
)
958 (void) memset(subname
, 0, SUBNAMESIZ
);
959 (void) strlcpy(subname
, "C=", SUBNAMESIZ
);
960 (void) strlcat(subname
, country
, SUBNAMESIZ
);
962 (void) strlcat(subname
, ", ST=", SUBNAMESIZ
);
963 (void) strlcat(subname
, state
, SUBNAMESIZ
);
966 if (locality
!= NULL
) {
967 (void) strlcat(subname
, ", L=", SUBNAMESIZ
);
968 (void) strlcat(subname
, locality
, SUBNAMESIZ
);
972 (void) strlcat(subname
, ", O=", SUBNAMESIZ
);
973 (void) strlcat(subname
, org
, SUBNAMESIZ
);
977 (void) strlcat(subname
, ", OU=", SUBNAMESIZ
);
978 (void) strlcat(subname
, unit
, SUBNAMESIZ
);
982 (void) strlcat(subname
, ", CN=", SUBNAMESIZ
);
983 (void) strlcat(subname
, name
, SUBNAMESIZ
);
987 (void) strlcat(subname
, ", E=", SUBNAMESIZ
);
988 (void) strlcat(subname
, email
, SUBNAMESIZ
);
1007 if (subname
== NULL
)
1016 * Parse a string of KeyUsage values and convert
1017 * them to the correct KU Bits.
1018 * The field may be marked "critical" by prepending
1019 * "critical:" to the list.
1020 * EX: critical:digitialSignature,keyEncipherment
1023 verify_keyusage(char *kustr
, uint16_t *kubits
, int *critical
)
1025 KMF_RETURN ret
= KMF_OK
;
1030 if (kustr
== NULL
|| strlen(kustr
) == 0)
1031 return (KMF_ERR_BAD_PARAMETER
);
1033 /* Check to see if this is critical */
1034 if (strncasecmp(kustr
, "critical:", strlen("critical:")) == 0) {
1036 kustr
+= strlen("critical:");
1041 k
= strtok(kustr
, ",");
1043 kuval
= kmf_string_to_ku(k
);
1046 return (KMF_ERR_BAD_PARAMETER
);
1049 k
= strtok(NULL
, ",");
1056 * Verify the alternate subject label is real or invalid.
1058 * The field may be marked "critical" by prepending
1059 * "critical:" to the list.
1060 * EX: "critical:IP=1.2.3.4"
1063 verify_altname(char *arg
, KMF_GENERALNAMECHOICES
*type
, int *critical
)
1066 KMF_RETURN rv
= KMF_OK
;
1068 /* Check to see if this is critical */
1069 if (strncasecmp(arg
, "critical:", strlen("critical:")) == 0) {
1071 arg
+= strlen("critical:");
1076 /* Make sure there is an "=" sign */
1077 p
= strchr(arg
, '=');
1079 return (KMF_ERR_BAD_PARAMETER
);
1083 if (strcmp(arg
, "IP") == 0)
1084 *type
= GENNAME_IPADDRESS
;
1085 else if (strcmp(arg
, "DNS") == 0)
1086 *type
= GENNAME_DNSNAME
;
1087 else if (strcmp(arg
, "EMAIL") == 0)
1088 *type
= GENNAME_RFC822NAME
;
1089 else if (strcmp(arg
, "URI") == 0)
1090 *type
= GENNAME_URI
;
1091 else if (strcmp(arg
, "DN") == 0)
1092 *type
= GENNAME_DIRECTORYNAME
;
1093 else if (strcmp(arg
, "RID") == 0)
1094 *type
= GENNAME_REGISTEREDID
;
1095 else if (strcmp(arg
, "KRB") == 0)
1096 *type
= GENNAME_KRB5PRINC
;
1097 else if (strcmp(arg
, "UPN") == 0)
1098 *type
= GENNAME_SCLOGON_UPN
;
1100 rv
= KMF_ERR_BAD_PARAMETER
;
1108 get_token_password(KMF_KEYSTORE_TYPE kstype
,
1109 char *token_spec
, KMF_CREDENTIAL
*cred
)
1117 (void) memset(temptoken
, 0, sizeof (temptoken
));
1118 if (kstype
== KMF_KEYSTORE_PK11TOKEN
) {
1119 p
= strchr(token_spec
, ':');
1123 len
= strlen(token_spec
);
1124 if (len
> sizeof (temptoken
))
1125 len
= sizeof (temptoken
);
1127 (void) strncpy(temptoken
, token_spec
, len
);
1130 * Strip trailing whitespace
1132 t
= temptoken
+ (len
- 1);
1133 while (isspace(*t
) && t
>= temptoken
) {
1139 * Login to the token first.
1141 (void) snprintf(prompt
, sizeof (prompt
),
1142 gettext(DEFAULT_TOKEN_PROMPT
), temptoken
);
1144 if (get_pin(prompt
, NULL
, (uchar_t
**)&cred
->cred
,
1145 (ulong_t
*)&cred
->credlen
) != CKR_OK
) {
1150 if (kstype
== KMF_KEYSTORE_PK11TOKEN
&& p
!= NULL
)
1156 verify_file(char *filename
)
1158 KMF_RETURN ret
= KMF_OK
;
1162 * Attempt to open with the EXCL flag so that if
1163 * it already exists, the open will fail. It will
1164 * also fail if the file cannot be created due to
1165 * permissions on the parent directory, or if the
1166 * parent directory itself does not exist.
1168 fd
= open(filename
, O_CREAT
| O_EXCL
, 0600);
1170 if (errno
== EEXIST
)
1171 return (KMF_ERR_OPEN_FILE
);
1173 return (KMF_ERR_WRITE_FILE
);
1176 /* If we were able to create it, delete it. */
1178 (void) unlink(filename
);
1184 display_error(void *handle
, KMF_RETURN errcode
, char *prefix
)
1186 KMF_RETURN rv1
, rv2
;
1187 char *plugin_errmsg
= NULL
;
1188 char *kmf_errmsg
= NULL
;
1190 rv1
= kmf_get_plugin_error_str(handle
, &plugin_errmsg
);
1191 rv2
= kmf_get_kmf_error_str(errcode
, &kmf_errmsg
);
1193 cryptoerror(LOG_STDERR
, "%s:", prefix
);
1194 if (rv1
== KMF_OK
&& plugin_errmsg
) {
1195 cryptoerror(LOG_STDERR
, gettext("keystore error: %s"),
1197 kmf_free_str(plugin_errmsg
);
1200 if (rv2
== KMF_OK
&& kmf_errmsg
) {
1201 cryptoerror(LOG_STDERR
, gettext("libkmf error: %s"),
1203 kmf_free_str(kmf_errmsg
);
1206 if (rv1
!= KMF_OK
&& rv2
!= KMF_OK
)
1207 cryptoerror(LOG_STDERR
, gettext("<unknown error>\n"));
1212 addToEKUList(EKU_LIST
*ekus
, int critical
, KMF_OID
*newoid
)
1214 if (newoid
!= NULL
&& ekus
!= NULL
) {
1217 ekus
->critlist
= realloc(ekus
->critlist
,
1218 ekus
->eku_count
* sizeof (int));
1219 if (ekus
->critlist
!= NULL
)
1220 ekus
->critlist
[ekus
->eku_count
-1] = critical
;
1222 return (KMF_ERR_MEMORY
);
1224 ekus
->ekulist
= realloc(
1225 ekus
->ekulist
, ekus
->eku_count
* sizeof (KMF_OID
));
1226 if (ekus
->ekulist
!= NULL
)
1227 ekus
->ekulist
[ekus
->eku_count
-1] = *newoid
;
1229 return (KMF_ERR_MEMORY
);
1235 free_eku_list(EKU_LIST
*ekus
)
1237 if (ekus
!= NULL
&& ekus
->eku_count
> 0) {
1239 for (i
= 0; i
< ekus
->eku_count
; i
++) {
1240 kmf_free_data(&ekus
->ekulist
[i
]);
1242 free(ekus
->ekulist
);
1243 free(ekus
->critlist
);
1249 parse_ekus(char *ekustr
, EKU_LIST
*ekus
)
1251 KMF_RETURN rv
= KMF_OK
;
1255 if (strncasecmp(ekustr
, "critical:",
1256 strlen("critical:")) == 0) {
1258 ekustr
+= strlen("critical:");
1262 newoid
= kmf_ekuname_to_oid(ekustr
);
1263 if (newoid
!= NULL
) {
1264 rv
= addToEKUList(ekus
, critical
, newoid
);
1274 verify_ekunames(char *ekuliststr
, EKU_LIST
**ekulist
)
1276 KMF_RETURN rv
= KMF_OK
;
1278 EKU_LIST
*ekus
= NULL
;
1280 if (ekuliststr
== NULL
|| strlen(ekuliststr
) == 0)
1283 ekus
= calloc(sizeof (EKU_LIST
), 1);
1285 return (KMF_ERR_MEMORY
);
1288 * The list should be comma separated list of EKU Names.
1290 p
= strtok(ekuliststr
, ",");
1292 /* If no tokens found, then maybe it's just a single EKU value */
1294 rv
= parse_ekus(ekuliststr
, ekus
);
1298 rv
= parse_ekus(p
, ekus
);
1302 p
= strtok(NULL
, ",");
1306 free_eku_list(ekus
);
1314 token_auth_needed(KMF_HANDLE_T handle
, char *tokenlabel
, int *auth
)
1322 rv
= kmf_pk11_token_lookup(handle
, tokenlabel
, &slot
);
1326 ckrv
= C_GetTokenInfo(slot
, &info
);
1328 return (KMF_ERR_INTERNAL
);
1330 *auth
= (info
.flags
& CKF_LOGIN_REQUIRED
);
1340 (void) printf(gettext("Supported ECC curve names:\n"));
1341 for (i
= 0; i
< number_of_curves
; i
++) {
1342 (void) printf("%s", oid_table
[i
].name
);
1343 if (i
> 0 && ((i
+1) % 5) == 0)
1344 (void) printf("\n");
1345 else if (i
+1 < number_of_curves
)
1346 (void) printf(", ");
1348 (void) printf("\n");
1352 ecc_name_to_oid(char *name
)
1355 for (i
= 0; i
< number_of_oids
; i
++) {
1356 if (strcasecmp(name
, oid_table
[i
].name
) == 0)
1357 return ((KMF_OID
*)oid_table
[i
].oid
);