xref: /onnv-gate/usr/src/cmd/cmd-crypto/pktool/setpin.c (revision 3089:8ddeb2ace8aa)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3089Swyllys  * Common Development and Distribution License (the "License").
6*3089Swyllys  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3089Swyllys  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * This file implements the setpin operation for this tool.
300Sstevel@tonic-gate  * The basic flow of the process is to load the PKCS#11 module,
3117Sdinak  * finds the soft token, prompt the user for the old PIN (if
3217Sdinak  * any) and the new PIN, change the token's PIN, and clean up.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <stdlib.h>
3717Sdinak #include <errno.h>
380Sstevel@tonic-gate #include <string.h>
390Sstevel@tonic-gate #include <cryptoutil.h>
400Sstevel@tonic-gate #include <security/cryptoki.h>
410Sstevel@tonic-gate #include "common.h"
420Sstevel@tonic-gate 
43*3089Swyllys static int
44*3089Swyllys setpin_nss(KMF_HANDLE_T handle,
45*3089Swyllys 	char *token_spec, char *dir, char *prefix)
460Sstevel@tonic-gate {
47*3089Swyllys 	int rv = 0;
48*3089Swyllys 	KMF_SETPIN_PARAMS	params;
49*3089Swyllys 	KMF_CREDENTIAL		newpincred = { NULL, 0 };
50*3089Swyllys 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
51*3089Swyllys 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
52*3089Swyllys 
53*3089Swyllys 	rv = configure_nss(handle, dir, prefix);
54*3089Swyllys 	if (rv != KMF_OK)
55*3089Swyllys 		return (rv);
56*3089Swyllys 
57*3089Swyllys 	(void) memset(&params, 0, sizeof (params));
58*3089Swyllys 	params.kstype = KMF_KEYSTORE_NSS;
59*3089Swyllys 	params.tokenname = token_spec;
60*3089Swyllys 	params.nssparms.slotlabel = token_spec;
61*3089Swyllys 
62*3089Swyllys 	if ((rv = get_pin(gettext("Enter current token passphrase "
63*3089Swyllys 		"(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) !=
64*3089Swyllys 		CKR_OK) {
65*3089Swyllys 		cryptoerror(LOG_STDERR,
66*3089Swyllys 		    gettext("Unable to get token passphrase."));
67*3089Swyllys 		return (PK_ERR_NSS);
68*3089Swyllys 	}
69*3089Swyllys 	/* Get the user's new PIN. */
70*3089Swyllys 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
71*3089Swyllys 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
72*3089Swyllys 		if (rv == CKR_PIN_INCORRECT)
73*3089Swyllys 			cryptoerror(LOG_STDERR, gettext(
74*3089Swyllys 			    "Passphrases do not match."));
75*3089Swyllys 		else
76*3089Swyllys 			cryptoerror(LOG_STDERR, gettext(
77*3089Swyllys 			    "Unable to get and confirm new passphrase."));
78*3089Swyllys 		if (old_pin != NULL)
79*3089Swyllys 			free(old_pin);
80*3089Swyllys 		return (PK_ERR_NSS);
81*3089Swyllys 	}
82*3089Swyllys 
83*3089Swyllys 	params.cred.cred = (char *)old_pin;
84*3089Swyllys 	params.cred.credlen = old_pinlen;
85*3089Swyllys 
86*3089Swyllys 	newpincred.cred = (char *)new_pin;
87*3089Swyllys 	newpincred.credlen = new_pinlen;
88*3089Swyllys 
89*3089Swyllys 	rv = KMF_SetTokenPin(handle, &params, &newpincred);
90*3089Swyllys 
91*3089Swyllys 	if (new_pin)
92*3089Swyllys 		free(new_pin);
93*3089Swyllys 	if (old_pin)
94*3089Swyllys 		free(old_pin);
95*3089Swyllys 
96*3089Swyllys 	return (rv);
97*3089Swyllys }
98*3089Swyllys 
99*3089Swyllys static int
100*3089Swyllys setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec)
101*3089Swyllys {
1020Sstevel@tonic-gate 	CK_SLOT_ID		slot_id;
1030Sstevel@tonic-gate 	CK_FLAGS		pin_state;
10417Sdinak 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
10517Sdinak 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
10617Sdinak 	CK_RV			rv = CKR_OK;
107*3089Swyllys 	char			*token_name = NULL;
108*3089Swyllys 	KMF_SETPIN_PARAMS	params;
109*3089Swyllys 	CK_TOKEN_INFO		token_info;
110*3089Swyllys 	KMF_CREDENTIAL		newpincred = { NULL, 0 };
111864Sdinak 
112864Sdinak 	/* If nothing is specified, default is to use softtoken. */
113864Sdinak 	if (token_spec == NULL) {
114*3089Swyllys 		token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID;
115864Sdinak 		token_name = SOFT_TOKEN_LABEL;
116864Sdinak 	}
11717Sdinak 
118*3089Swyllys 	rv = KMF_PK11TokenLookup(NULL, token_spec, &slot_id);
119*3089Swyllys 	if (rv == KMF_OK) {
120*3089Swyllys 		/* find the pin state for the selected token */
121*3089Swyllys 		if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK)
122*3089Swyllys 			return (PK_ERR_PK11);
1230Sstevel@tonic-gate 
124*3089Swyllys 		pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED;
125*3089Swyllys 		if (token_name == NULL)
126*3089Swyllys 			token_name = (char *)token_info.label;
1270Sstevel@tonic-gate 	}
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	/*
13017Sdinak 	 * If the token is the softtoken, check if the token flags show the
13117Sdinak 	 * PIN has not been set yet.  If not then set the old PIN to the
13217Sdinak 	 * default "changeme".  Otherwise, let user type in the correct old
13317Sdinak 	 * PIN to unlock token.
1340Sstevel@tonic-gate 	 */
13517Sdinak 	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
13617Sdinak 	    strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
13717Sdinak 		if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
13817Sdinak 		    NULL) {
13917Sdinak 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
14017Sdinak 			final_pk11(NULL);
14117Sdinak 			return (PK_ERR_PK11);
14217Sdinak 		}
14317Sdinak 		old_pinlen = strlen(SOFT_DEFAULT_PIN);
14417Sdinak 	} else {
14517Sdinak 		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
14617Sdinak 		    &old_pin, &old_pinlen)) != CKR_OK) {
14717Sdinak 			cryptoerror(LOG_STDERR,
14817Sdinak 			    gettext("Unable to get token passphrase (%s)."),
14917Sdinak 			    pkcs11_strerror(rv));
15017Sdinak 			final_pk11(NULL);
15117Sdinak 			return (PK_ERR_PK11);
15217Sdinak 		}
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 
15517Sdinak 	/* Get the user's new PIN. */
15617Sdinak 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
15717Sdinak 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
15817Sdinak 		if (rv == CKR_PIN_INCORRECT)
15917Sdinak 			cryptoerror(LOG_STDERR, gettext(
16017Sdinak 			    "Passphrases do not match."));
16117Sdinak 		else
16217Sdinak 			cryptoerror(LOG_STDERR, gettext(
16317Sdinak 			    "Unable to get and confirm new passphrase (%s)."),
16417Sdinak 			    pkcs11_strerror(rv));
16517Sdinak 		free(old_pin);
16617Sdinak 		final_pk11(NULL);
16717Sdinak 		return (PK_ERR_PK11);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 
170*3089Swyllys 	(void) memset(&params, 0, sizeof (params));
171*3089Swyllys 	params.kstype = KMF_KEYSTORE_PK11TOKEN;
172*3089Swyllys 	params.tokenname = (char *)token_info.label;
173*3089Swyllys 	params.cred.cred = (char *)old_pin;
174*3089Swyllys 	params.cred.credlen = old_pinlen;
175*3089Swyllys 	params.pkcs11parms.slot = slot_id;
17617Sdinak 
177*3089Swyllys 	newpincred.cred = (char *)new_pin;
178*3089Swyllys 	newpincred.credlen = new_pinlen;
179*3089Swyllys 
180*3089Swyllys 	rv = KMF_SetTokenPin(handle, &params, &newpincred);
18117Sdinak 
18217Sdinak 	/* Clean up. */
183*3089Swyllys 	if (old_pin != NULL)
184*3089Swyllys 		free(old_pin);
185*3089Swyllys 	if (new_pin != NULL)
186*3089Swyllys 		free(new_pin);
187*3089Swyllys 
188*3089Swyllys 	return (rv);
189*3089Swyllys }
190*3089Swyllys 
191*3089Swyllys /*
192*3089Swyllys  * Changes the token's PIN.
193*3089Swyllys  */
194*3089Swyllys int
195*3089Swyllys pk_setpin(int argc, char *argv[])
196*3089Swyllys /* ARGSUSED */
197*3089Swyllys {
198*3089Swyllys 	int		opt;
199*3089Swyllys 	int		rv;
200*3089Swyllys 	extern int	optind_av;
201*3089Swyllys 	extern char	*optarg_av;
202*3089Swyllys 	char		*token_spec = NULL;
203*3089Swyllys 	char		*dir = NULL;
204*3089Swyllys 	char		*prefix = NULL;
205*3089Swyllys 	KMF_HANDLE_T	handle;
206*3089Swyllys 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
20717Sdinak 
208*3089Swyllys 	/* Parse command line options.  Do NOT i18n/l10n. */
209*3089Swyllys 	while ((opt = getopt_av(argc, argv,
210*3089Swyllys 		"T:(token)k:(keystore)d:(dir)"
211*3089Swyllys 		"p:(prefix)")) != EOF) {
212*3089Swyllys 		switch (opt) {
213*3089Swyllys 			case 'k':
214*3089Swyllys 				kstype = KS2Int(optarg_av);
215*3089Swyllys 				if (kstype == 0)
216*3089Swyllys 					return (PK_ERR_USAGE);
217*3089Swyllys 				break;
218*3089Swyllys 			case 'T':	/* token specifier */
219*3089Swyllys 				if (token_spec)
220*3089Swyllys 					return (PK_ERR_USAGE);
221*3089Swyllys 				token_spec = optarg_av;
222*3089Swyllys 				break;
223*3089Swyllys 			case 'd':
224*3089Swyllys 				if (dir)
225*3089Swyllys 					return (PK_ERR_USAGE);
226*3089Swyllys 				dir = optarg_av;
227*3089Swyllys 				break;
228*3089Swyllys 			case 'p':
229*3089Swyllys 				if (prefix)
230*3089Swyllys 					return (PK_ERR_USAGE);
231*3089Swyllys 				prefix = optarg_av;
232*3089Swyllys 				break;
233*3089Swyllys 			default:
234*3089Swyllys 				return (PK_ERR_USAGE);
235*3089Swyllys 				break;
236*3089Swyllys 		}
23717Sdinak 	}
23817Sdinak 
239*3089Swyllys 
240*3089Swyllys 	/* No additional args allowed. */
241*3089Swyllys 	argc -= optind_av;
242*3089Swyllys 	argv += optind_av;
243*3089Swyllys 	if (argc != 0)
244*3089Swyllys 		return (PK_ERR_USAGE);
245*3089Swyllys 
246*3089Swyllys 	/* Done parsing command line options. */
247*3089Swyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
248*3089Swyllys 		token_spec = PK_DEFAULT_PK11TOKEN;
249*3089Swyllys 	} else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
250*3089Swyllys 		token_spec = DEFAULT_NSS_TOKEN;
251*3089Swyllys 	}
252*3089Swyllys 
253*3089Swyllys 	if ((rv = KMF_Initialize(&handle, NULL, NULL)) != KMF_OK)
254*3089Swyllys 		return (rv);
255*3089Swyllys 
256*3089Swyllys 	switch (kstype) {
257*3089Swyllys 		case KMF_KEYSTORE_PK11TOKEN:
258*3089Swyllys 			rv = setpin_pkcs11(handle, token_spec);
259*3089Swyllys 			break;
260*3089Swyllys 		case KMF_KEYSTORE_NSS:
261*3089Swyllys 			rv = setpin_nss(handle, token_spec, dir, prefix);
262*3089Swyllys 			break;
263*3089Swyllys 		default:
264*3089Swyllys 			cryptoerror(LOG_STDERR,
265*3089Swyllys 				gettext("incorrect keystore."));
266*3089Swyllys 			return (PK_ERR_USAGE);
267*3089Swyllys 	}
268*3089Swyllys 
269*3089Swyllys 	(void) KMF_Finalize(handle);
270*3089Swyllys 
271*3089Swyllys 	if (rv == KMF_ERR_AUTH_FAILED) {
272*3089Swyllys 		cryptoerror(LOG_STDERR,
273*3089Swyllys 		    gettext("Incorrect passphrase."));
274*3089Swyllys 		return (PK_ERR_SYSTEM);
275*3089Swyllys 	} else if (rv != CKR_OK) {
276*3089Swyllys 		cryptoerror(LOG_STDERR,
277*3089Swyllys 		    gettext("Unable to change passphrase."));
278*3089Swyllys 		return (PK_ERR_SYSTEM);
279*3089Swyllys 	} else {
280*3089Swyllys 		(void) fprintf(stdout, gettext("Passphrase changed.\n"));
281*3089Swyllys 	}
28217Sdinak 	return (0);
2830Sstevel@tonic-gate }
284