xref: /titanic_51/usr/src/lib/libkmf/libkmf/common/pk11tokens.c (revision 47e946e784719ae402ace34695f67b0e6e76ae5c)
199ebb4caSwyllys /*
299ebb4caSwyllys  * CDDL HEADER START
399ebb4caSwyllys  *
499ebb4caSwyllys  * The contents of this file are subject to the terms of the
599ebb4caSwyllys  * Common Development and Distribution License (the "License").
699ebb4caSwyllys  * You may not use this file except in compliance with the License.
799ebb4caSwyllys  *
899ebb4caSwyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
999ebb4caSwyllys  * or http://www.opensolaris.org/os/licensing.
1099ebb4caSwyllys  * See the License for the specific language governing permissions
1199ebb4caSwyllys  * and limitations under the License.
1299ebb4caSwyllys  *
1399ebb4caSwyllys  * When distributing Covered Code, include this CDDL HEADER in each
1499ebb4caSwyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1599ebb4caSwyllys  * If applicable, add the following below this CDDL HEADER, with the
1699ebb4caSwyllys  * fields enclosed by brackets "[]" replaced with your own identifying
1799ebb4caSwyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
1899ebb4caSwyllys  *
1999ebb4caSwyllys  * CDDL HEADER END
2099ebb4caSwyllys  *
21*47e946e7SWyllys Ingersoll  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2271593db2Swyllys  * Use is subject to license terms.
2399ebb4caSwyllys  */
2499ebb4caSwyllys 
2599ebb4caSwyllys #include <stdio.h>
2699ebb4caSwyllys #include <stdlib.h>
2799ebb4caSwyllys #include <string.h>
2899ebb4caSwyllys #include <ctype.h>
2999ebb4caSwyllys #include <security/cryptoki.h>
3099ebb4caSwyllys #include <kmfapi.h>
3199ebb4caSwyllys #include <kmfapiP.h>
3299ebb4caSwyllys #include <cryptoutil.h>
3399ebb4caSwyllys 
3499ebb4caSwyllys /*
3599ebb4caSwyllys  * memcmp_pad_max() is a specialized version of memcmp() which
3699ebb4caSwyllys  * compares two pieces of data up to a maximum length.  If the
3799ebb4caSwyllys  * the two data match up the maximum length, they are considered
3899ebb4caSwyllys  * matching.  Trailing blanks do not cause the match to fail if
3999ebb4caSwyllys  * one of the data is shorted.
4099ebb4caSwyllys  *
4199ebb4caSwyllys  * Examples of matches:
4299ebb4caSwyllys  *	"one"           |
4399ebb4caSwyllys  *	"one      "     |
4499ebb4caSwyllys  *	                ^maximum length
4599ebb4caSwyllys  *
4699ebb4caSwyllys  *	"Number One     |  X"	(X is beyond maximum length)
4799ebb4caSwyllys  *	"Number One   " |
4899ebb4caSwyllys  *	                ^maximum length
4999ebb4caSwyllys  *
5099ebb4caSwyllys  * Examples of mismatches:
5199ebb4caSwyllys  *	" one"
5299ebb4caSwyllys  *	"one"
5399ebb4caSwyllys  *
5499ebb4caSwyllys  *	"Number One    X|"
5599ebb4caSwyllys  *	"Number One     |"
5699ebb4caSwyllys  *	                ^maximum length
5799ebb4caSwyllys  */
5899ebb4caSwyllys static int
5999ebb4caSwyllys memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
6099ebb4caSwyllys {
6199ebb4caSwyllys 	uint_t		len, extra_len;
6299ebb4caSwyllys 	char		*marker;
6399ebb4caSwyllys 
6499ebb4caSwyllys 	/* No point in comparing anything beyond max_sz */
6599ebb4caSwyllys 	if (d1_len > max_sz)
6699ebb4caSwyllys 		d1_len = max_sz;
6799ebb4caSwyllys 	if (d2_len > max_sz)
6899ebb4caSwyllys 		d2_len = max_sz;
6999ebb4caSwyllys 
7099ebb4caSwyllys 	/* Find shorter of the two data. */
7199ebb4caSwyllys 	if (d1_len <= d2_len) {
7299ebb4caSwyllys 		len = d1_len;
7399ebb4caSwyllys 		extra_len = d2_len;
7499ebb4caSwyllys 		marker = d2;
7599ebb4caSwyllys 	} else {	/* d1_len > d2_len */
7699ebb4caSwyllys 		len = d2_len;
7799ebb4caSwyllys 		extra_len = d1_len;
7899ebb4caSwyllys 		marker = d1;
7999ebb4caSwyllys 	}
8099ebb4caSwyllys 
8199ebb4caSwyllys 	/* Have a match in the shortest length of data? */
8299ebb4caSwyllys 	if (memcmp(d1, d2, len) != 0)
8399ebb4caSwyllys 		/* CONSTCOND */
8499ebb4caSwyllys 		return (1);
8599ebb4caSwyllys 
8699ebb4caSwyllys 	/* If the rest of longer data is nulls or blanks, call it a match. */
870fb5f8a6SWyllys Ingersoll 	while (len < extra_len && marker[len])
8899ebb4caSwyllys 		if (!isspace(marker[len++]))
8999ebb4caSwyllys 			/* CONSTCOND */
9099ebb4caSwyllys 			return (1);
9199ebb4caSwyllys 	return (0);
9299ebb4caSwyllys }
9399ebb4caSwyllys 
9499ebb4caSwyllys static KMF_RETURN
9599ebb4caSwyllys kmf_get_token_slots(KMF_HANDLE *handle, CK_SLOT_ID_PTR *slot_list,
9699ebb4caSwyllys     CK_ULONG *slot_count)
9799ebb4caSwyllys {
9899ebb4caSwyllys 
9999ebb4caSwyllys 	KMF_RETURN	kmf_rv = KMF_OK;
10099ebb4caSwyllys 	CK_RV		ck_rv = CKR_OK;
10199ebb4caSwyllys 	CK_ULONG	tmp_count = 0;
10299ebb4caSwyllys 	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
10399ebb4caSwyllys 
10499ebb4caSwyllys 	ck_rv = C_GetSlotList(1, NULL_PTR, &tmp_count);
10530a5e8faSwyllys 	if (ck_rv == CKR_CRYPTOKI_NOT_INITIALIZED) {
10630a5e8faSwyllys 		ck_rv = C_Initialize(NULL);
10730a5e8faSwyllys 		if ((ck_rv != CKR_OK) &&
10830a5e8faSwyllys 		    (ck_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
10930a5e8faSwyllys 			return (KMF_ERR_UNINITIALIZED);
11030a5e8faSwyllys 		if (ck_rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
11130a5e8faSwyllys 			ck_rv = CKR_OK;
11230a5e8faSwyllys 
11330a5e8faSwyllys 		ck_rv = C_GetSlotList(1, NULL_PTR, &tmp_count);
11430a5e8faSwyllys 	}
11599ebb4caSwyllys 	if (ck_rv != CKR_OK) {
11699ebb4caSwyllys 		if (handle != NULL) {
11799ebb4caSwyllys 			handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
11899ebb4caSwyllys 			handle->lasterr.errcode = ck_rv;
11999ebb4caSwyllys 		}
12099ebb4caSwyllys 		return (KMF_ERR_INTERNAL);
12199ebb4caSwyllys 	}
12299ebb4caSwyllys 
12399ebb4caSwyllys 	if (tmp_count == 0) {
12499ebb4caSwyllys 		*slot_list = NULL_PTR;
12599ebb4caSwyllys 		*slot_count = 0;
12699ebb4caSwyllys 		return (KMF_OK);
12799ebb4caSwyllys 	}
12899ebb4caSwyllys 
12999ebb4caSwyllys 	/* Allocate initial space for the slot list. */
13099ebb4caSwyllys 	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
13199ebb4caSwyllys 	    sizeof (CK_SLOT_ID))) == NULL)
13299ebb4caSwyllys 		return (KMF_ERR_MEMORY);
13399ebb4caSwyllys 
13499ebb4caSwyllys 	/* Then get the slot list itself. */
13599ebb4caSwyllys 	for (;;) {
13699ebb4caSwyllys 		ck_rv = C_GetSlotList(1, tmp_list, &tmp_count);
13799ebb4caSwyllys 		if (ck_rv == CKR_OK) {
13899ebb4caSwyllys 			*slot_list = tmp_list;
13999ebb4caSwyllys 			*slot_count = tmp_count;
14099ebb4caSwyllys 			kmf_rv = KMF_OK;
14199ebb4caSwyllys 			break;
14299ebb4caSwyllys 		}
14399ebb4caSwyllys 
14499ebb4caSwyllys 		if (ck_rv != CKR_BUFFER_TOO_SMALL) {
14599ebb4caSwyllys 			free(tmp_list);
14699ebb4caSwyllys 			if (handle != NULL) {
14799ebb4caSwyllys 				handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
14899ebb4caSwyllys 				handle->lasterr.errcode = ck_rv;
14999ebb4caSwyllys 			}
15099ebb4caSwyllys 			kmf_rv = KMF_ERR_INTERNAL;
15199ebb4caSwyllys 			break;
15299ebb4caSwyllys 		}
15399ebb4caSwyllys 
15499ebb4caSwyllys 		/*
15599ebb4caSwyllys 		 * If the number of slots grew, try again. This
15699ebb4caSwyllys 		 * is to be consistent with pktool in ONNV.
15799ebb4caSwyllys 		 */
15899ebb4caSwyllys 		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
15999ebb4caSwyllys 		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
16099ebb4caSwyllys 			free(tmp_list);
16199ebb4caSwyllys 			kmf_rv = KMF_ERR_MEMORY;
16299ebb4caSwyllys 			break;
16399ebb4caSwyllys 		}
16499ebb4caSwyllys 		tmp_list = tmp2_list;
16599ebb4caSwyllys 	}
16699ebb4caSwyllys 
16799ebb4caSwyllys 	return (kmf_rv);
16899ebb4caSwyllys }
16999ebb4caSwyllys 
17099ebb4caSwyllys /*
17199ebb4caSwyllys  * Returns pointer to either null-terminator or next unescaped colon.  The
17299ebb4caSwyllys  * string to be extracted starts at the beginning and goes until one character
17399ebb4caSwyllys  * before this pointer.  If NULL is returned, the string itself is NULL.
17499ebb4caSwyllys  */
17599ebb4caSwyllys static char *
17699ebb4caSwyllys find_unescaped_colon(char *str)
17799ebb4caSwyllys {
17899ebb4caSwyllys 	char *end;
17999ebb4caSwyllys 
18099ebb4caSwyllys 	if (str == NULL)
18199ebb4caSwyllys 		return (NULL);
18299ebb4caSwyllys 
18399ebb4caSwyllys 	while ((end = strchr(str, ':')) != NULL) {
18499ebb4caSwyllys 		if (end != str && *(end-1) != '\\')
18599ebb4caSwyllys 			return (end);
18699ebb4caSwyllys 		str = end + 1;		/* could point to null-terminator */
18799ebb4caSwyllys 	}
18899ebb4caSwyllys 	if (end == NULL)
18999ebb4caSwyllys 		end = strchr(str, '\0');
19099ebb4caSwyllys 	return (end);
19199ebb4caSwyllys }
19299ebb4caSwyllys 
19399ebb4caSwyllys /*
19499ebb4caSwyllys  * Compresses away any characters escaped with backslash from given string.
19599ebb4caSwyllys  * The string is altered in-place.  Example, "ab\:\\e" becomes "ab:\e".
19699ebb4caSwyllys  */
19799ebb4caSwyllys static void
19899ebb4caSwyllys unescape_str(char *str)
19999ebb4caSwyllys {
20099ebb4caSwyllys 	boolean_t	escaped = B_FALSE;
20199ebb4caSwyllys 	char		*mark;
20299ebb4caSwyllys 
20399ebb4caSwyllys 	if (str == NULL)
20499ebb4caSwyllys 		return;
20599ebb4caSwyllys 
20699ebb4caSwyllys 	for (mark = str; *str != '\0'; str++) {
20799ebb4caSwyllys 		if (*str != '\\' || escaped == B_TRUE) {
20899ebb4caSwyllys 			*mark++ = *str;
20999ebb4caSwyllys 			escaped = B_FALSE;
21099ebb4caSwyllys 		} else {
21199ebb4caSwyllys 			escaped = B_TRUE;
21299ebb4caSwyllys 		}
21399ebb4caSwyllys 	}
21499ebb4caSwyllys 	*mark = '\0';
21599ebb4caSwyllys }
21699ebb4caSwyllys 
21799ebb4caSwyllys 
21899ebb4caSwyllys /*
21999ebb4caSwyllys  * Given a colon-separated token specifier, this functions splits it into
22099ebb4caSwyllys  * its label, manufacturer ID (if any), and serial number (if any).  Literal
22199ebb4caSwyllys  * colons within the label/manuf/serial can be escaped with a backslash.
22299ebb4caSwyllys  * Fields can left blank and trailing colons can be omitted, however leading
22399ebb4caSwyllys  * colons are required as placeholders.  For example, these are equivalent:
22499ebb4caSwyllys  *	(a) "lbl", "lbl:", "lbl::"	(b) "lbl:man", "lbl:man:"
22599ebb4caSwyllys  * but these are not:
22699ebb4caSwyllys  *	(c) "man", ":man"	(d) "ser", "::ser"
22799ebb4caSwyllys  * Furthermore, the token label is required always.
22899ebb4caSwyllys  *
22999ebb4caSwyllys  * The buffer containing the token specifier is altered by replacing the
23099ebb4caSwyllys  * colons to null-terminators, and pointers returned are pointers into this
23199ebb4caSwyllys  * string.  No new memory is allocated.
23299ebb4caSwyllys  */
23399ebb4caSwyllys static int
23499ebb4caSwyllys parse_token_spec(char *token_spec, char **token_name, char **manuf_id,
23599ebb4caSwyllys 	char **serial_no)
23699ebb4caSwyllys {
23799ebb4caSwyllys 	char	*mark;
23899ebb4caSwyllys 
23999ebb4caSwyllys 	if (token_spec == NULL || *token_spec == '\0') {
24099ebb4caSwyllys 		return (-1);
24199ebb4caSwyllys 	}
24299ebb4caSwyllys 
24399ebb4caSwyllys 	*token_name = NULL;
24499ebb4caSwyllys 	*manuf_id = NULL;
24599ebb4caSwyllys 	*serial_no = NULL;
24699ebb4caSwyllys 
24799ebb4caSwyllys 	/* Token label (required) */
24899ebb4caSwyllys 	mark = find_unescaped_colon(token_spec);
24999ebb4caSwyllys 	*token_name = token_spec;
25099ebb4caSwyllys 	if (*mark != '\0')
25199ebb4caSwyllys 		*mark++ = '\0';		/* mark points to next field, if any */
25299ebb4caSwyllys 	unescape_str(*token_name);
25399ebb4caSwyllys 
25499ebb4caSwyllys 	if (*(*token_name) == '\0') {	/* token label is required */
25599ebb4caSwyllys 		return (-1);
25699ebb4caSwyllys 	}
25799ebb4caSwyllys 
25899ebb4caSwyllys 	if (*mark == '\0' || *(mark+1) == '\0')		/* no more fields */
25999ebb4caSwyllys 		return (0);
26099ebb4caSwyllys 	token_spec = mark;
26199ebb4caSwyllys 
26299ebb4caSwyllys 	/* Manufacturer identifier (optional) */
26399ebb4caSwyllys 	mark = find_unescaped_colon(token_spec);
26499ebb4caSwyllys 	*manuf_id = token_spec;
26599ebb4caSwyllys 	if (*mark != '\0')
26699ebb4caSwyllys 		*mark++ = '\0';		/* mark points to next field, if any */
26799ebb4caSwyllys 	unescape_str(*manuf_id);
26899ebb4caSwyllys 
26999ebb4caSwyllys 	if (*mark == '\0' || *(mark+1) == '\0')		/* no more fields */
27099ebb4caSwyllys 		return (0);
27199ebb4caSwyllys 	token_spec = mark;
27299ebb4caSwyllys 
27399ebb4caSwyllys 	/* Serial number (optional) */
27499ebb4caSwyllys 	mark = find_unescaped_colon(token_spec);
27599ebb4caSwyllys 	*serial_no = token_spec;
27699ebb4caSwyllys 	if (*mark != '\0')
27799ebb4caSwyllys 		*mark++ = '\0';		/* null-terminate, just in case */
27899ebb4caSwyllys 	unescape_str(*serial_no);
27999ebb4caSwyllys 
28099ebb4caSwyllys 	return (0);
28199ebb4caSwyllys }
28299ebb4caSwyllys 
28399ebb4caSwyllys /*
28499ebb4caSwyllys  * Find slots that match a token identifier.  Token labels take the
28599ebb4caSwyllys  * form of:
28699ebb4caSwyllys  *	token_name:manufacturer:serial_number
28799ebb4caSwyllys  * manufacterer and serial number are optional.  If used, the fields
28899ebb4caSwyllys  * are delimited by the colon ':' character.
28999ebb4caSwyllys  */
29099ebb4caSwyllys KMF_RETURN
29130a5e8faSwyllys kmf_pk11_token_lookup(KMF_HANDLE_T handle, char *label, CK_SLOT_ID *slot_id)
29299ebb4caSwyllys {
29399ebb4caSwyllys 	KMF_RETURN	kmf_rv = KMF_OK;
29499ebb4caSwyllys 	CK_RV		rv;
29599ebb4caSwyllys 	CK_SLOT_ID_PTR	slot_list = NULL;
29699ebb4caSwyllys 	CK_TOKEN_INFO	token_info;
29799ebb4caSwyllys 	CK_ULONG	slot_count = 0;
29899ebb4caSwyllys 	int		i;
29999ebb4caSwyllys 	uint_t		len, max_sz;
30099ebb4caSwyllys 	boolean_t 	metaslot_status_enabled;
30199ebb4caSwyllys 	boolean_t 	metaslot_migrate_enabled;
30299ebb4caSwyllys 	char	*metaslot_slot_info;
30399ebb4caSwyllys 	char	*metaslot_token_info;
30499ebb4caSwyllys 	char	*tmplabel = NULL;
30599ebb4caSwyllys 	char	*token_name = NULL;
30699ebb4caSwyllys 	char	*manuf_id = NULL;
30799ebb4caSwyllys 	char	*serial_no = NULL;
30830a5e8faSwyllys 	boolean_t	tok_match = B_FALSE;
30930a5e8faSwyllys 	boolean_t	man_match = B_FALSE;
31030a5e8faSwyllys 	boolean_t	ser_match = B_FALSE;
31199ebb4caSwyllys 
31299ebb4caSwyllys 	if (slot_id == NULL || label == NULL || !strlen(label))
31399ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
31499ebb4caSwyllys 
31599ebb4caSwyllys 	if (handle == NULL) {
31699ebb4caSwyllys 		rv = C_Initialize(NULL);
31799ebb4caSwyllys 		if ((rv != CKR_OK) &&
31899ebb4caSwyllys 		    (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
31999ebb4caSwyllys 			return (KMF_ERR_UNINITIALIZED);
32099ebb4caSwyllys 		}
32199ebb4caSwyllys 	}
32299ebb4caSwyllys 
32399ebb4caSwyllys 	/*
32499ebb4caSwyllys 	 * Parse token specifier into token_name, manuf_id, serial_no.
32599ebb4caSwyllys 	 * Token_name is required; manuf_id and serial_no are optional.
32699ebb4caSwyllys 	 */
32799ebb4caSwyllys 	tmplabel = strdup(label);
32899ebb4caSwyllys 	if (tmplabel == NULL)
32999ebb4caSwyllys 		return (KMF_ERR_MEMORY);
33099ebb4caSwyllys 
33199ebb4caSwyllys 	if (parse_token_spec(tmplabel, &token_name, &manuf_id,
33299ebb4caSwyllys 	    &serial_no) < 0) {
33399ebb4caSwyllys 		free(tmplabel);
33499ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
33599ebb4caSwyllys 	}
33699ebb4caSwyllys 
33799ebb4caSwyllys 	/* Get a list of all slots with tokens present. */
33899ebb4caSwyllys 	kmf_rv = kmf_get_token_slots(handle, &slot_list, &slot_count);
33999ebb4caSwyllys 	if (kmf_rv != KMF_OK) {
34099ebb4caSwyllys 		free(tmplabel);
34199ebb4caSwyllys 		return (kmf_rv);
34299ebb4caSwyllys 	}
34399ebb4caSwyllys 
34499ebb4caSwyllys 	/* If there are no such slots, the desired token won't be found. */
34599ebb4caSwyllys 	if (slot_count == 0) {
34699ebb4caSwyllys 		free(tmplabel);
34799ebb4caSwyllys 		return (KMF_ERR_TOKEN_NOT_PRESENT);
34899ebb4caSwyllys 	}
34999ebb4caSwyllys 
35099ebb4caSwyllys 	/* Search the slot list for the token. */
35199ebb4caSwyllys 	for (i = 0; i < slot_count; i++) {
35299ebb4caSwyllys 		if (C_GetTokenInfo(slot_list[i], &token_info) != CKR_OK) {
35399ebb4caSwyllys 			continue;
35499ebb4caSwyllys 		}
35599ebb4caSwyllys 
35699ebb4caSwyllys 		/* See if the token label matches. */
35799ebb4caSwyllys 		len = strlen(token_name);
35899ebb4caSwyllys 		max_sz = sizeof (token_info.label);
35999ebb4caSwyllys 		if (memcmp_pad_max(&(token_info.label), max_sz, token_name,
36099ebb4caSwyllys 		    len, max_sz) == 0)
36199ebb4caSwyllys 			tok_match = B_TRUE;
36299ebb4caSwyllys 		/*
36399ebb4caSwyllys 		 * If manufacturer id was given, see if it actually matches.
36499ebb4caSwyllys 		 * If no manufacturer id was given, assume match is true.
36599ebb4caSwyllys 		 */
36699ebb4caSwyllys 		if (manuf_id) {
36799ebb4caSwyllys 			len = strlen(manuf_id);
36899ebb4caSwyllys 			max_sz = sizeof ((char *)(token_info.manufacturerID));
36999ebb4caSwyllys 			if (memcmp_pad_max(&(token_info.manufacturerID), max_sz,
37099ebb4caSwyllys 			    manuf_id, len, max_sz) == 0)
37199ebb4caSwyllys 				man_match = B_TRUE;
37299ebb4caSwyllys 		} else {
37399ebb4caSwyllys 			man_match = B_TRUE;
37499ebb4caSwyllys 		}
37599ebb4caSwyllys 
37699ebb4caSwyllys 		/*
37799ebb4caSwyllys 		 * If serial number was given, see if it actually matches.
37899ebb4caSwyllys 		 * If no serial number was given, assume match is true.
37999ebb4caSwyllys 		 */
38099ebb4caSwyllys 		if (serial_no) {
38199ebb4caSwyllys 			len = strlen(serial_no);
38299ebb4caSwyllys 			max_sz = sizeof ((char *)(token_info.serialNumber));
38399ebb4caSwyllys 			if (memcmp_pad_max(&(token_info.serialNumber), max_sz,
38499ebb4caSwyllys 			    serial_no, len, max_sz) == 0)
38599ebb4caSwyllys 				ser_match = B_TRUE;
38699ebb4caSwyllys 		} else {
38799ebb4caSwyllys 			ser_match = B_TRUE;
38899ebb4caSwyllys 		}
38999ebb4caSwyllys 
39099ebb4caSwyllys 		if (tok_match && man_match && ser_match)
39199ebb4caSwyllys 			break;		/* found it! */
39299ebb4caSwyllys 	}
39399ebb4caSwyllys 
39499ebb4caSwyllys 	if (i < slot_count) {
39599ebb4caSwyllys 		/* found the desired token from the slotlist */
39699ebb4caSwyllys 		*slot_id = slot_list[i];
39799ebb4caSwyllys 		free(slot_list);
39899ebb4caSwyllys 		free(tmplabel);
39999ebb4caSwyllys 		return (KMF_OK);
40099ebb4caSwyllys 	}
40199ebb4caSwyllys 
40299ebb4caSwyllys 	/*
40399ebb4caSwyllys 	 * If we didn't find the token from the slotlist, check if this token
40499ebb4caSwyllys 	 * is the one currently hidden by the metaslot. If that's case,
40599ebb4caSwyllys 	 * we can just use the metaslot, the slot 0.
40699ebb4caSwyllys 	 */
40799ebb4caSwyllys 	kmf_rv = get_metaslot_info(&metaslot_status_enabled,
40899ebb4caSwyllys 	    &metaslot_migrate_enabled, &metaslot_slot_info,
40999ebb4caSwyllys 	    &metaslot_token_info);
41099ebb4caSwyllys 	if (kmf_rv) {
41199ebb4caSwyllys 		/*
41299ebb4caSwyllys 		 * Failed to get the metaslot info.  This usually means that
41399ebb4caSwyllys 		 * metaslot is disabled from the system.
41499ebb4caSwyllys 		 */
41599ebb4caSwyllys 		kmf_rv = KMF_ERR_TOKEN_NOT_PRESENT;
41699ebb4caSwyllys 	} else {
41799ebb4caSwyllys 		max_sz = strlen(metaslot_token_info);
41899ebb4caSwyllys 		if (memcmp_pad_max(metaslot_token_info, max_sz, token_name, len,
41999ebb4caSwyllys 		    max_sz) == 0) {
42099ebb4caSwyllys 			*slot_id = slot_list[0];
42199ebb4caSwyllys 		} else {
42299ebb4caSwyllys 			kmf_rv = KMF_ERR_TOKEN_NOT_PRESENT;
42399ebb4caSwyllys 		}
42499ebb4caSwyllys 		free(metaslot_slot_info);
42599ebb4caSwyllys 		free(metaslot_token_info);
42699ebb4caSwyllys 	}
42799ebb4caSwyllys 
42899ebb4caSwyllys 	free(slot_list);
42999ebb4caSwyllys 	free(tmplabel);
43099ebb4caSwyllys 	return (kmf_rv);
43199ebb4caSwyllys }
43299ebb4caSwyllys 
43399ebb4caSwyllys KMF_RETURN
43430a5e8faSwyllys kmf_set_token_pin(KMF_HANDLE_T handle,
43530a5e8faSwyllys 	int num_attr,
43630a5e8faSwyllys 	KMF_ATTRIBUTE *attrlist)
43799ebb4caSwyllys {
43830a5e8faSwyllys 	KMF_RETURN ret = KMF_OK;
43999ebb4caSwyllys 	KMF_PLUGIN *plugin;
44030a5e8faSwyllys 	KMF_ATTRIBUTE_TESTER required_attrs[] = {
44130a5e8faSwyllys 		{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
44230a5e8faSwyllys 		{KMF_CREDENTIAL_ATTR, FALSE, sizeof (KMF_CREDENTIAL),
44330a5e8faSwyllys 			sizeof (KMF_CREDENTIAL)},
44430a5e8faSwyllys 		{KMF_NEWPIN_ATTR, FALSE, sizeof (KMF_CREDENTIAL),
44530a5e8faSwyllys 			sizeof (KMF_CREDENTIAL)},
44630a5e8faSwyllys 	};
44799ebb4caSwyllys 
44830a5e8faSwyllys 	int num_req_attrs = sizeof (required_attrs) /
44930a5e8faSwyllys 	    sizeof (KMF_ATTRIBUTE_TESTER);
45030a5e8faSwyllys 	uint32_t len;
45130a5e8faSwyllys 	KMF_KEYSTORE_TYPE kstype;
45299ebb4caSwyllys 
45330a5e8faSwyllys 	if (handle == NULL)
45499ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
45599ebb4caSwyllys 
45630a5e8faSwyllys 	CLEAR_ERROR(handle, ret);
45730a5e8faSwyllys 	if (ret != KMF_OK)
45830a5e8faSwyllys 		return (ret);
45999ebb4caSwyllys 
46030a5e8faSwyllys 	ret = test_attributes(num_req_attrs, required_attrs,
46130a5e8faSwyllys 	    0, NULL, num_attr, attrlist);
46230a5e8faSwyllys 	if (ret != KMF_OK)
46330a5e8faSwyllys 		return (ret);
46430a5e8faSwyllys 
46530a5e8faSwyllys 	len = sizeof (kstype);
46630a5e8faSwyllys 	ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, num_attr,
46730a5e8faSwyllys 	    &kstype, &len);
46830a5e8faSwyllys 	if (ret != KMF_OK)
46930a5e8faSwyllys 		return (ret);
47030a5e8faSwyllys 
47130a5e8faSwyllys 	plugin = FindPlugin(handle, kstype);
47230a5e8faSwyllys 	if (plugin != NULL) {
47330a5e8faSwyllys 		if (plugin->funclist->SetTokenPin != NULL)
47430a5e8faSwyllys 			return (plugin->funclist->SetTokenPin(handle, num_attr,
47530a5e8faSwyllys 			    attrlist));
47630a5e8faSwyllys 		else
47799ebb4caSwyllys 			return (KMF_ERR_FUNCTION_NOT_FOUND);
47830a5e8faSwyllys 	}
47930a5e8faSwyllys 	return (KMF_ERR_PLUGIN_NOTFOUND);
48099ebb4caSwyllys }
48199ebb4caSwyllys 
48299ebb4caSwyllys /*
48330a5e8faSwyllys  * Name: kmf_select_token
48499ebb4caSwyllys  *
48599ebb4caSwyllys  * Description:
48699ebb4caSwyllys  *   This function enables the user of PKCS#11 plugin to select a
48799ebb4caSwyllys  *   particular PKCS#11 token. Valid token label are required in order to
48899ebb4caSwyllys  *   successfully complete this function.
48999ebb4caSwyllys  *   All subsequent KMF APIs, which specify PKCS#11 keystore as
49099ebb4caSwyllys  *   the backend, will be performed at the selected token.
49199ebb4caSwyllys  *
49299ebb4caSwyllys  * Parameters:
49399ebb4caSwyllys  *   label(input) - pointer to the token label
49499ebb4caSwyllys  *
49599ebb4caSwyllys  * Returns:
49699ebb4caSwyllys  *   A KMF_RETURN value indicating success or specifying a particular
49799ebb4caSwyllys  *   error condition.
49899ebb4caSwyllys  *   The value KMF_OK indicates success. All other values represent
49999ebb4caSwyllys  *   an error condition.
50099ebb4caSwyllys  */
50199ebb4caSwyllys KMF_RETURN
50230a5e8faSwyllys kmf_select_token(KMF_HANDLE_T handle, char *label, int readonly)
50399ebb4caSwyllys {
50499ebb4caSwyllys 	KMF_RETURN kmf_rv = KMF_OK;
50599ebb4caSwyllys 	CK_RV ck_rv = CKR_OK;
50699ebb4caSwyllys 	CK_SLOT_ID slot_id;
50799ebb4caSwyllys 	CK_SESSION_HANDLE hSession;
50899ebb4caSwyllys 	CK_FLAGS 	openflags;
50999ebb4caSwyllys 
51099ebb4caSwyllys 	CLEAR_ERROR(handle, kmf_rv);
51199ebb4caSwyllys 	if (kmf_rv != KMF_OK)
51299ebb4caSwyllys 		return (kmf_rv);
51399ebb4caSwyllys 
51499ebb4caSwyllys 	if (label == NULL) {
51599ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
51699ebb4caSwyllys 	}
51799ebb4caSwyllys 
5189b37d296Swyllys 	kmf_rv = init_pk11();
5199b37d296Swyllys 	if (kmf_rv != KMF_OK) {
5209b37d296Swyllys 		return (kmf_rv);
52199ebb4caSwyllys 	}
52299ebb4caSwyllys 
52399ebb4caSwyllys 	/* Only one token can be active per thread */
52499ebb4caSwyllys 	if (handle->pk11handle != NULL) {
52599ebb4caSwyllys 		return (KMF_ERR_TOKEN_SELECTED);
52699ebb4caSwyllys 	}
52799ebb4caSwyllys 
52899ebb4caSwyllys 	/* Find the token with matching label */
52930a5e8faSwyllys 	kmf_rv = kmf_pk11_token_lookup(handle, label, &slot_id);
53099ebb4caSwyllys 	if (kmf_rv != KMF_OK) {
53199ebb4caSwyllys 		return (kmf_rv);
53299ebb4caSwyllys 	}
53399ebb4caSwyllys 
53499ebb4caSwyllys 	openflags = CKF_SERIAL_SESSION;
53599ebb4caSwyllys 	if (!readonly)
53699ebb4caSwyllys 		openflags |= CKF_RW_SESSION;
53799ebb4caSwyllys 
53899ebb4caSwyllys 	/* Open a session then log the user into the token */
53999ebb4caSwyllys 	ck_rv = C_OpenSession(slot_id, openflags, NULL, NULL, &hSession);
54099ebb4caSwyllys 	if (ck_rv != CKR_OK) {
54199ebb4caSwyllys 		handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
54299ebb4caSwyllys 		handle->lasterr.errcode = ck_rv;
54399ebb4caSwyllys 		return (KMF_ERR_INTERNAL);
54499ebb4caSwyllys 	}
54599ebb4caSwyllys 
54699ebb4caSwyllys 	handle->pk11handle = hSession;
54799ebb4caSwyllys 
54899ebb4caSwyllys 	return (kmf_rv);
54999ebb4caSwyllys }
55071593db2Swyllys 
55171593db2Swyllys CK_SESSION_HANDLE
55230a5e8faSwyllys kmf_get_pk11_handle(KMF_HANDLE_T kmfh)
55371593db2Swyllys {
55471593db2Swyllys 	return (kmfh->pk11handle);
55571593db2Swyllys }
556*47e946e7SWyllys Ingersoll 
557*47e946e7SWyllys Ingersoll KMF_RETURN
558*47e946e7SWyllys Ingersoll kmf_pk11_init_token(KMF_HANDLE_T handle,
559*47e946e7SWyllys Ingersoll 	char *currlabel, char *newlabel,
560*47e946e7SWyllys Ingersoll 	CK_UTF8CHAR_PTR sopin, CK_ULONG sopinlen)
561*47e946e7SWyllys Ingersoll {
562*47e946e7SWyllys Ingersoll 	KMF_RETURN ret = KMF_OK;
563*47e946e7SWyllys Ingersoll 	CK_RV ckrv;
564*47e946e7SWyllys Ingersoll 	CK_SLOT_ID slot_id = 0;
565*47e946e7SWyllys Ingersoll 
566*47e946e7SWyllys Ingersoll 	CLEAR_ERROR(handle, ret);
567*47e946e7SWyllys Ingersoll 	if (ret != KMF_OK)
568*47e946e7SWyllys Ingersoll 		return (ret);
569*47e946e7SWyllys Ingersoll 
570*47e946e7SWyllys Ingersoll 	/*
571*47e946e7SWyllys Ingersoll 	 * It is best to try and lookup tokens by label.
572*47e946e7SWyllys Ingersoll 	 */
573*47e946e7SWyllys Ingersoll 	if (currlabel != NULL) {
574*47e946e7SWyllys Ingersoll 		ret = kmf_pk11_token_lookup(handle, currlabel, &slot_id);
575*47e946e7SWyllys Ingersoll 		if (ret != KMF_OK)
576*47e946e7SWyllys Ingersoll 			return (ret);
577*47e946e7SWyllys Ingersoll 	} else {
578*47e946e7SWyllys Ingersoll 		/* We can't determine which slot to initialize */
579*47e946e7SWyllys Ingersoll 		return (KMF_ERR_TOKEN_NOT_PRESENT);
580*47e946e7SWyllys Ingersoll 	}
581*47e946e7SWyllys Ingersoll 
582*47e946e7SWyllys Ingersoll 	/* Initialize and set the new label (if given) */
583*47e946e7SWyllys Ingersoll 	ckrv = C_InitToken(slot_id, sopin, sopinlen,
584*47e946e7SWyllys Ingersoll 	    (CK_UTF8CHAR_PTR)(newlabel ? newlabel : currlabel));
585*47e946e7SWyllys Ingersoll 
586*47e946e7SWyllys Ingersoll 	if (ckrv != CKR_OK) {
587*47e946e7SWyllys Ingersoll 		if (ckrv == CKR_PIN_INCORRECT)
588*47e946e7SWyllys Ingersoll 			return (KMF_ERR_AUTH_FAILED);
589*47e946e7SWyllys Ingersoll 		else
590*47e946e7SWyllys Ingersoll 			return (KMF_ERR_INTERNAL);
591*47e946e7SWyllys Ingersoll 	}
592*47e946e7SWyllys Ingersoll 
593*47e946e7SWyllys Ingersoll 	return (ret);
594*47e946e7SWyllys Ingersoll }
595