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
kernel_get_slot_number()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
_SUNW_GetThreshold(void * thresholdp)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
kernel_get_func_list(kernel_slot_t * pslot)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
kernel_slottable_init()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