1
0
mirror of https://github.com/opencryptoki/opencryptoki.git synced 2026-10-24 05:39:17 +03:00
Files
opencryptoki/usr/lib/common/key.c
Alexandre Laroche 2345b3c7e9 COMMON: Honour CKA_SENSITIVE and CKA_EXTRACTABLE from the unwrap template
secret_key_unwrap() and priv_key_unwrap() set CKA_SENSITIVE to FALSE and
CKA_EXTRACTABLE to TRUE on every unwrapped key, after the caller's
template, and the unwrapping key's CKA_UNWRAP_TEMPLATE, had already been
validated and merged into the new object. Both were silently overwritten:

 - a template asking for CKA_SENSITIVE = TRUE and CKA_EXTRACTABLE = FALSE
   gave a key whose value could be read in clear with
   C_GetAttributeValue(CKA_VALUE) and wrapped out again;
 - an unwrapping key whose CKA_UNWRAP_TEMPLATE requires CKA_SENSITIVE =
   TRUE or CKA_EXTRACTABLE = FALSE did not get that policy applied to the
   keys unwrapped with it.

C_UnwrapKey returned CKR_OK in both cases.

Stop overwriting these two attributes. object_create_skel() already
starts the object from the class defaults (CKA_SENSITIVE = FALSE,
CKA_EXTRACTABLE = TRUE), lets the token's t_set_attrs_for_new_object()
supply its own defaults, and merges the template over them. CKA_LOCAL,
CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE are still set to FALSE, as
PKCS#11 requires for an unwrapped key.

For a template that does not specify the two attributes, under an
unwrapping key without a CKA_UNWRAP_TEMPLATE, tokens that keep the class
defaults give the same key as before. Tokens that default CKA_SENSITIVE
to TRUE (EP11 and CCA for private keys, and for secret keys when
FORCE_SENSITIVE is enabled) now apply that default to unwrapped keys
too, as they already do for generated and derived keys; until now the
unwrap path overwrote it with FALSE.

Signed-off-by: Alexandre Laroche <larochealexandre@hotmail.com>
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
2026-10-19 13:52:53 +02:00

8897 lines
273 KiB
C

