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 2004 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, log into it, prompt the user for the
33  * new PIN, change the token's PIN, and log out.
34  */
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <cryptoutil.h>
40 #include <security/cryptoki.h>
41 #include "common.h"
42 
43 static int
44 set_token_pin(CK_SESSION_HANDLE hdl, CK_UTF8CHAR_PTR oldpin, CK_ULONG oldpinlen)
45 {
46 	CK_UTF8CHAR_PTR		pin1, pin2;
47 	int			len1, len2;
48 	int			rv;
49 
50 	cryptodebug("inside set_token_pin");
51 
52 	if ((len1 = get_password(gettext("Enter new PIN:"),
53 	    (char **)&pin1)) < 0)
54 		return (PK_ERR_NEWPIN);
55 
56 	if ((len2 = get_password(gettext("Re-enter new PIN:"),
57 	    (char **)&pin2)) < 0) {
58 		free(pin1);
59 		return (PK_ERR_PINCONFIRM);
60 	}
61 
62 	/* NOTE:  Do not use strcmp on pin1 and pin2; they are UTF strings */
63 	if (len1 != len2 || memcmp(pin1, pin2, len1) != 0) {
64 		free(pin1);
65 		free(pin2);
66 		return (PK_ERR_PINMATCH);
67 	}
68 
69 	if ((rv = C_SetPIN(hdl, oldpin, oldpinlen, pin1, (CK_ULONG)len1))
70 	    != CKR_OK) {
71 		pk11_errno = rv;
72 		free(pin1);
73 		free(pin2);
74 		return (PK_ERR_PK11SETPIN);
75 	}
76 
77 	free(pin1);
78 	free(pin2);
79 	return (PK_ERR_NONE);
80 }
81 
82 /*
83  * This is the main entry point in this module.  It controls the process
84  * by which the token's PIN is changed.  It relies on set_token_pin() to
85  * handle the extra work of prompting and confirming the new PIN.
86  */
87 int
88 pk_setpin(int argc, char *argv[])
89 /* ARGSUSED */
90 {
91 	char		*token_name = NULL;
92 	char		*manuf_id = NULL;
93 	char		*serial_no = NULL;
94 	CK_SLOT_ID		slot_id;
95 	CK_FLAGS		pin_state;
96 	CK_SESSION_HANDLE	hdl;
97 	CK_UTF8CHAR_PTR		pin;
98 	int			pinlen;
99 	int			rv;
100 
101 	cryptodebug("inside pk_setpin");
102 
103 	/*
104 	 * Token_name, manuf_id, and serial_no are all optional.
105 	 * If unspecified, token_name must have a default value
106 	 * at least.
107 	 */
108 	token_name = SOFT_TOKEN_LABEL;
109 	manuf_id = SOFT_MANUFACTURER_ID;
110 
111 	/* No additional args allowed. */
112 	if (argc != 1)
113 		return (PK_ERR_USAGE);
114 	/* Done parsing command line options. */
115 
116 	/* Initialize PKCS11, find the slot with token. */
117 	if ((rv = init_pk11()) != PK_ERR_NONE)
118 		return (rv);
119 	if ((rv = find_token_slot(token_name, manuf_id, serial_no,
120 	    &slot_id, &pin_state)) != PK_ERR_NONE)
121 		return (rv);
122 
123 	/* Check if the token flags show the PIN has not be set yet. */
124 	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED) {
125 		cryptodebug("pin_state: first time pin is being set");
126 		if ((pin = (CK_UTF8CHAR_PTR)strdup(SOFT_DEFAULT_PIN)) == NULL)
127 			return (PK_ERR_NOMEMORY);
128 		pinlen = strlen(SOFT_DEFAULT_PIN);
129 	} else {
130 		cryptodebug("pin_state: changing an existing pin ");
131 		/* Have user unlock token with correct password */
132 		if ((pinlen = get_password(gettext("Enter token PIN:"),
133 		    (char **)&pin)) < 0)
134 			return (PK_ERR_PASSPHRASE);
135 	}
136 
137 	/*
138 	 * Log into the token.  If login fails with an uninitialized PIN,
139 	 * it means this is the first time the token has been used.
140 	 * Or if the login is successful, but all subsequent calls to
141 	 * any function return with an expired PIN, then this is the
142 	 * first time the token is used.  In either case, use the
143 	 * passphrase "changeme" as the initial PIN.
144 	 */
145 	if ((rv = login_token(slot_id, pin, (CK_ULONG)pinlen, &hdl))
146 	    != PK_ERR_NONE) {
147 		free(pin);
148 		return (rv);
149 	}
150 
151 	/* Set the pin for the PKCS11 token. */
152 	if ((rv = set_token_pin(hdl, pin, (CK_ULONG)pinlen)) != PK_ERR_NONE) {
153 		free(pin);
154 		logout_token(hdl);
155 		return (rv);
156 	}
157 
158 	free(pin);
159 	logout_token(hdl);
160 	return (PK_ERR_NONE);
161 }
162