OpenSolaris_b135/lib/pkcs11/pkcs11_kernel/common/kernelSlotToken.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdlib.h>
#include <strings.h>
#include <security/cryptoki.h>
#include <cryptoutil.h>
#include <errno.h>
#include <sys/crypto/api.h>
#include <sys/crypto/common.h>
#include <sys/crypto/ioctl.h>
#include <sys/crypto/spi.h>
#include "kernelGlobal.h"
#include "kernelSlot.h"


/* ARGSUSED */
CK_RV
C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
    CK_ULONG_PTR pulCount)
{
	int i;

	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (pulCount == NULL) {
		return (CKR_ARGUMENTS_BAD);
	}

	if (pSlotList == NULL) {
		*pulCount = slot_count;
		return (CKR_OK);
	}

	if (*pulCount < slot_count) {
		*pulCount = slot_count;
		return (CKR_BUFFER_TOO_SMALL);
	}

	*pulCount = slot_count;

	/*
	 * The slotID returned to an application will be the index to
	 * the slot_table.  The library will map to the provider_id when
	 * making any ioctl call.
	 */
	for (i = 0; i < slot_count; i++) {
		pSlotList[i] = i;
	}

	return (CKR_OK);
}


CK_RV
C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
{
	CK_RV rv;
	crypto_get_provider_info_t gi;
	int r;

	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID >= slot_count) {
		return (CKR_SLOT_ID_INVALID);
	}

	if (pInfo == NULL)
		return (CKR_ARGUMENTS_BAD);

	/* kernel provider numbers start with 0 */
	gi.gi_provider_id = slot_table[slotID]->sl_provider_id;
	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_INFO, &gi)) < 0) {
		if (errno != EINTR)
			break;
	}
	if (r < 0) {
		rv = CKR_FUNCTION_FAILED;
	} else {
		if (gi.gi_return_value != CRYPTO_SUCCESS) {
			rv = crypto2pkcs11_error_number(
			    gi.gi_return_value);
		} else {
			rv = CKR_OK;
		}
	}

	if (rv == CKR_OK) {
		bcopy(gi.gi_provider_data.pd_prov_desc,
		    pInfo->slotDescription, CRYPTO_PROVIDER_DESCR_MAX_LEN);
		bcopy(gi.gi_provider_data.pd_manufacturerID,
		    pInfo->manufacturerID, CRYPTO_EXT_SIZE_MANUF);
		pInfo->flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT;
		pInfo->hardwareVersion.major =
		    gi.gi_provider_data.pd_hardware_version.cv_major;
		pInfo->hardwareVersion.minor =
		    gi.gi_provider_data.pd_hardware_version.cv_minor;
		pInfo->firmwareVersion.major =
		    gi.gi_provider_data.pd_firmware_version.cv_major;
		pInfo->firmwareVersion.minor =
		    gi.gi_provider_data.pd_firmware_version.cv_minor;
	}

	return (rv);
}


