You've already forked opencryptoki
mirror of
https://github.com/opencryptoki/opencryptoki.git
synced 2026-10-24 05:39:17 +03:00
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>
8897 lines
273 KiB
C
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, ¶ms);
|
|
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, ¶ms, &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;
|
|
}
|