view usr/src/lib/pkcs11/pkcs11_kms/common/kmsSlotToken.c @ 12720:3db6e0082404

PSARC 2010/195 PKCS11 KMS Provider 6944296 Solaris needs a PKCS#11 provider to allow access to KMS keystore functionality
author Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM>
date Mon, 28 Jun 2010 16:04:11 -0700
parents
children
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
 */


#include <stdlib.h>
#include <strings.h>
#include <security/cryptoki.h>
#include <cryptoutil.h>
#include <errno.h>
#include <aes_impl.h>

#include "kmsGlobal.h"
#include "kmsSlot.h"
#include "kmsKeystoreUtil.h"

/*
 * Just basic AES mechanisms (for now...)
 */
static CK_MECHANISM_TYPE kms_mechanisms[] = {
	CKM_AES_KEY_GEN,
	CKM_AES_CBC,
	CKM_AES_CBC_PAD
};

/*
 * KMS only supports 256 bit keys, so the range below is MAX-MAX
 * instead of MIN-MAX.
 */
static CK_MECHANISM_INFO kms_mechanism_info[] = {
	{AES_MAX_KEY_BYTES, AES_MAX_KEY_BYTES, CKF_GENERATE},
	{AES_MAX_KEY_BYTES, AES_MAX_KEY_BYTES, CKF_ENCRYPT|CKF_DECRYPT|
		CKF_WRAP|CKF_UNWRAP},		/* CKM_AES_CBC */
	{AES_MAX_KEY_BYTES, AES_MAX_KEY_BYTES, CKF_ENCRYPT|CKF_DECRYPT|
		CKF_WRAP|CKF_UNWRAP}		/* CKM_AES_CBC_PAD */
};

