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 	char		*token_name = NULL;
52 	char		*manuf_id = NULL;
53 	char		*serial_no = NULL;
54 	CK_SLOT_ID		slot_id;
55 	CK_FLAGS		pin_state;
56 	CK_SESSION_HANDLE	sess;
57 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
58 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
59 	CK_RV			rv = CKR_OK;
60 	char		full_name[FULL_NAME_LEN];
61 
62 	cryptodebug("inside pk_setpin");
63 
64 	/* Get rid of subcommand word "setpin". */
65 	argc--;
66 	argv++;
67 
68 	/* No additional args allowed. */
69 	if (argc != 0)
70 		return (PK_ERR_USAGE);
71 	/* Done parsing command line options. */
72 
73 	/*
74 	 * Token_name, manuf_id, and serial_no are all optional.
75 	 * If unspecified, token_name must have a default value
76 	 * at least, so set it to the default softtoken value.
77 	 */
78 	if (token_name == NULL)
79 		token_name = SOFT_TOKEN_LABEL;
80 	if (manuf_id == NULL)
81 		manuf_id = SOFT_MANUFACTURER_ID;
82 	if (serial_no == NULL)
83 		serial_no = SOFT_TOKEN_SERIAL;
84 	full_token_name(token_name, manuf_id, serial_no, full_name);
85 
86 	/* Find the slot with token. */
87 	if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
88 	    &pin_state)) != CKR_OK) {
89 		cryptoerror(LOG_STDERR,
90 		    gettext("Unable to find token %s (%s)."), full_name,
91 		    pkcs11_strerror(rv));
92 		final_pk11(NULL);
93 		return (PK_ERR_PK11);
94 	}
95 
96 	/*
97 	 * If the token is the softtoken, check if the token flags show the
98 	 * PIN has not been set yet.  If not then set the old PIN to the
99 	 * default "changeme".  Otherwise, let user type in the correct old
100 	 * PIN to unlock token.
101 	 */
102 	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
103 	    strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
104 		cryptodebug("pin_state: first time passphrase is being set");
105 		if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
106 		    NULL) {
107 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
108 			final_pk11(NULL);
109 			return (PK_ERR_PK11);
110 		}
111 		old_pinlen = strlen(SOFT_DEFAULT_PIN);
112 	} else {
113 		cryptodebug("pin_state: changing an existing pin ");
114 		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
115 		    &old_pin, &old_pinlen)) != CKR_OK) {
116 			cryptoerror(LOG_STDERR,
117 			    gettext("Unable to get token passphrase (%s)."),
118 			    pkcs11_strerror(rv));
119 			final_pk11(NULL);
120 			return (PK_ERR_PK11);
121 		}
122 	}
123 
124 	/* Get the user's new PIN. */
125 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
126 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
127 		if (rv == CKR_PIN_INCORRECT)
128 			cryptoerror(LOG_STDERR, gettext(
129 			    "Passphrases do not match."));
130 		else
131 			cryptoerror(LOG_STDERR, gettext(
132 			    "Unable to get and confirm new passphrase (%s)."),
133 			    pkcs11_strerror(rv));
134 		free(old_pin);
135 		final_pk11(NULL);
136 		return (PK_ERR_PK11);
137 	}
138 
139 	/* Open a R/W session to the token to change the PIN. */
140 	if ((rv = open_sess(slot_id, CKF_RW_SESSION, &sess)) != CKR_OK) {
141 		cryptoerror(LOG_STDERR,
142 		    gettext("Unable to open token session (%s)."),
143 		    pkcs11_strerror(rv));
144 		free(old_pin);
145 		final_pk11(NULL);
146 		return (PK_ERR_PK11);
147 	}
148 
149 	/* Change the PIN if possible. */
150 	cryptodebug("calling C_SetPIN");
151 	rv = C_SetPIN(sess, old_pin, old_pinlen, new_pin, new_pinlen);
152 
153 	/* Clean up. */
154 	free(old_pin);
155 	free(new_pin);
156 	quick_finish(sess);
157 
158 	if (rv != CKR_OK) {
159 		if (rv == CKR_PIN_INCORRECT)
160 			cryptoerror(LOG_STDERR,
161 			    gettext("Incorrect passphrase."));
162 		else
163 			cryptoerror(LOG_STDERR,
164 			    gettext("Unable to change passphrase (%s)."),
165 			    pkcs11_strerror(rv));
166 		return (PK_ERR_PK11);
167 	}
168 
169 	(void) fprintf(stdout, gettext("Passphrase changed.\n"));
170 	return (0);
171 }
172