CK_RV
C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
{
	CK_RV rv;
	crypto_get_provider_info_t gi;
	int r;

	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID >= slot_count)
		return (CKR_SLOT_ID_INVALID);

	if (pInfo == NULL)
		return (CKR_ARGUMENTS_BAD);

	gi.gi_provider_id = slot_table[slotID]->sl_provider_id;
	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_INFO, &gi)) < 0) {
		if (errno != EINTR)
			break;
	}
	if (r < 0) {
		rv = CKR_FUNCTION_FAILED;
	} else {
		rv = crypto2pkcs11_error_number(gi.gi_return_value);
	}

	if (rv == CKR_OK) {
		bcopy(gi.gi_provider_data.pd_label, pInfo->label,
		    CRYPTO_EXT_SIZE_LABEL);
		bcopy(gi.gi_provider_data.pd_manufacturerID,
		    pInfo->manufacturerID, CRYPTO_EXT_SIZE_MANUF);
		bcopy(gi.gi_provider_data.pd_model, pInfo->model,
		    CRYPTO_EXT_SIZE_MODEL);
		bcopy(gi.gi_provider_data.pd_serial_number,
		    pInfo->serialNumber, CRYPTO_EXT_SIZE_SERIAL);
		pInfo->flags = gi.gi_provider_data.pd_flags;
		pInfo->ulMaxSessionCount =
		    gi.gi_provider_data.pd_max_session_count;
		pInfo->ulSessionCount =
		    gi.gi_provider_data.pd_session_count;
		pInfo->ulMaxRwSessionCount =
		    gi.gi_provider_data.pd_max_rw_session_count;
		pInfo->ulRwSessionCount =
		    gi.gi_provider_data.pd_rw_session_count;
		pInfo->ulMaxPinLen =
		    gi.gi_provider_data.pd_max_pin_len;
		pInfo->ulMinPinLen =
		    gi.gi_provider_data.pd_min_pin_len;
		pInfo->ulTotalPublicMemory =
		    gi.gi_provider_data.pd_total_public_memory;
		pInfo->ulFreePublicMemory =
		    gi.gi_provider_data.pd_free_public_memory;
		pInfo->ulTotalPrivateMemory =
		    gi.gi_provider_data.pd_total_private_memory;
		pInfo->ulFreePrivateMemory =
		    gi.gi_provider_data.pd_free_private_memory;
		pInfo->hardwareVersion.major =
		    gi.gi_provider_data.pd_hardware_version.cv_major;
		pInfo->hardwareVersion.minor =
		    gi.gi_provider_data.pd_hardware_version.cv_minor;
		pInfo->firmwareVersion.major =
		    gi.gi_provider_data.pd_firmware_version.cv_major;
		pInfo->firmwareVersion.minor =
		    gi.gi_provider_data.pd_firmware_version.cv_minor;
		(void) strncpy((char *)pInfo->utcTime,
		    (const char *)gi.gi_provider_data.pd_time,
		    CRYPTO_EXT_SIZE_TIME);

	}

	return (rv);


}

/*ARGSUSED*/
CK_RV
C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
{
	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	return (CKR_FUNCTION_NOT_SUPPORTED);
}


CK_RV
C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList,
    CK_ULONG_PTR pulCount)
{
	CK_MECHANISM_TYPE type;
	CK_RV rv;
	CK_FLAGS flags;
	CK_ULONG specified_count, count = 0;
	crypto_get_provider_mechanisms_t *pm, tmp;
	crypto_get_provider_mechanism_info_t mechanism_info;
	crypto_provider_id_t provider_id;
	size_t alloc_bytes;
	int i, r;

	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID >= slot_count)
		return (CKR_SLOT_ID_INVALID);

	/* kernel provider numbers start with 0 */
	provider_id = slot_table[slotID]->sl_provider_id;

	if (pMechanismList != NULL) {
		if (pulCount == NULL) {
			return (CKR_ARGUMENTS_BAD);
		} else if (*pulCount == 0) {
			return (CKR_ARGUMENTS_BAD);
		}
	}
	specified_count = *pulCount;
	tmp.pm_provider_id = provider_id;
	tmp.pm_count = 0;
	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_MECHANISMS,
	    &tmp)) < 0) {
		if (errno != EINTR)
			break;
	}
	if (r < 0) {
		return (CKR_FUNCTION_FAILED);
	} else {
		if (tmp.pm_return_value != CRYPTO_SUCCESS) {
			rv = crypto2pkcs11_error_number(tmp.pm_return_value);
			return (rv);
		}
		alloc_bytes = sizeof (crypto_get_provider_mechanisms_t) +
		    (tmp.pm_count - 1) * sizeof (crypto_mech_name_t);
	}

	pm = malloc(alloc_bytes);
	if (pm == NULL)
		return (CKR_HOST_MEMORY);

	pm->pm_provider_id = provider_id;
	pm->pm_count = tmp.pm_count;

	while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_MECHANISMS, pm)) < 0) {
		if (errno != EINTR)
			break;
	}
	if (r < 0) {
		rv = CKR_FUNCTION_FAILED;
	} else {
		rv = crypto2pkcs11_error_number(pm->pm_return_value);
	}

	if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL)
		goto clean_exit;

	for (i = 0; i < pm->pm_count; i++) {
		mechanism_info.mi_provider_id = provider_id;
		bcopy(&pm->pm_list[i][0], mechanism_info.mi_mechanism_name,
		    sizeof (crypto_mech_name_t));

		/*
		 * Get each mechanism's flags.
		 * The ioctl should not fail since the mechanism info is
		 * already in the kernel and a call doesn't have to be made
		 * to the provider. If it fails, nothing can be done other
		 * than skip the mechanism.
		 */
		while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_MECHANISM_INFO,
		    &mechanism_info)) < 0) {
			if (errno != EINTR)
				break;
		}
		if (r < 0) {
			continue;
		}

		if (mechanism_info.mi_return_value != CRYPTO_SUCCESS)
			continue;

		flags = mechanism_info.mi_flags;

		/*
		 * Atomic flags are not part of PKCS#11 so we filter
		 * them out here.
		 */
		flags &= ~(CRYPTO_FG_DIGEST_ATOMIC | CRYPTO_FG_ENCRYPT_ATOMIC |
		    CRYPTO_FG_DECRYPT_ATOMIC | CRYPTO_FG_MAC_ATOMIC |
		    CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC |
		    CRYPTO_FG_SIGN_RECOVER_ATOMIC |
		    CRYPTO_FG_VERIFY_RECOVER_ATOMIC |
		    CRYPTO_FG_ENCRYPT_MAC_ATOMIC |
		    CRYPTO_FG_MAC_DECRYPT_ATOMIC);

		/* mechanism has no PKCS#11 flags, so don't report it */
		if (flags == 0)
			continue;

		/*
		 * The kernel framework has a pseudo mechanism
		 * for RNG which we remove from the list of mechanisms.
		 */
		if (strcmp(&pm->pm_list[i][0], "random") != 0) {

			if (pkcs11_str2mech(&pm->pm_list[i][0],
			    &type) != CKR_OK)
				continue;

			if (pMechanismList != NULL && rv == CKR_OK &&
			    (count < specified_count))
				pMechanismList[count] = type;

			count++;
		}

	}

	if (pMechanismList != NULL && (count > specified_count))
		rv = CKR_BUFFER_TOO_SMALL;

	*pulCount = count;

