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