2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <errno.h>
2N/A#include <security/cryptoki.h>
2N/A#include <string.h>
2N/A#include <sys/crypto/ioctl.h>
2N/A#include "kernelGlobal.h"
2N/A#include "kernelSlot.h"
2N/A
2N/ACK_ULONG slot_count = 0;
2N/Akernel_slot_t **slot_table;
2N/A
2N/Astatic CK_RV
2N/Akernel_get_slot_number()
2N/A{
2N/A CK_RV rv;
2N/A crypto_get_provider_list_t *pl;
2N/A int r;
2N/A
2N/A pl = malloc(sizeof (crypto_get_provider_list_t));
2N/A if (pl == NULL)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A pl->pl_count = 0;
2N/A while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_LIST, pl)) < 0) {
2N/A if (errno != EINTR)
2N/A break;
2N/A }
2N/A if (r < 0) {
2N/A rv = CKR_FUNCTION_FAILED;
2N/A } else {
2N/A if (pl->pl_return_value != CRYPTO_SUCCESS) {
2N/A rv = crypto2pkcs11_error_number(pl->pl_return_value);
2N/A } else {
2N/A rv = CKR_OK;
2N/A }
2N/A }
2N/A
2N/A if (rv == CKR_OK) {
2N/A slot_count = pl->pl_count;
2N/A }
2N/A
2N/A (void) free(pl);
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * This function will be used by metaslot to get the kernel
2N/A * provider's threshold value for the supported mechanisms.
2N/A */
2N/Avoid
2N/A_SUNW_GetThreshold(void *thresholdp)
2N/A{
2N/A
2N/A cipher_mechs_threshold_t *tp = (cipher_mechs_threshold_t *)thresholdp;
2N/A kernel_slot_t *pslot;
2N/A int i;
2N/A
2N/A /*
2N/A * We alway use the 1st slot in the kernel to
2N/A * get the threshold because all the kernel
2N/A * slots will have the same threshold value
2N/A * with the same mechanism.
2N/A */
2N/A pslot = slot_table[0];
2N/A
2N/A for (i = 0; i < pslot->total_threshold_count; i++) {
2N/A tp[i].mech_type =
2N/A pslot->sl_mechs_threshold[i].mech_type;
2N/A tp[i].mech_threshold =
2N/A pslot->sl_mechs_threshold[i].mech_threshold;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * To retrieve the crypto_function_list structure with boolean entries
2N/A * indicating which functions are supported by the hardware provider which
2N/A * is specified by the slot ID.
2N/A */
2N/Astatic CK_RV
2N/Akernel_get_func_list(kernel_slot_t *pslot)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A crypto_get_function_list_t fl;
2N/A int r;
2N/A int i;
2N/A
2N/A (void) memset(&fl, 0, sizeof (fl));
2N/A fl.fl_provider_id = pslot->sl_provider_id;
2N/A
2N/A while ((r = ioctl(kernel_fd, CRYPTO_GET_FUNCTION_LIST, &fl)) < 0) {
2N/A if (errno != EINTR)
2N/A break;
2N/A }
2N/A if (r < 0) {
2N/A rv = CKR_FUNCTION_FAILED;
2N/A } else {
2N/A if (fl.fl_return_value == 0) {
2N/A rv = CKR_OK;
2N/A } else {
2N/A rv = crypto2pkcs11_error_number(fl.fl_return_value);
2N/A }
2N/A }
2N/A
2N/A if (rv != CKR_OK) {
2N/A return (rv);
2N/A }
2N/A
2N/A /* copy data structure received from kernel */
2N/A pslot->sl_func_list = fl.fl_list;
2N/A
2N/A pslot->sl_flags = 0;
2N/A if (fl.fl_list.prov_is_hash_limited) {
2N/A pslot->sl_flags |= CRYPTO_LIMITED_HASH_SUPPORT;
2N/A pslot->sl_hash_max_inlen = fl.fl_list.prov_hash_limit;
2N/A }
2N/A
2N/A if (fl.fl_list.prov_is_hmac_limited) {
2N/A pslot->sl_flags |= CRYPTO_LIMITED_HMAC_SUPPORT;
2N/A pslot->sl_hmac_max_inlen = fl.fl_list.prov_hmac_limit;
2N/A }
2N/A
2N/A if (fl.fl_list.prov_is_hash_limited | fl.fl_list.prov_is_hmac_limited) {
2N/A pslot->sl_threshold = fl.fl_list.prov_hash_threshold;
2N/A }
2N/A
2N/A pslot->total_threshold_count = fl.fl_list.total_threshold_count;
2N/A
2N/A for (i = 0; i < pslot->total_threshold_count; i++) {
2N/A pslot->sl_mechs_threshold[i].mech_type =
2N/A fl.fl_list.fl_threshold[i].mech_type;
2N/A pslot->sl_mechs_threshold[i].mech_threshold =
2N/A fl.fl_list.fl_threshold[i].mech_threshold;
2N/A }
2N/A
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A/*
2N/A * Initialize the slot table.
2N/A *
2N/A * This function is called from C_Initialize() only. Since C_Initialize()
2N/A * holds the global mutex lock, there is no need to acquire another lock
2N/A * in this routine to protect the slot table.
2N/A */
2N/ACK_RV
2N/Akernel_slottable_init()
2N/A{
2N/A int i, cur_slot_num = -1;
2N/A CK_RV rv = CKR_OK;
2N/A crypto_get_provider_list_t *pl = NULL;
2N/A int r;
2N/A
2N/A /*
2N/A * Find out how many slots are presented from kernel hardware
2N/A * providers. If there is no slot presented, just return.
2N/A */
2N/A rv = kernel_get_slot_number();
2N/A if (rv != CKR_OK || slot_count == 0) {
2N/A return (rv);
2N/A }
2N/A
2N/A /* Allocate space for the slot table */
2N/A slot_table = malloc(sizeof (kernel_slot_t *) * slot_count);
2N/A if (slot_table == NULL) {
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A
2N/A /* For each slot, allocate space and initialize the slot's mutex. */
2N/A for (i = 0; i < slot_count; i++) {
2N/A slot_table[i] = malloc(sizeof (kernel_slot_t));
2N/A if (slot_table[i] == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto failed;
2N/A }
2N/A
2N/A slot_table[i]->sl_sess_list = NULL;
2N/A slot_table[i]->sl_tobj_list = NULL;
2N/A slot_table[i]->sl_state = CKU_PUBLIC;
2N/A slot_table[i]->sl_hash_max_inlen = CRYPTO_MAX_BUFFER_LEN;
2N/A slot_table[i]->sl_hmac_max_inlen = CRYPTO_MAX_BUFFER_LEN;
2N/A
2N/A /* Initialize this slot's mutex */
2N/A if (pthread_mutex_init(&slot_table[i]->sl_mutex, NULL) != 0) {
2N/A rv = CKR_FUNCTION_FAILED;
2N/A (void) free(slot_table[i]);
2N/A slot_table[i] = NULL;
2N/A goto failed;
2N/A }
2N/A
2N/A cur_slot_num = i;
2N/A }
2N/A
2N/A /*
2N/A * Get the provider ID for each slot from kernel and save it in the
2N/A * slot table.
2N/A */
2N/A pl = malloc(slot_count * sizeof (crypto_get_provider_list_t));
2N/A if (pl == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto failed;
2N/A }
2N/A
2N/A pl->pl_count = slot_count;
2N/A while ((r = ioctl(kernel_fd, CRYPTO_GET_PROVIDER_LIST, pl)) < 0) {
2N/A if (errno != EINTR)
2N/A break;
2N/A }
2N/A if (r < 0) {
2N/A rv = CKR_FUNCTION_FAILED;
2N/A goto failed;
2N/A } else {
2N/A if (pl->pl_return_value != CRYPTO_SUCCESS) {
2N/A rv = crypto2pkcs11_error_number(pl->pl_return_value);
2N/A goto failed;
2N/A } else {
2N/A rv = CKR_OK;
2N/A }
2N/A }
2N/A
2N/A for (i = 0; i < slot_count; i++) {
2N/A slot_table[i]->sl_provider_id = pl->pl_list[i].pe_provider_id;
2N/A }
2N/A
2N/A /*
2N/A * Get the function list for each slot from kernel and save it in
2N/A * the slot table.
2N/A */
2N/A for (i = 0; i < slot_count; i++) {
2N/A rv = kernel_get_func_list(slot_table[i]);
2N/A if (rv != CKR_OK) {
2N/A goto failed;
2N/A }
2N/A }
2N/A
2N/A (void) free(pl);
2N/A return (CKR_OK);
2N/A
2N/Afailed:
2N/A for (i = 0; i <= cur_slot_num; i++) {
2N/A (void) pthread_mutex_destroy(&slot_table[i]->sl_mutex);
2N/A (void) free(slot_table[i]);
2N/A }
2N/A
2N/A (void) free(slot_table);
2N/A (void) free(pl);
2N/A return (rv);
2N/A}