xref: /onnv-gate/usr/src/cmd/cmd-crypto/pktool/setpin.c (revision 5051:cbbb7c8b40a9)
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
53089Swyllys  * Common Development and Distribution License (the "License").
63089Swyllys  * 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*5051Swyllys  * Copyright 2007 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 
433089Swyllys static int
443089Swyllys setpin_nss(KMF_HANDLE_T handle,
453089Swyllys 	char *token_spec, char *dir, char *prefix)
460Sstevel@tonic-gate {
473089Swyllys 	int rv = 0;
48*5051Swyllys 	KMF_CREDENTIAL		oldcred = {NULL, 0};
49*5051Swyllys 	KMF_CREDENTIAL		newpincred = {NULL, 0};
503089Swyllys 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
513089Swyllys 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
52*5051Swyllys 	KMF_ATTRIBUTE		setpinattrs[6];
53*5051Swyllys 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_NSS;
54*5051Swyllys 	int			numattrs = 0;
553089Swyllys 
563089Swyllys 	rv = configure_nss(handle, dir, prefix);
573089Swyllys 	if (rv != KMF_OK)
583089Swyllys 		return (rv);
593089Swyllys 
60*5051Swyllys 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_KEYSTORE_TYPE_ATTR,
61*5051Swyllys 	    &kstype, sizeof (kstype));
62*5051Swyllys 	numattrs++;
63*5051Swyllys 	if (token_spec != NULL) {
64*5051Swyllys 		kmf_set_attr_at_index(setpinattrs, numattrs,
65*5051Swyllys 		    KMF_TOKEN_LABEL_ATTR,
66*5051Swyllys 		    token_spec, strlen(token_spec));
67*5051Swyllys 		numattrs++;
68*5051Swyllys 	}
693089Swyllys 
703089Swyllys 	if ((rv = get_pin(gettext("Enter current token passphrase "
71*5051Swyllys 	    "(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) != CKR_OK) {
723089Swyllys 		cryptoerror(LOG_STDERR,
733089Swyllys 		    gettext("Unable to get token passphrase."));
743089Swyllys 		return (PK_ERR_NSS);
753089Swyllys 	}
763089Swyllys 	/* Get the user's new PIN. */
773089Swyllys 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
783089Swyllys 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
793089Swyllys 		if (rv == CKR_PIN_INCORRECT)
803089Swyllys 			cryptoerror(LOG_STDERR, gettext(
813089Swyllys 			    "Passphrases do not match."));
823089Swyllys 		else
833089Swyllys 			cryptoerror(LOG_STDERR, gettext(
843089Swyllys 			    "Unable to get and confirm new passphrase."));
853089Swyllys 		if (old_pin != NULL)
863089Swyllys 			free(old_pin);
873089Swyllys 		return (PK_ERR_NSS);
883089Swyllys 	}
893089Swyllys 
90*5051Swyllys 	oldcred.cred = (char *)old_pin;
91*5051Swyllys 	oldcred.credlen = old_pinlen;
92*5051Swyllys 
93*5051Swyllys 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_CREDENTIAL_ATTR,
94*5051Swyllys 	    &oldcred, sizeof (oldcred));
95*5051Swyllys 	numattrs++;
963089Swyllys 
973089Swyllys 	newpincred.cred = (char *)new_pin;
983089Swyllys 	newpincred.credlen = new_pinlen;
99*5051Swyllys 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_NEWPIN_ATTR,
100*5051Swyllys 	    &newpincred, sizeof (newpincred));
101*5051Swyllys 	numattrs++;
1023089Swyllys 
103*5051Swyllys 	rv = kmf_set_token_pin(handle, numattrs, setpinattrs);
1043089Swyllys 
1053089Swyllys 	if (new_pin)
1063089Swyllys 		free(new_pin);
1073089Swyllys 	if (old_pin)
1083089Swyllys 		free(old_pin);
1093089Swyllys 
1103089Swyllys 	return (rv);
1113089Swyllys }
1123089Swyllys 
1133089Swyllys static int
1143089Swyllys setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec)
1153089Swyllys {
1160Sstevel@tonic-gate 	CK_SLOT_ID		slot_id;
1170Sstevel@tonic-gate 	CK_FLAGS		pin_state;
11817Sdinak 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
11917Sdinak 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
12017Sdinak 	CK_RV			rv = CKR_OK;
1213089Swyllys 	char			*token_name = NULL;
1223089Swyllys 	CK_TOKEN_INFO		token_info;
123*5051Swyllys 	KMF_CREDENTIAL		newpincred = {NULL, 0};
124*5051Swyllys 	KMF_CREDENTIAL		oldcred = {NULL, 0};
125*5051Swyllys 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
126*5051Swyllys 	KMF_ATTRIBUTE		attrlist[6];
127*5051Swyllys 	int			numattr = 0;
128864Sdinak 
129864Sdinak 	/* If nothing is specified, default is to use softtoken. */
130864Sdinak 	if (token_spec == NULL) {
1313089Swyllys 		token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID;
132864Sdinak 		token_name = SOFT_TOKEN_LABEL;
133864Sdinak 	}
13417Sdinak 
135*5051Swyllys 	rv = kmf_pk11_token_lookup(NULL, token_spec, &slot_id);
1363089Swyllys 	if (rv == KMF_OK) {
1373089Swyllys 		/* find the pin state for the selected token */
1383089Swyllys 		if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK)
1393089Swyllys 			return (PK_ERR_PK11);
1400Sstevel@tonic-gate 
1413089Swyllys 		pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED;
1423089Swyllys 		if (token_name == NULL)
1433089Swyllys 			token_name = (char *)token_info.label;
1440Sstevel@tonic-gate 	}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	/*
14717Sdinak 	 * If the token is the softtoken, check if the token flags show the
14817Sdinak 	 * PIN has not been set yet.  If not then set the old PIN to the
14917Sdinak 	 * default "changeme".  Otherwise, let user type in the correct old
15017Sdinak 	 * PIN to unlock token.
1510Sstevel@tonic-gate 	 */
15217Sdinak 	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
15317Sdinak 	    strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
15417Sdinak 		if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
15517Sdinak 		    NULL) {
15617Sdinak 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
15717Sdinak 			final_pk11(NULL);
15817Sdinak 			return (PK_ERR_PK11);
15917Sdinak 		}
16017Sdinak 		old_pinlen = strlen(SOFT_DEFAULT_PIN);
16117Sdinak 	} else {
16217Sdinak 		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
16317Sdinak 		    &old_pin, &old_pinlen)) != CKR_OK) {
16417Sdinak 			cryptoerror(LOG_STDERR,
16517Sdinak 			    gettext("Unable to get token passphrase (%s)."),
16617Sdinak 			    pkcs11_strerror(rv));
16717Sdinak 			final_pk11(NULL);
16817Sdinak 			return (PK_ERR_PK11);
16917Sdinak 		}
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 
17217Sdinak 	/* Get the user's new PIN. */
17317Sdinak 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
17417Sdinak 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
17517Sdinak 		if (rv == CKR_PIN_INCORRECT)
17617Sdinak 			cryptoerror(LOG_STDERR, gettext(
17717Sdinak 			    "Passphrases do not match."));
17817Sdinak 		else
17917Sdinak 			cryptoerror(LOG_STDERR, gettext(
18017Sdinak 			    "Unable to get and confirm new passphrase (%s)."),
18117Sdinak 			    pkcs11_strerror(rv));
18217Sdinak 		free(old_pin);
18317Sdinak 		final_pk11(NULL);
18417Sdinak 		return (PK_ERR_PK11);
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 
187*5051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
188*5051Swyllys 	    &kstype, sizeof (kstype));
189*5051Swyllys 	numattr++;
190*5051Swyllys 	if (token_name != NULL) {
191*5051Swyllys 		kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR,
192*5051Swyllys 		    token_name, strlen(token_name));
193*5051Swyllys 		numattr++;
194*5051Swyllys 	}
195*5051Swyllys 	oldcred.cred = (char *)old_pin;
196*5051Swyllys 	oldcred.credlen = old_pinlen;
197*5051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR,
198*5051Swyllys 	    &oldcred, sizeof (oldcred));
199*5051Swyllys 	numattr++;
200*5051Swyllys 
201*5051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_SLOT_ID_ATTR,
202*5051Swyllys 	    &slot_id, sizeof (slot_id));
203*5051Swyllys 	numattr++;
20417Sdinak 
2053089Swyllys 	newpincred.cred = (char *)new_pin;
2063089Swyllys 	newpincred.credlen = new_pinlen;
207*5051Swyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_NEWPIN_ATTR,
208*5051Swyllys 	    &newpincred, sizeof (newpincred));
209*5051Swyllys 	numattr++;
2103089Swyllys 
211*5051Swyllys 	rv = kmf_set_token_pin(handle, numattr, attrlist);
21217Sdinak 
21317Sdinak 	/* Clean up. */
2143089Swyllys 	if (old_pin != NULL)
2153089Swyllys 		free(old_pin);
2163089Swyllys 	if (new_pin != NULL)
2173089Swyllys 		free(new_pin);
2183089Swyllys 
2193089Swyllys 	return (rv);
2203089Swyllys }
2213089Swyllys 
2223089Swyllys /*
2233089Swyllys  * Changes the token's PIN.
2243089Swyllys  */
2253089Swyllys int
2263089Swyllys pk_setpin(int argc, char *argv[])
2273089Swyllys /* ARGSUSED */
2283089Swyllys {
2293089Swyllys 	int		opt;
2303089Swyllys 	int		rv;
2313089Swyllys 	extern int	optind_av;
2323089Swyllys 	extern char	*optarg_av;
2333089Swyllys 	char		*token_spec = NULL;
2343089Swyllys 	char		*dir = NULL;
2353089Swyllys 	char		*prefix = NULL;
2363089Swyllys 	KMF_HANDLE_T	handle;
2373089Swyllys 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
23817Sdinak 
2393089Swyllys 	/* Parse command line options.  Do NOT i18n/l10n. */
2403089Swyllys 	while ((opt = getopt_av(argc, argv,
2413089Swyllys 		"T:(token)k:(keystore)d:(dir)"
2423089Swyllys 		"p:(prefix)")) != EOF) {
2433089Swyllys 		switch (opt) {
2443089Swyllys 			case 'k':
2453089Swyllys 				kstype = KS2Int(optarg_av);
2463089Swyllys 				if (kstype == 0)
2473089Swyllys 					return (PK_ERR_USAGE);
2483089Swyllys 				break;
2493089Swyllys 			case 'T':	/* token specifier */
2503089Swyllys 				if (token_spec)
2513089Swyllys 					return (PK_ERR_USAGE);
2523089Swyllys 				token_spec = optarg_av;
2533089Swyllys 				break;
2543089Swyllys 			case 'd':
2553089Swyllys 				if (dir)
2563089Swyllys 					return (PK_ERR_USAGE);
2573089Swyllys 				dir = optarg_av;
2583089Swyllys 				break;
2593089Swyllys 			case 'p':
2603089Swyllys 				if (prefix)
2613089Swyllys 					return (PK_ERR_USAGE);
2623089Swyllys 				prefix = optarg_av;
2633089Swyllys 				break;
2643089Swyllys 			default:
2653089Swyllys 				return (PK_ERR_USAGE);
2663089Swyllys 				break;
2673089Swyllys 		}
26817Sdinak 	}
26917Sdinak 
2703089Swyllys 
2713089Swyllys 	/* No additional args allowed. */
2723089Swyllys 	argc -= optind_av;
2733089Swyllys 	argv += optind_av;
2743089Swyllys 	if (argc != 0)
2753089Swyllys 		return (PK_ERR_USAGE);
2763089Swyllys 
2773089Swyllys 	/* Done parsing command line options. */
2783089Swyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) {
2793089Swyllys 		token_spec = PK_DEFAULT_PK11TOKEN;
2803089Swyllys 	} else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) {
2813089Swyllys 		token_spec = DEFAULT_NSS_TOKEN;
2823089Swyllys 	}
2833089Swyllys 
284*5051Swyllys 	if ((rv = kmf_initialize(&handle, NULL, NULL)) != KMF_OK)
2853089Swyllys 		return (rv);
2863089Swyllys 
2873089Swyllys 	switch (kstype) {
2883089Swyllys 		case KMF_KEYSTORE_PK11TOKEN:
2893089Swyllys 			rv = setpin_pkcs11(handle, token_spec);
2903089Swyllys 			break;
2913089Swyllys 		case KMF_KEYSTORE_NSS:
2923089Swyllys 			rv = setpin_nss(handle, token_spec, dir, prefix);
2933089Swyllys 			break;
2943089Swyllys 		default:
2953089Swyllys 			cryptoerror(LOG_STDERR,
296*5051Swyllys 			    gettext("incorrect keystore."));
2973089Swyllys 			return (PK_ERR_USAGE);
2983089Swyllys 	}
2993089Swyllys 
300*5051Swyllys 	(void) kmf_finalize(handle);
3013089Swyllys 
3023089Swyllys 	if (rv == KMF_ERR_AUTH_FAILED) {
3033089Swyllys 		cryptoerror(LOG_STDERR,
3043089Swyllys 		    gettext("Incorrect passphrase."));
3053089Swyllys 		return (PK_ERR_SYSTEM);
3063089Swyllys 	} else if (rv != CKR_OK) {
3073089Swyllys 		cryptoerror(LOG_STDERR,
3083089Swyllys 		    gettext("Unable to change passphrase."));
3093089Swyllys 		return (PK_ERR_SYSTEM);
3103089Swyllys 	} else {
3113089Swyllys 		(void) fprintf(stdout, gettext("Passphrase changed.\n"));
3123089Swyllys 	}
31317Sdinak 	return (0);
3140Sstevel@tonic-gate }
315