setpin.c revision 5051:cbbb7c8b40a9
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
43static int
44setpin_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
113static int
114setpin_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 */
225int
226pk_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