/*
* COPYRIGHT (c) International Business Machines Corp. 2001-2017
*
* This program is provided under the terms of the Common Public License,
* version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
* software constitutes recipient's acceptance of CPL-1.0 terms which can be
* found in the file LICENSE file or at
* https://opensource.org/licenses/cpl1.0.php
*/
// File: key.c
//
// Functions contained within:
//
// key_object_check_required_attributes
// key_object_set_default_attributes
// key_object_validate_attribute
//
// publ_key_check_required_attributes
// publ_key_set_default_attributes
// publ_key_validate_attribute
//
// priv_key_check_required_attributes
// priv_key_set_default_attributes
// priv_key_validate_attribute
//
// secret_key_check_required_attributes
// secret_key_set_default_attributes
// secret_key_validate_attribute
//
// rsa_publ_check_required_attributes
// rsa_publ_validate_attribute
// rsa_priv_check_required_attributes
// rsa_priv_validate_attribute
// rsa_priv_check_exportability
//
// dsa_publ_check_required_attributes
// dsa_publ_validate_attribute
// dsa_priv_check_required_attributes
// dsa_priv_validate_attribute
// dsa_priv_check_exportability
//
// ec_publ_check_required_attributes
// ec_publ_validate_attribute
// ec_priv_check_required_attributes
// ec_priv_validate_attribute
// ec_priv_check_exportability
//
// dh_publ_check_required_attributes
// dh_publ_validate_attribute
// dh_priv_check_required_attributes
// dh_priv_validate_attribute
// dh_priv_check_exportability
//
// generic_secret_check_required_attributes
// generic_secret_validate_attribute
// generic_secret_set_default_attributes
//
// des_check_required_attributes
// des_validate_attribute
// des_priv_check_exportability
//
// des2_check_required_attributes
// des2_validate_attribute
// des2_priv_check_exportability
//
// des3_check_required_attributes
// des3_validate_attribute
// des3_priv_check_exportability
//
#include <pthread.h>
#include <stdlib.h>
#include <string.h> // for memcmp() et al
#include "pkcs11types.h"
#include "p11util.h"
#include "defs.h"
#include "host_defs.h"
#include "h_extern.h"
#include "attributes.h"
#include "trace.h"
#include "pqc_defs.h"
#include "ec_defs.h"
#include "tok_spec_struct.h"
#include <openssl/rsa.h>
// key_object_check_required_attributes()
//
// Check required common attributes for key objects
//
CK_RV key_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ULONG val;
CK_RV rc;
rc = template_attribute_get_ulong(tmpl, CKA_KEY_TYPE, &val);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_KEY_TYPE\n");
return rc;
}
}
return template_check_required_base_attributes(tmpl, mode);
}
// key_object_set_default_attributes()
//
CK_RV key_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *id_attr = NULL;
CK_ATTRIBUTE *sdate_attr = NULL;
CK_ATTRIBUTE *edate_attr = NULL;
CK_ATTRIBUTE *derive_attr = NULL;
CK_ATTRIBUTE *local_attr = NULL;
CK_ATTRIBUTE *keygenmech_attr = NULL;
CK_ATTRIBUTE *allowedmechs_attr = NULL;
CK_ATTRIBUTE *pkey_attr = NULL;
CK_ATTRIBUTE *pkey_nextr_attr = NULL;
CK_RV rc;
UNUSED(mode);
id_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
sdate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
edate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
derive_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
local_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
keygenmech_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)
+ sizeof(CK_MECHANISM_TYPE));
allowedmechs_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
pkey_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
pkey_nextr_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
if (!id_attr || !sdate_attr || !edate_attr || !derive_attr || !local_attr
|| !keygenmech_attr || !allowedmechs_attr || !pkey_attr
|| !pkey_nextr_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
id_attr->type = CKA_ID;
id_attr->ulValueLen = 0;
id_attr->pValue = NULL;
sdate_attr->type = CKA_START_DATE;
sdate_attr->ulValueLen = 0;
sdate_attr->pValue = NULL;
edate_attr->type = CKA_END_DATE;
edate_attr->ulValueLen = 0;
edate_attr->pValue = NULL;
derive_attr->type = CKA_DERIVE;
derive_attr->ulValueLen = sizeof(CK_BBOOL);
derive_attr->pValue = (CK_BYTE *) derive_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) derive_attr->pValue = FALSE;
local_attr->type = CKA_LOCAL;
local_attr->ulValueLen = sizeof(CK_BBOOL);
local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) local_attr->pValue = FALSE;
keygenmech_attr->type = CKA_KEY_GEN_MECHANISM;
keygenmech_attr->ulValueLen = sizeof(CK_MECHANISM_TYPE);
keygenmech_attr->pValue = (CK_BYTE *) keygenmech_attr + sizeof(CK_ATTRIBUTE);
*(CK_MECHANISM_TYPE *) keygenmech_attr->pValue = CK_UNAVAILABLE_INFORMATION;
allowedmechs_attr->type = CKA_ALLOWED_MECHANISMS;
allowedmechs_attr->ulValueLen = 0;
allowedmechs_attr->pValue = NULL;
pkey_attr->type = CKA_IBM_PROTKEY_EXTRACTABLE;
pkey_attr->ulValueLen = sizeof(CK_BBOOL);
pkey_attr->pValue = (CK_BBOOL *) pkey_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) pkey_attr->pValue = FALSE;
pkey_nextr_attr->type = CKA_IBM_PROTKEY_NEVER_EXTRACTABLE;
pkey_nextr_attr->ulValueLen = sizeof(CK_BBOOL);
pkey_nextr_attr->pValue = (CK_BBOOL *)pkey_nextr_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *)pkey_nextr_attr->pValue = TRUE;
rc = template_update_attribute(tmpl, id_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
id_attr = NULL;
rc = template_update_attribute(tmpl, sdate_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
sdate_attr = NULL;
rc = template_update_attribute(tmpl, edate_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
edate_attr = NULL;
rc = template_update_attribute(tmpl, derive_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
derive_attr = NULL;
rc = template_update_attribute(tmpl, local_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
local_attr = NULL;
rc = template_update_attribute(tmpl, keygenmech_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
keygenmech_attr = NULL;
rc = template_update_attribute(tmpl, allowedmechs_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
allowedmechs_attr = NULL;
rc = template_update_attribute(tmpl, pkey_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
pkey_attr = NULL;
rc = template_update_attribute(tmpl, pkey_nextr_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
pkey_nextr_attr = NULL;
return CKR_OK;
error:
if (id_attr)
free(id_attr);
if (sdate_attr)
free(sdate_attr);
if (edate_attr)
free(edate_attr);
if (derive_attr)
free(derive_attr);
if (local_attr)
free(local_attr);
if (keygenmech_attr)
free(keygenmech_attr);
if (allowedmechs_attr)
free(allowedmechs_attr);
if (pkey_attr)
free(pkey_attr);
if (pkey_nextr_attr)
free(pkey_nextr_attr);
return rc;
}
// key_object_validate_attribute()
//
CK_RV key_object_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode)
{
CK_RV rc;
CK_BBOOL ck_false = TRUE;
switch (attr->type) {
case CKA_KEY_TYPE:
if (attr->ulValueLen != sizeof(CK_KEY_TYPE) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_KEYGEN || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS ||
mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_ID:
case CKA_START_DATE:
case CKA_END_DATE:
return CKR_OK;
case CKA_ALLOWED_MECHANISMS:
if ((attr->ulValueLen > 0 && attr->pValue == NULL) ||
attr->ulValueLen % sizeof(CK_MECHANISM_TYPE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_DERIVE || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS ||
mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_DERIVE:
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
case CKA_KEY_GEN_MECHANISM:
case CKA_LOCAL:
/*
* CKA_LOCAL and CKA_KEY_GEN_MECHANISM are only set by the
* key-generate routine, but for extract it is allowed to be set.
*/
if (mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_IBM_PROTKEY_EXTRACTABLE:
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
CK_BBOOL value = *(CK_BBOOL *) attr->pValue;
if (mode != MODE_CREATE && mode != MODE_DERIVE &&
mode != MODE_KEYGEN && mode != MODE_UNWRAP &&
mode != MODE_ENCAPS && mode != MODE_DECAPS &&
mode != MODE_EXTRACT && value != FALSE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
if (value == TRUE) {
rc = template_build_update_attribute(tmpl,
CKA_IBM_PROTKEY_NEVER_EXTRACTABLE,
(CK_BYTE *)&ck_false,
sizeof(ck_false));
if (rc != CKR_OK) {
TRACE_DEVEL("template_build_update_attribute failed.\n");
return rc;
}
}
return CKR_OK;
case CKA_IBM_PROTKEY_NEVER_EXTRACTABLE:
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_IBM_ATTRBOUND:
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN
|| mode == MODE_UNWRAP || mode == MODE_ENCAPS ||
mode == MODE_DECAPS || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_IBM_USE_AS_DATA:
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN
|| mode == MODE_UNWRAP || mode == MODE_ENCAPS ||
mode == MODE_DECAPS || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return template_validate_base_attribute(tmpl, attr, mode);
}
TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type);
return CKR_ATTRIBUTE_TYPE_INVALID;
}
/*
* Check if the specified mechanism is contained in the CKA_ALLOWED_MECHANISMS
* attribute. If CKA_ALLOWED_MECHANISMS is not existing, or empty, then all
* mechanisms are allowed.
*/
CK_BBOOL key_object_is_mechanism_allowed(TEMPLATE *tmpl, CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *attr = NULL;
CK_MECHANISM_TYPE *mechs;
CK_ULONG num_mechs, i;
if (!template_attribute_find(tmpl, CKA_ALLOWED_MECHANISMS, &attr))
return TRUE;
if (attr->ulValueLen == 0 || attr->pValue == NULL)
return TRUE;
mechs = (CK_MECHANISM_TYPE *)attr->pValue;
num_mechs = attr->ulValueLen / sizeof(CK_MECHANISM_TYPE);
for (i = 0; i < num_mechs; i++) {
if (mechs[i] == mech)
return TRUE;
}
return FALSE;
}
/*
* Check if the to be wrapped key template matches the wrap template of the
* wrapping key (CKA_WRAP_TEMPLATE), if the wrapping key has one.
*/
CK_BBOOL key_object_wrap_template_matches(TEMPLATE *wrap_tmpl, TEMPLATE *tmpl)
{
CK_ATTRIBUTE *attr = NULL;
if (!template_attribute_find(wrap_tmpl, CKA_WRAP_TEMPLATE, &attr))
return TRUE;
if (attr->ulValueLen == 0 || attr->pValue == NULL)
return TRUE;
return template_compare((CK_ATTRIBUTE_PTR)attr->pValue,
attr->ulValueLen / sizeof(CK_ATTRIBUTE), tmpl);
}
CK_RV key_object_apply_template_attr(TEMPLATE *unwrap_tmpl,
CK_ATTRIBUTE_TYPE attr_type,
CK_ATTRIBUTE_PTR attrs,
CK_ULONG attrs_count,
CK_ATTRIBUTE_PTR *new_attrs,
CK_ULONG *new_attrs_count)
{
CK_ATTRIBUTE *attr = NULL;
CK_ATTRIBUTE_PTR apply_attrs;
CK_ULONG num_apply_attrs, i;
CK_RV rc;
rc = dup_attribute_array(attrs, attrs_count, new_attrs, new_attrs_count);
if (rc != CKR_OK) {
TRACE_DEVEL("dup_attribute_array failed\n");
return rc;
}
if (!template_attribute_find(unwrap_tmpl, attr_type, &attr))
return CKR_OK;
if (attr->ulValueLen == 0 || attr->pValue == NULL)
return CKR_OK;
apply_attrs = (CK_ATTRIBUTE_PTR)attr->pValue;
num_apply_attrs = attr->ulValueLen / sizeof (CK_ATTRIBUTE);
for (i = 0; i < num_apply_attrs; i++) {
/*
* If the attribute to apply is already in the user supplied template,
* make sure that it does not conflict.
*/
attr = get_attribute_by_type(attrs, attrs_count, apply_attrs[i].type);
if (attr != NULL) {
if (compare_attribute(attr, &apply_attrs[i]) == FALSE) {
TRACE_DEVEL("%s: %lu conflicts\n",
ock_err(ERR_TEMPLATE_INCONSISTENT),
apply_attrs[i].type);
return CKR_TEMPLATE_INCONSISTENT;
}
} else {
rc = add_to_attribute_array(new_attrs, new_attrs_count,
apply_attrs[i].type,
apply_attrs[i].pValue,
apply_attrs[i].ulValueLen);
if (rc != CKR_OK) {
TRACE_DEVEL("add_to_attribute_array failed\n");
return rc;
}
}
}
return CKR_OK;
}
CK_RV key_object_is_always_authenticate(TEMPLATE *tmpl, CK_BBOOL *auth)
{
CK_OBJECT_CLASS class;
CK_BBOOL private;
CK_RV rc;
rc = template_attribute_get_ulong(tmpl, CKA_CLASS, &class);
if (rc != CKR_OK) {
TRACE_DEVEL("Can not find CKA_CLASS in object\n");
return rc;
}
/* CKA_ALWAYS_AUTHENTICATE is only defined for CKO_PRIVATE_KEY objects */
if (class != CKO_PRIVATE_KEY) {
*auth = FALSE;
return CKR_OK;
}
rc = template_attribute_get_bool(tmpl, CKA_PRIVATE, &private);
if (rc != CKR_OK) {
TRACE_DEVEL("Can not find CKA_PRIVATE in object\n");
return rc;
}
/* CKA_ALWAYS_AUTHENTICATE can only be true if CKA_PRIVATE is also TRUE */
if (private == FALSE) {
*auth = FALSE;
return CKR_OK;
}
rc = template_attribute_get_bool(tmpl, CKA_ALWAYS_AUTHENTICATE, auth);
if (rc == CKR_TEMPLATE_INCOMPLETE) {
*auth = FALSE;
} else if (rc != CKR_OK) {
TRACE_DEVEL("CKA_ALWAYS_AUTHENTICATE is invalid\n");
return rc;
}
return CKR_OK;
}
CK_RV key_pub_from_priv(STDLL_TokData_t *tokdata, SESSION *sess,
OBJECT *priv_key_obj,
CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount,
CK_OBJECT_HANDLE *pub_key_handle)
{
CK_ATTRIBUTE *attrs = NULL;
CK_ULONG num_attrs = 0;
CK_ATTRIBUTE *attr, *spki_attr;
CK_OBJECT_CLASS class;
CK_KEY_TYPE keytype;
CK_BBOOL ck_true = CK_TRUE, ck_false = CK_FALSE;
CK_ULONG i;
TEMPLATE *tmpl = NULL;
DL_NODE *node;
CK_RV rc;
const struct default_attr {
CK_ATTRIBUTE attr;
CK_BBOOL copy_from_priv;
CK_ATTRIBUTE_TYPE priv_attr_type;
} default_attrs[] = {
{ .attr = { CKA_TOKEN, &ck_false, sizeof(ck_false)} },
{ .attr = { CKA_PRIVATE, &ck_false, sizeof(ck_false) } },
{ .attr = { CKA_MODIFIABLE, &ck_true, sizeof(ck_true) } },
{ .attr = { CKA_LOCAL, &ck_false, sizeof(ck_false) } },
{ .attr = { CKA_COPYABLE, &ck_true, sizeof(ck_true) } },
{ .attr = { CKA_DESTROYABLE, &ck_true, sizeof(ck_true) } },
{ .attr = { CKA_LABEL, NULL, 0 } },
{ .attr = { CKA_WRAP_TEMPLATE, NULL, 0 } },
{ .attr = { CKA_ENCRYPT, &ck_false, sizeof(ck_false) },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_DECRYPT },
{ .attr = { CKA_VERIFY, &ck_false, sizeof(ck_false) },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_SIGN },
{ .attr = { CKA_VERIFY_RECOVER, &ck_false, sizeof(ck_false) },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_SIGN_RECOVER },
{ .attr = { CKA_WRAP, &ck_false, sizeof(ck_false) },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_UNWRAP },
{ .attr = { CKA_DERIVE, &ck_false, sizeof(ck_false) },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_DERIVE },
{ .attr = { CKA_ID, NULL, 0 },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_ID },
{ .attr = { CKA_START_DATE, NULL, 0 },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_START_DATE },
{ .attr = { CKA_END_DATE, NULL, 0 },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_END_DATE },
{ .attr = { CKA_SUBJECT, NULL, 0 },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_SUBJECT },
{ .attr = { CKA_PUBLIC_KEY_INFO, NULL, 0 },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_PUBLIC_KEY_INFO },
{ .attr = { CKA_KEY_GEN_MECHANISM, NULL, 0 },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_KEY_GEN_MECHANISM },
{ .attr = { CKA_ALLOWED_MECHANISMS, NULL, 0 },
.copy_from_priv = CK_TRUE, .priv_attr_type = CKA_ALLOWED_MECHANISMS },
};
rc = template_attribute_get_ulong(priv_key_obj->template,
CKA_CLASS, &class);
if (rc != CKR_OK) {
TRACE_DEVEL("Can not find CKA_CLASS in object\n");
return rc;
}
if (class != CKO_PRIVATE_KEY) {
TRACE_DEVEL("Base key is not a private key\n");
return CKR_KEY_TYPE_INCONSISTENT;
}
rc = template_attribute_get_ulong(priv_key_obj->template,
CKA_KEY_TYPE, &keytype);
if (rc != CKR_OK) {
TRACE_DEVEL("Can not find CKA_KEY_TYPE in object\n");
return rc;
}
rc = template_attribute_get_non_empty(priv_key_obj->template,
CKA_PUBLIC_KEY_INFO, &spki_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("Can not find CKA_PUBLIC_KEY_INFO in object\n");
return CKR_PUBLIC_KEY_INVALID;
}
rc = dup_attribute_array(pTemplate, ulCount, &attrs, &num_attrs);
if (rc != CKR_OK) {
TRACE_DEVEL("dup_attribute_array failed\n");
return rc;
}
/* Add class and key type attributes */
class = CKO_PUBLIC_KEY;
rc = add_to_attribute_array(&attrs, &num_attrs, CKA_CLASS,
(CK_BYTE *)&class, sizeof(class));
if (rc != CKR_OK) {
TRACE_DEVEL("add_to_attribute_array failed\n");
goto done;
}
rc = add_to_attribute_array(&attrs, &num_attrs, CKA_KEY_TYPE,
(CK_BYTE *)&keytype, sizeof(keytype));
if (rc != CKR_OK) {
TRACE_DEVEL("add_to_attribute_array failed\n");
goto done;
}
/* Apply defaults for public key object, if not in the template */
for (i = 0; i < sizeof(default_attrs) /
sizeof(struct default_attr); i++) {
attr = get_attribute_by_type(pTemplate, ulCount,
default_attrs[i].attr.type);
if (attr == NULL) {
attr = (CK_ATTRIBUTE *)&default_attrs[i].attr;
if (default_attrs[i].copy_from_priv) {
if (template_attribute_find(priv_key_obj->template,
default_attrs[i].priv_attr_type,
&attr) == CK_FALSE) {
TRACE_DEVEL("Can not find %s in object\n",
p11_get_cka(
default_attrs[i].priv_attr_type));
rc = CKR_TEMPLATE_INCOMPLETE;
goto done;
}
}
rc = add_to_attribute_array(&attrs, &num_attrs,
default_attrs[i].attr.type,
attr->pValue, attr->ulValueLen);
if (rc != CKR_OK) {
TRACE_DEVEL("add_to_attribute_array failed\n");
goto done;
}
}
}
/* Get the public key attributes from SPKI into temporary template */
tmpl = calloc(1, sizeof(TEMPLATE));
if (tmpl == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
switch (keytype) {
case CKK_EC:
case CKK_EC_EDWARDS:
case CKK_EC_MONTGOMERY:
rc = ec_priv_unwrap_get_data(tmpl, spki_attr->pValue,
spki_attr->ulValueLen, CK_TRUE, keytype);
break;
case CKK_RSA:
rc = rsa_priv_unwrap_get_data(tmpl, spki_attr->pValue,
spki_attr->ulValueLen, CK_TRUE);
break;
case CKK_DSA:
rc = dsa_priv_unwrap_get_data(tmpl, spki_attr->pValue,
spki_attr->ulValueLen, CK_TRUE);
break;
case CKK_DH:
rc = dh_priv_unwrap_get_data(tmpl, spki_attr->pValue,
spki_attr->ulValueLen, CK_TRUE);
break;
case CKK_IBM_PQC_DILITHIUM:
case CKK_IBM_PQC_KYBER:
case CKK_IBM_ML_DSA:
case CKK_IBM_ML_KEM:
case CKK_ML_DSA:
case CKK_ML_KEM:
rc = pqc_priv_unwrap_get_data(tmpl, keytype, spki_attr->pValue,
spki_attr->ulValueLen, CK_TRUE);
break;
default:
rc = CKR_KEY_TYPE_INCONSISTENT;
break;
}
if (rc != 0) {
TRACE_ERROR("xxx_priv_unwrap_get_data failed (keytype 0x%lx): 0x%lx\n",
keytype, rc);
goto done;
}
/* Add public key attributes to array of attributes */
node = tmpl->attribute_list;
while (node != NULL) {
attr = (CK_ATTRIBUTE *)node->data;
rc = add_to_attribute_array(&attrs, &num_attrs, attr->type,
attr->pValue, attr->ulValueLen);
if (rc != CKR_OK) {
TRACE_DEVEL("add_to_attribute_array failed\n");
goto done;
}
node = node->next;
}
/* Create the public key object */
rc = object_mgr_add(tokdata, sess, attrs, num_attrs, pub_key_handle,
MODE_EXTRACT);
if (rc != CKR_OK) {
TRACE_DEVEL("object_mgr_add failed\n");
goto done;
}
done:
if (attrs != NULL && num_attrs > 0)
free_attribute_array(attrs, num_attrs);
if (tmpl != NULL)
template_free(tmpl);
return rc;
}
// publ_key_check_required_attributes()
//
CK_RV publ_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
// CKO_PUBLIC_KEY has no required attributes
//
return key_object_check_required_attributes(tmpl, mode);
}
// publ_key_set_default_attributes()
//
// some of the common public key attributes have defaults but none of the
// specific public keytypes have default attributes
//
CK_RV publ_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *class_attr = NULL;
CK_ATTRIBUTE *subject_attr = NULL;
CK_ATTRIBUTE *encrypt_attr = NULL;
CK_ATTRIBUTE *verify_attr = NULL;
CK_ATTRIBUTE *verify_recover_attr = NULL;
CK_ATTRIBUTE *wrap_attr = NULL;
CK_ATTRIBUTE *trusted_attr = NULL;
CK_ATTRIBUTE *pki_attr = NULL;
CK_ATTRIBUTE *wraptmpl_attr = NULL;
CK_ATTRIBUTE *encaps_attr = NULL;
CK_ATTRIBUTE *encapstmpl_attr = NULL;
CK_RV rc;
rc = key_object_set_default_attributes(tmpl, mode);
if (rc != CKR_OK) {
TRACE_DEVEL("key_object_set_default_attributes failed\n");
return rc;
}
// add the default CKO_PUBLIC_KEY attributes
//
class_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS));
subject_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
encrypt_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
verify_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
verify_recover_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
wrap_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
trusted_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
pki_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
wraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
encaps_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
encapstmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!class_attr || !subject_attr || !encrypt_attr ||
!verify_attr || !verify_recover_attr || !wrap_attr || !trusted_attr ||
!pki_attr || !wraptmpl_attr || !encaps_attr || !encapstmpl_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
class_attr->type = CKA_CLASS;
class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS);
class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE);
*(CK_OBJECT_CLASS *) class_attr->pValue = CKO_PUBLIC_KEY;
subject_attr->type = CKA_SUBJECT;
subject_attr->ulValueLen = 0; // empty string
subject_attr->pValue = NULL;
encrypt_attr->type = CKA_ENCRYPT;
encrypt_attr->ulValueLen = sizeof(CK_BBOOL);
encrypt_attr->pValue = (CK_BYTE *) encrypt_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) encrypt_attr->pValue = TRUE;
verify_attr->type = CKA_VERIFY;
verify_attr->ulValueLen = sizeof(CK_BBOOL);
verify_attr->pValue = (CK_BYTE *) verify_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) verify_attr->pValue = TRUE;
verify_recover_attr->type = CKA_VERIFY_RECOVER;
verify_recover_attr->ulValueLen = sizeof(CK_BBOOL);
verify_recover_attr->pValue =
(CK_BYTE *) verify_recover_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) verify_recover_attr->pValue = TRUE;
wrap_attr->type = CKA_WRAP;
wrap_attr->ulValueLen = sizeof(CK_BBOOL);
wrap_attr->pValue = (CK_BYTE *) wrap_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) wrap_attr->pValue = TRUE;
trusted_attr->type = CKA_TRUSTED;
trusted_attr->ulValueLen = sizeof(CK_BBOOL);
trusted_attr->pValue = (CK_BYTE *)trusted_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) trusted_attr->pValue = FALSE;
pki_attr->type = CKA_PUBLIC_KEY_INFO;
pki_attr->ulValueLen = 0; // empty string
pki_attr->pValue = NULL;
wraptmpl_attr->type = CKA_WRAP_TEMPLATE;
wraptmpl_attr->ulValueLen = 0;
wraptmpl_attr->pValue = NULL;
encaps_attr->type = CKA_ENCAPSULATE;
encaps_attr->ulValueLen = sizeof(CK_BBOOL);
encaps_attr->pValue = (CK_BYTE *)encaps_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) encaps_attr->pValue = FALSE;
encapstmpl_attr->type = CKA_ENCAPSULATE_TEMPLATE;
encapstmpl_attr->ulValueLen = 0;
encapstmpl_attr->pValue = NULL;
rc = template_update_attribute(tmpl, class_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
class_attr = NULL;
rc = template_update_attribute(tmpl, subject_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
subject_attr = NULL;
rc = template_update_attribute(tmpl, encrypt_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
encrypt_attr = NULL;
rc = template_update_attribute(tmpl, verify_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
verify_attr = NULL;
rc = template_update_attribute(tmpl, verify_recover_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
verify_recover_attr = NULL;
rc = template_update_attribute(tmpl, wrap_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
wrap_attr = NULL;
rc = template_update_attribute(tmpl, trusted_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
trusted_attr = NULL;
rc = template_update_attribute(tmpl, pki_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
pki_attr = NULL;
rc = template_update_attribute(tmpl, wraptmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
wraptmpl_attr = NULL;
rc = template_update_attribute(tmpl, encaps_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
encaps_attr = NULL;
rc = template_update_attribute(tmpl, encapstmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
encapstmpl_attr = NULL;
return CKR_OK;
error:
if (class_attr)
free(class_attr);
if (subject_attr)
free(subject_attr);
if (encrypt_attr)
free(encrypt_attr);
if (verify_attr)
free(verify_attr);
if (verify_recover_attr)
free(verify_recover_attr);
if (wrap_attr)
free(wrap_attr);
if (trusted_attr)
free(trusted_attr);
if (pki_attr)
free(pki_attr);
if (wraptmpl_attr)
free(wraptmpl_attr);
if (encaps_attr)
free(encaps_attr);
if (encapstmpl_attr)
free(encapstmpl_attr);
return rc;
}
// publ_key_validate_attribute
//
CK_RV publ_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
CK_RV rc;
switch (attr->type) {
case CKA_SUBJECT:
return CKR_OK;
case CKA_ENCRYPT:
case CKA_VERIFY:
case CKA_VERIFY_RECOVER:
case CKA_WRAP:
case CKA_ENCAPSULATE:
if (mode == MODE_MODIFY) {
if (tokdata->nv_token_data->tweak_vector.allow_key_mods == TRUE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
case CKA_TRUSTED:
/* Can only be set to CK_TRUE by the SO user */
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (*((CK_BBOOL *)attr->pValue) == CK_TRUE &&
!session_mgr_so_session_exists(tokdata)) {
TRACE_ERROR("CKA_TRUSTED can only be set to TRUE by SO\n");
return CKR_USER_NOT_LOGGED_IN;
}
return CKR_OK;
case CKA_PUBLIC_KEY_INFO:
if (mode == MODE_CREATE || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS ||
mode == MODE_EXTRACT)
return CKR_OK;
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_WRAP_TEMPLATE:
case CKA_ENCAPSULATE_TEMPLATE:
if ((attr->ulValueLen > 0 && attr->pValue == NULL) ||
attr->ulValueLen % sizeof(CK_ATTRIBUTE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
rc = validate_attribute_array((CK_ATTRIBUTE_PTR)attr->pValue,
attr->ulValueLen / sizeof(CK_ATTRIBUTE));
if (rc != CKR_OK) {
TRACE_ERROR("validate_attribute_array rc=0x%lx\n", rc);
return rc;
}
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_DERIVE || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS ||
mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return key_object_validate_attribute(tmpl, attr, mode);
}
TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type);
return CKR_ATTRIBUTE_TYPE_INVALID;
}
/*
* Extract the SubjectPublicKeyInfo from the public key
*/
CK_RV publ_key_get_spki(TEMPLATE *tmpl, CK_ULONG keytype, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_BBOOL is_priv_tmpl)
{
CK_RV rc;
switch (keytype) {
case CKK_RSA:
rc = rsa_publ_get_spki(tmpl, length_only, data, data_len);
break;
case CKK_DSA:
rc = dsa_publ_get_spki(tmpl, length_only, data, data_len);
break;
case CKK_DH:
rc = dh_publ_get_spki(tmpl, length_only, data, data_len);
break;
case CKK_EC:
case CKK_EC_EDWARDS:
case CKK_EC_MONTGOMERY:
rc = ec_publ_get_spki(tmpl, length_only, data, data_len, keytype);
break;
case CKK_IBM_PQC_DILITHIUM:
rc = ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_DILITHIUM);
break;
case CKK_IBM_PQC_KYBER:
rc = ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_KYBER);
break;
case CKK_IBM_ML_DSA:
rc = ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_ML_DSA);
break;
case CKK_IBM_ML_KEM:
rc = ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_ML_KEM);
break;
case CKK_ML_DSA:
rc = ml_dsa_publ_get_spki(tmpl, length_only, data, data_len,
is_priv_tmpl);
break;
case CKK_ML_KEM:
rc = ml_kem_publ_get_spki(tmpl, length_only, data, data_len,
is_priv_tmpl);
break;
default:
TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT));
return CKR_KEY_TYPE_INCONSISTENT;
}
return rc;
}
// priv_key_check_required_attributes()
//
CK_RV priv_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
// CKO_PRIVATE_KEY has no required attributes
//
return key_object_check_required_attributes(tmpl, mode);
}
// priv_key_set_default_attributes()
//
// some of the common private key attributes have defaults but none of the
// specific private keytypes have default attributes
//
CK_RV priv_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *class_attr = NULL;
CK_ATTRIBUTE *subject_attr = NULL;
CK_ATTRIBUTE *sensitive_attr = NULL;
CK_ATTRIBUTE *decrypt_attr = NULL;
CK_ATTRIBUTE *sign_attr = NULL;
CK_ATTRIBUTE *sign_recover_attr = NULL;
CK_ATTRIBUTE *unwrap_attr = NULL;
CK_ATTRIBUTE *extractable_attr = NULL;
CK_ATTRIBUTE *never_extr_attr = NULL;
CK_ATTRIBUTE *always_sens_attr = NULL;
CK_ATTRIBUTE *always_auth_attr = NULL;
CK_ATTRIBUTE *wrap_trusted_attr = NULL;
CK_ATTRIBUTE *pki_attr = NULL;
CK_ATTRIBUTE *unwraptmpl_attr = NULL;
CK_ATTRIBUTE *derivetmpl_attr = NULL;
CK_ATTRIBUTE *decaps_attr = NULL;
CK_ATTRIBUTE *decapstmpl_attr = NULL;
CK_RV rc;
rc = key_object_set_default_attributes(tmpl, mode);
if (rc != CKR_OK) {
TRACE_DEVEL("key_object_set_default_attributes failed\n");
return rc;
}
// add the default CKO_PUBLIC_KEY attributes
//
class_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS));
subject_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
sensitive_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
decrypt_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
sign_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
sign_recover_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
unwrap_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
extractable_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
never_extr_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
always_sens_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
always_auth_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
wrap_trusted_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
pki_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
unwraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
derivetmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
decaps_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
decapstmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!class_attr || !subject_attr || !sensitive_attr || !decrypt_attr ||
!sign_attr || !sign_recover_attr || !unwrap_attr || !extractable_attr ||
!never_extr_attr || !always_sens_attr || !always_auth_attr ||
!wrap_trusted_attr || !pki_attr || !unwraptmpl_attr ||
!derivetmpl_attr || !decaps_attr || !decapstmpl_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
class_attr->type = CKA_CLASS;
class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS);
class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE);
*(CK_OBJECT_CLASS *) class_attr->pValue = CKO_PRIVATE_KEY;
subject_attr->type = CKA_SUBJECT;
subject_attr->ulValueLen = 0; // empty string
subject_attr->pValue = NULL;
sensitive_attr->type = CKA_SENSITIVE;
sensitive_attr->ulValueLen = sizeof(CK_BBOOL);
sensitive_attr->pValue = (CK_BYTE *) sensitive_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) sensitive_attr->pValue = FALSE;
decrypt_attr->type = CKA_DECRYPT;
decrypt_attr->ulValueLen = sizeof(CK_BBOOL);
decrypt_attr->pValue = (CK_BYTE *) decrypt_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) decrypt_attr->pValue = TRUE;
sign_attr->type = CKA_SIGN;
sign_attr->ulValueLen = sizeof(CK_BBOOL);
sign_attr->pValue = (CK_BYTE *) sign_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) sign_attr->pValue = TRUE;
sign_recover_attr->type = CKA_SIGN_RECOVER;
sign_recover_attr->ulValueLen = sizeof(CK_BBOOL);
sign_recover_attr->pValue =
(CK_BYTE *) sign_recover_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) sign_recover_attr->pValue = TRUE;
unwrap_attr->type = CKA_UNWRAP;
unwrap_attr->ulValueLen = sizeof(CK_BBOOL);
unwrap_attr->pValue = (CK_BYTE *) unwrap_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) unwrap_attr->pValue = TRUE;
extractable_attr->type = CKA_EXTRACTABLE;
extractable_attr->ulValueLen = sizeof(CK_BBOOL);
extractable_attr->pValue =
(CK_BYTE *) extractable_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) extractable_attr->pValue = TRUE;
// by default, we'll set NEVER_EXTRACTABLE == FALSE and
// ALWAYS_SENSITIVE == FALSE
// If the key is being created with KEYGEN, it will adjust as necessary.
//
never_extr_attr->type = CKA_NEVER_EXTRACTABLE;
never_extr_attr->ulValueLen = sizeof(CK_BBOOL);
never_extr_attr->pValue =
(CK_BYTE *) never_extr_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) never_extr_attr->pValue = FALSE;
always_sens_attr->type = CKA_ALWAYS_SENSITIVE;
always_sens_attr->ulValueLen = sizeof(CK_BBOOL);
always_sens_attr->pValue =
(CK_BYTE *) always_sens_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) always_sens_attr->pValue = FALSE;
always_auth_attr->type = CKA_ALWAYS_AUTHENTICATE;
always_auth_attr->ulValueLen = sizeof(CK_BBOOL);
always_auth_attr->pValue =
(CK_BYTE *) always_auth_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) always_auth_attr->pValue = FALSE;
wrap_trusted_attr->type = CKA_WRAP_WITH_TRUSTED;
wrap_trusted_attr->ulValueLen = sizeof(CK_BBOOL);
wrap_trusted_attr->pValue =
(CK_BYTE *) wrap_trusted_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) wrap_trusted_attr->pValue = FALSE;
pki_attr->type = CKA_SUBJECT;
pki_attr->ulValueLen = 0; // empty string
pki_attr->pValue = NULL;
unwraptmpl_attr->type = CKA_UNWRAP_TEMPLATE;
unwraptmpl_attr->ulValueLen = 0;
unwraptmpl_attr->pValue = NULL;
derivetmpl_attr->type = CKA_DERIVE_TEMPLATE;
derivetmpl_attr->ulValueLen = 0;
derivetmpl_attr->pValue = NULL;
decaps_attr->type = CKA_DECAPSULATE;
decaps_attr->ulValueLen = sizeof(CK_BBOOL);
decaps_attr->pValue =
(CK_BYTE *) decaps_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) decaps_attr->pValue = FALSE;
decapstmpl_attr->type = CKA_DECAPSULATE_TEMPLATE;
decapstmpl_attr->ulValueLen = 0;
decapstmpl_attr->pValue = NULL;
rc = template_update_attribute(tmpl, class_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
class_attr = NULL;
rc = template_update_attribute(tmpl, subject_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
subject_attr = NULL;
rc = template_update_attribute(tmpl, sensitive_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
sensitive_attr = NULL;
rc = template_update_attribute(tmpl, decrypt_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
decrypt_attr = NULL;
rc = template_update_attribute(tmpl, sign_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
sign_attr = NULL;
rc = template_update_attribute(tmpl, sign_recover_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
sign_recover_attr = NULL;
rc = template_update_attribute(tmpl, unwrap_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
unwrap_attr = NULL;
rc = template_update_attribute(tmpl, extractable_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
extractable_attr = NULL;
rc = template_update_attribute(tmpl, never_extr_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
never_extr_attr = NULL;
rc = template_update_attribute(tmpl, always_sens_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
always_sens_attr = NULL;
rc = template_update_attribute(tmpl, always_auth_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
always_auth_attr = NULL;
rc = template_update_attribute(tmpl, wrap_trusted_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
wrap_trusted_attr = NULL;
rc = template_update_attribute(tmpl, pki_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
pki_attr = NULL;
rc = template_update_attribute(tmpl, unwraptmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
unwraptmpl_attr = NULL;
rc = template_update_attribute(tmpl, derivetmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
derivetmpl_attr = NULL;
rc = template_update_attribute(tmpl, decaps_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
decaps_attr = NULL;
rc = template_update_attribute(tmpl, decapstmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
decapstmpl_attr = NULL;
return CKR_OK;
error:
if (class_attr)
free(class_attr);
if (subject_attr)
free(subject_attr);
if (sensitive_attr)
free(sensitive_attr);
if (decrypt_attr)
free(decrypt_attr);
if (sign_attr)
free(sign_attr);
if (sign_recover_attr)
free(sign_recover_attr);
if (unwrap_attr)
free(unwrap_attr);
if (extractable_attr)
free(extractable_attr);
if (always_sens_attr)
free(always_sens_attr);
if (never_extr_attr)
free(never_extr_attr);
if (always_auth_attr)
free(always_auth_attr);
if (wrap_trusted_attr)
free(wrap_trusted_attr);
if (pki_attr)
free(pki_attr);
if (unwraptmpl_attr)
free(unwraptmpl_attr);
if (derivetmpl_attr)
free(derivetmpl_attr);
if (decaps_attr)
free(decaps_attr);
if (decapstmpl_attr)
free(decapstmpl_attr);
return rc;
}
//
//
CK_RV priv_key_unwrap(TEMPLATE *tmpl,
CK_ULONG keytype,
CK_BYTE *data, CK_ULONG data_len)
{
CK_ATTRIBUTE *always_sens = NULL;
CK_ATTRIBUTE *never_extract = NULL;
CK_ATTRIBUTE *local = NULL;
CK_ATTRIBUTE *pub_key_info = NULL;
CK_BBOOL false = FALSE;
CK_BYTE *spki = NULL;
CK_ULONG spki_length = 0;
CK_RV rc;
switch (keytype) {
case CKK_RSA:
rc = rsa_priv_unwrap(tmpl, data, data_len);
break;
case CKK_DSA:
rc = dsa_priv_unwrap(tmpl, data, data_len);
break;
case CKK_DH:
rc = dh_priv_unwrap(tmpl, data, data_len);
break;
case CKK_EC:
case CKK_EC_EDWARDS:
case CKK_EC_MONTGOMERY:
rc = ec_priv_unwrap(tmpl, data, data_len, keytype);
break;
case CKK_IBM_PQC_DILITHIUM:
rc = ibm_ml_dsa_priv_unwrap(tmpl, data, data_len, TRUE,
CKM_IBM_DILITHIUM);
break;
case CKK_IBM_PQC_KYBER:
rc = ibm_ml_kem_priv_unwrap(tmpl, data, data_len, TRUE, CKM_IBM_KYBER);
break;
case CKK_IBM_ML_DSA:
rc = ibm_ml_dsa_priv_unwrap(tmpl, data, data_len, TRUE, CKM_IBM_ML_DSA);
break;
case CKK_IBM_ML_KEM:
rc = ibm_ml_kem_priv_unwrap(tmpl, data, data_len, TRUE, CKM_IBM_ML_KEM);
break;
case CKK_ML_DSA:
rc = ml_dsa_priv_unwrap(tmpl, data, data_len, TRUE);
break;
case CKK_ML_KEM:
rc = ml_kem_priv_unwrap(tmpl, data, data_len, TRUE);
break;
default:
TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID));
return CKR_WRAPPED_KEY_INVALID;
}
if (rc != CKR_OK) {
TRACE_DEVEL("priv unwrap failed\n");
return rc;
}
// make sure
// CKA_LOCAL == FALSE
// CKA_ALWAYS_SENSITIVE == FALSE
// CKA_NEVER_EXTRACTABLE == FALSE
//
// CKA_SENSITIVE and CKA_EXTRACTABLE are left as the object was created:
// the values from the unwrap template or, when it does not specify them,
// the defaults (CKA_SENSITIVE == FALSE, CKA_EXTRACTABLE == TRUE, unless
// the token's t_set_attrs_for_new_object supplies its own). Overwriting
// them here would silently discard a template that asks for a sensitive
// or non-extractable key.
//
rc = build_attribute(CKA_LOCAL, &false, 1, &local);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto cleanup;
}
rc = build_attribute(CKA_ALWAYS_SENSITIVE, &false, 1, &always_sens);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto cleanup;
}
rc = build_attribute(CKA_NEVER_EXTRACTABLE, &false, 1, &never_extract);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto cleanup;
}
/*
* Try to extract the SPKI and add CKA_PUBLIC_KEY_INFO to the key.
* This may fail if the public key info can not be reconstructed from
* the private key (e.g. because its a secure key token).
*/
rc = publ_key_get_spki(tmpl, keytype, FALSE, &spki, &spki_length, TRUE);
if (rc == CKR_OK && spki != NULL && spki_length > 0) {
rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length,
&pub_key_info);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto cleanup;
}
rc = template_update_attribute(tmpl, pub_key_info);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto cleanup;
}
pub_key_info = NULL;
}
rc = template_update_attribute(tmpl, local);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto cleanup;
}
local = NULL;
rc = template_update_attribute(tmpl, always_sens);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto cleanup;
}
always_sens = NULL;
rc = template_update_attribute(tmpl, never_extract);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto cleanup;
}
never_extract = NULL;
if (spki != NULL)
free(spki);
return CKR_OK;
cleanup:
if (local)
free(local);
if (always_sens)
free(always_sens);
if (never_extract)
free(never_extract);
if (pub_key_info)
free(pub_key_info);
if (spki != NULL)
free(spki);
return rc;
}
// priv_key_validate_attribute()
//
CK_RV priv_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
CK_RV rc;
switch (attr->type) {
case CKA_SUBJECT:
return CKR_OK;
case CKA_DECRYPT:
case CKA_SIGN:
case CKA_SIGN_RECOVER:
case CKA_UNWRAP:
case CKA_DECAPSULATE:
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
// we might want to do this for MODE_COPY too
//
if (mode == MODE_MODIFY) {
if (tokdata->nv_token_data->tweak_vector.allow_key_mods == TRUE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
return CKR_OK;
/*
* After key creation, CKA_SENSITIVE and CKA_WRAP_WITH_TRUSTED may only
* be set to TRUE
*/
case CKA_SENSITIVE:
case CKA_WRAP_WITH_TRUSTED:
{
CK_BBOOL value;
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_UNWRAP || mode == MODE_ENCAPS ||
mode == MODE_DECAPS)
return CKR_OK;
value = *(CK_BBOOL *) attr->pValue;
if (value != TRUE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
return CKR_OK;
}
// after key creation, CKA_EXTRACTABLE may only be set to FALSE
//
case CKA_EXTRACTABLE:
{
CK_BBOOL value;
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
value = *(CK_BBOOL *) attr->pValue;
if ((mode != MODE_CREATE && mode != MODE_KEYGEN &&
mode != MODE_UNWRAP && mode != MODE_ENCAPS) &&
value != FALSE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
if (value == TRUE) {
CK_ATTRIBUTE *attr;
attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) +
sizeof(CK_BBOOL));
if (!attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
attr->type = CKA_NEVER_EXTRACTABLE;
attr->ulValueLen = sizeof(CK_BBOOL);
attr->pValue = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) attr->pValue = FALSE;
rc = template_update_attribute(tmpl, attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
free(attr);
return rc;
}
}
return CKR_OK;
}
case CKA_ALWAYS_SENSITIVE:
case CKA_NEVER_EXTRACTABLE:
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_PUBLIC_KEY_INFO:
/*
* PKCS#11: A token MAY choose not to support the CKA_PUBLIC_KEY_INFO
* attribute for commands which create new private keys. If it does not
* support the attribute, the command SHALL return
* CKR_ATTRIBUTE_TYPE_INVALID.
*/
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID));
return CKR_ATTRIBUTE_TYPE_INVALID;
case CKA_UNWRAP_TEMPLATE:
case CKA_DERIVE_TEMPLATE:
case CKA_DECAPSULATE_TEMPLATE:
if ((attr->ulValueLen > 0 && attr->pValue == NULL) ||
attr->ulValueLen % sizeof(CK_ATTRIBUTE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
rc = validate_attribute_array((CK_ATTRIBUTE_PTR)attr->pValue,
attr->ulValueLen / sizeof(CK_ATTRIBUTE));
if (rc != CKR_OK) {
TRACE_ERROR("validate_attribute_array rc=0x%lx\n", rc);
return rc;
}
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_DERIVE || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_ALWAYS_AUTHENTICATE:
{
CK_BBOOL value = FALSE;
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_MODIFY || mode == MODE_COPY) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
/*
* CKA_ALWAYS_AUTHENTICATE can only be set to TRUE if CKA_PRIVATE
* is also true. If CKA_PRIVATE is not in the template, we assume
* the default value of CKA_PRIVATE (FALSE).
*/
if (*(CK_BBOOL *)attr->pValue == FALSE)
return CKR_OK;
if (template_attribute_get_bool(tmpl, CKA_PRIVATE,
&value) != CKR_OK ||
value == FALSE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
default:
return key_object_validate_attribute(tmpl, attr, mode);
}
TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type);
return CKR_ATTRIBUTE_TYPE_INVALID;
}
// secret_key_check_required_attributes()
//
CK_RV secret_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
return key_object_check_required_attributes(tmpl, mode);
}
// secret_key_set_default_attributes()
//
// some of the common secret key attributes have defaults but none of the
// specific secret keytypes have default attributes
//
CK_RV secret_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *class_attr = NULL;
CK_ATTRIBUTE *sensitive_attr = NULL;
CK_ATTRIBUTE *encrypt_attr = NULL;
CK_ATTRIBUTE *decrypt_attr = NULL;
CK_ATTRIBUTE *sign_attr = NULL;
CK_ATTRIBUTE *verify_attr = NULL;
CK_ATTRIBUTE *wrap_attr = NULL;
CK_ATTRIBUTE *unwrap_attr = NULL;
CK_ATTRIBUTE *extractable_attr = NULL;
CK_ATTRIBUTE *never_extr_attr = NULL;
CK_ATTRIBUTE *always_sens_attr = NULL;
CK_ATTRIBUTE *trusted_attr = NULL;
CK_ATTRIBUTE *wrap_trusted_attr = NULL;
CK_ATTRIBUTE *chkval_attr = NULL;
CK_ATTRIBUTE *wraptmpl_attr = NULL;
CK_ATTRIBUTE *unwraptmpl_attr = NULL;
CK_ATTRIBUTE *derivetmpl_attr = NULL;
CK_RV rc;
rc = key_object_set_default_attributes(tmpl, mode);
if (rc != CKR_OK)
return rc;
// add the default CKO_DATA attributes
//
class_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS));
sensitive_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
encrypt_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
decrypt_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
sign_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
verify_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
wrap_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
unwrap_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
extractable_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
never_extr_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
always_sens_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
trusted_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
wrap_trusted_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
chkval_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
wraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
unwraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
derivetmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!class_attr || !sensitive_attr || !encrypt_attr || !decrypt_attr ||
!sign_attr || !verify_attr || !wrap_attr ||
!unwrap_attr || !extractable_attr || !never_extr_attr
|| !always_sens_attr || !trusted_attr || !wrap_trusted_attr ||
!chkval_attr || !wraptmpl_attr || !unwraptmpl_attr ||
!derivetmpl_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
class_attr->type = CKA_CLASS;
class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS);
class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE);
*(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY;
sensitive_attr->type = CKA_SENSITIVE;
sensitive_attr->ulValueLen = sizeof(CK_BBOOL);
sensitive_attr->pValue = (CK_BYTE *) sensitive_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) sensitive_attr->pValue = FALSE;
encrypt_attr->type = CKA_ENCRYPT;
encrypt_attr->ulValueLen = sizeof(CK_BBOOL);
encrypt_attr->pValue = (CK_BYTE *) encrypt_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) encrypt_attr->pValue = TRUE;
decrypt_attr->type = CKA_DECRYPT;
decrypt_attr->ulValueLen = sizeof(CK_BBOOL);
decrypt_attr->pValue = (CK_BYTE *) decrypt_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) decrypt_attr->pValue = TRUE;
sign_attr->type = CKA_SIGN;
sign_attr->ulValueLen = sizeof(CK_BBOOL);
sign_attr->pValue = (CK_BYTE *) sign_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) sign_attr->pValue = TRUE;
verify_attr->type = CKA_VERIFY;
verify_attr->ulValueLen = sizeof(CK_BBOOL);
verify_attr->pValue = (CK_BYTE *) verify_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) verify_attr->pValue = TRUE;
wrap_attr->type = CKA_WRAP;
wrap_attr->ulValueLen = sizeof(CK_BBOOL);
wrap_attr->pValue = (CK_BYTE *) wrap_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) wrap_attr->pValue = TRUE;
unwrap_attr->type = CKA_UNWRAP;
unwrap_attr->ulValueLen = sizeof(CK_BBOOL);
unwrap_attr->pValue = (CK_BYTE *) unwrap_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) unwrap_attr->pValue = TRUE;
extractable_attr->type = CKA_EXTRACTABLE;
extractable_attr->ulValueLen = sizeof(CK_BBOOL);
extractable_attr->pValue =
(CK_BYTE *) extractable_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) extractable_attr->pValue = TRUE;
// by default, we'll set NEVER_EXTRACTABLE == FALSE and
// ALWAYS_SENSITIVE == FALSE
// If the key is being created with KEYGEN, it will adjust as necessary.
//
always_sens_attr->type = CKA_ALWAYS_SENSITIVE;
always_sens_attr->ulValueLen = sizeof(CK_BBOOL);
always_sens_attr->pValue =
(CK_BYTE *) always_sens_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) always_sens_attr->pValue = FALSE;
never_extr_attr->type = CKA_NEVER_EXTRACTABLE;
never_extr_attr->ulValueLen = sizeof(CK_BBOOL);
never_extr_attr->pValue =
(CK_BYTE *) never_extr_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) never_extr_attr->pValue = FALSE;
trusted_attr->type = CKA_TRUSTED;
trusted_attr->ulValueLen = sizeof(CK_BBOOL);
trusted_attr->pValue = (CK_BYTE *)trusted_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) trusted_attr->pValue = FALSE;
wrap_trusted_attr->type = CKA_WRAP_WITH_TRUSTED;
wrap_trusted_attr->ulValueLen = sizeof(CK_BBOOL);
wrap_trusted_attr->pValue =
(CK_BYTE *) wrap_trusted_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) wrap_trusted_attr->pValue = FALSE;
chkval_attr->type = CKA_CHECK_VALUE;
chkval_attr->ulValueLen = 0;
chkval_attr->pValue = NULL;
wraptmpl_attr->type = CKA_WRAP_TEMPLATE;
wraptmpl_attr->ulValueLen = 0;
wraptmpl_attr->pValue = NULL;
unwraptmpl_attr->type = CKA_UNWRAP_TEMPLATE;
unwraptmpl_attr->ulValueLen = 0;
unwraptmpl_attr->pValue = NULL;
derivetmpl_attr->type = CKA_DERIVE_TEMPLATE;
derivetmpl_attr->ulValueLen = 0;
derivetmpl_attr->pValue = NULL;
rc = template_update_attribute(tmpl, class_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
class_attr = NULL;
rc = template_update_attribute(tmpl, sensitive_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
sensitive_attr = NULL;
rc = template_update_attribute(tmpl, encrypt_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
encrypt_attr = NULL;
rc = template_update_attribute(tmpl, decrypt_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
decrypt_attr = NULL;
rc = template_update_attribute(tmpl, sign_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
sign_attr = NULL;
rc = template_update_attribute(tmpl, verify_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
verify_attr = NULL;
rc = template_update_attribute(tmpl, wrap_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
wrap_attr = NULL;
rc = template_update_attribute(tmpl, unwrap_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
unwrap_attr = NULL;
rc = template_update_attribute(tmpl, extractable_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
extractable_attr = NULL;
rc = template_update_attribute(tmpl, never_extr_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
never_extr_attr = NULL;
rc = template_update_attribute(tmpl, always_sens_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
always_sens_attr = NULL;
rc = template_update_attribute(tmpl, trusted_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
trusted_attr = NULL;
rc = template_update_attribute(tmpl, wrap_trusted_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
wrap_trusted_attr = NULL;
rc = template_update_attribute(tmpl, chkval_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
chkval_attr = NULL;
rc = template_update_attribute(tmpl, wraptmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
wraptmpl_attr = NULL;
rc = template_update_attribute(tmpl, unwraptmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
unwraptmpl_attr = NULL;
rc = template_update_attribute(tmpl, derivetmpl_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
derivetmpl_attr = NULL;
return CKR_OK;
error:
if (class_attr)
free(class_attr);
if (sensitive_attr)
free(sensitive_attr);
if (encrypt_attr)
free(encrypt_attr);
if (decrypt_attr)
free(decrypt_attr);
if (sign_attr)
free(sign_attr);
if (verify_attr)
free(verify_attr);
if (wrap_attr)
free(wrap_attr);
if (unwrap_attr)
free(unwrap_attr);
if (extractable_attr)
free(extractable_attr);
if (never_extr_attr)
free(never_extr_attr);
if (always_sens_attr)
free(always_sens_attr);
if (trusted_attr)
free(trusted_attr);
if (wrap_trusted_attr)
free(wrap_trusted_attr);
if (chkval_attr)
free(chkval_attr);
if (wraptmpl_attr)
free(wraptmpl_attr);
if (unwraptmpl_attr)
free(unwraptmpl_attr);
if (derivetmpl_attr)
free(derivetmpl_attr);
return rc;
}
//
//
CK_RV secret_key_unwrap(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl,
CK_ULONG keytype,
CK_BYTE *data,
CK_ULONG data_len, CK_BBOOL fromend)
{
CK_ATTRIBUTE *local = NULL;
CK_ATTRIBUTE *always_sens = NULL;
CK_ATTRIBUTE *never_extract = NULL;
CK_BBOOL false = FALSE;
CK_RV rc;
switch (keytype) {
case CKK_DES:
rc = des_unwrap(tokdata, tmpl, data, data_len, fromend);
break;
case CKK_DES3:
rc = des3_unwrap(tokdata, tmpl, data, data_len, fromend);
break;
case CKK_AES:
case CKK_AES_XTS:
rc = aes_unwrap(tokdata, tmpl, data, data_len, fromend,
keytype == CKK_AES_XTS);
break;
case CKK_GENERIC_SECRET:
case CKK_SHA_1_HMAC:
case CKK_SHA224_HMAC:
case CKK_SHA256_HMAC:
case CKK_SHA384_HMAC:
case CKK_SHA512_HMAC:
case CKK_SHA3_224_HMAC:
case CKK_SHA3_256_HMAC:
case CKK_SHA3_384_HMAC:
case CKK_SHA3_512_HMAC:
case CKK_SHA512_224_HMAC:
case CKK_SHA512_256_HMAC:
rc = generic_secret_unwrap(tmpl, data, data_len, fromend);
break;
default:
TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID));
return CKR_WRAPPED_KEY_INVALID;
}
if (rc != CKR_OK)
return rc;
// make sure
// CKA_LOCAL == FALSE
// CKA_ALWAYS_SENSITIVE == FALSE
// CKA_NEVER_EXTRACTABLE == FALSE
//
// CKA_SENSITIVE and CKA_EXTRACTABLE are left as the object was created:
// the values from the unwrap template or, when it does not specify them,
// the defaults (CKA_SENSITIVE == FALSE, CKA_EXTRACTABLE == TRUE, unless
// the token's t_set_attrs_for_new_object supplies its own). Overwriting
// them here would silently discard a template that asks for a sensitive
// or non-extractable key.
//
rc = build_attribute(CKA_LOCAL, &false, 1, &local);
if (rc != CKR_OK) {
TRACE_DEVEL("build attribute failed\n");
goto cleanup;
}
rc = build_attribute(CKA_ALWAYS_SENSITIVE, &false, 1, &always_sens);
if (rc != CKR_OK) {
TRACE_DEVEL("build attribute failed\n");
goto cleanup;
}
rc = build_attribute(CKA_NEVER_EXTRACTABLE, &false, 1, &never_extract);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto cleanup;
}
rc = template_update_attribute(tmpl, local);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto cleanup;
}
local = NULL;
rc = template_update_attribute(tmpl, always_sens);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto cleanup;
}
always_sens = NULL;
rc = template_update_attribute(tmpl, never_extract);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto cleanup;
}
never_extract = NULL;
return CKR_OK;
cleanup:
if (local)
free(local);
if (always_sens)
free(always_sens);
if (never_extract)
free(never_extract);
return rc;
}
// secret_key_validate_attribute()
//
CK_RV secret_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
CK_RV rc;
switch (attr->type) {
case CKA_ENCRYPT:
case CKA_DECRYPT:
case CKA_SIGN:
case CKA_VERIFY:
case CKA_WRAP:
case CKA_UNWRAP:
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_MODIFY) {
if (tokdata->nv_token_data->tweak_vector.allow_key_mods == TRUE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
return CKR_OK;
case CKA_TRUSTED:
/* Can only be set to CK_TRUE by the SO user */
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (*((CK_BBOOL *)attr->pValue) == CK_TRUE &&
!session_mgr_so_session_exists(tokdata)) {
TRACE_ERROR("CKA_TRUSTED can only be set to TRUE by SO\n");
return CKR_USER_NOT_LOGGED_IN;
}
return CKR_OK;
/*
* After key creation, CKA_SENSITIVE and CKA_WRAP_WITH_TRUSTED may only
* be set to TRUE
*/
case CKA_SENSITIVE:
case CKA_WRAP_WITH_TRUSTED:
{
CK_BBOOL value;
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
value = *(CK_BBOOL *) attr->pValue;
if ((mode != MODE_CREATE && mode != MODE_DERIVE &&
mode != MODE_KEYGEN && mode != MODE_UNWRAP &&
mode != MODE_ENCAPS && mode != MODE_DECAPS) &&
(value != TRUE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
return CKR_OK;
}
// after key creation, CKA_EXTRACTABLE may only be set to FALSE
//
case CKA_EXTRACTABLE:
{
CK_BBOOL value;
// the unwrap routine will automatically set extractable to TRUE
//
if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
value = *(CK_BBOOL *) attr->pValue;
if ((mode != MODE_CREATE && mode != MODE_DERIVE &&
mode != MODE_KEYGEN && mode != MODE_UNWRAP &&
mode != MODE_ENCAPS && mode != MODE_DECAPS) &&
(value != FALSE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
if (value == TRUE) {
CK_ATTRIBUTE *attr;
attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) +
sizeof(CK_BBOOL));
if (!attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
attr->type = CKA_NEVER_EXTRACTABLE;
attr->ulValueLen = sizeof(CK_BBOOL);
attr->pValue = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) attr->pValue = FALSE;
rc = template_update_attribute(tmpl, attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
free(attr);
return rc;
}
}
return CKR_OK;
}
case CKA_ALWAYS_SENSITIVE:
case CKA_NEVER_EXTRACTABLE:
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_CHECK_VALUE:
if (mode != MODE_CREATE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
return CKR_OK;
case CKA_WRAP_TEMPLATE:
case CKA_UNWRAP_TEMPLATE:
case CKA_DERIVE_TEMPLATE:
if ((attr->ulValueLen > 0 && attr->pValue == NULL) ||
attr->ulValueLen % sizeof(CK_ATTRIBUTE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
rc = validate_attribute_array((CK_ATTRIBUTE_PTR)attr->pValue,
attr->ulValueLen / sizeof(CK_ATTRIBUTE));
if (rc != CKR_OK) {
TRACE_ERROR("validate_attribute_array rc=0x%lx\n", rc);
return rc;
}
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_DERIVE || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return key_object_validate_attribute(tmpl, attr, mode);
}
TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type);
return CKR_ATTRIBUTE_TYPE_INVALID;
}
// secret_key_check_exportability()
//
CK_BBOOL secret_key_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
TRACE_ERROR("%s\n", ock_err(ERR_KEY_UNEXTRACTABLE));
return FALSE;
}
return TRUE;
}
// rsa_publ_check_required_attributes()
//
CK_RV rsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_ULONG val;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for public key templates.
*/
return publ_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_MODULUS\n");
return rc;
}
}
rc = template_attribute_get_ulong(tmpl, CKA_MODULUS_BITS, &val);
if (rc != CKR_OK) {
if (mode == MODE_KEYGEN || mode == MODE_ENCAPS) {
TRACE_ERROR("Could not find CKA_MODULUS_BITS\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT\n");
return rc;
}
}
return publ_key_check_required_attributes(tmpl, mode);
}
// rsa_publ_set_default_attributes()
//
CK_RV rsa_publ_set_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl,
CK_ULONG mode)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *modulus_attr = NULL;
CK_ATTRIBUTE *modulus_bits_attr = NULL;
CK_ATTRIBUTE *public_exp_attr = NULL;
CK_ATTRIBUTE *tmpattr = NULL;
CK_ULONG bits = 0L;
CK_BYTE pubExp[3] = { 0x01, 0x00, 0x01 };
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
modulus_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
modulus_bits_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG));
public_exp_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(pubExp));
if (!type_attr || !modulus_attr || !modulus_bits_attr || !public_exp_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_RSA;
modulus_attr->type = CKA_MODULUS;
modulus_attr->ulValueLen = 0;
modulus_attr->pValue = NULL;
modulus_bits_attr->type = CKA_MODULUS_BITS;
modulus_bits_attr->ulValueLen = sizeof(CK_ULONG);
modulus_bits_attr->pValue =
(CK_BYTE *) modulus_bits_attr + sizeof(CK_ATTRIBUTE);
if (template_attribute_find(basetmpl, CKA_MODULUS, &tmpattr)) {
*(CK_ULONG *) modulus_bits_attr->pValue = 8 * tmpattr->ulValueLen;
} else {
*(CK_ULONG *) modulus_bits_attr->pValue = bits;
}
public_exp_attr->type = CKA_PUBLIC_EXPONENT;
public_exp_attr->ulValueLen = sizeof(pubExp);
public_exp_attr->pValue =
(CK_BYTE *) public_exp_attr + sizeof(CK_ATTRIBUTE);
memcpy(public_exp_attr->pValue, pubExp, sizeof(pubExp));
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, modulus_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
modulus_attr = NULL;
rc = template_update_attribute(tmpl, modulus_bits_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
modulus_bits_attr = NULL;
rc = template_update_attribute(tmpl, public_exp_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
public_exp_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (modulus_attr)
free(modulus_attr);
if (modulus_bits_attr)
free(modulus_bits_attr);
if (public_exp_attr)
free(public_exp_attr);
return rc;
}
// rsa_publ_validate_attributes()
//
CK_RV rsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
switch (attr->type) {
case CKA_MODULUS_BITS:
if (mode == MODE_KEYGEN || mode == MODE_ENCAPS ||
mode == MODE_EXTRACT) {
if (attr->ulValueLen != sizeof(CK_ULONG) ||
attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
} else {
CK_ULONG mod_bits = *(CK_ULONG *) attr->pValue;
if (mod_bits < 512 || mod_bits > OPENSSL_RSA_MAX_MODULUS_BITS) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mod_bits % 8 != 0) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_MODULUS:
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_PUBLIC_EXPONENT:
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
/*
* Extract the SubjectPublicKeyInfo from the RSA public key
*/
CK_RV rsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *modulus = NULL;
CK_ATTRIBUTE *publ_exp = NULL;
CK_RV rc;
rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &modulus);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_MODULUS for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &publ_exp);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT for the key.\n");
return rc;
}
rc = ber_encode_RSAPublicKey(length_only, data,data_len, modulus, publ_exp);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_RSAPublicKey failed.\n");
return rc;
}
return CKR_OK;
}
// rsa_priv_check_required_attributes()
//
CK_RV rsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL, *coef = NULL;
CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL, *exp1 = NULL, *exp2 = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for private key templates.
*/
return priv_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_MODULUS\n");
return rc;
}
}
/*
* PKCS#11 is flexible with respect to which attributes must be present
* in an RSA key. Keys can be specified in Chinese-Remainder format or
* they can be specified in modular-exponent format. Effective with version
* 2.40, tokens MUST store CKA_PUBLIC_EXPONENT in any case. This permits the
* retrieval of sufficient data to reconstitute the associated public key.
*/
rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_PRIVATE_EXPONENT, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_PRIVATE_EXPONENT\n");
return rc;
}
}
/* The RSA CRT components are optional, no return code checking */
template_attribute_get_non_empty(tmpl, CKA_PRIME_1, &prime1);
template_attribute_get_non_empty(tmpl, CKA_PRIME_2, &prime2);
template_attribute_get_non_empty(tmpl, CKA_EXPONENT_1, &exp1);
template_attribute_get_non_empty(tmpl, CKA_EXPONENT_2, &exp2);
template_attribute_get_non_empty(tmpl, CKA_COEFFICIENT, &coef);
/* For CREATE either all CRT components or none of them must be specified */
if (mode == MODE_CREATE &&
!((prime1 == NULL && prime2 == NULL && exp1 == NULL &&
exp2 == NULL && coef == NULL) ||
(prime1 != NULL && prime2 != NULL && exp1 != NULL &&
exp2 != NULL && coef != NULL))) {
TRACE_ERROR("Either all CRT attrs must be specified or none of them\n");
return CKR_TEMPLATE_INCONSISTENT;
}
return priv_key_check_required_attributes(tmpl, mode);
}
// rsa_priv_set_default_attributes()
//
CK_RV rsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *modulus_attr = NULL;
CK_ATTRIBUTE *public_exp_attr = NULL;
CK_ATTRIBUTE *private_exp_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
modulus_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
public_exp_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
private_exp_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !modulus_attr || !public_exp_attr || !private_exp_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
modulus_attr->type = CKA_MODULUS;
modulus_attr->ulValueLen = 0;
modulus_attr->pValue = NULL;
public_exp_attr->type = CKA_PUBLIC_EXPONENT;
public_exp_attr->ulValueLen = 0;
public_exp_attr->pValue = NULL;
private_exp_attr->type = CKA_PRIVATE_EXPONENT;
private_exp_attr->ulValueLen = 0;
private_exp_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_RSA;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, modulus_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
modulus_attr = NULL;
rc = template_update_attribute(tmpl, private_exp_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
private_exp_attr = NULL;
rc = template_update_attribute(tmpl, public_exp_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
public_exp_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (modulus_attr)
free(modulus_attr);
if (private_exp_attr)
free(private_exp_attr);
if (public_exp_attr)
free(public_exp_attr);
return rc;
}
// rsa_priv_validate_attributes()
//
CK_RV rsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
switch (attr->type) {
case CKA_MODULUS:
case CKA_PRIVATE_EXPONENT:
if (mode == MODE_CREATE) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_PUBLIC_EXPONENT:
case CKA_PRIME_1:
case CKA_PRIME_2:
case CKA_EXPONENT_1:
case CKA_EXPONENT_2:
case CKA_COEFFICIENT:
if (mode == MODE_CREATE) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// rsa_priv_check_exportability()
//
CK_BBOOL rsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_PRIVATE_EXPONENT:
case CKA_PRIME_1:
case CKA_PRIME_2:
case CKA_EXPONENT_1:
case CKA_EXPONENT_2:
case CKA_COEFFICIENT:
TRACE_ERROR("%s\n", ock_err(ERR_KEY_UNEXTRACTABLE));
return FALSE;
}
return TRUE;
}
// create the ASN.1 encoding for the private key for wrapping as defined
// in PKCS #8
//
// ASN.1 type PrivateKeyInfo ::= SEQUENCE {
// version Version
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
// privateKey PrivateKey
// attributes OPTIONAL
// }
//
// Where PrivateKey is defined as follows for RSA:
//
// ASN.1 type RSAPrivateKey
//
// RSAPrivateKey ::= SEQUENCE {
// version Version
// modulus INTEGER
// publicExponent INTEGER
// privateExponent INTEGER
// prime1 INTEGER
// prime2 INTEGER
// exponent1 INTEGER
// exponent2 INTEGER
// coefficient INTEGER
// }
//
CK_RV rsa_priv_wrap_get_data(TEMPLATE *tmpl,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *modulus = NULL;
CK_ATTRIBUTE *publ_exp = NULL, *priv_exp = NULL;
CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL;
CK_ATTRIBUTE *exponent1 = NULL, *exponent2 = NULL;
CK_ATTRIBUTE *coeff = NULL;
CK_BBOOL crt_alloced = FALSE;
CK_RV rc;
rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &modulus);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_MODULUS for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &publ_exp);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_PRIVATE_EXPONENT,
&priv_exp);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_PRIVATE_EXPONENT for the key.\n");
return rc;
}
/* CRT attributes are optional */
template_attribute_get_non_empty(tmpl, CKA_PRIME_1, &prime1);
template_attribute_get_non_empty(tmpl, CKA_PRIME_2, &prime2);
template_attribute_get_non_empty(tmpl, CKA_EXPONENT_1, &exponent1);
template_attribute_get_non_empty(tmpl, CKA_EXPONENT_2, &exponent2);
template_attribute_get_non_empty(tmpl, CKA_COEFFICIENT, &coeff);
if (prime1 == NULL || prime2 == NULL || exponent1 == NULL ||
exponent2 == NULL || coeff == NULL) {
/* no CRT components, calculate them */
rc = calc_rsa_crt_from_me(modulus, publ_exp, priv_exp, &prime1,
&prime2, &exponent1, &exponent2, &coeff);
if (rc != CKR_OK) {
TRACE_ERROR("calc_rsa_crt_from_me failed\n");
return rc;
}
crt_alloced = TRUE;
}
rc = ber_encode_RSAPrivateKey(length_only, data, data_len, modulus,
publ_exp, priv_exp, prime1, prime2,
exponent1, exponent2, coeff);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_RSAPrivateKey failed\n");
}
if (crt_alloced) {
OPENSSL_cleanse(prime1->pValue, prime1->ulValueLen);
free(prime1);
OPENSSL_cleanse(prime2->pValue, prime2->ulValueLen);
free(prime2);
OPENSSL_cleanse(exponent1->pValue, exponent1->ulValueLen);
free(exponent1);
OPENSSL_cleanse(exponent2->pValue, exponent2->ulValueLen);
free(exponent2);
OPENSSL_cleanse(coeff->pValue, coeff->ulValueLen);
free(coeff);
}
return rc;
}
//
//
CK_RV rsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length)
{
CK_ATTRIBUTE *modulus = NULL;
CK_ATTRIBUTE *publ_exp = NULL;
CK_ATTRIBUTE *priv_exp = NULL;
CK_ATTRIBUTE *prime1 = NULL;
CK_ATTRIBUTE *prime2 = NULL;
CK_ATTRIBUTE *exponent1 = NULL;
CK_ATTRIBUTE *exponent2 = NULL;
CK_ATTRIBUTE *coeff = NULL;
CK_RV rc;
rc = ber_decode_RSAPrivateKey(data,
total_length,
&modulus,
&publ_exp,
&priv_exp,
&prime1,
&prime2,
&exponent1,
&exponent2, &coeff);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_decode_RSAPrivateKey failed\n");
return rc;
}
p11_attribute_trim(modulus);
p11_attribute_trim(publ_exp);
p11_attribute_trim(priv_exp);
p11_attribute_trim(prime1);
p11_attribute_trim(prime2);
p11_attribute_trim(exponent1);
p11_attribute_trim(exponent2);
p11_attribute_trim(coeff);
rc = template_update_attribute(tmpl, modulus);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
modulus = NULL;
rc = template_update_attribute(tmpl, publ_exp);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
publ_exp = NULL;
rc = template_update_attribute(tmpl, priv_exp);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
priv_exp = NULL;
rc = template_update_attribute(tmpl, prime1);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
prime1 = NULL;
rc = template_update_attribute(tmpl, prime2);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
prime2 = NULL;
rc = template_update_attribute(tmpl, exponent1);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
exponent1 = NULL;
rc = template_update_attribute(tmpl, exponent2);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
exponent2 = NULL;
rc = template_update_attribute(tmpl, coeff);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
coeff = NULL;
return CKR_OK;
error:
if (modulus)
free(modulus);
if (publ_exp)
free(publ_exp);
if (priv_exp)
free(priv_exp);
if (prime1)
free(prime1);
if (prime2)
free(prime2);
if (exponent1)
free(exponent1);
if (exponent2)
free(exponent2);
if (coeff)
free(coeff);
return rc;
}
CK_RV rsa_priv_unwrap_get_data(TEMPLATE *tmpl,
CK_BYTE *data, CK_ULONG total_length,
CK_BBOOL is_public)
{
CK_ATTRIBUTE *modulus = NULL;
CK_ATTRIBUTE *publ_exp = NULL;
CK_ULONG mod_bits;
CK_RV rc;
rc = ber_decode_RSAPublicKey(data, total_length, &modulus, &publ_exp);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_decode_RSAPublicKey failed\n");
return rc;
}
p11_attribute_trim(modulus);
p11_attribute_trim(publ_exp);
mod_bits = modulus->ulValueLen * 8;
if (is_public) {
rc = template_build_update_attribute(tmpl, CKA_MODULUS_BITS,
(CK_BYTE *)&mod_bits,
sizeof(mod_bits));
if (rc != CKR_OK) {
TRACE_DEVEL("template_build_update_attribute failed.\n");
goto error;
}
}
rc = template_update_attribute(tmpl, modulus);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
modulus = NULL;
rc = template_update_attribute(tmpl, publ_exp);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
publ_exp = NULL;
return CKR_OK;
error:
if (modulus)
free(modulus);
if (publ_exp)
free(publ_exp);
return rc;
}
CK_RV rsa_priv_check_and_swap_pq(TEMPLATE *tmpl)
{
CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL;
CK_ATTRIBUTE *exponent1 = NULL, *exponent2 = NULL;
CK_ATTRIBUTE *coeff = NULL;
BIGNUM *bn_tmp = NULL;
BIGNUM *bn_p = NULL;
BIGNUM *bn_q = NULL;
BIGNUM *bn_invq = NULL;
BN_CTX *ctx = NULL;
CK_RV rc = CKR_OK;
CK_ULONG len;
CK_BYTE *buf = NULL;
if (template_attribute_find(tmpl, CKA_PRIME_1, &prime1) == FALSE ||
prime1->ulValueLen == 0 || prime1->pValue == NULL) {
TRACE_DEVEL("Could not find CKA_PRIME_1 for the key, not CRT format.\n");
return CKR_OK;
}
if (template_attribute_find(tmpl, CKA_PRIME_2, &prime2) == FALSE ||
prime2->ulValueLen == 0 || prime2->pValue == NULL) {
TRACE_DEVEL("Could not find CKA_PRIME_2 for the key, not CRT format.\n");
return CKR_OK;
}
if (template_attribute_find(tmpl, CKA_EXPONENT_1, &exponent1) == FALSE ||
exponent1->ulValueLen == 0 || exponent1->pValue == NULL) {
TRACE_DEVEL("Could not find CKA_EXPONENT_1 for the key, not CRT format.\n");
return CKR_OK;
}
if (template_attribute_find(tmpl, CKA_EXPONENT_2, &exponent2) == FALSE ||
exponent2->ulValueLen == 0 || exponent2->pValue == NULL) {
TRACE_DEVEL("Could not find CKA_EXPONENT_2 for the key, not CRT format.\n");
return CKR_OK;
}
if (template_attribute_find(tmpl, CKA_COEFFICIENT, &coeff) == FALSE ||
coeff->ulValueLen == 0 || coeff->pValue == NULL) {
TRACE_DEVEL("Could not find CKA_COEFFICIENT for the key, not CRT format.\n");
return CKR_OK;
}
ctx = BN_CTX_secure_new();
if (ctx == NULL) {
TRACE_ERROR("BN_CTX_secure_new failed.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
bn_p = BN_CTX_get(ctx);
bn_q = BN_CTX_get(ctx);
bn_invq = BN_CTX_get(ctx);
if (bn_p == NULL || bn_q == NULL || bn_invq== NULL) {
TRACE_ERROR("BN_CTX_get failed.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
if (BN_bin2bn(prime1->pValue, prime1->ulValueLen, bn_p) == NULL ||
BN_bin2bn(prime2->pValue, prime2->ulValueLen, bn_q) == NULL){
TRACE_ERROR("BN_bin2bn failed.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
/* check if p > q */
if (BN_ucmp(bn_p, bn_q) != 1) {
/* Unprivileged key format, swap p and q, swap dp and dq, recalc qinv */
bn_tmp = bn_p;
bn_p = bn_q;
bn_q = bn_tmp;
/* qInv = (1/q) mod p */
if (BN_mod_inverse(bn_invq, bn_q, bn_p, ctx) == NULL) {
TRACE_ERROR("BN_mod_inverse failed.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
len = BN_num_bytes(bn_invq);
buf = OPENSSL_secure_zalloc(len);
if (buf == NULL) {
TRACE_ERROR("OPENSSL_secure_zalloc failed.\n");
rc = CKR_HOST_MEMORY;
goto out;
}
if (BN_bn2binpad(bn_invq, buf, len) <= 0) {
TRACE_ERROR("BN_bn2binpad failed.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
prime1->type = CKA_PRIME_2;
prime2->type = CKA_PRIME_1;
exponent1->type = CKA_EXPONENT_2;
exponent2->type = CKA_EXPONENT_1;
rc = build_attribute(CKA_COEFFICIENT, buf, len, &coeff);
if (rc != CKR_OK) {
TRACE_ERROR("build_attribute for CKA_COEFFICIENT failed.\n");
goto out;
}
rc = template_update_attribute(tmpl, coeff);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute for CKA_COEFFICIENT failed.\n");
free(coeff);
goto out;
}
}
out:
if (bn_p != NULL)
BN_clear(bn_p);
if (bn_q != NULL)
BN_clear(bn_q);
if (ctx != NULL)
BN_CTX_free(ctx);
if (buf != NULL)
OPENSSL_clear_free(buf, len);
return rc;
}
static CK_RV pqc_keyform_mode_attrs_by_mech(CK_MECHANISM_TYPE mech,
CK_ATTRIBUTE_TYPE *keyform_attr,
CK_ATTRIBUTE_TYPE *mode_attr,
const struct pqc_oid **oids)
{
switch (mech) {
case CKM_IBM_DILITHIUM:
*keyform_attr = CKA_IBM_DILITHIUM_KEYFORM;
*mode_attr = CKA_IBM_DILITHIUM_MODE;
*oids = dilithium_oids;
break;
case CKM_IBM_KYBER:
*keyform_attr = CKA_IBM_KYBER_KEYFORM;
*mode_attr = CKA_IBM_KYBER_MODE;
*oids = kyber_oids;
break;
case CKM_IBM_ML_DSA:
case CKM_IBM_ML_DSA_KEY_PAIR_GEN:
*keyform_attr = CKA_IBM_PARAMETER_SET;
*mode_attr = (CK_ATTRIBUTE_TYPE)-1;
*oids = ml_dsa_oids;
break;
case CKM_IBM_ML_KEM:
case CKM_IBM_ML_KEM_KEY_PAIR_GEN:
case CKM_IBM_ML_KEM_WITH_ECDH:
*keyform_attr = CKA_IBM_PARAMETER_SET;
*mode_attr = (CK_ATTRIBUTE_TYPE)-1;
*oids = ml_kem_oids;
break;
case CKM_ML_DSA:
case CKM_ML_DSA_KEY_PAIR_GEN:
case CKM_HASH_ML_DSA:
*keyform_attr = CKA_PARAMETER_SET;
*mode_attr = (CK_ATTRIBUTE_TYPE)-1;
*oids = ml_dsa_oids;
break;
case CKM_ML_KEM:
case CKM_ML_KEM_KEY_PAIR_GEN:
*keyform_attr = CKA_PARAMETER_SET;
*mode_attr = (CK_ATTRIBUTE_TYPE)-1;
*oids = ml_kem_oids;
break;
default:
TRACE_ERROR("Unsupported mechanims: 0x%lx\n", mech);
return CKR_MECHANISM_INVALID;
}
return CKR_OK;
}
const struct pqc_oid *pqc_get_keyform_mode(TEMPLATE *tmpl,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *attr = NULL;
const struct pqc_oid *oids = NULL, *oid;
CK_ATTRIBUTE_TYPE keyform_attr = 0;
CK_ATTRIBUTE_TYPE mode_attr = 0;
if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr,
&mode_attr, &oids) != CKR_OK)
return NULL;
if (template_attribute_find(tmpl, keyform_attr, &attr) &&
attr->ulValueLen == sizeof(CK_ULONG) && attr->pValue != NULL) {
oid = find_pqc_by_keyform(oids, *(CK_ULONG *)(attr->pValue));
if (oid == NULL) {
TRACE_ERROR("KEYFORM attribute specifies an invalid value: %lu\n",
*(CK_ULONG *)(attr->pValue));
return NULL;
}
return oid;
}
if (mode_attr != (CK_ATTRIBUTE_TYPE)-1 &&
template_attribute_find(tmpl, mode_attr, &attr) &&
attr->ulValueLen != 0 && attr->pValue != NULL) {
oid = find_pqc_by_oid(oids, attr->pValue, attr->ulValueLen);
if (oid == NULL) {
TRACE_ERROR("MODE attribute specifies an invalid value\n");
return NULL;
}
return oid;
}
TRACE_ERROR("Neither KEYFORM nor MODE found\n");
return NULL;
}
CK_RV pqc_add_keyform_mode(TEMPLATE *tmpl, const struct pqc_oid *oid,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *mode = NULL;
CK_ATTRIBUTE *keyform = NULL;
CK_RV rc;
CK_ATTRIBUTE_TYPE keyform_attr = 0;
CK_ATTRIBUTE_TYPE mode_attr = 0;
const struct pqc_oid *oids;
if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr,
&mode_attr, &oids) != CKR_OK)
return CKR_MECHANISM_INVALID;
if (mode_attr != (CK_ATTRIBUTE_TYPE)-1) {
rc = build_attribute(mode_attr, (CK_BYTE *)oid->oid, oid->oid_len,
&mode);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto error;
}
rc = template_update_attribute(tmpl, mode);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
mode = NULL;
}
rc = build_attribute(keyform_attr, (CK_BYTE *)&oid->keyform,
sizeof(CK_ULONG), &keyform);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto error;
}
rc = template_update_attribute(tmpl, keyform);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
keyform = NULL;
return CKR_OK;
error:
if (mode)
free(mode);
if (keyform)
free(keyform);
return rc;
}
static CK_RV pqc_private_seed_attr_by_mech(CK_MECHANISM_TYPE mech,
CK_ATTRIBUTE_TYPE *priv_seed_attr)
{
switch (mech) {
case CKM_IBM_DILITHIUM:
*priv_seed_attr = (CK_ATTRIBUTE_TYPE)-1;
break;
case CKM_IBM_KYBER:
*priv_seed_attr = (CK_ATTRIBUTE_TYPE)-1;
break;
case CKM_IBM_ML_DSA:
case CKM_IBM_ML_DSA_KEY_PAIR_GEN:
*priv_seed_attr = CKA_IBM_ML_DSA_PRIVATE_SEED;
break;
case CKM_IBM_ML_KEM:
case CKM_IBM_ML_KEM_KEY_PAIR_GEN:
*priv_seed_attr = CKA_IBM_ML_KEM_PRIVATE_SEED;
break;
default:
TRACE_ERROR("Unsupported mechanims: 0x%lx\n", mech);
return CKR_MECHANISM_INVALID;
}
return CKR_OK;
}
/*
* Extract the SubjectPublicKeyInfo from the Dilithium or ML-DSA public key
*/
CK_RV ibm_ml_dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *rho = NULL;
CK_ATTRIBUTE *t1 = NULL;
const struct pqc_oid *oid;
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, mech);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
rc = template_attribute_get_non_empty(tmpl, CKA_IBM_ML_DSA_RHO, &rho);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_RHO for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_IBM_ML_DSA_T1, &t1);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_T1 for the key.\n");
return rc;
}
rc = ber_encode_IBM_ML_DSA_PublicKey(mech, length_only, data, data_len,
oid->oid, oid->oid_len, rho, t1);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_IBM_ML_DSA_PublicKey failed.\n");
return rc;
}
return CKR_OK;
}
CK_RV ibm_ml_dsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *rho = NULL, *seed = NULL;
CK_ATTRIBUTE *tr = NULL, *s1 = NULL, *s2 = NULL;
CK_ATTRIBUTE *t0 = NULL, *t1 = NULL, *priv_seed = NULL;
const struct pqc_oid *oid;
CK_MECHANISM_TYPE priv_seed_attr;
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, mech);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
rc = pqc_private_seed_attr_by_mech(mech, &priv_seed_attr);
if (rc != CKR_OK)
return rc;
/* If private seed is available, then the other components are optional */
if (priv_seed_attr != (CK_MECHANISM_TYPE)-1 &&
template_attribute_find(tmpl, priv_seed_attr, &priv_seed) == TRUE) {
if (priv_seed->ulValueLen == 0 || priv_seed->pValue == NULL)
priv_seed = NULL;
}
template_attribute_find(tmpl, CKA_IBM_ML_DSA_RHO, &rho);
template_attribute_find(tmpl, CKA_IBM_ML_DSA_SEED, &seed);
template_attribute_find(tmpl, CKA_IBM_ML_DSA_TR, &tr);
template_attribute_find(tmpl, CKA_IBM_ML_DSA_S1, &s1);
template_attribute_find(tmpl, CKA_IBM_ML_DSA_S2, &s2);
template_attribute_find(tmpl, CKA_IBM_ML_DSA_T0, &t0);
template_attribute_find(tmpl, CKA_IBM_ML_DSA_T1, &t1);
if (priv_seed == NULL) {
if (rho == NULL || rho->ulValueLen == 0 || rho->pValue == NULL) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_RHO for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
if (seed == NULL || seed->ulValueLen == 0 || seed->pValue == NULL) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_SEED for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
if (tr == NULL || tr->ulValueLen == 0 || tr->pValue == NULL) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_TR for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
if (s1 == NULL || s1->ulValueLen == 0 || s1->pValue == NULL) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_S1 for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
if (s2 == NULL || s2->ulValueLen == 0 || s2->pValue == NULL) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_S2 for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
if (t0 == NULL || t0->ulValueLen == 0 || t0->pValue == NULL) {
TRACE_ERROR("Could not find CKA_IBM_ML_DSA_T0 for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
/* t1 is optional and can be NULL */
}
rc = ber_encode_IBM_ML_DSA_PrivateKey(mech, length_only, data, data_len,
oid->oid, oid->oid_len,
rho, seed, tr, s1, s2, t0, t1,
priv_seed);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_IBM_ML_DSA_PrivateKey failed\n");
}
return rc;
}
CK_RV ibm_ml_dsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length,
CK_BBOOL is_public,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *rho = NULL;
CK_ATTRIBUTE *t1 = NULL;
CK_ATTRIBUTE *value = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_IBM_ML_DSA_PublicKey(mech, data, total_length, &rho, &t1,
&value, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_IBM_ML_DSA_PublicKey failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, mech);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
rc = template_update_attribute(tmpl, rho);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
rho = NULL;
rc = template_update_attribute(tmpl, t1);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
t1 = NULL;
if (is_public) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (rho)
free(rho);
if (t1)
free(t1);
if (value)
free(value);
return rc;
}
//
//
CK_RV ibm_ml_dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL add_value,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *rho = NULL, *seed = NULL, *tr = NULL, *value = NULL;
CK_ATTRIBUTE *s1 = NULL, *s2 = NULL, *t0 = NULL, *t1 = NULL;
CK_ATTRIBUTE *private_seed = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_IBM_ML_DSA_PrivateKey(mech, data, total_length,
&rho, &seed, &tr, &s1, &s2, &t0,
&t1, &private_seed, &value, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_IBM_ML_DSA_PrivateKey failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, mech);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
if (rho != NULL) {
rc = template_update_attribute(tmpl, rho);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
rho = NULL;
}
if (seed != NULL) {
rc = template_update_attribute(tmpl, seed);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
seed = NULL;
}
if (tr != NULL) {
rc = template_update_attribute(tmpl, tr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
tr = NULL;
}
if (s1 != NULL) {
rc = template_update_attribute(tmpl, s1);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
s1 = NULL;
}
if (s2 != NULL) {
rc = template_update_attribute(tmpl, s2);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
s2 = NULL;
}
if (t0 != NULL) {
rc = template_update_attribute(tmpl, t0);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
t0 = NULL;
}
if (t1 != NULL) {
rc = template_update_attribute(tmpl, t1);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
t1 = NULL;
}
if (private_seed) {
rc = template_update_attribute(tmpl, private_seed);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
private_seed = NULL;
}
if (add_value) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (rho)
free(rho);
if (seed)
free(seed);
if (tr)
free(tr);
if (s1)
free(s1);
if (s2)
free(s2);
if (t0)
free(t0);
if (t1)
free(t1);
if (private_seed)
free(private_seed);
if (value)
free(value);
return rc;
}
/*
* Extract the SubjectPublicKeyInfo from the Kyber or ML-KEM public key
*/
CK_RV ibm_ml_kem_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *pk = NULL;
const struct pqc_oid *oid;
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, mech);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
rc = template_attribute_get_non_empty(tmpl, CKA_IBM_ML_KEM_PK, &pk);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_IBM_ML_KEM_PK for the key.\n");
return rc;
}
rc = ber_encode_IBM_ML_KEM_PublicKey(mech, length_only, data, data_len,
oid->oid, oid->oid_len, pk);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_IBM_ML_KEM_PublicKey failed.\n");
return rc;
}
return CKR_OK;
}
CK_RV ibm_ml_kem_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *sk = NULL, *pk = NULL, *priv_seed = NULL;
const struct pqc_oid *oid;
CK_MECHANISM_TYPE priv_seed_attr;
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, mech);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
rc = pqc_private_seed_attr_by_mech(mech, &priv_seed_attr);
if (rc != CKR_OK)
return rc;
/* If private seed is available, then the other components are optional */
if (priv_seed_attr != (CK_MECHANISM_TYPE)-1 &&
template_attribute_find(tmpl, priv_seed_attr, &priv_seed) == TRUE) {
if (priv_seed->ulValueLen == 0 || priv_seed->pValue == NULL)
priv_seed = NULL;
}
template_attribute_find(tmpl, CKA_IBM_ML_KEM_SK, &sk);
template_attribute_find(tmpl, CKA_IBM_ML_KEM_PK, &pk);
if (priv_seed == NULL) {
if (sk == NULL || sk->ulValueLen == 0 || sk->pValue == NULL) {
TRACE_ERROR("Could not find CKA_IBM_ML_KEM_SK for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
/* pk is optional and can be NULL */
}
rc = ber_encode_IBM_ML_KEM_PrivateKey(mech, length_only, data, data_len,
oid->oid, oid->oid_len, sk, pk,
priv_seed);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_IBM_ML_KEM_PrivateKey failed\n");
}
return rc;
}
CK_RV ibm_ml_kem_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length,
CK_BBOOL is_public,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *pk = NULL;
CK_ATTRIBUTE *value = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_IBM_ML_KEM_PublicKey(mech, data, total_length, &pk,
&value, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_IBM_ML_KEM_PublicKey failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, mech);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
rc = template_update_attribute(tmpl, pk);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
pk = NULL;
if (is_public) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (pk)
free(pk);
if (value)
free(value);
return rc;
}
//
//
CK_RV ibm_ml_kem_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL add_value,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE *sk = NULL, *pk = NULL, *value = NULL;
CK_ATTRIBUTE *private_seed = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_IBM_ML_KEM_PrivateKey(mech, data, total_length,
&sk, &pk, &private_seed,
&value, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_IBM_ML_KEM_PrivateKey mech, failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, mech);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
if (sk != NULL) {
rc = template_update_attribute(tmpl, sk);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
sk = NULL;
}
if (pk != NULL) {
rc = template_update_attribute(tmpl, pk);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
pk = NULL;
}
if (private_seed != NULL) {
rc = template_update_attribute(tmpl, private_seed);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
private_seed = NULL;
}
if (add_value) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (sk)
free(sk);
if (pk)
free(pk);
if (private_seed)
free(private_seed);
if (value)
free(value);
return rc;
}
CK_RV ml_dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_BBOOL is_priv_tmpl)
{
CK_ATTRIBUTE *value = NULL;
const struct pqc_oid *oid;
CK_ATTRIBUTE val_attr = { 0, NULL, 0 };
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, CKM_ML_DSA);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
if (is_priv_tmpl) {
#if OPENSSL_VERSION_PREREQ(3, 0)
/*
* An ML-DSA private key does not contain the public key components,
* try to calculate them from the private key using OpenSSL
*/
rc = openssl_specific_pqc_get_pub_key_from_priv_key(tmpl, oid,
CKM_ML_DSA,
&val_attr);
if (rc != CKR_OK) {
TRACE_ERROR("openssl_specific_pqc_get_pub_key_from_priv_key "
"failed.\n");
goto out;
}
value = &val_attr;
#else
TRACE_ERROR("OpenSSL < 3.0.0: Can not calc pub key from priv key\n");
return CKR_TEMPLATE_INCOMPLETE;
#endif
} else {
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
goto out;
}
}
rc = ber_encode_ML_DSA_PublicKey(length_only, data, data_len,
oid->oid, oid->oid_len, value);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_ML_DSA_PublicKey failed.\n");
goto out;
}
out:
if (val_attr.pValue != NULL)
free(val_attr.pValue);
return rc;
}
CK_RV ml_dsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *value = NULL, *seed = NULL;
const struct pqc_oid *oid;
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, CKM_ML_DSA);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
/* If seed is available, then the value is optional */
if (template_attribute_find(tmpl, CKA_SEED, &seed) == TRUE) {
if (seed->ulValueLen == 0 || seed->pValue == NULL)
seed = NULL;
}
template_attribute_find(tmpl, CKA_VALUE, &value);
if (seed == NULL) {
if (value == NULL || value->ulValueLen == 0 || value->pValue == NULL) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
}
rc = ber_encode_ML_DSA_PrivateKey(length_only, data, data_len,
oid->oid, oid->oid_len, value, seed);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_ML_DSA_PrivateKey failed\n");
}
return rc;
}
CK_RV ml_dsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL is_public)
{
CK_ATTRIBUTE *value = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_ML_DSA_PublicKey(data, total_length, &value, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_ML_DSA_PublicKey failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_DSA);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
if (is_public) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (value)
free(value);
return rc;
}
CK_RV ml_dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL add_value)
{
CK_ATTRIBUTE *seed = NULL, *value = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_ML_DSA_PrivateKey(data, total_length, &value, &seed, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_ML_DSA_PrivateKey failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_DSA);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
if (seed != NULL) {
rc = template_update_attribute(tmpl, seed);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
seed = NULL;
}
if (add_value && value != NULL) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else if (value != NULL) {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (seed)
free(seed);
if (value)
free(value);
return rc;
}
CK_RV ml_kem_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_BBOOL is_priv_tmpl)
{
CK_ATTRIBUTE *value = NULL;
const struct pqc_oid *oid;
CK_ATTRIBUTE val_attr = { 0, NULL, 0 };
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, CKM_ML_KEM);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
if (is_priv_tmpl) {
#if OPENSSL_VERSION_PREREQ(3, 0)
/*
* An ML-KEM private key does not contain the public key components,
* try to calculate them from the private key using OpenSSL
*/
rc = openssl_specific_pqc_get_pub_key_from_priv_key(tmpl, oid,
CKM_ML_KEM,
&val_attr);
if (rc != CKR_OK) {
TRACE_ERROR("openssl_specific_pqc_get_pub_key_from_priv_key "
"failed.\n");
goto out;
}
value = &val_attr;
#else
TRACE_ERROR("OpenSSL < 3.0.0: Can not calc pub key from priv key\n");
return CKR_TEMPLATE_INCOMPLETE;
#endif
} else {
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
goto out;
}
}
rc = ber_encode_ML_KEM_PublicKey(length_only, data, data_len,
oid->oid, oid->oid_len, value);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_ML_KEM_PublicKey failed.\n");
goto out;
}
out:
if (val_attr.pValue != NULL)
free(val_attr.pValue);
return rc;
}
CK_RV ml_kem_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *value = NULL, *seed = NULL;
const struct pqc_oid *oid;
CK_RV rc;
oid = pqc_get_keyform_mode(tmpl, CKM_ML_KEM);
if (oid == NULL)
return CKR_TEMPLATE_INCOMPLETE;
/* If seed is available, then the value is optional */
if (template_attribute_find(tmpl, CKA_SEED, &seed) == TRUE) {
if (seed->ulValueLen == 0 || seed->pValue == NULL)
seed = NULL;
}
template_attribute_find(tmpl, CKA_VALUE, &value);
if (seed == NULL) {
if (value == NULL || value->ulValueLen == 0 || value->pValue == NULL) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
}
rc = ber_encode_ML_KEM_PrivateKey(length_only, data, data_len,
oid->oid, oid->oid_len, value, seed);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_ML_KEM_PrivateKey failed\n");
}
return rc;
}
CK_RV ml_kem_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL is_public)
{
CK_ATTRIBUTE *value = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_ML_KEM_PublicKey(data, total_length, &value, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_ML_KEM_PublicKey failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_KEM);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
if (is_public) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (value)
free(value);
return rc;
}
CK_RV ml_kem_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL add_value)
{
CK_ATTRIBUTE *seed = NULL, *value = NULL;
const struct pqc_oid *oid;
CK_RV rc;
rc = ber_decode_ML_KEM_PrivateKey(data, total_length, &value, &seed, &oid);
if (rc != CKR_OK) {
TRACE_ERROR("ber_decode_ML_KEM_PrivateKey failed\n");
return rc;
}
rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_KEM);
if (rc != CKR_OK) {
TRACE_ERROR("pqc_add_keyform_mode failed\n");
goto error;
}
if (seed != NULL) {
rc = template_update_attribute(tmpl, seed);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
seed = NULL;
}
if (add_value && value != NULL) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_DEVEL("template_update_attribute failed.\n");
goto error;
}
} else if (value != NULL) {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (seed)
free(seed);
if (value)
free(value);
return rc;
}
CK_RV pqc_publ_get_spki(TEMPLATE *tmpl, CK_KEY_TYPE keytype,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_BBOOL is_priv_tmpl)
{
switch (keytype) {
case CKK_IBM_PQC_DILITHIUM:
return ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_DILITHIUM);
case CKK_IBM_PQC_KYBER:
return ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_KYBER);
case CKK_IBM_ML_DSA:
return ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_ML_DSA);
case CKK_IBM_ML_KEM:
return ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len,
CKM_IBM_ML_KEM);
case CKK_ML_DSA:
return ml_dsa_publ_get_spki(tmpl, length_only, data, data_len,
is_priv_tmpl);
case CKK_ML_KEM:
return ml_kem_publ_get_spki(tmpl, length_only, data, data_len,
is_priv_tmpl);
default:
TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype);
return CKR_KEY_TYPE_INCONSISTENT;
}
}
CK_RV pqc_priv_wrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
switch (keytype) {
case CKK_IBM_PQC_DILITHIUM:
return ibm_ml_dsa_priv_wrap_get_data(tmpl, length_only, data, data_len,
CKM_IBM_DILITHIUM);
case CKK_IBM_PQC_KYBER:
return ibm_ml_kem_priv_wrap_get_data(tmpl, length_only, data, data_len,
CKM_IBM_KYBER);
case CKK_IBM_ML_DSA:
return ibm_ml_dsa_priv_wrap_get_data(tmpl, length_only, data, data_len,
CKM_IBM_ML_DSA);
case CKK_IBM_ML_KEM:
return ibm_ml_kem_priv_wrap_get_data(tmpl, length_only, data, data_len,
CKM_IBM_ML_KEM);
case CKK_ML_DSA:
return ml_dsa_priv_wrap_get_data(tmpl, length_only, data, data_len);
case CKK_ML_KEM:
return ml_kem_priv_wrap_get_data(tmpl, length_only, data, data_len);
default:
TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype);
return CKR_KEY_TYPE_INCONSISTENT;
}
}
CK_RV pqc_priv_unwrap(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL add_value)
{
switch (keytype) {
case CKK_IBM_PQC_DILITHIUM:
return ibm_ml_dsa_priv_unwrap(tmpl, data, total_length, add_value,
CKM_IBM_DILITHIUM);
case CKK_IBM_PQC_KYBER:
return ibm_ml_kem_priv_unwrap(tmpl, data, total_length, add_value,
CKM_IBM_KYBER);
case CKK_IBM_ML_DSA:
return ibm_ml_dsa_priv_unwrap(tmpl, data, total_length, add_value,
CKM_IBM_ML_DSA);
case CKK_IBM_ML_KEM:
return ibm_ml_kem_priv_unwrap(tmpl, data, total_length, add_value,
CKM_IBM_ML_KEM);
case CKK_ML_DSA:
return ml_dsa_priv_unwrap(tmpl, data, total_length, add_value);
case CKK_ML_KEM:
return ml_kem_priv_unwrap(tmpl, data, total_length, add_value);
default:
TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype);
return CKR_KEY_TYPE_INCONSISTENT;
}
}
CK_RV pqc_priv_unwrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype,
CK_BYTE *data, CK_ULONG total_length,
CK_BBOOL is_public)
{
switch (keytype) {
case CKK_IBM_PQC_DILITHIUM:
return ibm_ml_dsa_priv_unwrap_get_data(tmpl, data, total_length,
is_public, CKM_IBM_DILITHIUM);
case CKK_IBM_PQC_KYBER:
return ibm_ml_kem_priv_unwrap_get_data(tmpl, data, total_length,
is_public, CKM_IBM_KYBER);
case CKK_IBM_ML_DSA:
return ibm_ml_dsa_priv_unwrap_get_data(tmpl, data, total_length,
is_public, CKM_IBM_ML_DSA);
case CKK_IBM_ML_KEM:
return ibm_ml_kem_priv_unwrap_get_data(tmpl, data, total_length,
is_public, CKM_IBM_ML_KEM);
case CKK_ML_DSA:
return ml_dsa_priv_unwrap_get_data(tmpl, data, total_length, is_public);
case CKK_ML_KEM:
return ml_kem_priv_unwrap_get_data(tmpl, data, total_length, is_public);
default:
TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype);
return CKR_KEY_TYPE_INCONSISTENT;
}
}
// dsa_publ_check_required_attributes()
//
CK_RV dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for public key templates.
*/
return publ_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_PRIME\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_SUBPRIME\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_BASE\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return publ_key_check_required_attributes(tmpl, mode);
}
// dsa_publ_set_default_attributes()
//
CK_RV dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *subprime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !prime_attr || !subprime_attr || !base_attr
|| !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
prime_attr->type = CKA_PRIME;
prime_attr->ulValueLen = 0;
prime_attr->pValue = NULL;
subprime_attr->type = CKA_SUBPRIME;
subprime_attr->ulValueLen = 0;
subprime_attr->pValue = NULL;
base_attr->type = CKA_BASE;
base_attr->ulValueLen = 0;
base_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_DSA;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, prime_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime_attr = NULL;
rc = template_update_attribute(tmpl, subprime_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
subprime_attr = NULL;
rc = template_update_attribute(tmpl, base_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (prime_attr)
free(prime_attr);
if (subprime_attr)
free(subprime_attr);
if (base_attr)
free(base_attr);
if (value_attr)
free(value_attr);
return rc;
}
// dsa_publ_validate_attributes()
//
CK_RV dsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
switch (attr->type) {
case CKA_PRIME:
{
CK_ULONG size;
if (mode != MODE_CREATE && mode != MODE_KEYGEN &&
mode != MODE_ENCAPS && mode != MODE_EXTRACT) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
// must be between [512, 1024] bits, and a multiple of 64 bits
//
size = attr->ulValueLen;
if (size < 64 || (size % 8 != 0)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
p11_attribute_trim(attr);
return CKR_OK;
}
case CKA_SUBPRIME:
if (mode != MODE_CREATE && mode != MODE_KEYGEN &&
mode != MODE_ENCAPS && mode != MODE_EXTRACT) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
// subprime must be 160 bits
//
if (attr->ulValueLen < 20) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
p11_attribute_trim(attr);
return CKR_OK;
case CKA_BASE:
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_VALUE:
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
/*
* Extract the SubjectPublicKeyInfo from the DSA public key
*/
CK_RV dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *subprime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_RV rc;
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_PRIME for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_BASE for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &subprime);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_SUBPRIME for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
rc = ber_encode_DSAPublicKey(length_only, data,data_len, prime, subprime,
base, value);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_DSAPublicKey failed.\n");
return rc;
}
return CKR_OK;
}
// dsa_priv_check_required_attributes()
//
CK_RV dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for private key templates.
*/
return priv_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_PRIME\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_SUBPRIME\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_BASE\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return priv_key_check_required_attributes(tmpl, mode);
}
// dsa_priv_set_default_attributes()
//
CK_RV dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *subprime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !prime_attr || !subprime_attr || !base_attr
|| !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
prime_attr->type = CKA_PRIME;
prime_attr->ulValueLen = 0;
prime_attr->pValue = NULL;
subprime_attr->type = CKA_SUBPRIME;
subprime_attr->ulValueLen = 0;
subprime_attr->pValue = NULL;
base_attr->type = CKA_BASE;
base_attr->ulValueLen = 0;
base_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_DSA;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, prime_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime_attr = NULL;
rc = template_update_attribute(tmpl, subprime_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
subprime_attr = NULL;
rc = template_update_attribute(tmpl, base_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (prime_attr)
free(prime_attr);
if (subprime_attr)
free(subprime_attr);
if (base_attr)
free(base_attr);
if (value_attr)
free(value_attr);
return rc;
}
// dsa_priv_validate_attributes()
//
CK_RV dsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
switch (attr->type) {
case CKA_PRIME:
{
CK_ULONG size;
if (mode != MODE_CREATE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
// must be between [512, 1024] bits, and a multiple of 64 bits
//
size = attr->ulValueLen;
if (size < 64 || size > 128 || (size % 8 != 0)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
p11_attribute_trim(attr);
return CKR_OK;
}
case CKA_SUBPRIME:
if (mode != MODE_CREATE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
// subprime must be 160 bits
//
if (attr->ulValueLen != 20) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
p11_attribute_trim(attr);
return CKR_OK;
case CKA_BASE:
case CKA_VALUE:
if (mode == MODE_CREATE) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// dsa_priv_check_exportability()
//
CK_BBOOL dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
return FALSE;
}
return TRUE;
}
// create the ASN.1 encoding for the private key for wrapping as defined
// in PKCS #8
//
// ASN.1 type PrivateKeyInfo ::= SEQUENCE {
// version Version
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
// privateKey PrivateKey
// attributes OPTIONAL
// }
//
// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
//
// AlgorithmIdentifier ::= SEQUENCE {
// algorithm OBJECT IDENTIFIER
// parameters ANY DEFINED BY algorithm OPTIONAL
// }
//
// paramters ::= SEQUENCE {
// p INTEGER
// q INTEGER
// g INTEGER
// }
//
// privateKey ::= INTEGER
//
//
CK_RV dsa_priv_wrap_get_data(TEMPLATE *tmpl,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *subprime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_RV rc;
// compute the total length of the BER-encoded data
//
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_PRIME for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &subprime);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_SUBPRIME for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_BASE for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
rc = ber_encode_DSAPrivateKey(length_only, data, data_len,
prime, subprime, base, value);
if (rc != CKR_OK)
TRACE_DEVEL("ber_encode_DSAPrivateKey failed\n");
return rc;
}
//
//
CK_RV dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *subprime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_RV rc;
rc = ber_decode_DSAPrivateKey(data, total_length,
&prime, &subprime, &base, &value);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_decode_DSAPrivateKey failed\n");
return rc;
}
p11_attribute_trim(prime);
p11_attribute_trim(subprime);
p11_attribute_trim(base);
p11_attribute_trim(value);
rc = template_update_attribute(tmpl, prime);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime = NULL;
rc = template_update_attribute(tmpl, subprime);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
subprime = NULL;
rc = template_update_attribute(tmpl, base);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base = NULL;
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value = NULL;
return CKR_OK;
error:
if (prime)
free(prime);
if (subprime)
free(subprime);
if (base)
free(base);
if (value)
free(value);
return rc;
}
CK_RV dsa_priv_unwrap_get_data(TEMPLATE *tmpl,
CK_BYTE *data, CK_ULONG total_length,
CK_BBOOL is_public)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *subprime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_RV rc;
rc = ber_decode_DSAPublicKey(data, total_length, &prime, &subprime,
&base, &value);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_decode_DSAPublicKey failed\n");
return rc;
}
p11_attribute_trim(prime);
p11_attribute_trim(subprime);
p11_attribute_trim(base);
p11_attribute_trim(value);
rc = template_update_attribute(tmpl, prime);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime = NULL;
rc = template_update_attribute(tmpl, subprime);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
subprime = NULL;
rc = template_update_attribute(tmpl, base);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base = NULL;
if (is_public) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
} else {
free(value);
}
value = NULL;
return CKR_OK;
error:
if (prime)
free(prime);
if (subprime)
free(subprime);
if (base)
free(base);
if (value)
free(value);
return rc;
}
// ec_publ_check_required_attributes()
//
CK_RV ec_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for a public key templates.
*/
return publ_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_EC_PARAMS\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_EC_POINT, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_EC_POINT\n");
return rc;
}
}
return publ_key_check_required_attributes(tmpl, mode);
}
// ec_publ_set_default_attributes()
//
CK_RV ec_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *params_attr = NULL;
CK_ATTRIBUTE *ec_point_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
params_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
ec_point_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !params_attr || !ec_point_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
params_attr->type = CKA_EC_PARAMS;
params_attr->ulValueLen = 0;
params_attr->pValue = NULL;
ec_point_attr->type = CKA_EC_POINT;
ec_point_attr->ulValueLen = 0;
ec_point_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = key_type;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, params_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
params_attr = NULL;
rc = template_update_attribute(tmpl, ec_point_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
ec_point_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (params_attr)
free(params_attr);
if (ec_point_attr)
free(ec_point_attr);
return rc;
}
// ec_publ_validate_attributes()
//
CK_RV ec_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
switch (attr->type) {
case CKA_EC_PARAMS:
if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_DERIVE ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_EC_POINT:
if (mode == MODE_CREATE || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
/*
* Extract the SubjectPublicKeyInfo from the EC public key
*/
CK_RV ec_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *ec_parms = NULL;
CK_ATTRIBUTE *ec_point = NULL;
CK_ATTRIBUTE *value = NULL;
CK_BYTE *buf = NULL;
CK_ULONG buf_len = 0;
CK_ATTRIBUTE point = { .type = CKA_EC_POINT,
.pValue = NULL, .ulValueLen = 0 };
int i, curve_type = -1;
CK_RV rc;
rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ec_parms);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n");
return rc;
}
for (i = 0; i < NUMEC; i++) {
if (der_ec_supported[i].data_size == ec_parms->ulValueLen &&
memcmp(der_ec_supported[i].data, ec_parms->pValue,
ec_parms->ulValueLen) == 0) {
curve_type = der_ec_supported[i].curve_type;
break;
}
}
if (curve_type == -1) {
TRACE_ERROR("Could not find a curve type\n");
return CKR_CURVE_NOT_SUPPORTED;
}
/* CKA_EC_POINT is optional in EC private keys */
rc = template_attribute_get_non_empty(tmpl, CKA_EC_POINT, &ec_point);
if (rc != CKR_OK) {
TRACE_DEVEL("Could not find CKA_EC_POINT, possibly EC private key.\n");
/*
* For a secure key token, we can't calculate the public key from the
* private key
*/
if (token_specific.secure_key_token) {
TRACE_DEVEL("Its a secure key token, no SPKI avaiable.\n");
*data = NULL;
*data_len = 0;
return CKR_OK;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
rc = ec_point_from_priv_key(ec_parms->pValue, ec_parms->ulValueLen,
value->pValue, value->ulValueLen,
&buf, &buf_len);
if (rc != CKR_OK) {
TRACE_ERROR("ec_point_from_priv_key failed.\n");
return rc;
}
if (curve_type != EDWARDS_CURVE && curve_type != MONTGOMERY_CURVE) {
rc = ber_encode_OCTET_STRING(FALSE, (CK_BYTE **)&point.pValue,
&point.ulValueLen, buf, buf_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed\n");
goto out;
}
} else {
/* Edwards/Montgomery keys have raw CKA_EC_POINT */
point.pValue = buf;
point.ulValueLen = buf_len;
buf = NULL;
}
ec_point = &point;
}
rc = ber_encode_ECPublicKey(length_only, data,data_len, ec_parms,
ec_point, key_type);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_ECPublicKey failed.\n");
goto out;
}
out:
if (buf != NULL)
free(buf);
if (point.pValue != NULL)
free(point.pValue);
return rc;
}
// ec_priv_check_required_attributes()
//
CK_RV ec_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for private key templates.
*/
return priv_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_EC_PARAMS\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return priv_key_check_required_attributes(tmpl, mode);
}
// ec_priv_set_default_attributes()
//
CK_RV ec_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *params_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
params_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !params_attr || !value_attr) {
if (type_attr)
free(type_attr);
if (params_attr)
free(params_attr);
if (value_attr)
free(value_attr);
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
params_attr->type = CKA_EC_PARAMS;
params_attr->ulValueLen = 0;
params_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = key_type;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, params_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
params_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (params_attr)
free(params_attr);
if (value_attr)
free(value_attr);
return rc;
}
// ec_priv_validate_attribute()
//
CK_RV ec_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
switch (attr->type) {
case CKA_EC_PARAMS:
if (mode == MODE_CREATE || mode == MODE_DERIVE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_VALUE:
if (mode == MODE_CREATE) {
if (key_type == CKK_EC)
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_EC_POINT:
if (mode == MODE_CREATE) {
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// ec_priv_check_exportability()
//
CK_BBOOL ec_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
return FALSE;
}
return TRUE;
}
/*
* create the ASN.1 encoding for the private key for wrapping as defined
* in PKCS #8
*
* ASN.1 type PrivateKeyInfo ::= SEQUENCE {
* version Version
* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
* privateKey PrivateKey
* attributes OPTIONAL
* }
*
* Where PrivateKey is defined as follows for EC:
*
* ASN.1 type RSAPrivateKey
*
* ECPrivateKey ::= SEQUENCE {
* version Version
* privateKey OCTET STRING
* parameters [0] ECParameters (OPTIONAL)
* publicKey [1] BIT STRING (OPTIONAL)
* }
*/
CK_RV ec_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *params = NULL;
CK_ATTRIBUTE *privkey = NULL;
CK_ATTRIBUTE *pubkey = NULL;
CK_RV rc;
// compute the total length of the BER-encoded data
//
rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &params);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &privkey);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
/* check if optional public-key part was defined */
template_attribute_get_non_empty(tmpl, CKA_EC_POINT, &pubkey);
rc = der_encode_ECPrivateKey(length_only, data, data_len, params,
privkey, pubkey, key_type);
if (rc != CKR_OK) {
TRACE_DEVEL("der_encode_ECPrivateKey failed\n");
}
return rc;
}
CK_RV ec_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data,
CK_ULONG total_length, CK_BBOOL is_public,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *params = NULL;
CK_ATTRIBUTE *point = NULL;
CK_RV rc;
rc = der_decode_ECPublicKey(data, total_length, &params, &point, key_type);
if (rc != CKR_OK) {
TRACE_DEVEL("der_decode_ECPublicKey failed\n");
return rc;
}
rc = template_update_attribute(tmpl, params);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
params = NULL;
if (is_public) {
rc = template_update_attribute(tmpl, point);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
} else {
free(point);
}
point = NULL;
return CKR_OK;
error:
if (params)
free(params);
if (point)
free(point);
return rc;
}
//
//
CK_RV ec_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *pubkey = NULL;
CK_ATTRIBUTE *privkey = NULL;
CK_ATTRIBUTE *ecparam = NULL;
CK_RV rc;
rc = der_decode_ECPrivateKey(data, total_length, &ecparam,
&pubkey, &privkey, key_type);
if (rc != CKR_OK) {
TRACE_DEVEL("der_decode_ECPrivateKey failed\n");
return rc;
}
if (key_type == CKK_EC)
p11_attribute_trim(privkey);
if (pubkey) {
rc = template_update_attribute(tmpl, pubkey);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
pubkey = NULL;
}
if (privkey) {
rc = template_update_attribute(tmpl, privkey);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
privkey = NULL;
}
rc = template_update_attribute(tmpl, ecparam);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
ecparam = NULL;
return CKR_OK;
error:
if (pubkey)
free(pubkey);
if (privkey)
free(privkey);
if (ecparam)
free(ecparam);
return rc;
}
// dh_publ_check_required_attributes()
//
CK_RV dh_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for public key templates.
*/
return publ_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_PRIME\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_BASE\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return publ_key_check_required_attributes(tmpl, mode);
}
// dh_publ_set_default_attributes()
//
CK_RV dh_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !prime_attr || !base_attr || !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
prime_attr->type = CKA_PRIME;
prime_attr->ulValueLen = 0;
prime_attr->pValue = NULL;
base_attr->type = CKA_BASE;
base_attr->ulValueLen = 0;
base_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_DH;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, prime_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime_attr = NULL;
rc = template_update_attribute(tmpl, base_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (prime_attr)
free(prime_attr);
if (base_attr)
free(base_attr);
if (value_attr)
free(value_attr);
return rc;
}
// dh_publ_validate_attribute()
//
CK_RV dh_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
switch (attr->type) {
case CKA_PRIME:
case CKA_BASE:
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_VALUE:
if (mode == MODE_CREATE || mode == MODE_EXTRACT) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
/*
* Extract the SubjectPublicKeyInfo from the DH public key
*/
CK_RV dh_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_RV rc;
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_PRIME for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_BASE for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
rc = ber_encode_DHPublicKey(length_only, data,data_len, prime, base, value);
if (rc != CKR_OK) {
TRACE_ERROR("ber_encode_DHPublicKey failed.\n");
return rc;
}
return CKR_OK;
}
// dh_priv_check_required_attributes()
//
CK_RV dh_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_ULONG val;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for private key templates.
*/
return priv_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_PRIME\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_BASE\n");
return rc;
}
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
rc = template_attribute_get_ulong(tmpl, CKA_VALUE_BITS, &val);
if (rc != CKR_TEMPLATE_INCOMPLETE) {
if (mode == MODE_CREATE || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
}
return priv_key_check_required_attributes(tmpl, mode);
}
// dh_priv_set_default_attributes()
//
CK_RV dh_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *value_bits_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_ULONG bits = 0L;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (mode != MODE_CREATE && mode != MODE_UNWRAP &&
mode != MODE_ENCAPS && mode != MODE_DECAPS)
value_bits_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG));
if (!type_attr || !prime_attr || !base_attr || !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
if (mode != MODE_CREATE && mode != MODE_UNWRAP &&
mode != MODE_ENCAPS && mode != MODE_DECAPS &&
!value_bits_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
prime_attr->type = CKA_PRIME;
prime_attr->ulValueLen = 0;
prime_attr->pValue = NULL;
base_attr->type = CKA_BASE;
base_attr->ulValueLen = 0;
base_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
if (mode != MODE_CREATE && mode != MODE_UNWRAP &&
mode != MODE_ENCAPS && mode != MODE_DECAPS) {
value_bits_attr->type = CKA_VALUE_BITS;
value_bits_attr->ulValueLen = sizeof(CK_ULONG);
value_bits_attr->pValue =
(CK_BYTE *) value_bits_attr + sizeof(CK_ATTRIBUTE);
*(CK_ULONG *) value_bits_attr->pValue = bits;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_DH;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, prime_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime_attr = NULL;
rc = template_update_attribute(tmpl, base_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
if (mode != MODE_CREATE && mode != MODE_UNWRAP &&
mode != MODE_ENCAPS && mode != MODE_DECAPS) {
rc = template_update_attribute(tmpl, value_bits_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_bits_attr = NULL;
}
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (prime_attr)
free(prime_attr);
if (base_attr)
free(base_attr);
if (value_attr)
free(value_attr);
if (value_bits_attr)
free(value_bits_attr);
return rc;
}
// dh_priv_validate_attribute()
//
CK_RV dh_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
switch (attr->type) {
case CKA_PRIME:
case CKA_BASE:
case CKA_VALUE:
if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_ENCAPS) {
p11_attribute_trim(attr);
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
// I'm not sure what to do about VALUE_BITS...we don't really support
// Diffie-Hellman keys other than for storage...when the object is
// created, we're supposed to add CKA_VALUE_BITS outselves...which we
// don't do at this time. (we'd need to add code in C_CreateObject to
// call some sort of objecttype-specific callback)
//
// kapil 05/08/03 : Commented out error flagging, as CKA_VALUE_BITS is
// valid attribute for creating DH priv object. The
// above is an older comment.
case CKA_VALUE_BITS:
// TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
// return CKR_ATTRIBUTE_READ_ONLY;
if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
break;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// dh_priv_check_exportability()
//
CK_BBOOL dh_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
return FALSE;
}
return TRUE;
}
//
//
CK_RV dh_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_RV rc;
rc = ber_decode_DHPrivateKey(data, total_length, &prime, &base, &value);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_decode_DHPrivateKey failed\n");
return rc;
}
p11_attribute_trim(prime);
p11_attribute_trim(base);
p11_attribute_trim(value);
rc = template_update_attribute(tmpl, prime);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime = NULL;
rc = template_update_attribute(tmpl, base);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base = NULL;
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value = NULL;
return CKR_OK;
error:
if (prime)
free(prime);
if (base)
free(base);
if (value)
free(value);
return rc;
}
CK_RV dh_priv_unwrap_get_data(TEMPLATE *tmpl,
CK_BYTE *data, CK_ULONG total_length,
CK_BBOOL is_public)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_ATTRIBUTE *value_bits = NULL;
CK_ULONG num_bits;
CK_RV rc;
rc = ber_decode_DHPublicKey(data, total_length, &prime, &base, &value);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_decode_DHPublicKey failed\n");
return rc;
}
p11_attribute_trim(prime);
p11_attribute_trim(base);
p11_attribute_trim(value);
num_bits = value->ulValueLen * 8;
rc = template_update_attribute(tmpl, prime);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
prime = NULL;
rc = template_update_attribute(tmpl, base);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
base = NULL;
if (is_public) {
rc = template_update_attribute(tmpl, value);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
} else {
free(value);
}
value = NULL;
if (!is_public) {
rc = build_attribute(CKA_VALUE_BITS, (CK_BYTE *)&num_bits,
sizeof(num_bits), &value_bits);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto error;
}
rc = template_update_attribute(tmpl, value_bits);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_bits = NULL;
}
return CKR_OK;
error:
if (prime)
free(prime);
if (base)
free(base);
if (value)
free(value);
if (value_bits)
free(value_bits);
return rc;
}
// create the ASN.1 encoding for the private key for wrapping as defined
// in PKCS #8
//
// ASN.1 type PrivateKeyInfo ::= SEQUENCE {
// version Version
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
// privateKey PrivateKey
// attributes OPTIONAL
// }
//
// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
//
// AlgorithmIdentifier ::= SEQUENCE {
// algorithm OBJECT IDENTIFIER
// parameters ANY DEFINED BY algorithm OPTIONAL
// }
//
// paramters ::= SEQUENCE {
// p INTEGER
// g INTEGER
// }
//
// privateKey ::= INTEGER
//
//
CK_RV dh_priv_wrap_get_data(TEMPLATE *tmpl,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *prime = NULL;
CK_ATTRIBUTE *base = NULL;
CK_ATTRIBUTE *value = NULL;
CK_RV rc;
// compute the total length of the BER-encoded data
rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_PRIME for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_BASE for the key.\n");
return rc;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
rc = ber_encode_DHPrivateKey(length_only, data, data_len,
prime, base, value);
if (rc != CKR_OK)
TRACE_DEVEL("ber_encode_DHPrivateKey failed\n");
return rc;
}
// ibm_ml_dsa_publ_set_default_attributes() - for Dilithium and ML-DSA
//
CK_RV ibm_ml_dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *rho_attr = NULL;
CK_ATTRIBUTE *t1_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
rho_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
t1_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !rho_attr || !t1_attr || !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = key_type;
rho_attr->type = CKA_IBM_ML_DSA_RHO;
rho_attr->ulValueLen = 0;
rho_attr->pValue = NULL;
t1_attr->type = CKA_IBM_ML_DSA_T1;
t1_attr->ulValueLen = 0;
t1_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, rho_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
rho_attr = NULL;
rc = template_update_attribute(tmpl, t1_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
t1_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (rho_attr)
free(rho_attr);
if (t1_attr)
free(t1_attr);
if (value_attr)
free(value_attr);
return rc;
}
// ibm_ml_dsa_priv_set_default_attributes() - for Dilithium and ML-DSA
//
CK_RV ibm_ml_dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *rho_attr = NULL;
CK_ATTRIBUTE *seed_attr = NULL;
CK_ATTRIBUTE *tr_attr = NULL;
CK_ATTRIBUTE *s1_attr = NULL;
CK_ATTRIBUTE *s2_attr = NULL;
CK_ATTRIBUTE *t0_attr = NULL;
CK_ATTRIBUTE *t1_attr = NULL;
CK_ATTRIBUTE *priv_seed_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
rho_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
tr_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
s1_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
s2_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
t0_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
t1_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (key_type == CKK_IBM_ML_DSA)
priv_seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !rho_attr || !seed_attr || !tr_attr || !s1_attr
|| !s2_attr || !t0_attr || !t1_attr || !value_attr ||
(key_type == CKK_IBM_ML_DSA && !priv_seed_attr)) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = key_type;
rho_attr->type = CKA_IBM_ML_DSA_RHO;
rho_attr->ulValueLen = 0;
rho_attr->pValue = NULL;
seed_attr->type = CKA_IBM_ML_DSA_SEED;
seed_attr->ulValueLen = 0;
seed_attr->pValue = NULL;
tr_attr->type = CKA_IBM_ML_DSA_TR;
tr_attr->ulValueLen = 0;
tr_attr->pValue = NULL;
s1_attr->type = CKA_IBM_ML_DSA_S1;
s1_attr->ulValueLen = 0;
s1_attr->pValue = NULL;
s2_attr->type = CKA_IBM_ML_DSA_S2;
s2_attr->ulValueLen = 0;
s2_attr->pValue = NULL;
t0_attr->type = CKA_IBM_ML_DSA_T0;
t0_attr->ulValueLen = 0;
t0_attr->pValue = NULL;
t1_attr->type = CKA_IBM_ML_DSA_T1;
t1_attr->ulValueLen = 0;
t1_attr->pValue = NULL;
if (key_type == CKK_IBM_ML_DSA) {
priv_seed_attr->type = CKA_IBM_ML_DSA_PRIVATE_SEED;
priv_seed_attr->ulValueLen = 0;
priv_seed_attr->pValue = NULL;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, rho_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
rho_attr = NULL;
rc = template_update_attribute(tmpl, seed_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
seed_attr = NULL;
rc = template_update_attribute(tmpl, tr_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
tr_attr = NULL;
rc = template_update_attribute(tmpl, s1_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
s1_attr = NULL;
rc = template_update_attribute(tmpl, s2_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
s2_attr = NULL;
rc = template_update_attribute(tmpl, t0_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
t0_attr = NULL;
rc = template_update_attribute(tmpl, t1_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
t1_attr = NULL;
if (key_type == CKK_IBM_ML_DSA) {
rc = template_update_attribute(tmpl, priv_seed_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
priv_seed_attr = NULL;
}
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (rho_attr)
free(rho_attr);
if (seed_attr)
free(seed_attr);
if (tr_attr)
free(tr_attr);
if (s1_attr)
free(s1_attr);
if (s2_attr)
free(s2_attr);
if (t0_attr)
free(t0_attr);
if (t1_attr)
free(t1_attr);
if (priv_seed_attr)
free(priv_seed_attr);
if (value_attr)
free(value_attr);
return rc;
}
// ibm_ml_kem_publ_set_default_attributes() - for Kyber and ML-KEM
//
CK_RV ibm_ml_kem_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *pk_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
pk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !pk_attr ||!value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = key_type;
pk_attr->type = CKA_IBM_ML_KEM_PK;
pk_attr->ulValueLen = 0;
pk_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, pk_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
pk_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (pk_attr)
free(pk_attr);
if (value_attr)
free(value_attr);
return rc;
}
// ibm_ml_kem_priv_set_default_attributes() - for Kyber and ML-KEM
//
CK_RV ibm_ml_kem_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *sk_attr = NULL;
CK_ATTRIBUTE *pk_attr = NULL;
CK_ATTRIBUTE *priv_seed_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
sk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
pk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (key_type == CKK_IBM_ML_KEM)
priv_seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !sk_attr || !pk_attr || !value_attr ||
(key_type == CKK_IBM_ML_KEM && !priv_seed_attr)) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = key_type;
sk_attr->type = CKA_IBM_ML_KEM_SK;
sk_attr->ulValueLen = 0;
sk_attr->pValue = NULL;
pk_attr->type = CKA_IBM_ML_KEM_PK;
pk_attr->ulValueLen = 0;
pk_attr->pValue = NULL;
if (key_type == CKK_IBM_ML_KEM) {
priv_seed_attr->type = CKA_IBM_ML_KEM_PRIVATE_SEED;
priv_seed_attr->ulValueLen = 0;
priv_seed_attr->pValue = NULL;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, sk_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
sk_attr = NULL;
rc = template_update_attribute(tmpl, pk_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
pk_attr = NULL;
if (key_type == CKK_IBM_ML_KEM) {
rc = template_update_attribute(tmpl, priv_seed_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
priv_seed_attr = NULL;
}
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (sk_attr)
free(sk_attr);
if (pk_attr)
free(pk_attr);
if (priv_seed_attr)
free(priv_seed_attr);
if (value_attr)
free(value_attr);
return rc;
}
CK_RV ml_dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = CKK_ML_DSA;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (value_attr)
free(value_attr);
return rc;
}
CK_RV ml_dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *seed_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !seed_attr || !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = CKK_ML_DSA;
seed_attr->type = CKA_SEED;
seed_attr->ulValueLen = 0;
seed_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, seed_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
seed_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (seed_attr)
free(seed_attr);
if (value_attr)
free(value_attr);
return rc;
}
CK_RV ml_kem_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
publ_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = CKK_ML_KEM;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (value_attr)
free(value_attr);
return rc;
}
CK_RV ml_kem_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *seed_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_RV rc;
priv_key_set_default_attributes(tmpl, mode);
type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
if (!type_attr || !seed_attr || !value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)type_attr->pValue = CKK_ML_KEM;
seed_attr->type = CKA_SEED;
seed_attr->ulValueLen = 0;
seed_attr->pValue = NULL;
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, seed_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
seed_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (seed_attr)
free(seed_attr);
if (value_attr)
free(value_attr);
return rc;
}
static CK_RV pqc_check_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_MECHANISM_TYPE mech,
const CK_MECHANISM_TYPE *req_attrs,
CK_ULONG num_req_attrs,
CK_MECHANISM_TYPE priv_seed_attr)
{
CK_ATTRIBUTE_TYPE keyform_attr;
CK_ATTRIBUTE_TYPE mode_attr;
CK_ATTRIBUTE *attr = NULL;
CK_BBOOL keyform_present = FALSE;
CK_BBOOL mode_present = FALSE;
const struct pqc_oid *oids, *oid;
CK_ULONG i;
CK_RV rc;
if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr,
&mode_attr, &oids) != CKR_OK)
return CKR_MECHANISM_INVALID;
if (template_attribute_find(tmpl, keyform_attr, &attr) &&
attr->ulValueLen == sizeof(CK_ULONG) && attr->pValue != NULL) {
oid = find_pqc_by_keyform(oids, *(CK_ULONG *)(attr->pValue));
if (oid == NULL) {
TRACE_ERROR("%s, attribute KEYFORM has an unsupported value.\n",
ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
keyform_present = TRUE;
}
if (mode_attr != (CK_ATTRIBUTE_TYPE)-1 &&
template_attribute_find(tmpl, mode_attr, &attr) &&
attr->ulValueLen > 0 && attr->pValue != NULL) {
oid = find_pqc_by_oid(oids, attr->pValue, attr->ulValueLen);
if (oid == NULL) {
TRACE_ERROR("%s, attribute MODE has an unsupported value.\n",
ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
mode_present = TRUE;
}
switch (mode) {
case MODE_CREATE:
case MODE_EXTRACT:
/* Import of an already existing secure key via CKA_IBM_OPAQUE */
if (token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE,
&attr) == CKR_OK)
break;
/* Either CKA_VALUE or priv. seed or all other attrs must be present */
if (template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr) == CKR_OK)
break;
if (priv_seed_attr != (CK_ATTRIBUTE_TYPE)-1 &&
template_attribute_get_non_empty(tmpl, priv_seed_attr, &attr)
== CKR_OK)
break;
for (i = 0; i < num_req_attrs; i++) {
rc = template_attribute_get_non_empty(tmpl, req_attrs[i], &attr);
if (rc != CKR_OK) {
if (rc != CKR_ATTRIBUTE_VALUE_INVALID)
TRACE_ERROR("%s, attribute %08lX missing.\n",
ock_err(ERR_TEMPLATE_INCOMPLETE), req_attrs[i]);
return rc;
}
}
if (num_req_attrs == 0) {
TRACE_ERROR("%s, Either CKA_VALUE or private seed attr %08lX must "
"be specified.\n",
ock_err(ERR_TEMPLATE_INCOMPLETE), priv_seed_attr);
return CKR_TEMPLATE_INCONSISTENT;
}
/* fallthrough */
case MODE_KEYGEN:
case MODE_ENCAPS:
/* Either keyform or mode or none of it must be present */
if (keyform_present && mode_present) {
TRACE_ERROR("%s, only one of KEYFORM or MODE can be specified .\n",
ock_err(ERR_TEMPLATE_INCONSISTENT));
return CKR_TEMPLATE_INCONSISTENT;
}
break;
case MODE_UNWRAP:
case MODE_DECAPS:
/* neither keyform or mode must be present */
if (keyform_present || mode_present) {
TRACE_ERROR("%s, none of KEYFORM or MODE can be specified .\n",
ock_err(ERR_TEMPLATE_INCONSISTENT));
return CKR_TEMPLATE_INCONSISTENT;
}
break;
case MODE_COPY:
/* All attributes must be present */
if (!keyform_present ||
(mode_attr != (CK_ATTRIBUTE_TYPE)-1 && !mode_present)) {
TRACE_ERROR("%s, KEYFORM or MODE must be specified .\n",
ock_err(ERR_TEMPLATE_INCOMPLETE));
return CKR_TEMPLATE_INCOMPLETE;
}
for (i = 0; i < num_req_attrs; i++) {
if (!template_attribute_find(tmpl, req_attrs[i], &attr)) {
TRACE_ERROR("%s, attribute %08lX missing.\n",
ock_err(ERR_TEMPLATE_INCOMPLETE), req_attrs[i]);
return CKR_TEMPLATE_INCOMPLETE;
}
}
if (priv_seed_attr != (CK_ATTRIBUTE_TYPE)-1 &&
!template_attribute_find(tmpl, priv_seed_attr, &attr)) {
TRACE_ERROR("%s, attribute %08lX missing.\n",
ock_err(ERR_TEMPLATE_INCOMPLETE), priv_seed_attr);
return CKR_TEMPLATE_INCOMPLETE;
}
break;
}
return CKR_OK;
}
// ibm_ml_dsa_publ_check_required_attributes() - for Dilithium and ML-DSA
//
CK_RV ibm_ml_dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_MECHANISM_TYPE mech)
{
static const CK_MECHANISM_TYPE req_attrs[] = {
CKA_IBM_ML_DSA_RHO,
CKA_IBM_ML_DSA_T1,
};
CK_RV rc;
rc = pqc_check_attributes(tmpl, mode, mech, req_attrs,
sizeof(req_attrs) / sizeof(req_attrs[0]),
(CK_MECHANISM_TYPE)-1);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return publ_key_check_required_attributes(tmpl, mode);
}
// ibm_ml_dsa_priv_check_required_attributes() - for Dilithium and ML-DSA
//
CK_RV ibm_ml_dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_MECHANISM_TYPE mech)
{
static const CK_MECHANISM_TYPE req_attrs[] = {
CKA_IBM_ML_DSA_RHO,
CKA_IBM_ML_DSA_SEED,
CKA_IBM_ML_DSA_TR,
CKA_IBM_ML_DSA_S1,
CKA_IBM_ML_DSA_S2,
CKA_IBM_ML_DSA_T0,
CKA_IBM_ML_DSA_T1,
};
CK_MECHANISM_TYPE priv_seed_attr;
CK_RV rc;
if (pqc_private_seed_attr_by_mech(mech, &priv_seed_attr) != CKR_OK)
return CKR_MECHANISM_INVALID;
rc = pqc_check_attributes(tmpl, mode, mech, req_attrs,
sizeof(req_attrs) / sizeof(req_attrs[0]),
priv_seed_attr);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return priv_key_check_required_attributes(tmpl, mode);
}
// ibm_ml_kem_publ_check_required_attributes() - for Kyber and ML-KEM
//
CK_RV ibm_ml_kem_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_MECHANISM_TYPE mech)
{
static const CK_MECHANISM_TYPE req_attrs[] = {
CKA_IBM_ML_KEM_PK,
};
CK_RV rc;
rc = pqc_check_attributes(tmpl, mode, mech, req_attrs,
sizeof(req_attrs) / sizeof(req_attrs[0]),
(CK_MECHANISM_TYPE)-1);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return publ_key_check_required_attributes(tmpl, mode);
}
// ibm_ml_kem_priv_check_required_attributes() - for Kyber and ML-KEM
//
CK_RV ibm_ml_kem_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_MECHANISM_TYPE mech)
{
static const CK_MECHANISM_TYPE req_attrs[] = {
CKA_IBM_ML_KEM_SK,
CKA_IBM_ML_KEM_PK,
};
CK_MECHANISM_TYPE priv_seed_attr;
CK_RV rc;
if (pqc_private_seed_attr_by_mech(mech, &priv_seed_attr) != CKR_OK)
return CKR_MECHANISM_INVALID;
rc = pqc_check_attributes(tmpl, mode, mech, req_attrs,
sizeof(req_attrs) / sizeof(req_attrs[0]),
priv_seed_attr);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return priv_key_check_required_attributes(tmpl, mode);
}
CK_RV ml_dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_RV rc;
rc = pqc_check_attributes(tmpl, mode, CKM_ML_DSA, NULL, 0,
(CK_MECHANISM_TYPE)-1);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return publ_key_check_required_attributes(tmpl, mode);
}
CK_RV ml_dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_RV rc;
rc = pqc_check_attributes(tmpl, mode, CKM_ML_DSA, NULL, 0, CKA_SEED);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return priv_key_check_required_attributes(tmpl, mode);
}
CK_RV ml_kem_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_RV rc;
rc = pqc_check_attributes(tmpl, mode, CKM_ML_KEM, NULL, 0,
(CK_MECHANISM_TYPE)-1);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return publ_key_check_required_attributes(tmpl, mode);
}
CK_RV ml_kem_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_RV rc;
rc = pqc_check_attributes(tmpl, mode, CKM_ML_KEM, NULL, 0, CKA_SEED);
if (rc != CKR_OK)
return rc;
/* All required attrs found, check them */
return priv_key_check_required_attributes(tmpl, mode);
}
static CK_RV pqc_validate_keyform_mode(CK_ATTRIBUTE *attr, CK_ULONG mode,
CK_MECHANISM_TYPE mech)
{
CK_ATTRIBUTE_TYPE keyform_attr;
CK_ATTRIBUTE_TYPE mode_attr;
const struct pqc_oid *oids, *oid;
if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr,
&mode_attr, &oids) != CKR_OK)
return CKR_MECHANISM_INVALID;
if (attr->type == keyform_attr) {
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
oid = find_pqc_by_keyform(oids, *((CK_ULONG *)attr->pValue));
if (oid == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
if (attr->type == mode_attr) {
if (mode == MODE_CREATE || mode == MODE_KEYGEN ||
mode == MODE_ENCAPS || mode == MODE_EXTRACT) {
if (attr->ulValueLen == 0 || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
oid = find_pqc_by_oid(oids, attr->pValue, attr->ulValueLen);
if (oid == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
return CKR_ATTRIBUTE_TYPE_INVALID;
}
// ibm_ml_dsa_publ_validate_attribute() - for Dilithium and ML-DSA
//
CK_RV ibm_ml_dsa_publ_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode, CK_MECHANISM_TYPE mech)
{
CK_RV rc;
switch (attr->type) {
case CKA_IBM_DILITHIUM_KEYFORM:
case CKA_IBM_DILITHIUM_MODE:
case CKA_IBM_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, mech);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_IBM_ML_DSA_RHO:
case CKA_IBM_ML_DSA_T1:
case CKA_VALUE:
if (mode == MODE_CREATE || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// ibm_ml_dsa_priv_validate_attribute() - for Dilithium and ML-DSA
//
CK_RV ibm_ml_dsa_priv_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode, CK_MECHANISM_TYPE mech)
{
CK_RV rc;
switch (attr->type) {
case CKA_IBM_DILITHIUM_KEYFORM:
case CKA_IBM_DILITHIUM_MODE:
case CKA_IBM_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, mech);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_IBM_ML_DSA_PRIVATE_SEED:
if (mech != CKM_IBM_ML_DSA)
return CKR_ATTRIBUTE_TYPE_INVALID;
/* Fall through */
case CKA_IBM_ML_DSA_RHO:
case CKA_IBM_ML_DSA_SEED:
case CKA_IBM_ML_DSA_TR:
case CKA_IBM_ML_DSA_S1:
case CKA_IBM_ML_DSA_S2:
case CKA_IBM_ML_DSA_T0:
case CKA_IBM_ML_DSA_T1:
case CKA_VALUE:
if (mode == MODE_CREATE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
CK_BBOOL ibm_ml_dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
case CKA_IBM_ML_DSA_SEED:
case CKA_IBM_ML_DSA_TR:
case CKA_IBM_ML_DSA_S1:
case CKA_IBM_ML_DSA_S2:
case CKA_IBM_ML_DSA_T0:
case CKA_IBM_ML_DSA_PRIVATE_SEED:
return FALSE;
}
return TRUE;
}
// ibm_ml_kem_publ_validate_attribute() - for Kyber and KL-KEM
//
CK_RV ibm_ml_kem_publ_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode, CK_MECHANISM_TYPE mech)
{
CK_RV rc;
switch (attr->type) {
case CKA_IBM_KYBER_KEYFORM:
case CKA_IBM_KYBER_MODE:
case CKA_IBM_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, mech);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_IBM_KYBER_PK:
case CKA_VALUE:
if (mode == MODE_CREATE || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// ibm_ml_kem_priv_validate_attribute() - for Kyber and KL-KEM
//
CK_RV ibm_ml_kem_priv_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode, CK_MECHANISM_TYPE mech)
{
CK_RV rc;
switch (attr->type) {
case CKA_IBM_KYBER_KEYFORM:
case CKA_IBM_KYBER_MODE:
case CKA_IBM_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, mech);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_IBM_ML_KEM_PRIVATE_SEED:
if (mech != CKM_IBM_ML_KEM)
return CKR_ATTRIBUTE_TYPE_INVALID;
/* Fall through */
case CKA_IBM_ML_KEM_SK:
case CKA_IBM_ML_KEM_PK:
case CKA_VALUE:
if (mode == MODE_CREATE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
CK_BBOOL ibm_ml_kem_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
case CKA_IBM_ML_KEM_SK:
case CKA_IBM_ML_KEM_PRIVATE_SEED:
return FALSE;
}
return TRUE;
}
CK_RV ml_dsa_publ_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode)
{
CK_RV rc;
extern const char manuf[];
extern const char model[];
switch (attr->type) {
case CKA_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_DSA);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_VALUE:
if (mode == MODE_CREATE || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_IBM_CCA_ML_DSA_KEY_MODE:
if (strcmp(manuf, "IBM") != 0 || strcmp(model, "CCA") != 0) {
TRACE_ERROR("%s (only valid for the CCA token)\n",
ock_err(ERR_ATTRIBUTE_TYPE_INVALID));
return CKR_ATTRIBUTE_TYPE_INVALID;
}
/*
* CKA_IBM_CCA_ML_DSA_KEY_MODE can not be specified for the public key,
* but only for the private key when generating a ML-DSA key pair
* (MODE_KEYGEN). Nevertheless, both generated keys, private and public
* key, get the CKA_IBM_CCA_ML_DSA_KEY_MODE attribute with the same
* value.
* For other modes, only the public key is created/derived/etc, and
* thus attribute CKA_IBM_CCA_ML_DSA_KEY_MODE can be specified here.
*/
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_UNWRAP ||mode == MODE_ENCAPS ||
mode == MODE_DECAPS || mode == MODE_EXTRACT) {
if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) ||
attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
switch (*(CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE *)attr->pValue) {
case CK_IBM_CCA_ML_DSA_PURE_KEY:
case CK_IBM_CCA_ML_DSA_PREHASH_KEY:
return CKR_OK;
default:
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
CK_RV ml_dsa_priv_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode)
{
CK_RV rc;
extern const char manuf[];
extern const char model[];
switch (attr->type) {
case CKA_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_DSA);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_VALUE:
case CKA_SEED:
if (mode == MODE_CREATE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_IBM_CCA_ML_DSA_KEY_MODE:
if (strcmp(manuf, "IBM") != 0 || strcmp(model, "CCA") != 0) {
TRACE_ERROR("%s (only valid for the CCA token)\n",
ock_err(ERR_ATTRIBUTE_TYPE_INVALID));
return CKR_ATTRIBUTE_TYPE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_KEYGEN || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS) {
if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) ||
attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
switch (*(CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE *)attr->pValue) {
case CK_IBM_CCA_ML_DSA_PURE_KEY:
case CK_IBM_CCA_ML_DSA_PREHASH_KEY:
return CKR_OK;
default:
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
CK_BBOOL ml_dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
case CKA_SEED:
return FALSE;
}
return TRUE;
}
CK_RV ml_kem_publ_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode)
{
CK_RV rc;
switch (attr->type) {
case CKA_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_KEM);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_VALUE:
if (mode == MODE_CREATE || mode == MODE_EXTRACT)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return publ_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
CK_RV ml_kem_priv_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode)
{
CK_RV rc;
switch (attr->type) {
case CKA_PARAMETER_SET:
rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_KEM);
if (rc != CKR_OK)
return rc;
return CKR_OK;
case CKA_VALUE:
case CKA_SEED:
if (mode == MODE_CREATE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return priv_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
CK_BBOOL ml_kem_priv_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
case CKA_SEED:
return FALSE;
}
return TRUE;
}
// generic_secret_check_required_attributes()
//
CK_RV generic_secret_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_ULONG val;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for des key templates.
*/
return secret_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
rc = template_attribute_get_ulong(tmpl, CKA_VALUE_LEN, &val);
if (rc != CKR_OK) {
// here's another place where PKCS #11 deviates from its own
// specification.
// the spec states that VALUE_LEN must be present for KEYGEN but later
// it's merely optional if the mechanism is CKM_SSL3_PRE_MASTER_KEY_GEN.
// Unfortunately, we can't check the mechanism at this point
//
return CKR_OK;
} else {
// Another contradiction within the spec: When describing the key types
// the spec says that VALUE_LEN must not be specified when unwrapping
// a key. In the section describing the mechanisms, though, it's allowed
// for most unwrapping mechanisms. Netscape DOES does specify this
// attribute when unwrapping.
//
if (mode == MODE_CREATE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
}
return secret_key_check_required_attributes(tmpl, mode);
}
// generic_secret_set_default_attributes()
//
CK_RV generic_secret_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode,
CK_KEY_TYPE key_type)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *value_len_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *class_attr = NULL;
CK_ATTRIBUTE *sensitive_attr = NULL;
CK_ATTRIBUTE *encrypt_attr = NULL;
CK_ATTRIBUTE *decrypt_attr = NULL;
CK_ATTRIBUTE *sign_attr = NULL;
CK_ATTRIBUTE *verify_attr = NULL;
CK_ATTRIBUTE *wrap_attr = NULL;
CK_ATTRIBUTE *unwrap_attr = NULL;
CK_ATTRIBUTE *extractable_attr = NULL;
CK_ATTRIBUTE *never_extr_attr = NULL;
CK_ATTRIBUTE *always_sens_attr = NULL;
CK_ATTRIBUTE *id_attr = NULL;
CK_ATTRIBUTE *sdate_attr = NULL;
CK_ATTRIBUTE *edate_attr = NULL;
CK_ATTRIBUTE *derive_attr = NULL;
CK_ATTRIBUTE *local_attr = NULL;
CK_ULONG len = 0L;
CK_RV rc;
/* First set the Common Key Attributes's defaults for Generic Secret Keys */
id_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
sdate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
edate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
derive_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
local_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
if (!id_attr || !sdate_attr || !edate_attr || !derive_attr || !local_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
id_attr->type = CKA_ID;
id_attr->ulValueLen = 0;
id_attr->pValue = NULL;
sdate_attr->type = CKA_START_DATE;
sdate_attr->ulValueLen = 0;
sdate_attr->pValue = NULL;
edate_attr->type = CKA_END_DATE;
edate_attr->ulValueLen = 0;
edate_attr->pValue = NULL;
derive_attr->type = CKA_DERIVE;
derive_attr->ulValueLen = sizeof(CK_BBOOL);
derive_attr->pValue = (CK_BYTE *) derive_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) derive_attr->pValue = TRUE;
/* should be safe to set CKA_LOCAL here... */
local_attr->type = CKA_LOCAL;
local_attr->ulValueLen = sizeof(CK_BBOOL);
local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE);
if (mode == MODE_KEYGEN)
*(CK_BBOOL *) local_attr->pValue = TRUE;
else
*(CK_BBOOL *) local_attr->pValue = FALSE;
rc = template_update_attribute(tmpl, id_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
id_attr = NULL;
rc = template_update_attribute(tmpl, sdate_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
sdate_attr = NULL;
rc = template_update_attribute(tmpl, edate_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
edate_attr = NULL;
rc = template_update_attribute(tmpl, derive_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
derive_attr = NULL;
rc = template_update_attribute(tmpl, local_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
local_attr = NULL;
/* Next, set the Common Secret Key Attributes and defaults for
* Generic Secret Keys.
*/
class_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS));
sensitive_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
encrypt_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
decrypt_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
sign_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
verify_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
wrap_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
unwrap_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
extractable_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
never_extr_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
always_sens_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL));
if (!class_attr || !sensitive_attr || !encrypt_attr || !decrypt_attr
|| !sign_attr || !verify_attr || !wrap_attr || !unwrap_attr
|| !extractable_attr || !never_extr_attr || !always_sens_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
class_attr->type = CKA_CLASS;
class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS);
class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE);
*(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY;
sensitive_attr->type = CKA_SENSITIVE;
sensitive_attr->ulValueLen = sizeof(CK_BBOOL);
sensitive_attr->pValue = (CK_BYTE *) sensitive_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) sensitive_attr->pValue = FALSE;
encrypt_attr->type = CKA_ENCRYPT;
encrypt_attr->ulValueLen = sizeof(CK_BBOOL);
encrypt_attr->pValue = (CK_BYTE *) encrypt_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) encrypt_attr->pValue = FALSE;
decrypt_attr->type = CKA_DECRYPT;
decrypt_attr->ulValueLen = sizeof(CK_BBOOL);
decrypt_attr->pValue = (CK_BYTE *) decrypt_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) decrypt_attr->pValue = FALSE;
sign_attr->type = CKA_SIGN;
sign_attr->ulValueLen = sizeof(CK_BBOOL);
sign_attr->pValue = (CK_BYTE *) sign_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) sign_attr->pValue = TRUE;
verify_attr->type = CKA_VERIFY;
verify_attr->ulValueLen = sizeof(CK_BBOOL);
verify_attr->pValue = (CK_BYTE *) verify_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) verify_attr->pValue = TRUE;
wrap_attr->type = CKA_WRAP;
wrap_attr->ulValueLen = sizeof(CK_BBOOL);
wrap_attr->pValue = (CK_BYTE *) wrap_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) wrap_attr->pValue = FALSE;
unwrap_attr->type = CKA_UNWRAP;
unwrap_attr->ulValueLen = sizeof(CK_BBOOL);
unwrap_attr->pValue = (CK_BYTE *) unwrap_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) unwrap_attr->pValue = FALSE;
extractable_attr->type = CKA_EXTRACTABLE;
extractable_attr->ulValueLen = sizeof(CK_BBOOL);
extractable_attr->pValue =
(CK_BYTE *) extractable_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) extractable_attr->pValue = TRUE;
/* by default, we'll set NEVER_EXTRACTABLE == FALSE and
* ALWAYS_SENSITIVE == FALSE
* If the key is being created with KEYGEN, it will adjust as necessary.
*/
always_sens_attr->type = CKA_ALWAYS_SENSITIVE;
always_sens_attr->ulValueLen = sizeof(CK_BBOOL);
always_sens_attr->pValue =
(CK_BYTE *) always_sens_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) always_sens_attr->pValue = FALSE;
never_extr_attr->type = CKA_NEVER_EXTRACTABLE;
never_extr_attr->ulValueLen = sizeof(CK_BBOOL);
never_extr_attr->pValue =
(CK_BYTE *) never_extr_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *) never_extr_attr->pValue = FALSE;
rc = template_update_attribute(tmpl, class_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
class_attr = NULL;
rc = template_update_attribute(tmpl, sensitive_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
sensitive_attr = NULL;
rc = template_update_attribute(tmpl, encrypt_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
encrypt_attr = NULL;
rc = template_update_attribute(tmpl, decrypt_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
decrypt_attr = NULL;
rc = template_update_attribute(tmpl, sign_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
sign_attr = NULL;
rc = template_update_attribute(tmpl, verify_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
verify_attr = NULL;
rc = template_update_attribute(tmpl, wrap_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
wrap_attr = NULL;
rc = template_update_attribute(tmpl, unwrap_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
unwrap_attr = NULL;
rc = template_update_attribute(tmpl, extractable_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
extractable_attr = NULL;
rc = template_update_attribute(tmpl, never_extr_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
never_extr_attr = NULL;
rc = template_update_attribute(tmpl, always_sens_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
always_sens_attr = NULL;
/* Now set the type, value and value_len */
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
value_len_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG));
if (!type_attr || !value_attr || !value_len_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
value_len_attr->type = CKA_VALUE_LEN;
value_len_attr->ulValueLen = sizeof(CK_ULONG);
value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE);
*(CK_ULONG *) value_len_attr->pValue = len;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = key_type;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
rc = template_update_attribute(tmpl, value_len_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_len_attr = NULL;
return CKR_OK;
error:
if (id_attr)
free(id_attr);
if (sdate_attr)
free(sdate_attr);
if (edate_attr)
free(edate_attr);
if (derive_attr)
free(derive_attr);
if (local_attr)
free(local_attr);
if (class_attr)
free(class_attr);
if (sensitive_attr)
free(sensitive_attr);
if (encrypt_attr)
free(encrypt_attr);
if (decrypt_attr)
free(decrypt_attr);
if (sign_attr)
free(sign_attr);
if (verify_attr)
free(verify_attr);
if (wrap_attr)
free(wrap_attr);
if (unwrap_attr)
free(unwrap_attr);
if (extractable_attr)
free(extractable_attr);
if (never_extr_attr)
free(never_extr_attr);
if (always_sens_attr)
free(always_sens_attr);
if (type_attr)
free(type_attr);
if (value_attr)
free(value_attr);
if (value_len_attr)
free(value_len_attr);
return rc;
}
// generic_secret_validate_attribute()
//
CK_RV generic_secret_validate_attribute(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl, CK_ATTRIBUTE *attr,
CK_ULONG mode)
{
switch (attr->type) {
case CKA_VALUE:
if (mode == MODE_CREATE)
return CKR_OK;
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
// Another contradiction within the spec: When describing the key types
// the spec says that VALUE_LEN must not be specified when unwrapping
// a key. In the section describing the mechanisms, though, it's allowed
// for most unwrapping mechanisms. Netscape DOES does specify this
// attribute when unwrapping.
//
case CKA_VALUE_LEN:
if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_KEYGEN || mode == MODE_DERIVE)
return CKR_OK;
if (mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) {
if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE)
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return secret_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// generic_secret_check_exportability()
//
CK_BBOOL generic_secret_check_exportability(CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_VALUE:
return FALSE;
}
return TRUE;
}
//
//
CK_RV generic_secret_wrap_get_data(TEMPLATE *tmpl,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *attr = NULL;
CK_BYTE *ptr = NULL;
CK_RV rc;
if (!tmpl || !data_len) {
TRACE_ERROR("Invalid function arguments.\n");
return CKR_FUNCTION_FAILED;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
*data_len = attr->ulValueLen;
if (length_only == FALSE) {
ptr = (CK_BYTE *) malloc(attr->ulValueLen);
if (!ptr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
memcpy(ptr, attr->pValue, attr->ulValueLen);
*data = ptr;
}
return CKR_OK;
}
//
//
CK_RV generic_secret_unwrap(TEMPLATE *tmpl,
CK_BYTE *data,
CK_ULONG data_len,
CK_BBOOL fromend)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *value_len_attr = NULL;
CK_BYTE *ptr = NULL;
CK_ULONG rc, len = 0;
if (fromend == TRUE)
ptr = data + data_len;
else
ptr = data;
// it's possible that the user specified CKA_VALUE_LEN in the
// template. if so, try to use it. by default, CKA_VALUE_LEN is 0
//
rc = template_attribute_get_ulong(tmpl, CKA_VALUE_LEN, &len);
if (rc == CKR_OK) {
if (len > data_len) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
rc = CKR_ATTRIBUTE_VALUE_INVALID;
goto error;
}
if (len != 0)
data_len = len;
}
if (fromend == TRUE)
ptr -= data_len;
rc = build_attribute(CKA_VALUE, ptr, data_len, &value_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto error;
}
if (data_len != len) {
rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *) & data_len,
sizeof(CK_ULONG), &value_len_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto error;
}
}
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
if (data_len != len) {
rc = template_update_attribute(tmpl, value_len_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_len_attr = NULL;
}
return CKR_OK;
error:
if (value_attr)
free(value_attr);
if (value_len_attr)
free(value_len_attr);
return rc;
}
//
//
CK_RV des_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for des key templates.
*/
return secret_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return secret_key_check_required_attributes(tmpl, mode);
}
//
//
CK_BBOOL des_check_weak_key(CK_BYTE *key)
{
CK_ULONG i;
for (i = 0; i < des_weak_count; i++) {
if (memcmp(key, des_weak_keys[i], DES_KEY_SIZE) == 0)
return TRUE;
}
for (i = 0; i < des_semi_weak_count; i++) {
if (memcmp(key, des_semi_weak_keys[i], DES_KEY_SIZE) == 0)
return TRUE;
}
for (i = 0; i < des_possibly_weak_count; i++) {
if (memcmp(key, des_possibly_weak_keys[i], DES_KEY_SIZE) == 0)
return TRUE;
}
return FALSE;
}
//
//
CK_RV des_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
secret_key_set_default_attributes(tmpl, mode);
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
if (!value_attr || !type_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_DES;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (value_attr)
free(value_attr);
if (type_attr)
free(type_attr);
return rc;
}
//
//
CK_RV des_unwrap(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl,
CK_BYTE *data,
CK_ULONG data_len, CK_BBOOL fromend)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_BYTE *ptr = NULL;
CK_ULONG i;
CK_RV rc;
if (data_len < DES_BLOCK_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID));
return CKR_WRAPPED_KEY_INVALID;
}
if (fromend == TRUE)
ptr = data + data_len - DES_BLOCK_SIZE;
else
ptr = data;
if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) {
for (i = 0; i < DES_KEY_SIZE; i++) {
if (parity_is_odd(ptr[i]) == FALSE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
}
value_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + DES_BLOCK_SIZE);
if (!value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = DES_BLOCK_SIZE;
value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE);
memcpy(value_attr->pValue, ptr, DES_BLOCK_SIZE);
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
free(value_attr);
return rc;
}
return CKR_OK;
}
// des_validate_attribute()
//
CK_RV des_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
CK_BYTE *ptr = NULL;
CK_ULONG i;
switch (attr->type) {
case CKA_VALUE:
// key length always 8 bytes
//
if (mode == MODE_CREATE) {
if (attr->ulValueLen != DES_KEY_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) {
ptr = attr->pValue;
if (ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
for (i = 0; i < DES_KEY_SIZE; i++) {
if (parity_is_odd(ptr[i]) == FALSE) {
TRACE_ERROR("%s\n",
ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_VALUE_LEN:
// Cryptoki doesn't allow this but Netscape tries uses it
//
if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) {
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_KEYGEN || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS) {
CK_ULONG len = *(CK_ULONG *) attr->pValue;
if (len != DES_KEY_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID));
return CKR_ATTRIBUTE_TYPE_INVALID;
default:
return secret_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
//
//
CK_RV des_wrap_get_data(TEMPLATE *tmpl,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *attr = NULL;
CK_BYTE *ptr = NULL;
CK_RV rc;
if (!tmpl || !data_len) {
TRACE_ERROR("Invalid function arguments.\n");
return CKR_FUNCTION_FAILED;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
*data_len = attr->ulValueLen;
if (length_only == FALSE) {
ptr = (CK_BYTE *) malloc(attr->ulValueLen);
if (!ptr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
memcpy(ptr, attr->pValue, attr->ulValueLen);
*data = ptr;
}
return CKR_OK;
}
// des2_check_required_attributes()
//
CK_RV des2_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for des key templates.
*/
return secret_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return secret_key_check_required_attributes(tmpl, mode);
}
// des2_set_default_attributes()
//
CK_RV des2_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
secret_key_set_default_attributes(tmpl, mode);
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
if (!value_attr || !type_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_DES2;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (value_attr)
free(value_attr);
if (type_attr)
free(type_attr);
return rc;
}
// des2_validate_attribute()
//
CK_RV des2_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
CK_BYTE *ptr = NULL;
CK_ULONG i;
switch (attr->type) {
case CKA_VALUE:
// key length always 16 bytes
//
if (mode == MODE_CREATE) {
if (attr->ulValueLen != (2 * DES_KEY_SIZE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) {
ptr = attr->pValue;
if (ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
for (i = 0; i < 2 * DES_KEY_SIZE; i++) {
if (parity_is_odd(ptr[i]) == FALSE) {
TRACE_ERROR("%s\n",
ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_VALUE_LEN:
if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
// Cryptoki doesn't allow this but Netscape tries uses it
//
if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) {
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_KEYGEN || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS) {
CK_ULONG len = *(CK_ULONG *) attr->pValue;
if (len != (2 * DES_KEY_SIZE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID));
return CKR_ATTRIBUTE_TYPE_INVALID;
default:
return secret_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
// des3_check_required_attributes()
//
CK_RV des3_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for des3 key templates.
*/
return secret_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return secret_key_check_required_attributes(tmpl, mode);
}
// des3_set_default_attributes()
//
CK_RV des3_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_RV rc;
secret_key_set_default_attributes(tmpl, mode);
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
if (!value_attr || !type_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = CKK_DES3;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
return CKR_OK;
error:
if (value_attr)
free(value_attr);
if (type_attr)
free(type_attr);
return rc;
}
//
//
CK_RV des3_unwrap(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl,
CK_BYTE *data,
CK_ULONG data_len, CK_BBOOL fromend)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_BYTE *ptr = NULL;
CK_ULONG i;
CK_RV rc;
if (data_len < 3 * DES_BLOCK_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID));
return CKR_WRAPPED_KEY_INVALID;
}
if (fromend == TRUE)
ptr = data + data_len - (3 * DES_BLOCK_SIZE);
else
ptr = data;
if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) {
for (i = 0; i < 3 * DES_KEY_SIZE; i++) {
if (parity_is_odd(ptr[i]) == FALSE) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
}
value_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + (3 * DES_BLOCK_SIZE));
if (!value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 3 * DES_BLOCK_SIZE;
value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE);
memcpy(value_attr->pValue, ptr, 3 * DES_BLOCK_SIZE);
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
free(value_attr);
return rc;
}
return CKR_OK;
}
//
//
CK_RV des3_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode)
{
CK_BYTE *ptr = NULL;
CK_ULONG i;
switch (attr->type) {
case CKA_VALUE:
// key length always 24 bytes
//
if (mode == MODE_CREATE) {
if (attr->ulValueLen != (3 * DES_KEY_SIZE)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) {
ptr = attr->pValue;
if (ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
for (i = 0; i < 3 * DES_KEY_SIZE; i++) {
if (parity_is_odd(ptr[i]) == FALSE) {
TRACE_ERROR("%s\n",
ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_VALUE_LEN:
if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
// Cryptoki doesn't allow this but Netscape tries uses it
//
if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) {
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_KEYGEN || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS) {
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID));
return CKR_ATTRIBUTE_TYPE_INVALID;
default:
return secret_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
//
//
CK_RV des3_wrap_get_data(TEMPLATE *tmpl,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *attr = NULL;
CK_BYTE *ptr = NULL;
CK_RV rc;
if (!tmpl || !data_len) {
TRACE_ERROR("Invalid function arguments.\n");
return CKR_FUNCTION_FAILED;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
*data_len = attr->ulValueLen;
if (length_only == FALSE) {
ptr = (CK_BYTE *) malloc(attr->ulValueLen);
if (!ptr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
memcpy(ptr, attr->pValue, attr->ulValueLen);
*data = ptr;
}
return CKR_OK;
}
// aes_set_default_attributes()
//
CK_RV aes_set_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl,
CK_ULONG mode, CK_BBOOL xts)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *type_attr = NULL;
CK_ATTRIBUTE *len_attr = NULL;
CK_ULONG keysize;
CK_RV rc;
secret_key_set_default_attributes(tmpl, mode);
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE));
type_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE));
if (!value_attr || !type_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto error;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 0;
value_attr->pValue = NULL;
type_attr->type = CKA_KEY_TYPE;
type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *) type_attr->pValue = xts ? CKK_AES_XTS : CKK_AES;
rc = template_update_attribute(tmpl, type_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
type_attr = NULL;
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
/* If CKA_VALUE specified in base tmpl, add CKA_VALUE_LEN to tmpl. */
if (template_attribute_find(basetmpl, CKA_VALUE, &value_attr) &&
!template_attribute_find(basetmpl, CKA_VALUE_LEN, &len_attr)) {
keysize = value_attr->ulValueLen;
rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&keysize, sizeof(CK_ULONG), &len_attr);
if (rc != CKR_OK) {
TRACE_ERROR("build_attribute failed\n");
goto error;
}
rc = template_update_attribute(tmpl, len_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
goto error;
}
value_attr = NULL;
}
return CKR_OK;
error:
if (type_attr)
free(type_attr);
if (value_attr)
free(value_attr);
return rc;
}
// aes_check_required_attributes()
//
CK_RV aes_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode)
{
CK_ATTRIBUTE *attr = NULL;
CK_RV rc;
if (mode == MODE_CREATE &&
token_specific.secure_key_token == TRUE &&
template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) {
/*
* Import of an already existing secure key. Only
* do the base checks for aes key templates.
*/
return secret_key_check_required_attributes(tmpl, mode);
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
if (mode == MODE_CREATE) {
TRACE_ERROR("Could not find CKA_VALUE\n");
return rc;
}
}
return secret_key_check_required_attributes(tmpl, mode);
}
//
//
CK_RV aes_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl,
CK_ATTRIBUTE *attr, CK_ULONG mode, CK_BBOOL xts)
{
CK_ULONG val;
extern const char manuf[];
extern const char model[];
switch (attr->type) {
case CKA_VALUE:
// key length is either 16, 24 or 32 bytes
//
if (mode == MODE_CREATE) {
if (attr->ulValueLen != (AES_KEY_SIZE_128 * (xts ? 2 : 1)) &&
(xts || attr->ulValueLen != AES_KEY_SIZE_192) &&
attr->ulValueLen != (AES_KEY_SIZE_256 * (xts ? 2 : 1))) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_VALUE_LEN:
if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_KEYGEN || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS) {
if (attr->ulValueLen != sizeof(CK_ULONG) ||
attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
val = *(CK_ULONG *) attr->pValue;
if (val != (AES_KEY_SIZE_128 * (xts ? 2 : 1)) &&
(xts || val != AES_KEY_SIZE_192) &&
val != (AES_KEY_SIZE_256 * (xts ? 2 : 1))) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
case CKA_IBM_CCA_AES_KEY_MODE:
if (strcmp(manuf, "IBM") != 0 || strcmp(model, "CCA") != 0) {
TRACE_ERROR("%s (only valid for the CCA token)\n",
ock_err(ERR_ATTRIBUTE_TYPE_INVALID));
return CKR_ATTRIBUTE_TYPE_INVALID;
}
if (mode == MODE_CREATE || mode == MODE_DERIVE ||
mode == MODE_KEYGEN || mode == MODE_UNWRAP ||
mode == MODE_ENCAPS || mode == MODE_DECAPS ||
mode == MODE_COPY || mode == MODE_MODIFY) {
if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) ||
attr->pValue == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
switch (*(CK_IBM_CCA_AES_KEY_MODE_TYPE *)attr->pValue) {
case CK_IBM_CCA_AES_DATA_KEY:
/* Modify/Copy can only set it to mode CIPHER */
if (mode == MODE_COPY || mode == MODE_MODIFY) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
return CKR_OK;
case CK_IBM_CCA_AES_CIPHER_KEY:
return CKR_OK;
default:
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY));
return CKR_ATTRIBUTE_READ_ONLY;
default:
return secret_key_validate_attribute(tokdata, tmpl, attr, mode);
}
}
//
//
CK_RV aes_wrap_get_data(TEMPLATE *tmpl,
CK_BBOOL length_only,
CK_BYTE **data, CK_ULONG *data_len)
{
CK_ATTRIBUTE *attr = NULL;
CK_BYTE *ptr = NULL;
CK_RV rc;
if (!tmpl || !data_len) {
TRACE_ERROR("Invalid function arguments.\n");
return CKR_FUNCTION_FAILED;
}
rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("Could not find CKA_VALUE for the key.\n");
return rc;
}
*data_len = attr->ulValueLen;
if (length_only == FALSE) {
ptr = (CK_BYTE *) malloc(attr->ulValueLen);
if (!ptr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
memcpy(ptr, attr->pValue, attr->ulValueLen);
*data = ptr;
}
return CKR_OK;
}
//
//
CK_RV aes_unwrap(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl,
CK_BYTE *data,
CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL xts)
{
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *val_len_attr = NULL;
CK_BYTE *ptr = NULL;
CK_ULONG key_size;
CK_BBOOL found = FALSE;
CK_RV rc;
UNUSED(tokdata);
/* accept CKA_VALUE_LEN. pkcs11v2.20 doesn't want this attribute when
* unwrapping an AES key, but we need it for several reasons:
* - because some mechanisms may have added padding
* - AES keys come in several sizes
* If not a available, try datalen and see if matches an aes key size.
* Otherwise, fail because we need to return CKA_VALUE_LEN and we cannot
* unless user tells us what it is.
*/
rc = template_attribute_get_ulong(tmpl, CKA_VALUE_LEN, &key_size);
if (rc == CKR_ATTRIBUTE_VALUE_INVALID) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
if (rc == CKR_OK)
found = TRUE;
else
key_size = data_len;
/* key_size should be one of AES's possible sizes */
if (key_size != (AES_KEY_SIZE_128 * (xts ? 2 : 1)) &&
(xts || key_size != AES_KEY_SIZE_192) &&
key_size != (AES_KEY_SIZE_256 * (xts ? 2 : 1))) {
TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_LEN_RANGE));
return CKR_WRAPPED_KEY_LEN_RANGE;
}
if (fromend == TRUE)
ptr = data + data_len - key_size;
else
ptr = data;
value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + key_size);
if (!value_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = key_size;
value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE);
memcpy(value_attr->pValue, ptr, key_size);
rc = template_update_attribute(tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
free(value_attr);
return rc;
}
/* pkcs11v2-20: CKA_VALUE and CKA_VALUE_LEN given for aes key object. */
if (!found) {
val_len_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG));
if (!val_len_attr) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
val_len_attr->type = CKA_VALUE_LEN;
val_len_attr->ulValueLen = sizeof(CK_ULONG);
val_len_attr->pValue = (CK_BYTE *) val_len_attr + sizeof(CK_ATTRIBUTE);
*((CK_ULONG *) val_len_attr->pValue) = key_size;
rc = template_update_attribute(tmpl, val_len_attr);
if (rc != CKR_OK) {
TRACE_ERROR("template_update_attribute failed\n");
free(val_len_attr);
return rc;
}
}
return CKR_OK;
}