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