/* ARGSUSED */
CK_RV
C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
    CK_ULONG_PTR pulCount)
{
	if (!kms_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

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

	/*
	 * If KMS is not available or initialized, return 0 slots
	 * but CKR_OK status.
	 */
	if (!kms_is_initialized()) {
		*pulCount = 0;
		return (CKR_OK);
	}

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

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

	*pulCount = 1;
	pSlotList[0] = KMS_TOKEN_SLOTID;

	return (CKR_OK);
}

CK_RV
C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
{
	if (!kms_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID != KMS_TOKEN_SLOTID ||
	    !kms_is_initialized()) {
		return (CKR_SLOT_ID_INVALID);
	}

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

	/* Provide information about the slot in the provided buffer */
	(void) strncpy((char *)pInfo->slotDescription, SLOT_DESCRIPTION,
	    64);
	(void) strncpy((char *)pInfo->manufacturerID, MANUFACTURER_ID, 32);
	pInfo->flags = CKF_TOKEN_PRESENT;
	pInfo->hardwareVersion.major = HARDWARE_VERSION_MAJOR;
	pInfo->hardwareVersion.minor = HARDWARE_VERSION_MINOR;
	pInfo->firmwareVersion.major = FIRMWARE_VERSION_MAJOR;
	pInfo->firmwareVersion.minor = FIRMWARE_VERSION_MINOR;

	return (CKR_OK);
}

CK_RV
C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
{
	kms_cfg_info_t kmscfg;
	KMSAGENT_PROFILE_FLAGS kmsflags = 0;

	if (!kms_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID != KMS_TOKEN_SLOTID ||
	    !kms_is_initialized())
		return (CKR_SLOT_ID_INVALID);

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

	/* Provide information about a token in the provided buffer */
	(void) strncpy((char *)pInfo->label, KMS_TOKEN_LABEL, 32);
	(void) strncpy((char *)pInfo->manufacturerID, MANUFACTURER_ID, 32);
	(void) strncpy((char *)pInfo->model, KMS_TOKEN_MODEL, 16);
	(void) strncpy((char *)pInfo->serialNumber, KMS_TOKEN_SERIAL, 16);

	pInfo->flags = KMS_TOKEN_FLAGS;
	pInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
	pInfo->ulSessionCount = kms_session_cnt;
	pInfo->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
	pInfo->ulRwSessionCount = kms_session_rw_cnt;
	pInfo->ulMaxPinLen = MAX_PIN_LEN;
	pInfo->ulMinPinLen = MIN_PIN_LEN;
	pInfo->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
	pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
	pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
	pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
	pInfo->hardwareVersion.major = HARDWARE_VERSION_MAJOR;
	pInfo->hardwareVersion.minor = HARDWARE_VERSION_MINOR;
	pInfo->firmwareVersion.major = FIRMWARE_VERSION_MAJOR;
	pInfo->firmwareVersion.minor = FIRMWARE_VERSION_MINOR;
	(void) memset(pInfo->utcTime, ' ', 16);

	if (KMS_GetConfigInfo(&kmscfg) == CKR_OK &&
	    KMSAgent_GetProfileStatus(kmscfg.name, &kmsflags) ==
	    KMS_AGENT_STATUS_OK) {

		if ((kmsflags & KMSAGENT_PROFILE_EXISTS_FLAG) &&
		    (kmsflags & KMSAGENT_CLIENTKEY_EXISTS_FLAG))
			pInfo->flags |= CKF_TOKEN_INITIALIZED;
		else
			pInfo->flags &= ~CKF_TOKEN_INITIALIZED;
	}
	return (CKR_OK);
}

/*ARGSUSED*/
CK_RV
C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
{
	if (!kms_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)
{
	int i;
	ulong_t mechnum;

	/*
	 * Just check to see if the library has been
	 * properly initialized.
	 */
	if (!kms_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	/*
	 * This is different from above check, this verifies that
	 * the KMS token is actually configured.
	 */
	if (slotID != KMS_TOKEN_SLOTID ||
	    !kms_is_initialized())
		return (CKR_SLOT_ID_INVALID);

	mechnum = sizeof (kms_mechanisms) / sizeof (CK_MECHANISM_TYPE);
	if (pMechanismList == NULL) {
		*pulCount = mechnum;
		return (CKR_OK);
	}
	if (*pulCount < mechnum) {
		*pulCount = mechnum;
		return (CKR_BUFFER_TOO_SMALL);
	}
	for (i = 0; i < mechnum; i++)
		pMechanismList[i] = kms_mechanisms[i];

	*pulCount = mechnum;

	return (CKR_OK);
}

CK_RV
C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
    CK_MECHANISM_INFO_PTR pInfo)
{
	CK_ULONG mechnum, i;

	if (!kms_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID != KMS_TOKEN_SLOTID ||
	    !kms_is_initialized())
		return (CKR_SLOT_ID_INVALID);

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

	mechnum = sizeof (kms_mechanisms) / sizeof (CK_MECHANISM_TYPE);
	for (i = 0; i < mechnum; i++) {
		if (kms_mechanisms[i] == type)
			break;
	}

	if (i == mechnum)
		/* unsupported mechanism */
		return (CKR_MECHANISM_INVALID);

	pInfo->ulMinKeySize = kms_mechanism_info[i].ulMinKeySize;
	pInfo->ulMaxKeySize = kms_mechanism_info[i].ulMaxKeySize;
	pInfo->flags = kms_mechanism_info[i].flags;

	return (CKR_OK);
}

/*ARGSUSED*/
CK_RV
C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen,
    CK_UTF8CHAR_PTR pLabel)
{
	CK_RV rv = CKR_FUNCTION_FAILED;
	kms_cfg_info_t kmscfg;
	KMSAGENT_PROFILE_FLAGS kmsflags;

	if (!kms_initialized)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (slotID != KMS_TOKEN_SLOTID ||
	    !kms_is_initialized())
		return (CKR_SLOT_ID_INVALID);

	if (KMS_GetConfigInfo(&kmscfg) != CKR_OK ||
	    KMSAgent_GetProfileStatus(kmscfg.name, &kmsflags) !=
	    KMS_AGENT_STATUS_OK)
		return (CKR_FUNCTION_FAILED);

	if (!(kmsflags & KMSAGENT_PROFILE_EXISTS_FLAG) ||
	    !(kmsflags & KMSAGENT_CLIENTKEY_EXISTS_FLAG)) {
		KMSClientProfile kmsProfile;
		/*
		 * Attempt to enroll and load a KMS profile.
		 * This will force the KMSAgent library to fetch
		 * the profile, the CA certificate, and the
		 * client private key and store them locally so that
		 * the KMS agent API can be used later.
		 */
		rv = KMS_LoadProfile(
		    &kmsProfile,
		    &kmscfg,
		    (const char *)pPin,
		    (size_t)ulPinLen);

		if (rv == CKR_OK)
			KMS_UnloadProfile(&kmsProfile);
	}
	return (rv);
}

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

	/*
	 * Could be supported once the agent library supports
	 * storing the client certificate in a PKCS#12 file.
	 */
	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;
	kms_session_t *session_p;
	boolean_t ses_lock_held = B_FALSE;

	if (!kms_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);
	}

	/*
	 * If the token is not yet initialized, we cannot set the pin.
	 */
	if (!kms_is_initialized()) {
		REFRELE(session_p, ses_lock_held);
		return (CKR_FUNCTION_FAILED);
	}

	if (pOldPin == NULL || ulOldLen == 0 ||
	    pNewPin == NULL || ulNewLen == 0) {
		REFRELE(session_p, ses_lock_held);
		return (CKR_ARGUMENTS_BAD);
	}

	if (!kms_is_pin_set()) {
		/*
		 * We don't yet support this mode since
		 * the KMS private key file will automatically
		 * be generated using the KMS Agent passphrase
		 * which is initialized out-of-band.
		 */
		rv = CKR_FUNCTION_NOT_SUPPORTED;

	} else {
		/*
		 * Login to KMS by attempting to load the profile using
		 * the given password.
		 */
		rv = KMS_LoadProfile(&session_p->kmsProfile,
		    &session_p->configInfo,
		    (const char *)pOldPin,
		    (size_t)ulOldLen);
		if (rv == CKR_USER_ANOTHER_ALREADY_LOGGED_IN)
			rv = CKR_OK;

		if (rv == CKR_OK)
			rv = KMS_ChangeLocalPWD(session_p,
			    (const char *)pOldPin,
			    (const char *)pNewPin);
	}

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