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