#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include "metaGlobal.h"
#include "metaAttrMasters.h"
static void
find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes,
size_t num_attributes, generic_attr_t **found_attribute);
CK_RV
get_master_attributes_by_object(slot_session_t *session,
slot_object_t *slot_object, generic_attr_t **attributes,
size_t *num_attributes)
{
CK_RV rv;
CK_ATTRIBUTE attr;
CK_OBJECT_CLASS class;
CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION;
attr.type = CKA_CLASS;
attr.pValue = &class;
attr.ulValueLen = sizeof (class);
rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue(
session->hSession, slot_object->hObject, &attr, 1);
if (rv != CKR_OK) {
return (rv);
}
attr.pValue = &subtype;
attr.ulValueLen = sizeof (subtype);
switch (class) {
case CKO_CERTIFICATE:
attr.type = CKA_CERTIFICATE_TYPE;
break;
case CKO_HW_FEATURE:
attr.type = CKA_HW_FEATURE_TYPE;
break;
case CKO_PUBLIC_KEY:
case CKO_PRIVATE_KEY:
case CKO_SECRET_KEY:
case CKO_DOMAIN_PARAMETERS:
attr.type = CKA_KEY_TYPE;
break;
case CKO_DATA:
goto get_attr;
default:
return (CKR_ATTRIBUTE_VALUE_INVALID);
}
rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue(
session->hSession, slot_object->hObject, &attr, 1);
if (rv != CKR_OK) {
return (rv);
}
get_attr:
rv = get_master_attributes_by_type(class, subtype,
attributes, num_attributes);
return (rv);
}
CK_RV
get_master_attributes_by_template(
CK_ATTRIBUTE *template, CK_ULONG template_size,
generic_attr_t **attributes, size_t *num_attributes)
{
CK_OBJECT_CLASS class;
CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION;
boolean_t found;
found = get_template_ulong(CKA_CLASS, template, template_size, &class);
if (!found) {
return (CKR_TEMPLATE_INCOMPLETE);
}
switch (class) {
case CKO_CERTIFICATE:
found = get_template_ulong(CKA_CERTIFICATE_TYPE,
template, template_size, &subtype);
break;
case CKO_HW_FEATURE:
found = get_template_ulong(CKA_HW_FEATURE_TYPE,
template, template_size, &subtype);
break;
case CKO_PUBLIC_KEY:
case CKO_PRIVATE_KEY:
case CKO_SECRET_KEY:
case CKO_DOMAIN_PARAMETERS:
found = get_template_ulong(CKA_KEY_TYPE,
template, template_size, &subtype);
break;
case CKO_DATA:
found = B_TRUE;
break;
default:
return (CKR_ATTRIBUTE_VALUE_INVALID);
}
if (!found) {
return (CKR_TEMPLATE_INCOMPLETE);
}
return (get_master_attributes_by_type(class, subtype,
attributes, num_attributes));
}
CK_RV
get_master_template_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype,
generic_attr_t **attributes, size_t *num_attributes)
{
generic_attr_t *master_template = NULL;
size_t master_template_size = 0;
switch (class) {
case CKO_HW_FEATURE:
switch (subtype) {
case CKO_HW_FEATURE:
master_template = (generic_attr_t *)OBJ_HW_CLOCK;
master_template_size = sizeof (OBJ_HW_CLOCK);
break;
case CKH_MONOTONIC_COUNTER:
master_template = (generic_attr_t *)OBJ_HW_MONOTONIC;
master_template_size = sizeof (OBJ_HW_MONOTONIC);
break;
default:
break;
}
break;
case CKO_DATA:
master_template = (generic_attr_t *)OBJ_DATA;
master_template_size = sizeof (OBJ_DATA);
break;
case CKO_CERTIFICATE:
switch (subtype) {
case CKC_X_509:
master_template = (generic_attr_t *)OBJ_CERT_X509;
master_template_size = sizeof (OBJ_CERT_X509);
break;
case CKC_X_509_ATTR_CERT:
master_template = (generic_attr_t *)OBJ_CERT_X509ATTR;
master_template_size = sizeof (OBJ_CERT_X509ATTR);
break;
default:
break;
}
break;
case CKO_PUBLIC_KEY:
switch (subtype) {
case CKK_RSA:
master_template = (generic_attr_t *)OBJ_PUBKEY_RSA;
master_template_size = sizeof (OBJ_PUBKEY_RSA);
break;
case CKK_DSA:
master_template = (generic_attr_t *)OBJ_PUBKEY_DSA;
master_template_size = sizeof (OBJ_PUBKEY_DSA);
break;
case CKK_EC:
master_template = (generic_attr_t *)OBJ_PUBKEY_EC;
master_template_size = sizeof (OBJ_PUBKEY_EC);
break;
case CKK_DH:
master_template = (generic_attr_t *)OBJ_PUBKEY_DH;
master_template_size = sizeof (OBJ_PUBKEY_DH);
break;
case CKK_X9_42_DH:
master_template = (generic_attr_t *)OBJ_PUBKEY_X942DH;
master_template_size = sizeof (OBJ_PUBKEY_X942DH);
break;
case CKK_KEA:
master_template = (generic_attr_t *)OBJ_PUBKEY_KEA;
master_template_size = sizeof (OBJ_PUBKEY_KEA);
break;
default:
break;
}
break;
case CKO_PRIVATE_KEY:
switch (subtype) {
case CKK_RSA:
master_template = (generic_attr_t *)OBJ_PRIVKEY_RSA;
master_template_size = sizeof (OBJ_PRIVKEY_RSA);
break;
case CKK_DSA:
master_template = (generic_attr_t *)OBJ_PRIVKEY_DSA;
master_template_size = sizeof (OBJ_PRIVKEY_DSA);
break;
case CKK_EC:
master_template = (generic_attr_t *)OBJ_PRIVKEY_EC;
master_template_size = sizeof (OBJ_PRIVKEY_EC);
break;
case CKK_DH:
master_template = (generic_attr_t *)OBJ_PRIVKEY_DH;
master_template_size = sizeof (OBJ_PRIVKEY_DH);
break;
case CKK_X9_42_DH:
master_template = (generic_attr_t *)OBJ_PRIVKEY_X942DH;
master_template_size = sizeof (OBJ_PRIVKEY_X942DH);
break;
case CKK_KEA:
master_template = (generic_attr_t *)OBJ_PRIVKEY_KEA;
master_template_size = sizeof (OBJ_PRIVKEY_KEA);
break;
default:
break;
}
break;
case CKO_SECRET_KEY:
switch (subtype) {
case CKK_DES:
case CKK_DES2:
case CKK_DES3:
case CKK_IDEA:
case CKK_CDMF:
case CKK_SKIPJACK:
case CKK_BATON:
case CKK_JUNIPER:
master_template = (generic_attr_t *)OBJ_SECKEY;
master_template_size = sizeof (OBJ_SECKEY);
break;
case CKK_GENERIC_SECRET:
case CKK_RC2:
case CKK_RC4:
case CKK_RC5:
case CKK_AES:
case CKK_BLOWFISH:
case CKK_CAST:
case CKK_CAST3:
case CKK_CAST128:
master_template = (generic_attr_t *)OBJ_SECKEY_WITHLEN;
master_template_size = sizeof (OBJ_SECKEY_WITHLEN);
break;
default:
break;
}
break;
case CKO_DOMAIN_PARAMETERS:
switch (subtype) {
case CKK_DSA:
master_template = (generic_attr_t *)OBJ_DOM_DSA;
master_template_size = sizeof (OBJ_DOM_DSA);
break;
case CKK_DH:
master_template = (generic_attr_t *)OBJ_DOM_DH;
master_template_size = sizeof (OBJ_DOM_DH);
break;
case CKK_X9_42_DH:
master_template = (generic_attr_t *)OBJ_DOM_X942DH;
master_template_size = sizeof (OBJ_DOM_X942DH);
break;
default:
break;
}
break;
default:
break;
}
if (master_template == NULL)
return (CKR_ATTRIBUTE_VALUE_INVALID);
else {
*attributes = master_template;
*num_attributes = master_template_size;
return (CKR_OK);
}
}
CK_RV
get_master_attributes_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype,
generic_attr_t **attributes, size_t *num_attributes)
{
CK_RV rv;
generic_attr_t *master_template = NULL;
generic_attr_t *new_attributes;
size_t i, num_new_attributes, master_template_size = 0;
rv = get_master_template_by_type(class, subtype,
&master_template, &master_template_size);
if (rv != CKR_OK)
return (rv);
new_attributes = malloc(master_template_size);
if (new_attributes == NULL)
return (CKR_HOST_MEMORY);
(void) memcpy(new_attributes, master_template, master_template_size);
num_new_attributes = master_template_size / sizeof (generic_attr_t);
for (i = 0; i < num_new_attributes; i++) {
generic_attr_t *attr;
attr = new_attributes + i;
switch (attr->attribute.ulValueLen) {
case (sizeof (CK_ULONG)):
attr->attribute.pValue = &attr->generic_ulong;
break;
case (sizeof (CK_BBOOL)):
attr->attribute.pValue = &attr->generic_bbool;
break;
default:
attr->attribute.pValue = attr->generic_data;
break;
}
}
if (class == CKO_SECRET_KEY) {
new_attributes[1].generic_ulong = subtype;
}
*attributes = new_attributes;
*num_attributes = num_new_attributes;
return (CKR_OK);
}
CK_RV
get_master_attributes_by_duplication(
generic_attr_t *src_attrs, size_t num_src_attrs,
generic_attr_t **dst_attrs, size_t *num_dst_attrs)
{
CK_RV rv = CKR_OK;
generic_attr_t *new_attrs, *src, *dst;
size_t i;
new_attrs = malloc(sizeof (generic_attr_t) * num_src_attrs);
if (new_attrs == NULL)
return (CKR_HOST_MEMORY);
for (i = 0; i < num_src_attrs; i++) {
src = src_attrs + i;
dst = new_attrs + i;
*dst = *src;
if (src->isMalloced) {
dst->attribute.pValue =
malloc(src->attribute.ulValueLen);
if (dst->attribute.pValue == NULL) {
dst->attribute.ulValueLen = 0;
rv = CKR_HOST_MEMORY;
continue;
}
} else if (src->attribute.pValue == &src->generic_bbool) {
dst->attribute.pValue = &dst->generic_bbool;
} else if (src->attribute.pValue == &src->generic_ulong) {
dst->attribute.pValue = &dst->generic_ulong;
} else if (src->attribute.pValue == &src->generic_data) {
dst->attribute.pValue = &dst->generic_data;
} else {
dst->attribute.pValue = NULL;
dst->attribute.ulValueLen = 0;
rv = CKR_GENERAL_ERROR;
num_src_attrs = i + 1;
break;
}
(void) memcpy(dst->attribute.pValue, src->attribute.pValue,
src->attribute.ulValueLen);
}
if (rv != CKR_OK) {
dealloc_attributes(new_attrs, num_src_attrs);
} else {
*dst_attrs = new_attrs;
*num_dst_attrs = num_src_attrs;
}
return (rv);
}
void
dealloc_attributes(generic_attr_t *attributes, size_t num_attributes)
{
size_t i;
generic_attr_t *attr;
for (i = 0; i < num_attributes; i++) {
attr = attributes + i;
explicit_bzero(attr->attribute.pValue,
attr->attribute.ulValueLen);
if (attr->isMalloced)
free(attr->attribute.pValue);
}
free(attributes);
}
CK_RV
attribute_set_value(CK_ATTRIBUTE *new_attr,
generic_attr_t *attributes, size_t num_attributes)
{
generic_attr_t *attr = NULL;
if (new_attr == NULL)
return (CKR_TEMPLATE_INCOMPLETE);
else if (new_attr->pValue == NULL) {
return (CKR_ATTRIBUTE_VALUE_INVALID);
}
find_attribute(new_attr->type, attributes, num_attributes, &attr);
if (attr == NULL) {
return (CKR_ATTRIBUTE_TYPE_INVALID);
}
if (attr->attribute.ulValueLen >= new_attr->ulValueLen) {
explicit_bzero((char *)attr->attribute.pValue +
new_attr->ulValueLen,
attr->attribute.ulValueLen - new_attr->ulValueLen);
} else if (new_attr->ulValueLen <= sizeof (attr->generic_data)) {
explicit_bzero(attr->attribute.pValue,
attr->attribute.ulValueLen);
if (attr->isMalloced) {
free(attr->attribute.pValue);
attr->isMalloced = B_FALSE;
}
attr->attribute.pValue = attr->generic_data;
} else {
void *newStorage;
newStorage = malloc(new_attr->ulValueLen);
if (newStorage == NULL)
return (CKR_HOST_MEMORY);
bzero(attr->attribute.pValue, attr->attribute.ulValueLen);
attr->attribute.pValue = newStorage;
attr->isMalloced = B_TRUE;
}
(void) memcpy(attr->attribute.pValue, new_attr->pValue,
new_attr->ulValueLen);
attr->attribute.ulValueLen = new_attr->ulValueLen;
attr->hasValueForClone = B_TRUE;
return (CKR_OK);
}
static void
find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes,
size_t num_attributes, generic_attr_t **found_attribute)
{
generic_attr_t *attr;
boolean_t found = B_FALSE;
size_t i;
for (i = 0, attr = attributes; i < num_attributes; i++, attr++) {
if (attr->attribute.type == attrtype) {
found = B_TRUE;
break;
}
}
*found_attribute = found ? attr : NULL;
}
boolean_t
get_template_ulong(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
CK_ULONG num_attributes, CK_ULONG *result)
{
boolean_t found = B_FALSE;
CK_ULONG i;
for (i = 0; i < num_attributes; i++) {
if (attributes[i].type == type) {
CK_ULONG *value = attributes[i].pValue;
*result = *value;
found = B_TRUE;
break;
}
}
return (found);
}
boolean_t
get_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
CK_ULONG num_attributes, boolean_t *result)
{
boolean_t found = B_FALSE;
CK_ULONG i;
for (i = 0; i < num_attributes; i++) {
if (attributes[i].type == type) {
CK_BBOOL *value = attributes[i].pValue;
if (*value == CK_FALSE)
*result = B_FALSE;
else
*result = B_TRUE;
found = B_TRUE;
break;
}
}
return (found);
}
int
set_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
CK_ULONG num_attributes, boolean_t local, CK_BBOOL *value)
{
int i;
for (i = 0; i < num_attributes; i++) {
if (attributes[i].type == type) {
if (local)
attributes[i].pValue = value;
else
*((CK_BBOOL *)attributes[i].pValue) = *value;
return (i);
}
}
return (-1);
}