xref: /illumos-gate/usr/src/cmd/cmd-crypto/pktool/setpin.c (revision cb6207858a9fcc2feaee22e626912fba281ac969)
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 
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_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 
99 static int
100 setpin_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  */
194 int
195 pk_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