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
32CK_ULONG	slot_count = 0;
33kernel_slot_t	**slot_table;
34
35static CK_RV
36kernel_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 */
73void
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 */
102static CK_RV
103kernel_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 */
168CK_RV
169kernel_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
258failed:
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