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 token object delete operation for this tool.
31  * It loads the PKCS#11 modules, finds the object to delete, deletes it,
32  * and cleans up.  User must be R/W logged into the token.
33  */
34 
35 #include <stdio.h>
36 #include <string.h>
37 #include <cryptoutil.h>
38 #include <security/cryptoki.h>
39 #include "common.h"
40 
41 /*
42  * Delete token objects.
43  */
44 int
45 pk_delete(int argc, char *argv[])
46 {
47 	int		opt;
48 	extern int	optind_av;
49 	extern char	*optarg_av;
50 	char		*token_spec = NULL;
51 	char		*token_name = NULL;
52 	char		*manuf_id = NULL;
53 	char		*serial_no = NULL;
54 	char		*type_spec = NULL;
55 	char		full_name[FULL_NAME_LEN];
56 	boolean_t	public_objs = B_FALSE;
57 	boolean_t	private_objs = B_FALSE;
58 	CK_BYTE		*object_label = NULL;
59 	int		obj_type = 0x00;
60 	CK_SLOT_ID	slot_id;
61 	CK_FLAGS	pin_state;
62 	CK_UTF8CHAR_PTR	pin = NULL;
63 	CK_ULONG	pinlen = 0;
64 	CK_SESSION_HANDLE	sess;
65 	CK_OBJECT_HANDLE	*objs;
66 	CK_ULONG	num_objs;
67 	CK_ATTRIBUTE	label = { CKA_LABEL, NULL, 0 };
68 	CK_RV		rv = CKR_OK;
69 	int		i;
70 
71 	cryptodebug("inside pk_delete");
72 
73 	/* Parse command line options.  Do NOT i18n/l10n. */
74 	while ((opt = getopt_av(argc, argv,
75 	    "T:(token)y:(objtype)l:(label)")) != EOF) {
76 		switch (opt) {
77 		case 'T':	/* token specifier */
78 			if (token_spec)
79 				return (PK_ERR_USAGE);
80 			token_spec = optarg_av;
81 			break;
82 		case 'y':	/* object type:  public, private, both */
83 			if (type_spec)
84 				return (PK_ERR_USAGE);
85 			type_spec = optarg_av;
86 			break;
87 		case 'l':	/* objects with specific label */
88 			if (object_label)
89 				return (PK_ERR_USAGE);
90 			object_label = (CK_BYTE *)optarg_av;
91 			break;
92 		default:
93 			return (PK_ERR_USAGE);
94 			break;
95 		}
96 	}
97 
98 	/* If no token is specified, default is to use softtoken. */
99 	if (token_spec == NULL) {
100 		token_name = SOFT_TOKEN_LABEL;
101 		manuf_id = SOFT_MANUFACTURER_ID;
102 		serial_no = SOFT_TOKEN_SERIAL;
103 	} else {
104 		/*
105 		 * Parse token specifier into token_name, manuf_id, serial_no.
106 		 * Token_name is required; manuf_id and serial_no are optional.
107 		 */
108 		if (parse_token_spec(token_spec, &token_name, &manuf_id,
109 		    &serial_no) < 0)
110 			return (PK_ERR_USAGE);
111 	}
112 
113 	/* If no object type specified, default is public objects. */
114 	if (!type_spec) {
115 		public_objs = B_TRUE;
116 	} else {
117 		/*
118 		 * Otherwise, the object type must be "public", "private",
119 		 * or "both".
120 		 */
121 		if (strcmp(type_spec, "private") == 0) {
122 			private_objs = B_TRUE;
123 		} else if (strcmp(type_spec, "public") == 0) {
124 			public_objs = B_TRUE;
125 		} else if (strcmp(type_spec, "both") == 0) {
126 			private_objs = B_TRUE;
127 			public_objs = B_TRUE;
128 		} else
129 			return (PK_ERR_USAGE);
130 	}
131 
132 	if (private_objs)
133 		obj_type |= PK_PRIVATE_OBJ;
134 	if (public_objs)
135 		obj_type |= PK_PUBLIC_OBJ;
136 
137 	/* At least one of public, private, or object label is required. */
138 	if (!private_objs && !public_objs && object_label == NULL)
139 		return (PK_ERR_USAGE);
140 
141 	/*
142 	 * If object label is given but neither public/private is specified,
143 	 * delete all objects with that label.
144 	 */
145 	if (!private_objs && !public_objs && object_label != NULL)
146 		obj_type = PK_ALL_OBJ;
147 
148 	/* No additional args allowed. */
149 	argc -= optind_av;
150 	argv += optind_av;
151 	if (argc)
152 		return (PK_ERR_USAGE);
153 	/* Done parsing command line options. */
154 
155 	full_token_name(token_name, manuf_id, serial_no, full_name);
156 
157 	/* Find the slot with token. */
158 	if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
159 	    &pin_state)) != CKR_OK) {
160 		cryptoerror(LOG_STDERR, gettext(
161 		    "Unable to find token %s (%s)."), full_name,
162 		    pkcs11_strerror(rv));
163 		return (PK_ERR_PK11);
164 	}
165 
166 	/* Always get the user's PIN for delete operations. */
167 	if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
168 	    &pinlen)) != CKR_OK) {
169 		cryptoerror(LOG_STDERR, gettext(
170 		    "Unable to get token passphrase (%s)."),
171 		    pkcs11_strerror(rv));
172 		quick_finish(NULL);
173 		return (PK_ERR_PK11);
174 	}
175 
176 	/* Log the user R/W into the token. */
177 	if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
178 	    CKR_OK) {
179 		cryptoerror(LOG_STDERR, gettext(
180 		    "Unable to log into token (%s)."), pkcs11_strerror(rv));
181 		quick_finish(sess);
182 		return (PK_ERR_PK11);
183 	}
184 
185 	/* Find the object(s) with the given label and/or type. */
186 	if ((rv = find_objs(sess, obj_type, object_label, &objs, &num_objs)) !=
187 	    CKR_OK) {
188 		cryptoerror(LOG_STDERR, gettext(
189 		    "Unable to find token objects (%s)."), pkcs11_strerror(rv));
190 		quick_finish(sess);
191 		return (PK_ERR_PK11);
192 	}
193 
194 	if (num_objs == 0) {
195 		(void) fprintf(stdout, gettext("No matching objects found.\n"));
196 		quick_finish(sess);
197 		return (0);
198 	}
199 
200 	if (num_objs != 1) {
201 		(void) fprintf(stdout, gettext(
202 		    "Warning: %d matching objects found, deleting all.\n"),
203 		    num_objs);
204 		if (yesno(gettext("Continue with delete? "),
205 		    gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
206 			quick_finish(sess);
207 			return (0);
208 		}
209 	}
210 
211 	/* Destroy the objects if found. */
212 	for (i = 0; i < num_objs; i++) {
213 		/*
214 		 * To give nice feedback to the user, get the object's
215 		 * label before deleting it.
216 		 */
217 		cryptodebug("calling C_GetAttributeValue for label");
218 		label.pValue = NULL;
219 		label.ulValueLen = 0;
220 		if (C_GetAttributeValue(sess, objs[i], &label, 1) == CKR_OK) {
221 			if (label.ulValueLen != (CK_ULONG)-1 &&
222 			    label.ulValueLen != 0 &&
223 			    (label.pValue = malloc(label.ulValueLen)) != NULL) {
224 				if (C_GetAttributeValue(sess, objs[i], &label,
225 				    1) != CKR_OK) {
226 					free(label.pValue);
227 					label.pValue = NULL;
228 					label.ulValueLen = 0;
229 				}
230 			} else {
231 				label.ulValueLen = 0;
232 			}
233 		}
234 
235 		cryptodebug("calling C_DestroyObject");
236 		if ((rv = C_DestroyObject(sess, objs[i])) != CKR_OK) {
237 			if (label.pValue != NULL)
238 				cryptoerror(LOG_STDERR, gettext(
239 				    "Unable to delete object #%d \"%.*s\" "
240 				    "(%s)."), i+1, label.ulValueLen,
241 				    label.pValue, pkcs11_strerror(rv));
242 			else
243 				cryptoerror(LOG_STDERR, gettext(
244 				    "Unable to delete object #%d (%s)."),
245 				    i+1, pkcs11_strerror(rv));
246 		} else {
247 			if (label.pValue != NULL)
248 				(void) fprintf(stdout, gettext("Object #%d "
249 				    "\"%.*s\" successfully deleted.\n"),
250 				    i+1, label.ulValueLen, label.pValue);
251 			else
252 				(void) fprintf(stdout, gettext(
253 				    "Object #%d successfully deleted.\n"), i+1);
254 		}
255 
256 		if (label.pValue != NULL)
257 			free(label.pValue);
258 	}
259 
260 	/* Clean up. */
261 	quick_finish(sess);
262 	return (0);
263 }
264