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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file implements the setpin operation for this tool.
31  * The basic flow of the process is to load the PKCS#11 module,
32  * finds the soft token, prompt the user for the old PIN (if
33  * any) and the new PIN, change the token's PIN, and clean up.
34  */
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <cryptoutil.h>
41 #include <security/cryptoki.h>
42 #include "common.h"
43 
44 /*
45  * Changes the token's PIN.
46  */
47 int
48 pk_setpin(int argc, char *argv[])
49 /* ARGSUSED */
50 {
51 	int		opt;
52 	extern int	optind_av;
53 	extern char	*optarg_av;
54 	char		*token_spec = NULL;
55 	char		*token_name = NULL;
56 	char		*manuf_id = NULL;
57 	char		*serial_no = NULL;
58 	CK_SLOT_ID		slot_id;
59 	CK_FLAGS		pin_state;
60 	CK_SESSION_HANDLE	sess;
61 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
62 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
63 	CK_RV			rv = CKR_OK;
64 	char		full_name[FULL_NAME_LEN];
65 
66 	cryptodebug("inside pk_setpin");
67 
68 	/* Parse command line options.  Do NOT i18n/l10n. */
69 	while ((opt = getopt_av(argc, argv, "T:(token)")) != EOF) {
70 		switch (opt) {
71 		case 'T':	/* token specifier */
72 			if (token_spec)
73 				return (PK_ERR_USAGE);
74 			token_spec = optarg_av;
75 			break;
76 		default:
77 			return (PK_ERR_USAGE);
78 			break;
79 		}
80 	}
81 
82 	/* If nothing is specified, default is to use softtoken. */
83 	if (token_spec == NULL) {
84 		token_name = SOFT_TOKEN_LABEL;
85 		manuf_id = SOFT_MANUFACTURER_ID;
86 		serial_no = SOFT_TOKEN_SERIAL;
87 	} else {
88 		/*
89 		 * Parse token specifier into token_name, manuf_id, serial_no.
90 		 * Token_name is required; manuf_id and serial_no are optional.
91 		 */
92 		if (parse_token_spec(token_spec, &token_name, &manuf_id,
93 		    &serial_no) < 0)
94 			return (PK_ERR_USAGE);
95 	}
96 
97 	/* No additional args allowed. */
98 	argc -= optind_av;
99 	argv += optind_av;
100 	if (argc != 0)
101 		return (PK_ERR_USAGE);
102 	/* Done parsing command line options. */
103 
104 	full_token_name(token_name, manuf_id, serial_no, full_name);
105 
106 	/* Find the slot with token. */
107 	if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
108 	    &pin_state)) != CKR_OK) {
109 		cryptoerror(LOG_STDERR,
110 		    gettext("Unable to find token %s (%s)."), full_name,
111 		    pkcs11_strerror(rv));
112 		final_pk11(NULL);
113 		return (PK_ERR_PK11);
114 	}
115 
116 	/*
117 	 * If the token is the softtoken, check if the token flags show the
118 	 * PIN has not been set yet.  If not then set the old PIN to the
119 	 * default "changeme".  Otherwise, let user type in the correct old
120 	 * PIN to unlock token.
121 	 */
122 	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
123 	    strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
124 		cryptodebug("pin_state: first time passphrase is being set");
125 		if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
126 		    NULL) {
127 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
128 			final_pk11(NULL);
129 			return (PK_ERR_PK11);
130 		}
131 		old_pinlen = strlen(SOFT_DEFAULT_PIN);
132 	} else {
133 		cryptodebug("pin_state: changing an existing pin ");
134 		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
135 		    &old_pin, &old_pinlen)) != CKR_OK) {
136 			cryptoerror(LOG_STDERR,
137 			    gettext("Unable to get token passphrase (%s)."),
138 			    pkcs11_strerror(rv));
139 			final_pk11(NULL);
140 			return (PK_ERR_PK11);
141 		}
142 	}
143 
144 	/* Get the user's new PIN. */
145 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
146 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
147 		if (rv == CKR_PIN_INCORRECT)
148 			cryptoerror(LOG_STDERR, gettext(
149 			    "Passphrases do not match."));
150 		else
151 			cryptoerror(LOG_STDERR, gettext(
152 			    "Unable to get and confirm new passphrase (%s)."),
153 			    pkcs11_strerror(rv));
154 		free(old_pin);
155 		final_pk11(NULL);
156 		return (PK_ERR_PK11);
157 	}
158 
159 	/* Open a R/W session to the token to change the PIN. */
160 	if ((rv = open_sess(slot_id, CKF_RW_SESSION, &sess)) != CKR_OK) {
161 		cryptoerror(LOG_STDERR,
162 		    gettext("Unable to open token session (%s)."),
163 		    pkcs11_strerror(rv));
164 		free(old_pin);
165 		final_pk11(NULL);
166 		return (PK_ERR_PK11);
167 	}
168 
169 	/* Change the PIN if possible. */
170 	cryptodebug("calling C_SetPIN");
171 	rv = C_SetPIN(sess, old_pin, old_pinlen, new_pin, new_pinlen);
172 
173 	/* Clean up. */
174 	free(old_pin);
175 	free(new_pin);
176 	quick_finish(sess);
177 
178 	if (rv != CKR_OK) {
179 		if (rv == CKR_PIN_INCORRECT)
180 			cryptoerror(LOG_STDERR,
181 			    gettext("Incorrect passphrase."));
182 		else
183 			cryptoerror(LOG_STDERR,
184 			    gettext("Unable to change passphrase (%s)."),
185 			    pkcs11_strerror(rv));
186 		return (PK_ERR_PK11);
187 	}
188 
189 	(void) fprintf(stdout, gettext("Passphrase changed.\n"));
190 	return (0);
191 }
192