blob: 9af5ecfbfe5d8e4781ec018c7800392a4771c788 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2017-2018, Linaro Limited
*/
#include <pkcs11.h>
#include <pkcs11_ta.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tee_client_api.h>
#include "pkcs11_processing.h"
#include "invoke_ta.h"
#include "serializer.h"
#include "serialize_ck.h"
CK_RV ck_create_object(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR attribs,
CK_ULONG count, CK_OBJECT_HANDLE_PTR handle)
{
CK_RV rv = CKR_GENERAL_ERROR;
struct serializer obj = { 0 };
size_t ctrl_size = 0;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
uint32_t session_handle = session;
uint32_t key_handle = 0;
char *buf = NULL;
size_t out_size = 0;
if (!handle || !attribs || !count)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_attributes(&obj, attribs, count);
if (rv)
goto out;
/* Shm io0: (i/o) [session-handle][serialized-attributes] / [status] */
ctrl_size = sizeof(session_handle) + obj.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto out;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, obj.buffer, obj.size);
/* Shm io2: (out) [object handle] */
out_shm = ckteec_alloc_shm(sizeof(key_handle), CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto out;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_CREATE_OBJECT,
ctrl, out_shm, &out_size);
if (rv != CKR_OK || out_size != out_shm->size) {
if (rv == CKR_OK)
rv = CKR_DEVICE_ERROR;
goto out;
}
memcpy(&key_handle, out_shm->buffer, sizeof(key_handle));
*handle = key_handle;
out:
release_serial_object(&obj);
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_destroy_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
size_t ctrl_size = 0;
char *buf = NULL;
uint32_t session_handle = session;
uint32_t obj_id = obj;
/* Shm io0: (i/o) ctrl = [session-handle][object-handle] / [status] */
ctrl_size = sizeof(session_handle) + sizeof(obj_id);
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl)
return CKR_HOST_MEMORY;
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &obj_id, sizeof(obj_id));
rv = ckteec_invoke_ctrl(PKCS11_CMD_DESTROY_OBJECT, ctrl);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_encdecrypt_init(CK_SESSION_HANDLE session,
CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE key,
int decrypt)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
struct serializer obj = { 0 };
uint32_t session_handle = session;
uint32_t key_handle = key;
size_t ctrl_size = 0;
char *buf = NULL;
if (!mechanism)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_mecha_params(&obj, mechanism);
if (rv)
return rv;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][key-handle][serialized-mechanism-blob]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + sizeof(key_handle) + obj.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &key_handle, sizeof(key_handle));
buf += sizeof(key_handle);
memcpy(buf, obj.buffer, obj.size);
rv = ckteec_invoke_ctrl(decrypt ? PKCS11_CMD_DECRYPT_INIT :
PKCS11_CMD_ENCRYPT_INIT, ctrl);
bail:
ckteec_free_shm(ctrl);
release_serial_object(&obj);
return rv;
}
CK_RV ck_encdecrypt_update(CK_SESSION_HANDLE session,
CK_BYTE_PTR in,
CK_ULONG in_len,
CK_BYTE_PTR out,
CK_ULONG_PTR out_len,
int decrypt)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *in_shm = NULL;
TEEC_SharedMemory *out_shm = NULL;
uint32_t session_handle = session;
size_t out_size = 0;
if (!out_len || (in_len && !in)) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
/* Shm io1: input data buffer if any */
if (in_len) {
in_shm = ckteec_register_shm(in, in_len, CKTEEC_SHM_IN);
if (!in_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
}
/* Shm io2: output data buffer */
if (out && out_len && *out_len) {
out_shm = ckteec_register_shm(out, *out_len, CKTEEC_SHM_OUT);
} else {
/* Query output data size */
out_shm = ckteec_alloc_shm(0, CKTEEC_SHM_OUT);
}
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
/* Invoke */
rv = ckteec_invoke_ta(decrypt ? PKCS11_CMD_DECRYPT_UPDATE :
PKCS11_CMD_ENCRYPT_UPDATE, ctrl,
in_shm, out_shm, &out_size, NULL, NULL);
if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
*out_len = out_size;
if (rv == CKR_BUFFER_TOO_SMALL && out_size && !out)
rv = CKR_OK;
goto bail_invoked;
bail:
ck_release_active_processing(session, decrypt ?
PKCS11_CMD_DECRYPT_UPDATE :
PKCS11_CMD_ENCRYPT_UPDATE);
bail_invoked:
ckteec_free_shm(out_shm);
ckteec_free_shm(in_shm);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_encdecrypt_oneshot(CK_SESSION_HANDLE session,
CK_BYTE_PTR in,
CK_ULONG in_len,
CK_BYTE_PTR out,
CK_ULONG_PTR out_len,
int decrypt)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *in_shm = NULL;
TEEC_SharedMemory *out_shm = NULL;
uint32_t session_handle = session;
size_t out_size = 0;
if (!out_len || (in_len && !in)) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
/* Shm io1: input data buffer */
if (in) {
in_shm = ckteec_register_shm(in, in_len, CKTEEC_SHM_IN);
if (!in_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
}
/* Shm io2: output data buffer */
if (out && out_len && *out_len) {
out_shm = ckteec_register_shm(out, *out_len, CKTEEC_SHM_OUT);
} else {
/* Query output data size */
out_shm = ckteec_alloc_shm(0, CKTEEC_SHM_OUT);
}
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ta(decrypt ? PKCS11_CMD_DECRYPT_ONESHOT :
PKCS11_CMD_ENCRYPT_ONESHOT, ctrl,
in_shm, out_shm, &out_size, NULL, NULL);
if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
*out_len = out_size;
if (rv == CKR_BUFFER_TOO_SMALL && out_size && !out)
rv = CKR_OK;
goto bail_invoked;
bail:
ck_release_active_processing(session, decrypt ?
PKCS11_CMD_DECRYPT_ONESHOT :
PKCS11_CMD_ENCRYPT_ONESHOT);
bail_invoked:
ckteec_free_shm(out_shm);
ckteec_free_shm(in_shm);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_encdecrypt_final(CK_SESSION_HANDLE session,
CK_BYTE_PTR out,
CK_ULONG_PTR out_len,
int decrypt)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
uint32_t session_handle = session;
size_t out_size = 0;
if (!out_len) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
/* Shm io2: output buffer reference */
if (out && out_len && *out_len) {
out_shm = ckteec_register_shm(out, *out_len, CKTEEC_SHM_OUT);
} else {
/* Query output data size */
out_shm = ckteec_alloc_shm(0, CKTEEC_SHM_OUT);
}
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(decrypt ? PKCS11_CMD_DECRYPT_FINAL :
PKCS11_CMD_ENCRYPT_FINAL,
ctrl, out_shm, &out_size);
if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
*out_len = out_size;
if (rv == CKR_BUFFER_TOO_SMALL && out_size && !out)
rv = CKR_OK;
goto bail_invoked;
bail:
ck_release_active_processing(session, decrypt ?
PKCS11_CMD_DECRYPT_FINAL :
PKCS11_CMD_ENCRYPT_FINAL);
bail_invoked:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_digest_init(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
struct serializer obj = { 0 };
uint32_t session_handle = session;
size_t ctrl_size = 0;
uint8_t *buf = NULL;
if (!mechanism)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_mecha_params(&obj, mechanism);
if (rv)
return rv;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][serialized-mechanism-blob]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + obj.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, obj.buffer, obj.size);
rv = ckteec_invoke_ctrl(PKCS11_CMD_DIGEST_INIT, ctrl);
bail:
ckteec_free_shm(ctrl);
release_serial_object(&obj);
return rv;
}
CK_RV ck_digest_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
uint32_t session_handle = session;
uint32_t key_handle = key;
size_t ctrl_size = 0;
uint8_t *buf = NULL;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][key-handle]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + sizeof(key_handle);
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl)
return CKR_HOST_MEMORY;
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &key_handle, sizeof(key_handle));
rv = ckteec_invoke_ctrl(PKCS11_CMD_DIGEST_KEY, ctrl);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_digest_update(CK_SESSION_HANDLE session, CK_BYTE_PTR in,
CK_ULONG in_len)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *io1 = NULL;
uint32_t session_handle = session;
uint8_t *buf = NULL;
if (!in && in_len) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/*
* Shm io0: (in/out) ctrl = [session-handle] / [status]
*/
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
/* Shm io1: input payload */
if (in_len && in) {
io1 = ckteec_register_shm(in, in_len, CKTEEC_SHM_IN);
if (!io1) {
rv = CKR_HOST_MEMORY;
goto bail;
}
}
rv = ckteec_invoke_ctrl_in(PKCS11_CMD_DIGEST_UPDATE, ctrl, io1);
goto bail_invoked;
bail:
ck_release_active_processing(session, PKCS11_CMD_DIGEST_UPDATE);
bail_invoked:
ckteec_free_shm(io1);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_digest_oneshot(CK_SESSION_HANDLE session, CK_BYTE_PTR in,
CK_ULONG in_len, CK_BYTE_PTR digest_ref,
CK_ULONG_PTR digest_len)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *io1 = NULL;
TEEC_SharedMemory *io2 = NULL;
uint32_t session_handle = session;
size_t out_size = 0;
uint8_t *buf = NULL;
if ((!in && in_len) || !digest_len) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/*
* Shm io0: (in/out) ctrl = [session-handle] / [status]
*/
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
/* Shm io1: input payload */
if (in_len && in) {
io1 = ckteec_register_shm(in, in_len, CKTEEC_SHM_IN);
if (!io1) {
rv = CKR_HOST_MEMORY;
goto bail;
}
}
/* Shm io2: output digest or null sized shm */
if (digest_ref) {
io2 = ckteec_register_shm(digest_ref, *digest_len,
CKTEEC_SHM_OUT);
} else {
/* Query size if output signature */
io2 = ckteec_alloc_shm(0, CKTEEC_SHM_OUT);
}
if (!io2) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ta(PKCS11_CMD_DIGEST_ONESHOT, ctrl,
io1, io2, &out_size, NULL, NULL);
if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
*digest_len = out_size;
if (rv == CKR_BUFFER_TOO_SMALL && out_size && !digest_ref)
rv = CKR_OK;
goto bail_invoked;
bail:
ck_release_active_processing(session, PKCS11_CMD_DIGEST_ONESHOT);
bail_invoked:
ckteec_free_shm(io1);
ckteec_free_shm(io2);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_digest_final(CK_SESSION_HANDLE session, CK_BYTE_PTR digest_ref,
CK_ULONG_PTR digest_len)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *io2 = NULL;
uint32_t session_handle = session;
size_t io2_size = 0;
uint8_t *buf = NULL;
/*
* - If digest_ref == NULL AND digest_len == NULL -> need to call TA to
* terminate session.
* - If digest_len == NULL -> need to call to TA to terminate session.
* - If digest_ref == NULL BUT digest_len != NULL just operate normally
* to get size of the required buffer
*/
if (!digest_len) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/*
* Shm io0: (in/out) ctrl = [session-handle] / [status]
*/
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
/* Shm io2: output digest or null sized shm */
if (digest_ref)
io2 = ckteec_register_shm(digest_ref, *digest_len,
CKTEEC_SHM_OUT);
else
io2 = ckteec_alloc_shm(0, CKTEEC_SHM_OUT);
if (!io2) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ta(PKCS11_CMD_DIGEST_FINAL, ctrl, NULL, io2,
&io2_size, NULL, NULL);
if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
*digest_len = io2_size;
if (rv == CKR_BUFFER_TOO_SMALL && io2_size && !digest_ref)
rv = CKR_OK;
goto bail_invoked;
bail:
ck_release_active_processing(session, PKCS11_CMD_DIGEST_FINAL);
bail_invoked:
ckteec_free_shm(io2);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_signverify_init(CK_SESSION_HANDLE session,
CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE key,
int sign)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
struct serializer obj = { 0 };
uint32_t session_handle = session;
uint32_t key_handle = key;
size_t ctrl_size = 0;
char *buf = NULL;
if (!mechanism)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_mecha_params(&obj, mechanism);
if (rv)
return rv;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][key-handle][serialized-mechanism-blob]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + sizeof(key_handle) + obj.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &key_handle, sizeof(key_handle));
buf += sizeof(key_handle);
memcpy(buf, obj.buffer, obj.size);
rv = ckteec_invoke_ctrl(sign ? PKCS11_CMD_SIGN_INIT :
PKCS11_CMD_VERIFY_INIT, ctrl);
bail:
ckteec_free_shm(ctrl);
release_serial_object(&obj);
return rv;
}
CK_RV ck_signverify_update(CK_SESSION_HANDLE session,
CK_BYTE_PTR in,
CK_ULONG in_len,
int sign)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *in_shm = NULL;
uint32_t session_handle = session;
if (!in && in_len) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
/* Shm io1: input data */
in_shm = ckteec_register_shm(in, in_len, CKTEEC_SHM_IN);
if (!in_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_in(sign ? PKCS11_CMD_SIGN_UPDATE :
PKCS11_CMD_VERIFY_UPDATE, ctrl, in_shm);
goto bail_invoked;
bail:
ck_release_active_processing(session, sign ? PKCS11_CMD_SIGN_UPDATE :
PKCS11_CMD_VERIFY_UPDATE);
bail_invoked:
ckteec_free_shm(in_shm);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_signverify_oneshot(CK_SESSION_HANDLE session,
CK_BYTE_PTR in,
CK_ULONG in_len,
CK_BYTE_PTR sign_ref,
CK_ULONG_PTR sign_len,
int sign)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *io1 = NULL;
TEEC_SharedMemory *io2 = NULL;
uint32_t session_handle = session;
size_t out_size = 0;
if ((in_len && !in) || (!sign && sign_len && *sign_len && !sign_ref) ||
(sign && !sign_len)) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
/* Shm io1: input payload */
if (in_len) {
io1 = ckteec_register_shm(in, in_len, CKTEEC_SHM_IN);
if (!io1) {
rv = CKR_HOST_MEMORY;
goto bail;
}
}
/*
* Shm io2: input signature (if verifying) or null sized shm
* or
* Shm io2: output signature (if signing) or null sized shm
*/
if (sign_ref && sign_len && *sign_len) {
io2 = ckteec_register_shm(sign_ref, *sign_len,
sign ? CKTEEC_SHM_OUT : CKTEEC_SHM_IN);
} else {
/* Query size if output signature */
io2 = ckteec_alloc_shm(0, sign ? CKTEEC_SHM_OUT : CKTEEC_SHM_IN);
}
if (!io2) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ta(sign ? PKCS11_CMD_SIGN_ONESHOT :
PKCS11_CMD_VERIFY_ONESHOT, ctrl,
io1, io2, &out_size, NULL, NULL);
if (sign && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
*sign_len = out_size;
if (rv == CKR_BUFFER_TOO_SMALL && out_size && !sign_ref)
rv = CKR_OK;
goto bail_invoked;
bail:
ck_release_active_processing(session, sign ? PKCS11_CMD_SIGN_ONESHOT :
PKCS11_CMD_VERIFY_ONESHOT);
bail_invoked:
ckteec_free_shm(io1);
ckteec_free_shm(io2);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_signverify_final(CK_SESSION_HANDLE session,
CK_BYTE_PTR sign_ref,
CK_ULONG_PTR sign_len,
int sign)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *io = NULL;
uint32_t session_handle = session;
size_t io_size = 0;
if ((!sign && sign_len && *sign_len && !sign_ref) ||
(sign && !sign_len)) {
rv = CKR_ARGUMENTS_BAD;
goto bail;
}
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
/*
* Shm io1: input signature (if verifying) or null sized shm
* or
* Shm io1: output signature (if signing) or null sized shm
*/
if (sign_ref && sign_len && *sign_len)
io = ckteec_register_shm(sign_ref, *sign_len,
sign ? CKTEEC_SHM_OUT : CKTEEC_SHM_IN);
else
io = ckteec_alloc_shm(0, sign ? CKTEEC_SHM_OUT : CKTEEC_SHM_IN);
if (!io) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ta(sign ? PKCS11_CMD_SIGN_FINAL :
PKCS11_CMD_VERIFY_FINAL, ctrl, NULL, io,
&io_size, NULL, NULL);
if (sign && sign_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
*sign_len = io_size;
if (rv == CKR_BUFFER_TOO_SMALL && io_size && !sign_ref)
rv = CKR_OK;
goto bail_invoked;
bail:
ck_release_active_processing(session, sign ? PKCS11_CMD_SIGN_FINAL :
PKCS11_CMD_VERIFY_FINAL);
bail_invoked:
ckteec_free_shm(io);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_generate_key(CK_SESSION_HANDLE session,
CK_MECHANISM_PTR mechanism,
CK_ATTRIBUTE_PTR attribs,
CK_ULONG count,
CK_OBJECT_HANDLE_PTR handle)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
struct serializer smecha = { 0 };
struct serializer sattr = { 0 };
uint32_t session_handle = session;
size_t ctrl_size = 0;
uint32_t key_handle = 0;
char *buf = NULL;
size_t out_size = 0;
if (!handle || !mechanism || (count && !attribs))
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_mecha_params(&smecha, mechanism);
if (rv)
return rv;
rv = serialize_ck_attributes(&sattr, attribs, count);
if (rv)
goto bail;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][serialized-mecha][serialized-attributes]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + smecha.size + sattr.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, smecha.buffer, smecha.size);
buf += smecha.size;
memcpy(buf, sattr.buffer, sattr.size);
/* Shm io2: (out) [object handle] */
out_shm = ckteec_alloc_shm(sizeof(key_handle), CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_GENERATE_KEY,
ctrl, out_shm, &out_size);
if (rv != CKR_OK || out_size != out_shm->size) {
if (rv == CKR_OK)
rv = CKR_DEVICE_ERROR;
goto bail;
}
memcpy(&key_handle, out_shm->buffer, sizeof(key_handle));
*handle = key_handle;
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
release_serial_object(&sattr);
release_serial_object(&smecha);
return rv;
}
CK_RV ck_find_objects_init(CK_SESSION_HANDLE session,
CK_ATTRIBUTE_PTR attribs,
CK_ULONG count)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
uint32_t session_handle = session;
struct serializer obj = { 0 };
size_t ctrl_size = 0;
char *buf = NULL;
if (count && !attribs)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_attributes(&obj, attribs, count);
if (rv)
return rv;
/* Shm io0: (in/out) ctrl
* (in) [session-handle][headed-serialized-attributes]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + obj.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, obj.buffer, obj.size);
rv = ckteec_invoke_ctrl(PKCS11_CMD_FIND_OBJECTS_INIT, ctrl);
bail:
ckteec_free_shm(ctrl);
release_serial_object(&obj);
return rv;
}
CK_RV ck_find_objects(CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE_PTR obj,
CK_ULONG max_count,
CK_ULONG_PTR count)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
uint32_t session_handle = session;
uint32_t *handles = NULL;
size_t handles_size = max_count * sizeof(uint32_t);
CK_ULONG n = 0;
CK_ULONG last = 0;
size_t out_size = 0;
if (!count || (max_count && !obj))
return CKR_ARGUMENTS_BAD;
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
/* Shm io2: (out) [object handle list] */
out_shm = ckteec_alloc_shm(handles_size, CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_FIND_OBJECTS,
ctrl, out_shm, &out_size);
if (rv || out_size > out_shm->size) {
if (rv == CKR_OK)
rv = CKR_DEVICE_ERROR;
goto bail;
}
handles = out_shm->buffer;
last = out_size / sizeof(uint32_t);
*count = last;
for (n = 0; n < last; n++)
obj[n] = handles[n];
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_find_objects_final(CK_SESSION_HANDLE session)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
uint32_t session_handle = session;
/* Shm io0: (in/out) ctrl = [session-handle] / [status] */
ctrl = ckteec_alloc_shm(sizeof(session_handle), CKTEEC_SHM_INOUT);
if (!ctrl)
return CKR_HOST_MEMORY;
memcpy(ctrl->buffer, &session_handle, sizeof(session_handle));
rv = ckteec_invoke_ctrl(PKCS11_CMD_FIND_OBJECTS_FINAL, ctrl);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_get_object_size(CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE obj,
CK_ULONG_PTR p_size)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
size_t ctrl_size = 0;
uint32_t session_handle = session;
uint32_t obj_handle = obj;
char *buf = NULL;
size_t out_size = 0;
uint32_t u32_sz = 0;
if (!p_size)
return CKR_ARGUMENTS_BAD;
/* Shm io0: (in/out) [session][obj-handle] / [status] */
ctrl_size = sizeof(session_handle) + sizeof(obj_handle);
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &obj_handle, sizeof(obj_handle));
/* Shm io2: (out) [object size] */
out_shm = ckteec_alloc_shm(sizeof(uint32_t), CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_GET_OBJECT_SIZE,
ctrl, out_shm, &out_size);
if (rv)
goto bail;
if (out_shm->size != sizeof(uint32_t)) {
rv = CKR_DEVICE_ERROR;
goto bail;
}
memcpy(&u32_sz, out_shm->buffer, out_shm->size);
*p_size = u32_sz;
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_get_attribute_value(CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE obj,
CK_ATTRIBUTE_PTR attribs,
CK_ULONG count)
{
CK_RV rv = CKR_GENERAL_ERROR;
CK_RV rv2 = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
struct serializer sattr = { 0 };
size_t ctrl_size = 0;
uint32_t session_handle = session;
uint32_t obj_handle = obj;
char *buf = NULL;
size_t out_size = 0;
if (count && !attribs)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_attributes(&sattr, attribs, count);
if (rv)
goto bail;
/* Shm io0: (in/out) [session][obj-handle][attributes] / [status] */
ctrl_size = sizeof(session_handle) + sizeof(obj_handle) + sattr.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &obj_handle, sizeof(obj_handle));
buf += sizeof(obj_handle);
memcpy(buf, sattr.buffer, sattr.size);
/* Shm io2: (out) [attributes] */
out_shm = ckteec_alloc_shm(sattr.size, CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_GET_ATTRIBUTE_VALUE,
ctrl, out_shm, &out_size);
if (rv == CKR_OK || rv == CKR_ATTRIBUTE_SENSITIVE ||
rv == CKR_ATTRIBUTE_TYPE_INVALID || rv == CKR_BUFFER_TOO_SMALL) {
rv2 = deserialize_ck_attributes(out_shm->buffer, attribs,
count);
if (rv2)
rv = CKR_GENERAL_ERROR;
}
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
release_serial_object(&sattr);
return rv;
}
CK_RV ck_set_attribute_value(CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE obj,
CK_ATTRIBUTE_PTR attribs,
CK_ULONG count)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
struct serializer sattr = { 0 };
size_t ctrl_size = 0;
uint32_t session_handle = session;
uint32_t obj_handle = obj;
char *buf = NULL;
if (count && !attribs)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_attributes(&sattr, attribs, count);
if (rv)
goto bail;
/* Shm io0: (in/out) [session][obj-handle][attributes] / [status] */
ctrl_size = sizeof(session_handle) + sizeof(obj_handle) + sattr.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &obj_handle, sizeof(obj_handle));
buf += sizeof(obj_handle);
memcpy(buf, sattr.buffer, sattr.size);
rv = ckteec_invoke_ctrl(PKCS11_CMD_SET_ATTRIBUTE_VALUE, ctrl);
bail:
ckteec_free_shm(ctrl);
release_serial_object(&sattr);
return rv;
}
CK_RV ck_copy_object(CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE obj,
CK_ATTRIBUTE_PTR attribs,
CK_ULONG count,
CK_OBJECT_HANDLE_PTR handle)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
struct serializer sattr = { 0 };
size_t ctrl_size = 0;
uint32_t session_handle = session;
uint32_t obj_handle = obj;
uint32_t key_handle = 0;
char *buf = NULL;
size_t out_size = 0;
if (!handle || (count && !attribs))
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_attributes(&sattr, attribs, count);
if (rv)
goto bail;
/* Shm io0: (in/out) [session][obj-handle][attributes] / [status] */
ctrl_size = sizeof(session_handle) + sizeof(obj_handle) + sattr.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &obj_handle, sizeof(obj_handle));
buf += sizeof(obj_handle);
memcpy(buf, sattr.buffer, sattr.size);
/* Shm io2: (out) [object handle] */
out_shm = ckteec_alloc_shm(sizeof(key_handle), CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_COPY_OBJECT,
ctrl, out_shm, &out_size);
if (rv != CKR_OK || out_size != out_shm->size) {
if (rv == CKR_OK)
rv = CKR_DEVICE_ERROR;
goto bail;
}
memcpy(&key_handle, out_shm->buffer, sizeof(key_handle));
*handle = key_handle;
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
release_serial_object(&sattr);
return rv;
}
CK_RV ck_derive_key(CK_SESSION_HANDLE session,
CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE parent_key,
CK_ATTRIBUTE_PTR attribs,
CK_ULONG count,
CK_OBJECT_HANDLE_PTR handle)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
struct serializer smecha = { 0 };
struct serializer sattr = { 0 };
uint32_t session_handle = session;
uint32_t obj_handle = parent_key;
size_t ctrl_size = 0;
uint32_t key_handle = 0;
char *buf = NULL;
size_t out_size = 0;
if (!handle || !mechanism || (count && !attribs))
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_mecha_params(&smecha, mechanism);
if (rv)
return rv;
rv = serialize_ck_attributes(&sattr, attribs, count);
if (rv)
goto bail;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][obj-handle][serialized-mecha][serialized-attributes]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + sizeof(obj_handle) + smecha.size +
sattr.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &obj_handle, sizeof(obj_handle));
buf += sizeof(obj_handle);
memcpy(buf, smecha.buffer, smecha.size);
buf += smecha.size;
memcpy(buf, sattr.buffer, sattr.size);
/* Shm io2: (out) [object handle] */
out_shm = ckteec_alloc_shm(sizeof(key_handle), CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_DERIVE_KEY,
ctrl, out_shm, &out_size);
if (rv != CKR_OK || out_size != out_shm->size) {
if (rv == CKR_OK)
rv = CKR_DEVICE_ERROR;
goto bail;
}
memcpy(&key_handle, out_shm->buffer, sizeof(key_handle));
*handle = key_handle;
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
release_serial_object(&sattr);
release_serial_object(&smecha);
return rv;
}
CK_RV ck_release_active_processing(CK_SESSION_HANDLE session,
enum pkcs11_ta_cmd command)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
uint32_t session_handle = session;
uint32_t cmd = command;
size_t ctrl_size = 0;
char *buf = NULL;
/* Shm io0: (in/out) ctrl = [session-handle][command] / [status] */
ctrl_size = sizeof(session_handle) + sizeof(cmd);
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl)
return CKR_HOST_MEMORY;
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &cmd, sizeof(cmd));
rv = ckteec_invoke_ctrl(PKCS11_CMD_RELEASE_ACTIVE_PROCESSING, ctrl);
ckteec_free_shm(ctrl);
return rv;
}
CK_RV ck_generate_key_pair(CK_SESSION_HANDLE session,
CK_MECHANISM_PTR mechanism,
CK_ATTRIBUTE_PTR pub_attribs,
CK_ULONG pub_count,
CK_ATTRIBUTE_PTR priv_attribs,
CK_ULONG priv_count,
CK_OBJECT_HANDLE_PTR pub_key,
CK_OBJECT_HANDLE_PTR priv_key)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
struct serializer smecha = { 0 };
struct serializer pub_sattr = { 0 };
struct serializer priv_sattr = { 0 };
uint32_t session_handle = session;
size_t ctrl_size = 0;
uint32_t *key_handle = NULL;
size_t key_handle_size = 2 * sizeof(*key_handle);
char *buf = NULL;
size_t out_size = 0;
if (!(mechanism && pub_attribs && priv_attribs && pub_key && priv_key))
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_mecha_params(&smecha, mechanism);
if (rv)
return rv;
rv = serialize_ck_attributes(&pub_sattr, pub_attribs, pub_count);
if (rv)
goto bail;
rv = serialize_ck_attributes(&priv_sattr, priv_attribs, priv_count);
if (rv)
goto bail;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][serialized-mecha][serialized-pub_attribs]
* [serialized-priv_attribs]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + smecha.size + pub_sattr.size +
priv_sattr.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, smecha.buffer, smecha.size);
buf += smecha.size;
memcpy(buf, pub_sattr.buffer, pub_sattr.size);
buf += pub_sattr.size;
memcpy(buf, priv_sattr.buffer, priv_sattr.size);
/*
* Shm io2: (out) public key object handle][private key object handle]
*/
out_shm = ckteec_alloc_shm(key_handle_size, CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_GENERATE_KEY_PAIR,
ctrl, out_shm, &out_size);
if (rv != CKR_OK || out_size != out_shm->size) {
if (rv == CKR_OK)
rv = CKR_DEVICE_ERROR;
goto bail;
}
key_handle = out_shm->buffer;
*pub_key = key_handle[0];
*priv_key = key_handle[1];
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
release_serial_object(&priv_sattr);
release_serial_object(&pub_sattr);
release_serial_object(&smecha);
return rv;
}
CK_RV ck_wrap_key(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key,
CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *out_shm = NULL;
struct serializer smecha = { 0 };
uint32_t session_handle = session;
uint32_t wrp_key_handle = wrapping_key;
uint32_t key_handle = key;
size_t ctrl_size = 0;
size_t out_size = 0;
char *buf = NULL;
if (!mechanism || !wrapped_key_len)
return CKR_ARGUMENTS_BAD;
rv = serialize_ck_mecha_params(&smecha, mechanism);
if (rv)
return rv;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][wrapping-key-handle][key-handle]
* [serialized-mecha]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + sizeof(wrp_key_handle) +
sizeof(key_handle) + smecha.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &wrp_key_handle, sizeof(wrp_key_handle));
buf += sizeof(wrp_key_handle);
memcpy(buf, &key_handle, sizeof(key_handle));
buf += sizeof(key_handle);
memcpy(buf, smecha.buffer, smecha.size);
/* Shm io2: output buffer reference - wrapped key */
if (wrapped_key && *wrapped_key_len)
out_shm = ckteec_register_shm(wrapped_key, *wrapped_key_len,
CKTEEC_SHM_OUT);
else
/* Query output data size */
out_shm = ckteec_alloc_shm(0, CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ctrl_out(PKCS11_CMD_WRAP_KEY, ctrl, out_shm,
&out_size);
if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
*wrapped_key_len = out_size;
if (rv == CKR_BUFFER_TOO_SMALL && out_size && !wrapped_key)
rv = CKR_OK;
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(ctrl);
release_serial_object(&smecha);
return rv;
}
CK_RV ck_unwrap_key(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE unwrapping_key, CK_BYTE_PTR wrapped_key,
CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR attribs,
CK_ULONG count, CK_OBJECT_HANDLE_PTR handle)
{
CK_RV rv = CKR_GENERAL_ERROR;
TEEC_SharedMemory *ctrl = NULL;
TEEC_SharedMemory *in_shm = NULL;
TEEC_SharedMemory *out_shm = NULL;
struct serializer smecha = { 0 };
struct serializer sattr = { 0 };
uint32_t session_handle = session;
uint32_t unwrapping_key_handle = unwrapping_key;
size_t ctrl_size = 0;
uint32_t key_handle = 0;
char *buf = NULL;
size_t out_size = 0;
if (!handle || !mechanism || (count && !attribs) ||
(wrapped_key_len && !wrapped_key))
return CKR_ARGUMENTS_BAD;
if (!unwrapping_key)
return CKR_UNWRAPPING_KEY_HANDLE_INVALID;
rv = serialize_ck_mecha_params(&smecha, mechanism);
if (rv)
return rv;
rv = serialize_ck_attributes(&sattr, attribs, count);
if (rv)
goto bail;
/*
* Shm io0: (in/out) ctrl
* (in) [session-handle][unwrapping-key-handle][serialized-mecha]
* [serialized-attributes]
* (out) [status]
*/
ctrl_size = sizeof(session_handle) + sizeof(unwrapping_key_handle) +
smecha.size + sattr.size;
ctrl = ckteec_alloc_shm(ctrl_size, CKTEEC_SHM_INOUT);
if (!ctrl) {
rv = CKR_HOST_MEMORY;
goto bail;
}
buf = ctrl->buffer;
memcpy(buf, &session_handle, sizeof(session_handle));
buf += sizeof(session_handle);
memcpy(buf, &unwrapping_key_handle, sizeof(unwrapping_key_handle));
buf += sizeof(unwrapping_key_handle);
memcpy(buf, smecha.buffer, smecha.size);
buf += smecha.size;
memcpy(buf, sattr.buffer, sattr.size);
/* Shm io1: input - wrapped key buffer */
in_shm = ckteec_register_shm(wrapped_key, wrapped_key_len,
CKTEEC_SHM_IN);
if (!in_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
/* Shm io2: (out) [object handle] */
out_shm = ckteec_alloc_shm(sizeof(key_handle), CKTEEC_SHM_OUT);
if (!out_shm) {
rv = CKR_HOST_MEMORY;
goto bail;
}
rv = ckteec_invoke_ta(PKCS11_CMD_UNWRAP_KEY, ctrl, in_shm, out_shm,
&out_size, NULL, NULL);
if (rv != CKR_OK || out_size != out_shm->size) {
if (rv == CKR_OK)
rv = CKR_DEVICE_ERROR;
goto bail;
}
memcpy(&key_handle, out_shm->buffer, sizeof(key_handle));
*handle = key_handle;
bail:
ckteec_free_shm(out_shm);
ckteec_free_shm(in_shm);
ckteec_free_shm(ctrl);
release_serial_object(&sattr);
release_serial_object(&smecha);
return rv;
}