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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <errno.h>
26 #include <security/cryptoki.h>
27 #include <strings.h>
28 #include <sys/crypto/ioctl.h>
29 #include "kernelGlobal.h"
30 #include "kernelSlot.h"
31 
32 CK_ULONG	slot_count = 0;
33 kernel_slot_t	**slot_table;
34 
35 static CK_RV
36 kernel_get_slot_number()
37 {
38 	CK_RV rv;
39 	crypto_get_provider_list_t *pl;
40 	int r;
41 
42 	pl = malloc(sizeof (crypto_get_provider_list_t));
43 	if (pl == NULL)
44 		return (CKR_HOST_MEMORY);
45 
46 	pl->pl_count = 0;
47 	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_LIST, pl)) < 0) {
48 		if (errno != EINTR)
49 			break;
50 	}
51 	if (r < 0) {
52 		rv = CKR_FUNCTION_FAILED;
53 	} else {
54 		if (pl->pl_return_value != CRYPTO_SUCCESS) {
55 			rv = crypto2pkcs11_error_number(pl->pl_return_value);
56 		} else {
57 			rv = CKR_OK;
58 		}
59 	}
60 
61 	if (rv == CKR_OK) {
62 		slot_count = pl->pl_count;
63 	}
64 
65 	(void) free(pl);
66 	return (rv);
67 }
68 
69 /*
70  * This function will be used by metaslot to get the kernel
71  * provider's threshold value for the supported mechanisms.
72  */
73 void
74 _SUNW_GetThreshold(void *thresholdp)
75 {
76 
77 	cipher_mechs_threshold_t *tp = (cipher_mechs_threshold_t *)thresholdp;
78 	kernel_slot_t *pslot;
79 	int i;
80 
81 	/*
82 	 * We alway use the 1st slot in the kernel to
83 	 * get the threshold because all the kernel
84 	 * slots will have the same threshold value
85 	 * with the same mechanism.
86 	 */
87 	pslot = slot_table[0];
88 
89 	for (i = 0; i < pslot->total_threshold_count; i++) {
90 		tp[i].mech_type =
91 		    pslot->sl_mechs_threshold[i].mech_type;
92 		tp[i].mech_threshold =
93 		    pslot->sl_mechs_threshold[i].mech_threshold;
94 	}
95 }
96 
97 /*
98  * To retrieve the crypto_function_list structure with boolean entries
99  * indicating which functions are supported by the hardware provider which
100  * is specified by the slot ID.
101  */
102 static CK_RV
103 kernel_get_func_list(kernel_slot_t *pslot)
104 {
105 	CK_RV rv = CKR_OK;
106 	crypto_get_function_list_t  fl;
107 	int r;
108 	int i;
109 
110 	(void) memset(&fl, 0, sizeof (fl));
111 	fl.fl_provider_id = pslot->sl_provider_id;
112 
113 	while ((r = ioctl(kernel_fd, CRYPTO_GET_FUNCTION_LIST, &fl)) < 0) {
114 		if (errno != EINTR)
115 			break;
116 	}
117 	if (r < 0) {
118 		rv = CKR_FUNCTION_FAILED;
119 	} else {
120 		if (fl.fl_return_value == 0) {
121 			rv = CKR_OK;
122 		} else {
123 			rv = crypto2pkcs11_error_number(fl.fl_return_value);
124 		}
125 	}
126 
127 	if (rv != CKR_OK) {
128 		return (rv);
129 	}
130 
131 	/* copy data structure received from kernel */
132 	pslot->sl_func_list = fl.fl_list;
133 
134 	pslot->sl_flags = 0;
135 	if (fl.fl_list.prov_is_hash_limited) {
136 		pslot->sl_flags |= CRYPTO_LIMITED_HASH_SUPPORT;
137 		pslot->sl_hash_max_inlen = fl.fl_list.prov_hash_limit;
138 	}
139 
140 	if (fl.fl_list.prov_is_hmac_limited) {
141 		pslot->sl_flags |= CRYPTO_LIMITED_HMAC_SUPPORT;
142 		pslot->sl_hmac_max_inlen = fl.fl_list.prov_hmac_limit;
143 	}
144 
145 	if (fl.fl_list.prov_is_hash_limited | fl.fl_list.prov_is_hmac_limited) {
146 		pslot->sl_threshold = fl.fl_list.prov_hash_threshold;
147 	}
148 
149 	pslot->total_threshold_count = fl.fl_list.total_threshold_count;
150 
151 	for (i = 0; i < pslot->total_threshold_count; i++) {
152 		pslot->sl_mechs_threshold[i].mech_type =
153 		    fl.fl_list.fl_threshold[i].mech_type;
154 		pslot->sl_mechs_threshold[i].mech_threshold =
155 		    fl.fl_list.fl_threshold[i].mech_threshold;
156 	}
157 
158 	return (CKR_OK);
159 }
160 
161 /*
162  * Initialize the slot table.
163  *
164  * This function is called from C_Initialize() only.  Since C_Initialize()
165  * holds the global mutex lock, there is no need to acquire another lock
166  * in this routine to protect the slot table.
167  */
168 CK_RV
169 kernel_slottable_init()
170 {
171 	int i, cur_slot_num = 0;
172 	CK_RV rv = CKR_OK;
173 	crypto_get_provider_list_t *pl = NULL;
174 	int r;
175 
176 	/*
177 	 * Find out how many slots are presented from kernel hardware
178 	 * providers. If there is no slot presented, just return.
179 	 */
180 	rv = kernel_get_slot_number();
181 	if (rv != CKR_OK || slot_count == 0) {
182 		return (rv);
183 	}
184 
185 	/* Allocate space for the slot table */
186 	slot_table = malloc(sizeof (kernel_slot_t *) * slot_count);
187 	if (slot_table == NULL) {
188 		return (CKR_HOST_MEMORY);
189 	}
190 
191 	/* For each slot, allocate space and initialize the slot's mutex. */
192 	for (i = 0; i < slot_count; i++) {
193 		slot_table[i] = malloc(sizeof (kernel_slot_t));
194 		if (slot_table[i] == NULL) {
195 			rv = CKR_HOST_MEMORY;
196 			goto failed;
197 		}
198 
199 		slot_table[i]->sl_sess_list = NULL;
200 		slot_table[i]->sl_tobj_list = NULL;
201 		slot_table[i]->sl_state = CKU_PUBLIC;
202 
203 		/* Initialize this slot's mutex */
204 		if (pthread_mutex_init(&slot_table[i]->sl_mutex, NULL) != 0) {
205 			rv = CKR_FUNCTION_FAILED;
206 			(void) free(slot_table[i]);
207 			goto failed;
208 		}
209 
210 		cur_slot_num = i;
211 	}
212 
213 	/*
214 	 * Get the provider ID for each slot from kernel and save it in the
215 	 * slot table.
216 	 */
217 	pl = malloc(slot_count * sizeof (crypto_get_provider_list_t));
218 	if (pl == NULL) {
219 		rv = CKR_HOST_MEMORY;
220 		goto failed;
221 	}
222 
223 	pl->pl_count = slot_count;
224 	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_LIST, pl)) < 0) {
225 		if (errno != EINTR)
226 			break;
227 	}
228 	if (r < 0) {
229 		rv = CKR_FUNCTION_FAILED;
230 		goto failed;
231 	} else {
232 		if (pl->pl_return_value != CRYPTO_SUCCESS) {
233 			rv = crypto2pkcs11_error_number(pl->pl_return_value);
234 			goto failed;
235 		} else {
236 			rv = CKR_OK;
237 		}
238 	}
239 
240 	for (i = 0; i < slot_count; i++) {
241 		slot_table[i]->sl_provider_id = pl->pl_list[i].pe_provider_id;
242 	}
243 
244 	/*
245 	 * Get the function list for each slot from kernel and save it in
246 	 * the slot table.
247 	 */
248 	for (i = 0; i < slot_count; i++) {
249 		rv = kernel_get_func_list(slot_table[i]);
250 		if (rv != CKR_OK) {
251 			goto failed;
252 		}
253 	}
254 
255 	(void) free(pl);
256 	return (CKR_OK);
257 
258 failed:
259 	for (i = 0; i < cur_slot_num; i++) {
260 		(void) pthread_mutex_destroy(&slot_table[i]->sl_mutex);
261 		(void) free(slot_table[i]);
262 	}
263 
264 	(void) free(slot_table);
265 	(void) free(pl);
266 	return (rv);
267 }
268