1384 lines
38 KiB
C
1384 lines
38 KiB
C
/*
|
|
* pkcs11-object.c: PKCS#11 object management and handling functions
|
|
*
|
|
* Copyright (C) 2002 Timo Teräs <timo.teras@iki.fi>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "sc-pkcs11.h"
|
|
|
|
static void sc_find_release(sc_pkcs11_operation_t *operation);
|
|
|
|
/* Pseudo mechanism for the Find operation */
|
|
static sc_pkcs11_mechanism_type_t find_mechanism = {
|
|
0, /* mech */
|
|
{0,0,0}, /* mech_info */
|
|
0, /* key_type */
|
|
sizeof(struct sc_pkcs11_find_operation), /* obj_size */
|
|
sc_find_release, /* release */
|
|
NULL, /* md_init */
|
|
NULL, /* md_update */
|
|
NULL, /* md_final */
|
|
NULL, /* sign_init */
|
|
NULL, /* sign_update */
|
|
NULL, /* sign_final */
|
|
NULL, /* sign_size */
|
|
NULL, /* verif_init */
|
|
NULL, /* verif_update */
|
|
NULL, /* verif_final */
|
|
NULL, /* decrypt_init */
|
|
NULL, /* decrypt */
|
|
NULL, /* derive */
|
|
NULL /* mech_data */
|
|
};
|
|
|
|
static void
|
|
sc_find_release(sc_pkcs11_operation_t *operation)
|
|
{
|
|
struct sc_pkcs11_find_operation *fop = (struct sc_pkcs11_find_operation *)operation;
|
|
|
|
sc_log(context,"freeing %d handles used %d at %p", fop->allocated_handles, fop->num_handles, fop->handles);
|
|
if (fop->handles) {
|
|
free(fop->handles);
|
|
fop->handles = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
static CK_RV
|
|
get_object_from_session(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
|
|
struct sc_pkcs11_session **session, struct sc_pkcs11_object **object)
|
|
{
|
|
struct sc_pkcs11_session *sess;
|
|
CK_RV rv;
|
|
|
|
rv = get_session(hSession, &sess);
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
*object = list_seek(&sess->slot->objects, &hObject);
|
|
if (!*object)
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
*session = sess;
|
|
return CKR_OK;
|
|
}
|
|
|
|
/* C_CreateObject can be called from C_DeriveKey
|
|
* which is holding the sc_pkcs11_lock
|
|
* So dont get the lock again. */
|
|
static
|
|
CK_RV sc_create_object_int(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
|
|
CK_ULONG ulCount, /* attributes in template */
|
|
CK_OBJECT_HANDLE_PTR phObject, /* receives new object's handle. */
|
|
int use_lock)
|
|
{
|
|
CK_RV rv = CKR_OK;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_card *card;
|
|
|
|
LOG_FUNC_CALLED(context);
|
|
if (pTemplate == NULL_PTR || ulCount == 0)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
if (use_lock) {
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
}
|
|
|
|
dump_template(SC_LOG_DEBUG_NORMAL, "C_CreateObject()", pTemplate, ulCount);
|
|
|
|
session = list_seek(&sessions, &hSession);
|
|
if (!session) {
|
|
rv = CKR_SESSION_HANDLE_INVALID;
|
|
goto out;
|
|
}
|
|
|
|
#if 0
|
|
/* TODO DEE what should we check here */
|
|
if (!(session->flags & CKF_RW_SESSION)) {
|
|
rv = CKR_SESSION_READ_ONLY;
|
|
goto out;
|
|
}
|
|
#endif
|
|
card = session->slot->card;
|
|
if (card->framework->create_object == NULL)
|
|
rv = CKR_FUNCTION_NOT_SUPPORTED;
|
|
else
|
|
rv = card->framework->create_object(session->slot, pTemplate, ulCount, phObject);
|
|
|
|
out:
|
|
if (use_lock)
|
|
sc_pkcs11_unlock();
|
|
LOG_FUNC_RETURN(context, rv);
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_CreateObject(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
|
|
CK_ULONG ulCount, /* attributes in template */
|
|
CK_OBJECT_HANDLE_PTR phObject)
|
|
{
|
|
return sc_create_object_int(hSession, pTemplate, ulCount, phObject, 1);
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_CopyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
|
|
CK_ULONG ulCount, /* attributes in template */
|
|
CK_OBJECT_HANDLE_PTR phNewObject) /* receives handle of copy */
|
|
{
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_DestroyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_OBJECT_HANDLE hObject) /* the object's handle */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
CK_BBOOL is_token = FALSE;
|
|
CK_ATTRIBUTE token_attribure = {CKA_TOKEN, &is_token, sizeof(is_token)};
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
sc_log(context, "C_DestroyObject(hSession=0x%lx, hObject=0x%lx)", hSession, hObject);
|
|
rv = get_object_from_session(hSession, hObject, &session, &object);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
object->ops->get_attribute(session, object, &token_attribure);
|
|
if (is_token == TRUE && !(session->flags & CKF_RW_SESSION)) {
|
|
rv = CKR_SESSION_READ_ONLY;
|
|
goto out;
|
|
}
|
|
|
|
if (object->ops->destroy_object == NULL)
|
|
rv = CKR_FUNCTION_NOT_SUPPORTED;
|
|
else
|
|
rv = object->ops->destroy_object(session, object);
|
|
|
|
out:
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_GetObjectSize(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
|
CK_ULONG_PTR pulSize) /* receives size of object */
|
|
{
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_GetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* specifies attributes, gets values */
|
|
CK_ULONG ulCount) /* attributes in template */
|
|
{
|
|
static int precedence[] = {
|
|
CKR_OK,
|
|
CKR_BUFFER_TOO_SMALL,
|
|
CKR_ATTRIBUTE_TYPE_INVALID,
|
|
CKR_ATTRIBUTE_SENSITIVE,
|
|
-1
|
|
};
|
|
char object_name[64];
|
|
int j;
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
int res, res_type;
|
|
unsigned int i;
|
|
|
|
if (pTemplate == NULL_PTR || ulCount == 0)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_object_from_session(hSession, hObject, &session, &object);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
/* Debug printf */
|
|
snprintf(object_name, sizeof(object_name), "Object %lu", (unsigned long)hObject);
|
|
|
|
res_type = 0;
|
|
for (i = 0; i < ulCount; i++) {
|
|
res = object->ops->get_attribute(session, object, &pTemplate[i]);
|
|
if (res != CKR_OK)
|
|
pTemplate[i].ulValueLen = (CK_ULONG) - 1;
|
|
|
|
dump_template(SC_LOG_DEBUG_NORMAL, object_name, &pTemplate[i], 1);
|
|
|
|
/* the pkcs11 spec has complicated rules on
|
|
* what errors take precedence:
|
|
* CKR_ATTRIBUTE_SENSITIVE
|
|
* CKR_ATTRIBUTE_INVALID
|
|
* CKR_BUFFER_TOO_SMALL
|
|
* It does not exactly specify how other errors
|
|
* should be handled - we give them highest
|
|
* precedence
|
|
*/
|
|
for (j = 0; precedence[j] != -1; j++) {
|
|
if (precedence[j] == res)
|
|
break;
|
|
}
|
|
if (j > res_type) {
|
|
res_type = j;
|
|
rv = res;
|
|
}
|
|
}
|
|
|
|
out: sc_log(context, "C_GetAttributeValue(hSession=0x%lx, hObject=0x%lx) = %s",
|
|
hSession, hObject, lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_SetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* specifies attributes and values */
|
|
CK_ULONG ulCount) /* attributes in template */
|
|
{
|
|
CK_RV rv;
|
|
unsigned int i;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
|
|
if (pTemplate == NULL_PTR || ulCount == 0)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
dump_template(SC_LOG_DEBUG_NORMAL, "C_SetAttributeValue", pTemplate, ulCount);
|
|
|
|
rv = get_object_from_session(hSession, hObject, &session, &object);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
if (!(session->flags & CKF_RW_SESSION)) {
|
|
rv = CKR_SESSION_READ_ONLY;
|
|
goto out;
|
|
}
|
|
|
|
if (object->ops->set_attribute == NULL)
|
|
rv = CKR_FUNCTION_NOT_SUPPORTED;
|
|
else {
|
|
for (i = 0; i < ulCount; i++) {
|
|
rv = object->ops->set_attribute(session, object, &pTemplate[i]);
|
|
if (rv != CKR_OK)
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
|
|
CK_ULONG ulCount) /* attributes in search template */
|
|
{
|
|
CK_RV rv;
|
|
CK_BBOOL is_private = TRUE;
|
|
CK_ATTRIBUTE private_attribute = { CKA_PRIVATE, &is_private, sizeof(is_private) };
|
|
int match, hide_private;
|
|
unsigned int i, j;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
struct sc_pkcs11_find_operation *operation;
|
|
struct sc_pkcs11_slot *slot;
|
|
|
|
if (pTemplate == NULL_PTR && ulCount > 0)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
sc_log(context, "C_FindObjectsInit(slot = %d)\n", session->slot->id);
|
|
dump_template(SC_LOG_DEBUG_NORMAL, "C_FindObjectsInit()", pTemplate, ulCount);
|
|
|
|
rv = session_start_operation(session, SC_PKCS11_OPERATION_FIND,
|
|
&find_mechanism, (struct sc_pkcs11_operation **)&operation);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
operation->current_handle = 0;
|
|
operation->num_handles = 0;
|
|
operation->allocated_handles = 0;
|
|
operation->handles = NULL;
|
|
slot = session->slot;
|
|
|
|
/* Check whether we should hide private objects */
|
|
hide_private = 0;
|
|
if (slot->login_user != CKU_USER && (slot->token_info.flags & CKF_LOGIN_REQUIRED))
|
|
hide_private = 1;
|
|
|
|
/* For each object in token do */
|
|
for (i=0; i<list_size(&slot->objects); i++) {
|
|
object = (struct sc_pkcs11_object *)list_get_at(&slot->objects, i);
|
|
sc_log(context, "Object with handle 0x%lx", object->handle);
|
|
|
|
/* User not logged in and private object? */
|
|
if (hide_private) {
|
|
if (object->ops->get_attribute(session, object, &private_attribute) != CKR_OK)
|
|
continue;
|
|
if (is_private) {
|
|
sc_log(context, "Object %d/%d: Private object and not logged in.",
|
|
slot->id, object->handle);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Try to match every attribute */
|
|
match = 1;
|
|
for (j = 0; j < ulCount; j++) {
|
|
rv = object->ops->cmp_attribute(session, object, &pTemplate[j]);
|
|
if (rv == 0) {
|
|
sc_log(context, "Object %d/%d: Attribute 0x%x does NOT match.",
|
|
slot->id, object->handle, pTemplate[j].type);
|
|
match = 0;
|
|
break;
|
|
}
|
|
|
|
if (context->debug >= 4) {
|
|
sc_log(context, "Object %d/%d: Attribute 0x%x matches.",
|
|
slot->id, object->handle, pTemplate[j].type);
|
|
}
|
|
}
|
|
|
|
if (match) {
|
|
sc_log(context, "Object %d/%d matches\n", slot->id, object->handle);
|
|
/* Realloc handles - remove restriction on only 32 matching objects -dee */
|
|
if (operation->num_handles >= operation->allocated_handles) {
|
|
operation->allocated_handles += SC_PKCS11_FIND_INC_HANDLES;
|
|
sc_log(context, "realloc for %d handles", operation->allocated_handles);
|
|
operation->handles = realloc(operation->handles,
|
|
sizeof(CK_OBJECT_HANDLE) * operation->allocated_handles);
|
|
if (operation->handles == NULL) {
|
|
rv = CKR_HOST_MEMORY;
|
|
break;
|
|
}
|
|
}
|
|
operation->handles[operation->num_handles++] = object->handle;
|
|
}
|
|
}
|
|
rv = CKR_OK;
|
|
|
|
sc_log(context, "%d matching objects\n", operation->num_handles);
|
|
|
|
out:
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_OBJECT_HANDLE_PTR phObject, /* receives object handle array */
|
|
CK_ULONG ulMaxObjectCount, /* max handles to be returned */
|
|
CK_ULONG_PTR pulObjectCount) /* actual number returned */
|
|
{
|
|
CK_RV rv;
|
|
CK_ULONG to_return;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_find_operation *operation;
|
|
|
|
if (phObject == NULL_PTR || ulMaxObjectCount == 0 || pulObjectCount == NULL_PTR)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
rv = session_get_operation(session, SC_PKCS11_OPERATION_FIND, (sc_pkcs11_operation_t **) & operation);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
to_return = (CK_ULONG) operation->num_handles - operation->current_handle;
|
|
if (to_return > ulMaxObjectCount)
|
|
to_return = ulMaxObjectCount;
|
|
|
|
*pulObjectCount = to_return;
|
|
|
|
memcpy(phObject, &operation->handles[operation->current_handle], to_return * sizeof(CK_OBJECT_HANDLE));
|
|
|
|
operation->current_handle += to_return;
|
|
|
|
out: sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_FindObjectsFinal(CK_SESSION_HANDLE hSession) /* the session's handle */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
rv = session_get_operation(session, SC_PKCS11_OPERATION_FIND, NULL);
|
|
if (rv == CKR_OK)
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_FIND);
|
|
|
|
out: sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Below here all functions are wrappers to pass all object attribute and method
|
|
* handling to appropriate object layer.
|
|
*/
|
|
CK_RV
|
|
C_DigestInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism) /* the digesting mechanism */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
if (pMechanism == NULL_PTR)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
sc_log(context, "C_DigestInit(hSession=0x%lx)", hSession);
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_md_init(session, pMechanism);
|
|
|
|
sc_log(context, "C_DigestInit() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_Digest(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pData, /* data to be digested */
|
|
CK_ULONG ulDataLen, /* bytes of data to be digested */
|
|
CK_BYTE_PTR pDigest, /* receives the message digest */
|
|
CK_ULONG_PTR pulDigestLen) /* receives byte length of digest */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
sc_log(context, "C_Digest(hSession=0x%lx)", hSession);
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
rv = sc_pkcs11_md_update(session, pData, ulDataLen);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen);
|
|
|
|
out: sc_log(context, "C_Digest() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_DigestUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pPart, /* data to be digested */
|
|
CK_ULONG ulPartLen) /* bytes of data to be digested */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_md_update(session, pPart, ulPartLen);
|
|
|
|
sc_log(context, "C_DigestUpdate() == %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_DigestKey(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_OBJECT_HANDLE hKey) /* handle of secret key to digest */
|
|
{
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_DigestFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pDigest, /* receives the message digest */
|
|
CK_ULONG_PTR pulDigestLen) /* receives byte count of digest */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen);
|
|
|
|
sc_log(context, "C_DigestFinal() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_SignInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
|
|
CK_OBJECT_HANDLE hKey) /* handle of the signature key */
|
|
{
|
|
CK_BBOOL can_sign;
|
|
CK_KEY_TYPE key_type;
|
|
CK_ATTRIBUTE sign_attribute = { CKA_SIGN, &can_sign, sizeof(can_sign) };
|
|
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
CK_RV rv;
|
|
|
|
if (pMechanism == NULL_PTR)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_object_from_session(hSession, hKey, &session, &object);
|
|
if (rv != CKR_OK) {
|
|
if (rv == CKR_OBJECT_HANDLE_INVALID)
|
|
rv = CKR_KEY_HANDLE_INVALID;
|
|
goto out;
|
|
}
|
|
|
|
if (object->ops->sign == NULL_PTR) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
rv = object->ops->get_attribute(session, object, &sign_attribute);
|
|
if (rv != CKR_OK || !can_sign) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
rv = object->ops->get_attribute(session, object, &key_type_attr);
|
|
if (rv != CKR_OK) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type);
|
|
|
|
out:
|
|
sc_log(context, "C_SignInit() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_Sign(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pData, /* the data (digest) to be signed */
|
|
CK_ULONG ulDataLen, /* count of bytes to be signed */
|
|
CK_BYTE_PTR pSignature, /* receives the signature */
|
|
CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
CK_ULONG length;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
/* According to the pkcs11 specs, we must not do any calls that
|
|
* change our crypto state if the caller is just asking for the
|
|
* signature buffer size, or if the result would be
|
|
* CKR_BUFFER_TOO_SMALL. Thus we cannot do the sign_update call
|
|
* below. */
|
|
if ((rv = sc_pkcs11_sign_size(session, &length)) != CKR_OK)
|
|
goto out;
|
|
|
|
if (pSignature == NULL || length > *pulSignatureLen) {
|
|
*pulSignatureLen = length;
|
|
rv = pSignature ? CKR_BUFFER_TOO_SMALL : CKR_OK;
|
|
goto out;
|
|
}
|
|
|
|
rv = sc_pkcs11_sign_update(session, pData, ulDataLen);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen);
|
|
|
|
out:
|
|
sc_log(context, "C_Sign() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_SignUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pPart, /* the data (digest) to be signed */
|
|
CK_ULONG ulPartLen) /* count of bytes to be signed */
|
|
{
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_sign_update(session, pPart, ulPartLen);
|
|
|
|
sc_log(context, "C_SignUpdate() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pSignature, /* receives the signature */
|
|
CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */
|
|
{
|
|
struct sc_pkcs11_session *session;
|
|
CK_ULONG length;
|
|
CK_RV rv;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
/* According to the pkcs11 specs, we must not do any calls that
|
|
* change our crypto state if the caller is just asking for the
|
|
* signature buffer size, or if the result would be
|
|
* CKR_BUFFER_TOO_SMALL.
|
|
*/
|
|
if ((rv = sc_pkcs11_sign_size(session, &length)) != CKR_OK)
|
|
goto out;
|
|
|
|
if (pSignature == NULL || length > *pulSignatureLen) {
|
|
*pulSignatureLen = length;
|
|
rv = pSignature ? CKR_BUFFER_TOO_SMALL : CKR_OK;
|
|
} else {
|
|
rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen);
|
|
}
|
|
|
|
out:
|
|
sc_log(context, "C_SignFinal() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_SignRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
|
|
CK_OBJECT_HANDLE hKey) /* handle of the signature key */
|
|
{
|
|
CK_RV rv;
|
|
CK_BBOOL can_sign;
|
|
CK_KEY_TYPE key_type;
|
|
CK_ATTRIBUTE sign_attribute = { CKA_SIGN, &can_sign, sizeof(can_sign) };
|
|
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
|
|
/* FIXME #47: C_SignRecover is not implemented */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
|
|
if (pMechanism == NULL_PTR)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_object_from_session(hSession, hKey, &session, &object);
|
|
if (rv != CKR_OK) {
|
|
if (rv == CKR_OBJECT_HANDLE_INVALID)
|
|
rv = CKR_KEY_HANDLE_INVALID;
|
|
goto out;
|
|
}
|
|
|
|
if (object->ops->sign == NULL_PTR) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
rv = object->ops->get_attribute(session, object, &sign_attribute);
|
|
if (rv != CKR_OK || !can_sign) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
rv = object->ops->get_attribute(session, object, &key_type_attr);
|
|
if (rv != CKR_OK) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
/* XXX: need to tell the signature algorithm that we want
|
|
* to recover the signature */
|
|
sc_log(context, "SignRecover operation initialized\n");
|
|
|
|
rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type);
|
|
|
|
out:
|
|
sc_log(context, "C_SignRecoverInit() = %sn", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_SignRecover(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pData, /* the data (digest) to be signed */
|
|
CK_ULONG ulDataLen, /* count of bytes to be signed */
|
|
CK_BYTE_PTR pSignature, /* receives the signature */
|
|
CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */
|
|
{
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
CK_RV
|
|
C_EncryptInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
|
|
CK_OBJECT_HANDLE hKey) /* handle of encryption key */
|
|
{
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pData, /* the plaintext data */
|
|
CK_ULONG ulDataLen, /* bytes of plaintext data */
|
|
CK_BYTE_PTR pEncryptedData, /* receives encrypted data */
|
|
CK_ULONG_PTR pulEncryptedDataLen)
|
|
{ /* receives encrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pPart, /* the plaintext data */
|
|
CK_ULONG ulPartLen, /* bytes of plaintext data */
|
|
CK_BYTE_PTR pEncryptedPart, /* receives encrypted data */
|
|
CK_ULONG_PTR pulEncryptedPartLen)
|
|
{ /* receives encrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pLastEncryptedPart, /* receives encrypted last part */
|
|
CK_ULONG_PTR pulLastEncryptedPartLen)
|
|
{ /* receives byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
|
|
CK_OBJECT_HANDLE hKey)
|
|
{ /* handle of the decryption key */
|
|
CK_BBOOL can_decrypt, can_unwrap;
|
|
CK_KEY_TYPE key_type;
|
|
CK_ATTRIBUTE decrypt_attribute = { CKA_DECRYPT, &can_decrypt, sizeof(can_decrypt) };
|
|
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
|
|
CK_ATTRIBUTE unwrap_attribute = { CKA_UNWRAP, &can_unwrap, sizeof(can_unwrap) };
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
CK_RV rv;
|
|
|
|
if (pMechanism == NULL_PTR)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_object_from_session(hSession, hKey, &session, &object);
|
|
if (rv != CKR_OK) {
|
|
if (rv == CKR_OBJECT_HANDLE_INVALID)
|
|
rv = CKR_KEY_HANDLE_INVALID;
|
|
goto out;
|
|
}
|
|
|
|
if (object->ops->decrypt == NULL_PTR) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
rv = object->ops->get_attribute(session, object, &decrypt_attribute);
|
|
if (rv != CKR_OK || !can_decrypt) {
|
|
/* Also accept UNWRAP - apps call Decrypt when they mean Unwrap */
|
|
rv = object->ops->get_attribute(session, object, &unwrap_attribute);
|
|
if (rv != CKR_OK || !can_unwrap) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
}
|
|
rv = object->ops->get_attribute(session, object, &key_type_attr);
|
|
if (rv != CKR_OK) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
rv = sc_pkcs11_decr_init(session, pMechanism, object, key_type);
|
|
|
|
out: sc_log(context, "C_DecryptInit() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pEncryptedData, /* input encrypted data */
|
|
CK_ULONG ulEncryptedDataLen, /* count of bytes of input */
|
|
CK_BYTE_PTR pData, /* receives decrypted output */
|
|
CK_ULONG_PTR pulDataLen)
|
|
{ /* receives decrypted byte count */
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_decr(session, pEncryptedData, ulEncryptedDataLen,
|
|
pData, pulDataLen);
|
|
|
|
sc_log(context, "C_Decrypt() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pEncryptedPart, /* input encrypted data */
|
|
CK_ULONG ulEncryptedPartLen, /* count of bytes of input */
|
|
CK_BYTE_PTR pPart, /* receives decrypted output */
|
|
CK_ULONG_PTR pulPartLen)
|
|
{ /* receives decrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pLastPart, /* receives decrypted output */
|
|
CK_ULONG_PTR pulLastPartLen)
|
|
{ /* receives decrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pPart, /* the plaintext data */
|
|
CK_ULONG ulPartLen, /* bytes of plaintext data */
|
|
CK_BYTE_PTR pEncryptedPart, /* receives encrypted data */
|
|
CK_ULONG_PTR pulEncryptedPartLen)
|
|
{ /* receives encrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pEncryptedPart, /* input encrypted data */
|
|
CK_ULONG ulEncryptedPartLen, /* count of bytes of input */
|
|
CK_BYTE_PTR pPart, /* receives decrypted output */
|
|
CK_ULONG_PTR pulPartLen)
|
|
{ /* receives decrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pPart, /* the plaintext data */
|
|
CK_ULONG ulPartLen, /* bytes of plaintext data */
|
|
CK_BYTE_PTR pEncryptedPart, /* receives encrypted data */
|
|
CK_ULONG_PTR pulEncryptedPartLen)
|
|
{ /* receives encrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pEncryptedPart, /* input encrypted data */
|
|
CK_ULONG ulEncryptedPartLen, /* count of byes of input */
|
|
CK_BYTE_PTR pPart, /* receives decrypted output */
|
|
CK_ULONG_PTR pulPartLen)
|
|
{ /* receives decrypted byte count */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the key generation mechanism */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* template for the new key */
|
|
CK_ULONG ulCount, /* number of attributes in template */
|
|
CK_OBJECT_HANDLE_PTR phKey)
|
|
{ /* receives handle of new key */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the key gen. mech. */
|
|
CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* pub. attr. template */
|
|
CK_ULONG ulPublicKeyAttributeCount, /* # of pub. attrs. */
|
|
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* priv. attr. template */
|
|
CK_ULONG ulPrivateKeyAttributeCount, /* # of priv. attrs. */
|
|
CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. key handle */
|
|
CK_OBJECT_HANDLE_PTR phPrivateKey)
|
|
{ /* gets priv. key handle */
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_slot *slot;
|
|
|
|
if (pMechanism == NULL_PTR
|
|
|| (pPublicKeyTemplate == NULL_PTR && ulPublicKeyAttributeCount > 0)
|
|
|| (pPrivateKeyTemplate == NULL_PTR && ulPrivateKeyAttributeCount > 0))
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
dump_template(SC_LOG_DEBUG_NORMAL, "C_GenerateKeyPair(), PrivKey attrs", pPrivateKeyTemplate, ulPrivateKeyAttributeCount);
|
|
dump_template(SC_LOG_DEBUG_NORMAL, "C_GenerateKeyPair(), PubKey attrs", pPublicKeyTemplate, ulPublicKeyAttributeCount);
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
if (!(session->flags & CKF_RW_SESSION)) {
|
|
rv = CKR_SESSION_READ_ONLY;
|
|
goto out;
|
|
}
|
|
|
|
slot = session->slot;
|
|
if (slot->card->framework->gen_keypair == NULL)
|
|
rv = CKR_FUNCTION_NOT_SUPPORTED;
|
|
else
|
|
rv = slot->card->framework->gen_keypair(slot, pMechanism,
|
|
pPublicKeyTemplate, ulPublicKeyAttributeCount,
|
|
pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
|
|
phPublicKey, phPrivateKey);
|
|
|
|
out:
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
|
|
CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
|
|
CK_OBJECT_HANDLE hWrappingKey, /* handle of the wrapping key */
|
|
CK_OBJECT_HANDLE hKey, /* handle of the key to be wrapped */
|
|
CK_BYTE_PTR pWrappedKey, /* receives the wrapped key */
|
|
CK_ULONG_PTR pulWrappedKeyLen)
|
|
{ /* receives byte size of wrapped key */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the unwrapping mechanism */
|
|
CK_OBJECT_HANDLE hUnwrappingKey, /* handle of the unwrapping key */
|
|
CK_BYTE_PTR pWrappedKey, /* the wrapped key */
|
|
CK_ULONG ulWrappedKeyLen, /* bytes length of wrapped key */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* template for the new key */
|
|
CK_ULONG ulAttributeCount, /* # of attributes in template */
|
|
CK_OBJECT_HANDLE_PTR phKey)
|
|
{ /* gets handle of recovered key */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the key derivation mechanism */
|
|
CK_OBJECT_HANDLE hBaseKey, /* handle of the base key */
|
|
CK_ATTRIBUTE_PTR pTemplate, /* template for the new key */
|
|
CK_ULONG ulAttributeCount, /* # of attributes in template */
|
|
CK_OBJECT_HANDLE_PTR phKey) /* gets handle of derived key */
|
|
{
|
|
/* TODO: -DEE ECDH with Cofactor on PIV is an example */
|
|
/* TODO: need to do a lot of checking, will only support ECDH for now.*/
|
|
CK_RV rv;
|
|
CK_BBOOL can_derive;
|
|
CK_KEY_TYPE key_type;
|
|
CK_ATTRIBUTE derive_attribute = { CKA_DERIVE, &can_derive, sizeof(can_derive) };
|
|
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
struct sc_pkcs11_object *key_object;
|
|
|
|
if (pMechanism == NULL_PTR)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_object_from_session(hSession, hBaseKey, &session, &object);
|
|
if (rv != CKR_OK) {
|
|
if (rv == CKR_OBJECT_HANDLE_INVALID)
|
|
rv = CKR_KEY_HANDLE_INVALID;
|
|
goto out;
|
|
}
|
|
|
|
if (object->ops->derive == NULL_PTR) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
rv = object->ops->get_attribute(session, object, &derive_attribute);
|
|
if (rv != CKR_OK || !can_derive) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
rv = object->ops->get_attribute(session, object, &key_type_attr);
|
|
if (rv != CKR_OK) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
/* TODO DEE Should also check SENSITIVE, ALWAYS_SENSITIVE, EXTRACTABLE,
|
|
NEVER_EXTRACTABLE of the BaseKey against the template for the newkey.
|
|
*/
|
|
|
|
switch(key_type) {
|
|
case CKK_EC:
|
|
|
|
rv = sc_create_object_int(hSession, pTemplate, ulAttributeCount, phKey, 0);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
rv = get_object_from_session(hSession, *phKey, &session, &key_object);
|
|
if (rv != CKR_OK) {
|
|
if (rv == CKR_OBJECT_HANDLE_INVALID)
|
|
rv = CKR_KEY_HANDLE_INVALID;
|
|
goto out;
|
|
}
|
|
|
|
rv = sc_pkcs11_deri(session, pMechanism, object, key_type,
|
|
hSession, *phKey, key_object);
|
|
/* TODO if (rv != CK_OK) need to destroy the object */
|
|
|
|
break;
|
|
default:
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
}
|
|
|
|
out:
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pSeed, /* the seed material */
|
|
CK_ULONG ulSeedLen)
|
|
{ /* count of bytes of seed material */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR RandomData, /* receives the random data */
|
|
CK_ULONG ulRandomLen)
|
|
{ /* number of bytes to be generated */
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_slot *slot;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK) {
|
|
slot = session->slot;
|
|
if (slot->card->framework->get_random == NULL)
|
|
rv = CKR_RANDOM_NO_RNG;
|
|
else
|
|
rv = slot->card->framework->get_random(slot, RandomData, ulRandomLen);
|
|
}
|
|
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
}
|
|
|
|
CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
|
|
{ /* the session's handle */
|
|
return CKR_FUNCTION_NOT_PARALLEL;
|
|
}
|
|
|
|
CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession)
|
|
{ /* the session's handle */
|
|
return CKR_FUNCTION_NOT_PARALLEL;
|
|
}
|
|
|
|
CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
|
|
CK_OBJECT_HANDLE hKey)
|
|
{ /* handle of the verification key */
|
|
#ifndef ENABLE_OPENSSL
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
#else
|
|
#if 0
|
|
CK_BBOOL can_verify;
|
|
CK_ATTRIBUTE verify_attribute = { CKA_VERIFY, &can_verify, sizeof(can_verify) };
|
|
#endif
|
|
CK_KEY_TYPE key_type;
|
|
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
struct sc_pkcs11_object *object;
|
|
|
|
if (pMechanism == NULL_PTR)
|
|
return CKR_ARGUMENTS_BAD;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
|
|
rv = get_object_from_session(hSession, hKey, &session, &object);
|
|
if (rv != CKR_OK) {
|
|
if (rv == CKR_OBJECT_HANDLE_INVALID)
|
|
rv = CKR_KEY_HANDLE_INVALID;
|
|
goto out;
|
|
}
|
|
#if 0
|
|
rv = object->ops->get_attribute(session, object, &verify_attribute);
|
|
if (rv != CKR_OK || !can_verify) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
#endif
|
|
rv = object->ops->get_attribute(session, object, &key_type_attr);
|
|
if (rv != CKR_OK) {
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
goto out;
|
|
}
|
|
|
|
rv = sc_pkcs11_verif_init(session, pMechanism, object, key_type);
|
|
|
|
out: sc_log(context, "C_VerifyInit() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
#endif
|
|
}
|
|
|
|
CK_RV C_Verify(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pData, /* plaintext data (digest) to compare */
|
|
CK_ULONG ulDataLen, /* length of data (digest) in bytes */
|
|
CK_BYTE_PTR pSignature, /* the signature to be verified */
|
|
CK_ULONG ulSignatureLen)
|
|
{ /* count of bytes of signature */
|
|
#ifndef ENABLE_OPENSSL
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
#else
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv != CKR_OK)
|
|
goto out;
|
|
|
|
rv = sc_pkcs11_verif_update(session, pData, ulDataLen);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen);
|
|
|
|
out: sc_log(context, "C_Verify() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
#endif
|
|
}
|
|
|
|
CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pPart, /* plaintext data (digest) to compare */
|
|
CK_ULONG ulPartLen)
|
|
{ /* length of data (digest) in bytes */
|
|
#ifndef ENABLE_OPENSSL
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
#else
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_verif_update(session, pPart, ulPartLen);
|
|
|
|
sc_log(context, "C_VerifyUpdate() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
#endif
|
|
}
|
|
|
|
CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pSignature, /* the signature to be verified */
|
|
CK_ULONG ulSignatureLen)
|
|
{ /* count of bytes of signature */
|
|
#ifndef ENABLE_OPENSSL
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
#else
|
|
CK_RV rv;
|
|
struct sc_pkcs11_session *session;
|
|
|
|
rv = sc_pkcs11_lock();
|
|
if (rv != CKR_OK)
|
|
return rv;
|
|
|
|
rv = get_session(hSession, &session);
|
|
if (rv == CKR_OK)
|
|
rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen);
|
|
|
|
sc_log(context, "C_VerifyFinal() = %s", lookup_enum ( RV_T, rv ));
|
|
sc_pkcs11_unlock();
|
|
return rv;
|
|
#endif
|
|
}
|
|
|
|
CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
|
|
CK_OBJECT_HANDLE hKey)
|
|
{ /* handle of the verification key */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|
CK_BYTE_PTR pSignature, /* the signature to be verified */
|
|
CK_ULONG ulSignatureLen, /* count of bytes of signature */
|
|
CK_BYTE_PTR pData, /* receives decrypted data (digest) */
|
|
CK_ULONG_PTR pulDataLen)
|
|
{ /* receives byte count of data */
|
|
return CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
/*
|
|
* Helper function to compare attributes on any sort of object
|
|
*/
|
|
int sc_pkcs11_any_cmp_attribute(struct sc_pkcs11_session *session, void *ptr, CK_ATTRIBUTE_PTR attr)
|
|
{
|
|
int rv;
|
|
struct sc_pkcs11_object *object;
|
|
u8 temp1[1024];
|
|
u8 *temp2 = NULL; /* dynamic allocation for large attributes */
|
|
CK_ATTRIBUTE temp_attr;
|
|
int res;
|
|
|
|
object = (struct sc_pkcs11_object *)ptr;
|
|
temp_attr.type = attr->type;
|
|
temp_attr.pValue = NULL;
|
|
temp_attr.ulValueLen = 0;
|
|
|
|
/* Get the length of the attribute */
|
|
rv = object->ops->get_attribute(session, object, &temp_attr);
|
|
if (rv != CKR_OK || temp_attr.ulValueLen != attr->ulValueLen)
|
|
return 0;
|
|
|
|
if (temp_attr.ulValueLen <= sizeof(temp1))
|
|
temp_attr.pValue = temp1;
|
|
else {
|
|
temp2 = calloc(1, temp_attr.ulValueLen);
|
|
if (temp2 == NULL)
|
|
return 0;
|
|
temp_attr.pValue = temp2;
|
|
}
|
|
|
|
/* Get the attribute */
|
|
rv = object->ops->get_attribute(session, object, &temp_attr);
|
|
if (rv != CKR_OK) {
|
|
res = 0;
|
|
goto done;
|
|
}
|
|
#ifdef DEBUG
|
|
{
|
|
char foo[64];
|
|
|
|
snprintf(foo, sizeof(foo), "Object %p (slot 0x%lx)", object, session->slot->id);
|
|
dump_template(SC_LOG_DEBUG_NORMAL, foo, &temp_attr, 1);
|
|
}
|
|
#endif
|
|
res = temp_attr.ulValueLen == attr->ulValueLen
|
|
&& !memcmp(temp_attr.pValue, attr->pValue, attr->ulValueLen);
|
|
|
|
done:
|
|
if (temp2 != NULL)
|
|
free(temp2);
|
|
|
|
return res;
|
|
}
|