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 implements the setpin operation for this tool.
30  * The basic flow of the process is to load the PKCS#11 module,
31  * finds the soft token, prompt the user for the old PIN (if
32  * any) and the new PIN, change the token's PIN, and clean up.
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <cryptoutil.h>
40 #include <security/cryptoki.h>
41 #include "common.h"
42 
43 static int
44 setpin_nss(KMF_HANDLE_T handle,
45 	char *token_spec, char *dir, char *prefix)
46 {
47 	int rv = 0;
48 	KMF_CREDENTIAL		oldcred = {NULL, 0};
49 	KMF_CREDENTIAL		newpincred = {NULL, 0};
50 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
51 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
52 	KMF_ATTRIBUTE		setpinattrs[6];
53 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_NSS;
54 	int			numattrs = 0;
55 
56 	rv = configure_nss(handle, dir, prefix);
57 	if (rv != KMF_OK)
58 		return (rv);
59 
60 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_KEYSTORE_TYPE_ATTR,
61 	    &kstype, sizeof (kstype));
62 	numattrs++;
63 	if (token_spec != NULL) {
64 		kmf_set_attr_at_index(setpinattrs, numattrs,
65 		    KMF_TOKEN_LABEL_ATTR,
66 		    token_spec, strlen(token_spec));
67 		numattrs++;
68 	}
69 
70 	if ((rv = get_pin(gettext("Enter current token passphrase "
71 	    "(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) != CKR_OK) {
72 		cryptoerror(LOG_STDERR,
73 		    gettext("Unable to get token passphrase."));
74 		return (PK_ERR_NSS);
75 	}
76 	/* Get the user's new PIN. */
77 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
78 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
79 		if (rv == CKR_PIN_INCORRECT)
80 			cryptoerror(LOG_STDERR, gettext(
81 			    "Passphrases do not match."));
82 		else
83 			cryptoerror(LOG_STDERR, gettext(
84 			    "Unable to get and confirm new passphrase."));
85 		if (old_pin != NULL)
86 			free(old_pin);
87 		return (PK_ERR_NSS);
88 	}
89 
90 	oldcred.cred = (char *)old_pin;
91 	oldcred.credlen = old_pinlen;
92 
93 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_CREDENTIAL_ATTR,
94 	    &oldcred, sizeof (oldcred));
95 	numattrs++;
96 
97 	newpincred.cred = (char *)new_pin;
98 	newpincred.credlen = new_pinlen;
99 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_NEWPIN_ATTR,
100 	    &newpincred, sizeof (newpincred));
101 	numattrs++;
102 
103 	rv = kmf_set_token_pin(handle, numattrs, setpinattrs);
104 
105 	if (new_pin)
106 		free(new_pin);
107 	if (old_pin)
108 		free(old_pin);
109 
110 	return (rv);
111 }
112 
113 static int
114 setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec)
115 {
116 	CK_SLOT_ID		slot_id;
117 	CK_FLAGS		pin_state;
118 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
119 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
120 	CK_RV			rv = CKR_OK;
121 	char			*token_name = NULL;
122 	CK_TOKEN_INFO		token_info;
123 	KMF_CREDENTIAL		newpincred = {NULL, 0};
124 	KMF_CREDENTIAL		oldcred = {NULL, 0};
125 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
126 	KMF_ATTRIBUTE		attrlist[6];
127 	int			numattr = 0;
128 
129 	/* If nothing is specified, default is to use softtoken. */
130 	if (token_spec == NULL) {
131 		token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID;
132 		token_name = SOFT_TOKEN_LABEL;
133 	}
134 
135 	rv = kmf_pk11_token_lookup(NULL, token_spec, &slot_id);
136 	if (rv == KMF_OK) {
137 		/* find the pin state for the selected token */
138 		if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK)
139 			return (PK_ERR_PK11);
140 
141 		pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED;
142 		if (token_name == NULL)
143 			token_name = (char *)token_info.label;
144 	}
145 
146 	/*
147 	 * If the token is the softtoken, check if the token flags show the
148 	 * PIN has not been set yet.  If not then set the old PIN to the
149 	 * default "changeme".  Otherwise, let user type in the correct old
150 	 * PIN to unlock token.
151 	 */
152 	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
153 	    strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
154 		if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
155 		    NULL) {
156 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
157 			final_pk11(NULL);
158 			return (PK_ERR_PK11);
159 		}
160 		old_pinlen = strlen(SOFT_DEFAULT_PIN);
161 	} else {
162 		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
163 		    &old_pin, &old_pinlen)) != CKR_OK) {
164 			cryptoerror(LOG_STDERR,
165 			    gettext("Unable to get token passphrase (%s)."),
166 			    pkcs11_strerror(rv));
167 			final_pk11(NULL);
168 			return (PK_ERR_PK11);
169 		}
170 	}
171 
172 	/* Get the user's new PIN. */
173 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
174 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
175 		if (rv == CKR_PIN_INCORRECT)
176 			cryptoerror(LOG_STDERR, gettext(
177 			    "Passphrases do not match."));
178 		else
179 			cryptoerror(LOG_STDERR, gettext(
180 			    "Unable to get and confirm new passphrase (%s)."),
181 			    pkcs11_strerror(rv));
182 		free(old_pin);
183 		final_pk11(NULL);
184 		return (PK_ERR_PK11);
185 	}
186 
187 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
188 	    &kstype, sizeof (kstype));
189 	numattr++;
190 	if (token_name != NULL) {
191 		kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR,
192 		    token_name, strlen(token_name));
193 		numattr++;
194 	}
195 	oldcred.cred = (char *)old_pin;
196 	oldcred.credlen = old_pinlen;
197 	kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR,
198 	    &oldcred, sizeof (oldcred));
199 	numattr++;
200 
201 	kmf_set_attr_at_index(attrlist, numattr, KMF_SLOT_ID_ATTR,
202 	    &slot_id, sizeof (slot_id));
203 	numattr++;
204 
205 	newpincred.cred = (char *)new_pin;
206 	newpincred.credlen = new_pinlen;
207 	kmf_set_attr_at_index(attrlist, numattr, KMF_NEWPIN_ATTR,
208 	    &newpincred, sizeof (newpincred));
209 	numattr++;
210 
211 	rv = kmf_set_token_pin(handle, numattr, attrlist);
212 
213 	/* Clean up. */
214 	if (old_pin != NULL)
215 		free(old_pin);
216 	if (new_pin != NULL)
217 		free(new_pin);
218 
219 	return (rv);
220 }
221 
222 /*
223  * Changes the token's PIN.
224  */
225 int
226 pk_setpin(int argc, char *argv[])
227 /* ARGSUSED */
228 {
229 	int		opt;
230 	int		rv;
231 	extern int	optind_av;
232 	extern char	*optarg_av;
233 	char		*token_spec = NULL;
234 	char		*dir = NULL;
235 	char		*prefix = NULL;
236 	KMF_HANDLE_T	handle;
237 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
238 
239 	/* Parse command line options.  Do NOT i18n/l10n. */
240 	while ((opt = getopt_av(argc, argv,
241 		"T:(token)k:(keystore)d:(dir)"
242 		"p:(prefix)")) != EOF) {
243 		switch (opt) {
244 			case 'k':
245 				kstype = KS2Int(optarg_av);
246 				if (kstype == 0)
247 					return (PK_ERR_USAGE);
248 				break;
249 			case 'T':	/* token specifier */
250 				if (token_spec)
251 					return (PK_ERR_USAGE);
252 				token_spec = optarg_av;
253 				break;
254 			case 'd':
255 				if (dir)
256 					return (PK_ERR_USAGE);
257 				dir = optarg_av;
258 				break;
259 			case 'p':
260 				if (prefix)
261 					return (PK_ERR_USAGE);
262 				prefix = optarg_av;
263 				break;
264 			default:
265 				return (PK_ERR_USAGE);
266 				break;
267 		}
268 	}
269 
270 
271 	/* No additional args allowed. */
272 	argc -= optind_av;
273 	argv += optind_av;
274 	if (argc != 0)
275 		return (PK_ERR_USAGE);
276 
277 	/* Done parsing command line options. */
278 	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
279 		token_spec = PK_DEFAULT_PK11TOKEN;
280 	} else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
281 		token_spec = DEFAULT_NSS_TOKEN;
282 	}
283 
284 	if ((rv = kmf_initialize(&handle, NULL, NULL)) != KMF_OK)
285 		return (rv);
286 
287 	switch (kstype) {
288 		case KMF_KEYSTORE_PK11TOKEN:
289 			rv = setpin_pkcs11(handle, token_spec);
290 			break;
291 		case KMF_KEYSTORE_NSS:
292 			rv = setpin_nss(handle, token_spec, dir, prefix);
293 			break;
294 		default:
295 			cryptoerror(LOG_STDERR,
296 			    gettext("incorrect keystore."));
297 			return (PK_ERR_USAGE);
298 	}
299 
300 	(void) kmf_finalize(handle);
301 
302 	if (rv == KMF_ERR_AUTH_FAILED) {
303 		cryptoerror(LOG_STDERR,
304 		    gettext("Incorrect passphrase."));
305 		return (PK_ERR_SYSTEM);
306 	} else if (rv != CKR_OK) {
307 		cryptoerror(LOG_STDERR,
308 		    gettext("Unable to change passphrase."));
309 		return (PK_ERR_SYSTEM);
310 	} else {
311 		(void) fprintf(stdout, gettext("Passphrase changed.\n"));
312 	}
313 	return (0);
314 }
315