xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelSlotToken.c (revision 012e6ce759c490003aed29439cc47d3d73a99ad3)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <security/cryptoki.h>
30 #include <cryptoutil.h>
31 #include <errno.h>
32 #include <sys/crypto/api.h>
33 #include <sys/crypto/common.h>
34 #include <sys/crypto/ioctl.h>
35 #include <sys/crypto/spi.h>
36 #include "kernelGlobal.h"
37 #include "kernelSlot.h"
38 
39 
40 /* ARGSUSED */
41 CK_RV
42 C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
43     CK_ULONG_PTR pulCount)
44 {
45 	int i;
46 
47 	if (!kernel_initialized)
48 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
49 
50 	if (pulCount == NULL) {
51 		return (CKR_ARGUMENTS_BAD);
52 	}
53 
54 	if (pSlotList == NULL) {
55 		*pulCount = slot_count;
56 		return (CKR_OK);
57 	}
58 
59 	if (*pulCount < slot_count) {
60 		*pulCount = slot_count;
61 		return (CKR_BUFFER_TOO_SMALL);
62 	}
63 
64 	*pulCount = slot_count;
65 
66 	/*
67 	 * The slotID returned to an application will be the index to
68 	 * the slot_table.  The library will map to the provider_id when
69 	 * making any ioctl call.
70 	 */
71 	for (i = 0; i < slot_count; i++) {
72 		pSlotList[i] = i;
73 	}
74 
75 	return (CKR_OK);
76 }
77 
78 
79 CK_RV
80 C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
81 {
82 	CK_RV rv;
83 	crypto_get_provider_info_t gi;
84 	int r;
85 
86 	if (!kernel_initialized)
87 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
88 
89 	if (slotID >= slot_count) {
90 		return (CKR_SLOT_ID_INVALID);
91 	}
92 
93 	if (pInfo == NULL)
94 		return (CKR_ARGUMENTS_BAD);
95 
96 	/* kernel provider numbers start with 0 */
97 	gi.gi_provider_id = slot_table[slotID]->sl_provider_id;
98 	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_INFO, &gi)) < 0) {
99 		if (errno != EINTR)
100 			break;
101 	}
102 	if (r < 0) {
103 		rv = CKR_FUNCTION_FAILED;
104 	} else {
105 		if (gi.gi_return_value != CRYPTO_SUCCESS) {
106 			rv = crypto2pkcs11_error_number(
107 			    gi.gi_return_value);
108 		} else {
109 			rv = CKR_OK;
110 		}
111 	}
112 
113 	if (rv == CKR_OK) {
114 		bcopy(gi.gi_provider_data.pd_prov_desc,
115 		    pInfo->slotDescription, CRYPTO_PROVIDER_DESCR_MAX_LEN);
116 		bcopy(gi.gi_provider_data.pd_manufacturerID,
117 		    pInfo->manufacturerID, CRYPTO_EXT_SIZE_MANUF);
118 		pInfo->flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT;
119 		pInfo->hardwareVersion.major =
120 		    gi.gi_provider_data.pd_hardware_version.cv_major;
121 		pInfo->hardwareVersion.minor =
122 		    gi.gi_provider_data.pd_hardware_version.cv_minor;
123 		pInfo->firmwareVersion.major =
124 		    gi.gi_provider_data.pd_firmware_version.cv_major;
125 		pInfo->firmwareVersion.minor =
126 		    gi.gi_provider_data.pd_firmware_version.cv_minor;
127 	}
128 
129 	return (rv);
130 }
131 
132 
133 CK_RV
134 C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
135 {
136 	CK_RV rv;
137 	crypto_get_provider_info_t gi;
138 	int r;
139 
140 	if (!kernel_initialized)
141 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
142 
143 	if (slotID >= slot_count)
144 		return (CKR_SLOT_ID_INVALID);
145 
146 	if (pInfo == NULL)
147 		return (CKR_ARGUMENTS_BAD);
148 
149 	gi.gi_provider_id = slot_table[slotID]->sl_provider_id;
150 	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_INFO, &gi)) < 0) {
151 		if (errno != EINTR)
152 			break;
153 	}
154 	if (r < 0) {
155 		rv = CKR_FUNCTION_FAILED;
156 	} else {
157 		rv = crypto2pkcs11_error_number(gi.gi_return_value);
158 	}
159 
160 	if (rv == CKR_OK) {
161 		bcopy(gi.gi_provider_data.pd_label, pInfo->label,
162 		    CRYPTO_EXT_SIZE_LABEL);
163 		bcopy(gi.gi_provider_data.pd_manufacturerID,
164 		    pInfo->manufacturerID, CRYPTO_EXT_SIZE_MANUF);
165 		bcopy(gi.gi_provider_data.pd_model, pInfo->model,
166 		    CRYPTO_EXT_SIZE_MODEL);
167 		bcopy(gi.gi_provider_data.pd_serial_number,
168 		    pInfo->serialNumber, CRYPTO_EXT_SIZE_SERIAL);
169 		pInfo->flags = gi.gi_provider_data.pd_flags;
170 		pInfo->ulMaxSessionCount =
171 		    gi.gi_provider_data.pd_max_session_count;
172 		pInfo->ulSessionCount =
173 		    gi.gi_provider_data.pd_session_count;
174 		pInfo->ulMaxRwSessionCount =
175 		    gi.gi_provider_data.pd_max_rw_session_count;
176 		pInfo->ulRwSessionCount =
177 		    gi.gi_provider_data.pd_rw_session_count;
178 		pInfo->ulMaxPinLen =
179 		    gi.gi_provider_data.pd_max_pin_len;
180 		pInfo->ulMinPinLen =
181 		    gi.gi_provider_data.pd_min_pin_len;
182 		pInfo->ulTotalPublicMemory =
183 		    gi.gi_provider_data.pd_total_public_memory;
184 		pInfo->ulFreePublicMemory =
185 		    gi.gi_provider_data.pd_free_public_memory;
186 		pInfo->ulTotalPrivateMemory =
187 		    gi.gi_provider_data.pd_total_private_memory;
188 		pInfo->ulFreePrivateMemory =
189 		    gi.gi_provider_data.pd_free_private_memory;
190 		pInfo->hardwareVersion.major =
191 		    gi.gi_provider_data.pd_hardware_version.cv_major;
192 		pInfo->hardwareVersion.minor =
193 		    gi.gi_provider_data.pd_hardware_version.cv_minor;
194 		pInfo->firmwareVersion.major =
195 		    gi.gi_provider_data.pd_firmware_version.cv_major;
196 		pInfo->firmwareVersion.minor =
197 		    gi.gi_provider_data.pd_firmware_version.cv_minor;
198 		(void) strncpy((char *)pInfo->utcTime,
199 		    (const char *)gi.gi_provider_data.pd_time,
200 		    CRYPTO_EXT_SIZE_TIME);
201 
202 	}
203 
204 	return (rv);
205 
206 
207 }
208 
209 /*ARGSUSED*/
210 CK_RV
211 C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
212 {
213 	if (!kernel_initialized)
214 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
215 
216 	return (CKR_FUNCTION_NOT_SUPPORTED);
217 }
218 
219 
220 CK_RV
221 C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList,
222     CK_ULONG_PTR pulCount)
223 {
224 	CK_MECHANISM_TYPE type;
225 	CK_RV rv;
226 	CK_FLAGS flags;
227 	CK_ULONG specified_count, count = 0;
228 	crypto_get_provider_mechanisms_t *pm, tmp;
229 	crypto_get_provider_mechanism_info_t mechanism_info;
230 	crypto_provider_id_t provider_id;
231 	size_t alloc_bytes;
232 	int i, r;
233 
234 	if (!kernel_initialized)
235 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
236 
237 	if (slotID >= slot_count)
238 		return (CKR_SLOT_ID_INVALID);
239 
240 	/* kernel provider numbers start with 0 */
241 	provider_id = slot_table[slotID]->sl_provider_id;
242 
243 	if (pMechanismList != NULL) {
244 		if (pulCount == NULL) {
245 			return (CKR_ARGUMENTS_BAD);
246 		} else if (*pulCount == 0) {
247 			return (CKR_ARGUMENTS_BAD);
248 		}
249 	}
250 	specified_count = *pulCount;
251 	tmp.pm_provider_id = provider_id;
252 	tmp.pm_count = 0;
253 	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_MECHANISMS,
254 	    &tmp)) < 0) {
255 		if (errno != EINTR)
256 			break;
257 	}
258 	if (r < 0) {
259 		return (CKR_FUNCTION_FAILED);
260 	} else {
261 		if (tmp.pm_return_value != CRYPTO_SUCCESS) {
262 			rv = crypto2pkcs11_error_number(tmp.pm_return_value);
263 			return (rv);
264 		}
265 		alloc_bytes = sizeof (crypto_get_provider_mechanisms_t) +
266 		    (tmp.pm_count - 1) * sizeof (crypto_mech_name_t);
267 	}
268 
269 	pm = malloc(alloc_bytes);
270 	if (pm == NULL)
271 		return (CKR_HOST_MEMORY);
272 
273 	pm->pm_provider_id = provider_id;
274 	pm->pm_count = tmp.pm_count;
275 
276 	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_MECHANISMS, pm)) < 0) {
277 		if (errno != EINTR)
278 			break;
279 	}
280 	if (r < 0) {
281 		rv = CKR_FUNCTION_FAILED;
282 	} else {
283 		rv = crypto2pkcs11_error_number(pm->pm_return_value);
284 	}
285 
286 	if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL)
287 		goto clean_exit;
288 
289 	for (i = 0; i < pm->pm_count; i++) {
290 		mechanism_info.mi_provider_id = provider_id;
291 		bcopy(&pm->pm_list[i][0], mechanism_info.mi_mechanism_name,
292 		    sizeof (crypto_mech_name_t));
293 
294 		/*
295 		 * Get each mechanism's flags.
296 		 * The ioctl should not fail since the mechanism info is
297 		 * already in the kernel and a call doesn't have to be made
298 		 * to the provider. If it fails, nothing can be done other
299 		 * than skip the mechanism.
300 		 */
301 		while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_MECHANISM_INFO,
302 		    &mechanism_info)) < 0) {
303 			if (errno != EINTR)
304 				break;
305 		}
306 		if (r < 0) {
307 			continue;
308 		}
309 
310 		if (mechanism_info.mi_return_value != CRYPTO_SUCCESS)
311 			continue;
312 
313 		flags = mechanism_info.mi_flags;
314 
315 		/*
316 		 * Atomic flags are not part of PKCS#11 so we filter
317 		 * them out here.
318 		 */
319 		flags &= ~(CRYPTO_FG_DIGEST_ATOMIC | CRYPTO_FG_ENCRYPT_ATOMIC |
320 		    CRYPTO_FG_DECRYPT_ATOMIC | CRYPTO_FG_MAC_ATOMIC |
321 		    CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC |
322 		    CRYPTO_FG_SIGN_RECOVER_ATOMIC |
323 		    CRYPTO_FG_VERIFY_RECOVER_ATOMIC |
324 		    CRYPTO_FG_ENCRYPT_MAC_ATOMIC |
325 		    CRYPTO_FG_MAC_DECRYPT_ATOMIC);
326 
327 		/* mechanism has no PKCS#11 flags, so don't report it */
328 		if (flags == 0)
329 			continue;
330 
331 		/*
332 		 * The kernel framework has a pseudo mechanism
333 		 * for RNG which we remove from the list of mechanisms.
334 		 */
335 		if (strcmp(&pm->pm_list[i][0], "random") != 0) {
336 
337 			if (pkcs11_str2mech(&pm->pm_list[i][0],
338 			    &type) != CKR_OK)
339 				continue;
340 
341 			if (pMechanismList != NULL && rv == CKR_OK &&
342 			    (count < specified_count))
343 				pMechanismList[count] = type;
344 
345 			count++;
346 		}
347 
348 	}
349 
350 	if (pMechanismList != NULL && (count > specified_count))
351 		rv = CKR_BUFFER_TOO_SMALL;
352 
353 	*pulCount = count;
354 
355 clean_exit:
356 	free(pm);
357 	return (rv);
358 }
359 
360 
361 CK_RV
362 C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
363     CK_MECHANISM_INFO_PTR pInfo)
364 {
365 	uint32_t k_mi_flags;
366 	CK_RV rv;
367 
368 	if (!kernel_initialized)
369 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
370 
371 	if (slotID >= slot_count)
372 		return (CKR_SLOT_ID_INVALID);
373 
374 	if (pInfo == NULL) {
375 		return (CKR_ARGUMENTS_BAD);
376 	}
377 
378 	rv = get_mechanism_info(slot_table[slotID], type, pInfo, &k_mi_flags);
379 
380 	return (rv);
381 }
382 
383 
384 /*ARGSUSED*/
385 CK_RV
386 C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen,
387     CK_UTF8CHAR_PTR pLabel)
388 {
389 	if (!kernel_initialized)
390 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
391 
392 	return (CKR_FUNCTION_NOT_SUPPORTED);
393 }
394 
395 /*ARGSUSED*/
396 CK_RV
397 C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
398 {
399 	if (!kernel_initialized)
400 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
401 
402 	return (CKR_FUNCTION_NOT_SUPPORTED);
403 }
404 
405 
406 CK_RV
407 C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin,
408     CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen)
409 {
410 	CK_RV	rv = CKR_OK;
411 	kernel_session_t *session_p;
412 	boolean_t ses_lock_held = B_FALSE;
413 	crypto_set_pin_t	setpin;
414 	int r;
415 
416 	if (!kernel_initialized)
417 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
418 
419 	/*
420 	 * Obtain the session pointer. Also, increment the session
421 	 * reference count.
422 	 */
423 	rv = handle2session(hSession, &session_p);
424 	if (rv != CKR_OK)
425 		return (rv);
426 
427 	/* Make sure it is a RW session. */
428 	if (session_p->ses_RO) {
429 		rv = CKR_SESSION_READ_ONLY;
430 		REFRELE(session_p, ses_lock_held);
431 		return (rv);
432 	}
433 
434 	/* Lock the session and make the CRYPTO_SET_PIN ioctl call. */
435 	(void) pthread_mutex_lock(&session_p->session_mutex);
436 	ses_lock_held = B_TRUE;
437 
438 	setpin.sp_session = session_p->k_session;
439 	setpin.sp_old_pin = (char *)pOldPin;
440 	setpin.sp_old_len = ulOldLen;
441 	setpin.sp_new_pin = (char *)pNewPin;
442 	setpin.sp_new_len = ulNewLen;
443 
444 	while ((r = ioctl(kernel_fd, CRYPTO_SET_PIN, &setpin)) < 0) {
445 		if (errno != EINTR)
446 			break;
447 	}
448 	if (r < 0) {
449 		rv = CKR_FUNCTION_FAILED;
450 	} else {
451 		rv = crypto2pkcs11_error_number(setpin.sp_return_value);
452 	}
453 
454 	REFRELE(session_p, ses_lock_held);
455 	return (rv);
456 }
457