setpin.c revision 3089:8ddeb2ace8aa
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 2006 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_SETPIN_PARAMS	params;
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
53	rv = configure_nss(handle, dir, prefix);
54	if (rv != KMF_OK)
55		return (rv);
56
57	(void) memset(&params, 0, sizeof (params));
58	params.kstype = KMF_KEYSTORE_NSS;
59	params.tokenname = token_spec;
60	params.nssparms.slotlabel = token_spec;
61
62	if ((rv = get_pin(gettext("Enter current token passphrase "
63		"(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) !=
64		CKR_OK) {
65		cryptoerror(LOG_STDERR,
66		    gettext("Unable to get token passphrase."));
67		return (PK_ERR_NSS);
68	}
69	/* Get the user's new PIN. */
70	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
71	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
72		if (rv == CKR_PIN_INCORRECT)
73			cryptoerror(LOG_STDERR, gettext(
74			    "Passphrases do not match."));
75		else
76			cryptoerror(LOG_STDERR, gettext(
77			    "Unable to get and confirm new passphrase."));
78		if (old_pin != NULL)
79			free(old_pin);
80		return (PK_ERR_NSS);
81	}
82
83	params.cred.cred = (char *)old_pin;
84	params.cred.credlen = old_pinlen;
85
86	newpincred.cred = (char *)new_pin;
87	newpincred.credlen = new_pinlen;
88
89	rv = KMF_SetTokenPin(handle, &params, &newpincred);
90
91	if (new_pin)
92		free(new_pin);
93	if (old_pin)
94		free(old_pin);
95
96	return (rv);
97}
98
99static int
100setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec)
101{
102	CK_SLOT_ID		slot_id;
103	CK_FLAGS		pin_state;
104	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
105	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
106	CK_RV			rv = CKR_OK;
107	char			*token_name = NULL;
108	KMF_SETPIN_PARAMS	params;
109	CK_TOKEN_INFO		token_info;
110	KMF_CREDENTIAL		newpincred = { NULL, 0 };
111
112	/* If nothing is specified, default is to use softtoken. */
113	if (token_spec == NULL) {
114		token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID;
115		token_name = SOFT_TOKEN_LABEL;
116	}
117
118	rv = KMF_PK11TokenLookup(NULL, token_spec, &slot_id);
119	if (rv == KMF_OK) {
120		/* find the pin state for the selected token */
121		if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK)
122			return (PK_ERR_PK11);
123
124		pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED;
125		if (token_name == NULL)
126			token_name = (char *)token_info.label;
127	}
128
129	/*
130	 * If the token is the softtoken, check if the token flags show the
131	 * PIN has not been set yet.  If not then set the old PIN to the
132	 * default "changeme".  Otherwise, let user type in the correct old
133	 * PIN to unlock token.
134	 */
135	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
136	    strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
137		if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
138		    NULL) {
139			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
140			final_pk11(NULL);
141			return (PK_ERR_PK11);
142		}
143		old_pinlen = strlen(SOFT_DEFAULT_PIN);
144	} else {
145		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
146		    &old_pin, &old_pinlen)) != CKR_OK) {
147			cryptoerror(LOG_STDERR,
148			    gettext("Unable to get token passphrase (%s)."),
149			    pkcs11_strerror(rv));
150			final_pk11(NULL);
151			return (PK_ERR_PK11);
152		}
153	}
154
155	/* Get the user's new PIN. */
156	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
157	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
158		if (rv == CKR_PIN_INCORRECT)
159			cryptoerror(LOG_STDERR, gettext(
160			    "Passphrases do not match."));
161		else
162			cryptoerror(LOG_STDERR, gettext(
163			    "Unable to get and confirm new passphrase (%s)."),
164			    pkcs11_strerror(rv));
165		free(old_pin);
166		final_pk11(NULL);
167		return (PK_ERR_PK11);
168	}
169
170	(void) memset(&params, 0, sizeof (params));
171	params.kstype = KMF_KEYSTORE_PK11TOKEN;
172	params.tokenname = (char *)token_info.label;
173	params.cred.cred = (char *)old_pin;
174	params.cred.credlen = old_pinlen;
175	params.pkcs11parms.slot = slot_id;
176
177	newpincred.cred = (char *)new_pin;
178	newpincred.credlen = new_pinlen;
179
180	rv = KMF_SetTokenPin(handle, &params, &newpincred);
181
182	/* Clean up. */
183	if (old_pin != NULL)
184		free(old_pin);
185	if (new_pin != NULL)
186		free(new_pin);
187
188	return (rv);
189}
190
191/*
192 * Changes the token's PIN.
193 */
194int
195pk_setpin(int argc, char *argv[])
196/* ARGSUSED */
197{
198	int		opt;
199	int		rv;
200	extern int	optind_av;
201	extern char	*optarg_av;
202	char		*token_spec = NULL;
203	char		*dir = NULL;
204	char		*prefix = NULL;
205	KMF_HANDLE_T	handle;
206	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
207
208	/* Parse command line options.  Do NOT i18n/l10n. */
209	while ((opt = getopt_av(argc, argv,
210		"T:(token)k:(keystore)d:(dir)"
211		"p:(prefix)")) != EOF) {
212		switch (opt) {
213			case 'k':
214				kstype = KS2Int(optarg_av);
215				if (kstype == 0)
216					return (PK_ERR_USAGE);
217				break;
218			case 'T':	/* token specifier */
219				if (token_spec)
220					return (PK_ERR_USAGE);
221				token_spec = optarg_av;
222				break;
223			case 'd':
224				if (dir)
225					return (PK_ERR_USAGE);
226				dir = optarg_av;
227				break;
228			case 'p':
229				if (prefix)
230					return (PK_ERR_USAGE);
231				prefix = optarg_av;
232				break;
233			default:
234				return (PK_ERR_USAGE);
235				break;
236		}
237	}
238
239
240	/* No additional args allowed. */
241	argc -= optind_av;
242	argv += optind_av;
243	if (argc != 0)
244		return (PK_ERR_USAGE);
245
246	/* Done parsing command line options. */
247	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
248		token_spec = PK_DEFAULT_PK11TOKEN;
249	} else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
250		token_spec = DEFAULT_NSS_TOKEN;
251	}
252
253	if ((rv = KMF_Initialize(&handle, NULL, NULL)) != KMF_OK)
254		return (rv);
255
256	switch (kstype) {
257		case KMF_KEYSTORE_PK11TOKEN:
258			rv = setpin_pkcs11(handle, token_spec);
259			break;
260		case KMF_KEYSTORE_NSS:
261			rv = setpin_nss(handle, token_spec, dir, prefix);
262			break;
263		default:
264			cryptoerror(LOG_STDERR,
265				gettext("incorrect keystore."));
266			return (PK_ERR_USAGE);
267	}
268
269	(void) KMF_Finalize(handle);
270
271	if (rv == KMF_ERR_AUTH_FAILED) {
272		cryptoerror(LOG_STDERR,
273		    gettext("Incorrect passphrase."));
274		return (PK_ERR_SYSTEM);
275	} else if (rv != CKR_OK) {
276		cryptoerror(LOG_STDERR,
277		    gettext("Unable to change passphrase."));
278		return (PK_ERR_SYSTEM);
279	} else {
280		(void) fprintf(stdout, gettext("Passphrase changed.\n"));
281	}
282	return (0);
283}
284