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  * Administration for metaslot
31  *
32  * All the "list" operations will call functions in libpkcs11.so
33  * Normally, it doesn't make sense to call functions in libpkcs11.so directly
34  * because libpkcs11.so depends on the configuration file (pkcs11.conf) the
35  * cryptoadm command is trying to administer.  However, since metaslot
36  * is part of the framework, it is not possible to get information about
37  * it without actually calling functions in libpkcs11.so.
38  *
39  * So, for the listing operation, which won't modify the value of pkcs11.conf
40  * it is safe to call libpkcs11.so.
41  *
42  * For other operations that modifies the pkcs11.conf file, libpkcs11.so
43  * will not be called.
44  *
45  */
46 
47 #include <cryptoutil.h>
48 #include <stdio.h>
49 #include <libintl.h>
50 #include <dlfcn.h>
51 #include <link.h>
52 #include <strings.h>
53 #include <security/cryptoki.h>
54 #include <cryptoutil.h>
55 #include "cryptoadm.h"
56 
57 #define	METASLOT_ID	0
58 
59 int
60 list_metaslot_info(boolean_t show_mechs, boolean_t verbose,
61     mechlist_t *mechlist)
62 {
63 	int rc = SUCCESS;
64 	CK_RV rv;
65 	CK_SLOT_INFO slot_info;
66 	CK_TOKEN_INFO token_info;
67 	CK_MECHANISM_TYPE_PTR pmech_list = NULL;
68 	CK_ULONG mech_count;
69 	int i;
70 	CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR);
71 	CK_FUNCTION_LIST_PTR	funcs;
72 	void *dldesc = NULL;
73 	boolean_t lib_initialized = B_FALSE;
74 	uentry_t *puent;
75 	char buf[128];
76 
77 
78 	/*
79 	 * Display the system-wide metaslot settings as specified
80 	 * in pkcs11.conf file.
81 	 */
82 	if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
83 		cryptoerror(LOG_STDERR,
84 		    gettext("metaslot entry doesn't exist."));
85 		return (FAILURE);
86 	}
87 
88 	(void) printf(gettext("System-wide Meta Slot Configuration:\n"));
89 	/*
90 	 * TRANSLATION_NOTE:
91 	 * Strictly for appearance's sake, this line should be as long as
92 	 * the length of the translated text above.
93 	 */
94 	(void) printf(gettext("------------------------------------\n"));
95 	(void) printf(gettext("Status: %s\n"), puent->flag_metaslot_enabled ?
96 	    gettext("enabled") : gettext("disabled"));
97 	(void) printf(gettext("Sensitive Token Object Automatic Migrate: %s\n"),
98 	    puent->flag_metaslot_auto_key_migrate ? gettext("enabled") :
99 	    gettext("disabled"));
100 
101 	bzero(buf, sizeof (buf));
102 	if (memcmp(puent->metaslot_ks_slot, buf, SLOT_DESCRIPTION_SIZE) != 0) {
103 		(void) printf(gettext("Persistent object store slot: %s\n"),
104 		    puent->metaslot_ks_slot);
105 	}
106 
107 	if (memcmp(puent->metaslot_ks_token, buf, TOKEN_LABEL_SIZE) != 0) {
108 		(void) printf(gettext("Persistent object store token: %s\n"),
109 		    puent->metaslot_ks_token);
110 	}
111 
112 	if ((!verbose) && (!show_mechs)) {
113 		return (SUCCESS);
114 	}
115 
116 	if (verbose) {
117 		(void) printf(gettext("\nDetailed Meta Slot Information:\n"));
118 		/*
119 		 * TRANSLATION_NOTE:
120 		 * Strictly for appearance's sake, this line should be as
121 		 * long as the length of the translated text above.
122 		 */
123 		(void) printf(gettext("-------------------------------\n"));
124 	}
125 
126 	/*
127 	 * Need to actually make calls to libpkcs11.so to get
128 	 * information about metaslot.
129 	 */
130 
131 	dldesc = dlopen(UEF_FRAME_LIB, RTLD_NOW);
132 	if (dldesc == NULL) {
133 		char *dl_error;
134 		dl_error = dlerror();
135 		cryptodebug("Cannot load PKCS#11 framework library. "
136 		    "dlerror:%s", dl_error);
137 		return (FAILURE);
138 	}
139 
140 	/* Get the pointer to library's C_GetFunctionList() */
141 	Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList");
142 	if (Tmp_C_GetFunctionList == NULL) {
143 		cryptodebug("Cannot get the address of the C_GetFunctionList "
144 		    "from framework");
145 		rc = FAILURE;
146 		goto finish;
147 	}
148 
149 
150 	/* Get the provider's function list */
151 	rv = Tmp_C_GetFunctionList(&funcs);
152 	if (rv != CKR_OK) {
153 		cryptodebug("failed to call C_GetFunctionList in "
154 		    "framework library");
155 		rc = FAILURE;
156 		goto finish;
157 	}
158 
159 	/* Initialize this provider */
160 	rv = funcs->C_Initialize(NULL_PTR);
161 	if (rv != CKR_OK) {
162 		cryptodebug("C_Initialize failed with error code 0x%x\n", rv);
163 		rc = FAILURE;
164 		goto finish;
165 	} else {
166 		lib_initialized = B_TRUE;
167 	}
168 
169 	/*
170 	 * We know for sure that metaslot is slot 0 in the framework,
171 	 * so, we will do a C_GetSlotInfo() trying to see if it works.
172 	 * If it failes with CKR_SLOT_ID_INVALID, we know that metaslot
173 	 * is not really enabled.
174 	 */
175 	rv = funcs->C_GetSlotInfo(METASLOT_ID, &slot_info);
176 	if (rv == CKR_SLOT_ID_INVALID) {
177 		(void) printf(gettext("actual status: disabled.\n"));
178 		/*
179 		 * Even if the -m and -v flag is supplied, there's nothing
180 		 * interesting to display about metaslot since it is disabled,
181 		 * so, just stop right here.
182 		 */
183 		goto finish;
184 	}
185 
186 	if (rv != CKR_OK) {
187 		cryptodebug("C_GetSlotInfo failed with error "
188 		    "code 0x%x\n", rv);
189 		rc = FAILURE;
190 		goto finish;
191 	}
192 
193 	if (!verbose) {
194 		goto display_mechs;
195 	}
196 
197 	(void) printf(gettext("actual status: enabled.\n"));
198 
199 	(void) printf(gettext("Description: %.64s\n"),
200 	    slot_info.slotDescription);
201 
202 	(void) printf(gettext("Token Present: %s\n"),
203 	    (slot_info.flags & CKF_TOKEN_PRESENT ?
204 	    gettext("True") : gettext("False")));
205 
206 	rv = funcs->C_GetTokenInfo(METASLOT_ID, &token_info);
207 	if (rv != CKR_OK) {
208 		cryptodebug("C_GetTokenInfo failed with error "
209 		    "code 0x%x\n", rv);
210 		rc = FAILURE;
211 		goto finish;
212 	}
213 
214 	(void) printf(gettext("Token Label: %.32s\n"
215 	    "Manufacturer ID: %.32s\n"
216 	    "Model: %.16s\n"
217 	    "Serial Number: %.16s\n"
218 	    "Hardware Version: %d.%d\n"
219 	    "Firmware Version: %d.%d\n"
220 	    "UTC Time: %.16s\n"
221 	    "PIN Length: %d-%d\n"),
222 	    token_info.label,
223 	    token_info.manufacturerID,
224 	    token_info.model,
225 	    token_info.serialNumber,
226 	    token_info.hardwareVersion.major,
227 	    token_info.hardwareVersion.minor,
228 	    token_info.firmwareVersion.major,
229 	    token_info.firmwareVersion.minor,
230 	    token_info.utcTime,
231 	    token_info.ulMinPinLen,
232 	    token_info.ulMaxPinLen);
233 
234 	display_token_flags(token_info.flags);
235 
236 	if (!show_mechs) {
237 		goto finish;
238 	}
239 
240 display_mechs:
241 
242 	if (mechlist == NULL) {
243 		rv = funcs->C_GetMechanismList(METASLOT_ID, NULL_PTR,
244 		    &mech_count);
245 		if (rv != CKR_OK) {
246 			cryptodebug("C_GetMechanismList failed with error "
247 			    "code 0x%x\n", rv);
248 			rc = FAILURE;
249 			goto finish;
250 		}
251 
252 		if (mech_count > 0) {
253 			pmech_list = malloc(mech_count *
254 			    sizeof (CK_MECHANISM_TYPE));
255 			if (pmech_list == NULL) {
256 				cryptodebug("out of memory");
257 				rc = FAILURE;
258 				goto finish;
259 			}
260 			rv = funcs->C_GetMechanismList(METASLOT_ID, pmech_list,
261 			    &mech_count);
262 			if (rv != CKR_OK) {
263 				cryptodebug("C_GetMechanismList failed with "
264 				    "error code 0x%x\n", rv);
265 				rc = FAILURE;
266 				goto finish;
267 			}
268 		}
269 	} else {
270 		rc = convert_mechlist(&pmech_list, &mech_count, mechlist);
271 		if (rc != SUCCESS) {
272 			goto finish;
273 		}
274 	}
275 
276 	(void) printf(gettext("Mechanisms:\n"));
277 	if (mech_count == 0) {
278 		/* should never be this case */
279 		(void) printf(gettext("No mechanisms\n"));
280 		goto finish;
281 	}
282 	if (verbose) {
283 		display_verbose_mech_header();
284 	}
285 
286 	for (i = 0; i < mech_count; i++) {
287 		(void) printf("%-29s", pkcs11_mech2str(pmech_list[i]));
288 		if (verbose) {
289 			CK_MECHANISM_INFO mech_info;
290 			rv = funcs->C_GetMechanismInfo(METASLOT_ID,
291 			    pmech_list[i], &mech_info);
292 			if (rv != CKR_OK) {
293 				cryptodebug("C_GetMechanismInfo failed with "
294 				    "error code 0x%x\n", rv);
295 				rc = FAILURE;
296 				goto finish;
297 			}
298 			display_mech_info(&mech_info);
299 		}
300 		(void) printf("\n");
301 	}
302 
303 finish:
304 
305 	if ((rc == FAILURE) && (show_mechs)) {
306 		(void) printf(gettext(
307 		    "metaslot: failed to retrieve the mechanism list.\n"));
308 	}
309 
310 	if (lib_initialized) {
311 		(void) funcs->C_Finalize(NULL_PTR);
312 	}
313 
314 	if (dldesc != NULL) {
315 		(void) dlclose(dldesc);
316 	}
317 
318 	if (pmech_list != NULL) {
319 		(void) free(pmech_list);
320 	}
321 
322 	return (rc);
323 }
324 
325 int
326 list_metaslot_policy()
327 {
328 
329 	uentry_t *puent;
330 	int rc;
331 
332 	if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
333 		cryptoerror(LOG_STDERR,
334 		    gettext("metaslot entry doesn't exist."));
335 		return (FAILURE);
336 	}
337 
338 	rc = display_policy(puent);
339 	(void) printf("\n");
340 	free_uentry(puent);
341 	return (rc);
342 }
343 
344 /*
345  * disable metaslot and some of its configuration options
346  *
347  * If mechlist==NULL, and the other 2 flags are false, just disabled
348  * the metaslot feature.
349  *
350  * mechlist: list of mechanisms to disable
351  * allflag: if true, indicates all mechanisms should be disabled.
352  * auto_key_migrate_flag: if true, indicates auto key migrate should be disabled
353  */
354 int
355 disable_metaslot(mechlist_t *mechlist, boolean_t allflag,
356     boolean_t auto_key_migrate_flag)
357 {
358 	uentry_t *puent;
359 	int rc = SUCCESS;
360 
361 	if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
362 		cryptoerror(LOG_STDERR,
363 		    gettext("metaslot entry doesn't exist."));
364 		return (FAILURE);
365 	}
366 
367 
368 	if ((mechlist == NULL) && (!auto_key_migrate_flag) && (!allflag)) {
369 		/* disable metaslot */
370 		puent->flag_metaslot_enabled = B_FALSE;
371 		goto write_to_file;
372 	}
373 
374 	if (auto_key_migrate_flag) {
375 		/* need to disable auto_key_migrate */
376 		puent->flag_metaslot_auto_key_migrate = B_FALSE;
377 	}
378 
379 	if ((mechlist == NULL) && (!allflag)) {
380 		goto write_to_file;
381 	}
382 
383 	/* disable specified mechanisms */
384 	if (allflag) {
385 		free_umechlist(puent->policylist);
386 		puent->policylist = NULL;
387 		puent->count = 0;
388 		puent->flag_enabledlist = B_TRUE;
389 		rc = SUCCESS;
390 	} else {
391 		if (puent->flag_enabledlist == B_TRUE) {
392 			/*
393 			 * The current default policy mode
394 			 * is "all are disabled, except ...", so if a
395 			 * specified mechanism is in the exception list
396 			 * (the policylist), delete it from the policylist.
397 			 */
398 			rc = update_policylist(puent, mechlist, DELETE_MODE);
399 		} else {
400 			/*
401 			 * The current default policy mode of this library
402 			 * is "all are enabled", so if a specified mechanism
403 			 * is not in the exception list (policylist), add
404 			 * it into the policylist.
405 			 */
406 			rc = update_policylist(puent, mechlist, ADD_MODE);
407 		}
408 	}
409 
410 	if (rc != SUCCESS) {
411 		goto finish;
412 	}
413 
414 	/* If all mechanisms are disabled, metaslot will be disabled as well */
415 	if ((puent->flag_enabledlist) && (puent->count == 0)) {
416 		puent->flag_metaslot_enabled = B_FALSE;
417 	}
418 
419 write_to_file:
420 
421 	rc = update_pkcs11conf(puent);
422 
423 finish:
424 	free_uentry(puent);
425 	return (rc);
426 }
427 
428 /*
429  * enable metaslot and some of its configuration options
430  *
431  * If mechlist==NULL, and the other flags are false, or not specified,
432  * just enable the metaslot feature.
433  *
434  * token: if specified, indicate label of token to be used as keystore.
435  * slot: if specified, indicate slot to be used as keystore.
436  * use_default: if true, indicate to use the default keystore.  It should
437  * 		not be specified if either token or slot is specified.
438  * mechlist: list of mechanisms to enable
439  * allflag: if true, indicates all mechanisms should be enabled.
440  * auto_key_migrate_flag: if true, indicates auto key migrate should be enabled
441  */
442 int
443 enable_metaslot(char *token, char *slot, boolean_t use_default,
444     mechlist_t *mechlist,  boolean_t allflag, boolean_t auto_key_migrate_flag)
445 {
446 	uentry_t *puent;
447 	int rc = SUCCESS;
448 
449 	if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
450 		cryptoerror(LOG_STDERR,
451 		    gettext("metaslot entry doesn't exist."));
452 		return (FAILURE);
453 	}
454 
455 	puent->flag_metaslot_enabled = B_TRUE;
456 
457 	if (auto_key_migrate_flag) {
458 		/* need to enable auto_key_migrate */
459 		puent->flag_metaslot_auto_key_migrate = B_TRUE;
460 	}
461 
462 	if (allflag) {
463 		/*
464 		 * If enabling all, what needs to be done are cleaning up the
465 		 * policylist and setting the "flag_enabledlist" flag to
466 		 * B_FALSE.
467 		 */
468 		free_umechlist(puent->policylist);
469 		puent->policylist = NULL;
470 		puent->count = 0;
471 		puent->flag_enabledlist = B_FALSE;
472 		rc = SUCCESS;
473 	} else {
474 		if (mechlist) {
475 			if (puent->flag_enabledlist == B_TRUE) {
476 				/*
477 				 * The current default policy mode of this
478 				 * library is "all are disabled, except ...",
479 				 * so if a specified mechanism is not in the
480 				 * exception list (policylist), add it.
481 				 */
482 				rc = update_policylist(puent, mechlist,
483 				    ADD_MODE);
484 			} else {
485 				/*
486 				 * The current default policy mode of this
487 				 * library is "all are enabled, except", so if
488 				 * a specified  mechanism is in the exception
489 				 * list (policylist), delete it.
490 				 */
491 				rc = update_policylist(puent, mechlist,
492 				    DELETE_MODE);
493 			}
494 		}
495 	}
496 
497 	if (rc != SUCCESS) {
498 		goto finish;
499 	}
500 
501 	if (!use_default && !token && !slot) {
502 		/* no need to change metaslot keystore */
503 		goto write_to_file;
504 	}
505 
506 	(void) bzero((char *)puent->metaslot_ks_token, TOKEN_LABEL_SIZE);
507 	(void) bzero((char *)puent->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE);
508 
509 	if (use_default) {
510 		(void) strlcpy((char *)puent->metaslot_ks_token,
511 		    SOFT_TOKEN_LABEL, TOKEN_LABEL_SIZE);
512 		(void) strlcpy((char *)puent->metaslot_ks_slot,
513 		    SOFT_SLOT_DESCRIPTION, SLOT_DESCRIPTION_SIZE);
514 	} else {
515 
516 		if (token) {
517 			(void) strlcpy((char *)puent->metaslot_ks_token, token,
518 			    TOKEN_LABEL_SIZE);
519 		}
520 
521 		if (slot) {
522 			(void) strlcpy((char *)puent->metaslot_ks_slot, slot,
523 			    SLOT_DESCRIPTION_SIZE);
524 		}
525 	}
526 
527 
528 write_to_file:
529 
530 	rc = update_pkcs11conf(puent);
531 
532 finish:
533 	free_uentry(puent);
534 	return (rc);
535 }
536