clean_exit:
	free(pm);
	return (rv);
}


CK_RV
C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
    CK_MECHANISM_INFO_PTR pInfo)
{
	uint32_t k_mi_flags;
	CK_RV rv;

	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID >= slot_count)
		return (CKR_SLOT_ID_INVALID);

	if (pInfo == NULL) {
		return (CKR_ARGUMENTS_BAD);
	}

	rv = get_mechanism_info(slot_table[slotID], type, pInfo, &k_mi_flags);

	return (rv);
}


/*ARGSUSED*/
CK_RV
C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen,
    CK_UTF8CHAR_PTR pLabel)
{
	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	return (CKR_FUNCTION_NOT_SUPPORTED);
}

/*ARGSUSED*/
CK_RV
C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
{
	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	return (CKR_FUNCTION_NOT_SUPPORTED);
}


CK_RV
C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin,
    CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen)
{
	CK_RV	rv = CKR_OK;
	kernel_session_t *session_p;
	boolean_t ses_lock_held = B_FALSE;
	crypto_set_pin_t	setpin;
	int r;

	if (!kernel_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	/*
	 * Obtain the session pointer. Also, increment the session
	 * reference count.
	 */
	rv = handle2session(hSession, &session_p);
	if (rv != CKR_OK)
		return (rv);

	/* Make sure it is a RW session. */
	if (session_p->ses_RO) {
		rv = CKR_SESSION_READ_ONLY;
		REFRELE(session_p, ses_lock_held);
		return (rv);
	}

	/* Lock the session and make the CRYPTO_SET_PIN ioctl call. */
	(void) pthread_mutex_lock(&session_p->session_mutex);
	ses_lock_held = B_TRUE;

	setpin.sp_session = session_p->k_session;
	setpin.sp_old_pin = (char *)pOldPin;
	setpin.sp_old_len = ulOldLen;
	setpin.sp_new_pin = (char *)pNewPin;
	setpin.sp_new_len = ulNewLen;

	while ((r = ioctl(kernel_fd, CRYPTO_SET_PIN, &setpin)) < 0) {
		if (errno != EINTR)
			break;
	}
	if (r < 0) {
		rv = CKR_FUNCTION_FAILED;
	} else {
		rv = crypto2pkcs11_error_number(setpin.sp_return_value);
	}

	REFRELE(session_p, ses_lock_held);
	return (rv);
}